Files
bvandeusen 013b9d7f06
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 21s
CI / backend-lint-and-test (push) Successful in 28s
CI / integration (push) Failing after 3m17s
feat(series): operator-set sparse page numbers + gap blocks (#789 tweak)
Replaces the auto-renumbered 1..N position key with operator-OWNED page
numbers: sparse, gaps allowed, editable, never auto-renumbered. Order follows
the numbers; unnumbered pages sort to the tail. This is the fix for the model
that clobbered hand-set numbers on the flatten — numbers are now data, not a
derived sequence.

- series_service: drop the renumber-on-reorder/remove; order by page_number
  NULLS LAST; new set_page_number(image_id, n|None); list_pages returns `gaps`
  (one entry per missing-number run) + each pending group's parsed `start_page`;
  set_cover renumbers below the current min; place_pending(image_ids, start_page)
  numbers placed pages sequentially from the start (drop junk first → numbers
  line up); add_post stamps the parsed start on staged pages.
- api/tags: POST /series/<id>/pages/number (set one page's number); /pending/
  place takes start_page; removed /reorder.
- frontend: per-card editable number input; one gap block per gap with
  drop-on-edge to assign the adjacent number (middle → type); append drop zone;
  pending tray gets a "from page N" field + "Place from page N".
- tests reworked: sparse numbers + gaps, place-from-start, set-page-number route.

No migration; nothing destructive.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 23:10:30 -04:00

60 lines
1.7 KiB
Python

import pytest
pytestmark = pytest.mark.integration
async def _series(client, name="Vol"):
r = await client.post("/api/tags", json={"name": name, "kind": "series"})
return (await r.get_json())["id"]
@pytest.mark.asyncio
async def test_pages_404_for_non_series(client):
r = await client.post("/api/tags", json={"name": "g", "kind": "general"})
gid = (await r.get_json())["id"]
resp = await client.get(f"/api/series/{gid}/pages")
assert resp.status_code == 404
@pytest.mark.asyncio
async def test_pages_empty_shape(client):
sid = await _series(client, "Empty")
resp = await client.get(f"/api/series/{sid}/pages")
assert resp.status_code == 200
body = await resp.get_json()
assert body["series"]["id"] == sid
assert body["pages"] == []
@pytest.mark.asyncio
async def test_add_requires_ids(client):
sid = await _series(client, "NoIds")
resp = await client.post(f"/api/series/{sid}/pages", json={})
assert resp.status_code == 400
@pytest.mark.asyncio
async def test_add_over_cap_400(client):
sid = await _series(client, "Cap")
resp = await client.post(
f"/api/series/{sid}/pages",
json={"image_ids": list(range(1, 502))},
)
assert resp.status_code == 400
@pytest.mark.asyncio
async def test_set_page_number_requires_image_id(client):
sid = await _series(client, "Num")
resp = await client.post(
f"/api/series/{sid}/pages/number", json={"page_number": 5}
)
assert resp.status_code == 400
@pytest.mark.asyncio
async def test_cover_requires_image_id(client):
sid = await _series(client, "Cov")
resp = await client.post(f"/api/series/{sid}/cover", json={})
assert resp.status_code == 400