feat: implement RBAC permissions system
Add role-based access control with hierarchy: super_admin > team_admin > engineer > viewer. Adds is_super_admin boolean to User model (migration 010), centralized backend permissions module, frontend usePermissions hook, and UI enforcement (conditional Create/Edit buttons, editor redirect for viewers, role badge in header). All endpoint admin checks updated from role=="admin" to is_super_admin. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@ from sqlalchemy import select, or_, and_, func, desc, Integer, case
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.api.deps import get_current_user
|
||||
from app.api.deps import get_current_user, require_engineer_or_admin
|
||||
from app.models.user import User
|
||||
from app.models.step_library import StepLibrary, StepRating
|
||||
from app.models.step_category import StepCategory
|
||||
@@ -33,14 +33,16 @@ def can_view_step(user: User, step: StepLibrary) -> bool:
|
||||
if step.visibility == 'private':
|
||||
return step.created_by == user.id
|
||||
if step.visibility == 'team':
|
||||
return step.team_id == user.team_id or user.role == 'admin'
|
||||
return step.team_id == user.team_id or user.is_super_admin
|
||||
return False
|
||||
|
||||
|
||||
def can_edit_step(user: User, step: StepLibrary) -> bool:
|
||||
"""Check if user can edit/delete a step."""
|
||||
if user.role == 'admin':
|
||||
if user.is_super_admin:
|
||||
return True
|
||||
if user.role == 'viewer':
|
||||
return False
|
||||
return step.created_by == user.id
|
||||
|
||||
|
||||
@@ -300,9 +302,9 @@ async def get_step(
|
||||
async def create_step(
|
||||
step_data: StepLibraryCreate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
current_user: User = Depends(require_engineer_or_admin)
|
||||
):
|
||||
"""Create a new step."""
|
||||
"""Create a new step (engineers and admins only, not viewers)."""
|
||||
# Validate category if provided
|
||||
if step_data.category_id:
|
||||
cat_result = await db.execute(
|
||||
@@ -316,7 +318,7 @@ async def create_step(
|
||||
|
||||
# Team validation: can only set team_id to own team
|
||||
team_id = step_data.team_id
|
||||
if team_id and team_id != current_user.team_id and current_user.role != 'admin':
|
||||
if team_id and team_id != current_user.team_id and not current_user.is_super_admin:
|
||||
raise HTTPException(status_code=403, detail="Cannot create step for another team")
|
||||
|
||||
step = StepLibrary(
|
||||
|
||||
Reference in New Issue
Block a user