fix(config): refuser les fenêtres de synchronisation négatives
Contraint SYNC_PAST_DAYS et SYNC_FUTURE_DAYS à ge=0 et documente l'effet réel de 0 jour (le jour courant reste inclus). Refs #14
This commit is contained in:
+1
-1
@@ -32,7 +32,7 @@ CALDAV_CALENDAR_PATH=/pronote-sync/
|
|||||||
# Autoriser HTTP (non-HTTPS) pour un serveur CalDAV local (localhost uniquement)
|
# Autoriser HTTP (non-HTTPS) pour un serveur CalDAV local (localhost uniquement)
|
||||||
CALDAV_ALLOW_INSECURE_HTTP=false
|
CALDAV_ALLOW_INSECURE_HTTP=false
|
||||||
|
|
||||||
# Fenêtre de synchronisation (jours)
|
# Fenêtre de synchronisation (jours) — entier >= 0 ; 0 = aucune journée supplémentaire de ce côté (le jour courant reste inclus). Valeurs négatives refusées au chargement (ValidationError).
|
||||||
SYNC_PAST_DAYS=7
|
SYNC_PAST_DAYS=7
|
||||||
SYNC_FUTURE_DAYS=30
|
SYNC_FUTURE_DAYS=30
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -299,8 +299,8 @@ d'un besoin réel et testé.
|
|||||||
| `PRONOTE_AGENDA_SOURCE` | Source pour l'agenda (`auto`, `ical`, `pronotepy`). | `auto` | `Literal` |
|
| `PRONOTE_AGENDA_SOURCE` | Source pour l'agenda (`auto`, `ical`, `pronotepy`). | `auto` | `Literal` |
|
||||||
| `PRONOTE_HOMEWORK_SOURCE` | Source pour les devoirs (`auto`, `ical`, `pronotepy`). | `auto` | `Literal` |
|
| `PRONOTE_HOMEWORK_SOURCE` | Source pour les devoirs (`auto`, `ical`, `pronotepy`). | `auto` | `Literal` |
|
||||||
| `PRONOTE_MESSAGES_SOURCE` | Source pour les messages (`pronotepy` uniquement). | `pronotepy` | `Literal` |
|
| `PRONOTE_MESSAGES_SOURCE` | Source pour les messages (`pronotepy` uniquement). | `pronotepy` | `Literal` |
|
||||||
| `SYNC_PAST_DAYS` | Nombre de jours dans le passé pour la sync CalDAV. | `7` | `int` |
|
| `SYNC_PAST_DAYS` | Nombre de jours dans le passé pour la sync CalDAV, entier `>= 0` (`0` = aucune journée supplémentaire de ce côté ; le jour courant reste inclus). | `7` | `int` |
|
||||||
| `SYNC_FUTURE_DAYS` | Nombre de jours dans le futur pour la sync CalDAV. | `30` | `int` |
|
| `SYNC_FUTURE_DAYS` | Nombre de jours dans le futur pour la sync CalDAV, entier `>= 0` (`0` = aucune journée supplémentaire de ce côté ; le jour courant reste inclus). | `30` | `int` |
|
||||||
| `THEORETICAL_AGENDA_PATH` | Chemin vers le fichier JSON de l'agenda théorique. | `None` | `str \| None`|
|
| `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`|
|
| `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 (paire/impaire). | `None` | `date \| None`|
|
| `THEORETICAL_WEEK_ANCHOR_DATE` | Date de référence pour la parité des semaines (paire/impaire). | `None` | `date \| None`|
|
||||||
@@ -421,8 +421,8 @@ class CalDAVSettings(BaseSettings):
|
|||||||
password: SecretStr | None = None
|
password: SecretStr | None = None
|
||||||
calendar_path: str = "/pronote-sync/"
|
calendar_path: str = "/pronote-sync/"
|
||||||
allow_insecure_http: bool = False
|
allow_insecure_http: bool = False
|
||||||
sync_past_days: int = 7
|
sync_past_days: int = Field(default=7, ge=0)
|
||||||
sync_future_days: int = 30
|
sync_future_days: int = Field(default=30, ge=0)
|
||||||
|
|
||||||
|
|
||||||
class AISettings(BaseSettings):
|
class AISettings(BaseSettings):
|
||||||
|
|||||||
@@ -293,8 +293,8 @@ class AppSettings(BaseSettings):
|
|||||||
school_holidays_path: str | None = None
|
school_holidays_path: str | None = None
|
||||||
theoretical_week_anchor_date: date | None = None
|
theoretical_week_anchor_date: date | None = None
|
||||||
theoretical_week_anchor_type: Literal["even", "odd"] | None = None
|
theoretical_week_anchor_type: Literal["even", "odd"] | None = None
|
||||||
sync_past_days: int = 7
|
sync_past_days: int = Field(default=7, ge=0)
|
||||||
sync_future_days: int = 30
|
sync_future_days: int = Field(default=30, ge=0)
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
|
|||||||
+120
-3
@@ -10,10 +10,10 @@ from __future__ import annotations
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from pydantic import SecretStr
|
from pydantic import SecretStr, ValidationError
|
||||||
|
|
||||||
from pronote_sync.config.env import load_settings
|
from pronote_sync.config.env import load_settings
|
||||||
from pronote_sync.config.settings import PronoteSettings, Settings
|
from pronote_sync.config.settings import AppSettings, PronoteSettings, Settings
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from _pytest.monkeypatch import MonkeyPatch
|
from _pytest.monkeypatch import MonkeyPatch
|
||||||
@@ -207,4 +207,121 @@ def test_qr_pin_in_redaction_secrets(monkeypatch: MonkeyPatch) -> None:
|
|||||||
assert "**********" in repr(settings.pronote.qr_pin)
|
assert "**********" in repr(settings.pronote.qr_pin)
|
||||||
|
|
||||||
|
|
||||||
# Ensure trailing newline
|
def test_sync_past_days_negative_direct_instantiation() -> None:
|
||||||
|
"""Vérifie que ``sync_past_days`` négatif lève ``ValidationError`` à l'instanciation.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
AppSettings(sync_past_days=-1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_sync_future_days_negative_direct_instantiation() -> None:
|
||||||
|
"""Vérifie que ``sync_future_days`` négatif lève ``ValidationError`` à l'instanciation.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
AppSettings(sync_future_days=-1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_sync_past_days_zero_accepted() -> None:
|
||||||
|
"""Vérifie que ``sync_past_days=0`` est accepté.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
settings = AppSettings(sync_past_days=0)
|
||||||
|
assert settings.sync_past_days == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_sync_future_days_zero_accepted() -> None:
|
||||||
|
"""Vérifie que ``sync_future_days=0`` est accepté.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
settings = AppSettings(sync_future_days=0)
|
||||||
|
assert settings.sync_future_days == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_sync_past_days_positive_accepted() -> None:
|
||||||
|
"""Vérifie que ``sync_past_days`` positif est accepté.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
settings = AppSettings(sync_past_days=7)
|
||||||
|
assert settings.sync_past_days == 7
|
||||||
|
|
||||||
|
|
||||||
|
def test_sync_future_days_positive_accepted() -> None:
|
||||||
|
"""Vérifie que ``sync_future_days`` positif est accepté.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
settings = AppSettings(sync_future_days=30)
|
||||||
|
assert settings.sync_future_days == 30
|
||||||
|
|
||||||
|
|
||||||
|
def test_sync_past_days_negative_env_loading(monkeypatch: MonkeyPatch) -> None:
|
||||||
|
"""Vérifie que ``SYNC_PAST_DAYS=-1`` lève ``ValidationError`` via chargement env.
|
||||||
|
|
||||||
|
:param monkeypatch: Fixture pytest pour modifier temporairement l'environnement.
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
monkeypatch.setenv("SYNC_PAST_DAYS", "-1")
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
load_settings()
|
||||||
|
|
||||||
|
|
||||||
|
def test_sync_future_days_negative_env_loading(monkeypatch: MonkeyPatch) -> None:
|
||||||
|
"""Vérifie que ``SYNC_FUTURE_DAYS=-1`` lève ``ValidationError`` via chargement env.
|
||||||
|
|
||||||
|
:param monkeypatch: Fixture pytest pour modifier temporairement l'environnement.
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
monkeypatch.setenv("SYNC_FUTURE_DAYS", "-1")
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
load_settings()
|
||||||
|
|
||||||
|
|
||||||
|
def test_sync_past_days_zero_env_loading(monkeypatch: MonkeyPatch) -> None:
|
||||||
|
"""Vérifie que ``SYNC_PAST_DAYS=0`` est accepté via chargement env.
|
||||||
|
|
||||||
|
:param monkeypatch: Fixture pytest pour modifier temporairement l'environnement.
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
monkeypatch.setenv("SYNC_PAST_DAYS", "0")
|
||||||
|
settings = load_settings()
|
||||||
|
assert settings.app.sync_past_days == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_sync_future_days_zero_env_loading(monkeypatch: MonkeyPatch) -> None:
|
||||||
|
"""Vérifie que ``SYNC_FUTURE_DAYS=0`` est accepté via chargement env.
|
||||||
|
|
||||||
|
:param monkeypatch: Fixture pytest pour modifier temporairement l'environnement.
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
monkeypatch.setenv("SYNC_FUTURE_DAYS", "0")
|
||||||
|
settings = load_settings()
|
||||||
|
assert settings.app.sync_future_days == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_sync_past_days_positive_env_loading(monkeypatch: MonkeyPatch) -> None:
|
||||||
|
"""Vérifie que ``SYNC_PAST_DAYS`` positif est accepté via chargement env.
|
||||||
|
|
||||||
|
:param monkeypatch: Fixture pytest pour modifier temporairement l'environnement.
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
monkeypatch.setenv("SYNC_PAST_DAYS", "7")
|
||||||
|
settings = load_settings()
|
||||||
|
assert settings.app.sync_past_days == 7
|
||||||
|
|
||||||
|
|
||||||
|
def test_sync_future_days_positive_env_loading(monkeypatch: MonkeyPatch) -> None:
|
||||||
|
"""Vérifie que ``SYNC_FUTURE_DAYS`` positif est accepté via chargement env.
|
||||||
|
|
||||||
|
:param monkeypatch: Fixture pytest pour modifier temporairement l'environnement.
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
monkeypatch.setenv("SYNC_FUTURE_DAYS", "30")
|
||||||
|
settings = load_settings()
|
||||||
|
assert settings.app.sync_future_days == 30
|
||||||
|
|||||||
Reference in New Issue
Block a user