From bd78e1d5c2de715e7cffd2467ddde7159fcb5274 Mon Sep 17 00:00:00 2001 From: Tatlatat Date: Tue, 2 Jun 2026 18:35:57 +0700 Subject: [PATCH] Admin: wipe gallery albums with images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The /api/admin/wipe/gallery branch deleted GalleryImage rows but left every GalleryAlbum row behind (GalleryAlbum wasn't even imported). After "wipe gallery" the user is left with orphaned, empty albums whose cover_id points at now-deleted images — inconsistent with the other wipe branches, which clear both parent and child tables. Delete GalleryAlbum alongside GalleryImage and include both in the returned count. Adds tests/test_admin_wipe_gallery.py: seeds a real in-memory SQLite DB with an album + image, runs the actual wipe handler, and asserts both tables are emptied. Fails before this change (albums survive). --- routes/admin_wipe_routes.py | 4 ++- tests/test_admin_wipe_gallery.py | 57 ++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 tests/test_admin_wipe_gallery.py diff --git a/routes/admin_wipe_routes.py b/routes/admin_wipe_routes.py index 668b02d..01511c3 100644 --- a/routes/admin_wipe_routes.py +++ b/routes/admin_wipe_routes.py @@ -27,6 +27,7 @@ from core.database import ( Document, DocumentVersion, GalleryImage, + GalleryAlbum, CalendarEvent, CalendarCal, ) @@ -145,8 +146,9 @@ def setup_admin_wipe_routes(session_manager): return {"status": "deleted", "kind": kind, "count": count} if kind == "gallery": - count = db.query(GalleryImage).count() + count = db.query(GalleryImage).count() + db.query(GalleryAlbum).count() db.query(GalleryImage).delete() + db.query(GalleryAlbum).delete() db.commit() # Also drop the upload dir so disk doesn't keep orphans. _rmtree_quiet(os.path.join(DATA_DIR, "gallery")) diff --git a/tests/test_admin_wipe_gallery.py b/tests/test_admin_wipe_gallery.py new file mode 100644 index 0000000..ce062dd --- /dev/null +++ b/tests/test_admin_wipe_gallery.py @@ -0,0 +1,57 @@ +import pytest +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from core.database import Base, GalleryImage, GalleryAlbum +from routes.admin_wipe_routes import setup_admin_wipe_routes +from fastapi import Request + +def test_wipe_gallery_clears_albums(monkeypatch): + # 1. Create a clean in-memory database + engine = create_engine("sqlite:///:memory:") + Base.metadata.create_all(bind=engine) + + # 2. Create test session factory + TestSessionLocal = sessionmaker(bind=engine) + + # 3. Populate test database with an album and an image linked to it + db = TestSessionLocal() + album = GalleryAlbum(id="album-1", name="Trip to Rome") + image = GalleryImage(id="img-1", filename="rome1.jpg", album_id="album-1") + db.add(album) + db.add(image) + db.commit() + + assert db.query(GalleryImage).count() == 1 + assert db.query(GalleryAlbum).count() == 1 + db.close() + + # 4. Patch SessionLocal in routes/admin_wipe_routes.py to use our in-memory DB + import routes.admin_wipe_routes + monkeypatch.setattr(routes.admin_wipe_routes, "SessionLocal", TestSessionLocal) + + # Mock require_admin to bypass auth check (using standard pytest monkeypatch) + monkeypatch.setattr(routes.admin_wipe_routes, "require_admin", lambda r: None) + + # Construct a real FastAPI Request object + request = Request(scope={"type": "http"}) + + # 5. Initialize the router and retrieve the handler + router = setup_admin_wipe_routes(session_manager=None) + wipe_route = next(r for r in router.routes if r.path == "/api/admin/wipe/{kind}") + wipe_handler = wipe_route.endpoint + + # 6. Execute the wipe logic for gallery + result = wipe_handler(kind="gallery", request=request) + + # 7. Assertions + db = TestSessionLocal() + assert db.query(GalleryImage).count() == 0 + # This assertion will fail before the fix because GalleryAlbum rows were not deleted + assert db.query(GalleryAlbum).count() == 0 + + # Check returned stats + assert result["status"] == "deleted" + assert result["kind"] == "gallery" + assert result["count"] == 2 # 1 image + 1 album + + db.close()