Add the Healthcare platform backend (phases 13.0–13.7) with Alembic migration revision fix, production deploy script, validation reports, shared UI exports, and loyalty list page client directives so Next.js build succeeds. Co-authored-by: Cursor <cursoragent@cursor.com>
49 lines
1.6 KiB
Python
49 lines
1.6 KiB
Python
"""Permission enforcement helpers for Delivery APIs."""
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
|
|
from fastapi import Depends
|
|
|
|
from app.core.config import settings
|
|
from app.core.security import get_current_user
|
|
from shared.exceptions import ForbiddenError
|
|
from shared.security import CurrentUser
|
|
|
|
_ADMIN_ROLES = frozenset({"platform_admin", "tenant_owner", "tenant_admin"})
|
|
|
|
|
|
def user_has_permission(user: CurrentUser, permission: str) -> bool:
|
|
if any(role in _ADMIN_ROLES for role in user.roles):
|
|
return True
|
|
roles = set(user.roles)
|
|
if "healthcare.manage" in roles or permission in roles:
|
|
return True
|
|
if "healthcare.view" in roles and permission.endswith(".view"):
|
|
return True
|
|
parts = permission.split(".")
|
|
if len(parts) >= 3:
|
|
manage = f"{parts[0]}.{parts[1]}.manage"
|
|
if manage in roles:
|
|
return True
|
|
return False
|
|
|
|
|
|
def require_permissions(*permissions: str) -> Callable:
|
|
"""Deny unless AUTH is off, user is admin, or any listed permission is present."""
|
|
|
|
async def _dependency(
|
|
user: CurrentUser = Depends(get_current_user),
|
|
) -> CurrentUser:
|
|
if not settings.auth_required:
|
|
return user
|
|
if any(user_has_permission(user, perm) for perm in permissions):
|
|
return user
|
|
raise ForbiddenError(
|
|
"دسترسی مجاز نیست",
|
|
error_code="permission_denied",
|
|
details={"required": list(permissions)},
|
|
)
|
|
|
|
return _dependency
|