Files
ERP/backend/app/routers/files.py
T
MMD 934b74ebbd Squashed 'pm/' content from commit 91f3271
git-subtree-dir: pm
git-subtree-split: 91f3271d866fa8ee471cfb6793e334b83e6d2b6e
2026-10-07 15:14:20 +03:30

55 lines
1.9 KiB
Python

"""Defect photos — upload to PM volume, serve (LAN-internal, unauthenticated)."""
import uuid
from fastapi import APIRouter, Depends, UploadFile
from fastapi.responses import FileResponse
from sqlalchemy.ext.asyncio import AsyncSession
from app.authz import AuthContext, Perm, require_permission
from app.config import settings
from app.db import get_db
from app.errors import ValidationError
router = APIRouter(prefix="/files", tags=["files"])
ALLOWED = {"image/jpeg": ".jpg", "image/png": ".png", "image/webp": ".webp"}
MAX_SIZE = 10 * 1024 * 1024
# photos are attached to QC defects, so both roles may upload
upload_file = require_permission(Perm.files_upload)
@router.post("")
async def upload(
file: UploadFile,
_: AuthContext = Depends(upload_file),
db: AsyncSession = Depends(get_db),
):
_ = db
ext = ALLOWED.get(file.content_type or "")
if ext is None:
raise ValidationError("فقط تصویر jpg/png/webp پذیرفته میشود", field="file")
data = await file.read()
if len(data) > MAX_SIZE:
raise ValidationError("حجم فایل بیش از حد مجاز است (۱۰ مگابایت)", field="file")
settings.FILES_DIR.mkdir(parents=True, exist_ok=True)
file_id = uuid.uuid4().hex
path = settings.FILES_DIR / f"{file_id}{ext}"
path.write_bytes(data)
return {"data": {"id": file_id, "url": f"/api/v1/files/{file_id}", "filename": file.filename}}
@router.get("/{file_id}")
async def serve(file_id: str, db: AsyncSession = Depends(get_db)):
_ = db
if not file_id.isalnum():
raise ValidationError("شناسه فایل نامعتبر است")
for ext in ALLOWED.values():
path = settings.FILES_DIR / f"{file_id}{ext}"
if path.exists():
media = next(k for k, v in ALLOWED.items() if v == ext)
return FileResponse(path, media_type=media)
from app.errors import NotFoundError
raise NotFoundError("فایل یافت نشد")