diff options
Diffstat (limited to 'api/user')
-rw-r--r-- | api/user/avatar.py | 37 | ||||
-rw-r--r-- | api/user/games.py | 116 | ||||
-rw-r--r-- | api/user/info.py | 145 | ||||
-rw-r--r-- | api/user/password.py | 13 | ||||
-rw-r--r-- | api/user/preferences.py | 51 | ||||
-rw-r--r-- | api/user/status.py | 20 |
6 files changed, 221 insertions, 161 deletions
diff --git a/api/user/avatar.py b/api/user/avatar.py index b4edeed..1b5500a 100644 --- a/api/user/avatar.py +++ b/api/user/avatar.py @@ -10,29 +10,34 @@ default_avatar = open("database/avatars/default.png", "rb").read() avatar = Blueprint('avatar', __name__) -@avatar.route('/avatar', methods = ["GET"]) + +@avatar.route('/avatar', methods=["GET"]) def get_avatar(): - token = request.cookies.get("token") or "" - login = token_login(token) or "" + token = request.cookies.get("token") or "" + login = token_login(token) or "" + + user_id = request.args.get("id") or login + if not user_id: return "", 400 + if not valid_user_id(user_id): return "", 403 - user_id = request.args.get("id") or login - if not user_id: return "", 400 - if not valid_user_id(user_id): return "", 403 + avatar_path = f"database/avatars/{user_id}.png" + avatar = "" + if exists(avatar_path): + avatar = open(avatar_path, "rb").read() + return Response(avatar or default_avatar, 200, mimetype="image/png") - avatar_path = f"database/avatars/{user_id}.png" - avatar = "" - if exists(avatar_path): - avatar = open(avatar_path, "rb").read() - return Response(avatar or default_avatar, 200, mimetype="image/png") -@avatar.route('/avatar', methods = ["POST"]) #TODO: pillow image size validation (client side resize) +@avatar.route( + '/avatar', methods=["POST"] +) #TODO: pillow image size validation (client side resize) @auth_required("user") def update_avatar(login): - if not request.data: return "", 400 + if not request.data: return "", 400 - open(f"database/avatars/{login}.png", "wb").write(decode(request.data, "base64")) + open(f"database/avatars/{login}.png", + "wb").write(decode(request.data, "base64")) - return "", 200 + return "", 200 -dynamic_route = ["/user", avatar] +dynamic_route = ["/user", avatar] diff --git a/api/user/games.py b/api/user/games.py index 3936566..83d721a 100644 --- a/api/user/games.py +++ b/api/user/games.py @@ -8,69 +8,89 @@ from ruleset import resolve_ruleset from game.info import format_game import json + # get total game outcome amount for user -def sum_games(user_id): #! SANITIZE USER_ID FIRST - wld_querys = [' '.join([ - "select count(game_id)", - "from games", - "where", - f"player_{x[0]}_id = \"{user_id}\" and", - f"outcome = \"{x[1]}\"", - ]) for x in [(1, "w"), (1, "l"), (2, "w"), (2, "l")]] - wld_querys.insert(0, ' '.join([ - "select count(game_id)", - "from games", - "where", - f"(player_1_id = \"{user_id}\" or player_2_id = \"{user_id}\") and", - "outcome = \"d\"", - ])) - - big_query = "select " + ", ".join([f"({query})" for query in wld_querys]) - - results = cursor.execute(big_query).fetchone() - - # win and lose are calculated from user_id's perspective (player_1_id, player_2_id in db) - return { - "draw": results[0], - "win": results[1] + results[4], - "lose": results[2] + results[3], - "games": reduce(lambda a, b: a + b, results) - } +def sum_games(user_id): #! SANITIZE USER_ID FIRST + wld_querys = [ + ' '.join( + [ + "select count(game_id)", + "from games", + "where", + f"player_{x[0]}_id = \"{user_id}\" and", + f"outcome = \"{x[1]}\"", + ] + ) for x in [(1, "w"), (1, "l"), (2, "w"), (2, "l")] + ] + wld_querys.insert( + 0, ' '.join( + [ + "select count(game_id)", + "from games", + "where", + f"(player_1_id = \"{user_id}\" or player_2_id = \"{user_id}\") and", + "outcome = \"d\"", + ] + ) + ) + + big_query = "select " + ", ".join([f"({query})" for query in wld_querys]) + + results = cursor.execute(big_query).fetchone() + + # win and lose are calculated from user_id's perspective (player_1_id, player_2_id in db) + return { + "draw": results[0], + "win": results[1] + results[4], + "lose": results[2] + results[3], + "games": reduce(lambda a, b: a + b, results) + } + # get `count` games that `user_id` participated in, sorted by newest game def fetch_games(user_id, count): - game_ids = cursor.execute("select game_id from games where player_1_id = ? or player_2_id = ? order by created desc", [user_id, user_id]).fetchmany(count) - export = [] + game_ids = cursor.execute( + "select game_id from games where player_1_id = ? or player_2_id = ? order by created desc", + [user_id, user_id] + ).fetchmany(count) + export = [] + + for game_id in game_ids: + export.append(format_game(game_id[0], user_id)) - for game_id in game_ids: - export.append(format_game(game_id[0], user_id)) + return export - return export games = Blueprint('games', __name__) -@games.route('/games', methods = ['GET', 'POST']) + +@games.route('/games', methods=['GET', 'POST']) def index(): - data_string = request.data or "{}" - data = json.loads(data_string) + data_string = request.data or "{}" + data = json.loads(data_string) + + user_id = data.get("id") or "" + token = request.cookies.get("token") or "" - user_id = data.get("id") or "" - token = request.cookies.get("token") or "" + if not user_id and \ + not token: + return "", 400 - if not user_id and \ - not token: - return "", 400 + if token and not user_id: + user_id = token_login(token) - if token and not user_id: - user_id = token_login(token) + if not cursor.execute( + "select user_id from users where user_id = ?", [user_id] + ).fetchone(): + return "", 403 - if not cursor.execute("select user_id from users where user_id = ?", [user_id]).fetchone(): return "", 403 + export = {} + merge( + export, {"totals": sum_games(user_id)}, + {"games": fetch_games(user_id, 20)} + ) - export = {} - merge(export, - {"totals": sum_games(user_id)}, - {"games": fetch_games(user_id, 20)}) + return export, 200 - return export, 200 dynamic_route = ["/user", games] diff --git a/api/user/info.py b/api/user/info.py index be48ef1..de0d2e8 100644 --- a/api/user/info.py +++ b/api/user/info.py @@ -4,84 +4,103 @@ from auth.login_token import token_login from rating import get_rating import json + # check if user_id exists in database def valid_user_id(user_id): - query = cursor.execute("select user_id from users where user_id = ?", [user_id]).fetchone() - return bool(query) + query = cursor.execute( + "select user_id from users where user_id = ?", [user_id] + ).fetchone() + return bool(query) + # get relation to user_2_id from user_1_id's perspective def get_relation_to(user_1_id, user_2_id): - relation = cursor.execute("select * from social where " + \ - "(user_1_id = ? and user_2_id = ?) or " + \ - "(user_1_id = ? and user_2_id = ?)", [user_1_id, user_2_id, user_2_id, user_1_id]).fetchone() - if not relation: return "none" - if relation[2] == "friendship": return "friends" - if relation[2] == "outgoing" and relation[0] == user_1_id: return "outgoing" - if relation[2] == "outgoing" and relation[1] == user_1_id: return "incoming" - if relation[2] == "block" and relation[0] == user_1_id: return "blocked" - return "none" + relation = cursor.execute("select * from social where " + \ + "(user_1_id = ? and user_2_id = ?) or " + \ + "(user_1_id = ? and user_2_id = ?)", [user_1_id, user_2_id, user_2_id, user_1_id]).fetchone() + if not relation: return "none" + if relation[2] == "friendship": return "friends" + if relation[2] == "outgoing" and relation[0] == user_1_id: + return "outgoing" + if relation[2] == "outgoing" and relation[1] == user_1_id: + return "incoming" + if relation[2] == "block" and relation[0] == user_1_id: return "blocked" + return "none" + # get users friend count def count_friends(user_id): - query = cursor.execute("select type from social where (user_1_id = ? or user_2_id = ?) and type = \"friendship\"", [user_id, user_id]).fetchall() - return len(query) #FIXME: use SQL count() instead of python's len() + query = cursor.execute( + "select type from social where (user_1_id = ? or user_2_id = ?) and type = \"friendship\"", + [user_id, user_id] + ).fetchall() + return len(query) #FIXME: use SQL count() instead of python's len() + # get user/info of `user_id` as `viewer` (id) -def format_user(user_id, viewer = ''): - user = cursor.execute("select " + ", ".join([ - "username", - "user_id", - "country", - "registered", - "status", - ]) + " from users where user_id = ?", [user_id]).fetchone() - formatted_user = { - "username": user[0], - "id": user[1], - "country": user[2], - "registered": user[3], - "status": user[4], - "friends": count_friends(user_id), - "rating": get_rating(user_id), #TODO: calculate rating based on game analysis - } - if viewer: - #FIXME: validate viewer id? - formatted_user["relation"] = get_relation_to(viewer, user_id) - return formatted_user +def format_user(user_id, viewer=''): + user = cursor.execute( + "select " + ", ".join( + [ + "username", + "user_id", + "country", + "registered", + "status", + ] + ) + " from users where user_id = ?", [user_id] + ).fetchone() + formatted_user = { + "username": user[0], + "id": user[1], + "country": user[2], + "registered": user[3], + "status": user[4], + "friends": count_friends(user_id), + "rating": + get_rating(user_id), #TODO: calculate rating based on game analysis + } + if viewer: + #FIXME: validate viewer id? + formatted_user["relation"] = get_relation_to(viewer, user_id) + return formatted_user + info = Blueprint('info', __name__) + # view own user/info if no user_id or username is provided and is logged in, # else view user/info of user with user_id = `user_id` or username = `username` -@info.route('/info', methods = ['GET', 'POST']) +@info.route('/info', methods=['GET', 'POST']) def index(): - data_string = request.data or "{}" - data = json.loads(data_string) - - username = data.get("username") or "" - user_id = data.get("id") or "" - token = request.cookies.get("token") or "" - viewer = "" - - if not username and \ - not user_id and \ - not token: - return "", 400 - - if username: - temp_user_id = cursor.execute("select user_id from users where username = ?", [username]).fetchone() - if len(temp_user_id) > 0: user_id = temp_user_id - - if token: - self_id = token_login(token) - if not (username or user_id): - user_id = self_id - if user_id: - viewer = self_id - - if user_id and not valid_user_id(user_id): return "", 403 - user = format_user(user_id, viewer) - - return user, 200 + data_string = request.data or "{}" + data = json.loads(data_string) + + username = data.get("username") or "" + user_id = data.get("id") or "" + token = request.cookies.get("token") or "" + viewer = "" + + if all(not v for v in [username, user_id, token]): + return "", 400 + + if username: + temp_user_id = cursor.execute( + "select user_id from users where username = ?", [username] + ).fetchone() + if len(temp_user_id) > 0: user_id = temp_user_id + + if token: + self_id = token_login(token) + if not (username or user_id): + user_id = self_id + if user_id: + viewer = self_id + + if user_id and not valid_user_id(user_id): return "", 403 + user = format_user(user_id, viewer) + + return user, 200 + dynamic_route = ["/user", info] diff --git a/api/user/password.py b/api/user/password.py index 0c1cb70..ff52ba4 100644 --- a/api/user/password.py +++ b/api/user/password.py @@ -3,16 +3,17 @@ from db import cursor password = Blueprint('password', __name__) + # this endpoint is unfinished @password.route('/password') def index(): - data = request.get_json() + data = request.get_json() - if not data["password"] or \ - not data["newPassword"]: - return "", 400 + if not data["password"] or \ + not data["newPassword"]: + return "", 400 - return {}, 200 + return {}, 200 -dynamic_route = ["/user", password] +dynamic_route = ["/user", password] diff --git a/api/user/preferences.py b/api/user/preferences.py index d4e27c9..2feaade 100644 --- a/api/user/preferences.py +++ b/api/user/preferences.py @@ -4,38 +4,49 @@ from ruleset import resolve_ruleset from hierarchy import auth_required import json + # fill missing dict keys in preferences object def format_preferences(prefs): - return { - "darkMode": prefs.get("darkMode") or False, - "ruleset": resolve_ruleset(json.dumps(prefs.get("ruleset") or {}) or "default"), - "userColors": { - "diskA": prefs.get("userColors", {}).get("diskA") or "", - "diskB": prefs.get("userColors", {}).get("diskB") or "", - "background": prefs.get("userColors", {}).get("background") or "" - } - } + return { + "darkMode": + prefs.get("darkMode") or False, + "ruleset": + resolve_ruleset(json.dumps(prefs.get("ruleset") or {}) or "default"), + "userColors": { + "diskA": prefs.get("userColors", {}).get("diskA") or "", + "diskB": prefs.get("userColors", {}).get("diskB") or "", + "background": prefs.get("userColors", {}).get("background") or "" + } + } + preferences = Blueprint('preferences', __name__) -@preferences.route('/preferences', methods = ["GET"]) + +@preferences.route('/preferences', methods=["GET"]) @auth_required("user") def get_preferences(login): - user_prefs = cursor.execute("select preferences from users where user_id = ?", [login]).fetchone() - return { "preferences": format_preferences(json.loads(user_prefs[0])) }, 200 + user_prefs = cursor.execute( + "select preferences from users where user_id = ?", [login] + ).fetchone() + return {"preferences": format_preferences(json.loads(user_prefs[0]))}, 200 -@preferences.route('/preferences', methods = ["POST"]) + +@preferences.route('/preferences', methods=["POST"]) @auth_required("user") def index(login): - data = request.get_json() - new_preferences = data.get("newPreferences") or "" + data = request.get_json() + new_preferences = data.get("newPreferences") or "" - formatted_json = format_preferences(new_preferences) + formatted_json = format_preferences(new_preferences) - cursor.execute("update users set preferences = ? where user_id = ?", [json.dumps(formatted_json), login]) - connection.commit() + cursor.execute( + "update users set preferences = ? where user_id = ?", + [json.dumps(formatted_json), login] + ) + connection.commit() - return "", 200 + return "", 200 -dynamic_route = ["/user", preferences] +dynamic_route = ["/user", preferences] diff --git a/api/user/status.py b/api/user/status.py index 3adb013..e762d12 100644 --- a/api/user/status.py +++ b/api/user/status.py @@ -5,17 +5,21 @@ import json status = Blueprint('user_status', __name__) -@status.route('/status', methods = ['POST']) + +@status.route('/status', methods=['POST']) @auth_required("user") def index(user_id): - data = request.get_json() - status = data.get("status") or "" - if not status: return "", 400 + data = request.get_json() + status = data.get("status") or "" + if not status: return "", 400 - cursor.execute("update users set status = ? where user_id = ?", [status[0:200], user_id]) - connection.commit() + cursor.execute( + "update users set status = ? where user_id = ?", + [status[0:200], user_id] + ) + connection.commit() - return "", 200 + return "", 200 -dynamic_route = ["/user", status] +dynamic_route = ["/user", status] |