diff --git a/__pycache__/app.cpython-311.pyc b/__pycache__/app.cpython-311.pyc index d2bf45c..eb089a1 100644 Binary files a/__pycache__/app.cpython-311.pyc and b/__pycache__/app.cpython-311.pyc differ diff --git a/__pycache__/app.cpython-312.pyc b/__pycache__/app.cpython-312.pyc index f32d9e3..5905808 100644 Binary files a/__pycache__/app.cpython-312.pyc and b/__pycache__/app.cpython-312.pyc differ diff --git a/app.py b/app.py index 169471a..522a053 100644 --- a/app.py +++ b/app.py @@ -4,7 +4,7 @@ import threading import logging from datetime import datetime, timedelta -from flask import Flask, render_template, Response, request, redirect, flash, jsonify, session +from flask import Flask, render_template, Response, request, redirect, flash, jsonify, session, url_for import requests from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate @@ -14,6 +14,7 @@ from playsound import playsound from dotenv import load_dotenv from twilio.rest import Client +from authlib.integrations.flask_client import OAuth # Load environment variables load_dotenv() @@ -52,7 +53,25 @@ "alerts": "sqlite:///alerts.db" } app.config['UPLOAD_FOLDER'] = 'uploads' -ALLOWED_EXTENSIONS = {"mp4"} +ALLOWED_EXTENSIONS = {"mp4"} + +# Google OAuth Configuration +app.config['GOOGLE_CLIENT_ID'] = os.getenv('GOOGLE_CLIENT_ID') +app.config['GOOGLE_CLIENT_SECRET'] = os.getenv('GOOGLE_CLIENT_SECRET') + + +# Set up Authlib OAuth +oauth = OAuth(app) +CONF_URL = 'https://accounts.google.com/.well-known/openid-configuration' +google = oauth.register( + name='google', + server_metadata_url=CONF_URL, + client_id=app.config['GOOGLE_CLIENT_ID'], + client_secret=app.config['GOOGLE_CLIENT_SECRET'], + client_kwargs={ + 'scope': 'openid email profile' + } +) db = SQLAlchemy(app) migrate = Migrate(app, db) @@ -67,8 +86,10 @@ def load_user(user_id): class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(100), unique=True, nullable=False) - password = db.Column(db.String(200), nullable=False) # increased length for hashed passwords + password = db.Column(db.String(200), nullable=True) # Changed to nullable=True email = db.Column(db.String(100), unique=True, nullable=False) + google_id = db.Column(db.String(100), unique=True, nullable=True) # ADD THIS LINE + profile_pic = db.Column(db.String(200), nullable=True) # ADD THIS LINE class Camera(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -129,6 +150,62 @@ def play_alert_sound(): logging.error(f"Error playing alert sound: {str(e)}") # Routes + +@app.route('/google/login') +def google_login(): + """Initiate Google OAuth login""" + redirect_uri = url_for('google_callback', _external=True) + return google.authorize_redirect(redirect_uri) + +@app.route('/google/callback') +def google_callback(): + """Handle Google OAuth callback""" + try: + token = google.authorize_access_token() + user_info = token.get('userinfo') + + if user_info: + google_id = user_info.get('sub') + email = user_info.get('email') + name = user_info.get('name') + picture = user_info.get('picture') + + # Check if user exists + user = User.query.filter_by(email=email).first() + + if user: + # Update Google ID and profile picture if not set + if not user.google_id: + user.google_id = google_id + if not user.profile_pic: + user.profile_pic = picture + db.session.commit() + else: + # Create new user + user = User( + username=name, + email=email, + google_id=google_id, + profile_pic=picture, + password=None # No password for OAuth users + ) + db.session.add(user) + db.session.commit() + + # Log the user in + login_user(user) + logging.info(f"User {user.username} logged in via Google OAuth.") + flash('Successfully logged in with Google!', 'success') + return redirect('/dashboard') + else: + flash('Failed to get user info from Google', 'error') + return redirect('/login_page') + + except Exception as e: + logging.error(f"Google OAuth error: {str(e)}") + flash(f'Authentication failed: {str(e)}', 'error') + return redirect('/login_page') + @app.route('/') def index(): return render_template('index.html') @@ -149,20 +226,24 @@ def login(): if not email or not password_input: flash('Email or Password Missing!!') - return redirect('/login') + return redirect('/login_page') user = User.query.filter_by(email=email).first() - if user and check_password_hash(user.password, password_input): + + # Check if user exists and has a password (not OAuth user) + if user and user.password and check_password_hash(user.password, password_input): login_user(user) logging.info(f"User {user.username} logged in successfully.") return redirect('/dashboard') + elif user and not user.password: + flash('This account uses Google Sign-In. Please use the Google login button.') + return redirect('/login_page') else: flash('Invalid email or password') logging.warning("Invalid login attempt.") - return redirect('/login') + return redirect('/login_page') return render_template('login.html') - @app.route('/register', methods=['GET', 'POST']) def register(): if request.method == 'POST': @@ -174,7 +255,7 @@ def register(): if existing_user: flash('Username or email already exists.') logging.warning("Attempted registration with existing username or email.") - return redirect('/register') + return redirect('/register_page') hashed_password = generate_password_hash(password_input) new_user = User(username=username, email=email, password=hashed_password) @@ -183,10 +264,9 @@ def register(): flash('User registered successfully! Please log in.') logging.info(f"New user {username} registered successfully.") - return redirect('/login') + return redirect('/login_page') return render_template('register.html') - @app.route('/upload') def upload(): return render_template('VideoUpload.html') @@ -850,5 +930,12 @@ def debug_gemini(): except Exception as e: return jsonify({'success': False, 'error': f'Debug failed: {str(e)}'}) +# with app.app_context(): +# db.create_all() +# print("Database tables created successfully!") + if __name__ == "__main__": + with app.app_context(): + db.create_all() app.run(debug=True) + diff --git a/create_db.py b/create_db.py new file mode 100644 index 0000000..d400f01 --- /dev/null +++ b/create_db.py @@ -0,0 +1,29 @@ +from app import app, db, User + +print("Creating database...") + +with app.app_context(): + # Drop all tables first + db.drop_all() + print("Dropped all tables") + + # Create all tables + db.create_all() + print("Created all tables") + + # Verify + from sqlalchemy import inspect + inspector = inspect(db.engine) + + tables = inspector.get_table_names() + print(f"\nTables created: {tables}") + + if 'user' in tables: + columns = inspector.get_columns('user') + print("\nColumns in user table:") + for col in columns: + print(f" - {col['name']}") + else: + print("\nERROR: user table was not created!") + +print("\nDone!") diff --git a/models/__pycache__/config_loader.cpython-312.pyc b/models/__pycache__/config_loader.cpython-312.pyc index bed0800..458dd10 100644 Binary files a/models/__pycache__/config_loader.cpython-312.pyc and b/models/__pycache__/config_loader.cpython-312.pyc differ diff --git a/models/__pycache__/fire_detection.cpython-312.pyc b/models/__pycache__/fire_detection.cpython-312.pyc index 0293841..6c7b3ef 100644 Binary files a/models/__pycache__/fire_detection.cpython-312.pyc and b/models/__pycache__/fire_detection.cpython-312.pyc differ diff --git a/models/__pycache__/gear_detection.cpython-312.pyc b/models/__pycache__/gear_detection.cpython-312.pyc index 0c75bb5..a505486 100644 Binary files a/models/__pycache__/gear_detection.cpython-312.pyc and b/models/__pycache__/gear_detection.cpython-312.pyc differ diff --git a/models/__pycache__/motion_amp.cpython-312.pyc b/models/__pycache__/motion_amp.cpython-312.pyc index f7a3789..904e492 100644 Binary files a/models/__pycache__/motion_amp.cpython-312.pyc and b/models/__pycache__/motion_amp.cpython-312.pyc differ diff --git a/models/__pycache__/pose_detection.cpython-312.pyc b/models/__pycache__/pose_detection.cpython-312.pyc index f72fe22..0064d55 100644 Binary files a/models/__pycache__/pose_detection.cpython-312.pyc and b/models/__pycache__/pose_detection.cpython-312.pyc differ diff --git a/models/__pycache__/r_zone.cpython-312.pyc b/models/__pycache__/r_zone.cpython-312.pyc index 6ef7d87..b537246 100644 Binary files a/models/__pycache__/r_zone.cpython-312.pyc and b/models/__pycache__/r_zone.cpython-312.pyc differ diff --git a/templates/login.html b/templates/login.html index 913102f..2db796f 100644 --- a/templates/login.html +++ b/templates/login.html @@ -18,6 +18,52 @@ + + @@ -50,12 +96,20 @@

Login

{% endwith %} + + + + Continue with Google + + +
+ OR +
+
-
+
- -
@@ -78,24 +132,22 @@

Login

renderer: 'svg', loop: true, autoplay: true, - path: 'static/img/blue_secuirity.json' // Replace with your JSON animation file + path: 'static/img/blue_secuirity.json' }); diff --git a/templates/register.html b/templates/register.html index ba19170..4e56779 100644 --- a/templates/register.html +++ b/templates/register.html @@ -9,80 +9,120 @@ - - - - - - - - + + + + - -
-
-
- {% with messages = get_flashed_messages(with_categories=true) %} - {% if messages %} +
+
+ {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} +
+ +

SignUp

- {% for category, message in messages %} - - {% endfor %} + + + + Sign up with Google + - {% endif %} - {% endwith %} +
+ OR +
+ + +
+ Username + +
+
+ + +
+
+ + +
+
+
-

SignUp

- -
- Username - - -
-
- - -
-
- - - -
- -
- -
-
-

Already Signed in? Sign in

-
- -
+
+

Already Signed in? Sign in

+
+ +
- - - - \ No newline at end of file + diff --git a/user.db b/user.db new file mode 100644 index 0000000..e69de29