Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified __pycache__/app.cpython-311.pyc
Binary file not shown.
Binary file modified __pycache__/app.cpython-312.pyc
Binary file not shown.
107 changes: 97 additions & 10 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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')
Expand All @@ -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':
Expand All @@ -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)
Expand All @@ -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')
Expand Down Expand Up @@ -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)

29 changes: 29 additions & 0 deletions create_db.py
Original file line number Diff line number Diff line change
@@ -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!")
Binary file modified models/__pycache__/config_loader.cpython-312.pyc
Binary file not shown.
Binary file modified models/__pycache__/fire_detection.cpython-312.pyc
Binary file not shown.
Binary file modified models/__pycache__/gear_detection.cpython-312.pyc
Binary file not shown.
Binary file modified models/__pycache__/motion_amp.cpython-312.pyc
Binary file not shown.
Binary file modified models/__pycache__/pose_detection.cpython-312.pyc
Binary file not shown.
Binary file modified models/__pycache__/r_zone.cpython-312.pyc
Binary file not shown.
86 changes: 69 additions & 17 deletions templates/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,52 @@
<link rel="stylesheet" href="/static/css/dark-theme.css">
<link rel="stylesheet" href="/static/css/glass-spark.css">
<link rel="stylesheet" href="/static/css/text-animation.css">

<style>
.google-btn {
width: 100%;
padding: 12px;
background-color: #4285f4;
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
transition: background-color 0.3s;
}

.google-btn:hover {
background-color: #357ae8;
}

.google-btn i {
font-size: 20px;
}

.divider {
display: flex;
align-items: center;
text-align: center;
margin: 20px 0;
color: #007bff;
}

.divider::before,
.divider::after {
content: '';
flex: 1;
border-bottom: 1px solid #007bff;
}

.divider span {
padding: 0 10px;
}
</style>
</head>

<body>
Expand Down Expand Up @@ -50,12 +96,20 @@ <h2 class="animated-text" style="color: #ffffff;">Login</h2>
{% endwith %}
</div>

<!-- Google Sign-In Button -->
<a href="/google/login" class="google-btn">
<i class="fab fa-google"></i>
<span>Continue with Google</span>
</a>

<div class="divider">
<span>OR</span>
</div>

<form action="/login" method="POST">
<div class="inputBx" >
<div class="inputBx">
<label for="email" style="color: #007bff;">Email:</label>

<input type="email" id="email" name="email" style="color: white; background-color: black; border: 1px solid #007bff;" required>

</div>
<div class="inputBx">
<label for="password" style="color: #007bff;">Password:</label>
Expand All @@ -78,24 +132,22 @@ <h2 class="animated-text" style="color: #ffffff;">Login</h2>
renderer: 'svg',
loop: true,
autoplay: true,
path: 'static/img/blue_secuirity.json' // Replace with your JSON animation file
path: 'static/img/blue_secuirity.json'
});
</script>

<script>
window.addEventListener("DOMContentLoaded", function () {
if (!sessionStorage.getItem("soundPlayed")) { // Check if sound has already played
var audio = document.getElementById("loginSound");
audio.muted = true; // Start muted to bypass restrictions
audio.play().then(() => {
audio.muted = false; // Unmute after playback starts
setTimeout(() => audio.play(), 2000); // Delay before unmuted replay
sessionStorage.setItem("soundPlayed", "true"); // Store flag
}).catch(error => console.log("Autoplay blocked:", error));
}
});


window.addEventListener("DOMContentLoaded", function () {
if (!sessionStorage.getItem("soundPlayed")) {
var audio = document.getElementById("loginSound");
audio.muted = true;
audio.play().then(() => {
audio.muted = false;
setTimeout(() => audio.play(), 2000);
sessionStorage.setItem("soundPlayed", "true");
}).catch(error => console.log("Autoplay blocked:", error));
}
});
</script>
</body>

Expand Down
Loading