diff --git a/app/main.py b/app/main.py index 46617db..df11f87 100644 --- a/app/main.py +++ b/app/main.py @@ -595,6 +595,11 @@ def settings_save( "(défini)" if ntfy_token.strip() else "(vide)", ) save_notif_config(user_id, ntfy_topic, ntfy_server, rappel_debut_h, rappel_fin_h, ntfy_token) + append_log( + user_id, "settings", "Réglages ntfy", + f"topic={ntfy_topic or '(vide)'} server={ntfy_server} plage={rappel_debut_h}h-{rappel_fin_h}h " + f"jeton={'défini' if ntfy_token.strip() else '(vide)'}", + ) return RedirectResponse("/settings?saved=1", status_code=303) @@ -639,6 +644,7 @@ def settings_regenerate_presence_token(request: Request): new_token = regenerate_presence_token(user_id) logger.warning("token de présence régénéré pour %r", user_id) + append_log(user_id, "settings", "Token présence régénéré", "Les URLs Tasker ont été invalidées et remplacées.") base_url = str(request.base_url).rstrip("/") arrivee_url = f"{base_url}/presence/{new_token}/arrivee" @@ -691,6 +697,13 @@ def settings_plages_save( logger.info("réglages plages mis à jour: user_id=%r plages=%r", user_id, fields) save_plages(user_id, fields) + append_log( + user_id, "settings", "Plages horaires", + f"matin {fields['matin_debut']}→{fields['matin_fin']}, " + f"aprem {fields['aprem_debut']}→{fields['aprem_fin']}, " + f"reprise {fields['pause_dejeuner_fin']}" + + (f", visées {fields['arrivee_visee']}→{fields['depart_vise']}" if fields['arrivee_visee'] or fields['depart_vise'] else ""), + ) return RedirectResponse("/settings?plages_saved=1", status_code=303) diff --git a/app/models.py b/app/models.py index dd9286c..983471e 100644 --- a/app/models.py +++ b/app/models.py @@ -272,7 +272,7 @@ def toggle_conge(date: str, type_conge: str, user_id: str = ""): # ── Journaux (notifications + présence) ─────────────────────────────────────── -LOG_TYPES = ("notif", "presence") +LOG_TYPES = ("notif", "presence", "settings") MAX_LOGS = 500 diff --git a/app/templates/logs.html b/app/templates/logs.html index 1e68289..303ed6e 100644 --- a/app/templates/logs.html +++ b/app/templates/logs.html @@ -10,7 +10,7 @@
- {% set counts = {'all': logs|length, 'notif': logs | selectattr('type', 'equalto', 'notif') | list | length, 'presence': logs | selectattr('type', 'equalto', 'presence') | list | length} %} + {% set counts = {'all': logs|length, 'notif': logs | selectattr('type', 'equalto', 'notif') | list | length, 'presence': logs | selectattr('type', 'equalto', 'presence') | list | length, 'settings': logs | selectattr('type', 'equalto', 'settings') | list | length} %} Tout {{ counts.all }} @@ -20,6 +20,9 @@ Présence {{ counts.presence }} + + Réglages {{ counts.settings }} +
{% set visible = logs if filter == 'all' else logs | selectattr('type', 'equalto', filter) | list %} @@ -29,7 +32,7 @@ {% for entry in visible %}
{{ entry.ts }}
-
{{ 'Notification' if entry.type == 'notif' else 'Présence' }}
+
{{ {'notif': 'Notification', 'presence': 'Présence', 'settings': 'Réglages'}[entry.type] }}
{{ entry.event }} {% if entry.message %}{{ entry.message }}{% endif %} @@ -105,6 +108,7 @@ } .log-notif .log-type { color: var(--accent); } .log-presence .log-type { color: var(--accent-2); } +.log-settings .log-type { color: var(--conge-txt); } .log-body { display: flex; flex-direction: column; gap: .15rem; } .log-event { font-weight: 500; diff --git a/app/tests/test_logs.py b/app/tests/test_logs.py index 37482d7..e065035 100644 --- a/app/tests/test_logs.py +++ b/app/tests/test_logs.py @@ -299,3 +299,50 @@ def test_regenerate_preserves_other_notif_fields(): assert after["ntfy_topic"] == "topic-x" assert after["ntfy_server"] == "https://ntfy.arkel.fr" assert after["ntfy_token"] == "tk_xyz" + + +# ── Changements de paramètres tracés dans le journal ───────────────────────── + +def test_settings_save_logged(): + """Sauvegarder les réglages ntfy doit écrire une entrée de journal.""" + models.save_notif_config("alice", ntfy_topic="t", ntfy_server="https://ntfy.sh") + before = len([l for l in models.load_logs("alice") if l["type"] == "settings"]) + client.post("/settings", cookies=COOKIES, data={ + "ntfy_topic": "topic-new", + "ntfy_server": "https://ntfy.arkel.fr", + "ntfy_token": "tk_abc", + "rappel_debut_h": "8", + "rappel_fin_h": "19", + }) + after = [l for l in models.load_logs("alice") if l["type"] == "settings"] + assert len(after) == before + 1 + latest = after[0] + assert latest["event"] == "Réglages ntfy" + assert "topic-new" in latest["message"] + assert "ntfy.arkel.fr" in latest["message"] + + +def test_settings_plages_save_logged(): + """Sauvegarder les plages horaires doit écrire une entrée de journal.""" + before = len([l for l in models.load_logs("alice") if l["type"] == "settings"]) + client.post("/settings/plages", cookies=COOKIES, data={ + "matin_debut": "09:00", "matin_fin": "12:00", + "aprem_debut": "14:00", "aprem_fin": "17:00", + "pause_dejeuner_fin": "13:30", + "arrivee_visee": "", "depart_vise": "", + }) + after = [l for l in models.load_logs("alice") if l["type"] == "settings"] + assert len(after) == before + 1 + latest = after[0] + assert latest["event"] == "Plages horaires" + assert "09:00" in latest["message"] + + +def test_regenerate_presence_token_logged(): + """Régénérer le token de présence doit écrire une entrée de journal.""" + before = len([l for l in models.load_logs("alice") if l["type"] == "settings"]) + client.post("/settings/regenerate-presence-token", cookies=COOKIES) + after = [l for l in models.load_logs("alice") if l["type"] == "settings"] + assert len(after) == before + 1 + latest = after[0] + assert "régénéré" in latest["event"].lower()