优化路由结构
This commit is contained in:
345
routers/api/v1/admin/group/__init__.py
Normal file
345
routers/api/v1/admin/group/__init__.py
Normal file
@@ -0,0 +1,345 @@
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from loguru import logger as l
|
||||
|
||||
from middleware.auth import admin_required
|
||||
from middleware.dependencies import SessionDep
|
||||
from models import (
|
||||
User, ResponseBase,
|
||||
Group, GroupOptions, )
|
||||
from models.group import (
|
||||
GroupCreateRequest, GroupUpdateRequest, GroupDetailResponse, )
|
||||
from models.policy import GroupPolicyLink
|
||||
|
||||
admin_group_router = APIRouter(
|
||||
prefix="/group",
|
||||
tags=["admin", "admin_group"],
|
||||
)
|
||||
|
||||
@admin_group_router.get(
|
||||
path='/',
|
||||
summary='获取用户组列表',
|
||||
description='Get user group list',
|
||||
dependencies=[Depends(admin_required)],
|
||||
)
|
||||
async def router_admin_get_groups(
|
||||
session: SessionDep,
|
||||
page: int = 1,
|
||||
page_size: int = 20,
|
||||
) -> ResponseBase:
|
||||
"""
|
||||
获取用户组列表,支持分页。
|
||||
|
||||
:param session: 数据库会话
|
||||
:param page: 页码
|
||||
:param page_size: 每页数量
|
||||
:return: 用户组列表
|
||||
"""
|
||||
offset = (page - 1) * page_size
|
||||
|
||||
groups = await Group.get(
|
||||
session,
|
||||
None,
|
||||
fetch_mode="all",
|
||||
offset=offset,
|
||||
limit=page_size,
|
||||
load=Group.options,
|
||||
)
|
||||
|
||||
total = await Group.count(session, None)
|
||||
|
||||
# 构建响应
|
||||
group_list = []
|
||||
for g in groups:
|
||||
opts = g.options
|
||||
policies = await g.awaitable_attrs.policies
|
||||
user_count = await User.count(session, User.group_id == g.id)
|
||||
|
||||
group_list.append(GroupDetailResponse(
|
||||
id=g.id,
|
||||
name=g.name,
|
||||
max_storage=g.max_storage,
|
||||
share_enabled=g.share_enabled,
|
||||
web_dav_enabled=g.web_dav_enabled,
|
||||
admin=g.admin,
|
||||
speed_limit=g.speed_limit,
|
||||
user_count=user_count,
|
||||
policy_ids=[p.id for p in policies],
|
||||
share_download=opts.share_download if opts else False,
|
||||
share_free=opts.share_free if opts else False,
|
||||
relocate=opts.relocate if opts else False,
|
||||
source_batch=opts.source_batch if opts else 0,
|
||||
select_node=opts.select_node if opts else False,
|
||||
advance_delete=opts.advance_delete if opts else False,
|
||||
archive_download=opts.archive_download if opts else False,
|
||||
archive_task=opts.archive_task if opts else False,
|
||||
webdav_proxy=opts.webdav_proxy if opts else False,
|
||||
aria2=opts.aria2 if opts else False,
|
||||
redirected_source=opts.redirected_source if opts else False,
|
||||
).model_dump())
|
||||
|
||||
return ResponseBase(data={"groups": group_list, "total": total})
|
||||
|
||||
|
||||
@admin_group_router.get(
|
||||
path='/{group_id}',
|
||||
summary='获取用户组信息',
|
||||
description='Get user group information by ID',
|
||||
dependencies=[Depends(admin_required)],
|
||||
)
|
||||
async def router_admin_get_group(
|
||||
session: SessionDep,
|
||||
group_id: UUID,
|
||||
) -> ResponseBase:
|
||||
"""
|
||||
根据用户组ID获取用户组详细信息。
|
||||
|
||||
:param session: 数据库会话
|
||||
:param group_id: 用户组UUID
|
||||
:return: 用户组详情
|
||||
"""
|
||||
group = await Group.get(session, Group.id == group_id, load=Group.options)
|
||||
|
||||
if not group:
|
||||
raise HTTPException(status_code=404, detail="用户组不存在")
|
||||
|
||||
opts = group.options
|
||||
policies = await group.awaitable_attrs.policies
|
||||
user_count = await User.count(session, User.group_id == group_id)
|
||||
|
||||
response = GroupDetailResponse(
|
||||
id=group.id,
|
||||
name=group.name,
|
||||
max_storage=group.max_storage,
|
||||
share_enabled=group.share_enabled,
|
||||
web_dav_enabled=group.web_dav_enabled,
|
||||
admin=group.admin,
|
||||
speed_limit=group.speed_limit,
|
||||
user_count=user_count,
|
||||
policy_ids=[p.id for p in policies],
|
||||
share_download=opts.share_download if opts else False,
|
||||
share_free=opts.share_free if opts else False,
|
||||
relocate=opts.relocate if opts else False,
|
||||
source_batch=opts.source_batch if opts else 0,
|
||||
select_node=opts.select_node if opts else False,
|
||||
advance_delete=opts.advance_delete if opts else False,
|
||||
archive_download=opts.archive_download if opts else False,
|
||||
archive_task=opts.archive_task if opts else False,
|
||||
webdav_proxy=opts.webdav_proxy if opts else False,
|
||||
aria2=opts.aria2 if opts else False,
|
||||
redirected_source=opts.redirected_source if opts else False,
|
||||
)
|
||||
|
||||
return ResponseBase(data=response.model_dump())
|
||||
|
||||
|
||||
@admin_group_router.get(
|
||||
path='/list/{group_id}',
|
||||
summary='获取用户组成员列表',
|
||||
description='Get user group member list by group ID',
|
||||
dependencies=[Depends(admin_required)],
|
||||
)
|
||||
async def router_admin_get_group_members(
|
||||
session: SessionDep,
|
||||
group_id: UUID,
|
||||
page: int = 1,
|
||||
page_size: int = 20,
|
||||
) -> ResponseBase:
|
||||
"""
|
||||
根据用户组ID获取用户组成员列表。
|
||||
|
||||
:param session: 数据库会话
|
||||
:param group_id: 用户组UUID
|
||||
:param page: 页码
|
||||
:param page_size: 每页数量
|
||||
:return: 成员列表
|
||||
"""
|
||||
# 验证组存在
|
||||
group = await Group.get(session, Group.id == group_id)
|
||||
if not group:
|
||||
raise HTTPException(status_code=404, detail="用户组不存在")
|
||||
|
||||
offset = (page - 1) * page_size
|
||||
|
||||
users = await User.get(
|
||||
session,
|
||||
User.group_id == group_id,
|
||||
fetch_mode="all",
|
||||
offset=offset,
|
||||
limit=page_size,
|
||||
)
|
||||
|
||||
total = await User.count(session, User.group_id == group_id)
|
||||
|
||||
return ResponseBase(data={
|
||||
"members": [u.to_public().model_dump() for u in users],
|
||||
"total": total,
|
||||
})
|
||||
|
||||
|
||||
@admin_group_router.post(
|
||||
path='/',
|
||||
summary='创建用户组',
|
||||
description='Create a new user group',
|
||||
dependencies=[Depends(admin_required)],
|
||||
)
|
||||
async def router_admin_create_group(
|
||||
session: SessionDep,
|
||||
request: GroupCreateRequest,
|
||||
) -> ResponseBase:
|
||||
"""
|
||||
创建新的用户组。
|
||||
|
||||
:param session: 数据库会话
|
||||
:param request: 创建请求
|
||||
:return: 创建结果
|
||||
"""
|
||||
# 检查名称唯一性
|
||||
existing = await Group.get(session, Group.name == request.name)
|
||||
if existing:
|
||||
raise HTTPException(status_code=409, detail="用户组名称已存在")
|
||||
|
||||
# 创建用户组
|
||||
group = Group(
|
||||
name=request.name,
|
||||
max_storage=request.max_storage,
|
||||
share_enabled=request.share_enabled,
|
||||
web_dav_enabled=request.web_dav_enabled,
|
||||
speed_limit=request.speed_limit,
|
||||
)
|
||||
group = await group.save(session)
|
||||
|
||||
# 创建选项
|
||||
options = GroupOptions(
|
||||
group_id=group.id,
|
||||
share_download=request.share_download,
|
||||
share_free=request.share_free,
|
||||
relocate=request.relocate,
|
||||
source_batch=request.source_batch,
|
||||
select_node=request.select_node,
|
||||
advance_delete=request.advance_delete,
|
||||
archive_download=request.archive_download,
|
||||
archive_task=request.archive_task,
|
||||
webdav_proxy=request.webdav_proxy,
|
||||
aria2=request.aria2,
|
||||
redirected_source=request.redirected_source,
|
||||
)
|
||||
await options.save(session)
|
||||
|
||||
# 关联存储策略
|
||||
for policy_id in request.policy_ids:
|
||||
link = GroupPolicyLink(group_id=group.id, policy_id=policy_id)
|
||||
session.add(link)
|
||||
await session.commit()
|
||||
|
||||
l.info(f"管理员创建了用户组: {group.name}")
|
||||
return ResponseBase(data={"id": str(group.id), "name": group.name})
|
||||
|
||||
|
||||
@admin_group_router.patch(
|
||||
path='/{group_id}',
|
||||
summary='更新用户组信息',
|
||||
description='Update user group information by ID',
|
||||
dependencies=[Depends(admin_required)],
|
||||
)
|
||||
async def router_admin_update_group(
|
||||
session: SessionDep,
|
||||
group_id: UUID,
|
||||
request: GroupUpdateRequest,
|
||||
) -> ResponseBase:
|
||||
"""
|
||||
根据用户组ID更新用户组信息。
|
||||
|
||||
:param session: 数据库会话
|
||||
:param group_id: 用户组UUID
|
||||
:param request: 更新请求
|
||||
:return: 更新结果
|
||||
"""
|
||||
group = await Group.get(session, Group.id == group_id, load=Group.options)
|
||||
if not group:
|
||||
raise HTTPException(status_code=404, detail="用户组不存在")
|
||||
|
||||
# 检查名称唯一性(如果要更新名称)
|
||||
if request.name and request.name != group.name:
|
||||
existing = await Group.get(session, Group.name == request.name)
|
||||
if existing:
|
||||
raise HTTPException(status_code=409, detail="用户组名称已存在")
|
||||
|
||||
# 更新组基础字段
|
||||
update_data = request.model_dump(
|
||||
exclude_unset=True,
|
||||
exclude={'policy_ids', 'share_download', 'share_free', 'relocate',
|
||||
'source_batch', 'select_node', 'advance_delete', 'archive_download',
|
||||
'archive_task', 'webdav_proxy', 'aria2', 'redirected_source'}
|
||||
)
|
||||
if update_data:
|
||||
for key, value in update_data.items():
|
||||
setattr(group, key, value)
|
||||
group = await group.save(session)
|
||||
|
||||
# 更新选项
|
||||
if group.options:
|
||||
options_fields = {'share_download', 'share_free', 'relocate', 'source_batch',
|
||||
'select_node', 'advance_delete', 'archive_download',
|
||||
'archive_task', 'webdav_proxy', 'aria2', 'redirected_source'}
|
||||
options_data = {k: v for k, v in request.model_dump(exclude_unset=True).items()
|
||||
if k in options_fields and v is not None}
|
||||
if options_data:
|
||||
for key, value in options_data.items():
|
||||
setattr(group.options, key, value)
|
||||
await group.options.save(session)
|
||||
|
||||
# 更新策略关联
|
||||
if request.policy_ids is not None:
|
||||
# 删除旧关联
|
||||
from sqlmodel import delete
|
||||
await session.execute(
|
||||
delete(GroupPolicyLink).where(GroupPolicyLink.group_id == group_id)
|
||||
)
|
||||
# 添加新关联
|
||||
for policy_id in request.policy_ids:
|
||||
link = GroupPolicyLink(group_id=group_id, policy_id=policy_id)
|
||||
session.add(link)
|
||||
await session.commit()
|
||||
|
||||
l.info(f"管理员更新了用户组: {group.name}")
|
||||
return ResponseBase(data={"id": str(group.id)})
|
||||
|
||||
|
||||
@admin_group_router.delete(
|
||||
path='/{group_id}',
|
||||
summary='删除用户组',
|
||||
description='Delete user group by ID',
|
||||
dependencies=[Depends(admin_required)],
|
||||
)
|
||||
async def router_admin_delete_group(
|
||||
session: SessionDep,
|
||||
group_id: UUID,
|
||||
) -> ResponseBase:
|
||||
"""
|
||||
根据用户组ID删除用户组。
|
||||
|
||||
注意: 如果有用户属于该组,需要先迁移用户或拒绝删除。
|
||||
|
||||
:param session: 数据库会话
|
||||
:param group_id: 用户组UUID
|
||||
:return: 删除结果
|
||||
"""
|
||||
group = await Group.get(session, Group.id == group_id)
|
||||
if not group:
|
||||
raise HTTPException(status_code=404, detail="用户组不存在")
|
||||
|
||||
# 检查是否有用户属于该组
|
||||
user_count = await User.count(session, User.group_id == group_id)
|
||||
if user_count > 0:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"无法删除,该组下还有 {user_count} 个用户"
|
||||
)
|
||||
|
||||
group_name = group.name
|
||||
await Group.delete(session, group)
|
||||
|
||||
l.info(f"管理员删除了用户组: {group_name}")
|
||||
return ResponseBase(data={"deleted": True})
|
||||
Reference in New Issue
Block a user