diff --git a/api/routes_admin.py b/api/routes_admin.py index 9bafe2e..420e8c5 100644 --- a/api/routes_admin.py +++ b/api/routes_admin.py @@ -681,12 +681,13 @@ class AdminPresenceOverrideConsequenceRequest(BaseModel): ``is_present`` bool are enforced by the SAME :class:`~nestquest_core.presence.PresenceOverride` constructor the create route's core path builds; this model only guards the SHAPE. + Strict fields: a JSON ``true`` is not child id 1, nor ``1`` a bool. """ - child_id: int + child_id: StrictInt start_date: str end_date: str - is_present: bool + is_present: StrictBool class AdminPresenceOverrideConsequenceResponse(BaseModel): diff --git a/tests/test_api_admin_presence_consequence.py b/tests/test_api_admin_presence_consequence.py index 4c0ae76..4bdaac4 100644 --- a/tests/test_api_admin_presence_consequence.py +++ b/tests/test_api_admin_presence_consequence.py @@ -371,6 +371,42 @@ async def test_malformed_range_or_status_is_422( assert response.status_code == 422 +@pytest.mark.parametrize( + "overrides", + [ + {"child_id": True}, + {"child_id": False}, + {"child_id": "1"}, + {"child_id": 1.0}, + {"is_present": 1}, + {"is_present": 0}, + {"is_present": "true"}, + {"is_present": "false"}, + ], +) +async def test_coercible_child_id_or_status_is_422( + custody: SimpleNamespace, overrides: dict[str, object] +) -> None: + """Strict fields: a bool id or a numeric/string status is rejected. + + The fixture child's id is 1, so a coerced ``true`` would otherwise + target it and return 200. Nothing is stored and nothing removed. + """ + assert custody.child_id == 1 + database = custody.database + before = await _open_future_keys(database, custody.child_id) + body = {**_body(custody.child_id, 0, 14), **overrides} + response = await custody.client.post( + CONSEQUENCE_URL, json=body, headers=_admin_headers() + ) + assert response.status_code == 422 + assert await _open_future_keys(database, custody.child_id) == before + overrides_stored = await _dao_presence.PresenceOverridesDao( + database + ).list_by_child_and_range(custody.child_id, "2000-01-01", "2100-01-01") + assert overrides_stored == [] + + # --- authentication: the router's ONE require_admin --------------------------