From 6845308a3454a9e42fca8234d04804254126c41c Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Nov 2025 15:58:51 +0000 Subject: [PATCH] Add password change functionality and profile image upload - Add profile_image field to Profile model with default value - Update profile edit route to handle profile image file uploads - Add password change route with validation in auth module - Create change password template with form - Update profile template to include image upload with preview - Add password change link to admin sidebar - Update homepage to use dynamic profile image from database --- init_db.py | 3 +- models.py | 4 +- routes/admin.py | 13 +++++++ routes/auth.py | 41 ++++++++++++++++++++- templates/admin/base.html | 3 ++ templates/admin/profile.html | 25 ++++++++++++- templates/auth/change_password.html | 57 +++++++++++++++++++++++++++++ templates/index.html | 2 +- 8 files changed, 143 insertions(+), 5 deletions(-) create mode 100644 templates/auth/change_password.html diff --git a/init_db.py b/init_db.py index 1fd1f19..04c7815 100644 --- a/init_db.py +++ b/init_db.py @@ -32,7 +32,8 @@ def init_database(): lead_text="Con oltre 7 Anni di esperienza nello sviluppo di applicazioni web con Python Flask, offro soluzioni complete end-to-end.", description_1="La mia doppia specializzazione mi permette di comprendere a fondo l'intero ciclo di vita delle applicazioni, dall'architettura del server fino all'implementazione e al deployment.", description_2="Mi piace risolvere problemi complessi e creare soluzioni che siano robuste, scalabili e facili da mantenere.", - years_experience=7 + years_experience=7, + profile_image='img/personal.webp' ) db.session.add(profile) diff --git a/models.py b/models.py index e6e98b8..b070043 100644 --- a/models.py +++ b/models.py @@ -53,6 +53,7 @@ class Profile(db.Model): description_2 = db.Column(db.Text) years_experience = db.Column(db.Integer, default=7) cv_url = db.Column(db.String(500)) + profile_image = db.Column(db.String(500), default='img/personal.webp') created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) @@ -64,7 +65,8 @@ class Profile(db.Model): 'description_1': self.description_1, 'description_2': self.description_2, 'years_experience': self.years_experience, - 'cv_url': self.cv_url + 'cv_url': self.cv_url, + 'profile_image': self.profile_image } diff --git a/routes/admin.py b/routes/admin.py index 16a6f60..f3ee306 100644 --- a/routes/admin.py +++ b/routes/admin.py @@ -78,12 +78,25 @@ def profile_edit(): flash('Profilo non trovato.', 'danger') return redirect(url_for('admin.profile_manage')) + # Handle profile image upload + profile_image_url = request.form.get('profile_image', profile.profile_image) + if 'profile_image_file' in request.files: + file = request.files['profile_image_file'] + if file.filename: + uploaded_path = save_uploaded_file(file) + if uploaded_path: + profile_image_url = uploaded_path + else: + flash('Formato immagine non valido. Usa: png, jpg, jpeg, gif, webp', 'danger') + return redirect(url_for('admin.profile_manage')) + profile.title = request.form.get('title', profile.title) profile.lead_text = request.form.get('lead_text', profile.lead_text) profile.description_1 = request.form.get('description_1', profile.description_1) profile.description_2 = request.form.get('description_2', profile.description_2) profile.years_experience = int(request.form.get('years_experience', profile.years_experience)) profile.cv_url = request.form.get('cv_url', profile.cv_url) + profile.profile_image = profile_image_url db.session.commit() flash('Profilo aggiornato con successo!', 'success') diff --git a/routes/auth.py b/routes/auth.py index 111262f..c854894 100644 --- a/routes/auth.py +++ b/routes/auth.py @@ -8,7 +8,7 @@ Authentication routes for login/logout """ from flask import Blueprint, render_template, request, redirect, url_for, flash -from flask_login import login_user, logout_user, current_user +from flask_login import login_user, logout_user, current_user, login_required from models import User, db from datetime import datetime @@ -60,3 +60,42 @@ def logout(): logout_user() flash('Logout effettuato con successo.', 'info') return redirect(url_for('route_home.home')) + + +@route_auth.route('/change-password', methods=['GET', 'POST']) +@login_required +def change_password(): + """Change password page""" + if request.method == 'POST': + current_password = request.form.get('current_password') + new_password = request.form.get('new_password') + confirm_password = request.form.get('confirm_password') + + # Validation + if not current_password or not new_password or not confirm_password: + flash('Tutti i campi sono obbligatori.', 'danger') + return render_template('auth/change_password.html') + + # Check current password + if not current_user.check_password(current_password): + flash('La password attuale non รจ corretta.', 'danger') + return render_template('auth/change_password.html') + + # Check if new passwords match + if new_password != confirm_password: + flash('Le nuove password non corrispondono.', 'danger') + return render_template('auth/change_password.html') + + # Check password length + if len(new_password) < 6: + flash('La nuova password deve essere di almeno 6 caratteri.', 'danger') + return render_template('auth/change_password.html') + + # Update password + current_user.set_password(new_password) + db.session.commit() + + flash('Password modificata con successo!', 'success') + return redirect(url_for('admin.dashboard')) + + return render_template('auth/change_password.html') diff --git a/templates/admin/base.html b/templates/admin/base.html index 32aa6e8..872e3d8 100644 --- a/templates/admin/base.html +++ b/templates/admin/base.html @@ -100,6 +100,9 @@ Link Social
+ + Cambia Password + Visualizza Sito diff --git a/templates/admin/profile.html b/templates/admin/profile.html index d1630d5..8a530bb 100644 --- a/templates/admin/profile.html +++ b/templates/admin/profile.html @@ -6,7 +6,7 @@ {% block content %}
-
+
+
+ +
+
+ + + Formati supportati: png, jpg, jpeg, gif, webp (max 16 MB) +
+
+ + + Percorso relativo alla cartella static/ +
+
+ {% if profile and profile.profile_image %} +
+ Immagine attuale:
+ Profile +
+ {% endif %} +
+
+ + Annulla + +
+
+
+
+ +
+ + Nota: Dopo aver cambiato la password, verrai reindirizzato alla dashboard. +
+ + +{% endblock %} diff --git a/templates/index.html b/templates/index.html index a23a1ff..809de93 100644 --- a/templates/index.html +++ b/templates/index.html @@ -19,7 +19,7 @@
- Profile + Profile