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
+50 -3
View File
@@ -1,4 +1,6 @@
from fastapi import Depends, Query, Request
import hashlib
from fastapi import Depends, File, Query, Request, UploadFile
from fastapi.responses import Response
from pydantic import Field
@@ -8,6 +10,7 @@ from pigway_frame_flow.display.libraries import GenerationPlan
from pigway_frame_flow.errors import ErrorCode as E
from pigway_frame_flow.errors import FlowError
from pigway_frame_flow.models import ImageExclusion, ImageStar, StrictModel
from pigway_frame_flow.providers.photo_sources import PhotoSourceInput
from pigway_frame_flow.providers.source_browser import BrowseFilters
@@ -16,6 +19,10 @@ class BindingInput(StrictModel):
plan_id: str = Field(pattern=r"^[a-f0-9]{32}$")
class UploadURLInput(StrictModel):
url: str = Field(min_length=1, max_length=2048)
class ImportInput(StrictModel):
item_id: str = Field(min_length=1, max_length=2048)
@@ -56,6 +63,46 @@ def install_libraries(app, service):
for source in service.photo_sources.list()
]
def save_upload(source_id, data, name):
if len(data) > service.settings.max_bytes:
raise FlowError(E.INVALID_REQUEST, "Image exceeds size limit")
with service.lock:
if source_id == "manual-uploads" and not db.one(
"SELECT key FROM app_config WHERE key='photo_source:manual-uploads'"
):
from pigway_frame_flow.renderers.images import convert
convert(data, size=(1, 1))
service.photo_sources.save(
source_id,
PhotoSourceInput(name="手动上传", kind="uploads", location="."),
)
if not service.photo_sources.get(source_id).enabled:
raise FlowError(E.CONFLICT, "Photo source is disabled", 409)
return libraries.ingest(
source_id, "upload:" + hashlib.sha256(data).hexdigest(), data, name, {}
)
@app.post(
"/api/v1/source-libraries/{source_id}/upload",
dependencies=[Depends(require("images:write"))],
)
def upload(source_id: str, file: UploadFile = File(...)):
return save_upload(
source_id,
file.file.read(service.settings.max_bytes + 1),
file.filename or "upload.jpg",
)
@app.post(
"/api/v1/source-libraries/{source_id}/upload-url",
dependencies=[Depends(require("images:write"))],
)
def upload_url(source_id: str, payload: UploadURLInput):
return save_upload(
source_id, service.assets.fetch_url(payload.url), "url-upload.jpg"
)
@app.get(
"/api/v1/source-libraries/{source_id}/images",
dependencies=[Depends(require("images:read"))],
@@ -183,7 +230,7 @@ def install_libraries(app, service):
@app.put(
"/api/v1/source-images/{picture_id}/star",
dependencies=[Depends(require("admin"))],
dependencies=[Depends(require("images:write"))],
)
def star(picture_id: str, payload: ImageStar):
picture = libraries.picture(picture_id)
@@ -193,7 +240,7 @@ def install_libraries(app, service):
@app.put(
"/api/v1/source-images/{picture_id}/exclusion",
dependencies=[Depends(require("admin"))],
dependencies=[Depends(require("images:write"))],
)
def exclude(picture_id: str, payload: ImageExclusion):
picture = libraries.picture(picture_id)