BookSystem/backend/auth/apps/roles/urls.py
jayhgq 19d6db6ecc feat: 添加登录日志和操作日志功能
1. 新增日志相关数据库模型、API路由、前端页面与权限配置
2. 为现有业务接口添加操作日志记录功能
3. 优化导入顺序与权限初始化数据
2026-06-12 22:41:41 +08:00

194 lines
6.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from fastapi import APIRouter, Depends, HTTPException, Query, Request
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from fastcrud import FastCRUD
from database import get_db
from models import Role, User
from schemas import RoleCreate, RoleResponse
from middleware import get_current_user
from utils.like_filter import ilike_contains
from utils.log_utils import get_client_ip, get_user_agent, create_operation_log
router = APIRouter(prefix="/roles", tags=["roles"])
# 创建FastCRUD实例指定update_schema为RoleCreate
role_crud = FastCRUD(Role, RoleResponse, RoleCreate)
@router.post("/", response_model=RoleResponse)
async def create_role(
role_data: RoleCreate,
request: Request,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""创建角色"""
# 检查角色名是否已存在
result = await db.execute(select(Role).filter(Role.name == role_data.name))
existing_role = result.scalar_one_or_none()
if existing_role:
raise HTTPException(status_code=400, detail="角色名已存在")
# 设置创建人为当前登录用户
role_data.creator = current_user.nickname or current_user.username
# 创建角色对象
new_role = Role(
name=role_data.name,
creator=role_data.creator
)
db.add(new_role)
await db.flush() # 获取生成的ID
await db.refresh(new_role)
# 记录操作日志
await create_operation_log(
db, current_user.id, current_user.username, "create", "role",
new_role.id, new_role.name, {"name": role_data.name},
get_client_ip(request), get_user_agent(request),
)
await db.commit()
return RoleResponse.model_validate(new_role)
@router.post("/search", response_model=list[RoleResponse])
async def search_roles(
query: dict = {},
request: Request = None,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""获取角色列表POST方式支持按名称模糊查询"""
stmt = select(Role)
name = query.get("name")
cond = ilike_contains(Role.name, name)
if cond is not None:
stmt = stmt.where(cond)
result = await db.execute(stmt)
rows = result.scalars().all()
# 记录查询日志
await create_operation_log(
db, current_user.id, current_user.username, "search", "role",
None, None, {"filters": {k: v for k, v in query.items() if v}},
get_client_ip(request), get_user_agent(request),
)
await db.commit()
return [RoleResponse.model_validate(r) for r in rows]
@router.get("/{role_id}", response_model=RoleResponse)
async def get_role(
role_id: int,
request: Request,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""获取单个角色"""
result = await db.execute(select(Role).filter(Role.id == role_id))
role = result.scalar_one_or_none()
if not role:
raise HTTPException(status_code=404, detail="角色不存在")
# 记录查询日志
await create_operation_log(
db, current_user.id, current_user.username, "search", "role",
role_id, role.name, None,
get_client_ip(request), get_user_agent(request),
)
await db.commit()
return RoleResponse.model_validate(role)
@router.put("/{role_id}", response_model=RoleResponse)
async def update_role(
role_id: int,
role_data: RoleCreate,
request: Request,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""更新角色"""
# 获取原角色数据
result = await db.execute(select(Role).filter(Role.id == role_id))
old_role = result.scalar_one_or_none()
if not old_role:
raise HTTPException(status_code=404, detail="角色不存在")
# 检查角色名是否被其他角色使用
result = await db.execute(
select(Role).filter(Role.name == role_data.name, Role.id != role_id)
)
existing_role = result.scalar_one_or_none()
if existing_role:
raise HTTPException(status_code=400, detail="角色名已存在")
# 使用原生 SQLAlchemy 更新角色FastCRUD 有问题)
from sqlalchemy import update
stmt = (
update(Role)
.where(Role.id == role_id)
.values(name=role_data.name)
)
result = await db.execute(stmt)
if result.rowcount == 0:
raise HTTPException(status_code=404, detail="角色不存在")
# 记录操作日志
changed = {}
if old_role.name != role_data.name:
changed["name"] = {"old": old_role.name, "new": role_data.name}
await create_operation_log(
db, current_user.id, current_user.username, "update", "role",
role_id, old_role.name, changed if changed else None,
get_client_ip(request), get_user_agent(request),
)
await db.commit()
# 查询更新后的数据
result = await db.execute(select(Role).filter(Role.id == role_id))
updated_role = result.scalar_one_or_none()
return updated_role
@router.delete("/{role_id}")
async def delete_role(
role_id: int,
request: Request,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""删除角色"""
# 检查角色是否存在
result = await db.execute(select(Role).filter(Role.id == role_id))
existing_role = result.scalar_one_or_none()
if not existing_role:
raise HTTPException(status_code=404, detail="角色不存在")
# 检查是否有用户使用此角色
result = await db.execute(select(User).filter(User.role_id == role_id))
users = result.scalars().all()
if users:
raise HTTPException(
status_code=400, detail=f"该角色正在被 {len(users)} 个用户使用,无法删除"
)
# 记录操作日志(删除前)
await create_operation_log(
db, current_user.id, current_user.username, "delete", "role",
role_id, existing_role.name, {"name": existing_role.name},
get_client_ip(request), get_user_agent(request),
)
# 使用FastCRUD删除角色
await role_crud.delete(db, id=role_id)
return {"message": "角色删除成功"}