The PM panel (PmPanelPage -> iframe /pm/) needs the project-management platform served at /pm/ on the ERP domain. Source: org repo Aramesh/PM, branch feature/project-management-platform. Update via: git subtree pull --prefix=pm aramesh-pm feature/project-management-platform --squash
55 lines
1.9 KiB
Python
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("فایل یافت نشد")
|