add image flow
This commit is contained in:
+72
-2
@@ -1,12 +1,13 @@
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from fastapi import Depends, FastAPI, Form, HTTPException, Request, status
|
||||
from fastapi.responses import RedirectResponse
|
||||
from fastapi import Depends, FastAPI, File, Form, HTTPException, Request, UploadFile, status
|
||||
from fastapi.responses import RedirectResponse, Response
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.db import get_db, init_db
|
||||
from app.images import process_upload
|
||||
from app.models import Box, Item, SubItem
|
||||
|
||||
templates = Jinja2Templates(directory="app/templates")
|
||||
@@ -56,6 +57,30 @@ def _require_container_item(item: Item) -> None:
|
||||
raise HTTPException(status_code=400, detail="Only container items can have sub-items")
|
||||
|
||||
|
||||
def _set_image_fields(target, processed_image) -> None:
|
||||
if processed_image is None:
|
||||
return
|
||||
|
||||
target.image_blob = processed_image.blob
|
||||
target.image_mime_type = processed_image.mime_type
|
||||
target.image_width = processed_image.width
|
||||
target.image_height = processed_image.height
|
||||
|
||||
|
||||
def _clear_image_fields(target) -> None:
|
||||
target.image_blob = None
|
||||
target.image_mime_type = None
|
||||
target.image_width = None
|
||||
target.image_height = None
|
||||
|
||||
|
||||
def _image_response_or_404(target) -> Response:
|
||||
if target.image_blob is None or target.image_mime_type is None:
|
||||
raise HTTPException(status_code=404, detail="Image not found")
|
||||
|
||||
return Response(content=target.image_blob, media_type=target.image_mime_type)
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
@@ -97,6 +122,7 @@ def create_app() -> FastAPI:
|
||||
note: str | None = Form(default=None),
|
||||
room: str | None = Form(default=None),
|
||||
status_text: str | None = Form(default=None, alias="status"),
|
||||
image_file: UploadFile | None = File(default=None),
|
||||
db: Session = Depends(get_db),
|
||||
) -> RedirectResponse:
|
||||
box = Box(
|
||||
@@ -105,6 +131,7 @@ def create_app() -> FastAPI:
|
||||
room=_clean_text(room),
|
||||
status=_clean_text(status_text),
|
||||
)
|
||||
_set_image_fields(box, process_upload(image_file))
|
||||
db.add(box)
|
||||
db.commit()
|
||||
db.refresh(box)
|
||||
@@ -119,6 +146,10 @@ def create_app() -> FastAPI:
|
||||
context={"page_title": box.name, "box": box},
|
||||
)
|
||||
|
||||
@app.get("/boxes/{box_id}/image")
|
||||
def get_box_image(box_id: int, db: Session = Depends(get_db)) -> Response:
|
||||
return _image_response_or_404(_get_box_or_404(db, box_id))
|
||||
|
||||
@app.get("/boxes/{box_id}/edit")
|
||||
def edit_box_page(box_id: int, request: Request, db: Session = Depends(get_db)):
|
||||
box = _get_box_or_404(db, box_id)
|
||||
@@ -140,6 +171,7 @@ def create_app() -> FastAPI:
|
||||
note: str | None = Form(default=None),
|
||||
room: str | None = Form(default=None),
|
||||
status_text: str | None = Form(default=None, alias="status"),
|
||||
image_file: UploadFile | None = File(default=None),
|
||||
db: Session = Depends(get_db),
|
||||
) -> RedirectResponse:
|
||||
box = _get_box_or_404(db, box_id)
|
||||
@@ -147,9 +179,17 @@ def create_app() -> FastAPI:
|
||||
box.note = _clean_text(note)
|
||||
box.room = _clean_text(room)
|
||||
box.status = _clean_text(status_text)
|
||||
_set_image_fields(box, process_upload(image_file))
|
||||
db.commit()
|
||||
return RedirectResponse(url=f"/boxes/{box.id}", status_code=status.HTTP_303_SEE_OTHER)
|
||||
|
||||
@app.post("/boxes/{box_id}/image/delete")
|
||||
def delete_box_image(box_id: int, db: Session = Depends(get_db)) -> RedirectResponse:
|
||||
box = _get_box_or_404(db, box_id)
|
||||
_clear_image_fields(box)
|
||||
db.commit()
|
||||
return RedirectResponse(url=f"/boxes/{box.id}/edit", status_code=status.HTTP_303_SEE_OTHER)
|
||||
|
||||
@app.post("/boxes/{box_id}/delete")
|
||||
def delete_box(box_id: int, db: Session = Depends(get_db)) -> RedirectResponse:
|
||||
box = _get_box_or_404(db, box_id)
|
||||
@@ -179,6 +219,7 @@ def create_app() -> FastAPI:
|
||||
note: str | None = Form(default=None),
|
||||
quantity: str | None = Form(default=None),
|
||||
is_container: str | None = Form(default=None),
|
||||
image_file: UploadFile | None = File(default=None),
|
||||
db: Session = Depends(get_db),
|
||||
) -> RedirectResponse:
|
||||
box = _get_box_or_404(db, box_id)
|
||||
@@ -189,6 +230,7 @@ def create_app() -> FastAPI:
|
||||
quantity=_parse_quantity(quantity),
|
||||
is_container=_is_checked(is_container),
|
||||
)
|
||||
_set_image_fields(item, process_upload(image_file))
|
||||
db.add(item)
|
||||
db.commit()
|
||||
db.refresh(item)
|
||||
@@ -203,6 +245,10 @@ def create_app() -> FastAPI:
|
||||
context={"page_title": item.name, "item": item},
|
||||
)
|
||||
|
||||
@app.get("/items/{item_id}/image")
|
||||
def get_item_image(item_id: int, db: Session = Depends(get_db)) -> Response:
|
||||
return _image_response_or_404(_get_item_or_404(db, item_id))
|
||||
|
||||
@app.get("/items/{item_id}/edit")
|
||||
def edit_item_page(item_id: int, request: Request, db: Session = Depends(get_db)):
|
||||
item = _get_item_or_404(db, item_id)
|
||||
@@ -225,6 +271,7 @@ def create_app() -> FastAPI:
|
||||
note: str | None = Form(default=None),
|
||||
quantity: str | None = Form(default=None),
|
||||
is_container: str | None = Form(default=None),
|
||||
image_file: UploadFile | None = File(default=None),
|
||||
db: Session = Depends(get_db),
|
||||
) -> RedirectResponse:
|
||||
item = _get_item_or_404(db, item_id)
|
||||
@@ -234,9 +281,17 @@ def create_app() -> FastAPI:
|
||||
item.is_container = _is_checked(is_container)
|
||||
if not item.is_container:
|
||||
item.subitems.clear()
|
||||
_set_image_fields(item, process_upload(image_file))
|
||||
db.commit()
|
||||
return RedirectResponse(url=f"/items/{item.id}", status_code=status.HTTP_303_SEE_OTHER)
|
||||
|
||||
@app.post("/items/{item_id}/image/delete")
|
||||
def delete_item_image(item_id: int, db: Session = Depends(get_db)) -> RedirectResponse:
|
||||
item = _get_item_or_404(db, item_id)
|
||||
_clear_image_fields(item)
|
||||
db.commit()
|
||||
return RedirectResponse(url=f"/items/{item.id}/edit", status_code=status.HTTP_303_SEE_OTHER)
|
||||
|
||||
@app.post("/items/{item_id}/delete")
|
||||
def delete_item(item_id: int, db: Session = Depends(get_db)) -> RedirectResponse:
|
||||
item = _get_item_or_404(db, item_id)
|
||||
@@ -267,6 +322,7 @@ def create_app() -> FastAPI:
|
||||
name: str = Form(...),
|
||||
note: str | None = Form(default=None),
|
||||
quantity: str | None = Form(default=None),
|
||||
image_file: UploadFile | None = File(default=None),
|
||||
db: Session = Depends(get_db),
|
||||
) -> RedirectResponse:
|
||||
item = _get_item_or_404(db, item_id)
|
||||
@@ -277,11 +333,16 @@ def create_app() -> FastAPI:
|
||||
note=_clean_text(note),
|
||||
quantity=_parse_quantity(quantity),
|
||||
)
|
||||
_set_image_fields(subitem, process_upload(image_file))
|
||||
db.add(subitem)
|
||||
db.commit()
|
||||
db.refresh(subitem)
|
||||
return RedirectResponse(url=f"/items/{item.id}", status_code=status.HTTP_303_SEE_OTHER)
|
||||
|
||||
@app.get("/subitems/{subitem_id}/image")
|
||||
def get_subitem_image(subitem_id: int, db: Session = Depends(get_db)) -> Response:
|
||||
return _image_response_or_404(_get_subitem_or_404(db, subitem_id))
|
||||
|
||||
@app.get("/subitems/{subitem_id}/edit")
|
||||
def edit_subitem_page(subitem_id: int, request: Request, db: Session = Depends(get_db)):
|
||||
subitem = _get_subitem_or_404(db, subitem_id)
|
||||
@@ -303,18 +364,27 @@ def create_app() -> FastAPI:
|
||||
name: str = Form(...),
|
||||
note: str | None = Form(default=None),
|
||||
quantity: str | None = Form(default=None),
|
||||
image_file: UploadFile | None = File(default=None),
|
||||
db: Session = Depends(get_db),
|
||||
) -> RedirectResponse:
|
||||
subitem = _get_subitem_or_404(db, subitem_id)
|
||||
subitem.name = name.strip()
|
||||
subitem.note = _clean_text(note)
|
||||
subitem.quantity = _parse_quantity(quantity)
|
||||
_set_image_fields(subitem, process_upload(image_file))
|
||||
db.commit()
|
||||
return RedirectResponse(
|
||||
url=f"/items/{subitem.parent_item_id}",
|
||||
status_code=status.HTTP_303_SEE_OTHER,
|
||||
)
|
||||
|
||||
@app.post("/subitems/{subitem_id}/image/delete")
|
||||
def delete_subitem_image(subitem_id: int, db: Session = Depends(get_db)) -> RedirectResponse:
|
||||
subitem = _get_subitem_or_404(db, subitem_id)
|
||||
_clear_image_fields(subitem)
|
||||
db.commit()
|
||||
return RedirectResponse(url=f"/subitems/{subitem.id}/edit", status_code=status.HTTP_303_SEE_OTHER)
|
||||
|
||||
@app.post("/subitems/{subitem_id}/delete")
|
||||
def delete_subitem(subitem_id: int, db: Session = Depends(get_db)) -> RedirectResponse:
|
||||
subitem = _get_subitem_or_404(db, subitem_id)
|
||||
|
||||
Reference in New Issue
Block a user