Change password
This commit is contained in:
51
app.py
51
app.py
@@ -11,6 +11,8 @@ from flask import (
|
|||||||
)
|
)
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
|
|
||||||
|
|
||||||
DATABASE = os.path.join(os.path.dirname(__file__), "avent.db")
|
DATABASE = os.path.join(os.path.dirname(__file__), "avent.db")
|
||||||
UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), "static", "uploads")
|
UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), "static", "uploads")
|
||||||
@@ -44,7 +46,9 @@ def init_db():
|
|||||||
|
|
||||||
cur = db.execute("SELECT COUNT(*) AS c FROM user")
|
cur = db.execute("SELECT COUNT(*) AS c FROM user")
|
||||||
if cur.fetchone()['c'] == 0:
|
if cur.fetchone()['c'] == 0:
|
||||||
db.execute("INSERT INTO user (username, password) VALUES (?, ?)", ("admin", "admin"))
|
hashed_admin = generate_password_hash("admin")
|
||||||
|
db.execute("INSERT INTO user (username, password) VALUES (?, ?)", ("admin", hashed_admin))
|
||||||
|
|
||||||
|
|
||||||
cur = db.execute("SELECT COUNT(*) AS c FROM project")
|
cur = db.execute("SELECT COUNT(*) AS c FROM project")
|
||||||
if cur.fetchone()['c'] == 0:
|
if cur.fetchone()['c'] == 0:
|
||||||
@@ -70,10 +74,11 @@ def get_user_by_username(username):
|
|||||||
|
|
||||||
def check_login(username, password):
|
def check_login(username, password):
|
||||||
user = get_user_by_username(username)
|
user = get_user_by_username(username)
|
||||||
if user and user["password"] == password:
|
if user and check_password_hash(user["password"], password):
|
||||||
return user
|
return user
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def login_required(fn):
|
def login_required(fn):
|
||||||
@wraps(fn)
|
@wraps(fn)
|
||||||
def wrapped(*args, **kwargs):
|
def wrapped(*args, **kwargs):
|
||||||
@@ -310,6 +315,48 @@ def admin_projects():
|
|||||||
|
|
||||||
projects = get_project()
|
projects = get_project()
|
||||||
return render_template("admin_projects.html", projects=projects)
|
return render_template("admin_projects.html", projects=projects)
|
||||||
|
@app.route("/admin/change-password", methods=["GET", "POST"])
|
||||||
|
@login_required
|
||||||
|
def admin_change_password():
|
||||||
|
"""Page admin pour changer le mot de passe"""
|
||||||
|
db = get_db()
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Récupérer l'utilisateur connecté
|
||||||
|
user_id = session.get("user_id")
|
||||||
|
cur = db.execute("SELECT password FROM user WHERE id = ?", (user_id,))
|
||||||
|
user = cur.fetchone()
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
flash("Erreur utilisateur.")
|
||||||
|
return render_template("admin_change_password.html")
|
||||||
|
|
||||||
|
# Vérifier mot de passe actuel
|
||||||
|
if not check_password_hash(user["password"], current_password):
|
||||||
|
flash("Mot de passe actuel incorrect.")
|
||||||
|
return render_template("admin_change_password.html")
|
||||||
|
|
||||||
|
# Vérifications
|
||||||
|
if new_password != confirm_password:
|
||||||
|
flash("Les nouveaux mots de passe ne correspondent pas.")
|
||||||
|
return render_template("admin_change_password.html")
|
||||||
|
|
||||||
|
if len(new_password) < 6:
|
||||||
|
flash("Le nouveau mot de passe doit faire au moins 6 caractères.")
|
||||||
|
return render_template("admin_change_password.html")
|
||||||
|
|
||||||
|
# Hash et mise à jour
|
||||||
|
hashed_password = generate_password_hash(new_password)
|
||||||
|
db.execute("UPDATE user SET password = ? WHERE id = ?", (hashed_password, user_id))
|
||||||
|
db.commit()
|
||||||
|
flash("✅ Mot de passe changé avec succès !")
|
||||||
|
return redirect(url_for("admin_projects"))
|
||||||
|
|
||||||
|
return render_template("admin_change_password.html")
|
||||||
|
|
||||||
@app.route("/admin/project/<int:project_id>/people", methods=["GET", "POST"])
|
@app.route("/admin/project/<int:project_id>/people", methods=["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
65
templates/admin_change_password.html
Normal file
65
templates/admin_change_password.html
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Changer mot de passe - Admin</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body class="bg-light">
|
||||||
|
<div class="container py-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card shadow-lg">
|
||||||
|
<div class="card-header bg-primary text-white text-center">
|
||||||
|
<h2 class="mb-0">
|
||||||
|
<i class="fas fa-key me-2"></i>Changer mot de passe
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-4">
|
||||||
|
{% with messages = get_flashed_messages() %}
|
||||||
|
{% if messages %}
|
||||||
|
<div class="alert alert-info alert-dismissible fade show mb-4">
|
||||||
|
{% for msg in messages %}
|
||||||
|
<div>{{ msg }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">Mot de passe actuel</label>
|
||||||
|
<input type="password" name="current_password" class="form-control" required autocomplete="current-password">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label fw-bold">Nouveau mot de passe</label>
|
||||||
|
<input type="password" name="new_password" class="form-control" minlength="6" required autocomplete="new-password">
|
||||||
|
<small class="text-muted">Minimum 6 caractères</small>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label fw-bold">Confirmer nouveau</label>
|
||||||
|
<input type="password" name="confirm_password" class="form-control" minlength="6" required autocomplete="new-password">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
|
||||||
|
<a href="{{ url_for('admin_projects') }}" class="btn btn-outline-secondary me-md-2">
|
||||||
|
<i class="fas fa-arrow-left me-1"></i>Retour
|
||||||
|
</a>
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<i class="fas fa-save me-1"></i>Changer mot de passe
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -3,16 +3,23 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Administration des projets</title>
|
<title>Administration des projets</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet" />
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-light">
|
<body class="bg-light">
|
||||||
<div class="container py-5">
|
<div class="container py-5">
|
||||||
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<h1>Gestion des projets</h1>
|
<h1>Gestion des projets</h1>
|
||||||
<a href="{{ url_for('dashboard') }}" class="btn btn-outline-primary">
|
<div>
|
||||||
<i class="fas fa-arrow-left me-2"></i>Tableau de bord
|
<span class="badge bg-success me-3">Connecté: {{ session.username }}</span>
|
||||||
|
<a href="{{ url_for('admin_change_password') }}" class="btn btn-outline-warning btn-sm me-2">
|
||||||
|
<i class="fas fa-key me-1"></i>Changer mot de passe
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ url_for('logout') }}" class="btn btn-outline-danger btn-sm">
|
||||||
|
<i class="fas fa-sign-out-alt me-1"></i>Déconnexion
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% with messages = get_flashed_messages() %}
|
{% with messages = get_flashed_messages() %}
|
||||||
@@ -26,6 +33,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
|
|
||||||
|
<!-- Formulaire ajout projet -->
|
||||||
<div class="card mb-5">
|
<div class="card mb-5">
|
||||||
<div class="card-header bg-primary text-white">
|
<div class="card-header bg-primary text-white">
|
||||||
<h3 class="mb-0"><i class="fas fa-plus me-2"></i>Ajouter un projet</h3>
|
<h3 class="mb-0"><i class="fas fa-plus me-2"></i>Ajouter un projet</h3>
|
||||||
@@ -44,7 +52,7 @@
|
|||||||
<small class="text-muted">PNG, JPG, GIF (max 5 Mo)</small>
|
<small class="text-muted">PNG, JPG, GIF (max 5 Mo)</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<input type="number" name="total_days" class="form-control" value="24" min="1" max="365" required />
|
<input type="number" name="total_days" class="form-control" placeholder="Nombre de jours" value="24" min="1" max="365" required />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<button class="btn btn-primary w-100" type="submit">
|
<button class="btn btn-primary w-100" type="submit">
|
||||||
@@ -55,6 +63,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Liste projets -->
|
||||||
<h3>Projets existants ({{ projects|length }})</h3>
|
<h3>Projets existants ({{ projects|length }})</h3>
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
@@ -76,7 +85,7 @@
|
|||||||
<td>{{ proj.id }}</td>
|
<td>{{ proj.id }}</td>
|
||||||
<td>
|
<td>
|
||||||
{% if proj.image_url %}
|
{% if proj.image_url %}
|
||||||
<img src="{{ proj.image_url }}" alt="Illustration" style="width:50px; height:50px; object-fit:cover; border-radius:5px;">
|
<img src="{{ proj.image_url }}" alt="Illustration" style="width:50px; height:50px; object-fit:cover; border-radius:5px;" />
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="text-muted">—</span>
|
<span class="text-muted">—</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -95,8 +104,7 @@
|
|||||||
<button name="action" value="update" class="btn btn-sm btn-success me-2" type="submit">
|
<button name="action" value="update" class="btn btn-sm btn-success me-2" type="submit">
|
||||||
<i class="fas fa-save"></i> Sauvegarder
|
<i class="fas fa-save"></i> Sauvegarder
|
||||||
</button>
|
</button>
|
||||||
<button name="action" value="delete" class="btn btn-sm btn-danger me-2" type="submit"
|
<button name="action" value="delete" class="btn btn-sm btn-danger me-2" type="submit" onclick="return confirm('Supprimer ce projet ?');">
|
||||||
onclick="return confirm('Supprimer ce projet ?');">
|
|
||||||
<i class="fas fa-trash"></i> Supprimer
|
<i class="fas fa-trash"></i> Supprimer
|
||||||
</button>
|
</button>
|
||||||
<a href="{{ url_for('admin_project_people', project_id=proj.id) }}" class="btn btn-sm btn-primary" title="Gérer utilisateurs">
|
<a href="{{ url_for('admin_project_people', project_id=proj.id) }}" class="btn btn-sm btn-primary" title="Gérer utilisateurs">
|
||||||
@@ -110,9 +118,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href="{{ url_for('dashboard') }}" class="btn btn-link mt-3">Retour au tableau de bord</a>
|
|
||||||
</div>
|
</div>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user