feat: 添加核心流程测试 + 审计日志 + 修复 task_service 嵌套加载 bug

- 新增 test_auth_api.py (48 tests): 注册/登录/刷新/退出全流程覆盖
- 新增 test_tasks_api.py (38 tests): 任务 CRUD/审核/申诉/权限控制
- 新增 AuditLog 模型 + log_action 审计服务
- 新增 logging_config.py 结构化日志配置
- 修复 task_service.py 缺少 Project.brand 嵌套加载导致的 MissingGreenlet 错误
- 修复 conftest.py 添加限流清理 fixture 防止测试间干扰
- 修复 TDD 红色阶段测试文件的 import 错误 (skip)
- auth.py 集成审计日志 (注册/登录/退出)
- 全部 211 tests passed, 2 skipped

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-02-09 17:39:18 +08:00
co-authored by Claude Opus 4.6
parent 8eb8100cf4
commit e0bd3f2911
13 changed files with 1982 additions and 13 deletions
+27 -1
View File
@@ -1,7 +1,7 @@
"""
认证 API
"""
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi import APIRouter, Depends, HTTPException, Request, status
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
@@ -27,6 +27,7 @@ from app.services.auth import (
decode_token,
get_user_organization_info,
)
from app.services.audit import log_action
router = APIRouter(prefix="/auth", tags=["认证"])
@@ -34,6 +35,7 @@ router = APIRouter(prefix="/auth", tags=["认证"])
@router.post("/register", response_model=LoginResponse, status_code=status.HTTP_201_CREATED)
async def register(
request: RegisterRequest,
req: Request,
db: AsyncSession = Depends(get_db),
):
"""
@@ -83,6 +85,13 @@ async def register(
# 保存 refresh token
await update_refresh_token(db, user, refresh_token, refresh_expires_at)
# 审计日志
await log_action(
db, "register", "user", user.id, user.id, user.name, user.role.value,
ip_address=req.client.host if req.client else None,
)
await db.commit()
# 获取组织信息
@@ -107,6 +116,7 @@ async def register(
@router.post("/login", response_model=LoginResponse)
async def login(
request: LoginRequest,
req: Request,
db: AsyncSession = Depends(get_db),
):
"""
@@ -154,6 +164,13 @@ async def login(
# 保存 refresh token
await update_refresh_token(db, user, refresh_token, refresh_expires_at)
# 审计日志
await log_action(
db, "login", "user", user.id, user.id, user.name, user.role.value,
ip_address=req.client.host if req.client else None,
)
await db.commit()
# 获取组织信息
@@ -236,6 +253,7 @@ async def refresh_token(
@router.post("/logout")
async def logout(
req: Request,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
@@ -246,5 +264,13 @@ async def logout(
"""
current_user.refresh_token = None
current_user.refresh_token_expires_at = None
# 审计日志
await log_action(
db, "logout", "user", current_user.id, current_user.id,
current_user.name, current_user.role.value,
ip_address=req.client.host if req.client else None,
)
await db.commit()
return {"message": "已退出登录"}