fix(api): accept fractional progress seconds (R6 S1b code-review round 1)

/code-review high round 1 on S1b — 5 findings, 1 fixed, 4 by-design/deferred:
- FIXED: VideoProgressIn / ItemProgressIn position_seconds & duration_seconds
  typed `int` would 422 a raw float currentTime on the 10s progress checkpoint
  (the old `int(payload.get(...))` truncated it). Back to `float`, truncated in
  the handler; +test. The live frontend floors so this was latent, not live.
By-design / deferred (no change): the 422 detail-array isn't localized by the FE
(filed under R7); PATCH is-not-none (channels/quota, null-safe) vs model_fields_set
(nullable-clear) is a deliberate split; missing-field→422 is the point of the epic;
me/switch_account's numeric-string coercion is more correct and still session-gated.

Gate: ruff clean, pytest 172 green.
This commit is contained in:
2026-07-26 05:39:32 +02:00
parent b0894a9994
commit 81d21fdeac
3 changed files with 23 additions and 8 deletions
+10
View File
@@ -6,6 +6,7 @@ from pydantic import ValidationError
from app.routes.channels import AttachTagIn, ChannelUpdateIn
from app.routes.downloads import AdminSetQuotaIn
from app.routes.feed import VideoProgressIn
from app.routes.setup import SetupAdminIn
from app.routes.tags import TagUpdateIn
@@ -46,6 +47,15 @@ def test_admin_quota_rejects_non_numeric_limit():
AdminSetQuotaIn(max_bytes="lots")
def test_progress_accepts_fractional_seconds():
# The player may post a raw currentTime (a float). The field must accept it (truncated in the
# handler) — a plain `int` field would 422 on the progress hot path. (code-review round 1.)
assert VideoProgressIn(position_seconds=12.7).position_seconds == 12.7
assert int(VideoProgressIn(position_seconds=12.7).position_seconds) == 12
with pytest.raises(ValidationError):
VideoProgressIn(position_seconds="not-a-number")
# --- PATCH models: model_fields_set separates "absent" from "explicit null". ---
def test_tag_update_absent_vs_null_color():