Commit Graph

164 Commits

Author SHA1 Message Date
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
Colin Maudry 35e72645bd feat: add write_styled_excel utility for styled Excel exports #83
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 17:05:55 +02:00
Colin Maudry 2413ffb4f0 test(tableaux): barre miroir et en-tête sticky sur /tableau #82
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 16:05:49 +02:00
Colin Maudry 3e305845dd Fix réduction du nombre de colonne, ajoute de lla colonne Marché #84 2026-06-23 15:28:42 +02:00
Colin Maudry 074716bc16 feat(observatoire): restructurer tuile en 3 barres
- Barre 1 (grise) : % marchés avec champs considérations renseignés
- Barre 2 (rose)  : % positifs parmi les marchés renseignés — sociales
- Barre 3 (verte) : % positifs parmi les marchés renseignés — env

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 22:21:37 +02:00
Colin Maudry ae8292d68d fix(observatoire): filtre renseignées sur != 'Sans objet' plutôt que regex
Seule 'Sans objet' est considérée négative parmi les marchés renseignés,
cohérent avec le reste des traitements.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 22:02:37 +02:00
Colin Maudry 26455a7616 fix(observatoire): barre renseignée = positifs parmi les marchés renseignés
Dénominateur = marchés non-null ; numérateur = marchés positifs (regex).
Label affiché : "parmi les N marchés renseignés".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 21:18:00 +02:00
Colin Maudry 19e181734c feat(observatoire): ajouter barres 'valeur renseignée' dans tuile considérations
Affiche 4 barres groupées par type (sociales/env) : une pour les marchés
avec au moins une considération, une pour ceux qui ont une valeur renseignée
(non nulle, y compris 'Sans objet').

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 18:55:38 +02:00
Colin Maudry 8efd9b45eb fix(observatoire): texte % blanc sur les barres de considérations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 18:46:37 +02:00
Colin Maudry eab06eedae fix(observatoire): couleurs barres considérations palette Plotly Safe
Utilise les codes hex #CC6677 (sociales) et #117733 (env) via le prop
color de dbc.Progress, qui accepte les valeurs hex.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 18:45:33 +02:00
Colin Maudry a85baca408 feat(observatoire): calcul et rendu tuile considérations sociales/env
Ajoute compute_considerations_stats (dédoublonnage par uid, regex
Clause|Critère|Marché réservé, colonne absente → 0%) et
get_considerations_card_content (deux dbc.Progress colorés Safe).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 18:16:34 +02:00
Colin Maudry 992f6d4f93 Recherche dans les tableaux insensible aux accents #79 2026-06-22 17:46:31 +02:00
Colin Maudry 966d193ec4 test(api): benchmark comparatif decp.info vs data.gouv.fr (#78)
Requête identique envoyée aux deux APIs (drapeaux d'agrégation nus),
tableau côte à côte + ratio decp/datagouv. Couvre filtres, differs,
agrégation. --url decp.info paramétrable (défaut prod), data.gouv.fr
sans auth.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 15:16:35 +02:00
Colin Maudry b87eb4328c docs(api): documente les opérateurs (filtres + agrégation) dans Swagger (#78)
Remplace la description du paramètre <colonne>__<opérateur> par une
documentation complète listant tous les opérateurs de filtre (exact, differs,
contains, notcontains, in, notin, less, greater, strictly_less,
strictly_greater, isnull, isnotnull, sort) et les agrégations (groupby, count,
sum, avg, min, max).

Met à jour le docstring de data() pour documenter le mode agrégation et les
paramètres réservés.

Ajoute test_openapi_doc.py qui valide la présence des mots-clés clés dans
l'OpenAPI généré.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 14:09:34 +02:00
Colin Maudry 7c9a95355b feat(api): mode agrégation sur /data (groupby + agrégats) (#78) 2026-06-22 14:06:44 +02:00
Colin Maudry 28709a162a feat(db): aggregate_marches pour les requêtes GROUP BY (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 14:04:08 +02:00
Colin Maudry 9324a734d4 feat(api): parsing des opérateurs d'agrégation (groupby/count/sum/avg/min/max) (#78) 2026-06-22 13:59:50 +02:00
Colin Maudry 2a8e82ccd6 feat(api): ajoute l'opérateur de filtre differs (IS DISTINCT FROM) (#78)
Implémente l'opérateur de filtre `differs` qui génère un fragment SQL
`IS DISTINCT FROM` pour exclure des valeurs en tenant compte des NULL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 13:55:18 +02:00
Colin Maudry f5db674e22 feat(api): renomme le param réservé count en count_results (#78)
- Renomme RESERVED_PARAMS dans src/api/filters.py
- Fait passer le paramètre de 'count' à 'count_results' dans src/api/routes.py
- Met à jour la documentation swagger pour le nouveau nom

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 13:50:12 +02:00
Colin Maudry ffaf200c07 api/v1/schema n'est plus auth, schema renvoie table schema, adaptation des tests #78 2026-06-16 17:03:14 +02:00
Colin Maudry cb93dbe05a feat: chargements de pages best-effort au boot (tableau, sources) (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 13:58:50 +02:00
Colin Maudry fa2709b38c fix: re-vérifier db_path.exists() dans le handler et assertion return value (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 13:50:57 +02:00
Colin Maudry bba53d81e1 feat: réutiliser le DuckDB existant si le bootstrap échoue (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 13:48:32 +02:00
Colin Maudry 42ba73cd36 feat: schéma résilient URL→cache + suppression DATA_SCHEMA_LOCAL (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 13:26:03 +02:00
Colin Maudry 21c65c34fb test: réparer le baseline test_db cassé par le merge (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 11:37:54 +02:00
Colin Maudry 2f0cbada34 API: corriger flush() et isolation test compteur (#78) 2026-05-13 14:45:26 +02:00
Colin Maudry 985af0fdc7 API: envoi Matomo fire-and-forget en async (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 14:34:52 +02:00
Colin Maudry 912507b1d9 API: compteur de consommation SQLite asynchrone (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 14:31:22 +02:00
Colin Maudry 04c8bb8b6d API: tests d'intégration filtres/tri/columns (#78) 2026-05-13 14:28:18 +02:00
Colin Maudry 6d2a95d775 API: retirer benchmark non demandé (#78) 2026-05-13 14:16:27 +02:00
Colin Maudry 6c591aeb08 API: endpoint /data avec pagination et filtres (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 14:15:19 +02:00
Colin Maudry 7571b9a984 API: script de benchmark tests/benchmark_api.py (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 14:12:27 +02:00
Colin Maudry 6f4e7f1853 API: endpoint /schema (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 14:10:20 +02:00
Colin Maudry a05c869b0d API: renforcer test intégration /health (#78) 2026-05-13 14:08:30 +02:00
Colin Maudry 686218c639 API: branchement init_api dans l'app Dash (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 14:07:47 +02:00
Colin Maudry f24d0ba168 API: blueprint flask-smorest + endpoint /health (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 13:52:06 +02:00
Colin Maudry f12ada2fac API: décorateur @require_token (#78) 2026-05-13 13:49:01 +02:00
Colin Maudry a3cfad3d8f API: parser de filtres et génération SQL paramétré (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 13:45:55 +02:00
Colin Maudry 4b67cde147 API: CLI tokens_cli (create/list/revoke) (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 13:34:05 +02:00
Colin Maudry ca44b99016 API: tokens_db SQLite CRUD (#78) 2026-05-13 13:19:50 +02:00
Colin Maudry bc3b09e2a9 API: dépendances et squelette de package (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 13:04:09 +02:00
Colin Maudry 755b8c13ab Bug nom colonne, amélioration test #76 2026-05-05 14:56:59 +02:00