Commit Graph

155 Commits

Author SHA1 Message Date
Colin Maudry 8cd5bfe821 fix(csrf): supprimer prevent_initial_call=True sur _fill_csrf_inputs
Avec prevent_initial_call=True, le callback ne s'exécutait pas lors de
la chaîne initiale (_generate_csrf_token → csrf-token), laissant le champ
csrf_token vide au premier chargement direct de /connexion → erreur 400.

Ajoute des tests comportementaux avec CSRF activé (comme en production) et
un test architectural qui vérifie que le callback reste appelable initialement.
Corrige aussi les assertions de redirection post-login (/compte/abonnement).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 15:46:30 +02:00
Colin Maudry 8faeaa5804 Bandeau TOUS_ABONNES et boutons S'abonner désactivés
Affiche un bandeau d'info sur /compte/abonnement et grise les boutons
S'abonner quand l'accès gratuit pour tous est activé.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 18:12:58 +02:00
Colin Maudry 2bdcfdeb1a Ajoute le drapeau TOUS_ABONNES pour l'accès gratuit
Ouvre les fonctionnalités d'abonné à tout utilisateur connecté tant que
Frisbii n'a pas validé la réception de paiements.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 18:06:27 +02:00
Colin Maudry e229caf320 Fix affichage jours d'essai 2026-06-25 22:41:48 +02:00
Colin Maudry e932c66af0 Corrections des bugs de la connexion à Frisbii #90 2026-06-25 21:14:35 +02:00
Colin Maudry 5f500a1aa8 fix(abonnement): garde active→pending, datetime parse, resolve_handle vide (#90)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DRGb8NAMwaTZxUszSbaj4N
2026-06-25 19:26:15 +02:00
Colin Maudry d3025e323b feat(abonnement): page /compte/abonnement + accès premium réel (#90)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DRGb8NAMwaTZxUszSbaj4N
2026-06-25 19:08:22 +02:00
Colin Maudry 3d1cb69463 feat(abonnement): routes subscribe/cancel/webhook + câblage app (#90) 2026-06-25 19:00:53 +02:00
Colin Maudry 4b1d8bf5c3 feat(abonnement): signature + mapping des webhooks Frisbii (#90) 2026-06-25 18:56:26 +02:00
Colin Maudry 4f90184ddd feat(abonnement): catalogue de plans + durée d'essai dynamique (#90) 2026-06-25 18:53:41 +02:00
Colin Maudry b7a79d8d86 feat(abonnement): table subscriptions + état (#90) 2026-06-25 18:50:50 +02:00
Colin Maudry 007cb28b21 feat(abonnement): client HTTP Frisbii (#90)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DRGb8NAMwaTZxUszSbaj4N
2026-06-25 18:47:21 +02:00
Colin Maudry 6d07dcb0bb orjson pour sérialiser les sorties API 2026-06-25 13:04:24 +02:00
Colin Maudry 590b927e31 fix(auth): corrections runtime LinkedIn OAuth (#88)
- Workaround nonce OIDC LinkedIn (non-conformité) : capture MissingClaimError après échange de code réussi et fetch userinfo séparément
- Ajout token_endpoint_auth_method: client_secret_post (requis par LinkedIn)
- suppress_callback_exceptions=True pour corriger les erreurs Dash multi-pages
- Suppression bouton déconnexion redondant sur /compte/admin et style hover incorrect sur la navbar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 00:38:01 +02:00
Colin Maudry aac3753226 feat(auth): bouton Connexion avec LinkedIn sur connexion/inscription (#88)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 23:18:41 +02:00
Colin Maudry 9f10f1c4de feat(auth): routes /auth/linkedin et callback OIDC (#88)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 23:14:29 +02:00
Colin Maudry d79e990c04 feat(auth): init Authlib + provider LinkedIn (config env) (#88)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 23:11:26 +02:00
Colin Maudry d72cad90ec feat(auth): resolve_oauth_user (liaison/création de compte OIDC) (#88)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 23:07:46 +02:00
Colin Maudry 44031efcd5 feat(auth): oauth_identities table + password_hash nullable (#88)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-24 23:04:18 +02:00
Colin Maudry ff7aaa54cd fix(auth): vérification promote_pending_email, purge tokens change-email, fallback login (#73)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 22:25:34 +02:00
Colin Maudry dba8669f4b test(compte): redirections d'accès de l'espace compte (#73)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 22:16:02 +02:00
Colin Maudry 6144e3c18d feat(auth): route delete-account avec confirmation par mot de passe (#73) 2026-06-24 18:49:52 +02:00
Colin Maudry 558df9627b feat(auth): routes change-email + confirm-email-change (#73)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 18:48:08 +02:00
Colin Maudry 90261d4f31 feat(auth): email de confirmation de changement d'adresse (#73)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 18:45:37 +02:00
Colin Maudry 4602b45f30 feat(compte): coquille account_shell (sidebar + offcanvas + garde d'accès) (#73)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 18:43:53 +02:00
Colin Maudry f301a0a336 feat(auth): email en attente (pending_email) + migration (#73)
Adds pending_email column to users table with idempotent migration.
Implements set_pending_email() and promote_pending_email() for email-change workflow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 18:43:04 +02:00
Colin Maudry ac3ba89c0a fix(backup): retirer users.sqlite du suivi git, logging, test restore CLI, garde snapshot (#89)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:45:40 +02:00
Colin Maudry 1453990f7a feat(backup): CLI backup/list/restore (#89)
Implement CLI interface for the backup module with three subcommands:
- backup: create a backup and apply rotation
- list: list available backups
- restore: restore a specific backup

Also add __main__.py to enable 'python -m src.backup'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:23:57 +02:00
Colin Maudry ded5e66ccc fix(backup): nettoyer le fichier temporaire en cas d'erreur dans restore (#89)
Wraps temp file operations in try/except to ensure the temporary database file is always cleaned up, even if an exception occurs during write_snapshot or verify_integrity.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:21:28 +02:00
Colin Maudry cae0a528f3 feat(backup): orchestration backup/list/restore (#89)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:18:47 +02:00
Colin Maudry 0234505932 refactor(backup): type hints sur FakeStorage (#89) 2026-06-24 17:16:40 +02:00
Colin Maudry 108592f289 feat(backup): wrapper de stockage S3 (boto3) + faux stockage de test (#89) 2026-06-24 17:13:17 +02:00
Colin Maudry efefc3f5b0 feat(backup): snapshot SQLite cohérent et contrôle d'intégrité (#89)
Implémente les trois fonctions de gestion de snapshots SQLite:
- make_snapshot: crée un snapshot gzippé cohérent via sqlite3.Connection.backup()
- write_snapshot: écrit le snapshot décompressé à destination
- verify_integrity: valide l'intégrité d'une base avec PRAGMA integrity_check

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:10:22 +02:00
Colin Maudry 2a691e37b7 feat(backup): chiffrement Fernet des sauvegardes
- Ajouter encrypt() et decrypt() avec clés Fernet urlsafe-base64
- Tests de roundtrip et échec avec mauvaise clé

Fixes #89
2026-06-24 17:08:34 +02:00
Colin Maudry 927f56cb1c feat(backup): rotation multi-paliers (fonction pure)
Implémente la fonction select_retained() pour la rétention multi-paliers:
- Paliers fixes: horaire/12h, 12h/72h, quotidien/21j
- Palier mensuel: 12 mois calendaires
- Fonction pure, pas de dépendances sur d'autres modules backup

Fixes #89
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:06:27 +02:00
Colin Maudry 48c0649a68 feat(backup): nommage horodaté des clés S3 (#89)
Ajoute les fonctions make_key() et parse_timestamp() pour gérer
le format des clés S3 avec horodatage UTC.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:02:47 +02:00
Colin Maudry 1d2a945aa1 feat(backup): config et dépendances pour la sauvegarde S3 (#89) 2026-06-24 17:00:34 +02:00
Colin Maudry 3f1c39d5a6 fix(brevo): passer X-Sib-Sandbox dans le body email, pas en header HTTP (#87)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 16:22:42 +02:00
Colin Maudry c3408ecc3c refactor(brevo): utiliser DEVELOPMENT pour le mode sandbox Brevo (#87)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:40:46 +02:00
Colin Maudry c0927c718d test(brevo): test d'intégration sandbox optionnel (#87)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:35:23 +02:00
Colin Maudry e4c291a785 feat(brevo): envoyer les emails transactionnels via l'API Brevo v5 (#87)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:33:14 +02:00
Colin Maudry 7be0332f02 Merge branch 'dev' into feature/73_compte_utilisateur 2026-06-24 05:34:27 +02:00
Colin Maudry 8830b2ac91 fix(test): mettre à jour les assertions de compute_considerations_stats pour le retour en 3-tuple
La fonction retourne désormais (count_ren, count_pos_ren, pct) pour les clés
_renseignees, mais les tests attendaient encore l'ancien format (count_ren, pct).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 05:34:03 +02:00
Colin Maudry c99f4d970e fix(csrf): centraliser l'injection des tokens CSRF via un dcc.Store et un callback pattern-matching
Remplace les 7 callbacks CSRF individuels (un par formulaire, avec IDs string
page-spécifiques) par un seul dcc.Store(id="csrf-token") dans le layout principal
et un callback pattern-matching Output({"type": "csrf-input", "index": ALL}).
Évite les erreurs Dash "id non trouvé dans le layout" sans recourir à
suppress_callback_exceptions=True.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 05:26:07 +02:00
Colin Maudry c228f7be55 fix(auth): corriger le lien de validation email et l'isolation des tests
Le lien de vérification pointait vers la page Dash /verification-email
(qui se contente de rediriger vers /connexion) au lieu de la route
backend /auth/verify-email qui consomme réellement le token et marque
l'email comme vérifié. Conséquence : l'email n'était jamais validé et le
login renvoyait email_not_verified en boucle.

Ajoute aussi MAIL_SUPPRESS_SEND=true au bloc env de pytest : sans cela,
le load_dotenv() de src.app injectait MAIL_SUPPRESS_SEND=false depuis le
.env local, désactivant la suppression d'envoi et faisant échouer les
tests d'auth qui envoient un email (selon l'ordre d'import).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 03:55:52 +02:00
Colin Maudry cbce646fd8 Merge branch 'dev' into feature/73_compte_utilisateur 2026-06-24 03:01:43 +02:00
Colin Maudry d99bb00d6c Compactage 2026-06-23 20:16:51 +02:00
Colin Maudry ad0a220953 feat(tableaux): scroll horizontal ergonomique + barre custom (#82)
- Barre de défilement JS orange (12px) injectée en haut de chaque
  .marches_table, collée avec position:sticky, masquée si le tableau
  tient dans le viewport
- Scroll contenu dans .dash-spreadsheet-container (overflow-x:hidden)
  → plus de scrollbar navigateur en bas de page
- Drag souris + tactile, clic sur le track, molette/trackpad
- Recalcul automatique au resize et aux re-renders Dash (MutationObserver)
- Test Selenium de non-régression (overflow-x:hidden sur le conteneur)

Sticky headers abandonnés (incompatibles avec scroll contenu).
Portée : 4 pages via la classe partagée .marches_table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 20:12:47 +02:00
Colin Maudry f508c821c2 test(tableaux): adapter test post-abandon sticky headers #82
Le test ne vérifie plus position:sticky sur th (sticky abandonné car
incompatible avec scroll contenu). Vérifie à la place que overflow-x:hidden
est bien en place sur le conteneur Dash — garantit l'absence de scrollbar
navigateur en bas de page.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 20:00:41 +02:00
Colin Maudry e5ca7d62a3 fix: protect wb.close() with try/finally, strengthen width assertions, declare openpyxl dev dep #83
- I-1: Add explicit lower bounds to width assertions (>= 15 for autre, >= 40 for objet)
- I-2: Wrap write_excel() and close() in try/finally to ensure cleanup even on exception
- M-2: Add openpyxl to dev dependencies in pyproject.toml

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 17:08:32 +02:00