from typing import Optional from urllib.parse import quote from fastapi import APIRouter, Depends, File as FastAPIFile, Form, Header, Request, Response, UploadFile from sqlalchemy.orm import Session from app.core.response import success_response from app.db import get_db_session from app.services.audit_log_service import AuditLogService from app.services.auth_service import AuthService from app.services.file_service import FileService router = APIRouter(prefix="/files", tags=["files"]) ROUTE_PERMISSION_SCOPE = "file_management" ROUTE_PERMISSION_ACTIONS = { "list": "files:list", "upload": "files:upload", "detail": "files:detail", "delete": "files:delete", "download_url": "files:download_url", "download": "files:download", } def get_file_service(db: Session = Depends(get_db_session)) -> FileService: return FileService(db) def get_audit_log_service(db: Session = Depends(get_db_session)) -> AuditLogService: return AuditLogService(db) def require_current_user( authorization: Optional[str] = Header(default=None), db: Session = Depends(get_db_session), ): return AuthService(db).require_current_user(authorization) @router.get("") def list_files( page: int = 1, page_size: int = 20, file_type: Optional[str] = None, file_service: FileService = Depends(get_file_service), current_user: dict = Depends(require_current_user), ): return success_response(file_service.list_files(current_user, page, page_size, file_type)) @router.post("") def upload_file( file: UploadFile = FastAPIFile(...), file_type: str = Form(...), bucket: str = Form(default="default"), file_service: FileService = Depends(get_file_service), audit_log_service: AuditLogService = Depends(get_audit_log_service), current_user: dict = Depends(require_current_user), ): result = file_service.upload_file(current_user, file, file_type, bucket) audit_log_service.record_event( tenant_id=current_user.get("tenant_id"), user_id=current_user.get("id"), action="upload_file", resource_type="file", resource_id=result["id"], detail_json={ "file_name": result["file_name"], "file_type": result["file_type"], "file_size": result["file_size"], "mime_type": result["mime_type"], "file_hash": result["file_hash"], "bucket": result["bucket"], }, ) return success_response(result) @router.get("/{file_id}") def get_file( file_id: str, file_service: FileService = Depends(get_file_service), audit_log_service: AuditLogService = Depends(get_audit_log_service), current_user: dict = Depends(require_current_user), ): result = file_service.get_file(current_user, file_id) audit_log_service.record_event( tenant_id=current_user.get("tenant_id"), user_id=current_user.get("id"), action="get_file", resource_type="file", resource_id=file_id, detail_json={ "file_name": result["file_name"], "file_type": result["file_type"], "mime_type": result["mime_type"], "file_size": result["file_size"], "file_hash": result["file_hash"], }, ) return success_response(result) @router.delete("/{file_id}") def delete_file( file_id: str, file_service: FileService = Depends(get_file_service), audit_log_service: AuditLogService = Depends(get_audit_log_service), current_user: dict = Depends(require_current_user), ): file_detail = file_service.get_file(current_user, file_id) success = file_service.delete_file(current_user, file_id) audit_log_service.record_event( tenant_id=current_user.get("tenant_id"), user_id=current_user.get("id"), action="delete_file", resource_type="file", resource_id=file_id, detail_json={ "file_name": file_detail["file_name"], "file_hash": file_detail["file_hash"], "mime_type": file_detail["mime_type"], "file_size": file_detail["file_size"], "file_type": file_detail["file_type"], }, ) return success_response({"success": success}) @router.get("/{file_id}/download-url") def get_download_url( file_id: str, file_service: FileService = Depends(get_file_service), audit_log_service: AuditLogService = Depends(get_audit_log_service), current_user: dict = Depends(require_current_user), ): result = file_service.get_download_url(current_user, file_id) audit_log_service.record_event( tenant_id=current_user.get("tenant_id"), user_id=current_user.get("id"), action="get_download_url", resource_type="file", resource_id=file_id, detail_json={ "file_name": result["file_name"], "download_url": result["download_url"], "expires_in": result["expires_in"], }, ) return success_response(result) @router.get("/{file_id}/download") def download_file( file_id: str, request: Request, file_service: FileService = Depends(get_file_service), audit_log_service: AuditLogService = Depends(get_audit_log_service), current_user: dict = Depends(require_current_user), ): result = file_service.get_download_payload(current_user, file_id) audit_log_service.record_event( tenant_id=current_user.get("tenant_id"), user_id=current_user.get("id"), action="download_file", resource_type="file", resource_id=file_id, detail_json={"file_name": result["file_name"]}, ip_address=request.client.host if request.client else None, user_agent=request.headers.get("user-agent"), ) headers = { "Content-Disposition": f"attachment; filename*=UTF-8''{quote(result['file_name'])}", } return Response(content=result["content"], media_type=result["mime_type"], headers=headers)