From ef562083feca5c5c4c590a86c3c1f8f493807600 Mon Sep 17 00:00:00 2001 From: Antoine Van Elstraete Date: Tue, 8 Sep 2026 18:08:09 +0200 Subject: [PATCH] =?UTF-8?q?Corriger=20la=20valeur=20par=20d=C3=A9faut=20de?= =?UTF-8?q?=20BLOG=5FRSS=5FURL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Configuration.md | 121 --------------------------------------- unnamed.md | 143 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 107 insertions(+), 157 deletions(-) delete mode 100644 Configuration.md diff --git a/Configuration.md b/Configuration.md deleted file mode 100644 index c545291..0000000 --- a/Configuration.md +++ /dev/null @@ -1,121 +0,0 @@ -# Configuration - -Configuration via `pydantic-settings` depuis les variables d'environnement ou un fichier `.env`. Copiez `.env.example` vers `.env` pour démarrer. Les secrets utilisent `SecretStr` et sont masqués dans les logs. - -## Principe - -Les paramètres sont chargés automatiquement depuis les variables d'environnement ou un fichier `.env` à la racine du projet. Le fichier `.env` n'est **jamais** versionné (couvert par `.gitignore`). - -## Variables Pronote - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `PRONOTE_ICAL_URL` | URL du flux iCal Pronote (contient `icalsecurise`) | obligatoire si source `ical` | SecretStr | -| `PRONOTE_URL` | URL de la page Pronote pour `pronotepy` | obligatoire si source `pronotepy` | str | -| `PRONOTE_ACCOUNT_TYPE` | Type de compte Pronote | `parent` | str | -| `PRONOTE_USERNAME` | Identifiant Pronote | obligatoire si source `pronotepy` | str | -| `PRONOTE_PASSWORD` | Mot de passe Pronote | obligatoire si source `pronotepy` | SecretStr | -| `PRONOTE_ENT` | Slug ENT (résolu vers `pronotepy.ent`) | optionnel | str | -| `PRONOTE_AGENDA_SOURCE` | Source pour l'agenda | `auto` | Literal["auto", "ical", "pronotepy"] | -| `PRONOTE_HOMEWORK_SOURCE` | Source pour les devoirs | `auto` | Literal["auto", "ical", "pronotepy"] | -| `PRONOTE_MESSAGES_SOURCE` | Source pour les messages | `pronotepy` | Literal["pronotepy"] | - -> **Note** : `PRONOTE_URL` et `PRONOTE_ICAL_URL` sont deux contrats distincts. L'un ne doit **jamais** être déduit de l'autre. - -## Variables CalDAV - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `CALDAV_URL` | URL du serveur CalDAV | obligatoire | SecretStr | -| `CALDAV_USERNAME` | Identifiant CalDAV | obligatoire | str | -| `CALDAV_PASSWORD` | Mot de passe CalDAV | obligatoire | SecretStr | -| `CALDAV_CALENDAR_PATH` | Chemin du calendrier sur le serveur | `/pronote-sync/` | str | -| `CALDAV_ALLOW_INSECURE_HTTP` | Autoriser HTTP non sécurisé (localhost uniquement) | `false` | bool | - -## Fenêtre de synchronisation - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `SYNC_PAST_DAYS` | Nombre de jours dans le passé à synchroniser | `7` | int | -| `SYNC_FUTURE_DAYS` | Nombre de jours dans le futur à synchroniser | `30` | int | - -## Agenda théorique - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `THEORETICAL_AGENDA_PATH` | Chemin vers le fichier JSON de l'agenda théorique | `None` | str \| None | -| `SCHOOL_HOLIDAYS_PATH` | Chemin vers le fichier JSON des vacances scolaires | `None` | str \| None | -| `THEORETICAL_WEEK_ANCHOR_DATE` | Date de référence pour la parité des semaines | `None` | date \| None | -| `THEORETICAL_WEEK_ANCHOR_TYPE` | Parité de la semaine de référence | `None` | Literal["even", "odd"] \| None | - -## Variables XMPP - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `XMPP_ENABLED` | Activer la notification XMPP | `false` | bool | -| `XMPP_JID` | Identifiant XMPP (ex: `user@example.com`) | obligatoire si activé | str | -| `XMPP_PASSWORD` | Mot de passe XMPP | obligatoire si activé | SecretStr | -| `XMPP_HOST` | Hôte XMPP | `""` | str | -| `XMPP_PORT` | Port XMPP | `5222` | int | -| `XMPP_TO` | Destinataire XMPP | obligatoire si activé | str | -| `XMPP_RESOURCE` | Ressource XMPP | `pronote-sync` | str | -| `XMPP_USE_TLS` | Utiliser TLS pour la connexion | `true` | bool | -| `XMPP_TIMEOUT` | Délai d'attente en secondes | `30` | int | - -## Variables IA - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `AI_ENABLED` | Activer la synthèse IA | `false` | bool | -| `AI_PROVIDER` | Fournisseur IA | `openai` | Literal["openai", "litellm", "openai-compatible"] | -| `AI_BASE_URL` | URL de base de l'API IA | `None` | str \| None | -| `AI_API_KEY` | Clé API IA | `None` | SecretStr | -| `AI_MODEL` | Modèle IA | `None` | str \| None | -| `AI_ALLOW_INSECURE_HTTP` | Autoriser HTTP non sécurisé pour `openai-compatible` | `false` | bool | - -> **Note** : Le fournisseur `openai-compatible` réutilise `OpenAISynthesisProvider` avec un `base_url` personnalisé. `AI_BASE_URL` et `AI_MODEL` sont requis pour ce fournisseur. L'URL doit utiliser `https` sauf si `AI_ALLOW_INSECURE_HTTP=true`. Les identifiants dans l'URL sont rejetés. Les paramètres sensibles dans la *query string* sont rejetés. Aucune manipulation automatique de `/v1` n'est effectuée. En cas de configuration invalide, la factory retourne `None` avec un avertissement (mode dégradé). - -Exemples de configuration pour `openai-compatible` : - -```bash -# OpenRouter (HTTPS) -AI_PROVIDER=openai-compatible -AI_BASE_URL=https://openrouter.ai/api/v1 -AI_MODEL=fournisseur/modele -AI_API_KEY=your-openrouter-key -AI_ALLOW_INSECURE_HTTP=false - -# Ollama local (HTTP) -AI_PROVIDER=openai-compatible -AI_BASE_URL=http://127.0.0.1:11434/v1 -AI_MODEL=modele-local -AI_API_KEY=local-not-required -AI_ALLOW_INSECURE_HTTP=true -``` - -## Variables Blog - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `BLOG_ENABLED` | Activer la synchronisation du blog | `false` | bool | -| `BLOG_RSS_URL` | URL du flux RSS du blog | (ex: `https://blogpeda.ac-bordeaux.fr/cjeliote/?feed=rss2`) | str | - -## Divers - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `DRY_RUN` | Mode simulation (pas d'écriture) | `false` | bool | -| `LOG_LEVEL` | Niveau de log | `INFO` | str | - -## Fichier .env - -Pour créer votre fichier de configuration : - -```bash -cp .env.example .env -# Éditer .env avec vos paramètres -``` - -> **Rappel** : Le fichier `.env` n'est **jamais** versionné. Utilisez `.env.example` comme modèle. - -Voir aussi : [Sécurité](Sécurité) pour la gestion des secrets, [Déploiement](Déploiement) pour la configuration en production. \ No newline at end of file diff --git a/unnamed.md b/unnamed.md index 631f5d8..156efae 100644 --- a/unnamed.md +++ b/unnamed.md @@ -1,50 +1,121 @@ -# Architecture +# Configuration -## Vue d'ensemble +Configuration via `pydantic-settings` depuis les variables d'environnement ou un fichier `.env`. Copiez `.env.example` vers `.env` pour démarrer. Les secrets utilisent `SecretStr` et sont masqués dans les logs. -`pronote-sync` est un pipeline qui synchronise les données de **Pronote** vers **CalDAV** (agendas) et **XMPP** (notifications). Le flux principal est : **Pronote (iCal/pronotepy) → normalisation → comparaison avec l'agenda théorique → synchronisation CalDAV → synthèse IA (optionnelle) → notification XMPP**. Les sources sont **iCal** (primaire) et `pronotepy` (repli), avec trois modes de source : `auto`, `ical` et `pronotepy`. +## Principe -## Pipeline +Les paramètres sont chargés automatiquement depuis les variables d'environnement ou un fichier `.env` à la racine du projet. Le fichier `.env` n'est **jamais** versionné (couvert par `.gitignore`). -1. Récupération Pronote — agenda et devoirs via iCal ou `pronotepy` ; messages et informations via `pronotepy` uniquement -1. Normalisation et parsing — parsing iCal → modèles Pydantic, déduplication, normalisation des UID -1. Récupération du blog (RSS) — `feedparser`, déduplication par GUID, cache HTTP -1. Comparaison avec l'agenda théorique — matching déterministe, détection des changements -1. Synchronisation CalDAV — sync différentielle et idempotente, UID stables, conservation des annulés -1. Synthèse IA (optionnelle) — synthèse des changements, mode dégradé si échec -1. Envoi XMPP — message structuré (synthèse + devoirs bruts) +## Variables Pronote -## Modules +| Variable | Description | Valeur par défaut | Type | +|----------|-------------|--------------------|------| +| `PRONOTE_ICAL_URL` | URL du flux iCal Pronote (contient `icalsecurise`) | obligatoire si source `ical` | SecretStr | +| `PRONOTE_URL` | URL de la page Pronote pour `pronotepy` | obligatoire si source `pronotepy` | str | +| `PRONOTE_ACCOUNT_TYPE` | Type de compte Pronote | `parent` | str | +| `PRONOTE_USERNAME` | Identifiant Pronote | obligatoire si source `pronotepy` | str | +| `PRONOTE_PASSWORD` | Mot de passe Pronote | obligatoire si source `pronotepy` | SecretStr | +| `PRONOTE_ENT` | Slug ENT (résolu vers `pronotepy.ent`) | optionnel | str | +| `PRONOTE_AGENDA_SOURCE` | Source pour l'agenda | `auto` | Literal["auto", "ical", "pronotepy"] | +| `PRONOTE_HOMEWORK_SOURCE` | Source pour les devoirs | `auto` | Literal["auto", "ical", "pronotepy"] | +| `PRONOTE_MESSAGES_SOURCE` | Source pour les messages | `pronotepy` | Literal["pronotepy"] | -```text -pronote_sync/ -├── config/ Configuration (Pydantic Settings) -├── models/ Modèles de données (Pydantic v2) -├── sources/ Connecteurs (Pronote iCal/pronotepy, blog RSS, agenda théorique) -├── sync/ Synchronisation CalDAV et comparaison -├── synthesis/ Synthèse IA (OpenAI, litellm, openai-compatible) -├── channels/ Canaux de sortie (XMPP) -├── pipeline/ Orchestration (composition root, PipelineRunner) -├── utils/ Utilitaires (redaction, logging, UID) -└── cli/ Interface en ligne de commande +> **Note** : `PRONOTE_URL` et `PRONOTE_ICAL_URL` sont deux contrats distincts. L'un ne doit **jamais** être déduit de l'autre. + +## Variables CalDAV + +| Variable | Description | Valeur par défaut | Type | +|----------|-------------|--------------------|------| +| `CALDAV_URL` | URL du serveur CalDAV | obligatoire | SecretStr | +| `CALDAV_USERNAME` | Identifiant CalDAV | obligatoire | str | +| `CALDAV_PASSWORD` | Mot de passe CalDAV | obligatoire | SecretStr | +| `CALDAV_CALENDAR_PATH` | Chemin du calendrier sur le serveur | `/pronote-sync/` | str | +| `CALDAV_ALLOW_INSECURE_HTTP` | Autoriser HTTP non sécurisé (localhost uniquement) | `false` | bool | + +## Fenêtre de synchronisation + +| Variable | Description | Valeur par défaut | Type | +|----------|-------------|--------------------|------| +| `SYNC_PAST_DAYS` | Nombre de jours dans le passé à synchroniser | `7` | int | +| `SYNC_FUTURE_DAYS` | Nombre de jours dans le futur à synchroniser | `30` | int | + +## Agenda théorique + +| Variable | Description | Valeur par défaut | Type | +|----------|-------------|--------------------|------| +| `THEORETICAL_AGENDA_PATH` | Chemin vers le fichier JSON de l'agenda théorique | `None` | str \| None | +| `SCHOOL_HOLIDAYS_PATH` | Chemin vers le fichier JSON des vacances scolaires | `None` | str \| None | +| `THEORETICAL_WEEK_ANCHOR_DATE` | Date de référence pour la parité des semaines | `None` | date \| None | +| `THEORETICAL_WEEK_ANCHOR_TYPE` | Parité de la semaine de référence | `None` | Literal["even", "odd"] \| None | + +## Variables XMPP + +| Variable | Description | Valeur par défaut | Type | +|----------|-------------|--------------------|------| +| `XMPP_ENABLED` | Activer la notification XMPP | `false` | bool | +| `XMPP_JID` | Identifiant XMPP (ex: `user@example.com`) | obligatoire si activé | str | +| `XMPP_PASSWORD` | Mot de passe XMPP | obligatoire si activé | SecretStr | +| `XMPP_HOST` | Hôte XMPP | `""` | str | +| `XMPP_PORT` | Port XMPP | `5222` | int | +| `XMPP_TO` | Destinataire XMPP | obligatoire si activé | str | +| `XMPP_RESOURCE` | Ressource XMPP | `pronote-sync` | str | +| `XMPP_USE_TLS` | Utiliser TLS pour la connexion | `true` | bool | +| `XMPP_TIMEOUT` | Délai d'attente en secondes | `30` | int | + +## Variables IA + +| Variable | Description | Valeur par défaut | Type | +|----------|-------------|--------------------|------| +| `AI_ENABLED` | Activer la synthèse IA | `false` | bool | +| `AI_PROVIDER` | Fournisseur IA | `openai` | Literal["openai", "litellm", "openai-compatible"] | +| `AI_BASE_URL` | URL de base de l'API IA | `None` | str \| None | +| `AI_API_KEY` | Clé API IA | `None` | SecretStr | +| `AI_MODEL` | Modèle IA | `None` | str \| None | +| `AI_ALLOW_INSECURE_HTTP` | Autoriser HTTP non sécurisé pour `openai-compatible` | `false` | bool | + +> **Note** : Le fournisseur `openai-compatible` réutilise `OpenAISynthesisProvider` avec un `base_url` personnalisé. `AI_BASE_URL` et `AI_MODEL` sont requis pour ce fournisseur. L'URL doit utiliser `https` sauf si `AI_ALLOW_INSECURE_HTTP=true`. Les identifiants dans l'URL sont rejetés. Les paramètres sensibles dans la *query string* sont rejetés. Aucune manipulation automatique de `/v1` n'est effectuée. En cas de configuration invalide, la factory retourne `None` avec un avertissement (mode dégradé). + +Exemples de configuration pour `openai-compatible` : + +```bash +# OpenRouter (HTTPS) +AI_PROVIDER=openai-compatible +AI_BASE_URL=https://openrouter.ai/api/v1 +AI_MODEL=fournisseur/modele +AI_API_KEY=your-openrouter-key +AI_ALLOW_INSECURE_HTTP=false + +# Ollama local (HTTP) +AI_PROVIDER=openai-compatible +AI_BASE_URL=http://127.0.0.1:11434/v1 +AI_MODEL=modele-local +AI_API_KEY=local-not-required +AI_ALLOW_INSECURE_HTTP=true ``` -## Injection de dépendances +## Variables Blog -Le projet utilise `typing.Protocol` et une **composition root** dans `pipeline/run.py`. Aucun singleton global n'est autorisé. Le `PipelineRunner` reçoit toutes ses dépendances via **injection par constructeur** : `PronoteFetcher`, `CalDAVClient`, `AgendaComparator`, `SynthesisProvider`, `Channel`. +| Variable | Description | Valeur par défaut | Type | +|----------|-------------|--------------------|------| +| `BLOG_ENABLED` | Activer la synchronisation du blog | `false` | bool | +| `BLOG_RSS_URL` | URL du flux RSS du blog | `https://blogpeda.ac-bordeaux.fr/cjeliote/?feed=rss2` | str | -## Sources de données +## Divers -Les modes de source sont les suivants : +| Variable | Description | Valeur par défaut | Type | +|----------|-------------|--------------------|------| +| `DRY_RUN` | Mode simulation (pas d'écriture) | `false` | bool | +| `LOG_LEVEL` | Niveau de log | `INFO` | str | -- `auto` : essaie d'abord iCal, puis bascule vers `pronotepy` **uniquement** si iCal lève une exception. -- `ical` : utilise **uniquement** iCal, sans bascule silencieuse. -- `pronotepy` : utilise **uniquement** `pronotepy`, sans bascule silencieuse. -- En mode `auto`, si iCal **et** `pronotepy` échouent → erreur critique explicite. -- Une liste vide est un **succès valide**, pas une panne. -- `PRONOTE_URL` (connexion API) et `PRONOTE_ICAL_URL` (flux iCal) sont deux paramètres **distincts**. -- Les messages ne sont disponibles que via `pronotepy` (absents du flux iCal). +## Fichier .env -## Flux de données +Pour créer votre fichier de configuration : -Le flux de données suit ce chemin : données brutes (iCal/`pronotepy`) → modèles Pydantic (`Lesson`, `Homework`, `Message`, etc.) → `PronoteData` (agrégé) → `AgendaDiff` (comparaison) → `CalDavSyncResult` → `SynthesisInput`/`SynthesisResult` → `XmppMessage` → envoi via le canal XMPP. \ No newline at end of file +```bash +cp .env.example .env +# Éditer .env avec vos paramètres +``` + +> **Rappel** : Le fichier `.env` n'est **jamais** versionné. Utilisez `.env.example` comme modèle. + +Voir aussi : [Sécurité](Sécurité) pour la gestion des secrets, [Déploiement](Déploiement) pour la configuration en production. \ No newline at end of file