PMFlow/backend/app/dependencies/permissions.py

75 lines
2.3 KiB
Python

"""权限中间件依赖。"""
from __future__ import annotations
from enum import Enum
from fastapi import Depends, HTTPException
from sqlalchemy import and_, select
from sqlalchemy.ext.asyncio import AsyncSession
from ..database import get_db
from ..models import User, UserProject
from ..services.auth import parse_role_values
from .auth import get_current_user
MANAGER_ROLES = {"BOSS", "ADMIN"}
def _role_value(role: object) -> str:
return role.value if isinstance(role, Enum) else str(role or "")
async def require_manager_user(
current_user: User = Depends(get_current_user),
) -> User:
"""要求当前用户是管理角色。"""
user_roles = set(parse_role_values(_role_value(current_user.role)))
if not user_roles.intersection(MANAGER_ROLES):
raise HTTPException(status_code=403, detail="Manager permission required")
return current_user
async def require_self_or_manager(
user_id: int,
current_user: User = Depends(get_current_user),
) -> User:
"""要求“本人或管理角色”。"""
user_roles = set(parse_role_values(_role_value(current_user.role)))
if int(current_user.id) == int(user_id) or user_roles.intersection(MANAGER_ROLES):
return current_user
raise HTTPException(status_code=403, detail="No permission")
async def require_project_member_or_manager(
project_id: str,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> User:
"""
要求为项目成员或管理角色。
适用于所有带 `project_id` 的 mutation 端点。
"""
user_roles = set(parse_role_values(_role_value(current_user.role)))
if user_roles.intersection(MANAGER_ROLES):
return current_user
try:
pid = int(project_id)
except ValueError as exc:
raise HTTPException(status_code=400, detail="Invalid project_id") from exc
membership = await db.execute(
select(UserProject.user_id).where(
and_(
UserProject.tenant_id == int(current_user.tenant_id),
UserProject.project_id == pid,
UserProject.user_id == int(current_user.id),
)
)
)
if membership.scalar_one_or_none() is None:
raise HTTPException(status_code=403, detail="Project membership required")
return current_user