from collections import OrderedDict from fastapi import APIRouter, Depends, HTTPException from sqlalchemy import delete, select from sqlalchemy.orm import Session from app.db import get_db from app.deps import require_admin from app.models import Permission, User from app.models.user import role_permissions from app.schemas.role import ( PermissionCreate, PermissionGroup, PermissionResponse, PermissionUpdate, ) from app.services.audit_service import write_audit router = APIRouter() def _serialize(p: Permission) -> PermissionResponse: return PermissionResponse(id=p.id, code=p.code, name=p.name, module=p.module) @router.get("", response_model=list[PermissionGroup]) def list_permissions(db: Session = Depends(get_db), _: User = Depends(require_admin)) -> list[PermissionGroup]: permissions = db.scalars(select(Permission).order_by(Permission.module, Permission.id)).all() grouped: "OrderedDict[str, list[PermissionResponse]]" = OrderedDict() for p in permissions: grouped.setdefault(p.module or "其他", []).append(_serialize(p)) return [PermissionGroup(module=m, items=items) for m, items in grouped.items()] @router.post("", response_model=PermissionResponse) def create_permission( payload: PermissionCreate, db: Session = Depends(get_db), admin: User = Depends(require_admin), ) -> PermissionResponse: if db.scalar(select(Permission).where(Permission.code == payload.code)): raise HTTPException(status_code=409, detail="权限 code 已存在") p = Permission(code=payload.code, name=payload.name, module=payload.module) db.add(p) db.flush() write_audit(db, "permission.create", actor_id=admin.id, target_type="permission", target_id=str(p.id)) db.commit() db.refresh(p) return _serialize(p) @router.patch("/{permission_id}", response_model=PermissionResponse) def update_permission( permission_id: int, payload: PermissionUpdate, db: Session = Depends(get_db), admin: User = Depends(require_admin), ) -> PermissionResponse: p = db.get(Permission, permission_id) if not p: raise HTTPException(status_code=404, detail="权限不存在") if payload.name is not None: p.name = payload.name if payload.module is not None: p.module = payload.module write_audit(db, "permission.update", actor_id=admin.id, target_type="permission", target_id=str(p.id)) db.commit() db.refresh(p) return _serialize(p) @router.delete("/{permission_id}") def delete_permission( permission_id: int, db: Session = Depends(get_db), admin: User = Depends(require_admin), ) -> dict: p = db.get(Permission, permission_id) if not p: raise HTTPException(status_code=404, detail="权限不存在") db.execute(delete(role_permissions).where(role_permissions.c.permission_id == permission_id)) write_audit(db, "permission.delete", actor_id=admin.id, target_type="permission", target_id=str(permission_id), detail={"code": p.code, "name": p.name}) db.delete(p) db.commit() return {"deleted": True, "id": permission_id}