refactor(backend): 将模块从 api/v1 移至 backend 根目录

This commit is contained in:
zhangtao
2026-09-06 00:54:11 +08:00
parent 3f472d1e89
commit 92081815f4
40 changed files with 0 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
+48
View File
@@ -0,0 +1,48 @@
from pathlib import Path
from typing import Annotated, Literal
from fastapi import APIRouter, BackgroundTasks, Body, Depends, File, Form, Query, Request, Security, UploadFile
from fastapi.responses import FileResponse, JSONResponse
from app.common.response import ResponseSchema, SuccessResponse, UploadFileResponse
from app.core.base_schema import AuthSchema, UploadResponseSchema
from app.core.dependencies import AuthPermission, get_current_user
from app.core.router_class import OperationLogRoute
from app.utils.upload_util import UploadUtil
from .service import FileService
FileRouter = APIRouter(route_class=OperationLogRoute, prefix="/file", tags=["文件管理"])
@FileRouter.post("/upload", summary="上传文件", response_model=ResponseSchema[UploadResponseSchema], dependencies=[Security(AuthPermission(["module_common:file:upload"]))])
async def upload_controller(
request: Request,
auth: Annotated[AuthSchema, Depends(get_current_user)],
file: Annotated[UploadFile, File(description="上传文件")],
upload_type: Annotated[
Literal["file", "avatar", "param", "resource"] | None,
Query(description="上传类型: file=通用文件, avatar=头像, param=参数配置, resource=监控资源"),
] = "file",
target_path: Annotated[str | None, Form(description="目标目录路径(仅 resource 类型支持)")] = None,
) -> JSONResponse:
result = await FileService.upload_service(
base_url=str(request.base_url),
file=file,
upload_type=upload_type or "file",
target_path=target_path,
)
return SuccessResponse(data=result, msg="上传文件成功")
@FileRouter.post("/download", summary="下载文件", dependencies=[Security(AuthPermission(["module_common:file:download"]))])
async def download_controller(
auth: Annotated[AuthSchema, Depends(get_current_user)],
background_tasks: BackgroundTasks,
file_path: Annotated[str, Body(description="文件路径")],
delete: Annotated[bool, Body(description="是否删除文件")] = False,
) -> FileResponse:
result = await FileService.download_service(file_path=file_path)
if delete:
background_tasks.add_task(UploadUtil.delete_file, Path(result.file_path))
return UploadFileResponse(file_path=result.file_path, filename=result.file_name)
+67
View File
@@ -0,0 +1,67 @@
import os
from fastapi import UploadFile
from app.config.setting import settings
from app.core.base_schema import DownloadFileSchema, UploadResponseSchema
from app.core.exceptions import CustomException
from app.core.logger import logger
from app.utils.upload_util import UploadUtil
class FileService:
"""文件管理服务层
"""
@classmethod
async def upload_service(
cls,
base_url: str,
file: UploadFile,
upload_type: str = "file",
target_path: str | None = None,
) -> UploadResponseSchema:
"""上传文件"""
filename, filepath, file_url = await UploadUtil.upload_file(
file=file,
base_url=base_url,
upload_type=upload_type,
target_path=target_path,
)
return UploadResponseSchema(
file_path=f"{filepath}",
file_name=filename,
origin_name=file.filename,
file_url=f"{file_url}",
)
@classmethod
async def download_service(cls, file_path: str) -> DownloadFileSchema:
"""下载文件"""
if not file_path:
raise CustomException(msg="请选择要下载的文件")
dangerous_patterns = ["../", "..\\", "\0"]
for pattern in dangerous_patterns:
if pattern in file_path:
logger.error(f"检测到路径穿越攻击: {file_path}")
raise CustomException(msg="非法的文件路径")
upload_root = settings.UPLOAD_FILE_PATH.resolve()
abs_path = os.path.normpath(os.path.abspath(file_path))
if not abs_path.startswith(str(upload_root)):
logger.error(f"路径不在上传目录内: {file_path}")
raise CustomException(msg="非法的文件路径")
if not UploadUtil.check_file_exists(abs_path):
raise CustomException(msg="文件不存在")
file_name = UploadUtil.download_file(abs_path)
return DownloadFileSchema(
file_path=abs_path,
file_name=str(file_name),
)