feat: implement complete RBAC access control with tests
Add 4-layer access control stack (subscription → module → menu → permissions): - P1: Wire requires_permission into menu sidebar filtering - P2: Expose window.USER_PERMISSIONS for Alpine.js client-side gating - P3: Add page-level permission guards on store routes - P4: Role CRUD API endpoints and role editor UI - P5: Audit trail for all role/permission changes Includes unit tests (menu permission filtering, role CRUD service) and integration tests (role API endpoints). All 404 core+tenancy tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,7 +17,7 @@ from fastapi import APIRouter, Depends, Request
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import get_current_store_api
|
||||
from app.api.deps import get_current_store_api, get_user_permissions
|
||||
from app.core.database import get_db
|
||||
from app.modules.core.services.menu_service import menu_service
|
||||
from app.modules.enums import FrontendType
|
||||
@@ -81,6 +81,7 @@ async def get_rendered_store_menu(
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: UserContext = Depends(get_current_store_api),
|
||||
user_perms: list = Depends(get_user_permissions),
|
||||
):
|
||||
"""
|
||||
Get the rendered store menu for the current user.
|
||||
@@ -89,6 +90,7 @@ async def get_rendered_store_menu(
|
||||
- Modules enabled on the store's platform
|
||||
- AdminMenuConfig visibility for the platform
|
||||
- Store code for URL placeholder replacement
|
||||
- User permissions (items with requires_permission are hidden if user lacks it)
|
||||
|
||||
Used by the store frontend to render the sidebar dynamically.
|
||||
"""
|
||||
@@ -100,12 +102,13 @@ async def get_rendered_store_menu(
|
||||
if platform_id is None:
|
||||
platform_id = menu_service.get_store_primary_platform_id(db, store.id)
|
||||
|
||||
# Get filtered menu with platform visibility and store_code interpolation
|
||||
# Get filtered menu with platform visibility, store_code, and permission filtering
|
||||
menu = menu_service.get_menu_for_rendering(
|
||||
db=db,
|
||||
frontend_type=FrontendType.STORE,
|
||||
platform_id=platform_id,
|
||||
store_code=store.subdomain,
|
||||
user_permissions=user_perms,
|
||||
)
|
||||
|
||||
# Resolve language
|
||||
|
||||
Reference in New Issue
Block a user