Renamed AuthRequired/AdminRequired to auth_required/admin_required and updated all references. Replaced direct HTTPException usage with utils.http_exceptions for consistent error handling. Updated router endpoints to use new auth dependency and standardized not implemented responses. Cleaned up unused theme fields in SiteConfigResponse and improved site config endpoint. Minor type and import cleanups across routers and middleware.
156 lines
4.3 KiB
Python
156 lines
4.3 KiB
Python
from typing import Annotated
|
||
|
||
from fastapi import APIRouter, Depends, HTTPException
|
||
|
||
from middleware.auth import auth_required
|
||
from middleware.dependencies import SessionDep
|
||
from models import (
|
||
DirectoryCreateRequest,
|
||
DirectoryResponse,
|
||
Object,
|
||
ObjectResponse,
|
||
ObjectType,
|
||
PolicyResponse,
|
||
User,
|
||
ResponseBase,
|
||
)
|
||
|
||
directory_router = APIRouter(
|
||
prefix="/directory",
|
||
tags=["directory"]
|
||
)
|
||
|
||
@directory_router.get(
|
||
path="/{path:path}",
|
||
summary="获取目录内容",
|
||
)
|
||
async def router_directory_get(
|
||
session: SessionDep,
|
||
user: Annotated[User, Depends(auth_required)],
|
||
path: str
|
||
) -> DirectoryResponse:
|
||
"""
|
||
获取目录内容
|
||
|
||
路径必须以用户名开头,如 /api/directory/admin 或 /api/directory/admin/docs
|
||
|
||
:param session: 数据库会话
|
||
:param user: 当前登录用户
|
||
:param path: 目录路径(必须以用户名开头)
|
||
:return: 目录内容
|
||
"""
|
||
# 路径必须以用户名开头
|
||
path = path.strip("/")
|
||
if not path:
|
||
raise HTTPException(status_code=400, detail="路径不能为空,请使用 /{username} 格式")
|
||
|
||
path_parts = path.split("/")
|
||
if path_parts[0] != user.username:
|
||
raise HTTPException(status_code=403, detail="无权访问其他用户的目录")
|
||
|
||
folder = await Object.get_by_path(session, user.id, "/" + path, user.username)
|
||
|
||
if not folder:
|
||
raise HTTPException(status_code=404, detail="目录不存在")
|
||
|
||
if not folder.is_folder:
|
||
raise HTTPException(status_code=400, detail="指定路径不是目录")
|
||
|
||
children = await Object.get_children(session, user.id, folder.id)
|
||
policy = await folder.awaitable_attrs.policy
|
||
|
||
objects = [
|
||
ObjectResponse(
|
||
id=child.id,
|
||
name=child.name,
|
||
thumb=False,
|
||
size=child.size,
|
||
type=ObjectType.FOLDER if child.is_folder else ObjectType.FILE,
|
||
date=child.updated_at,
|
||
create_date=child.created_at,
|
||
source_enabled=False,
|
||
)
|
||
for child in children
|
||
]
|
||
|
||
policy_response = PolicyResponse(
|
||
id=policy.id,
|
||
name=policy.name,
|
||
type=policy.type.value,
|
||
max_size=policy.max_size,
|
||
)
|
||
|
||
return DirectoryResponse(
|
||
id=folder.id,
|
||
parent=folder.parent_id,
|
||
objects=objects,
|
||
policy=policy_response,
|
||
)
|
||
|
||
|
||
@directory_router.put(
|
||
path="/",
|
||
summary="创建目录",
|
||
)
|
||
async def router_directory_create(
|
||
session: SessionDep,
|
||
user: Annotated[User, Depends(auth_required)],
|
||
request: DirectoryCreateRequest
|
||
) -> ResponseBase:
|
||
"""
|
||
创建目录
|
||
|
||
:param session: 数据库会话
|
||
:param user: 当前登录用户
|
||
:param request: 创建请求(包含 parent_id UUID 和 name)
|
||
:return: 创建结果
|
||
"""
|
||
# 验证目录名称
|
||
name = request.name.strip()
|
||
if not name:
|
||
raise HTTPException(status_code=400, detail="目录名称不能为空")
|
||
|
||
# [TODO] 进一步验证名称合法性
|
||
if "/" in name or "\\" in name:
|
||
raise HTTPException(status_code=400, detail="目录名称不能包含斜杠")
|
||
|
||
# 通过 UUID 获取父目录
|
||
parent = await Object.get(session, Object.id == request.parent_id)
|
||
if not parent or parent.owner_id != user.id:
|
||
raise HTTPException(status_code=404, detail="父目录不存在")
|
||
|
||
if not parent.is_folder:
|
||
raise HTTPException(status_code=400, detail="父路径不是目录")
|
||
|
||
# 检查是否已存在同名对象
|
||
existing = await Object.get(
|
||
session,
|
||
(Object.owner_id == user.id) &
|
||
(Object.parent_id == parent.id) &
|
||
(Object.name == name)
|
||
)
|
||
if existing:
|
||
raise HTTPException(status_code=409, detail="同名文件或目录已存在")
|
||
|
||
policy_id = request.policy_id if request.policy_id else parent.policy_id
|
||
parent_id = parent.id # 在 save 前保存
|
||
|
||
new_folder = Object(
|
||
name=name,
|
||
type=ObjectType.FOLDER,
|
||
owner_id=user.id,
|
||
parent_id=parent_id,
|
||
policy_id=policy_id,
|
||
)
|
||
new_folder_id = new_folder.id # 在 save 前保存 UUID
|
||
new_folder_name = new_folder.name
|
||
await new_folder.save(session)
|
||
|
||
return ResponseBase(
|
||
data={
|
||
"id": new_folder_id,
|
||
"name": new_folder_name,
|
||
"parent_id": parent_id,
|
||
}
|
||
)
|