From 93b6fc21c86f80ca0e6c20215810a6fdf27e6458 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sat, 16 May 2026 15:51:27 -0400 Subject: [PATCH] =?UTF-8?q?fix(tags):=20invalid=20'copyright'=20kind=20500?= =?UTF-8?q?=20=E2=80=94=20KINDS=20uses=20real=20enum=20'fandom';=20directo?= =?UTF-8?q?ry=20400s=20on=20bad=20kind?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- backend/app/api/tags.py | 2 ++ frontend/src/views/TagsView.vue | 5 ++++- tests/test_api_tags_directory.py | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/backend/app/api/tags.py b/backend/app/api/tags.py index fbe746f..d477ea9 100644 --- a/backend/app/api/tags.py +++ b/backend/app/api/tags.py @@ -56,6 +56,8 @@ async def autocomplete(): @tags_bp.route("/tags/directory", methods=["GET"]) async def directory(): kind = request.args.get("kind") or None + if kind is not None and _coerce_kind(kind) is None: + return jsonify({"error": f"invalid kind {kind!r}"}), 400 q = request.args.get("q") or None cursor = request.args.get("cursor") or None try: diff --git a/frontend/src/views/TagsView.vue b/frontend/src/views/TagsView.vue index 8381763..a1ce81f 100644 --- a/frontend/src/views/TagsView.vue +++ b/frontend/src/views/TagsView.vue @@ -51,7 +51,10 @@ import { useTagDirectoryStore } from '../stores/tagDirectory.js' import TagCard from '../components/discovery/TagCard.vue' import MergeConfirmDialog from '../components/discovery/MergeConfirmDialog.vue' -const KINDS = ['artist', 'character', 'copyright', 'general', 'series', 'meta'] +// Must stay a subset of the backend TagKind enum (artist, character, +// fandom, general, series, archive, post, meta, rating). 'fandom' is this +// model's copyright/franchise concept (characters link via fandom_id). +const KINDS = ['artist', 'character', 'fandom', 'general', 'series', 'meta'] const store = useTagDirectoryStore() const router = useRouter() diff --git a/tests/test_api_tags_directory.py b/tests/test_api_tags_directory.py index de9c01e..1865482 100644 --- a/tests/test_api_tags_directory.py +++ b/tests/test_api_tags_directory.py @@ -28,3 +28,22 @@ async def test_directory_endpoint(client, db): async def test_directory_bad_limit(client): resp = await client.get("/api/tags/directory?limit=nan") assert resp.status_code == 400 + + +@pytest.mark.asyncio +async def test_directory_invalid_kind_is_400_not_500(client): + # 'copyright' is not a TagKind member; the route must reject it + # cleanly (400) instead of letting the enum cast 500. + resp = await client.get("/api/tags/directory?kind=copyright") + assert resp.status_code == 400 + + +@pytest.mark.asyncio +async def test_directory_valid_kind_ok(client, db): + db.add(Tag(name="a_fandom", kind=TagKind.fandom)) + await db.flush() + await db.commit() + resp = await client.get("/api/tags/directory?kind=fandom&limit=10") + assert resp.status_code == 200 + body = await resp.get_json() + assert any(c["name"] == "a_fandom" for c in body["cards"])