fix: gallery tag filters and tag-cleanup are empty in single-user mode (#1771)

This commit is contained in:
Afonso Coutinho
2026-06-03 05:23:08 +01:00
committed by GitHub
parent d25a860f71
commit bde5f6adb3
2 changed files with 66 additions and 2 deletions

View File

@@ -110,9 +110,17 @@ def _image_to_dict(img: GalleryImage, session_name: str = None) -> Dict[str, Any
def _owner_filter(q, user): def _owner_filter(q, user):
"""Apply owner filtering to a gallery query.""" """Apply owner filtering to a gallery query.
When auth is disabled (single-user mode) get_current_user returns None
and there is no per-user scoping. The main library list and stats already
treat None as "show everything" (`if user is not None`), so this helper
must too — otherwise the tag/model filter sidebars come back empty and the
tag-cleanup endpoints (clear-user-tags, clear-ai-tags, dedupe-tags)
silently affect zero rows in the most common self-hosted deployment.
"""
if user is None: if user is None:
return q.filter(False) return q
return q.filter(GalleryImage.owner == user) return q.filter(GalleryImage.owner == user)

View File

@@ -0,0 +1,56 @@
"""_owner_filter must not blank out the gallery in single-user mode.
When AUTH_ENABLED=false, get_current_user returns None. The gallery main
list and stats treat None as "show all images" (`if user is not None`), but
_owner_filter returned q.filter(False) (zero rows) for None. So the tag and
model filter chips were always empty and clear-user-tags / clear-ai-tags /
dedupe-tags silently no-oped. _owner_filter must match the main list: no
filter when user is None, owner-scoped otherwise.
"""
import tempfile
import uuid
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import NullPool
import core.database as cdb
from core.database import GalleryImage
from routes.gallery_helpers import _owner_filter
_TMPDB = tempfile.NamedTemporaryFile(suffix=".db", delete=False)
_ENGINE = create_engine(f"sqlite:///{_TMPDB.name}", connect_args={"check_same_thread": False}, poolclass=NullPool)
cdb.Base.metadata.create_all(_ENGINE)
_TS = sessionmaker(bind=_ENGINE, autoflush=False, autocommit=False)
def _seed(*owners):
db = _TS()
try:
db.query(GalleryImage).delete()
for o in owners:
db.add(GalleryImage(id=str(uuid.uuid4()), filename=f"{uuid.uuid4().hex}.png", owner=o))
db.commit()
finally:
db.close()
def test_none_user_returns_all_rows():
_seed(None, None, "alice")
db = _TS()
try:
n = _owner_filter(db.query(GalleryImage), None).count()
assert n == 3 # old code returned 0
finally:
db.close()
def test_named_user_is_still_scoped():
_seed("alice", "alice", "bob", None)
db = _TS()
try:
assert _owner_filter(db.query(GalleryImage), "alice").count() == 2
assert _owner_filter(db.query(GalleryImage), "bob").count() == 1
finally:
db.close()