Spaces:
Sleeping
Sleeping
Download app/dda/rbac/permissions.py from coderuday21/satdetect-dev: direct link, hf CLI and curl.
- Browser
- Download file 3.91 kB
-
https://huggingface.co/spaces/coderuday21/satdetect-dev/resolve/main/app/dda/rbac/permissions.py
- Command line
-
hf download hf://spaces/coderuday21/satdetect-dev/app/dda/rbac/permissions.py
-
curl -L -o permissions.py https://huggingface.co/spaces/coderuday21/satdetect-dev/resolve/main/app/dda/rbac/permissions.py
3.91 kB
| """Permission resolution for the dynamic RBAC system β used by the new admin | |
| routes/pages, and by the navbar to filter which menu items a user sees.""" | |
| from __future__ import annotations | |
| from typing import List, Optional | |
| from fastapi import Depends, HTTPException | |
| from sqlalchemy.orm import Session | |
| from ...database import get_db | |
| from ...models import User | |
| from ..dda_auth import current_dda_user | |
| from .models import MenuItem, Module, Role, RolePermission | |
| def get_user_role_row(user: User, db: Session) -> Optional[Role]: | |
| """Resolve the user's Role row: by role_id if backfilled, else by matching | |
| the legacy `User.role` string (case-insensitive) β covers any user created | |
| before the RBAC seed ran.""" | |
| if user.role_id: | |
| role = db.query(Role).filter(Role.id == user.role_id).first() | |
| if role: | |
| return role | |
| legacy = (user.role or "").strip().lower() | |
| if legacy: | |
| return db.query(Role).filter(Role.name == legacy).first() | |
| return None | |
| def get_role_rank(user: User, db: Session) -> Optional[int]: | |
| role = get_user_role_row(user, db) | |
| return role.rank if role else None | |
| def user_can(user: User, db: Session, module_key: str, action: str = "view") -> bool: | |
| """action: 'view' | 'create' | 'edit' | 'delete'.""" | |
| role = get_user_role_row(user, db) | |
| if not role: | |
| return False | |
| module = db.query(Module).filter(Module.key == module_key).first() | |
| if not module: | |
| return False | |
| perm = ( | |
| db.query(RolePermission) | |
| .filter(RolePermission.role_id == role.id, RolePermission.module_id == module.id) | |
| .first() | |
| ) | |
| if not perm: | |
| return False | |
| return bool(getattr(perm, f"can_{action}", False)) | |
| def require_module_permission(module_key: str, action: str = "view"): | |
| """FastAPI dependency factory β 403s unless the current user's role has | |
| `can_<action>` on `module_key`. Mirrors require_min_role's call shape.""" | |
| def _dependency( | |
| user: User = Depends(current_dda_user), | |
| db: Session = Depends(get_db), | |
| ) -> User: | |
| if not user_can(user, db, module_key, action): | |
| raise HTTPException( | |
| status_code=403, | |
| detail=f"Missing '{action}' permission on '{module_key}'.", | |
| ) | |
| return user | |
| return _dependency | |
| def resolve_user_menu(user: User, db: Session) -> List[MenuItem]: | |
| """Top-level menu items the user's role can view, in display order, each | |
| with a `.visible_children` list attached (set as a plain transient | |
| attribute, not persisted) for items that have sub-items β the navbar | |
| renders those as a collapsible group like "Configuration" > Roles & | |
| Users / App Modules / Menu Management. | |
| Items with no linked module (module_id is None) are always shown, except | |
| a group item ("Configuration") which is only shown once it has at least | |
| one visible child β otherwise a role with no admin access would see an | |
| empty, dead group header.""" | |
| def _visible(item: MenuItem) -> bool: | |
| if item.module_id is None: | |
| return True | |
| module = db.query(Module).filter(Module.id == item.module_id).first() | |
| return bool(module and user_can(user, db, module.key, "view")) | |
| top_level = ( | |
| db.query(MenuItem) | |
| .filter(MenuItem.is_active.is_(True), MenuItem.parent_id.is_(None)) | |
| .order_by(MenuItem.sort_order) | |
| .all() | |
| ) | |
| visible = [] | |
| for item in top_level: | |
| children = ( | |
| db.query(MenuItem) | |
| .filter(MenuItem.is_active.is_(True), MenuItem.parent_id == item.id) | |
| .order_by(MenuItem.sort_order) | |
| .all() | |
| ) | |
| item.visible_children = [c for c in children if _visible(c)] | |
| is_group = bool(children) | |
| if (item.visible_children if is_group else _visible(item)): | |
| visible.append(item) | |
| return visible | |