feat: implement source link endpoints and enforce policy rules
- Add POST/GET source link endpoints for file sharing via permanent URLs - Enforce max_size check in PATCH /file/content to prevent size limit bypass - Support is_private (proxy) vs public (302 redirect) storage modes - Replace all ResponseBase(data=...) with proper DTOs or 204 responses - Add 18 integration tests for source link and policy rule enforcement Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
from typing import Any
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
@@ -6,9 +7,44 @@ from loguru import logger as l
|
||||
from middleware.auth import admin_required
|
||||
from middleware.dependencies import SessionDep, TableViewRequestDep
|
||||
from sqlmodels import (
|
||||
ResponseBase, ListResponse,
|
||||
ListResponse,
|
||||
Task, TaskSummary,
|
||||
)
|
||||
from sqlmodel_ext import SQLModelBase
|
||||
|
||||
|
||||
class TaskDetailResponse(SQLModelBase):
|
||||
"""任务详情响应"""
|
||||
|
||||
id: int
|
||||
"""任务ID"""
|
||||
|
||||
status: int
|
||||
"""任务状态"""
|
||||
|
||||
type: int
|
||||
"""任务类型"""
|
||||
|
||||
progress: int
|
||||
"""任务进度"""
|
||||
|
||||
error: str | None
|
||||
"""错误信息"""
|
||||
|
||||
user_id: str
|
||||
"""用户UUID"""
|
||||
|
||||
username: str | None
|
||||
"""用户名"""
|
||||
|
||||
props: dict[str, Any] | None
|
||||
"""任务属性"""
|
||||
|
||||
created_at: str
|
||||
"""创建时间"""
|
||||
|
||||
updated_at: str
|
||||
"""更新时间"""
|
||||
|
||||
admin_task_router = APIRouter(
|
||||
prefix='/task',
|
||||
@@ -67,7 +103,7 @@ async def router_admin_get_task_list(
|
||||
async def router_admin_get_task(
|
||||
session: SessionDep,
|
||||
task_id: int,
|
||||
) -> ResponseBase:
|
||||
) -> TaskDetailResponse:
|
||||
"""
|
||||
获取任务详情。
|
||||
|
||||
@@ -82,30 +118,31 @@ async def router_admin_get_task(
|
||||
user = await task.awaitable_attrs.user
|
||||
props = await task.awaitable_attrs.props
|
||||
|
||||
return ResponseBase(data={
|
||||
"id": task.id,
|
||||
"status": task.status,
|
||||
"type": task.type,
|
||||
"progress": task.progress,
|
||||
"error": task.error,
|
||||
"user_id": str(task.user_id),
|
||||
"username": user.email if user else None,
|
||||
"props": props.model_dump() if props else None,
|
||||
"created_at": task.created_at.isoformat(),
|
||||
"updated_at": task.updated_at.isoformat(),
|
||||
})
|
||||
return TaskDetailResponse(
|
||||
id=task.id,
|
||||
status=task.status,
|
||||
type=task.type,
|
||||
progress=task.progress,
|
||||
error=task.error,
|
||||
user_id=str(task.user_id),
|
||||
username=user.email if user else None,
|
||||
props=props.model_dump() if props else None,
|
||||
created_at=task.created_at.isoformat(),
|
||||
updated_at=task.updated_at.isoformat(),
|
||||
)
|
||||
|
||||
|
||||
@admin_task_router.delete(
|
||||
path='/{task_id}',
|
||||
summary='删除任务',
|
||||
description='Delete task by ID',
|
||||
dependencies=[Depends(admin_required)]
|
||||
dependencies=[Depends(admin_required)],
|
||||
status_code=204,
|
||||
)
|
||||
async def router_admin_delete_task(
|
||||
session: SessionDep,
|
||||
task_id: int,
|
||||
) -> ResponseBase:
|
||||
) -> None:
|
||||
"""
|
||||
删除任务。
|
||||
|
||||
@@ -119,5 +156,4 @@ async def router_admin_delete_task(
|
||||
|
||||
await Task.delete(session, task)
|
||||
|
||||
l.info(f"管理员删除了任务: {task_id}")
|
||||
return ResponseBase(data={"deleted": True})
|
||||
l.info(f"管理员删除了任务: {task_id}")
|
||||
Reference in New Issue
Block a user