4a93bd1c44
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
176 lines
5.9 KiB
Python
176 lines
5.9 KiB
Python
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)
|