fix(tags): case-insensitive kind prefix + (Fandom) suffix rescue on add

parse_kind_prefix now lowercases the prefix before checking KNOWN_KINDS,
matching the modal JS which already lowercases before its visibility
check. Without this, typing 'Character:Jinx ...' showed the fandom
picker but the server fell back to kind=user.

Both /tags/add and /api/images/bulk-add-tag now also split a trailing
'(Fandom)' suffix from a typed character name when no explicit fandom
is staged, so a manual entry like 'Character:Jinx (League Of Legends)'
produces a clean (name='Jinx', fandom_id=<league>) row instead of a
malformed character with the suffix baked into the name.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-25 14:23:43 -04:00
parent 007592827c
commit 667a70acb9
2 changed files with 31 additions and 2 deletions
+9 -2
View File
@@ -25,6 +25,11 @@ KNOWN_KINDS: frozenset[str] = frozenset({
def parse_kind_prefix(raw: str) -> tuple[str | None, str]:
"""Split a raw user-typed tag string into (kind, name).
The kind prefix is matched case-insensitively so 'Character:' and
'CHARACTER:' resolve the same as 'character:'. The returned kind is
always lowercase canonical form. The modal JS already lowercases
before its own prefix check; this keeps the server in sync.
Returns:
(kind, name) where kind is one of KNOWN_KINDS, or
(None, raw.strip()) if no recognized prefix is present.
@@ -32,12 +37,14 @@ def parse_kind_prefix(raw: str) -> tuple[str | None, str]:
Examples:
parse_kind_prefix('character:Saber') -> ('character', 'Saber')
parse_kind_prefix('Character:Saber') -> ('character', 'Saber')
parse_kind_prefix('sunset') -> (None, 'sunset')
parse_kind_prefix('http://example') -> (None, 'http://example')
parse_kind_prefix('artist: Eric ') -> ('artist', 'Eric')
"""
if ':' in raw:
prefix, rest = raw.split(':', 1)
if prefix in KNOWN_KINDS:
return prefix, rest.strip()
prefix_lower = prefix.lower()
if prefix_lower in KNOWN_KINDS:
return prefix_lower, rest.strip()
return None, raw.strip()