fix: close library upload flow and harden image storage
Community checks / verify (push) Skipped
Verify Frame Flow / verify (push) Successful in 8m9s

This commit is contained in:
渡口浪人
2026-10-24 00:38:00 +08:00
parent 0859871363
commit 1494904b12
39 changed files with 1471 additions and 240 deletions
+14 -19
View File
@@ -425,7 +425,9 @@ def create_app(settings=None, start_worker=True):
from PIL import Image
try:
with Image.open(BytesIO(data)) as source:
with Image.open(
BytesIO(data), formats=("JPEG", "PNG", "WEBP")
) as source:
if source.width * source.height > 25_000_000:
raise ValueError()
if source.format not in {"JPEG", "PNG", "WEBP"}:
@@ -438,13 +440,13 @@ def create_app(settings=None, start_worker=True):
thumb = cached.with_name(cached.stem + "-thumb.jpg")
from PIL import Image
with Image.open(cached) as img:
with Image.open(cached, formats=("JPEG", "PNG", "WEBP")) as img:
# The 430px cards need up to 860px on 2x displays. Replace the
# existing cache in place so old 300px previews are upgraded.
expected_edge = min(860, max(img.size))
regenerate = not thumb.exists()
if not regenerate:
with Image.open(thumb) as existing:
with Image.open(thumb, formats=("JPEG", "PNG", "WEBP")) as existing:
regenerate = max(existing.size) != expected_edge
if regenerate:
img.thumbnail((860, 860), Image.Resampling.LANCZOS)
@@ -452,7 +454,7 @@ def create_app(settings=None, start_worker=True):
return FileResponse(thumb, media_type="image/jpeg")
from PIL import Image
with Image.open(cached) as original:
with Image.open(cached, formats=("JPEG", "PNG", "WEBP")) as original:
media_type = Image.MIME.get(
original.format or "", "application/octet-stream"
)
@@ -575,15 +577,15 @@ def create_app(settings=None, start_worker=True):
if len(data) > settings.max_bytes:
raise FlowError(E.INVALID_REQUEST, "Image exceeds 20 MiB")
name = Path(file.filename or "image").name[:120]
asset = assets.put(
with assets.creating(
await run_in_threadpool(convert, data, fit, profile),
settings.sanitize(name),
kind="cache",
)
db.execute(
"INSERT INTO asset_metadata(asset_id,origin) VALUES(?,?)",
(asset["asset_id"], "manual"),
)
) as asset:
db.execute(
"INSERT INTO asset_metadata(asset_id,origin) VALUES(?,?)",
(asset["asset_id"], "manual"),
)
return assets.info(asset["asset_id"])
@app.get(
@@ -620,7 +622,7 @@ def create_app(settings=None, start_worker=True):
dependencies=[Depends(require("images:delete"))],
)
def delete_asset(asset_id: str):
path = assets.path(asset_id)
assets.path(asset_id)
if db.one(
"SELECT id FROM assets WHERE id=? AND kind IN ('source-images','renditions')",
(asset_id,),
@@ -645,14 +647,7 @@ def create_app(settings=None, start_worker=True):
"Asset is referenced by a task, template or pending operation",
409,
)
path.unlink(missing_ok=True)
db.execute(
"DELETE FROM photo_preferences WHERE source_id='@assets' AND item_id=?",
(asset_id,),
)
db.execute("DELETE FROM asset_metadata WHERE asset_id=?", (asset_id,))
db.execute("DELETE FROM asset_sources WHERE asset_id=?", (asset_id,))
db.execute("DELETE FROM assets WHERE id=?", (asset_id,))
service.libraries.remove_asset(asset_id)
for row in db.all(
"SELECT key,payload FROM app_config WHERE key LIKE 'wrist-thumbnail:%'"
):