From 2cc969c2c94682c5eaf22d83aa8ebb4afadc46de Mon Sep 17 00:00:00 2001 From: ThisBirchWood Date: Thu, 6 Feb 2025 00:17:40 +0000 Subject: [PATCH 1/3] REFACTOR: Organised routes into groups, may still move user routes into user blueprint --- web_server/blueprints/streams.py | 104 +++++++++++++++---------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/web_server/blueprints/streams.py b/web_server/blueprints/streams.py index f0a6c62..871a364 100644 --- a/web_server/blueprints/streams.py +++ b/web_server/blueprints/streams.py @@ -1,12 +1,10 @@ from flask import Blueprint, session, jsonify, g, request, redirect, abort, send_from_directory from utils.stream_utils import * +from utils.recommendation_utils import * from utils.user_utils import get_user_id from blueprints.utils import login_required -from utils.recommendation_utils import * -from utils.utils import most_popular_category from database.database import Database from datetime import datetime - from celery_tasks import update_thumbnail stream_bp = Blueprint("stream", __name__) @@ -14,6 +12,8 @@ stream_bp = Blueprint("stream", __name__) # Constants THUMBNAIL_GENERATION_INTERVAL = 180 + +## Stream Routes @stream_bp.route('/streams/popular/') def get_popular_streams(no_streams) -> list[dict]: """ @@ -31,7 +31,6 @@ def get_popular_streams(no_streams) -> list[dict]: streams = get_highest_view_streams(no_streams) return jsonify(streams) - @login_required @stream_bp.route('/streams/recommended') def get_recommended_streams() -> list[dict]: @@ -46,6 +45,8 @@ def get_recommended_streams() -> list[dict]: streams = get_streams_based_on_category(category) return streams + +## Category Routes @stream_bp.route('/categories/popular/') def get_popular_categories(no_categories) -> list[dict]: """ @@ -71,51 +72,6 @@ def get_recommended_categories() -> list | list[dict]: categories = get_user_category_recommendations(user_id) return jsonify(categories) - -@stream_bp.route('/user/') -def get_user_data(username): - """ - Returns a given user's data - """ - user_id = get_user_id(username) - if not user_id: - abort(404) - data = get_streamer_data(user_id) - return jsonify(data) - - -@stream_bp.route('/user//status') -def get_user_live_status(streamer_username): - """ - Returns a streamer's status, if they are live or not and their most recent stream (their current stream if live) - """ - user_id = get_user_id(streamer_username) - - is_live = True if get_streamer_live_status(user_id)['is_live'] else False - - most_recent_vod = get_latest_vod(user_id) - - if not most_recent_vod: - most_recent_vod = None - else: - most_recent_vod = most_recent_vod['vod_id'] - - return jsonify({ - "is_live": is_live, - "most_recent_stream": most_recent_vod - }) - - -@stream_bp.route('/user//vods') -def get_vods(streamer_username): - """ - Returns a JSON of all the vods of a streamer - """ - user_id = get_user_id(streamer_username) - vods = get_user_vods(user_id) - return jsonify(vods) - - @login_required @stream_bp.route('/categories/following') def get_following_categories_streams(): @@ -127,8 +83,42 @@ def get_following_categories_streams(): return jsonify(streams) +## User Routes +@stream_bp.route('/user/') +def get_user_data(username): + """ + Returns a given user's data + """ + user_id = get_user_id(username) + if not user_id: + abort(404) + data = get_streamer_data(user_id) + return jsonify(data) + +@stream_bp.route('/user//status') +def get_user_live_status(username): + """ + Returns a streamer's status, if they are live or not and their most recent stream (their current stream if live) + """ + user_id = get_user_id(username) + + # Check if streamer is live and get their most recent vod + is_live = True if get_streamer_live_status(user_id)['is_live'] else False + most_recent_vod = get_latest_vod(user_id) + + # If there is no most recent vod, set it to None + if not most_recent_vod: + most_recent_vod = None + else: + most_recent_vod = most_recent_vod['vod_id'] + + return jsonify({ + "is_live": is_live, + "most_recent_stream": most_recent_vod + }) + @login_required -@stream_bp.route('/users/following') +@stream_bp.route('/user/following') def get_followed_streamers_(): """ Queries DB to get a list of followed streamers @@ -138,6 +128,18 @@ def get_followed_streamers_(): live_following_streams = get_followed_streamers(user_id) return live_following_streams + +## VOD Routes +@stream_bp.route('/vods/') +def get_vods(username): + """ + Returns a JSON of all the vods of a streamer + """ + user_id = get_user_id(username) + vods = get_user_vods(user_id) + return jsonify(vods) + + ## RTMP Server Routes @stream_bp.route("/publish_stream", methods=["POST"]) def publish_stream(): @@ -184,6 +186,4 @@ def end_stream(): # Remove stream from database db.execute("""DELETE FROM streams WHERE user_id = ?""", (user_info["user_id"],)) - # - return "Stream ended", 200 \ No newline at end of file From 4b0bbb12ae3fb4760052f4b489bf6231b35233f7 Mon Sep 17 00:00:00 2001 From: ThisBirchWood Date: Thu, 6 Feb 2025 00:21:53 +0000 Subject: [PATCH 2/3] UPDATE: Removed unnecessary imports --- web_server/blueprints/streams.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_server/blueprints/streams.py b/web_server/blueprints/streams.py index 871a364..c333ade 100644 --- a/web_server/blueprints/streams.py +++ b/web_server/blueprints/streams.py @@ -1,4 +1,4 @@ -from flask import Blueprint, session, jsonify, g, request, redirect, abort, send_from_directory +from flask import Blueprint, session, jsonify, request, redirect, abort from utils.stream_utils import * from utils.recommendation_utils import * from utils.user_utils import get_user_id From 6a8509ca42aabefb8e3cb9289fee4bda902e6b93 Mon Sep 17 00:00:00 2001 From: ThisBirchWood Date: Thu, 6 Feb 2025 01:00:46 +0000 Subject: [PATCH 3/3] REFACTOR: Moved user routes into user blueprint, and grouped them, fixed some (not all) routes --- web_server/blueprints/streams.py | 22 ---------- web_server/blueprints/user.py | 62 +++++++++++++++++++-------- web_server/database/app.db | Bin 81920 -> 86016 bytes web_server/database/testing_data.sql | 6 ++- web_server/database/users.sql | 2 +- web_server/utils/stream_utils.py | 23 ---------- web_server/utils/user_utils.py | 44 +++++++++++++++---- 7 files changed, 84 insertions(+), 75 deletions(-) diff --git a/web_server/blueprints/streams.py b/web_server/blueprints/streams.py index c333ade..6e6b1c3 100644 --- a/web_server/blueprints/streams.py +++ b/web_server/blueprints/streams.py @@ -84,17 +84,6 @@ def get_following_categories_streams(): ## User Routes -@stream_bp.route('/user/') -def get_user_data(username): - """ - Returns a given user's data - """ - user_id = get_user_id(username) - if not user_id: - abort(404) - data = get_streamer_data(user_id) - return jsonify(data) - @stream_bp.route('/user//status') def get_user_live_status(username): """ @@ -117,17 +106,6 @@ def get_user_live_status(username): "most_recent_stream": most_recent_vod }) -@login_required -@stream_bp.route('/user/following') -def get_followed_streamers_(): - """ - Queries DB to get a list of followed streamers - """ - user_id = session.get('user_id') - - live_following_streams = get_followed_streamers(user_id) - return live_following_streams - ## VOD Routes @stream_bp.route('/vods/') diff --git a/web_server/blueprints/user.py b/web_server/blueprints/user.py index 456b893..c51c1d2 100644 --- a/web_server/blueprints/user.py +++ b/web_server/blueprints/user.py @@ -1,11 +1,23 @@ -from flask import Blueprint, jsonify, session -from utils.user_utils import is_subscribed, is_following, subscription_expiration, verify_token, reset_password, get_user_id, unfollow +from flask import Blueprint, jsonify, session, abort +from utils.user_utils import * from blueprints.utils import login_required user_bp = Blueprint("user", __name__) +@user_bp.route('/user/') +def get_user_data_(username): + """ + Returns a given user's data + """ + user_id = get_user_id(username) + if not user_id: + abort(404) + data = get_user_data(user_id) + return jsonify(data) + +## Subscription Routes @login_required -@user_bp.route('/is_subscribed/') +@user_bp.route('/user/subscription/') def user_subscribed(subscribed_id: int): """ Checks to see if user is subscribed to another user @@ -15,17 +27,30 @@ def user_subscribed(subscribed_id: int): return jsonify({"subscribed": True}) return jsonify({"subscribed": False}) -@user_bp.route('/is_following//') -def user_following(user_id: int, subscribed_id: int): +@login_required +@user_bp.route('/user/subscription//expiration') +def user_subscription_expiration(subscribed_id: int): + """ + Returns remaining time until subscription expiration + """ + + user_id = session.get("user_id") + remaining_time = subscription_expiration(user_id, subscribed_id) + + return jsonify({"remaining_time": remaining_time}) + +## Follow Routes +@user_bp.route('/user//follows/') +def user_following(user_id: int, followed_id: int): """ Checks to see if user is following a streamer """ - if is_following(user_id, subscribed_id): + if is_following(user_id, followed_id): return jsonify({"following": True}) return jsonify({"following": False}) @login_required -@user_bp.route('/follow/') +@user_bp.route('/user/follow/') def follow(username): """ Follows a user @@ -34,9 +59,8 @@ def follow(username): following_id = get_user_id(username) follow(user_id, following_id) - @login_required -@user_bp.route('/unfollow/') +@user_bp.route('/user/unfollow/') def user_unfollow(followed_username): """ Unfollows a user @@ -46,18 +70,18 @@ def user_unfollow(followed_username): unfollow(user_id, followed_id) @login_required -@user_bp.route('/subscription_remaining/') -def user_subscription_expiration(streamer_id: int): +@user_bp.route('/user/following') +def get_followed_streamers_(): """ - Returns remaining time until subscription expiration + Queries DB to get a list of followed streamers """ + user_id = session.get('user_id') - user_id = session.get("user_id") - remaining_time = subscription_expiration(user_id, streamer_id) + live_following_streams = get_followed_streamers(user_id) + return live_following_streams - return jsonify({"remaining_time": remaining_time}) - -@user_bp.route('/get_login_status') +## Login Routes +@user_bp.route('/user/login_status') def get_login_status(): """ Returns whether the user is logged in or not @@ -65,7 +89,7 @@ def get_login_status(): username = session.get("username") return jsonify({'status': username is not None, 'username': username}) -@user_bp.route('/forgot_password/', methods=['POST']) +@user_bp.route('/user/forgot_password/', methods=['POST']) def user_forgot_password(email): """ Will send link to email to reset password by looking at the user_id within session to see whos password should be reset @@ -74,7 +98,7 @@ def user_forgot_password(email): return -@user_bp.route('/reset_password//') +@user_bp.route('/user/reset_password//') def user_reset_password(token, new_password): """ Given token and new password resets the users password diff --git a/web_server/database/app.db b/web_server/database/app.db index 718f8d2e07f9237fc29c26a1c7ff2fc8da3bcd0f..2c84a0199beec9d216a44d9eba07ce4afcf4debe 100644 GIT binary patch delta 1324 zcmdT^TSyd97@mJ-&YYc@b^le?6vt>+ibZm4FJ3kS#UOesD`Lx9EiaW%o0kZJ$XxYJ zQU=k{;vtAUat^o3HEy4;uBxgo zXk3f#%vsGwgV~k28YS)$73(=n;Rj6M4Bo*w4r3p-VH4Jy`EEBJbgCkNhmwFVP^J4q zdeG-oEJVyfWD5~;5SxYYSp=yFvWFTY;}-=LADVRHKC-YXg8`_hq^%&QEpL<9cA)0l zDZjgbVu-`f_yX_Y2zKL946)kE@QOwWtIb1m(y)Zpx-X#nt4k!p5_)L1gg;y$R6;B+ zr>QKbiB?cCL+;l7fi&r7o+enNU^QQ?`+Yj&tdxG{X}rbq#;as8$i~-Xsmq4*9IoIm zT*5Dy#07kV^Q?FiUBo7^#sxyx4A0aDGBuK^9fA#?oAk#s%%_4aa~d>r8t+%V&OLc6 z9HkKsC+&KUivLx|hYQl;&VHq*|AD;cKxE@NSz4rNFr=CfXek)qpjuMO zHxv5rD?(o%{Eb(H!uq6`;BXm#;&=Rni}(%`Ohk{dYNI|ROD2R^s7OT13Zh_HUf_u+ HgUtU1m)teJ delta 1231 zcmchXO=uHA6vyZ7?(FPGnzyahXi_k1l^Sd`AFcgBTPiAkwN$GX^&l#Oq7u}KCv8n= zZpGF;L_x4c5J9cbMFT>MC{8*HhVR!L?LT_(WXFkv`;PI=YF2?XCbnCjlr_+1n`#HpZL+7y zmwMd@^Q|GR6t>!rwZj0dcGz`B)Z=FpEzINdL3dmFTMd+f)v1+O_r*EZO}$Fi0_Wx> zn)~`M!j{yBI%t8->1Fkh1lVMuI0YNiw^o4yupxDKHJqe1vS(M+IViQh0V-jo{ff4O zHHcfGWynbGRjd8ss`_YkeZ)E+TUIc87>nj-_MaH_FE-rc1Sjz$KF51_9aEUZ4&0Be z*nmOwq3ZtS9=D7A!|qPQkN`|ZBcVuDFjO0ih75FwR6yJg5erC>Lxem*mjtTG^1#ru zOXNaf%^`)tYQRB-%8Ek@m04C!@=(aGhi z4~K$0;LNMf z2LAo}FXT>HE68J3Mrr!bPB_lEo39pnAs}(G$FW0ta3QoA73>aC Optional[List[dict]]: """, (user_id,)) return live_streams -def get_followed_streamers(user_id: int) -> Optional[List[dict]]: - """ - Returns a list of streamers who the user follows - """ - with Database() as db: - followed_streamers = db.fetchall(""" - SELECT user_id, username - FROM users - WHERE user_id IN (SELECT followed_id FROM follows WHERE user_id = ?); - """, (user_id,)) - return followed_streamers - def get_vod(vod_id: int) -> dict: """ Returns data of a streamers vod @@ -71,17 +59,6 @@ def get_user_vods(user_id: int): return vods -def get_streamer_data(user_id: int) -> Optional[dict]: - """ - Returns information about the streamer - """ - with Database() as db: - data = db.fetchone(""" - SELECT username, bio, num_followers, is_partnered FROM users - WHERE user_id = ?; - """, (user_id,)) - return data - def generate_thumbnail(user_id: int) -> None: """ Generates the thumbnail of a stream diff --git a/web_server/utils/user_utils.py b/web_server/utils/user_utils.py index c4bb5fc..bb1c4f0 100644 --- a/web_server/utils/user_utils.py +++ b/web_server/utils/user_utils.py @@ -1,5 +1,5 @@ from database.database import Database -from typing import Optional +from typing import Optional, List from datetime import datetime from itsdangerous import URLSafeTimedSerializer from os import getenv @@ -45,19 +45,22 @@ def is_user_partner(user_id: int) -> bool: """, (user_id,)) return bool(data) -def is_subscribed(user_id: int, streamer_id: int) -> bool: +def is_subscribed(user_id: int, subscribed_to_id: int) -> bool: """ Returns True if user is subscribed to a streamer, else False """ with Database() as db: result = db.fetchone(""" - SELECT 1 + SELECT * FROM subscribes WHERE user_id = ? - AND streamer_id = ? - AND expires > ? - """, (user_id, streamer_id, datetime.now())) - return bool(result) + AND subscribed_id = ? + AND expires > ?; + """, (user_id, subscribed_to_id, datetime.now())) + print(result) + if result: + return True + return False def is_following(user_id: int, followed_id: int) -> bool: """ @@ -108,7 +111,7 @@ def subscription_expiration(user_id: int, subscribed_id: int) -> int: with Database() as db: data = db.fetchone(""" SELECT expires - FROM subscriptions + FROM subscribes WHERE user_id = ? AND subscribed_id = ? AND expires > ? @@ -149,4 +152,27 @@ def get_email(user_id: int) -> Optional[str]: WHERE user_id = ? """, (user_id,)) - return email["email"] if email else None \ No newline at end of file + return email["email"] if email else None + +def get_followed_streamers(user_id: int) -> Optional[List[dict]]: + """ + Returns a list of streamers who the user follows + """ + with Database() as db: + followed_streamers = db.fetchall(""" + SELECT user_id, username + FROM users + WHERE user_id IN (SELECT followed_id FROM follows WHERE user_id = ?); + """, (user_id,)) + return followed_streamers + +def get_user_data(user_id: int) -> Optional[dict]: + """ + Returns username, bio, number of followers, and if user is partnered from user_id + """ + with Database() as db: + data = db.fetchone(""" + SELECT username, bio, num_followers, is_partnered FROM users + WHERE user_id = ?; + """, (user_id,)) + return data \ No newline at end of file