from flask import Blueprint, render_template, request, redirect, url_for, flash, make_response, jsonify
from config import Config
from app.models.asset import Asset
from app.models.userassets import UserAsset
from app.enums.AssetType import AssetType
from app.models.follow_relationship import FollowRelationship
from app.models.friend_relationship import FriendRelationship
from app.models.friend_request import FriendRequest
from app.models.package_asset import PackageAsset
from app.models.placeserver_players import PlaceServerPlayer
from app.util import auth, friends, websiteFeatures, membership
from app.services import economy
from app.enums.MembershipType import MembershipType
from app.models.user import User
from app.models.user_email import UserEmail
from sqlalchemy import or_, func
from app.extensions import limiter, db, csrf
import logging
from datetime import datetime, timedelta
from app.models.groups import GroupRole, GroupMember
from app.services.groups import GetGroupMemberCount
from app.services.groups import GetUserRankInGroup, GroupExceptions, GetUserRolesetInGroup
from app.services.user_relationships import followings
config = Config()
LuaWebServiceRoute = Blueprint('luawebservice', __name__, url_prefix='/')
def MakeReturnFalseResponse():
Resposne = make_response("""false""")
Resposne.headers["Content-Type"] = "application/xml; charset=utf-8"
return Resposne
def MakeReturnTrueResponse():
Resposne = make_response("""true""")
Resposne.headers["Content-Type"] = "application/xml; charset=utf-8"
return Resposne
def MakeReturnIntResponse(Value : int):
Resposne = make_response(f"""{str(Value)}""")
Resposne.headers["Content-Type"] = "application/xml; charset=utf-8"
return Resposne
def MakeReturnStringResponse(Value : str):
Resposne = make_response(Value)
#Resposne = make_response(f"""{Value}""")
Resposne.headers["Content-Type"] = "application/xml; charset=utf-8"
return Resposne
@LuaWebServiceRoute.route('/Game/LuaWebService/HandleSocialRequest.ashx', methods=['GET'])
def HandleSocialRequest():
playerid = request.args.get("playerid", None, int)
groupid = request.args.get("groupid", None, int)
userid = request.args.get("userid", None, int)
method = request.args.get("method", None, str)
if method is None:
return MakeReturnFalseResponse()
if groupid == 1200769:
groupid = config.ADMIN_GROUP_ID
if method == "GetGroupRank":
try:
if playerid is None or groupid is None:
return MakeReturnIntResponse(0)
if playerid < 1 or groupid < 1:
return MakeReturnIntResponse(0)
return MakeReturnIntResponse(GetUserRankInGroup(playerid, groupid))
except GroupExceptions.GroupDoesNotExist:
return MakeReturnIntResponse(0)
except GroupExceptions.UserDoesNotExist:
return MakeReturnIntResponse(0)
elif method == "IsInGroup":
try:
if playerid is None or groupid is None:
return MakeReturnFalseResponse()
if playerid < 1 or groupid < 1:
return MakeReturnFalseResponse()
if GetUserRankInGroup(playerid, groupid) == 0:
return MakeReturnFalseResponse()
return MakeReturnTrueResponse()
except GroupExceptions.GroupDoesNotExist:
return MakeReturnFalseResponse()
except GroupExceptions.UserDoesNotExist:
return MakeReturnFalseResponse()
elif method == "GetGroupRole":
try:
if playerid is None or groupid is None:
return MakeReturnStringResponse("Guest")
if playerid < 1 or groupid < 1:
return MakeReturnStringResponse("Guest")
if GetUserRankInGroup(playerid, groupid) == 0:
return MakeReturnStringResponse("Guest")
Roleset : GroupRole = GetUserRolesetInGroup(playerid, groupid)
return MakeReturnStringResponse(Roleset.name)
except GroupExceptions.GroupDoesNotExist:
return MakeReturnStringResponse("Guest")
except GroupExceptions.UserDoesNotExist:
return MakeReturnStringResponse("Guest")
elif method == "IsFriendsWith":
try:
if playerid is None or userid is None:
return MakeReturnFalseResponse()
if playerid < 1 or userid < 1:
return MakeReturnFalseResponse()
FriendRelationshipObj : FriendRelationship = friends.GetFriendRelationship(playerid, userid)
if FriendRelationshipObj is None:
return MakeReturnFalseResponse()
return MakeReturnTrueResponse()
except Exception as e:
logging.error(f"IsFriendsWith: {e}")
return MakeReturnFalseResponse()
return MakeReturnFalseResponse()
@LuaWebServiceRoute.route("/Game/GamePass/GamePassHandler.ashx", methods=['GET'])
def GamePassHandler():
Action = request.args.get("Action", None, str)
UserID = request.args.get("UserID", None, int)
PassID = request.args.get("PassID", None, int)
if Action is None or UserID is None or PassID is None:
return MakeReturnFalseResponse()
if Action == "HasPass":
AssetObj : Asset = Asset.query.filter_by(id=PassID).first()
if AssetObj is None:
return MakeReturnFalseResponse()
if AssetObj.asset_type != AssetType.GamePass:
return MakeReturnFalseResponse()
UserAssetObj : UserAsset = UserAsset.query.filter_by(userid=UserID, assetid=PassID).first()
if UserAssetObj is None:
return MakeReturnFalseResponse()
return MakeReturnTrueResponse()
return MakeReturnFalseResponse()
@LuaWebServiceRoute.route("/user/request-friendship", methods=['POST'])
@auth.authenticated_client_endpoint
@csrf.exempt
@limiter.limit("1/second")
def RequestFriendship():
UserID = request.args.get("recipientUserId", None, int)
if UserID is None:
return jsonify({"success": False, "message": "Invalid request"}), 400
AuthenticatedUser : User = auth.GetCurrentUser()
if AuthenticatedUser.id == UserID:
return jsonify({"success": False, "message": "Invalid request"}), 400
TargetUserObj : User = User.query.filter_by(id=UserID).first()
if TargetUserObj is None:
return jsonify({"success": False, "message": "Invalid request"}), 400
TargetPlaceServerPlayerObj : PlaceServerPlayer | None = PlaceServerPlayer.query.filter_by(userid=UserID).first()
if TargetPlaceServerPlayerObj is None:
return jsonify({"success": False, "message": "Invalid request"}), 400
AuthenticatedPlaceServerPlayerObj : PlaceServerPlayer | None = PlaceServerPlayer.query.filter_by(userid=AuthenticatedUser.id).first()
if AuthenticatedPlaceServerPlayerObj is None:
return jsonify({"success": False, "message": "Invalid request"}), 400
if TargetPlaceServerPlayerObj.serveruuid != AuthenticatedPlaceServerPlayerObj.serveruuid:
return jsonify({"success": False, "message": "Invalid request"}), 400
FriendRelationshipObj : FriendRelationship | None = friends.GetFriendRelationship(AuthenticatedUser.id, UserID)
if FriendRelationshipObj is not None:
return jsonify({"success": True }),200
FriendRequestObj : FriendRequest | None = FriendRequest.query.filter_by(requester_id=AuthenticatedUser.id, requestee_id=UserID).first()
if FriendRequestObj is not None:
return jsonify({"success": True }),200
FriendRequestObj : FriendRequest | None = FriendRequest.query.filter_by(requester_id=UserID, requestee_id=AuthenticatedUser.id).first()
if FriendRequestObj is not None:
FriendRelationshipObj : FriendRelationship = FriendRelationship(
user_id=AuthenticatedUser.id,
friend_id=UserID
)
db.session.add(FriendRelationshipObj)
db.session.delete(FriendRequestObj)
db.session.commit()
return jsonify({"success": True }),200
FriendRequestObj : FriendRequest = FriendRequest(
requester_id=AuthenticatedUser.id,
requestee_id=UserID
)
db.session.add(FriendRequestObj)
db.session.commit()
return jsonify({"success": True }),200
@LuaWebServiceRoute.route("/user/decline-friend-request", methods=['POST'])
@auth.authenticated_client_endpoint
@csrf.exempt
@limiter.limit("1/second")
def DeclineFriendRequest():
UserID = request.args.get("requesterUserId", None, int)
if UserID is None:
jsonify({"success": False, "message": "Invalid request"}), 400
AuthenticatedUser : User = auth.GetCurrentUser()
if AuthenticatedUser.id == UserID:
jsonify({"success": False, "message": "Invalid request"}), 400
TargetUserObj : User = User.query.filter_by(id=UserID).first()
if TargetUserObj is None:
jsonify({"success": False, "message": "Invalid request"}), 400
FriendRequestObj : FriendRequest | None = FriendRequest.query.filter_by(requester_id=UserID, requestee_id=AuthenticatedUser.id).first()
if FriendRequestObj is None:
FriendRelationshipObj : FriendRelationship | None = friends.GetFriendRelationship(AuthenticatedUser.id, UserID)
if FriendRelationshipObj is None:
jsonify({"success": False, "message": "Invalid request"}), 400
db.session.delete(FriendRelationshipObj)
db.session.commit()
return jsonify({"success": True }),200
db.session.delete(FriendRequestObj)
db.session.commit()
return jsonify({"success": True }),200
@LuaWebServiceRoute.route("/user/following-exists", methods=["GET"])
@limiter.limit("60/minute")
def FollowingExists():
UserID = request.args.get("userId", None, int)
FollowerUserID = request.args.get("followerUserId", None, int)
if UserID is None or FollowerUserID is None:
return jsonify({"success": False, "isFollowing": False})
FollowedUserObj : User = User.query.filter_by(id=UserID).first()
FollowerUserObj : User = User.query.filter_by(id=FollowerUserID).first()
if FollowedUserObj is None or FollowerUserObj is None:
return jsonify({"success": False, "isFollowing": False})
return jsonify({"success": True, "isFollowing": followings.is_following( follower_user = FollowerUserObj, followed_user = FollowedUserObj)})
@LuaWebServiceRoute.route("/user/get-friendship-count", methods=["GET"])
@limiter.limit("60/minute")
def GetFriendshipCount():
UserID = request.args.get("userId", None, int)
if UserID is None:
AuthenticatedUser = auth.GetCurrentUser()
if AuthenticatedUser is None:
return jsonify({"success": False, "count": 0})
UserID = AuthenticatedUser.id
FriendRelationshipCount : int = FriendRelationship.query.filter(or_( FriendRelationship.user_id == UserID, FriendRelationship.friend_id == UserID)).count()
return jsonify({"success": True, "count": FriendRelationshipCount})
@LuaWebServiceRoute.route("/user/follow", methods=["POST"])
@csrf.exempt
@auth.authenticated_client_endpoint
@limiter.limit("20/minute")
def FollowUser():
AuthenticatedUser : User = auth.GetCurrentUser()
if AuthenticatedUser is None:
return jsonify({"success": False, "message": "Unauthorized"}),401
TargetUserId = request.form.get("followedUserId", None, int)
if TargetUserId is None:
return jsonify({"success": False, "message": "Invalid request"}),400
if TargetUserId == AuthenticatedUser.id:
return jsonify({"success": False, "message": "Invalid request"}),400
TargetUserObj : User = User.query.filter_by(id=TargetUserId).first()
if TargetUserObj is None:
return jsonify({"success": False, "message": "Invalid request"}),400
try:
followings.follow_user(
follower_user = AuthenticatedUser,
followed_user = TargetUserObj
)
except followings.FollowingExceptions.AlreadyFollowing:
return jsonify({"success": True}),200
except followings.FollowingExceptions.UserRateLimited:
return jsonify({"success": False, "message": "Rate limited"}),429
except followings.FollowingExceptions.FollowingIsDisabled:
return jsonify({"success": False, "message": "Following is disabled"}),400
return jsonify({"success": True}),200
@LuaWebServiceRoute.route("/user/unfollow", methods=["POST"])
@csrf.exempt
@auth.authenticated_client_endpoint
@limiter.limit("20/minute")
def UnfollowUser():
AuthenticatedUser : User = auth.GetCurrentUser()
if AuthenticatedUser is None:
return jsonify({"success": False, "message": "Unauthorized"}),401
TargetUserId = request.form.get("followedUserId", None, int)
if TargetUserId is None:
return jsonify({"success": False, "message": "Invalid request"}),400
if TargetUserId == AuthenticatedUser.id:
return jsonify({"success": False, "message": "Invalid request"}),400
TargetUserObj : User = User.query.filter_by(id=TargetUserId).first()
if TargetUserObj is None:
return jsonify({"success": False, "message": "Invalid request"}),400
try:
followings.unfollow_user(
current_follower = AuthenticatedUser,
followed_user = TargetUserObj
)
except followings.FollowingExceptions.UserNotFollowing:
return jsonify({"success": True}),200
except followings.FollowingExceptions.UserRateLimited:
return jsonify({"success": False, "message": "Rate limited"}),429
return jsonify({"success": True}),200
@LuaWebServiceRoute.route("/my/economy-status", methods=["GET"])
@auth.authenticated_client_endpoint
def EconomyStatus():
return jsonify({
"success": True,
"isMarketplaceEnabled": websiteFeatures.GetWebsiteFeature("EconomyPurchase")
})
@LuaWebServiceRoute.route("/currency/balance", methods=["GET"])
@auth.authenticated_client_endpoint
def EconomyBalance():
AuthenticatedUser : User = auth.GetCurrentUser()
if AuthenticatedUser is None:
return jsonify({"success": False, "message": "Unauthorized"}),401
RobuxBal, TixBal = economy.GetUserBalance(AuthenticatedUser)
return jsonify({
"success": True,
"robux": RobuxBal,
"tickets": TixBal
})
@LuaWebServiceRoute.route("/ownership/hasasset", methods=["GET"])
@LuaWebServiceRoute.route("/ownership/hasAsset", methods=["GET"])
@auth.gameserver_authenticated_required
def HasAsset():
AssetID = request.args.get("assetId", None, int)
if AssetID is None:
return jsonify({"success": False, "message": "Invalid request"}),400
UserId = request.args.get("userId", None, int)
if UserId is None:
return jsonify({"success": False, "message": "Invalid request"}),400
AssetObj : Asset = Asset.query.filter_by(id=AssetID).first()
if AssetObj is None:
return "false",200
UserAssetObj : UserAsset = UserAsset.query.filter_by(userid=UserId, assetid=AssetID).first()
if UserAssetObj is None:
return "false",200
return "true",200
@LuaWebServiceRoute.route("/Friend/AreFriends", methods=["GET"])
@auth.gameserver_authenticated_required
def AreFriends():
userId = request.args.get("userId", None, int)
otherUserId = request.args.get("otherUserId", None, int)
otherUserIdList = request.args.getlist("otherUserIds")
if userId is None or ( otherUserId is None and len(otherUserIdList) == 0):
return jsonify({"success": False, "message": "Invalid request"}),400
if otherUserId is not None:
FriendRelationshipObj : FriendRelationship = friends.GetFriendRelationship(userId, otherUserId)
if FriendRelationshipObj is not None:
return jsonify({"success": True, "friendStatus": 2})
FriendRequestObj : FriendRequest = FriendRequest.query.filter_by(requester_id = userId, requestee_id=otherUserId).first()
if FriendRequestObj is not None:
return jsonify({"success": True, "friendStatus": 3})
FriendRequestObj : FriendRequest = FriendRequest.query.filter_by(requester_id = otherUserId, requestee_id=userId).first()
if FriendRequestObj is not None:
return jsonify({"success": True, "friendStatus": 4})
return jsonify({"success": True, "friendStatus": 1})
else:
if len(otherUserIdList) > 100:
return jsonify({"success": False, "message": "Invalid request"}),400
RequestResult = ""
for TargetUserId in otherUserIdList:
try:
TargetUserId = int(TargetUserId)
except:
continue
FriendRelationshipObj : FriendRelationship = friends.GetFriendRelationship(userId, TargetUserId)
if FriendRelationshipObj is not None:
RequestResult += f"{str(TargetUserId)},"
continue
return RequestResult,200
@LuaWebServiceRoute.route("/Friend/CreateFriend", methods=["POST"])
@csrf.exempt
@auth.gameserver_authenticated_required
def CreateFriend():
firstUserId = request.args.get( "firstUserId", default = None, type = int )
secondUserId = request.args.get( "secondUserId", default = None, type = int )
if firstUserId is None or secondUserId is None:
return jsonify({"success": False, "message": "Invalid request"}),400
firstUserObj : User = User.query.filter_by(id=firstUserId).first()
secondUserObj : User = User.query.filter_by(id=secondUserId).first()
if firstUserObj is None or secondUserObj is None:
return jsonify({"success": False, "message": "Invalid request"}),400
FriendRelationshipObj : FriendRelationship = friends.GetFriendRelationship(firstUserId, secondUserId)
if FriendRelationshipObj is not None:
return jsonify({"success": True}),200
FriendRequestObj : FriendRequest = FriendRequest.query.filter_by(requester_id=firstUserId, requestee_id=secondUserId).first()
if FriendRequestObj is not None:
db.session.delete(FriendRequestObj)
SecondFriendRequestObj : FriendRequest = FriendRequest.query.filter_by(requester_id=secondUserId, requestee_id=firstUserId).first()
if SecondFriendRequestObj is not None:
db.session.delete(SecondFriendRequestObj)
FriendRelationshipObj = FriendRelationship(
user_id=firstUserId,
friend_id=secondUserId
)
db.session.add(FriendRelationshipObj)
db.session.commit()
return jsonify({"success": True}),200
@LuaWebServiceRoute.route("/Friend/BreakFriend", methods=["POST"])
@csrf.exempt
@auth.gameserver_authenticated_required
def BreakFriend():
firstUserId = request.args.get( "firstUserId", default = None, type = int )
secondUserId = request.args.get( "secondUserId", default = None, type = int )
if firstUserId is None or secondUserId is None:
return jsonify({"success": False, "message": "Invalid request"}),400
firstUserObj : User = User.query.filter_by(id=firstUserId).first()
secondUserObj : User = User.query.filter_by(id=secondUserId).first()
if firstUserObj is None or secondUserObj is None:
return jsonify({"success": False, "message": "Invalid request"}),400
FriendRelationshipObj : FriendRelationship = friends.GetFriendRelationship(firstUserId, secondUserId)
if FriendRelationshipObj is not None:
db.session.delete(FriendRelationshipObj)
db.session.commit()
return jsonify({"success": True}),200
@LuaWebServiceRoute.route("/Friend/CreateFriendRequest", methods=["POST"])
@csrf.exempt
@auth.gameserver_authenticated_required
def CreateFriendRequest():
requesterUserId = request.args.get( "requesterUserId", default = None, type = int )
requestedUserId = request.args.get( "requestedUserId", default = None, type = int )
if requesterUserId is None or requestedUserId is None:
return jsonify({"success": False, "message": "Invalid request"}),400
requesterUserObj : User = User.query.filter_by(id=requesterUserId).first()
requestedUserObj : User = User.query.filter_by(id=requestedUserId).first()
if requesterUserObj is None or requestedUserObj is None:
return jsonify({"success": False, "message": "Invalid request"}),400
FriendRelationshipObj : FriendRelationship = friends.GetFriendRelationship(requesterUserId, requestedUserId)
if FriendRelationshipObj is not None:
return jsonify({"success": True}),200
FriendRequestObj : FriendRequest = FriendRequest.query.filter_by(requester_id=requesterUserId, requestee_id=requestedUserId).first()
OtherFriendRequestObj : FriendRequest = FriendRequest.query.filter_by(requester_id=requestedUserId, requestee_id=requesterUserId).first()
if FriendRequestObj is not None and OtherFriendRequestObj is None:
return jsonify({"success": True}),200
if OtherFriendRequestObj is not None:
if FriendRequestObj is not None:
db.session.delete(FriendRequestObj)
db.session.delete(OtherFriendRequestObj)
FriendRelationshipObj = FriendRelationship(
user_id=requesterUserId,
friend_id=requestedUserId
)
db.session.add(FriendRelationshipObj)
db.session.commit()
return jsonify({"success": True}),200
FriendRequestObj = FriendRequest(
requester_id=requesterUserId,
requestee_id=requestedUserId
)
db.session.add(FriendRequestObj)
db.session.commit()
return jsonify({"success": True}),200
@LuaWebServiceRoute.route("/Friend/DeleteFriendRequest", methods=["POST"])
@csrf.exempt
@auth.gameserver_authenticated_required
def DeleteFriendRequest():
requesterUserId = request.args.get( "requesterUserId", default = None, type = int )
requestedUserId = request.args.get( "requestedUserId", default = None, type = int )
if requesterUserId is None or requestedUserId is None:
return jsonify({"success": False, "message": "Invalid request"}),400
requesterUserObj : User = User.query.filter_by(id=requesterUserId).first()
requestedUserObj : User = User.query.filter_by(id=requestedUserId).first()
if requesterUserObj is None or requestedUserObj is None:
return jsonify({"success": False, "message": "Invalid request"}),400
FriendRequestObj : FriendRequest = FriendRequest.query.filter_by(requester_id=requesterUserId, requestee_id=requestedUserId).first()
if FriendRequestObj is not None:
db.session.delete(FriendRequestObj)
db.session.commit()
return jsonify({"success": True}),200
@LuaWebServiceRoute.route("/v2/users//groups/roles", methods=["GET"])
def GetUserGroupRoles( userId : int ):
if userId is None:
return jsonify({"success": False, "message": "Invalid request"}),400
UserObj : User = User.query.filter_by(id=userId).first()
if UserObj is None:
return jsonify({"success": False, "message": "Invalid request"}),400
GroupRoles = []
UserGroupMemberList : list[GroupMember] = GroupMember.query.filter_by(user_id = userId).all()
for GroupMemberObj in UserGroupMemberList:
GroupRoles.append({
"group": {
"id": GroupMemberObj.group_id,
"name": GroupMemberObj.group.name,
"memberCount": GetGroupMemberCount(GroupMemberObj.group)
},
"role" : {
"id": GroupMemberObj.group_role_id,
"name": GroupMemberObj.group_role.name,
"rank": GroupMemberObj.group_role.rank
}
})
if GroupMemberObj.group_id == config.ADMIN_GROUP_ID:
GroupRoles.append({
"group": {
"id": 1200769,
"name": GroupMemberObj.group.name,
"memberCount": GetGroupMemberCount(GroupMemberObj.group)
},
"role" : {
"id": GroupMemberObj.group_role_id,
"name": GroupMemberObj.group_role.name,
"rank": GroupMemberObj.group_role.rank
}
})
return jsonify({
"data": GroupRoles
})
@LuaWebServiceRoute.route("/users/get-by-username/", methods=["GET"])
def GetUserByUsername():
RequestedUsername = request.args.get(
key = "username",
default = None,
type = str
)
if RequestedUsername is None:
return jsonify({"success": False, "message": "Invalid request"}),400
UserObj : User = User.query.filter(func.lower(User.username) == func.lower(RequestedUsername)).first()
if UserObj is None:
return jsonify({"success": False, "message": "Invalid request"}),400
return jsonify({
"Id": UserObj.id,
"Username": UserObj.username
}), 200