新增查看站点概况

This commit is contained in:
2026-01-08 14:41:10 +08:00
parent c17511d2e8
commit baf59b9903
6 changed files with 417 additions and 25 deletions

View File

@@ -1,8 +1,19 @@
from fastapi import APIRouter, Depends
from typing import Annotated, Literal
from uuid import uuid4
from datetime import datetime
from fastapi import APIRouter, Depends, Query, HTTPException
from loguru import logger as l
from middleware.auth import auth_required
from middleware.dependencies import SessionDep
from models import ResponseBase
from models.user import User
from models.share import Share, ShareCreateRequest, ShareResponse
from models.object import Object
from models.mixin import ListResponse, TableViewRequest
from utils import http_exceptions
from utils.password.pwd import Password
share_router = APIRouter(
prefix='/share',
@@ -10,7 +21,7 @@ share_router = APIRouter(
)
@share_router.get(
path='/{info}/{id}',
path='/{id}',
summary='获取分享',
description='Get shared content by info type and ID.',
)
@@ -227,31 +238,147 @@ def router_share_search_public(keywords: str, type: str = 'all') -> ResponseBase
path='/',
summary='创建新分享',
description='Create a new share endpoint.',
dependencies=[Depends(auth_required)]
)
def router_share_create() -> ResponseBase:
async def router_share_create(
session: SessionDep,
user: Annotated[User, Depends(auth_required)],
request: ShareCreateRequest,
) -> ShareResponse:
"""
Create a new share endpoint.
Returns:
ResponseBase: A model containing the response data for the new share creation.
创建新分享
认证:需要 JWT token
流程:
1. 验证对象存在且属于当前用户
2. 生成随机分享码uuid4
3. 如果有密码则加密存储
4. 创建 Share 记录并保存
5. 返回分享信息
"""
http_exceptions.raise_not_implemented()
# 验证对象存在且属于当前用户
obj = await Object.get(session, Object.id == request.object_id)
if not obj or obj.owner_id != user.id:
raise HTTPException(status_code=404, detail="对象不存在或无权限")
# 生成分享码
code = str(uuid4())
# 密码加密处理(如果有)
hashed_password = None
if request.password:
hashed_password = Password.hash(request.password)
# 创建分享记录
share = Share(
code=code,
password=hashed_password,
object_id=request.object_id,
user_id=user.id,
expires=request.expires,
remain_downloads=request.remain_downloads,
preview_enabled=request.preview_enabled,
score=request.score,
source_name=obj.name,
)
share = await share.save(session)
l.info(f"用户 {user.id} 创建分享: {share.code}")
# 返回响应
return ShareResponse(
id=share.id,
code=share.code,
object_id=share.object_id,
source_name=share.source_name,
views=share.views,
downloads=share.downloads,
remain_downloads=share.remain_downloads,
expires=share.expires,
preview_enabled=share.preview_enabled,
score=share.score,
created_at=share.created_at,
is_expired=share.expires is not None and share.expires < datetime.now(),
has_password=share.password is not None,
)
@share_router.get(
path='/',
summary='列出我的分享',
description='Get a list of shares.',
dependencies=[Depends(auth_required)]
)
def router_share_list() -> ResponseBase:
async def router_share_list(
session: SessionDep,
user: Annotated[User, Depends(auth_required)],
offset: int = Query(default=0, ge=0),
limit: int = Query(default=50, le=100),
desc: bool = Query(default=True),
order: Literal["created_at", "updated_at"] = Query(default="created_at"),
keyword: str | None = Query(default=None),
expired: bool | None = Query(default=None),
) -> ListResponse[ShareResponse]:
"""
Get a list of shares.
Returns:
ResponseBase: A model containing the response data for the list of shares.
列出我的分享
认证:需要 JWT token
支持:
- 分页和排序
- 关键字搜索(搜索 source_name
- 过期状态筛选
"""
http_exceptions.raise_not_implemented()
# 构建基础条件
condition = Share.user_id == user.id
# 关键字搜索
if keyword:
condition = condition & Share.source_name.ilike(f"%{keyword}%")
# 过期状态筛选
now = datetime.now()
if expired is True:
# 已过期expires 不为 NULL 且 < 当前时间
condition = condition & (Share.expires != None) & (Share.expires < now)
elif expired is False:
# 未过期expires 为 NULL 或 >= 当前时间
condition = condition & ((Share.expires == None) | (Share.expires >= now))
# 构建 table_view
table_view = TableViewRequest(
offset=offset,
limit=limit,
desc=desc,
order=order,
)
# 使用 get_with_count 获取分页数据
result = await Share.get_with_count(
session,
condition,
table_view=table_view,
)
# 转换为响应模型
items = [
ShareResponse(
id=share.id,
code=share.code,
object_id=share.object_id,
source_name=share.source_name,
views=share.views,
downloads=share.downloads,
remain_downloads=share.remain_downloads,
expires=share.expires,
preview_enabled=share.preview_enabled,
score=share.score,
created_at=share.created_at,
is_expired=share.expires is not None and share.expires < now,
has_password=share.password is not None,
)
for share in result.items
]
return ListResponse(count=result.count, items=items)
@share_router.post(
path='/save/{id}',