ifixkart-backend/Backend/app/api/v1/routers/RolePermissionRouter.py

156 lines
6.5 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from sqlalchemy import select, func
from typing import List
import ulid
from app.core.database.db_session import get_db
from app.core.permissions.RoleChecker import get_current_user, RoleChecker
from app.models.UserModel import User
from app.models.RoleModel import Role
from app.models.PermissionModel import Permission, RolePermission
from app.schemas.RolePermission import RoleResponse, RoleCreate, PermissionResponse, RolePermissionUpdate
router = APIRouter(prefix="/api/v1/role-permissions", tags=["Roles & Permissions Control"])
@router.get("/roles/all", response_model=List[RoleResponse])
def get_all_roles(
db: Session = Depends(get_db),
current_user: User = Depends(RoleChecker(["Super Admin", "Admin"]))
):
stmt = select(Role).where(Role.deleted_at.is_(None))
roles = db.execute(stmt).scalars().all()
return roles
@router.post("/roles/create", response_model=RoleResponse, status_code=status.HTTP_201_CREATED)
def create_role(
data: RoleCreate,
db: Session = Depends(get_db),
current_user: User = Depends(RoleChecker(["Super Admin", "Admin"]))
):
existing = db.execute(select(Role).where(Role.role_name == data.role_name)).scalar_one_or_none()
if existing:
raise HTTPException(status_code=400, detail="Role name already exists")
role_id = str(ulid.ULID())
new_role = Role(
role_id=role_id,
role_name=data.role_name,
role_prefix=data.role_prefix,
description=data.description,
is_system=False,
is_active=True
)
db.add(new_role)
db.commit()
db.refresh(new_role)
return new_role
@router.delete("/roles/delete/{role_id}", status_code=status.HTTP_200_OK)
def delete_role(
role_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(RoleChecker(["Super Admin", "Admin"]))
):
role = db.execute(select(Role).where(Role.role_id == role_id)).scalar_one_or_none()
if not role:
raise HTTPException(status_code=404, detail="Role not found")
if role.is_system:
raise HTTPException(status_code=400, detail="System roles cannot be deleted")
user_assigned = db.execute(select(User).where(User.role_id == role_id, User.deleted_at.is_(None))).scalars().all()
if len(user_assigned) > 0:
raise HTTPException(status_code=400, detail="Cannot delete role because it is currently assigned to users")
role.deleted_at = db.execute(select(func.now())).scalar()
db.commit()
return {"detail": "Role deleted successfully"}
@router.get("/permissions/all", response_model=List[PermissionResponse])
def get_all_permissions(
db: Session = Depends(get_db),
current_user: User = Depends(RoleChecker(["Super Admin", "Admin"]))
):
stmt = select(Permission).where(Permission.is_active.is_(True))
permissions = db.execute(stmt).scalars().all()
if not permissions:
# Auto-seed standard platform permissions if permissions table is empty
seed_data = [
("users:read", "User Management", "View user lists and profile details"),
("users:write", "User Management", "Create and modify staff user accounts"),
("users:delete", "User Management", "Delete or deactivate staff user accounts"),
("roles:manage", "User Management", "Create, edit and assign roles & access control policies"),
("catalog:read", "Catalog Management", "View categories, brands, devices, and sales products"),
("catalog:write", "Catalog Management", "Create and edit product catalog items"),
("catalog:delete", "Catalog Management", "Delete catalog items, brands, and categories"),
("inventory:manage", "Inventory & Purchases", "Manage stock movements, warehouses, and purchase orders"),
("marketing:manage", "Marketing & Storefront", "Manage homepage sections, banners, and layout controls"),
("settings:manage", "System Infrastructure", "Configure global system settings and security policies"),
]
for code, group, desc in seed_data:
p_id = str(ulid.ULID())
parts = code.split(":")
module = parts[0]
action = parts[1]
resource = "general"
permission_code = f"{module}.{resource}.{action}"
p_obj = Permission(
permission_id=p_id,
module=module,
resource=resource,
action=action,
permission_code=permission_code,
description=desc,
is_active=True
)
db.add(p_obj)
db.commit()
permissions = db.execute(stmt).scalars().all()
return permissions
@router.get("/roles/{role_id}/permissions", response_model=List[str])
def get_role_permissions(
role_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(RoleChecker(["Super Admin", "Admin"]))
):
role = db.execute(select(Role).where(Role.role_id == role_id)).scalar_one_or_none()
if not role:
raise HTTPException(status_code=404, detail="Role not found")
stmt = select(RolePermission.permission_id).where(RolePermission.role_id == role_id)
perm_ids = db.execute(stmt).scalars().all()
return perm_ids
@router.post("/roles/{role_id}/permissions", status_code=status.HTTP_200_OK)
def update_role_permissions(
role_id: str,
data: RolePermissionUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(RoleChecker(["Super Admin", "Admin"]))
):
role = db.execute(select(Role).where(Role.role_id == role_id)).scalar_one_or_none()
if not role:
raise HTTPException(status_code=404, detail="Role not found")
if role.role_name.lower() == "super admin":
raise HTTPException(status_code=400, detail="Permissions for Super Admin role cannot be modified")
if data.permission_ids:
valid_perms = db.execute(select(Permission.permission_id).where(Permission.permission_id.in_(data.permission_ids))).scalars().all()
if len(valid_perms) != len(data.permission_ids):
raise HTTPException(status_code=400, detail="One or more permission IDs are invalid")
db.query(RolePermission).filter(RolePermission.role_id == role_id).delete()
for perm_id in data.permission_ids:
link_id = str(ulid.ULID())
link = RolePermission(
id=link_id,
role_id=role_id,
permission_id=perm_id
)
db.add(link)
db.commit()
return {"detail": "Role permissions updated successfully"}