From 088675785c2672abbb44bd4d3475158c85d959af Mon Sep 17 00:00:00 2001 From: JustIceO7 Date: Thu, 30 Jan 2025 22:12:35 +0000 Subject: [PATCH 1/3] FEAT: Added blueprints for Google OAuth --- web_server/blueprints/oauth.py | 58 ++++++++++++++++++++++++++++++++++ web_server/requirements.txt | 3 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 web_server/blueprints/oauth.py diff --git a/web_server/blueprints/oauth.py b/web_server/blueprints/oauth.py new file mode 100644 index 0000000..f294fe9 --- /dev/null +++ b/web_server/blueprints/oauth.py @@ -0,0 +1,58 @@ +from authlib.integrations.flask_client import OAuth, OAuthError +from flask import Blueprint, url_for, jsonify, session + +oauth_bp = Blueprint("oauth", __name__) +def init_oauth(app): + oauth = OAuth(app) + + google = oauth.register( + 'google', + client_id=app.config['GOOGLE_CLIENT_ID'], + client_secret=app.config['GOOGLE_CLIENT_SECRET'], + authorize_url='https://accounts.google.com/o/oauth2/auth', + authorize_params=None, + access_token_url='https://accounts.google.com/o/oauth2/token', + access_token_params=None, + refresh_token_url=None, + redirect_uri=url_for('google.google_auth', _external=True), + scope='openid profile email', + ) + + + @oauth_bp.route('/login/google') + def login_google(): + """ + Redirects to Google's OAuth authorization page + """ + return google.authorize_redirect(url_for('google.google_auth', _external=True)) + + @oauth_bp.route('/google_auth') + def google_auth(): + try: + token = google.authorize_access_token() + user = google.parse_id_token(token) + + # check if email exists else create a database entry + user_email = user.get("email") + + session.clear() + session["username"] = "a" + session["user_id"] = 1 + + return jsonify({ + 'message': 'User authenticated successfully', + }) + + except OAuthError as e: + # Handle OAuth errors like failed authentication or invalid token + return jsonify({ + 'message': 'Authentication failed', + 'error': str(e) + }), 400 + + except Exception as e: + # Handle other unexpected errors + return jsonify({ + 'message': 'An unexpected error occurred', + 'error': str(e) + }), 500 \ No newline at end of file diff --git a/web_server/requirements.txt b/web_server/requirements.txt index 14a4a9e..71a61e1 100644 --- a/web_server/requirements.txt +++ b/web_server/requirements.txt @@ -23,4 +23,5 @@ Werkzeug==3.1.3 WTForms==3.2.1 Gunicorn==20.1.0 gevent>=22.10.2 -gevent-websocket \ No newline at end of file +gevent-websocket +flask-oauthlib==0.9.6 \ No newline at end of file From 79c8ca8b894af9b006dae8ec557e340990082995 Mon Sep 17 00:00:00 2001 From: EvanLin3141 Date: Thu, 30 Jan 2025 22:38:52 +0000 Subject: [PATCH 2/3] ADD: Toggle Button In VideoPage, toggle button now exist to show and hide chat. --- frontend/src/pages/VideoPage.tsx | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/VideoPage.tsx b/frontend/src/pages/VideoPage.tsx index 533a97d..04fbdc0 100644 --- a/frontend/src/pages/VideoPage.tsx +++ b/frontend/src/pages/VideoPage.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect } from "react"; import Navbar from "../components/Layout/Navbar"; -import Button from "../components/Layout/Button"; +import Button, { ToggleButton } from "../components/Layout/Button"; import ChatPanel from "../components/Video/ChatPanel"; import CheckoutForm, { Return } from "../components/Checkout/CheckoutForm"; import { useNavigate, useParams } from "react-router-dom"; @@ -29,6 +29,12 @@ const VideoPage: React.FC = ({ streamId }) => { const [streamData, setStreamData] = useState(); const navigate = useNavigate(); + const [isChatVisible, setIsChatVisible] = useState(false); + + const toggleChat = () => { + setIsChatVisible((prev) => !prev); + } + // useEffect(() => { // // Prevent scrolling when checkout is open // if (showCheckout) { @@ -44,8 +50,7 @@ const VideoPage: React.FC = ({ streamId }) => { useEffect(() => { // Fetch stream data for this streamer fetch( - `/api/get_stream_data/${streamerName}${ - streamId == 0 ? "" : `/${streamId}` + `/api/get_stream_data/${streamerName}${streamId == 0 ? "" : `/${streamId}` }` ).then((res) => { if (!res.ok) { @@ -72,9 +77,21 @@ const VideoPage: React.FC = ({ streamId }) => {
+ - + + {isChatVisible ? "Hide Chat" : "Show Chat"} + + + {isChatVisible && +
+ +
}
Date: Thu, 30 Jan 2025 23:34:36 +0000 Subject: [PATCH 3/3] FEAT: Login Via Chat Added Functionality where is user not register/login they can access press chat to login and pop-up appears --- frontend/src/components/Auth/AuthModal.tsx | 4 +- frontend/src/components/Video/ChatPanel.tsx | 65 ++++++++++++++++----- frontend/src/pages/VideoPage.tsx | 11 +++- 3 files changed, 61 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/Auth/AuthModal.tsx b/frontend/src/components/Auth/AuthModal.tsx index 1f6fcf6..ac224be 100644 --- a/frontend/src/components/Auth/AuthModal.tsx +++ b/frontend/src/components/Auth/AuthModal.tsx @@ -25,10 +25,10 @@ const AuthModal: React.FC = ({ onClose }) => { return ( <> {/*Background Blur*/} -
+
{/*Container*/}
diff --git a/frontend/src/components/Video/ChatPanel.tsx b/frontend/src/components/Video/ChatPanel.tsx index 1aca340..e2e0836 100644 --- a/frontend/src/components/Video/ChatPanel.tsx +++ b/frontend/src/components/Video/ChatPanel.tsx @@ -2,6 +2,8 @@ import React, { useState, useEffect, useRef } from "react"; import Input from "../Layout/Input"; import { useAuth } from "../../context/AuthContext"; import { useSocket } from "../../context/SocketContext"; +import Button from "../Layout/Button"; +import AuthModal from "../Auth/AuthModal"; interface ChatMessage { chatter_username: string; @@ -93,7 +95,22 @@ const ChatPanel: React.FC = ({ streamId }) => { } }; + //added to show login/reg if not + const [showAuthModal, setShowAuthModal] = useState(false); + + useEffect(() => { + if (showAuthModal) { + document.body.style.overflow = "hidden"; + } else { + document.body.style.overflow = "unset"; + } + return () => { + document.body.style.overflow = "unset"; + }; + }, [showAuthModal]); + return ( + <>

Stream Chat

@@ -124,24 +141,40 @@ const ChatPanel: React.FC = ({ streamId }) => {
+ {isLoggedIn && + <> setInputMessage(e.target.value)} - onKeyDown={handleKeyPress} - placeholder={isLoggedIn ? "Type a message..." : "Login to chat"} - disabled={!isLoggedIn} - extraClasses="flex-grow disabled:cursor-not-allowed" - /> - + type="text" + value={inputMessage} + onChange={(e) => setInputMessage(e.target.value)} + onKeyDown={handleKeyPress} + placeholder={isLoggedIn ? "Type a message..." : "Login to chat"} + disabled={!isLoggedIn} + extraClasses="flex-grow" + onClick={() => (!isLoggedIn && setShowAuthModal(true))} /> + + + } + + {!isLoggedIn && + + } +
-
+ {showAuthModal && ( +
+ setShowAuthModal(false)} /> +
+ )} +
+ ); }; diff --git a/frontend/src/pages/VideoPage.tsx b/frontend/src/pages/VideoPage.tsx index 04fbdc0..af7ceb1 100644 --- a/frontend/src/pages/VideoPage.tsx +++ b/frontend/src/pages/VideoPage.tsx @@ -30,6 +30,7 @@ const VideoPage: React.FC = ({ streamId }) => { const navigate = useNavigate(); const [isChatVisible, setIsChatVisible] = useState(false); + const [showAuthModal, setShowAuthModal] = useState(false); const toggleChat = () => { setIsChatVisible((prev) => !prev); @@ -72,6 +73,14 @@ const VideoPage: React.FC = ({ streamId }) => { }); }, [streamId, streamerName]); + useEffect(() => { + document.body.style.overflow = showAuthModal ? "hidden" : "unset"; + + return () => { + document.body.style.overflow = "unset"; // Cleanup + }; + }, [showAuthModal]); + return (
@@ -83,7 +92,7 @@ const VideoPage: React.FC = ({ streamId }) => { {isChatVisible ? "Hide Chat" : "Show Chat"}