import io from flask import Blueprint, make_response, render_template, redirect, url_for, flash from werkzeug.http import http_date from app.models import Profile, db from app.forms import ProfileForm from flask_login import login_required, current_user import base64 from datetime import datetime from PIL import Image user = Blueprint('user', __name__) @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 profile.timezone = form.timezone.data # Handle profile picture upload if form.profile_pic.data: file_data = form.profile_pic.data.read() # Resize and compress the image try: image = Image.open(io.BytesIO(file_data)) image = image.convert("RGB") # Ensure it's in RGB format image.thumbnail((300, 300)) # Resize to a maximum of 300x300 pixels # Save the resized image to a buffer buffer = io.BytesIO() image.save(buffer, format="JPEG", quality=80) # Compress with quality=80 buffer.seek(0) # Encode the compressed image as base64 profile.profile_pic = base64.b64encode(buffer.read()).decode('utf-8') except Exception as e: flash(f"Error processing profile picture: {e}", 'danger') 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) @user.route('/profile/image/') def profile_image(user_id): # Ensure the reading belongs to the logged-in user if user_id != current_user.id: flash('You are not authorized to delete this reading.', 'danger') return redirect(url_for('main.dashboard')) profile = Profile.query.filter_by(user_id=user_id).first() if profile and profile.profile_pic: image_data = base64.b64decode(profile.profile_pic) response = make_response(image_data) response.headers.set('Content-Type', 'image/jpeg') response.headers.set('Cache-Control', 'public, max-age=86400') # Cache for 1 day response.headers.set('ETag', str(hash(profile.profile_pic))) # Unique ETag for the image response.headers.set('Last-Modified', http_date(datetime.utcnow().timestamp())) return response else: # Serve the default SVG if no profile picture is found with open('app/static/images/default-profile.svg', 'r') as f: default_image = f.read() response = make_response(default_image) response.headers.set('Content-Type', 'image/svg+xml')