refactor: rebrand decp.info to colibre #57
- Rename project from decp.info to colibre across all codebase - Update domain from https://decp.info to https://colibre.fr - Update GitHub repo references to ColinMaudry/colibre - Rename deployment files: decpinfo-backup.* → colibre-backup.* - Update project configuration and documentation - Rename project assets: decp.info.png → colibre.png - Update environment variables and constants (DOMAIN_NAME, TOKEN_PREFIX, GITHUB_REPO, etc.) - Update URLs in all pages, tests, and configuration files - Keep DECP acronym in text (unchanged per requirements) - Add rebrand note to README.md Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
+3
-3
@@ -8,9 +8,9 @@ build
|
|||||||
.env
|
.env
|
||||||
|
|
||||||
# DuckDB runtime artifacts (regenerated from decp_prod.parquet at startup)
|
# DuckDB runtime artifacts (regenerated from decp_prod.parquet at startup)
|
||||||
**/decp.duckdb
|
**/colibre.duckdb
|
||||||
**/decp.duckdb.tmp
|
**/colibre.duckdb.tmp
|
||||||
**/decp.duckdb.lock
|
**/colibre.duckdb.lock
|
||||||
**/schema.cache.json
|
**/schema.cache.json
|
||||||
|
|
||||||
# Runtime databases (never commit)
|
# Runtime databases (never commit)
|
||||||
|
|||||||
+6
-6
@@ -1,5 +1,5 @@
|
|||||||
DATA_FILE_PARQUET_PATH=https://www.data.gouv.fr/fr/datasets/r/11cea8e8-df3e-4ed1-932b-781e2635e432
|
DATA_FILE_PARQUET_PATH=https://www.data.gouv.fr/fr/datasets/r/11cea8e8-df3e-4ed1-932b-781e2635e432
|
||||||
DUCKDB_PATH=./decp.duckdb
|
DUCKDB_PATH=./colibre.duckdb
|
||||||
PORT=8050
|
PORT=8050
|
||||||
DEVELOPMENT=True
|
DEVELOPMENT=True
|
||||||
SOURCE_STATS_CSV_PATH="https://www.data.gouv.fr/api/1/datasets/r/8ded94de-3b80-4840-a5bb-7faad1c9c234"
|
SOURCE_STATS_CSV_PATH="https://www.data.gouv.fr/api/1/datasets/r/8ded94de-3b80-4840-a5bb-7faad1c9c234"
|
||||||
@@ -43,12 +43,12 @@ LINKEDIN_CLIENT_SECRET=
|
|||||||
BREVO_API_KEY= # clé API transactionnelle Brevo
|
BREVO_API_KEY= # clé API transactionnelle Brevo
|
||||||
BREVO_TEMPLATE_VERIFY_ID= # ID numérique du template "vérification d'adresse"
|
BREVO_TEMPLATE_VERIFY_ID= # ID numérique du template "vérification d'adresse"
|
||||||
BREVO_TEMPLATE_RESET_ID= # ID numérique du template "réinitialisation mot de passe"
|
BREVO_TEMPLATE_RESET_ID= # ID numérique du template "réinitialisation mot de passe"
|
||||||
MAIL_FROM=noreply@decp.info # expéditeur (doit être un expéditeur vérifié dans Brevo)
|
MAIL_FROM=noreply@colibre.fr # expéditeur (doit être un expéditeur vérifié dans Brevo)
|
||||||
MAIL_FROM_NAME=decp.info # nom d'expéditeur
|
MAIL_FROM_NAME=colibre # nom d'expéditeur
|
||||||
|
|
||||||
# Sauvegarde de users.sqlite vers un stockage S3-compatible
|
# Sauvegarde de users.sqlite vers un stockage S3-compatible
|
||||||
S3_ENDPOINT_URL=https://s3.exemple.net
|
S3_ENDPOINT_URL=https://s3.exemple.net
|
||||||
S3_BUCKET=decp-backups
|
S3_BUCKET=colibre-backups
|
||||||
S3_BACKUP_PREFIX=backups
|
S3_BACKUP_PREFIX=backups
|
||||||
S3_ACCESS_KEY_ID=
|
S3_ACCESS_KEY_ID=
|
||||||
S3_SECRET_ACCESS_KEY=
|
S3_SECRET_ACCESS_KEY=
|
||||||
@@ -60,8 +60,8 @@ BACKUP_ENCRYPTION_KEY=
|
|||||||
# Frisbii — gestion des abonnements (https://docs.frisbii.com)
|
# Frisbii — gestion des abonnements (https://docs.frisbii.com)
|
||||||
FRISBII_API_KEY= # clé PRIVÉE (priv_...), serveur uniquement
|
FRISBII_API_KEY= # clé PRIVÉE (priv_...), serveur uniquement
|
||||||
FRISBII_API_BASE_URL=https://api.frisbii.com # base de l'API Frisbii (déf. https://api.reepay.com, à confirmer)
|
FRISBII_API_BASE_URL=https://api.frisbii.com # base de l'API Frisbii (déf. https://api.reepay.com, à confirmer)
|
||||||
FRISBII_PLAN_SIMPLE=abonnement-decp.info # handle du plan "abonnement simple" (20 € HT/mois)
|
FRISBII_PLAN_SIMPLE=abonnement-colibre # handle du plan "abonnement simple" (20 € HT/mois)
|
||||||
FRISBII_PLAN_SOUTIEN=soutien-decp.info # handle du plan "abonnement de soutien" (50 € HT/mois)
|
FRISBII_PLAN_SOUTIEN=soutien-colibre # handle du plan "abonnement de soutien" (50 € HT/mois)
|
||||||
FRISBII_WEBHOOK_SECRET= # secret de signature des webhooks
|
FRISBII_WEBHOOK_SECRET= # secret de signature des webhooks
|
||||||
|
|
||||||
# Accès gratuit temporaire
|
# Accès gratuit temporaire
|
||||||
|
|||||||
+19
-19
@@ -1,7 +1,7 @@
|
|||||||
##### 2.9.0
|
##### 2.9.0
|
||||||
|
|
||||||
- Comptes utilisateurs : inscription avec vérification d'email, connexion, réinitialisation de mot de passe, page compte ([#73](https://github.com/ColinMaudry/decp.info/issues/73))
|
- Comptes utilisateurs : inscription avec vérification d'email, connexion, réinitialisation de mot de passe, page compte ([#73](https://github.com/ColinMaudry/colibre/issues/73))
|
||||||
- Sauvegarde régulière de la base de données des utilisateurs ([#89](https://github.com/ColinMaudry/decp.info/issues/89))
|
- Sauvegarde régulière de la base de données des utilisateurs ([#89](https://github.com/ColinMaudry/colibre/issues/89))
|
||||||
- Ajout des codes et libellés NAF des titulaires
|
- Ajout des codes et libellés NAF des titulaires
|
||||||
- Affichage de l'activité (NAF) des titulaires sur leur page /titulaire
|
- Affichage de l'activité (NAF) des titulaires sur leur page /titulaire
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
##### 2.7.4 (22 avril 2026)
|
##### 2.7.4 (22 avril 2026)
|
||||||
|
|
||||||
- Utilisation élargie de DuckDB au détriment de Polars => bien meilleure perf ([#72](https://github.com/ColinMaudry/decp.info/issues/72)
|
- Utilisation élargie de DuckDB au détriment de Polars => bien meilleure perf ([#72](https://github.com/ColinMaudry/colibre/issues/72)
|
||||||
|
|
||||||
##### 2.7.3 (20 avril 2026)
|
##### 2.7.3 (20 avril 2026)
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
|
|
||||||
##### 2.7.2 (19 avril 2026)
|
##### 2.7.2 (19 avril 2026)
|
||||||
|
|
||||||
- Chargement des données depuis une base DuckDB plutôt qu'en mémoire (plus de stabilité) ([#71](https://github.com/ColinMaudry/decp.info/issues/71))
|
- Chargement des données depuis une base DuckDB plutôt qu'en mémoire (plus de stabilité) ([#71](https://github.com/ColinMaudry/colibre/issues/71))
|
||||||
- Mise en cache des vue sur l'observatoire pour un chargement plus rapide (remise à zéro quotidienne)
|
- Mise en cache des vue sur l'observatoire pour un chargement plus rapide (remise à zéro quotidienne)
|
||||||
- Correction de bug : la liste de colonnes par défaut est bien appliquée plutôt qu'afficher toutes les colonnes
|
- Correction de bug : la liste de colonnes par défaut est bien appliquée plutôt qu'afficher toutes les colonnes
|
||||||
- Quelques corrections de bugs d'affichage
|
- Quelques corrections de bugs d'affichage
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
|
|
||||||
##### 2.5.1 (29 janvier 2026)
|
##### 2.5.1 (29 janvier 2026)
|
||||||
|
|
||||||
- Mise en production un peu hâtive ([#67](https://github.com/ColinMaudry/decp.info/issues/67), [#68](https://github.com/ColinMaudry/decp.info/issues/68))
|
- Mise en production un peu hâtive ([#67](https://github.com/ColinMaudry/colibre/issues/67), [#68](https://github.com/ColinMaudry/colibre/issues/68))
|
||||||
|
|
||||||
#### 2.5.0 (29 janvier 2026)
|
#### 2.5.0 (29 janvier 2026)
|
||||||
|
|
||||||
@@ -101,11 +101,11 @@
|
|||||||
|
|
||||||
#### 2.4.0 (22 janvier 2026)
|
#### 2.4.0 (22 janvier 2026)
|
||||||
|
|
||||||
- Site à peu près utilisable sur petit écran (smartphone) ([#63](https://github.com/ColinMaudry/decp.info/issues/63))
|
- Site à peu près utilisable sur petit écran (smartphone) ([#63](https://github.com/ColinMaudry/colibre/issues/63))
|
||||||
- Ajout de nouvelles statistiques dans [/statistiques](https://decp.info/statistiques) (stats par année, doublons par source)
|
- Ajout de nouvelles statistiques dans [/statistiques](https://decp.info/statistiques) (stats par année, doublons par source)
|
||||||
- Amélioration du référencement Web (sitemap, titres, descriptions) ([#50](https://github.com/ColinMaudry/decp.info/issues/50))
|
- Amélioration du référencement Web (sitemap, titres, descriptions) ([#50](https://github.com/ColinMaudry/colibre/issues/50))
|
||||||
- Possibilité dans les champs non-numériques de filtrer le texte selon son début ou sa fin (`text*` et `*text`)
|
- Possibilité dans les champs non-numériques de filtrer le texte selon son début ou sa fin (`text*` et `*text`)
|
||||||
- Ajout d'une table des matières dans la page [À propos](https://decp.infi/a-propos) ([#36](https://github.com/ColinMaudry/decp.info/issues/36))
|
- Ajout d'une table des matières dans la page [À propos](https://decp.infi/a-propos) ([#36](https://github.com/ColinMaudry/colibre/issues/36))
|
||||||
- Désactivation du bloquage des robot d'agents de LLM (robots.txt)
|
- Désactivation du bloquage des robot d'agents de LLM (robots.txt)
|
||||||
|
|
||||||
##### 2.3.1 (16 janvier 2026)
|
##### 2.3.1 (16 janvier 2026)
|
||||||
@@ -136,9 +136,9 @@
|
|||||||
|
|
||||||
#### 2.2.0 (13 novembre 2025)
|
#### 2.2.0 (13 novembre 2025)
|
||||||
|
|
||||||
- Moteur de recherche (acheteurs et titulaires) en page d'accueil ([#58](https://github.com/ColinMaudry/decp.info/issues/58))
|
- Moteur de recherche (acheteurs et titulaires) en page d'accueil ([#58](https://github.com/ColinMaudry/colibre/issues/58))
|
||||||
- Top acheteurs / titulaires par montant attribué/remporté (([#55](https://github.com/ColinMaudry/decp.info/issues/55)))
|
- Top acheteurs / titulaires par montant attribué/remporté (([#55](https://github.com/ColinMaudry/colibre/issues/55)))
|
||||||
- Moins de colonnes affichées par défaut dans Tableau ([#54](https://github.com/ColinMaudry/decp.info/issues/54))
|
- Moins de colonnes affichées par défaut dans Tableau ([#54](https://github.com/ColinMaudry/colibre/issues/54))
|
||||||
|
|
||||||
##### 2.1.7 (11 novembre 2025)
|
##### 2.1.7 (11 novembre 2025)
|
||||||
|
|
||||||
@@ -169,22 +169,22 @@
|
|||||||
|
|
||||||
##### 2.1.1 (1er octobre 2025)
|
##### 2.1.1 (1er octobre 2025)
|
||||||
|
|
||||||
- ajout d'une section dans À propos sur la qualité et l'exhaustivité des données ([#43](https://github.com/ColinMaudry/decp.info/issues/43))
|
- ajout d'une section dans À propos sur la qualité et l'exhaustivité des données ([#43](https://github.com/ColinMaudry/colibre/issues/43))
|
||||||
- ajout du nombre de marchés en plus du nombre de lignes dans la vue Tableau
|
- ajout du nombre de marchés en plus du nombre de lignes dans la vue Tableau
|
||||||
|
|
||||||
#### 2.1.0 (30 septembre 2025)
|
#### 2.1.0 (30 septembre 2025)
|
||||||
|
|
||||||
- Ajout des vues [acheteur](https://decp.info/acheteurs/24350013900189) ([#28](https://github.com/ColinMaudry/decp.info/issues/28)), [titulaire](https://decp.info/titulaires/51903758414786) ([#35](https://github.com/ColinMaudry/decp.info/issues/35)) et [marché](https://decp.info/marches/532239472000482025S00004) ([#40](https://github.com/ColinMaudry/decp.info/issues/40)) 🔎
|
- Ajout des vues [acheteur](https://decp.info/acheteurs/24350013900189) ([#28](https://github.com/ColinMaudry/colibre/issues/28)), [titulaire](https://decp.info/titulaires/51903758414786) ([#35](https://github.com/ColinMaudry/colibre/issues/35)) et [marché](https://decp.info/marches/532239472000482025S00004) ([#40](https://github.com/ColinMaudry/colibre/issues/40)) 🔎
|
||||||
- Ajout des balises HTML meta Open Graph et Twitter ([#39](https://github.com/ColinMaudry/decp.info/issues/39)) pour de beaux aperçus de liens 🖼️
|
- Ajout des balises HTML meta Open Graph et Twitter ([#39](https://github.com/ColinMaudry/colibre/issues/39)) pour de beaux aperçus de liens 🖼️
|
||||||
- Formulaire de contact ([#48](https://github.com/ColinMaudry/decp.info/issues/48)) 📨
|
- Formulaire de contact ([#48](https://github.com/ColinMaudry/colibre/issues/48)) 📨
|
||||||
- Nom de colonnes plus_agréables ([#33](https://github.com/ColinMaudry/decp.info/issues/33)) 💅
|
- Nom de colonnes plus_agréables ([#33](https://github.com/ColinMaudry/colibre/issues/33)) 💅
|
||||||
- Définition des colonnes quand vous passez votre souris sur les en-têtes ([#33](https://github.com/ColinMaudry/decp.info/issues/33)) 📖
|
- Définition des colonnes quand vous passez votre souris sur les en-têtes ([#33](https://github.com/ColinMaudry/colibre/issues/33)) 📖
|
||||||
- Affichage du numéro de version près du logo et lien vers ici 🤓
|
- Affichage du numéro de version près du logo et lien vers ici 🤓
|
||||||
- Variables globales uniquement en lecture (😁)
|
- Variables globales uniquement en lecture (😁)
|
||||||
|
|
||||||
##### 2.0.1 (23 septembre 2025)
|
##### 2.0.1 (23 septembre 2025)
|
||||||
|
|
||||||
- Bloquage du bouton de téléchargement si trop de lignes (+ 65000) [#38](https://github.com/ColinMaudry/decp.info/issues/38)
|
- Bloquage du bouton de téléchargement si trop de lignes (+ 65000) [#38](https://github.com/ColinMaudry/colibre/issues/38)
|
||||||
- Amélioration du script de déploiement (deploy.sh)
|
- Amélioration du script de déploiement (deploy.sh)
|
||||||
- Meilleures instructions d'installation et lancement
|
- Meilleures instructions d'installation et lancement
|
||||||
- Coquilles 🐚
|
- Coquilles 🐚
|
||||||
@@ -224,7 +224,7 @@
|
|||||||
|
|
||||||
- ajout d'une page "Notes de version"
|
- ajout d'une page "Notes de version"
|
||||||
- meilleur lien pour la documentation des champs
|
- meilleur lien pour la documentation des champs
|
||||||
- déplacement du code de decp.info depuis [ColinMaudry/decp-table-schema-utils](https://github.com/ColinMaudry/decp-table-schema-utils) vers [ColinMaudry/decp.info](https://github.com/ColinMaudry/decp.info)
|
- déplacement du code de decp.info depuis [ColinMaudry/decp-table-schema-utils](https://github.com/ColinMaudry/decp-table-schema-utils) vers [ColinMaudry/decp.info](https://github.com/ColinMaudry/colibre)
|
||||||
|
|
||||||
### 1.1.0 (25/05/2021)
|
### 1.1.0 (25/05/2021)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
**decp.info** is a French public procurement data explorer — a Dash (Python) web app for browsing, filtering, and visualizing _Données Essentielles de la Commande Publique_ (DECP). The UI is in French.
|
**colibre** is a French public procurement data explorer — a Dash (Python) web app for browsing, filtering, and visualizing _Données Essentielles de la Commande Publique_ (DECP). The UI is in French.
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
@@ -112,28 +112,28 @@ _MIGRATIONS = [
|
|||||||
|
|
||||||
### Deployment
|
### Deployment
|
||||||
|
|
||||||
- `main` branch → manual deploy to decp.info via GitHub Actions
|
- `main` branch → manual deploy to colibre.fr via GitHub Actions
|
||||||
- `dev` branch → auto-deploy to test.decp.info via GitHub Actions
|
- `dev` branch → auto-deploy to test.colibre.fr via GitHub Actions
|
||||||
|
|
||||||
#### Sauvegarde de la base utilisateurs
|
#### Sauvegarde de la base utilisateurs
|
||||||
|
|
||||||
`users.sqlite` est sauvegardée toutes les heures sur S3 par un timer systemd
|
`users.sqlite` est sauvegardée toutes les heures sur S3 par un timer systemd
|
||||||
(voir `deploy/decpinfo-backup.{service,timer}`). Installation initiale (une fois,
|
(voir `deploy/colibre-backup.{service,timer}`). Installation initiale (une fois,
|
||||||
sur le serveur, en root) :
|
sur le serveur, en root) :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp deploy/decpinfo-backup.service deploy/decpinfo-backup.timer /etc/systemd/system/
|
cp deploy/colibre-backup.service deploy/colibre-backup.timer /etc/systemd/system/
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl enable --now decpinfo-backup.timer
|
systemctl enable --now colibre-backup.timer
|
||||||
systemctl list-timers decpinfo-backup.timer # vérifier le prochain déclenchement
|
systemctl list-timers colibre-backup.timer # vérifier le prochain déclenchement
|
||||||
```
|
```
|
||||||
|
|
||||||
Restauration manuelle :
|
Restauration manuelle :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /var/www/decpinfo && source .venv/bin/activate
|
cd /var/www/colibre && source .venv/bin/activate
|
||||||
python -m src.backup list
|
python -m src.backup list
|
||||||
systemctl stop decpinfo
|
systemctl stop colibre
|
||||||
python -m src.backup restore backups/users-YYYYMMDDTHHMMSSZ.sqlite.gz.enc
|
python -m src.backup restore backups/users-YYYYMMDDTHHMMSSZ.sqlite.gz.enc
|
||||||
systemctl start decpinfo
|
systemctl start colibre
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
# decp.info
|
# colibre
|
||||||
|
|
||||||
|
> **Note:** Ce projet a été rebaptisé de **decp.info** à **colibre** en 2026.
|
||||||
|
|
||||||
> Outil d'exploration et de téléchargement des données essentielles de la commande publique.
|
> Outil d'exploration et de téléchargement des données essentielles de la commande publique.
|
||||||
|
|
||||||
=> [decp.info](https://decp.info)
|
=> [colibre.fr](https://colibre.fr)
|
||||||
|
|
||||||
## Installation et lancement
|
## Installation et lancement
|
||||||
|
|
||||||
@@ -20,8 +22,8 @@ uv run run.py
|
|||||||
|
|
||||||
## Déploiement
|
## Déploiement
|
||||||
|
|
||||||
- **Production** (branche `main`, [decp.info](https://decp.info)) : déploiement manuel via un déclenchement de la Github Action [Déploiement](https://github.com/ColinMaudry/decp.info/actions/workflows/deploy.yaml)
|
- **Production** (branche `main`, [colibre.fr](https://colibre.fr)) : déploiement manuel via un déclenchement de la Github Action [Déploiement](https://github.com/ColinMaudry/colibre/actions/workflows/deploy.yaml)
|
||||||
- **Test** (branche `dev`, [test.decp.info](https://test.decp.info)) : déploiement automatique à chaque push sur la branche `dev`, via la même Github Action.
|
- **Test** (branche `dev`, [test.colibre.fr](https://test.colibre.fr)) : déploiement automatique à chaque push sur la branche `dev`, via la même Github Action.
|
||||||
|
|
||||||
Ne pas oublier de mettre à jour les fichier .env.
|
Ne pas oublier de mettre à jour les fichier .env.
|
||||||
|
|
||||||
@@ -36,9 +38,9 @@ python -m src.backup list
|
|||||||
Pour restaurer une sauvegarde, arrêtez le service, restaurez la base, puis redémarrez :
|
Pour restaurer une sauvegarde, arrêtez le service, restaurez la base, puis redémarrez :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
systemctl stop decpinfo
|
systemctl stop colibre
|
||||||
python -m src.backup restore backups/users-YYYYMMDDTHHMMSSZ.sqlite.gz.enc
|
python -m src.backup restore backups/users-YYYYMMDDTHHMMSSZ.sqlite.gz.enc
|
||||||
systemctl start decpinfo
|
systemctl start colibre
|
||||||
```
|
```
|
||||||
|
|
||||||
## Migrations de base de données
|
## Migrations de base de données
|
||||||
@@ -60,4 +62,4 @@ Pour ajouter une migration, voir les instructions dans `src/migrations.py`.
|
|||||||
|
|
||||||
## Notes de version
|
## Notes de version
|
||||||
|
|
||||||
Voir [CHANGELOG](https://github.com/ColinMaudry/decp.info/blob/main/CHANGELOG.md).
|
Voir [CHANGELOG](https://github.com/ColinMaudry/colibre/blob/main/CHANGELOG.md).
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Sauvegarde horaire de users.sqlite (colibre) vers S3
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
User=colibre
|
||||||
|
WorkingDirectory=/var/www/colibre
|
||||||
|
EnvironmentFile=/var/www/colibre/.env
|
||||||
|
ExecStart=/var/www/colibre/.venv/bin/python -m src.backup backup
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Déclenche la sauvegarde horaire de users.sqlite (decp.info)
|
Description=Déclenche la sauvegarde horaire de users.sqlite (colibre)
|
||||||
|
|
||||||
[Timer]
|
[Timer]
|
||||||
OnCalendar=hourly
|
OnCalendar=hourly
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Sauvegarde horaire de users.sqlite (decp.info) vers S3
|
|
||||||
After=network-online.target
|
|
||||||
Wants=network-online.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=oneshot
|
|
||||||
User=decpinfo
|
|
||||||
WorkingDirectory=/var/www/decpinfo
|
|
||||||
EnvironmentFile=/var/www/decpinfo/.env
|
|
||||||
ExecStart=/var/www/decpinfo/.venv/bin/python -m src.backup backup
|
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "decp.info"
|
name = "colibre"
|
||||||
description = "Interface d'exploration et d'analyse des marchés publics français."
|
description = "Interface d'exploration et d'analyse des marchés publics français."
|
||||||
version = "2.8.1"
|
version = "2.8.1"
|
||||||
requires-python = ">= 3.10"
|
requires-python = ">= 3.10"
|
||||||
@@ -57,7 +57,7 @@ env = [
|
|||||||
"DATA_SCHEMA_PATH=/home/colin/git/decp-processing/dist/schema.json",
|
"DATA_SCHEMA_PATH=/home/colin/git/decp-processing/dist/schema.json",
|
||||||
"USERS_DB_PATH=tests/users.test.sqlite",
|
"USERS_DB_PATH=tests/users.test.sqlite",
|
||||||
"SECRET_KEY=test-secret-do-not-use-in-prod",
|
"SECRET_KEY=test-secret-do-not-use-in-prod",
|
||||||
"MAIL_FROM=test@decp.info",
|
"MAIL_FROM=test@colibre.fr",
|
||||||
"MAIL_SUPPRESS_SEND=true",
|
"MAIL_SUPPRESS_SEND=true",
|
||||||
"APP_BASE_URL=http://localhost:8050",
|
"APP_BASE_URL=http://localhost:8050",
|
||||||
"SMTP_HOST=localhost",
|
"SMTP_HOST=localhost",
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ from src.api import routes
|
|||||||
|
|
||||||
def init_api(server) -> None:
|
def init_api(server) -> None:
|
||||||
"""Enregistre le blueprint d'API privée sur le serveur Flask."""
|
"""Enregistre le blueprint d'API privée sur le serveur Flask."""
|
||||||
server.config.setdefault("API_TITLE", "decp.info API")
|
server.config.setdefault("API_TITLE", "colibre API")
|
||||||
server.config.setdefault("API_VERSION", "v1")
|
server.config.setdefault("API_VERSION", "v1")
|
||||||
server.config.setdefault("OPENAPI_VERSION", "3.0.3")
|
server.config.setdefault("OPENAPI_VERSION", "3.0.3")
|
||||||
server.config.setdefault("OPENAPI_URL_PREFIX", "/api/v1")
|
server.config.setdefault("OPENAPI_URL_PREFIX", "/api/v1")
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ bp = Blueprint(
|
|||||||
"api_v1",
|
"api_v1",
|
||||||
"api_v1",
|
"api_v1",
|
||||||
url_prefix="/api/v1",
|
url_prefix="/api/v1",
|
||||||
description="API privée decp.info — accès tabulaire aux marchés publics.",
|
description="API privée colibre — accès tabulaire aux marchés publics.",
|
||||||
)
|
)
|
||||||
|
|
||||||
MAX_PAGE_SIZE = 1000
|
MAX_PAGE_SIZE = 1000
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from contextlib import contextmanager
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
TOKEN_PREFIX = "decpinfo_"
|
TOKEN_PREFIX = "colibre_"
|
||||||
|
|
||||||
SCHEMA = """
|
SCHEMA = """
|
||||||
CREATE TABLE IF NOT EXISTS api_tokens (
|
CREATE TABLE IF NOT EXISTS api_tokens (
|
||||||
|
|||||||
+1
-1
@@ -59,7 +59,7 @@ def enqueue_matomo_event(
|
|||||||
site_id = os.getenv("MATOMO_SITE_ID")
|
site_id = os.getenv("MATOMO_SITE_ID")
|
||||||
if not url or not site_id:
|
if not url or not site_id:
|
||||||
return
|
return
|
||||||
full_url = f"https://decp.info{path}"
|
full_url = f"https://colibre.fr{path}"
|
||||||
if query_string:
|
if query_string:
|
||||||
full_url += f"?{query_string}"
|
full_url += f"?{query_string}"
|
||||||
params = {
|
params = {
|
||||||
|
|||||||
+5
-5
@@ -45,7 +45,7 @@ META_TAGS = [
|
|||||||
{"name": "viewport", "content": "width=device-width, initial-scale=1"},
|
{"name": "viewport", "content": "width=device-width, initial-scale=1"},
|
||||||
{
|
{
|
||||||
"name": "keywords",
|
"name": "keywords",
|
||||||
"content": "commande publique, decp, marchés publics, données essentielles",
|
"content": "commande publique, decp, marchés publics, données essentielles, colibre",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ if DEVELOPMENT:
|
|||||||
# fonctions memoizées (@cache.memoize) dès l'import (ex. tableau.py).
|
# fonctions memoizées (@cache.memoize) dès l'import (ex. tableau.py).
|
||||||
server = Flask(__name__)
|
server = Flask(__name__)
|
||||||
|
|
||||||
cache_dir = os.getenv("CACHE_DIR", "/tmp/decp-cache")
|
cache_dir = os.getenv("CACHE_DIR", "/tmp/colibre-cache")
|
||||||
|
|
||||||
if os.path.exists(cache_dir):
|
if os.path.exists(cache_dir):
|
||||||
rmtree(cache_dir)
|
rmtree(cache_dir)
|
||||||
@@ -83,7 +83,7 @@ app: Dash = Dash(
|
|||||||
# `src.pages.connexion` : deux identités, même URL → "duplicate paths" →
|
# `src.pages.connexion` : deux identités, même URL → "duplicate paths" →
|
||||||
# check_for_duplicate_pathnames lève à chaque requête → 500 sur toute l'app.
|
# check_for_duplicate_pathnames lève à chaque requête → 500 sur toute l'app.
|
||||||
name="src",
|
name="src",
|
||||||
title="decp.info",
|
title="Colibre",
|
||||||
use_pages=True,
|
use_pages=True,
|
||||||
suppress_callback_exceptions=True,
|
suppress_callback_exceptions=True,
|
||||||
compress=True,
|
compress=True,
|
||||||
@@ -132,7 +132,7 @@ Allow: /
|
|||||||
|
|
||||||
@app.server.route("/sitemap.xml")
|
@app.server.route("/sitemap.xml")
|
||||||
def sitemap():
|
def sitemap():
|
||||||
base_url = "https://decp.info"
|
base_url = "https://colibre.fr"
|
||||||
pages = [
|
pages = [
|
||||||
"/",
|
"/",
|
||||||
"/observatoire",
|
"/observatoire",
|
||||||
@@ -203,7 +203,7 @@ navbar = dbc.Navbar(
|
|||||||
children=[
|
children=[
|
||||||
html.Div(
|
html.Div(
|
||||||
[
|
[
|
||||||
dcc.Link(html.H1("decp.info"), href="/", className="logo"),
|
dcc.Link(html.H1("colibre"), href="/", className="logo"),
|
||||||
html.P(
|
html.P(
|
||||||
[
|
[
|
||||||
html.A(
|
html.A(
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 333 KiB |
@@ -0,0 +1,26 @@
|
|||||||
|
# decp.info
|
||||||
|
|
||||||
|
decp.info est une plateforme permettant d'explorer, filtrer et visualiser les données des marchés publics français. Elle est alimentée par des données publiées en Open Data et propose également une API REST JSON accessible sur abonnement (contacter <colin@colmo.tech>).
|
||||||
|
|
||||||
|
## Schéma des données
|
||||||
|
|
||||||
|
Le schéma des données est au format TableSchema et peut être librement téléchargé à cette adresse : <https://www.data.gouv.fr/api/1/datasets/r/9a4144c0-ee44-4dec-bee5-bbef38191d9a>
|
||||||
|
|
||||||
|
## Données source
|
||||||
|
|
||||||
|
Les données sont publiées en Open Data aux formats Parquet et CSV :
|
||||||
|
|
||||||
|
- Parquet : <https://www.data.gouv.fr/api/1/datasets/r/11cea8e8-df3e-4ed1-932b-781e2635e432>
|
||||||
|
- CSV : <https://www.data.gouv.fr/api/1/datasets/r/22847056-61df-452d-837d-8b8ceadbfc52>
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
L'API nécessite un jeton d'authentification pour se connecter. Elle utilise le même schéma que les données et renvoie les données au format JSON.
|
||||||
|
|
||||||
|
- Point d'accès : <https://decp.info/api/v1/data>
|
||||||
|
- Spec Open API : <https://decp.info/api/v1/openapi.json>
|
||||||
|
- Health : <https://decp.info/api/v1/health>
|
||||||
|
|
||||||
|
## Sources de données
|
||||||
|
|
||||||
|
Les données proviennent de nombreuses sources de données, le projet publie des statistiques au format CSV : <https://www.data.gouv.fr/api/1/datasets/r/8ded94de-3b80-4840-a5bb-7faad1c9c234>
|
||||||
+2
-2
@@ -25,8 +25,8 @@ def _base_url() -> str:
|
|||||||
|
|
||||||
def _sender() -> SendTransacEmailRequestSender:
|
def _sender() -> SendTransacEmailRequestSender:
|
||||||
return SendTransacEmailRequestSender(
|
return SendTransacEmailRequestSender(
|
||||||
email=os.getenv("MAIL_FROM", "noreply@decp.info"),
|
email=os.getenv("MAIL_FROM", "noreply@colibre"),
|
||||||
name=os.getenv("MAIL_FROM_NAME", "decp.info"),
|
name=os.getenv("MAIL_FROM_NAME", "colibre"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ from src.utils.seo import META_CONTENT
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/a-propos",
|
path="/a-propos",
|
||||||
title="À propos | decp.info",
|
title="À propos | colibre",
|
||||||
name="À propos",
|
name="À propos",
|
||||||
description="En savoir plus sur decp.info, l'outil d'exploration des données essentielles de la commande publique.",
|
description="En savoir plus sur colibre, l'outil d'exploration des données essentielles de la commande publique.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
order=5,
|
order=5,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ from src.utils.seo import META_CONTENT
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/a-propos/abonnement",
|
path="/a-propos/abonnement",
|
||||||
title="Abonnement | À propos | decp.info",
|
title="Abonnement | À propos | colibre",
|
||||||
description="Conditions d'abonnement à decp.info : tarifs, facturation, résiliation et données personnelles.",
|
description="Conditions d'abonnement à colibre : tarifs, facturation, résiliation et données personnelles.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ def layout(**_):
|
|||||||
html.H2("Abonnement"),
|
html.H2("Abonnement"),
|
||||||
dcc.Markdown(
|
dcc.Markdown(
|
||||||
"""
|
"""
|
||||||
L'accès aux fonctionnalités de base de decp.info est gratuit et sans inscription.
|
L'accès aux fonctionnalités de base de colibre est gratuit et sans inscription.
|
||||||
Un abonnement payant donne accès à des fonctionnalités supplémentaires qui nécessitent la création d'un compte.
|
Un abonnement payant donne accès à des fonctionnalités supplémentaires qui nécessitent la création d'un compte.
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
@@ -55,7 +55,7 @@ La période d'essai est accordée une seule fois par utilisateur.
|
|||||||
"""
|
"""
|
||||||
L'abonnement est facturé mensuellement, à la date anniversaire de la souscription.
|
L'abonnement est facturé mensuellement, à la date anniversaire de la souscription.
|
||||||
Le paiement est traité par [Frisbii](https://www.frisbii.com), prestataire européen de paiement en ligne.
|
Le paiement est traité par [Frisbii](https://www.frisbii.com), prestataire européen de paiement en ligne.
|
||||||
Les coordonnées bancaires sont conservées exclusivement par Frisbii et ne sont pas transmises à decp.info.
|
Les coordonnées bancaires sont conservées exclusivement par Frisbii et ne sont pas transmises à colibre.
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
html.H4("Résiliation"),
|
html.H4("Résiliation"),
|
||||||
@@ -68,9 +68,9 @@ La résiliation prend effet à la fin de la période mensuelle en cours : l'acc
|
|||||||
html.H4("Données personnelles"),
|
html.H4("Données personnelles"),
|
||||||
dcc.Markdown(
|
dcc.Markdown(
|
||||||
"""
|
"""
|
||||||
La gestion de l'abonnement implique le traitement de données personnelles, réparties entre decp.info et Frisbii (prestataire de paiement).
|
La gestion de l'abonnement implique le traitement de données personnelles, réparties entre colibre et Frisbii (prestataire de paiement).
|
||||||
|
|
||||||
**Données stockées par decp.info :**
|
**Données stockées par colibre :**
|
||||||
|
|
||||||
- Adresse e-mail (identification du compte)
|
- Adresse e-mail (identification du compte)
|
||||||
- Numéro SIRET (si renseigné, conservé pour pré-remplir les futures souscriptions)
|
- Numéro SIRET (si renseigné, conservé pour pré-remplir les futures souscriptions)
|
||||||
@@ -78,7 +78,7 @@ La gestion de l'abonnement implique le traitement de données personnelles, rép
|
|||||||
**Données stockées par Frisbii :**
|
**Données stockées par Frisbii :**
|
||||||
|
|
||||||
- Informations de facturation : prénom, nom, adresse postale, code postal, ville, pays, nom de l'entreprise
|
- Informations de facturation : prénom, nom, adresse postale, code postal, ville, pays, nom de l'entreprise
|
||||||
- Informations de paiement : coordonnées bancaires (accessibles uniquement par Frisbii, jamais transmises à decp.info)
|
- Informations de paiement : coordonnées bancaires (accessibles uniquement par Frisbii, jamais transmises à colibre)
|
||||||
- Historique des factures
|
- Historique des factures
|
||||||
|
|
||||||
Ces données sont utilisées uniquement pour la gestion de votre abonnement et ne sont pas transmises à des tiers à des fins commerciales.
|
Ces données sont utilisées uniquement pour la gestion de votre abonnement et ne sont pas transmises à des tiers à des fins commerciales.
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ from src.utils.seo import META_CONTENT
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/a-propos/contact",
|
path="/a-propos/contact",
|
||||||
title="Contact | À propos | decp.info",
|
title="Contact | À propos | colibre",
|
||||||
description="Contactez Colin Maudry, développeur de decp.info.",
|
description="Contactez Colin Maudry, développeur de colibre.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ from src.utils.seo import META_CONTENT
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/a-propos/contribuer",
|
path="/a-propos/contribuer",
|
||||||
title="Contribuer | À propos | decp.info",
|
title="Contribuer | À propos | colibre",
|
||||||
description="Comment contribuer au projet decp.info.",
|
description="Comment contribuer au projet colibre.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ def layout(**_):
|
|||||||
html.H2("Pour contribuer"),
|
html.H2("Pour contribuer"),
|
||||||
dcc.Markdown(
|
dcc.Markdown(
|
||||||
"""
|
"""
|
||||||
- via l'achat d'une prestation de service (devis, prestation, facture), vous pouvez financer le développement de [fonctionnalités prévues](https://github.com/ColinMaudry/decp.info/issues), ou d'autres !
|
- via l'achat d'une prestation de service (devis, prestation, facture), vous pouvez financer le développement de [fonctionnalités prévues](https://github.com/ColinMaudry/colibre/issues), ou d'autres !
|
||||||
- ma société accepte aussi les dons (pas de réduction d'impôt possible)
|
- ma société accepte aussi les dons (pas de réduction d'impôt possible)
|
||||||
- écrivez-moi et on discute !
|
- écrivez-moi et on discute !
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ from src.utils.seo import META_CONTENT
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/a-propos/donnees-brutes",
|
path="/a-propos/donnees-brutes",
|
||||||
title="Données brutes | À propos | decp.info",
|
title="Données brutes | À propos | colibre",
|
||||||
description="Téléchargez ou interrogez les données brutes qui alimentent decp.info.",
|
description="Téléchargez ou interrogez les données brutes qui alimentent colibre.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ def layout(**_):
|
|||||||
html.H2("Consommer les données brutes"),
|
html.H2("Consommer les données brutes"),
|
||||||
dcc.Markdown(
|
dcc.Markdown(
|
||||||
"""
|
"""
|
||||||
Vous pouvez consommer les données qui alimentent decp.info en les téléchargeant [sur data.gouv.fr](https://www.data.gouv.fr/datasets/donnees-essentielles-de-la-commande-publique-consolidees-format-tabulaire) (Parquet, CSV), pensez à lire la description du jeu de données
|
Vous pouvez consommer les données qui alimentent colibre en les téléchargeant [sur data.gouv.fr](https://www.data.gouv.fr/datasets/donnees-essentielles-de-la-commande-publique-consolidees-format-tabulaire) (Parquet, CSV), pensez à lire la description du jeu de données
|
||||||
|
|
||||||
Une API REST tabulaire (JSON) est également disponible par abonnement mensuel pour accéder aux mêmes données et alimenter une application.
|
Une API REST tabulaire (JSON) est également disponible par abonnement mensuel pour accéder aux mêmes données et alimenter une application.
|
||||||
Documentation interactive : [Swagger UI](/api/v1/swagger). Si cela vous intéresse, [contactez-moi](/a-propos/contact)."""
|
Documentation interactive : [Swagger UI](/api/v1/swagger). Si cela vous intéresse, [contactez-moi](/a-propos/contact)."""
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ from src.utils.seo import META_CONTENT
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/a-propos/explorer",
|
path="/a-propos/explorer",
|
||||||
title="Explorer le projet | À propos | decp.info",
|
title="Explorer le projet | À propos | colibre",
|
||||||
description="Ressources pour explorer le projet decp.info : données, code source, blog.",
|
description="Ressources pour explorer le projet colibre : données, code source, blog.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ def layout(**_):
|
|||||||
- 🗞️ [mon blog](https://colin.maudry.com)
|
- 🗞️ [mon blog](https://colin.maudry.com)
|
||||||
- 📔 [wiki du projet](https://github.com/ColinMaudry/decp-processing/wiki)
|
- 📔 [wiki du projet](https://github.com/ColinMaudry/decp-processing/wiki)
|
||||||
- 🚰 code source
|
- 🚰 code source
|
||||||
- [de decp.info](https://github.com/ColinMaudry/decp.info)
|
- [de colibre](https://github.com/ColinMaudry/colibre)
|
||||||
- [du traitement des données](https://github.com/ColinMaudry/decp-processing)
|
- [du traitement des données](https://github.com/ColinMaudry/decp-processing)
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ from src.utils.seo import META_CONTENT
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/a-propos/mentions-legales",
|
path="/a-propos/mentions-legales",
|
||||||
title="Mentions légales | À propos | decp.info",
|
title="Mentions légales | À propos | colibre",
|
||||||
description="Mentions légales de decp.info : éditeur, hébergement, suivi d'audience, attributions.",
|
description="Mentions légales de colibre : éditeur, hébergement, suivi d'audience, attributions.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ Hébergement : serveur situé en France et administré par Scaleway, 8 rue de la
|
|||||||
html.H4("Suivi d'audience", id="audience"),
|
html.H4("Suivi d'audience", id="audience"),
|
||||||
dcc.Markdown(
|
dcc.Markdown(
|
||||||
"""
|
"""
|
||||||
Ce site dépose un petit fichier texte (un « cookie ») sur votre ordinateur lorsque vous le consultez ([Wikipédia](https://fr.wikipedia.org/wiki/Cookie_(informatique))). Cela me permet de mesurer le nombre de visites, de distinguer les nouveaux visiteurs des utilisateurs réguliers et ainsi de communiquer sur l'impact de decp.info.
|
Ce site dépose un petit fichier texte (un « cookie ») sur votre ordinateur lorsque vous le consultez ([Wikipédia](https://fr.wikipedia.org/wiki/Cookie_(informatique))). Cela me permet de mesurer le nombre de visites, de distinguer les nouveaux visiteurs des utilisateurs réguliers et ainsi de communiquer sur l'impact de colibre.
|
||||||
|
|
||||||
**Ce site n'affiche pas de bannière de consentement aux cookies, pourquoi ?**
|
**Ce site n'affiche pas de bannière de consentement aux cookies, pourquoi ?**
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ from src.utils.seo import META_CONTENT
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/a-propos/presentation",
|
path="/a-propos/presentation",
|
||||||
title="Présentation | À propos | decp.info",
|
title="Présentation | À propos | colibre",
|
||||||
description="En savoir plus sur decp.info, l'outil d'exploration des données essentielles de la commande publique.",
|
description="En savoir plus sur colibre, l'outil d'exploration des données essentielles de la commande publique.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ Ce projet vise à démocratiser l'accès aux données des marchés publics et à
|
|||||||
j'aimerais beaucoup échanger avec vous pour comprendre vos cas d'usages et vos besoins. Cet outil ne peut rester performant que si je comprends les problèmes qu'il peut aider à résoudre. Ce projet ne peut rester gratuit que grâce au financement du développement de nouvelles fonctionnalités.
|
j'aimerais beaucoup échanger avec vous pour comprendre vos cas d'usages et vos besoins. Cet outil ne peut rester performant que si je comprends les problèmes qu'il peut aider à résoudre. Ce projet ne peut rester gratuit que grâce au financement du développement de nouvelles fonctionnalités.
|
||||||
|
|
||||||
En effet, le potentiel des données d'attribution de marchés et des données qui peuvent les enrichir est très loin d'être exploité par
|
En effet, le potentiel des données d'attribution de marchés et des données qui peuvent les enrichir est très loin d'être exploité par
|
||||||
les fonctionnalités actuelles de decp.info. Il est ainsi possible de rajouter
|
les fonctionnalités actuelles de colibre. Il est ainsi possible de rajouter
|
||||||
|
|
||||||
- de nombreuses visualisations de données (cartes, graphiques, tableaux) sur des thématiques variées (vivacité de la concurrence, secteurs d'activité, insertion par l'activité économique (IAE), distance acheteur-titulaire...)
|
- de nombreuses visualisations de données (cartes, graphiques, tableaux) sur des thématiques variées (vivacité de la concurrence, secteurs d'activité, insertion par l'activité économique (IAE), distance acheteur-titulaire...)
|
||||||
- des alertes par email si des marchés correspondant à certains critères
|
- des alertes par email si des marchés correspondant à certains critères
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ from src.utils.seo import META_CONTENT
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/a-propos/qualite",
|
path="/a-propos/qualite",
|
||||||
title="Qualité des données | À propos | decp.info",
|
title="Qualité des données | À propos | colibre",
|
||||||
description="Informations sur la qualité et l'exhaustivité des données de marchés publics sur decp.info.",
|
description="Informations sur la qualité et l'exhaustivité des données de marchés publics sur colibre.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ def layout(**_):
|
|||||||
peu aidé·es par la qualité des outils à leur disposition.
|
peu aidé·es par la qualité des outils à leur disposition.
|
||||||
|
|
||||||
Je pense que l'analyse de marchés
|
Je pense que l'analyse de marchés
|
||||||
individuels et le comptage de marchés sur des critères autres que financiers sont plutôt fiables. En revanche, certains montants de marché estimés à des valeurs farfelues ([1 euro](https://decp.info/marches/432766947000192025S01301), [1 milliard](https://decp.info/marches/2459004280001320210000000271)) faussent les calculs par aggrégation (sommes, moyennes, médianes) et donc la production de statistiques financières fiables. Acheteurs, acheteuses : s'il vous plaît, essayez d'estimer les montants des marchés publics attribués de manière plus précise.
|
individuels et le comptage de marchés sur des critères autres que financiers sont plutôt fiables. En revanche, certains montants de marché estimés à des valeurs farfelues ([1 euro](https://colibre.fr/marches/432766947000192025S01301), [1 milliard](https://colibre.fr/marches/2459004280001320210000000271)) faussent les calculs par aggrégation (sommes, moyennes, médianes) et donc la production de statistiques financières fiables. Acheteurs, acheteuses : s'il vous plaît, essayez d'estimer les montants des marchés publics attribués de manière plus précise.
|
||||||
|
|
||||||
Quant à l'exhaustivité, je consolide toutes les sources de données exploitables que j'ai pu identifier (voir [Sources de données](/a-propos/sources)). Je tiens à souligner la belle continuité de la publication par la DGFiP des données des marchés publics remontées via le [protocole PES](https://www.collectivites-locales.gouv.fr/finances-locales/le-protocole-dechange-standard-pes). Merci à leurs équipes."""
|
Quant à l'exhaustivité, je consolide toutes les sources de données exploitables que j'ai pu identifier (voir [Sources de données](/a-propos/sources)). Je tiens à souligner la belle continuité de la publication par la DGFiP des données des marchés publics remontées via le [protocole PES](https://www.collectivites-locales.gouv.fr/finances-locales/le-protocole-dechange-standard-pes). Merci à leurs équipes."""
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ from src.utils.seo import META_CONTENT
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/a-propos/roadmap",
|
path="/a-propos/roadmap",
|
||||||
title="Roadmap | À propos | decp.info",
|
title="Roadmap | À propos | colibre",
|
||||||
description="Les prochaines fonctionnalités de decp.info, soumises au vote des abonnés.",
|
description="Les prochaines fonctionnalités de colibre, soumises au vote des abonnés.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ from src.utils.seo import META_CONTENT
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/a-propos/sources",
|
path="/a-propos/sources",
|
||||||
title="Sources de données | À propos | decp.info",
|
title="Sources de données | À propos | colibre",
|
||||||
description="Sources de données utilisées par decp.info pour consolider les marchés publics français.",
|
description="Sources de données utilisées par colibre pour consolider les marchés publics français.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ def get_title(acheteur_id: str | None = None) -> str:
|
|||||||
"acheteur_nom"
|
"acheteur_nom"
|
||||||
)
|
)
|
||||||
if acheteur_nom.height > 0:
|
if acheteur_nom.height > 0:
|
||||||
return f"Marchés publics attribués par {acheteur_nom.item(0, 0)} | decp.info"
|
return f"Marchés publics attribués par {acheteur_nom.item(0, 0)} | colibre"
|
||||||
return "Marchés publics attribués | decp.info"
|
return "Marchés publics attribués | colibre"
|
||||||
|
|
||||||
|
|
||||||
register_page(
|
register_page(
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ NAME = "Département"
|
|||||||
|
|
||||||
|
|
||||||
def get_title(code):
|
def get_title(code):
|
||||||
return f"Marchés publics de {DEPARTEMENTS[code]['departement']} | decp.info"
|
return f"Marchés publics de {DEPARTEMENTS[code]['departement']} | colibre"
|
||||||
|
|
||||||
|
|
||||||
def get_description(code):
|
def get_description(code):
|
||||||
return f"Marchés publics passés dans le département {DEPARTEMENTS[code]['departement']} | decp.info"
|
return f"Marchés publics passés dans le département {DEPARTEMENTS[code]['departement']} | colibre"
|
||||||
|
|
||||||
|
|
||||||
register_page(
|
register_page(
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ NAME = "Départements"
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/departements",
|
path="/departements",
|
||||||
title="Marchés par département | decp.info",
|
title="Marchés par département | colibre",
|
||||||
name="Départements",
|
name="Départements",
|
||||||
description="Tous les marchés publics, classés par départements",
|
description="Tous les marchés publics, classés par départements",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -30,16 +30,16 @@ def make_org_nom_verbe(org_type, org_id) -> tuple:
|
|||||||
def get_title(code, org_type, org_id):
|
def get_title(code, org_type, org_id):
|
||||||
if org_type:
|
if org_type:
|
||||||
org_nom, verbe = make_org_nom_verbe(org_type, org_id)
|
org_nom, verbe = make_org_nom_verbe(org_type, org_id)
|
||||||
return f"Marchés publics {verbe} par {org_nom} | decp.info"
|
return f"Marchés publics {verbe} par {org_nom} | colibre"
|
||||||
else:
|
else:
|
||||||
logger.warning(f"Pas de org_type pour org_id: {org_id}")
|
logger.warning(f"Pas de org_type pour org_id: {org_id}")
|
||||||
return "Marchés publics | decp.info"
|
return "Marchés publics | colibre"
|
||||||
|
|
||||||
|
|
||||||
def get_description(code, org_type, org_id):
|
def get_description(code, org_type, org_id):
|
||||||
org_nom, verbe = make_org_nom_verbe(org_type, org_id)
|
org_nom, verbe = make_org_nom_verbe(org_type, org_id)
|
||||||
|
|
||||||
return f"Liste complète des marchés publics {verbe} par {org_nom} et publiés par decp.info. Cliquez sur les liens pour consulter les détails de chaque marché."
|
return f"Liste complète des marchés publics {verbe} par {org_nom} et publiés par colibre. Cliquez sur les liens pour consulter les détails de chaque marché."
|
||||||
|
|
||||||
|
|
||||||
register_page(
|
register_page(
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ from dash import dcc, register_page
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/compte",
|
path="/compte",
|
||||||
title="Mon compte | decp.info",
|
title="Mon compte | colibre",
|
||||||
name="Mon compte",
|
name="Mon compte",
|
||||||
description="Redirection vers la gestion de compte.",
|
description="Redirection vers la gestion de compte.",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ from src.subscriptions import db, plans
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/compte/abonnement",
|
path="/compte/abonnement",
|
||||||
title="Abonnement | decp.info",
|
title="Abonnement | colibre",
|
||||||
name="Abonnement",
|
name="Abonnement",
|
||||||
description="Gestion de votre abonnement decp.info.",
|
description="Gestion de votre abonnement colibre.",
|
||||||
)
|
)
|
||||||
|
|
||||||
_PLAN_KEYS = ("simple", "soutien")
|
_PLAN_KEYS = ("simple", "soutien")
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ from src.utils.data import get_annuaire_data
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/compte/abonnement/mes-infos",
|
path="/compte/abonnement/mes-infos",
|
||||||
title="Mes informations | Abonnement | decp.info",
|
title="Mes informations | Abonnement | colibre",
|
||||||
name="Mes informations de facturation",
|
name="Mes informations de facturation",
|
||||||
description="Informations de facturation pour votre abonnement decp.info.",
|
description="Informations de facturation pour votre abonnement colibre.",
|
||||||
)
|
)
|
||||||
|
|
||||||
_CGU_MARKDOWN = """
|
_CGU_MARKDOWN = """
|
||||||
L'accès aux fonctionnalités de base de decp.info est gratuit et sans inscription.
|
L'accès aux fonctionnalités de base de colibre est gratuit et sans inscription.
|
||||||
Un abonnement payant donne accès à des fonctionnalités supplémentaires qui nécessitent la création d'un compte.
|
Un abonnement payant donne accès à des fonctionnalités supplémentaires qui nécessitent la création d'un compte.
|
||||||
|
|
||||||
#### Fonctionnalités incluses
|
#### Fonctionnalités incluses
|
||||||
@@ -45,7 +45,7 @@ La période d'essai est accordée une seule fois par utilisateur.
|
|||||||
|
|
||||||
L'abonnement est facturé mensuellement, à la date anniversaire de la souscription.
|
L'abonnement est facturé mensuellement, à la date anniversaire de la souscription.
|
||||||
Le paiement est traité par [Frisbii](https://www.frisbii.com), prestataire européen de paiement en ligne.
|
Le paiement est traité par [Frisbii](https://www.frisbii.com), prestataire européen de paiement en ligne.
|
||||||
Les coordonnées bancaires sont conservées exclusivement par Frisbii et ne sont pas transmises à decp.info.
|
Les coordonnées bancaires sont conservées exclusivement par Frisbii et ne sont pas transmises à colibre.
|
||||||
|
|
||||||
#### Résiliation
|
#### Résiliation
|
||||||
|
|
||||||
@@ -54,9 +54,9 @@ La résiliation prend effet à la fin de la période mensuelle en cours : l'acc
|
|||||||
|
|
||||||
#### Données stockées
|
#### Données stockées
|
||||||
|
|
||||||
La gestion de l'abonnement implique le traitement de données personnelles, réparties entre decp.info et Frisbii (prestataire de paiement).
|
La gestion de l'abonnement implique le traitement de données personnelles, réparties entre colibre et Frisbii (prestataire de paiement).
|
||||||
|
|
||||||
**Données stockées par decp.info :**
|
**Données stockées par colibre :**
|
||||||
|
|
||||||
- Adresse e-mail (identification du compte)
|
- Adresse e-mail (identification du compte)
|
||||||
- Numéro SIRET (si renseigné, conservé pour pré-remplir les futures souscriptions et alimenter des fonctionnalités)
|
- Numéro SIRET (si renseigné, conservé pour pré-remplir les futures souscriptions et alimenter des fonctionnalités)
|
||||||
@@ -64,7 +64,7 @@ La gestion de l'abonnement implique le traitement de données personnelles, rép
|
|||||||
**Données stockées par Frisbii :**
|
**Données stockées par Frisbii :**
|
||||||
|
|
||||||
- Informations de facturation : prénom, nom, adresse postale, code postal, ville, pays, nom de l'entreprise
|
- Informations de facturation : prénom, nom, adresse postale, code postal, ville, pays, nom de l'entreprise
|
||||||
- Informations de paiement : coordonnées bancaires (accessibles uniquement par Frisbii, jamais transmises à decp.info)
|
- Informations de paiement : coordonnées bancaires (accessibles uniquement par Frisbii, jamais transmises à colibre)
|
||||||
- Historique des factures
|
- Historique des factures
|
||||||
|
|
||||||
Ces données sont utilisées uniquement pour la gestion de votre abonnement et ne sont pas transmises à des tiers à des fins commerciales.
|
Ces données sont utilisées uniquement pour la gestion de votre abonnement et ne sont pas transmises à des tiers à des fins commerciales.
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ from src.pages._compte_shell import account_guard, account_shell
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/compte/admin",
|
path="/compte/admin",
|
||||||
title="Mon compte | decp.info",
|
title="Mon compte | colibre",
|
||||||
name="Mon compte",
|
name="Mon compte",
|
||||||
description="Gestion de votre compte decp.info.",
|
description="Gestion de votre compte colibre.",
|
||||||
)
|
)
|
||||||
|
|
||||||
ERROR_MESSAGES = {
|
ERROR_MESSAGES = {
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ from src.subscriptions import db as subs_db
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/compte/roadmap",
|
path="/compte/roadmap",
|
||||||
title="Roadmap | decp.info",
|
title="Roadmap | colibre",
|
||||||
name="Roadmap",
|
name="Roadmap",
|
||||||
description="Votez pour les prochaines fonctionnalités de decp.info.",
|
description="Votez pour les prochaines fonctionnalités de colibre.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from src.saved_views import ui as saved_views_ui
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/compte/vues",
|
path="/compte/vues",
|
||||||
title="Mes vues | decp.info",
|
title="Mes vues | colibre",
|
||||||
name="Mes vues",
|
name="Mes vues",
|
||||||
description="Gérez vos vues enregistrées du tableau des marchés.",
|
description="Gérez vos vues enregistrées du tableau des marchés.",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ NAME = "Connexion"
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/connexion",
|
path="/connexion",
|
||||||
title="Connexion | decp.info",
|
title="Connexion | colibre",
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description="Se connecter à decp.info.",
|
description="Se connecter à colibre.",
|
||||||
)
|
)
|
||||||
|
|
||||||
ERROR_MESSAGES = {
|
ERROR_MESSAGES = {
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ NAME = "Quelles données pour quelles étapes et quels seuils dans les marchés
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/etapes",
|
path="/etapes",
|
||||||
title=f"{NAME} | decp.info",
|
title=f"{NAME} | colibre",
|
||||||
name="Étapes et données",
|
name="Étapes et données",
|
||||||
description=(
|
description=(
|
||||||
"À chaque étape d'un marché public (programmation, publicité, "
|
"À chaque étape d'un marché public (programmation, publicité, "
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ NAME = "Inscription"
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/inscription",
|
path="/inscription",
|
||||||
title="Inscription | decp.info",
|
title="Inscription | colibre",
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description="Créer un compte decp.info.",
|
description="Créer un compte colibre.",
|
||||||
)
|
)
|
||||||
|
|
||||||
ERROR_MESSAGES = {
|
ERROR_MESSAGES = {
|
||||||
|
|||||||
+2
-2
@@ -12,7 +12,7 @@ from src.utils.table import format_values, unformat_montant
|
|||||||
|
|
||||||
|
|
||||||
def get_title(uid: str = None) -> str:
|
def get_title(uid: str = None) -> str:
|
||||||
return f"Marché {uid} | decp.info"
|
return f"Marché {uid} | colibre"
|
||||||
|
|
||||||
|
|
||||||
register_page(
|
register_page(
|
||||||
@@ -231,7 +231,7 @@ def get_marche_jsonld(marche, titulaires) -> str:
|
|||||||
jsonld = {
|
jsonld = {
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "Order",
|
"@type": "Order",
|
||||||
"@id": f"https://decp.info/marches/{marche.get('uid')}",
|
"@id": f"https://colibre.fr/marches/{marche.get('uid')}",
|
||||||
"name": f"{marche.get('nature')} conclu par {marche.get('acheteur_nom')} le {marche.get('dateNotification')}",
|
"name": f"{marche.get('nature')} conclu par {marche.get('acheteur_nom')} le {marche.get('dateNotification')}",
|
||||||
"description": marche.get("objet"),
|
"description": marche.get("objet"),
|
||||||
"orderNumber": marche.get("uid"),
|
"orderNumber": marche.get("uid"),
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ NAME = "Mot de passe oublié"
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/mot-de-passe-oublie",
|
path="/mot-de-passe-oublie",
|
||||||
title="Mot de passe oublié | decp.info",
|
title="Mot de passe oublié | colibre",
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description="Réinitialiser votre mot de passe decp.info.",
|
description="Réinitialiser votre mot de passe colibre.",
|
||||||
)
|
)
|
||||||
|
|
||||||
ERROR_MESSAGES = {
|
ERROR_MESSAGES = {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ NAME = "Observatoire"
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/observatoire",
|
path="/observatoire",
|
||||||
title="Observatoire | decp.info",
|
title="Observatoire | colibre",
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description="Visualisez l'état de la publication des données essentielles des marchés publics en France.",
|
description="Visualisez l'état de la publication des données essentielles des marchés publics en France.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ NAME = "Recherche"
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/",
|
path="/",
|
||||||
title="Recherche de marchés publics | decp.info",
|
title="Recherche de marchés publics | colibre",
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description="Explorez et analysez les données des marchés publics français avec cet outil libre et gratuit. Pour une commande publique accessible à toutes et tous.",
|
description="Explorez et analysez les données des marchés publics français avec cet outil libre et gratuit. Pour une commande publique accessible à toutes et tous.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ NAME = "Réinitialiser le mot de passe"
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/reinitialiser-mot-de-passe",
|
path="/reinitialiser-mot-de-passe",
|
||||||
title="Nouveau mot de passe | decp.info",
|
title="Nouveau mot de passe | colibre",
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description="Choisir un nouveau mot de passe.",
|
description="Choisir un nouveau mot de passe.",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ NAME = "Tableau"
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/tableau",
|
path="/tableau",
|
||||||
title="Tableau des marchés publics | decp.info",
|
title="Tableau des marchés publics | colibre",
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description="Consultez, filtrez et exportez les données essentielles de la commande publique sous forme de tableau.",
|
description="Consultez, filtrez et exportez les données essentielles de la commande publique sous forme de tableau.",
|
||||||
image_url=META_CONTENT["image_url"],
|
image_url=META_CONTENT["image_url"],
|
||||||
@@ -149,7 +149,7 @@ layout = [
|
|||||||
"@type": "Dataset",
|
"@type": "Dataset",
|
||||||
"name": "Données essentielles des marchés publics français (DECP)",
|
"name": "Données essentielles des marchés publics français (DECP)",
|
||||||
"description": "Données de marchés publics exhaustives décrivant les marchés publics attribués en France depuis 2018.",
|
"description": "Données de marchés publics exhaustives décrivant les marchés publics attribués en France depuis 2018.",
|
||||||
"url": "https://decp.info",
|
"url": "https://colibre.fr",
|
||||||
"sameAs": "https://www.data.gouv.fr/datasets/608c055b35eb4e6ee20eb325",
|
"sameAs": "https://www.data.gouv.fr/datasets/608c055b35eb4e6ee20eb325",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"marchés publics",
|
"marchés publics",
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ def get_title(titulaire_id: str = None) -> str:
|
|||||||
"titulaire_nom"
|
"titulaire_nom"
|
||||||
)
|
)
|
||||||
if titulaire_nom.height > 0:
|
if titulaire_nom.height > 0:
|
||||||
return f"Marchés publics remportés par {titulaire_nom.item(0, 0)} | decp.info"
|
return f"Marchés publics remportés par {titulaire_nom.item(0, 0)} | colibre"
|
||||||
return "Marchés publics remportés | decp.info"
|
return "Marchés publics remportés | colibre"
|
||||||
|
|
||||||
|
|
||||||
register_page(
|
register_page(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ NAME = "Vérification email"
|
|||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
path="/verification-email",
|
path="/verification-email",
|
||||||
title="Vérification email | decp.info",
|
title="Vérification email | colibre",
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description="Vérification de l'adresse email.",
|
description="Vérification de l'adresse email.",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import httpx
|
|||||||
|
|
||||||
from src.utils.cache import cache
|
from src.utils.cache import cache
|
||||||
|
|
||||||
GITHUB_REPO = "ColinMaudry/decp.info"
|
GITHUB_REPO = "ColinMaudry/colibre"
|
||||||
_LABEL_KEYS = {"en cours": "en_cours", "mis au vote": "au_vote"}
|
_LABEL_KEYS = {"en cours": "en_cours", "mis au vote": "au_vote"}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ PLANS = {
|
|||||||
"env": "FRISBII_PLAN_SIMPLE",
|
"env": "FRISBII_PLAN_SIMPLE",
|
||||||
"label": "Abonnement",
|
"label": "Abonnement",
|
||||||
"prix_ht": 20,
|
"prix_ht": 20,
|
||||||
"description": "Accès aux fonctionnalités supplémentaires de decp.info.",
|
"description": "Accès aux fonctionnalités supplémentaires de colibre.",
|
||||||
},
|
},
|
||||||
"soutien": {
|
"soutien": {
|
||||||
"env": "FRISBII_PLAN_SOUTIEN",
|
"env": "FRISBII_PLAN_SOUTIEN",
|
||||||
|
|||||||
@@ -34,15 +34,15 @@ DEVELOPMENT = os.getenv("DEVELOPMENT", "False").lower() == "true"
|
|||||||
# Accès gratuit temporaire à toutes les fonctionnalités d'abonné, le temps que
|
# Accès gratuit temporaire à toutes les fonctionnalités d'abonné, le temps que
|
||||||
# la plateforme de paiement Frisbii valide la réception de paiements.
|
# la plateforme de paiement Frisbii valide la réception de paiements.
|
||||||
TOUS_ABONNES = os.getenv("TOUS_ABONNES", "False").lower() == "true"
|
TOUS_ABONNES = os.getenv("TOUS_ABONNES", "False").lower() == "true"
|
||||||
logger = logging.getLogger("decp.info")
|
logger = logging.getLogger("colibre")
|
||||||
|
|
||||||
if DEVELOPMENT:
|
if DEVELOPMENT:
|
||||||
logger.setLevel(logging.DEBUG)
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
DOMAIN_NAME = (
|
DOMAIN_NAME = (
|
||||||
"test.decp.info"
|
"test.colibre.fr"
|
||||||
if os.getenv("DEVELOPMENT", "False").lower() == "true"
|
if os.getenv("DEVELOPMENT", "False").lower() == "true"
|
||||||
else "decp.info"
|
else "colibre.fr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -29,7 +29,7 @@ def make_org_jsonld(org_id, org_type, org_name=None, type_org_id="SIRET") -> dic
|
|||||||
jsonld = {
|
jsonld = {
|
||||||
"@type": org_types[org_type],
|
"@type": org_types[org_type],
|
||||||
"name": org_name,
|
"name": org_name,
|
||||||
"url": f"https://decp.info/{org_type}s/{org_id}",
|
"url": f"https://{DOMAIN_NAME}/{org_type}s/{org_id}",
|
||||||
"sameAs": f"https://annuaire-entreprises.data.gouv.fr/etablissement/{org_id}",
|
"sameAs": f"https://annuaire-entreprises.data.gouv.fr/etablissement/{org_id}",
|
||||||
"identifier": {
|
"identifier": {
|
||||||
"@type": "PropertyValue",
|
"@type": "PropertyValue",
|
||||||
@@ -45,8 +45,8 @@ def make_org_jsonld(org_id, org_type, org_name=None, type_org_id="SIRET") -> dic
|
|||||||
|
|
||||||
|
|
||||||
META_CONTENT = {
|
META_CONTENT = {
|
||||||
"image_url": f"https://{DOMAIN_NAME}/assets/decp.info.png",
|
"image_url": f"https://{DOMAIN_NAME}/assets/colibre.png",
|
||||||
"title": "decp.info - exploration des marchés publics français",
|
"title": "colibre - exploration des marchés publics français",
|
||||||
"description": (
|
"description": (
|
||||||
"Explorez et analysez les données des marchés publics français avec cet outil libre et gratuit. "
|
"Explorez et analysez les données des marchés publics français avec cet outil libre et gratuit. "
|
||||||
"Pour une commande publique accessible à toutes et tous."
|
"Pour une commande publique accessible à toutes et tous."
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from src.utils import DEVELOPMENT
|
|||||||
|
|
||||||
def track_search(query, category):
|
def track_search(query, category):
|
||||||
if len(query) >= 4 and not DEVELOPMENT and os.getenv("MATOMO_DOMAIN"):
|
if len(query) >= 4 and not DEVELOPMENT and os.getenv("MATOMO_DOMAIN"):
|
||||||
url = "https://decp.info"
|
url = "https://colibre.fr"
|
||||||
params = {
|
params = {
|
||||||
"idsite": os.getenv("MATOMO_ID_SITE"),
|
"idsite": os.getenv("MATOMO_ID_SITE"),
|
||||||
"url": url,
|
"url": url,
|
||||||
|
|||||||
+22
-22
@@ -1,16 +1,16 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
"""Benchmark comparatif de l'endpoint /data : decp.info vs data.gouv.fr.
|
"""Benchmark comparatif de l'endpoint /data : colibre vs data.gouv.fr.
|
||||||
|
|
||||||
Les deux APIs partagent le même schéma de requête (mêmes opérateurs), donc
|
Les deux APIs partagent le même schéma de requête (mêmes opérateurs), donc
|
||||||
chaque scénario est envoyé à l'identique aux deux et les temps de réponse
|
chaque scénario est envoyé à l'identique aux deux et les temps de réponse
|
||||||
sont comparés côte à côte.
|
sont comparés côte à côte.
|
||||||
|
|
||||||
Usage :
|
Usage :
|
||||||
python tests/api/benchmark.py --token decpinfo_xxx
|
python tests/api/benchmark.py --token colibre_xxx
|
||||||
python tests/api/benchmark.py --url http://localhost:8050/api/v1/data --token decpinfo_xxx
|
python tests/api/benchmark.py --url http://localhost:8050/api/v1/data --token colibre_xxx
|
||||||
python tests/api/benchmark.py --decp-only --token decpinfo_xxx --runs 20
|
python tests/api/benchmark.py --decp-only --token colibre_xxx --runs 20
|
||||||
|
|
||||||
Par défaut, --url pointe vers la production decp.info ; data.gouv.fr est
|
Par défaut, --url pointe vers la production colibre.fr ; data.gouv.fr est
|
||||||
interrogé sans authentification.
|
interrogé sans authentification.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -23,7 +23,7 @@ from urllib.parse import quote
|
|||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
DECP_DEFAULT_URL = "https://decp.info/api/v1/data"
|
DECP_DEFAULT_URL = "https://colibre.fr/api/v1/data"
|
||||||
DATAGOUV_DEFAULT_URL = (
|
DATAGOUV_DEFAULT_URL = (
|
||||||
"https://tabular-api.data.gouv.fr/api/resources/"
|
"https://tabular-api.data.gouv.fr/api/resources/"
|
||||||
"22847056-61df-452d-837d-8b8ceadbfc52/data/"
|
"22847056-61df-452d-837d-8b8ceadbfc52/data/"
|
||||||
@@ -169,7 +169,7 @@ def measure(target: Target, query: str, runs: int) -> dict | None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def run_benchmark(targets: list[Target], decp_label: str, runs: int) -> None:
|
def run_benchmark(targets: list[Target], colibre_label: str, runs: int) -> None:
|
||||||
print("\nAVERTISSEMENT : volumes de données différents entre les deux APIs.")
|
print("\nAVERTISSEMENT : volumes de données différents entre les deux APIs.")
|
||||||
print(f"Scénarios : {len(SCENARIOS)} | Répétitions : {runs}\n")
|
print(f"Scénarios : {len(SCENARIOS)} | Répétitions : {runs}\n")
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ def run_benchmark(targets: list[Target], decp_label: str, runs: int) -> None:
|
|||||||
for scenario in SCENARIOS:
|
for scenario in SCENARIOS:
|
||||||
query = build_query(scenario["params"])
|
query = build_query(scenario["params"])
|
||||||
decp_only = scenario.get("decp_only", False)
|
decp_only = scenario.get("decp_only", False)
|
||||||
active = [t for t in targets if not (decp_only and t.label != decp_label)]
|
active = [t for t in targets if not (decp_only and t.label != colibre_label)]
|
||||||
|
|
||||||
measures = {t.label: measure(t, query, runs) for t in active}
|
measures = {t.label: measure(t, query, runs) for t in active}
|
||||||
rows.append({"name": scenario["name"], "measures": measures})
|
rows.append({"name": scenario["name"], "measures": measures})
|
||||||
@@ -191,7 +191,7 @@ def run_benchmark(targets: list[Target], decp_label: str, runs: int) -> None:
|
|||||||
bits.append(f"{t.label}: méd {m['median']:.0f}ms [{m['status']}]")
|
bits.append(f"{t.label}: méd {m['median']:.0f}ms [{m['status']}]")
|
||||||
print(f" {scenario['name'][:COL_NAME]:<{COL_NAME}} " + " | ".join(bits))
|
print(f" {scenario['name'][:COL_NAME]:<{COL_NAME}} " + " | ".join(bits))
|
||||||
|
|
||||||
_print_summary(rows, targets, decp_label)
|
_print_summary(rows, targets, colibre_label)
|
||||||
|
|
||||||
|
|
||||||
def _fmt(m: dict | None, key: str) -> str:
|
def _fmt(m: dict | None, key: str) -> str:
|
||||||
@@ -202,8 +202,8 @@ def _fmt(m: dict | None, key: str) -> str:
|
|||||||
return f"{m[key]:.0f}"
|
return f"{m[key]:.0f}"
|
||||||
|
|
||||||
|
|
||||||
def _print_summary(rows: list[dict], targets: list[Target], decp_label: str) -> None:
|
def _print_summary(rows: list[dict], targets: list[Target], colibre_label: str) -> None:
|
||||||
dg = next((t.label for t in targets if t.label != decp_label), None)
|
dg = next((t.label for t in targets if t.label != colibre_label), None)
|
||||||
|
|
||||||
header = (
|
header = (
|
||||||
f"{'Scénario':<{COL_NAME}}"
|
f"{'Scénario':<{COL_NAME}}"
|
||||||
@@ -218,18 +218,18 @@ def _print_summary(rows: list[dict], targets: list[Target], decp_label: str) ->
|
|||||||
print(f"{'=' * len(header)}\n{header}\n{sep}")
|
print(f"{'=' * len(header)}\n{header}\n{sep}")
|
||||||
|
|
||||||
for row in rows:
|
for row in rows:
|
||||||
m_decp = row["measures"].get(decp_label)
|
m_colibre = row["measures"].get(colibre_label)
|
||||||
m_dg = row["measures"].get(dg) if dg else None
|
m_dg = row["measures"].get(dg) if dg else None
|
||||||
|
|
||||||
ratio = "—"
|
ratio = "—"
|
||||||
if m_decp and m_dg and "error" not in m_decp and "error" not in m_dg:
|
if m_colibre and m_dg and "error" not in m_colibre and "error" not in m_dg:
|
||||||
if m_dg["median"] > 0:
|
if m_dg["median"] > 0:
|
||||||
ratio = f"{m_decp['median'] / m_dg['median']:.2f}"
|
ratio = f"{m_colibre['median'] / m_dg['median']:.2f}"
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"{row['name'][:COL_NAME]:<{COL_NAME}}"
|
f"{row['name'][:COL_NAME]:<{COL_NAME}}"
|
||||||
f" {_fmt(m_dg, 'median'):>{COL_STAT}} {_fmt(m_dg, 'p95'):>{COL_STAT}}"
|
f" {_fmt(m_dg, 'median'):>{COL_STAT}} {_fmt(m_dg, 'p95'):>{COL_STAT}}"
|
||||||
f" {_fmt(m_decp, 'median'):>{COL_STAT}} {_fmt(m_decp, 'p95'):>{COL_STAT}}"
|
f" {_fmt(m_colibre, 'median'):>{COL_STAT}} {_fmt(m_colibre, 'p95'):>{COL_STAT}}"
|
||||||
f" {ratio:>7}"
|
f" {ratio:>7}"
|
||||||
)
|
)
|
||||||
print(sep)
|
print(sep)
|
||||||
@@ -237,12 +237,12 @@ def _print_summary(rows: list[dict], targets: list[Target], decp_label: str) ->
|
|||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Benchmark comparatif decp.info vs data.gouv.fr (/data)"
|
description="Benchmark comparatif colibre vs data.gouv.fr (/data)"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--url",
|
"--url",
|
||||||
default=DECP_DEFAULT_URL,
|
default=DECP_DEFAULT_URL,
|
||||||
help=f"Endpoint /data de decp.info (défaut : {DECP_DEFAULT_URL})",
|
help=f"Endpoint /data de colibre (défaut : {DECP_DEFAULT_URL})",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--datagouv-url",
|
"--datagouv-url",
|
||||||
@@ -252,7 +252,7 @@ def main() -> None:
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--token",
|
"--token",
|
||||||
default=None,
|
default=None,
|
||||||
help="Token Bearer decp.info (format decpinfo_xxx)",
|
help="Token Bearer colibre (format decpinfo_xxx)",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--runs",
|
"--runs",
|
||||||
@@ -263,7 +263,7 @@ def main() -> None:
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--decp-only",
|
"--decp-only",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Ne benchmarker que decp.info (saute data.gouv.fr)",
|
help="Ne benchmarker que colibre (saute data.gouv.fr)",
|
||||||
)
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@@ -271,16 +271,16 @@ def main() -> None:
|
|||||||
print("--runs doit être ≥ 1", file=sys.stderr)
|
print("--runs doit être ≥ 1", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
decp_label = "decp.info"
|
colibre_label = "colibre"
|
||||||
decp_headers = {"Authorization": f"Bearer {args.token}"} if args.token else {}
|
decp_headers = {"Authorization": f"Bearer {args.token}"} if args.token else {}
|
||||||
decp = Target(label=decp_label, base_url=args.url, headers=decp_headers)
|
decp = Target(label=colibre_label, base_url=args.url, headers=decp_headers)
|
||||||
|
|
||||||
targets = [decp]
|
targets = [decp]
|
||||||
if not args.decp_only:
|
if not args.decp_only:
|
||||||
# data.gouv.fr d'abord pour l'affichage côte à côte
|
# data.gouv.fr d'abord pour l'affichage côte à côte
|
||||||
targets.insert(0, Target(label="data.gouv.fr", base_url=args.datagouv_url))
|
targets.insert(0, Target(label="data.gouv.fr", base_url=args.datagouv_url))
|
||||||
|
|
||||||
run_benchmark(targets, decp_label, args.runs)
|
run_benchmark(targets, colibre_label, args.runs)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ def fake_client(monkeypatch):
|
|||||||
monkeypatch.setenv("APP_BASE_URL", "http://localhost:8050")
|
monkeypatch.setenv("APP_BASE_URL", "http://localhost:8050")
|
||||||
monkeypatch.setenv("BREVO_TEMPLATE_VERIFY_ID", "11")
|
monkeypatch.setenv("BREVO_TEMPLATE_VERIFY_ID", "11")
|
||||||
monkeypatch.setenv("BREVO_TEMPLATE_RESET_ID", "22")
|
monkeypatch.setenv("BREVO_TEMPLATE_RESET_ID", "22")
|
||||||
monkeypatch.setenv("MAIL_FROM", "noreply@decp.info")
|
monkeypatch.setenv("MAIL_FROM", "noreply@colibre")
|
||||||
monkeypatch.setenv("MAIL_FROM_NAME", "decp.info")
|
monkeypatch.setenv("MAIL_FROM_NAME", "colibre")
|
||||||
return client
|
return client
|
||||||
|
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ def test_send_verification_email(fake_client):
|
|||||||
call = calls[0]
|
call = calls[0]
|
||||||
assert call["template_id"] == 11
|
assert call["template_id"] == 11
|
||||||
assert call["to"][0].email == "a@b.c"
|
assert call["to"][0].email == "a@b.c"
|
||||||
assert call["sender"].email == "noreply@decp.info"
|
assert call["sender"].email == "noreply@colibre"
|
||||||
assert "/auth/verify-email?token=TOKEN123" in call["params"]["link"]
|
assert "/auth/verify-email?token=TOKEN123" in call["params"]["link"]
|
||||||
assert call["headers"] == {"X-Sib-Sandbox": "drop"} # DEVELOPMENT=true en tests
|
assert call["headers"] == {"X-Sib-Sandbox": "drop"} # DEVELOPMENT=true en tests
|
||||||
|
|
||||||
|
|||||||
@@ -17,5 +17,5 @@ def test_send_verification_email_sandbox(monkeypatch):
|
|||||||
mailer.init_mailer()
|
mailer.init_mailer()
|
||||||
# Ne doit pas lever : l'API Brevo accepte la requête en sandbox.
|
# Ne doit pas lever : l'API Brevo accepte la requête en sandbox.
|
||||||
mailer.send_verification_email(
|
mailer.send_verification_email(
|
||||||
os.getenv("MAIL_FROM", "noreply@decp.info"), "INTEGRATION_TOKEN"
|
os.getenv("MAIL_FROM", "noreply@colibre"), "INTEGRATION_TOKEN"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from moto import mock_aws
|
|||||||
|
|
||||||
from src.backup.storage import S3Storage
|
from src.backup.storage import S3Storage
|
||||||
|
|
||||||
BUCKET = "decp-backups"
|
BUCKET = "colibre-backups"
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|||||||
+4
-4
@@ -43,10 +43,10 @@ _TEST_DATA = [
|
|||||||
_PARQUET_PATH = Path(os.path.abspath("tests/test.parquet"))
|
_PARQUET_PATH = Path(os.path.abspath("tests/test.parquet"))
|
||||||
|
|
||||||
# Base DuckDB de test ISOLÉE : src.db lit le chemin via DUCKDB_PATH (défaut
|
# Base DuckDB de test ISOLÉE : src.db lit le chemin via DUCKDB_PATH (défaut
|
||||||
# ./decp.duckdb). On la place dans tests/ pour ne JAMAIS toucher au decp.duckdb
|
# ./colibre.duckdb). On la place dans tests/ pour ne JAMAIS toucher au colibre.duckdb
|
||||||
# de dev/prod — plus besoin de sauvegarder/restaurer. Le nom decp.duckdb
|
# de dev/prod — plus besoin de sauvegarder/restaurer. Le nom colibre.duckdb
|
||||||
# correspond au motif **/decp.duckdb déjà présent dans .gitignore.
|
# correspond au motif **/colibre.duckdb déjà présent dans .gitignore.
|
||||||
_DB_PATH = Path(os.path.abspath("tests/decp.duckdb"))
|
_DB_PATH = Path(os.path.abspath("tests/colibre.duckdb"))
|
||||||
os.environ["DUCKDB_PATH"] = str(_DB_PATH)
|
os.environ["DUCKDB_PATH"] = str(_DB_PATH)
|
||||||
|
|
||||||
# Schéma déterministe et hors-ligne : on COPIE le fixture committé vers un cache
|
# Schéma déterministe et hors-ligne : on COPIE le fixture committé vers un cache
|
||||||
|
|||||||
@@ -16,25 +16,25 @@ _ISSUES = [
|
|||||||
{
|
{
|
||||||
"number": 10,
|
"number": 10,
|
||||||
"title": "Feature en cours",
|
"title": "Feature en cours",
|
||||||
"html_url": "https://github.com/ColinMaudry/decp.info/issues/10",
|
"html_url": "https://github.com/ColinMaudry/colibre/issues/10",
|
||||||
"labels": [{"name": "en cours"}],
|
"labels": [{"name": "en cours"}],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"number": 20,
|
"number": 20,
|
||||||
"title": "Feature au vote",
|
"title": "Feature au vote",
|
||||||
"html_url": "https://github.com/ColinMaudry/decp.info/issues/20",
|
"html_url": "https://github.com/ColinMaudry/colibre/issues/20",
|
||||||
"labels": [{"name": "mis au vote"}],
|
"labels": [{"name": "mis au vote"}],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"number": 30,
|
"number": 30,
|
||||||
"title": "Issue sans label pertinent",
|
"title": "Issue sans label pertinent",
|
||||||
"html_url": "https://github.com/ColinMaudry/decp.info/issues/30",
|
"html_url": "https://github.com/ColinMaudry/colibre/issues/30",
|
||||||
"labels": [{"name": "bug"}],
|
"labels": [{"name": "bug"}],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"number": 40,
|
"number": 40,
|
||||||
"title": "Une PR déguisée en issue",
|
"title": "Une PR déguisée en issue",
|
||||||
"html_url": "https://github.com/ColinMaudry/decp.info/pull/40",
|
"html_url": "https://github.com/ColinMaudry/colibre/pull/40",
|
||||||
"labels": [{"name": "mis au vote"}],
|
"labels": [{"name": "mis au vote"}],
|
||||||
"pull_request": {"url": "..."},
|
"pull_request": {"url": "..."},
|
||||||
},
|
},
|
||||||
@@ -49,5 +49,5 @@ def test_fetch_roadmap_issues_filters_by_label(monkeypatch):
|
|||||||
assert result["en_cours"][0] == {
|
assert result["en_cours"][0] == {
|
||||||
"number": 10,
|
"number": 10,
|
||||||
"title": "Feature en cours",
|
"title": "Feature en cours",
|
||||||
"html_url": "https://github.com/ColinMaudry/decp.info/issues/10",
|
"html_url": "https://github.com/ColinMaudry/colibre/issues/10",
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-9
@@ -33,8 +33,8 @@ def test_001_logo_and_search(dash_duo: DashComposite):
|
|||||||
from src.app import app
|
from src.app import app
|
||||||
|
|
||||||
dash_duo.start_server(app)
|
dash_duo.start_server(app)
|
||||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||||
assert dash_duo.find_element(".logo > h1").text == "decp.info"
|
assert dash_duo.find_element(".logo > h1").text == "colibre"
|
||||||
|
|
||||||
for org_type in ["acheteur", "titulaire"]:
|
for org_type in ["acheteur", "titulaire"]:
|
||||||
name = f"{org_type.upper()} 1"
|
name = f"{org_type.upper()} 1"
|
||||||
@@ -64,7 +64,7 @@ def test_002_filter_persistence(dash_duo: DashComposite):
|
|||||||
from src.app import app
|
from src.app import app
|
||||||
|
|
||||||
dash_duo.start_server(app)
|
dash_duo.start_server(app)
|
||||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||||
|
|
||||||
def open_page_and_check_filter_input():
|
def open_page_and_check_filter_input():
|
||||||
dash_duo.wait_for_page(f"{dash_duo.server_url}/{page}")
|
dash_duo.wait_for_page(f"{dash_duo.server_url}/{page}")
|
||||||
@@ -172,7 +172,7 @@ def test_006_observatoire_url_to_input(dash_duo: DashComposite):
|
|||||||
from src.app import app
|
from src.app import app
|
||||||
|
|
||||||
dash_duo.start_server(app)
|
dash_duo.start_server(app)
|
||||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||||
|
|
||||||
# Navigate to observatoire with acheteur_id query param
|
# Navigate to observatoire with acheteur_id query param
|
||||||
dash_duo.wait_for_page(f"{dash_duo.server_url}/observatoire?acheteur_id=123")
|
dash_duo.wait_for_page(f"{dash_duo.server_url}/observatoire?acheteur_id=123")
|
||||||
@@ -192,7 +192,7 @@ def test_007_observatoire_share_url(dash_duo: DashComposite):
|
|||||||
from src.app import app
|
from src.app import app
|
||||||
|
|
||||||
dash_duo.start_server(app)
|
dash_duo.start_server(app)
|
||||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||||
|
|
||||||
# Navigate to observatoire with acheteur_id query param
|
# Navigate to observatoire with acheteur_id query param
|
||||||
dash_duo.wait_for_page(f"{dash_duo.server_url}/observatoire?acheteur_id=123")
|
dash_duo.wait_for_page(f"{dash_duo.server_url}/observatoire?acheteur_id=123")
|
||||||
@@ -214,7 +214,7 @@ def test_008_search_to_observatoire(dash_duo: DashComposite):
|
|||||||
from src.app import app
|
from src.app import app
|
||||||
|
|
||||||
dash_duo.start_server(app)
|
dash_duo.start_server(app)
|
||||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||||
|
|
||||||
# Search for an acheteur
|
# Search for an acheteur
|
||||||
search_bar = dash_duo.find_element("#search")
|
search_bar = dash_duo.find_element("#search")
|
||||||
@@ -251,7 +251,7 @@ def test_009_observatoire_filter_persistence(dash_duo: DashComposite):
|
|||||||
from src.app import app
|
from src.app import app
|
||||||
|
|
||||||
dash_duo.start_server(app)
|
dash_duo.start_server(app)
|
||||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||||
|
|
||||||
# Clear localStorage to start from a clean state
|
# Clear localStorage to start from a clean state
|
||||||
dash_duo.driver.execute_script("localStorage.clear()")
|
dash_duo.driver.execute_script("localStorage.clear()")
|
||||||
@@ -298,7 +298,7 @@ def test_011_observatoire_multi_param_url(dash_duo: DashComposite):
|
|||||||
from src.app import app
|
from src.app import app
|
||||||
|
|
||||||
dash_duo.start_server(app)
|
dash_duo.start_server(app)
|
||||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||||
|
|
||||||
# Navigate with multiple filter params
|
# Navigate with multiple filter params
|
||||||
dash_duo.wait_for_page(
|
dash_duo.wait_for_page(
|
||||||
@@ -360,7 +360,7 @@ def test_015_tableau_filter_date(dash_duo: DashComposite):
|
|||||||
from src.app import app
|
from src.app import app
|
||||||
|
|
||||||
dash_duo.start_server(app)
|
dash_duo.start_server(app)
|
||||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||||
|
|
||||||
for page in ["tableau", "acheteurs/123", "titulaires/345"]:
|
for page in ["tableau", "acheteurs/123", "titulaires/345"]:
|
||||||
dash_duo.wait_for_page(f"{dash_duo.server_url}/{page}")
|
dash_duo.wait_for_page(f"{dash_duo.server_url}/{page}")
|
||||||
|
|||||||
Reference in New Issue
Block a user