diff --git a/api/routes_admin.py b/api/routes_admin.py index 419658a..b70e8eb 100644 --- a/api/routes_admin.py +++ b/api/routes_admin.py @@ -623,15 +623,16 @@ class AdminPresencePatternCreateRequest(BaseModel): covers that week (Monday=0); every week of the cycle must be covered, which the PRESENCE MODEL enforces at construction, not this shape — as it does the non-blank ``name`` and the - ``home``/``away`` ``kind``. ``cycle_length_weeks`` is a strict - JSON integer: ``2.0`` or ``"2"`` is a 422, not a silent coercion. + ``home``/``away`` ``kind``. ``cycle_length_weeks`` and the weekday + values are strict JSON integers: ``2.0``, ``"2"`` or ``true`` is a + 422, not a silent coercion. """ name: str kind: str cycle_length_weeks: StrictInt anchor_date: str - pattern: dict[int, list[int]] + pattern: dict[int, list[StrictInt]] class AdminPresencePatternEditRequest(BaseModel): @@ -646,7 +647,7 @@ class AdminPresencePatternEditRequest(BaseModel): kind: str | None = None cycle_length_weeks: StrictInt | None = None anchor_date: str | None = None - pattern: dict[int, list[int]] | None = None + pattern: dict[int, list[StrictInt]] | None = None class AdminPresencePatternResponse(BaseModel): diff --git a/tests/test_api_admin_presence.py b/tests/test_api_admin_presence.py index 84f7b95..5ce5590 100644 --- a/tests/test_api_admin_presence.py +++ b/tests/test_api_admin_presence.py @@ -690,6 +690,12 @@ async def test_pattern_patch_unknown_id_is_404( ({"anchor_date": None}, "anchor_date"), ({"pattern": {}}, "pattern"), ({"pattern": None}, "pattern"), + ({"pattern": {"0": [7]}}, "pattern"), # weekday out of 0..6 + # Strict JSON integer weekdays: no bool, string or float coercion. + ({"pattern": {"0": [True]}}, "pattern"), + ({"pattern": {"0": [False]}}, "pattern"), + ({"pattern": {"0": ["1"]}}, "pattern"), + ({"pattern": {"0": [1.0]}}, "pattern"), ], ) async def test_rejected_pattern_patch_is_422_and_changes_nothing( @@ -882,6 +888,11 @@ async def test_pattern_and_override_for_unknown_child_are_404( (_pattern_body(anchor_date="2026-13-40"), "anchor_date"), (_pattern_body(anchor_date="05/01/2026"), "anchor_date"), (_pattern_body(pattern={"0": [7]}), "pattern"), # weekday out of 0..6 + # Strict JSON integer weekdays: no bool, string or float coercion. + (_pattern_body(pattern={"0": [True]}), "pattern"), + (_pattern_body(pattern={"0": [False]}), "pattern"), + (_pattern_body(pattern={"0": ["1"]}), "pattern"), + (_pattern_body(pattern={"0": [1.0]}), "pattern"), (_pattern_body(pattern={"nope": [0]}), "pattern"), # non-int week (_pattern_body(pattern={"0": "0,2,4"}), "pattern"), # not a list (_pattern_body(kind="sometimes"), "kind"),