This commit is contained in:
2026-01-13 15:30:57 +08:00
28 changed files with 811 additions and 201 deletions

View File

@@ -2,14 +2,12 @@ from datetime import datetime, timedelta
from fastapi import APIRouter, Depends, status
from loguru import logger as l
from sqlalchemy import and_
from middleware.auth import admin_required
from middleware.dependencies import SessionDep
from models import (
User, ResponseBase,
Setting, Object, ObjectType, Share, AdminSummaryResponse, MetricsSummary, LicenseInfo, VersionInfo,
AdminSummaryData,
)
from models.base import SQLModelBase
from models.setting import (
@@ -92,8 +90,8 @@ async def router_admin_get_summary(session: SessionDep) -> AdminSummaryResponse:
Returns:
AdminSummaryResponse: 包含站点概况信息的响应模型。
"""
# 统计最近 12 天的数据
days_count = 12
# 统计最近 14 天的数据
days_count = 14
now = datetime.now()
today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
@@ -152,7 +150,7 @@ async def router_admin_get_summary(session: SessionDep) -> AdminSummaryResponse:
site_urls: list[str] = []
site_url_setting = await Setting.get(
session,
and_(Setting.type == SettingsType.BASIC, Setting.name == "siteURL"),
(Setting.type == SettingsType.BASIC) & (Setting.name == "siteURL"),
)
if site_url_setting and site_url_setting.value:
site_urls.append(site_url_setting.value)
@@ -173,15 +171,13 @@ async def router_admin_get_summary(session: SessionDep) -> AdminSummaryResponse:
commit="dev",
)
data = AdminSummaryData(
return AdminSummaryResponse(
metrics_summary=metrics_summary,
site_urls=site_urls,
license=license_info,
version=version_info,
)
return AdminSummaryResponse(data=data)
@admin_router.get(
path='/news',
summary='获取社区新闻',
@@ -220,7 +216,7 @@ async def router_admin_update_settings(
for item in request.settings:
existing = await Setting.get(
session,
and_(Setting.type == item.type, Setting.name == item.name)
(Setting.type == item.type) & (Setting.name == item.name)
)
if existing:
@@ -262,7 +258,12 @@ async def router_admin_get_settings(
if name:
conditions.append(Setting.name == name)
condition = and_(*conditions) if conditions else None
if conditions:
condition = conditions[0]
for c in conditions[1:]:
condition = condition & c
else:
condition = None
settings = await Setting.get(session, condition, fetch_mode="all")

View File

@@ -5,7 +5,6 @@ from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import FileResponse
from loguru import logger as l
from sqlalchemy import and_
from middleware.auth import admin_required
from middleware.dependencies import SessionDep, TableViewRequestDep
@@ -51,7 +50,12 @@ async def router_admin_get_file_list(
if keyword:
conditions.append(Object.name.ilike(f"%{keyword}%"))
condition = and_(*conditions) if len(conditions) > 1 else conditions[0]
if len(conditions) > 1:
condition = conditions[0]
for c in conditions[1:]:
condition = condition & c
else:
condition = conditions[0]
result = await Object.get_with_count(session, condition, table_view=table_view, load=Object.owner)
# 构建响应
@@ -197,13 +201,15 @@ async def router_admin_delete_file(
except Exception as e:
l.warning(f"删除物理文件失败: {e}")
# 更新用户存储量
owner = await User.get(session, User.id == owner_id)
if owner:
owner.storage = max(0, owner.storage - file_size)
await owner.save(session)
# 更新用户存储量(使用 SQL UPDATE 直接更新,无需加载实例)
from sqlmodel import update as sql_update
stmt = sql_update(User).where(User.id == owner_id).values(
storage=max(0, User.storage - file_size)
)
await session.exec(stmt)
await Object.delete(session, file_obj)
# 使用条件删除
await Object.delete(session, condition=Object.id == file_obj.id)
l.info(f"管理员删除了文件: {file_name}")
return ResponseBase(data={"deleted": True})

View File

@@ -63,12 +63,13 @@ async def router_admin_get_group(
:param group_id: 用户组UUID
:return: 用户组详情
"""
group = await Group.get(session, Group.id == group_id, load=Group.options)
group = await Group.get(session, Group.id == group_id, load=[Group.options, Group.policies])
if not group:
raise HTTPException(status_code=404, detail="用户组不存在")
policies = await group.awaitable_attrs.policies
# 直接访问已加载的关系,无需额外查询
policies = group.policies
user_count = await User.count(session, User.group_id == group_id)
response = GroupDetailResponse.from_group(group, user_count, policies)

View File

@@ -2,7 +2,6 @@ from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException
from loguru import logger as l
from sqlalchemy import and_
from middleware.auth import admin_required
from middleware.dependencies import SessionDep, TableViewRequestDep
@@ -43,7 +42,12 @@ async def router_admin_get_task_list(
if status:
conditions.append(Task.status == status)
condition = and_(*conditions) if conditions else None
if conditions:
condition = conditions[0]
for c in conditions[1:]:
condition = condition & c
else:
condition = None
result = await Task.get_with_count(session, condition, table_view=table_view, load=Task.user)
items: list[TaskSummary] = []

View File

@@ -2,7 +2,7 @@ from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException
from loguru import logger as l
from sqlalchemy import func, and_
from sqlalchemy import func
from middleware.auth import admin_required
from middleware.dependencies import SessionDep, TableViewRequestDep, UserFilterParamsDep
@@ -209,7 +209,7 @@ async def router_admin_calibrate_storage(
from sqlmodel import select
result = await session.execute(
select(func.sum(Object.size), func.count(Object.id)).where(
and_(Object.owner_id == user_id, Object.type == ObjectType.FILE)
(Object.owner_id == user_id) & (Object.type == ObjectType.FILE)
)
)
row = result.one()