013b9d7f06
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>
60 lines
1.7 KiB
Python
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
|