from flask import Blueprint, render_template, redirect, request, url_for, flash from werkzeug.security import generate_password_hash, check_password_hash from app.models import Profile, Reading, db, User from app.forms import DeleteForm, LoginForm, ProfileForm, ReadingForm, SignupForm from flask_login import login_user, login_required, current_user, logout_user import base64 main = Blueprint('main', __name__) auth = Blueprint('auth', __name__) user = Blueprint('user', __name__) @auth.route('/signup', methods=['GET', 'POST']) def signup(): form = SignupForm() if form.validate_on_submit(): hashed_password = generate_password_hash(form.password.data) new_user = User(username=form.username.data, password_hash=hashed_password) db.session.add(new_user) db.session.commit() flash("Account created successfully. Please log in.", "success") return redirect(url_for('auth.login')) return render_template('signup.html', form=form) @auth.route('/login', methods=['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): user = User.query.filter_by(username=form.username.data).first() if user and check_password_hash(user.password_hash, form.password.data): login_user(user) flash("Logged in successfully.", "success") return redirect(url_for('main.dashboard')) flash("Invalid username or password.", "danger") return render_template('login.html', form=form) @auth.route('/logout') @login_required def logout(): logout_user() # Logs out the current user flash('You have been logged out.', 'success') return redirect(url_for('auth.login')) # Redirect to login page or home page @main.route('/', methods=['GET', 'POST']) @login_required def dashboard(): from datetime import datetime, timedelta # Default values start_date = None end_date = None # Default to all readings readings_query = Reading.query.filter_by(user_id=current_user.id) # Handle filtering if it's a POST request if request.method == 'POST': start_date = request.form.get('start_date') end_date = request.form.get('end_date') if start_date and end_date: start_date_obj = datetime.strptime(start_date, '%Y-%m-%d') end_date_obj = datetime.strptime(end_date, '%Y-%m-%d') readings_query = readings_query.filter( Reading.timestamp >= start_date_obj, Reading.timestamp <= end_date_obj ) # Format start_date and end_date for the template start_date = start_date_obj.strftime('%Y-%m-%d') end_date = end_date_obj.strftime('%Y-%m-%d') # Fetch and order readings readings = readings_query.order_by(Reading.timestamp.desc()).all() # Weekly summary (last 7 days) one_week_ago = datetime.now() - timedelta(days=7) weekly_readings = [r for r in readings if r.timestamp >= one_week_ago] systolic_avg = round(sum(r.systolic for r in weekly_readings) / len(weekly_readings), 1) if weekly_readings else 0 diastolic_avg = round(sum(r.diastolic for r in weekly_readings) / len(weekly_readings), 1) if weekly_readings else 0 heart_rate_avg = round(sum(r.heart_rate for r in weekly_readings) / len(weekly_readings), 1) if weekly_readings else 0 # Progress badges badges = [] if len(readings) >= 10: badges.append("10 Readings Logged") if len(readings) >= 100: badges.append("100 Readings Milestone") if len(weekly_readings) >= 7: badges.append("Logged Readings for 7 Days") # Prepare data for the graphs timestamps = [reading.timestamp.strftime('%b %d') for reading in readings] systolic = [reading.systolic for reading in readings] diastolic = [reading.diastolic for reading in readings] heart_rate = [reading.heart_rate for reading in readings] # Pass the delete form to the template delete_form = DeleteForm() return render_template( 'dashboard.html', readings=readings, profile=current_user.profile, badges=badges, systolic_avg=systolic_avg, diastolic_avg=diastolic_avg, heart_rate_avg=heart_rate_avg, delete_form=delete_form, timestamps=timestamps, systolic=systolic, diastolic=diastolic, heart_rate=heart_rate, start_date=start_date, end_date=end_date ) @main.route('/add-reading', methods=['GET', 'POST']) @login_required def add_reading(): form = ReadingForm() if form.validate_on_submit(): new_reading = Reading( user_id=current_user.id, timestamp=form.timestamp.data, systolic=form.systolic.data, diastolic=form.diastolic.data, heart_rate=form.heart_rate.data ) db.session.add(new_reading) db.session.commit() flash("Reading added successfully.", "success") return redirect(url_for('main.dashboard')) return render_template('add_reading.html', form=form) @main.route('/reading//edit', methods=['GET', 'POST']) @login_required def edit_reading(reading_id): reading = Reading.query.get_or_404(reading_id) # Ensure the reading belongs to the logged-in user if reading.user_id != current_user.id: flash('You are not authorized to edit this reading.', 'danger') return redirect(url_for('main.dashboard')) form = ReadingForm(obj=reading) # Populate form with existing reading data if form.validate_on_submit(): reading.timestamp = form.timestamp.data reading.systolic = form.systolic.data reading.diastolic = form.diastolic.data reading.heart_rate = form.heart_rate.data db.session.commit() flash('Reading updated successfully!', 'success') return redirect(url_for('main.dashboard')) return render_template('edit_reading.html', form=form, reading=reading) @main.route('/reading//delete', methods=['POST']) @login_required def delete_reading(reading_id): reading = Reading.query.get_or_404(reading_id) # Ensure the reading belongs to the logged-in user if reading.user_id != current_user.id: flash('You are not authorized to delete this reading.', 'danger') return redirect(url_for('main.dashboard')) db.session.delete(reading) db.session.commit() flash('Reading deleted successfully!', 'success') return redirect(url_for('main.dashboard')) @user.route('/profile', methods=['GET', 'POST']) @login_required def profile(): profile = current_user.profile or Profile(user_id=current_user.id) form = ProfileForm(obj=profile) if form.validate_on_submit(): # Update profile fields profile.name = form.name.data profile.email = form.email.data profile.systolic_threshold = form.systolic_threshold.data or profile.systolic_threshold profile.diastolic_threshold = form.diastolic_threshold.data or profile.diastolic_threshold profile.dark_mode = form.dark_mode.data # Handle profile picture upload if form.profile_pic.data: file_data = form.profile_pic.data.read() profile.profile_pic = base64.b64encode(file_data).decode('utf-8') db.session.add(profile) db.session.commit() flash('Profile updated successfully!', 'success') return redirect(url_for('user.profile')) return render_template('profile.html', form=form, profile=profile)