diff --git a/Semaine_15/Jour_04/REFERENTIEL (1) (1).pdf b/Semaine_15/Jour_04/REFERENTIEL (1) (1).pdf new file mode 100644 index 0000000..e5efdb4 Binary files /dev/null and b/Semaine_15/Jour_04/REFERENTIEL (1) (1).pdf differ diff --git a/Semaine_15/Jour_04/atelier-web/starter/app.py b/Semaine_15/Jour_04/atelier-web/starter/app.py index 4fa72be..452fea6 100644 --- a/Semaine_15/Jour_04/atelier-web/starter/app.py +++ b/Semaine_15/Jour_04/atelier-web/starter/app.py @@ -1,7 +1,6 @@ -"""Bloc&Co — gestion des adhérents d'une salle d'escalade. +"""Bloc&Co — climbing gym member management. -Squelette de l'atelier. Complétez tout ce qui est marqué « À FAIRE ». -Lancement : python app.py puis http://127.0.0.1:5000 +Run: python app.py then open http://127.0.0.1:5000 """ import sqlite3 @@ -18,15 +17,21 @@ DB = BASE / "blocandco.db" app = Flask(__name__) app.secret_key = "cle-de-developpement-a-changer" -levelX = ["debutant", "intermediaire", "confirme"] +LEVELS = ["debutant", "intermediaire", "confirme"] + +MIN_PASSWORD_LENGTH = 12 + +# Compared against when the e-mail is unknown, so that both login failures +# take about the same time (limits account enumeration by timing). +DUMMY_HASH = generate_password_hash("mot-de-passe-factice") # ========================================================================== -# FOURNI — plomberie de la base de données. Ne rien modifier ici. +# Database plumbing # ========================================================================== def get_db(): - """Une connexion par requête, rangée dans g et fermée automatiquement.""" + """One connection per request, stored in g and closed automatically.""" if "db" not in g: g.db = sqlite3.connect(DB) g.db.row_factory = sqlite3.Row @@ -41,13 +46,13 @@ def close_db(exception): def init_db(): - """Crée la base au premier lancement et sème un compte administrateur.""" + """Create the database on first launch and seed an administrator account.""" if DB.exists(): return con = sqlite3.connect(DB) con.executescript((BASE / "schema.sql").read_text(encoding="utf-8")) con.execute( - "INSERT INTO adherents (lastname, firstname, email, password, level, role," + "INSERT INTO members (lastname, firstname, email, password, level, role," " sub_date) VALUES (?, ?, ?, ?, ?, ?, ?)", ("Martin", "Claire", "admin@blocandco.fr", generate_password_hash("Admin2026!"), "confirme", "admin", @@ -59,160 +64,208 @@ def init_db(): @app.context_processor -def injecter_utilisateur(): - """Rend la variable `utilisateur` disponible dans tous les templates.""" - return {"utilisateur": utilisateur_courant()} +def inject_user(): + """Make the `user` variable available in every template.""" + return {"user": current_user()} # ========================================================================== -# EXERCICE 6 — qui est connecté ? +# Who is logged in, and access control # ========================================================================== -def utilisateur_courant(): - """Renvoie la ligne de l'adhérent connecté, ou None si personne. - - À FAIRE : - - si "user_id" n'est pas dans `session`, renvoyer None - - sinon, aller chercher la ligne correspondante dans la base - """ - return None +def current_user(): + """Return the logged-in member's row, or None if nobody is logged in.""" + user_id = session.get("user_id") + if user_id is None: + return None + return get_db().execute( + "SELECT * FROM members WHERE id = ?", (user_id,) + ).fetchone() -# ========================================================================== -# EXERCICE 7 — protéger une page -# ========================================================================== - -def login_requis(vue): - """Interdit l'accès à la vue si personne n'est connecté. - - À FAIRE : si `utilisateur_courant()` vaut None, afficher un message - et rediriger vers la page de connexion. Sinon, appeler la vue. - """ - @wraps(vue) +def login_required(view): + """Block the view if nobody is logged in.""" + @wraps(view) def wrapper(*args, **kwargs): - return vue(*args, **kwargs) + if current_user() is None: + flash("Connectez-vous pour accéder à cette page.", "error") + return redirect(url_for("login")) + return view(*args, **kwargs) + return wrapper + + +def admin_required(view): + """Block the view unless the user is an administrator.""" + @wraps(view) + def wrapper(*args, **kwargs): + user = current_user() + if user is None: + flash("Connectez-vous pour accéder à cette page.", "error") + return redirect(url_for("login")) + if user["role"] != "admin": + flash("Accès réservé aux administrateurs.", "error") + return redirect(url_for("home")) + return view(*args, **kwargs) return wrapper # ========================================================================== -# EXERCICE 9 — réserver une page aux administrateurs +# Registration form validation # ========================================================================== -def admin_requis(vue): - """Interdit l'accès à la vue si l'utilisateur n'est pas administrateur. - - À FAIRE : refuser les visiteurs non connectés, PUIS refuser ceux dont - le rôle n'est pas "admin". Deux messages différents. - """ - @wraps(vue) - def wrapper(*args, **kwargs): - return vue(*args, **kwargs) - return wrapper +def validate_registration(lastname, firstname, email, password, confirmation): + """Return the list of error messages. An empty list means the form is valid.""" + errors = [] + if not lastname: + errors.append("Le nom est obligatoire.") + if not firstname: + errors.append("Le prénom est obligatoire.") + if "@" not in email or "." not in email.split("@", 1)[1]: + errors.append("L'adresse e-mail n'est pas valide.") + if len(password) < MIN_PASSWORD_LENGTH: + errors.append( + f"Le mot de passe doit faire au moins {MIN_PASSWORD_LENGTH} caractères." + ) + if not any(c.isdigit() for c in password): + errors.append("Le mot de passe doit contenir au moins un chiffre.") + if not any(c.isupper() for c in password): + errors.append("Le mot de passe doit contenir au moins une majuscule.") + if password != confirmation: + errors.append("Les mots de passe ne correspondent pas.") + return errors # ========================================================================== -# EXERCICE 5 — valider le formulaire d'inscription -# ========================================================================== - -def valider_inscription(lastname, firstname, email, mdp, confirmation): - """Renvoie la liste des messages d'erreur. Liste vide = tout est bon. - - À FAIRE, dans cet ordre : - - lastname et prélastname non vides - - email contenant "@" et un point après le "@" - - mot de passe d'au moins 12 caractères - - au moins un chiffre, au moins une majuscule - - les deux mots de passe identiques - """ - erreurs = [] - return erreurs - - -# ========================================================================== -# ROUTES +# Routes (URLs and messages stay in French: they are the user interface) # ========================================================================== @app.route("/") -def accueil(): - """EXERCICE 10 — afficher le lastnamebre d'adhérents inscrits. - - À FAIRE : remplacer le 0 par le vrai total, lu dans la base - avec un SELECT COUNT(*). - """ - nb = 0 - return render_template("accueil.html", nb_adherents=nb) +def home(): + member_count = get_db().execute("SELECT COUNT(*) FROM members").fetchone()[0] + return render_template("home.html", member_count=member_count) @app.route("/inscription", methods=["GET", "POST"]) -def inscription(): - """EXERCICE 5 — créer un compte. - - À FAIRE : - - en POST, récupérer les champs du formulaire - - les valider avec valider_inscription() - - refuser une adresse e-mail déjà présente dans la base - - hacher le mot de passe avec generate_password_hash() - - insérer l'adhérent avec le rôle "adherent" - - rediriger vers la page de connexion - """ +def register(): if request.method == "POST": - pass - return render_template("inscription.html") + lastname = request.form.get("lastname", "").strip() + firstname = request.form.get("firstname", "").strip() + email = request.form.get("email", "").strip().lower() + password = request.form.get("password", "") + confirmation = request.form.get("confirmation", "") + + errors = validate_registration( + lastname, firstname, email, password, confirmation + ) + db = get_db() + if not errors and db.execute( + "SELECT 1 FROM members WHERE email = ?", (email,) + ).fetchone(): + errors.append("Cette adresse e-mail est déjà utilisée.") + + if not errors: + try: + db.execute( + "INSERT INTO members (lastname, firstname, email, password," + " level, role, sub_date) VALUES (?, ?, ?, ?, ?, ?, ?)", + (lastname, firstname, email, generate_password_hash(password), + LEVELS[0], "adherent", date.today().isoformat()), + ) + db.commit() + except sqlite3.IntegrityError: + # Two simultaneous sign-ups with the same e-mail. + errors.append("Cette adresse e-mail est déjà utilisée.") + + if not errors: + flash("Compte créé. Vous pouvez vous connecter.", "success") + return redirect(url_for("login")) + + for error in errors: + flash(error, "error") + # The password is deliberately not sent back to the form. + return render_template( + "register.html", + lastname=lastname, firstname=firstname, email=email, + ) + return render_template("register.html") @app.route("/connexion", methods=["GET", "POST"]) -def connexion(): - """EXERCICE 6 — se connecter. - - À FAIRE : - - chercher l'adhérent par son e-mail - - vérifier le mot de passe avec check_password_hash() - - en cas d'échec, afficher LE MÊME message que l'adresse existe ou non - - en cas de succès, vider la session puis y stocker l'identifiant - """ +def login(): if request.method == "POST": - pass - return render_template("connexion.html") + email = request.form.get("email", "").strip().lower() + password = request.form.get("password", "") + + member = get_db().execute( + "SELECT * FROM members WHERE email = ?", (email,) + ).fetchone() + stored_hash = member["password"] if member else DUMMY_HASH + password_ok = check_password_hash(stored_hash, password) + + if member is None or not password_ok: + # Same message whether the address exists or not. + flash("Identifiants incorrects.", "error") + return render_template("login.html", email=email) + + session.clear() + session["user_id"] = member["id"] + return redirect(url_for("profile")) + return render_template("login.html") @app.route("/deconnexion") -def deconnexion(): - """EXERCICE 7 — se déconnecter. - - À FAIRE : vider la session et rediriger vers l'accueil. - """ - return redirect(url_for("accueil")) +def logout(): + session.clear() + return redirect(url_for("home")) @app.route("/profil", methods=["GET", "POST"]) -@login_requis -def profil(): - """EXERCICE 8 — consulter et modifier son profil. - - À FAIRE : - - en POST, mettre à jour lastname, prélastname et level de l'utilisateur CONNECTÉ - - refuser un level qui n'est pas dans levelX - """ +@login_required +def profile(): if request.method == "POST": - pass - return render_template("profil.html", levelx=levelX) + lastname = request.form.get("lastname", "").strip() + firstname = request.form.get("firstname", "").strip() + level = request.form.get("level", "") + + if not lastname or not firstname: + flash("Le nom et le prénom sont obligatoires.", "error") + elif level not in LEVELS: + flash("Niveau invalide.", "error") + else: + db = get_db() + # The row to update comes from the session, never from the form. + db.execute( + "UPDATE members SET lastname = ?, firstname = ?, level = ?" + " WHERE id = ?", + (lastname, firstname, level, session["user_id"]), + ) + db.commit() + flash("Profil mis à jour.", "success") + return redirect(url_for("profile")) + return render_template("profile.html", levels=LEVELS) @app.route("/admin") -@admin_requis +@admin_required def admin(): - """EXERCICE 9 — lister les adhérents. - - À FAIRE : lire tous les adhérents, les plus récents d'abord. - """ - adherents = [] - return render_template("admin.html", adherents=adherents) + members = get_db().execute( + "SELECT * FROM members ORDER BY sub_date DESC, id DESC" + ).fetchall() + return render_template("admin.html", members=members) -@app.route("/admin/promouvoir/", methods=["POST"]) -@admin_requis -def promouvoir(adherent_id): - """EXERCICE 9 (suite) — promouvoir un adhérent administrateur.""" +@app.route("/admin/promouvoir/", methods=["POST"]) +@admin_required +def promote(member_id): + db = get_db() + cursor = db.execute( + "UPDATE members SET role = 'admin' WHERE id = ?", (member_id,) + ) + db.commit() + if cursor.rowcount: + flash("Adhérent promu administrateur.", "success") + else: + flash("Adhérent introuvable.", "error") return redirect(url_for("admin")) diff --git a/Semaine_15/Jour_04/atelier-web/starter/blocandco.db b/Semaine_15/Jour_04/atelier-web/starter/blocandco.db index d9e815d..1f385c5 100644 Binary files a/Semaine_15/Jour_04/atelier-web/starter/blocandco.db and b/Semaine_15/Jour_04/atelier-web/starter/blocandco.db differ diff --git a/Semaine_15/Jour_04/atelier-web/starter/schema.sql b/Semaine_15/Jour_04/atelier-web/starter/schema.sql index dc6fde8..82ef593 100644 --- a/Semaine_15/Jour_04/atelier-web/starter/schema.sql +++ b/Semaine_15/Jour_04/atelier-web/starter/schema.sql @@ -1,9 +1,9 @@ -- Schéma de la base « Bloc&Co » -- Exécuté une seule fois, au premier démarrage de l'application. -DROP TABLE IF EXISTS adherents; +DROP TABLE IF EXISTS members; -CREATE TABLE adherents ( +CREATE TABLE members ( id INTEGER PRIMARY KEY AUTOINCREMENT, lastname TEXT NOT NULL, firstname TEXT NOT NULL, diff --git a/Semaine_15/Jour_04/atelier-web/starter/static/style.css b/Semaine_15/Jour_04/atelier-web/starter/static/style.css index 2c98700..00884a7 100644 --- a/Semaine_15/Jour_04/atelier-web/starter/static/style.css +++ b/Semaine_15/Jour_04/atelier-web/starter/static/style.css @@ -1,74 +1,74 @@ :root { - --bleu: #0b6e9e; - --bleu-fonce: #084f71; - --gris: #5c6672; - --bord: #dde3e9; - --fond: #f6f8fa; - --rouge: #a8341f; - --vert: #1f6b45; + --blue: #0b6e9e; + --blue-dark: #084f71; + --grey: #5c6672; + --border: #dde3e9; + --background: #f6f8fa; + --red: #a8341f; + --green: #1f6b45; } * { box-sizing: border-box; } body { margin: 0; font-family: "Segoe UI", system-ui, sans-serif; color: #1a1f26; - background: var(--fond); + background: var(--background); line-height: 1.55; } header { display: flex; align-items: center; gap: 1.5rem; padding: 0.9rem 1.5rem; background: #fff; - border-bottom: 1px solid var(--bord); + border-bottom: 1px solid var(--border); } -.logo { font-weight: 700; font-size: 1.15rem; color: var(--bleu); text-decoration: none; } +.logo { font-weight: 700; font-size: 1.15rem; color: var(--blue); text-decoration: none; } nav { margin-left: auto; display: flex; gap: 1.1rem; align-items: center; } -nav a { color: var(--gris); text-decoration: none; font-size: 0.92rem; } -nav a:hover { color: var(--bleu); } +nav a { color: var(--grey); text-decoration: none; font-size: 0.92rem; } +nav a:hover { color: var(--blue); } main { max-width: 780px; margin: 0 auto; padding: 2rem 1.5rem 4rem; } h1 { font-size: 1.7rem; margin: 0 0 0.4rem; } h2 { font-size: 1.15rem; margin: 2rem 0 0.6rem; } -.chapeau { color: var(--gris); margin-top: 0; } +.lead { color: var(--grey); margin-top: 0; } -.carte { - background: #fff; border: 1px solid var(--bord); border-radius: 8px; +.card { + background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem; display: flex; flex-direction: column; gap: 0.85rem; max-width: 420px; } -label { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.88rem; color: var(--gris); } +label { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.88rem; color: var(--grey); } input, select { - padding: 0.5rem 0.65rem; border: 1px solid var(--bord); border-radius: 5px; + padding: 0.5rem 0.65rem; border: 1px solid var(--border); border-radius: 5px; font-size: 0.95rem; font-family: inherit; color: #1a1f26; background: #fff; } -input:focus, select:focus { outline: 2px solid var(--bleu); outline-offset: 1px; border-color: var(--bleu); } -.aide { font-size: 0.8rem; color: var(--gris); margin: 0; } +input:focus, select:focus { outline: 2px solid var(--blue); outline-offset: 1px; border-color: var(--blue); } +.hint { font-size: 0.8rem; color: var(--grey); margin: 0; } -button, .bouton { - background: var(--bleu); color: #fff; border: none; border-radius: 5px; +button, .button { + background: var(--blue); color: #fff; border: none; border-radius: 5px; padding: 0.55rem 1rem; font-size: 0.95rem; font-family: inherit; cursor: pointer; text-decoration: none; display: inline-block; text-align: center; } -button:hover, .bouton:hover { background: var(--bleu-fonce); } -button.lien { background: none; color: var(--bleu); padding: 0; text-decoration: underline; } -button.lien:hover { background: none; color: var(--bleu-fonce); } +button:hover, .button:hover { background: var(--blue-dark); } +button.link { background: none; color: var(--blue); padding: 0; text-decoration: underline; } +button.link:hover { background: none; color: var(--blue-dark); } .messages { list-style: none; padding: 0; margin: 0 0 1.25rem; display: flex; flex-direction: column; gap: 0.4rem; } .messages li { padding: 0.6rem 0.85rem; border-radius: 5px; font-size: 0.9rem; border-left: 3px solid; } -.messages .erreur { background: #fbecea; border-color: var(--rouge); color: var(--rouge); } -.messages .succes { background: #e9f3ed; border-color: var(--vert); color: var(--vert); } +.messages .error { background: #fbecea; border-color: var(--red); color: var(--red); } +.messages .success { background: #e9f3ed; border-color: var(--green); color: var(--green); } .stat { display: flex; align-items: baseline; gap: 0.6rem; - background: #fff; border: 1px solid var(--bord); border-radius: 8px; + background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 1.1rem 1.4rem; margin: 1.5rem 0; max-width: 420px; } -.chiffre { font-size: 2.4rem; font-weight: 700; color: var(--bleu); line-height: 1; } -.libelle { color: var(--gris); } +.figure { font-size: 2.4rem; font-weight: 700; color: var(--blue); line-height: 1; } +.caption { color: var(--grey); } -.infos { display: grid; grid-template-columns: auto 1fr; gap: 0.4rem 1.5rem; } -.infos dt { color: var(--gris); font-size: 0.88rem; } -.infos dd { margin: 0; } +.details { display: grid; grid-template-columns: auto 1fr; gap: 0.4rem 1.5rem; } +.details dt { color: var(--grey); font-size: 0.88rem; } +.details dd { margin: 0; } -table { width: 100%; border-collapse: collapse; background: #fff; border: 1px solid var(--bord); border-radius: 8px; overflow: hidden; font-size: 0.9rem; } -th, td { text-align: left; padding: 0.6rem 0.8rem; border-bottom: 1px solid var(--bord); } -th { background: #eef2f6; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--gris); } +table { width: 100%; border-collapse: collapse; background: #fff; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; font-size: 0.9rem; } +th, td { text-align: left; padding: 0.6rem 0.8rem; border-bottom: 1px solid var(--border); } +th { background: #eef2f6; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--grey); } tr:last-child td { border-bottom: none; } diff --git a/Semaine_15/Jour_04/atelier-web/starter/templates/accueil.html b/Semaine_15/Jour_04/atelier-web/starter/templates/accueil.html deleted file mode 100644 index 7968ccb..0000000 --- a/Semaine_15/Jour_04/atelier-web/starter/templates/accueil.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "base.html" %} -{% block contenu %} -

Salle d'escalade Bloc&Co

-

Blocs, voies et cours collectifs, sept jours sur sept.

- -
- {{ nb_adherents }} - adhérent{{ 's' if nb_adherents > 1 else '' }} inscrit{{ 's' if nb_adherents > 1 else '' }} -
- - {% if not utilisateur %} -

Créer mon compte

- {% endif %} -{% endblock %} diff --git a/Semaine_15/Jour_04/atelier-web/starter/templates/admin.html b/Semaine_15/Jour_04/atelier-web/starter/templates/admin.html index f6c4257..b137475 100644 --- a/Semaine_15/Jour_04/atelier-web/starter/templates/admin.html +++ b/Semaine_15/Jour_04/atelier-web/starter/templates/admin.html @@ -1,25 +1,25 @@ {% extends "base.html" %} -{% block titre %}Administration — Bloc&Co{% endblock %} -{% block contenu %} +{% block title %}Administration — Bloc&Co{% endblock %} +{% block content %}

Administration

-

{{ adherents|length }} adhérent{{ 's' if adherents|length > 1 else '' }} enregistré{{ 's' if adherents|length > 1 else '' }}.

+

{{ members|length }} adhérent{{ 's' if members|length > 1 else '' }} enregistré{{ 's' if members|length > 1 else '' }}.

- + - {% for a in adherents %} + {% for m in members %} - - - - - + + + + + diff --git a/Semaine_15/Jour_04/atelier-web/starter/templates/base.html b/Semaine_15/Jour_04/atelier-web/starter/templates/base.html index b4de430..94da35c 100644 --- a/Semaine_15/Jour_04/atelier-web/starter/templates/base.html +++ b/Semaine_15/Jour_04/atelier-web/starter/templates/base.html @@ -3,22 +3,22 @@ - {% block titre %}Bloc&Co{% endblock %} + {% block title %}Bloc&Co{% endblock %}
- +
@@ -27,14 +27,14 @@ {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% endif %} {% endwith %} - {% block contenu %}{% endblock %} + {% block content %}{% endblock %} diff --git a/Semaine_15/Jour_04/atelier-web/starter/templates/home.html b/Semaine_15/Jour_04/atelier-web/starter/templates/home.html new file mode 100644 index 0000000..be0215d --- /dev/null +++ b/Semaine_15/Jour_04/atelier-web/starter/templates/home.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} +{% block content %} +

Salle d'escalade Bloc&Co

+

Blocs, voies et cours collectifs, sept jours sur sept.

+ +
+ {{ member_count }} + adhérent{{ 's' if member_count > 1 else '' }} inscrit{{ 's' if member_count > 1 else '' }} +
+ + {% if not user %} +

Créer mon compte

+ {% endif %} +{% endblock %} diff --git a/Semaine_15/Jour_04/atelier-web/starter/templates/connexion.html b/Semaine_15/Jour_04/atelier-web/starter/templates/login.html similarity index 61% rename from Semaine_15/Jour_04/atelier-web/starter/templates/connexion.html rename to Semaine_15/Jour_04/atelier-web/starter/templates/login.html index 0f3827c..1f31bfa 100644 --- a/Semaine_15/Jour_04/atelier-web/starter/templates/connexion.html +++ b/Semaine_15/Jour_04/atelier-web/starter/templates/login.html @@ -1,8 +1,8 @@ {% extends "base.html" %} -{% block titre %}Connexion — Bloc&Co{% endblock %} -{% block contenu %} +{% block title %}Connexion — Bloc&Co{% endblock %} +{% block content %}

Connexion

- + @@ -11,5 +11,5 @@ -

Pas encore de compte ? Inscrivez-vous.

+

Pas encore de compte ? Inscrivez-vous.

{% endblock %} diff --git a/Semaine_15/Jour_04/atelier-web/starter/templates/profil.html b/Semaine_15/Jour_04/atelier-web/starter/templates/profil.html deleted file mode 100644 index 4c2130a..0000000 --- a/Semaine_15/Jour_04/atelier-web/starter/templates/profil.html +++ /dev/null @@ -1,29 +0,0 @@ -{% extends "base.html" %} -{% block titre %}Mon profil — Bloc&Co{% endblock %} -{% block contenu %} -

Mon profil

- -
-
Adresse e-mail
{{ utilisateur.email }}
-
Rôle
{{ utilisateur.role }}
-
Inscrit depuis le
{{ utilisateur.sub_date }}
-
- -

Modifier mes informations

- - - - - - -{% endblock %} diff --git a/Semaine_15/Jour_04/atelier-web/starter/templates/profile.html b/Semaine_15/Jour_04/atelier-web/starter/templates/profile.html new file mode 100644 index 0000000..1dc4ee9 --- /dev/null +++ b/Semaine_15/Jour_04/atelier-web/starter/templates/profile.html @@ -0,0 +1,29 @@ +{% extends "base.html" %} +{% block title %}Mon profil — Bloc&Co{% endblock %} +{% block content %} +

Mon profil

+ +
+
Adresse e-mail
{{ user.email }}
+
Rôle
{{ user.role }}
+
Inscrit depuis le
{{ user.sub_date }}
+
+ +

Modifier mes informations

+ + + + + + +{% endblock %} diff --git a/Semaine_15/Jour_04/atelier-web/starter/templates/inscription.html b/Semaine_15/Jour_04/atelier-web/starter/templates/register.html similarity index 74% rename from Semaine_15/Jour_04/atelier-web/starter/templates/inscription.html rename to Semaine_15/Jour_04/atelier-web/starter/templates/register.html index 5255942..e7be020 100644 --- a/Semaine_15/Jour_04/atelier-web/starter/templates/inscription.html +++ b/Semaine_15/Jour_04/atelier-web/starter/templates/register.html @@ -1,12 +1,12 @@ {% extends "base.html" %} -{% block titre %}Inscription — Bloc&Co{% endblock %} -{% block contenu %} +{% block title %}Inscription — Bloc&Co{% endblock %} +{% block content %}

Créer un compte

- -
lastnameE-maillevelRôleInscription
NomE-mailNiveauRôleInscription
{{ a.firstname }} {{ a.lastname }}{{ a.email }}{{ a.level }}{{ a.role }}{{ a.sub_date }}{{ m.firstname }} {{ m.lastname }}{{ m.email }}{{ m.level }}{{ m.role }}{{ m.sub_date }} - {% if a.role != 'admin' %} -
- + {% if m.role != 'admin' %} + +
{% endif %}