"""FC-6.x — promote a post to a series + add a post's pages + browse list.""" import pytest from sqlalchemy import select from backend.app.models import Artist, ImageRecord, Post, TagKind from backend.app.models.series_page import SeriesPage from backend.app.services.series_service import SeriesError, SeriesService from backend.app.services.tag_service import TagService pytestmark = pytest.mark.integration _SEQ = 0 async def _artist(db, name): a = Artist(name=name, slug=name.lower().replace(" ", "-")) db.add(a) await db.flush() return a async def _post(db, artist, title, ext): p = Post(artist_id=artist.id, external_post_id=ext, post_title=title) db.add(p) await db.flush() return p async def _post_images(db, post, artist, n): global _SEQ ids = [] for _ in range(n): _SEQ += 1 rec = ImageRecord( path=f"/tmp/fc_ps_{_SEQ}.png", sha256=f"{_SEQ:064d}", size_bytes=1, mime="image/png", origin="downloaded", primary_post_id=post.id, artist_id=artist.id, ) db.add(rec) await db.flush() ids.append(rec.id) return ids @pytest.mark.asyncio async def test_promote_post_to_series(db): svc = SeriesService(db) artist = await _artist(db, "Bikupan") post = await _post(db, artist, "My Comic pages 1-3", "pp1") imgs = await _post_images(db, post, artist, 3) out = await svc.promote_post_to_series(post.id) assert out["added"] == 3 assert out["name"] == "My Comic pages 1-3" data = await svc.list_pages(out["series_tag_id"]) # one flat run in capture order, no dividers, stated pages parsed 1..3 assert [p["image_id"] for p in data["pages"]] == imgs assert [p["stated_page"] for p in data["pages"]] == [1, 2, 3] assert data["dividers"] == [] @pytest.mark.asyncio async def test_promote_requires_images(db): svc = SeriesService(db) artist = await _artist(db, "Empty Artist") post = await _post(db, artist, "No images", "pp2") with pytest.raises(SeriesError): await svc.promote_post_to_series(post.id) @pytest.mark.asyncio async def test_add_post_stages_pending(db): svc = SeriesService(db) artist = await _artist(db, "Story Artist") sid = (await TagService(db).find_or_create("Story", TagKind.series)).id # Seed the series with two PLACED pages. seed_post = await _post(db, artist, "seed", "pp3a") seed = await _post_images(db, seed_post, artist, 2) await svc.add_images(sid, seed) # A later post is STAGED as pending — not in the placed run yet. post = await _post(db, artist, "Story pages 9-11", "pp3b") imgs = await _post_images(db, post, artist, 3) out = await svc.add_post(sid, post.id) assert out["staged"] == 3 data = await svc.list_pages(sid) # placed run unchanged (just the seed); pending grouped under the post. assert [p["image_id"] for p in data["pages"]] == seed assert len(data["pending"]) == 1 grp = data["pending"][0] assert grp["post"]["id"] == post.id assert grp["post"]["title"] == "Story pages 9-11" assert [pg["image_id"] for pg in grp["pages"]] == imgs # add_post stamps the post's parsed START (9) on every staged page; the # group surfaces it as start_page (the default for "Place from page N"). assert grp["start_page"] == 9 @pytest.mark.asyncio async def test_list_series_cards(db): svc = SeriesService(db) artist = await _artist(db, "Card Artist") post = await _post(db, artist, "Card Comic pages 1-2", "pp4") await _post_images(db, post, artist, 2) out = await svc.promote_post_to_series(post.id) rows = await svc.list_series() card = next(r for r in rows if r["id"] == out["series_tag_id"]) assert card["name"] == "Card Comic pages 1-2" assert card["chapter_count"] == 0 # a flat promote has no dividers assert card["page_count"] == 2 assert card["artist_name"] == "Card Artist" assert card["cover_thumbnail_url"] assert card["has_gap"] is False # artist filter keeps it; a different artist id drops it. assert any( r["id"] == out["series_tag_id"] for r in await svc.list_series(artist_id=artist.id) ) assert all( r["id"] != out["series_tag_id"] for r in await svc.list_series(artist_id=artist.id + 99999) ) @pytest.mark.asyncio async def test_source_post_label_is_per_page(db): svc = SeriesService(db) artist = await _artist(db, "Src Artist") post = await _post(db, artist, "Source Comic pages 1-2", "pp5") await _post_images(db, post, artist, 2) out = await svc.promote_post_to_series(post.id) data = await svc.list_pages(out["series_tag_id"]) sp = data["pages"][0]["source_post"] assert sp is not None assert sp["id"] == post.id assert sp["title"] == "Source Comic pages 1-2"