diff --git a/src/iam/dependencies.py b/src/iam/dependencies.py index 7447aaf..d5632c7 100644 --- a/src/iam/dependencies.py +++ b/src/iam/dependencies.py @@ -1,5 +1,5 @@ """ -Router dependencies for +Router dependencies for the IAM module Classes: - List: Description @@ -8,4 +8,49 @@ Classes: Functions: - List: Description - Functions: Description -""" \ No newline at end of file +""" +from typing import Annotated, Optional + +from fastapi import Depends, Query + +from src.database import db_dependency + +from src.iam.models import Group +from src.iam.exceptions import GroupNotFoundException, PermNotFoundException +from src.iam.schemas import GroupIDMixin, PermIDMixin + + +def get_group_model_query(db: db_dependency, group_id: Annotated[int, Query(gt=0)]) -> type[Group]: + group_model = db.get(Group, group_id) + if group_model is None: + raise GroupNotFoundException(group_id) + + return group_model + +group_model_query_dependency = Annotated[type[Group], Depends(get_group_model_query)] + + +def get_group_model_body(db: db_dependency, request_model: Optional[GroupIDMixin] = None) -> type[Group]: + group_id = getattr(request_model, "group_id", None) + if group_id is None: + raise GroupNotFoundException() + group_model = db.get(Group, group_id) + if group_model is None: + raise GroupNotFoundException(group_id) + + return group_model + +group_model_body_dependency = Annotated[type[Group], Depends(get_group_model_body)] + + +def get_perm_model_body(db: db_dependency, request_model: Optional[PermIDMixin] = None) -> type[Group]: + perm_id = getattr(request_model, "permission_id", None) + if perm_id is None: + raise PermNotFoundException + group_model = db.get(Group, perm_id) + if group_model is None: + raise PermNotFoundException(perm_id) + + return group_model + +perm_model_body_dependency = Annotated[type[Group], Depends(get_perm_model_body)] diff --git a/src/iam/exceptions.py b/src/iam/exceptions.py index 5debbb4..5c97b9a 100644 --- a/src/iam/exceptions.py +++ b/src/iam/exceptions.py @@ -1,7 +1,28 @@ """ -Module specific exceptions for +Module specific exceptions for the IAM module Exceptions: - List: Description - Exceptions: Description -""" \ No newline at end of file +""" +from typing import Optional + +from fastapi import HTTPException, status + + +class GroupNotFoundException(HTTPException): + def __init__(self, group_id: Optional[int] = None) -> None: + detail = "Group not found" if group_id is None else f"User with ID '{group_id}' was not found." + super().__init__( + status_code=status.HTTP_404_NOT_FOUND, + detail=detail, + ) + + +class PermNotFoundException(HTTPException): + def __init__(self, perm_id: Optional[int] = None) -> None: + detail = "Permission not found" if perm_id is None else f"User with ID '{perm_id}' was not found." + super().__init__( + status_code=status.HTTP_404_NOT_FOUND, + detail=detail, + ) diff --git a/src/iam/router.py b/src/iam/router.py index b249b34..d874570 100644 --- a/src/iam/router.py +++ b/src/iam/router.py @@ -17,6 +17,7 @@ from src.iam.schemas import IAMGetGroupPermissionsResponse, IAMGetGroupUsersResp IAMPostPermissionResponse, PermissionResponse, IAMDeletePermissionRequest, IAMGetPermissionsSearchRequest, IAMGetPermissionsSearchResponse from src.schemas import ResourceName from src.auth.service import claims_dependency +from src.user.exceptions import UserNotFoundException from src.user.models import User from src.organisation.models import Organisation as Org from src.service.models import Service @@ -24,6 +25,7 @@ from src.organisation.dependencies import org_model_dependency from src.iam.service import service_key_dependency from src.iam.models import Permission as Perm, GroupPermissions as GPerms, Group, UserGroups +from src.iam.dependencies import group_model_query_dependency, group_model_body_dependency, perm_model_body_dependency router = APIRouter( tags=["IAM"], @@ -64,28 +66,21 @@ async def can_act_on_resource(valid_key: service_key_dependency, db: db_dependen @router.get("/group/permissions", response_model=IAMGetGroupPermissionsResponse) -async def get_group_permissions(db: db_dependency, group_id: Annotated[int, Query(gt=0)]): - # TODO: root_user_dependency & org_id query param - group_model = db.get(Group, group_id) - if group_model is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Group not found") - +async def get_group_permissions(db: db_dependency, group_model: group_model_query_dependency): + # TODO: root_user_dependency return {"permissions": group_model.permission_rel} @router.get("/group/users", response_model=IAMGetGroupUsersResponse) -async def get_group_users(db: db_dependency, group_id: Annotated[int, Query(gt=0)]): - # TODO: root_user_dependency & org_id query param - group_model = db.get(Group, group_id) - if group_model is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Group not found") - +async def get_group_users(db: db_dependency, group_model: group_model_query_dependency): + # TODO: root_user_dependency return {"users": group_model.user_rel} @router.post("/group", response_model=IAMPostGroupResponse) async def create_group(db: db_dependency, group_request: IAMPostGroupRequest, org_model: org_model_dependency, org_id: Annotated[int, Query(gt=0)]): # TODO: root_user_dependency + # TODO: get org ID from dependency instead of query (needs updated dep first) group_model = Group(name=group_request.name, org_id=org_id) db.add(group_model) @@ -96,15 +91,8 @@ async def create_group(db: db_dependency, group_request: IAMPostGroupRequest, or @router.put("/group/permission", response_model=IAMPutGroupPermissionResponse) -async def add_group_permission(db: db_dependency, request_model: IAMPutGroupPermissionRequest, org_model: org_model_dependency, org_id: Annotated[int, Query(gt=0)]): +async def add_group_permission(db: db_dependency, group_model: group_model_body_dependency, perm_model: perm_model_body_dependency, request_model: IAMPutGroupPermissionRequest): # TODO: root_user_dependency - group_model = db.get(Group, request_model.group_id) - if group_model is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Group not found") - perm_model = db.get(Perm, request_model.permission_id) - if perm_model is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Permission not found") - group_model.permission_rel.append(perm_model) db.flush() @@ -114,14 +102,12 @@ async def add_group_permission(db: db_dependency, request_model: IAMPutGroupPerm @router.put("/group/user") -async def add_group_user(db: db_dependency, request_model: IAMPutGroupUserRequest, org_model: org_model_dependency, org_id: Annotated[int, Query(gt=0)]): +async def add_group_user(db: db_dependency, group_model: group_model_body_dependency, request_model: IAMPutGroupUserRequest): # TODO: root_user_dependency - group_model = db.get(Group, request_model.group_id) - if group_model is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Group not found") + # TODO: user_model_dependency user_model = db.get(User, request_model.user_id) if user_model is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found") + raise UserNotFoundException(user_id=request_model.user_id) group_model.user_rel.append(user_model) db.flush() @@ -131,15 +117,8 @@ async def add_group_user(db: db_dependency, request_model: IAMPutGroupUserReques @router.delete("/group/permissions") -async def remove_group_permissions(db: db_dependency, request_model: IAMDeleteGroupPermissionRequest, org_model: org_model_dependency, org_id: Annotated[int, Query(gt=0)]): +async def remove_group_permissions(db: db_dependency, group_model: group_model_body_dependency, perm_model: perm_model_body_dependency, request_model: IAMDeleteGroupPermissionRequest): # TODO: root_user_dependency - group_model = db.get(Group, request_model.group_id) - if group_model is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Group not found") - perm_model = db.get(Perm, request_model.permission_id) - if perm_model is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Permission not found") - group_model.permission_rel.remove(perm_model) db.flush() response = IAMDeleteGroupPermissionResponse(group=GroupResponse(**group_model.__dict__), @@ -149,11 +128,9 @@ async def remove_group_permissions(db: db_dependency, request_model: IAMDeleteGr @router.delete("/group/user") -async def remove_group_user(db: db_dependency, request_model: IAMDeleteGroupUserRequest, org_model: org_model_dependency, org_id: Annotated[int, Query(gt=0)]): +async def remove_group_user(db: db_dependency, group_model: group_model_body_dependency, request_model: IAMDeleteGroupUserRequest): # TODO: root_user_dependency - group_model = db.get(Group, request_model.group_id) - if group_model is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Group not found") + # TODO: User model dependency user_model = db.get(User, request_model.user_id) if user_model is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found") @@ -167,7 +144,7 @@ async def remove_group_user(db: db_dependency, request_model: IAMDeleteGroupUser @router.get("/permissions", response_model=IAMGetPermissionsResponse) -async def get_permissions(db: db_dependency, org_model: org_model_dependency, org_id: Annotated[int, Query(gt=0)]): +async def get_permissions(db: db_dependency): # TODO: root_user_dependency permission_models = db.query(Perm).all() @@ -187,12 +164,8 @@ async def create_new_permission(db: db_dependency, request_mode: IAMPostPermissi @router.delete("/permission", status_code=status.HTTP_204_NO_CONTENT) -async def delete_permission(db: db_dependency, request_model: IAMDeletePermissionRequest): +async def delete_permission(db: db_dependency, perm_model: perm_model_body_dependency, request_model: IAMDeletePermissionRequest): # TODO: super_admin_dependency - perm_model = db.query(Perm).filter(Perm.service_id==request_model.service_id, Perm.resource==request_model.resource, Perm.action==request_model.action).first() - if perm_model is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Permission not found") - db.delete(perm_model) db.commit() diff --git a/src/iam/schemas.py b/src/iam/schemas.py index ef10df8..b73500b 100644 --- a/src/iam/schemas.py +++ b/src/iam/schemas.py @@ -30,6 +30,12 @@ class GroupResponse(CustomBaseModel): id: int name: str +class GroupIDMixin(CustomBaseModel): + group_id: int + +class PermIDMixin(CustomBaseModel): + permission_id: int + class IAMGetGroupPermissionsResponse(CustomBaseModel): permissions: list[PermissionResponse] @@ -42,32 +48,28 @@ class IAMPostGroupRequest(CustomBaseModel): class IAMPostGroupResponse(CustomBaseModel): group: GroupResponse -class IAMPutGroupPermissionRequest(CustomBaseModel): - group_id: int - permission_id: int +class IAMPutGroupPermissionRequest(GroupIDMixin, PermIDMixin): + pass class IAMPutGroupPermissionResponse(CustomBaseModel): group: GroupResponse permissions: list[PermissionResponse] -class IAMPutGroupUserRequest(CustomBaseModel): - group_id: int +class IAMPutGroupUserRequest(GroupIDMixin): user_id: int class IAMPutGroupUserResponse(CustomBaseModel): group: GroupResponse users: list[UserResponse] -class IAMDeleteGroupPermissionRequest(CustomBaseModel): - group_id: int - permission_id: int +class IAMDeleteGroupPermissionRequest(GroupIDMixin, PermIDMixin): + pass class IAMDeleteGroupPermissionResponse(CustomBaseModel): group: GroupResponse permissions: list[PermissionResponse] -class IAMDeleteGroupUserRequest(CustomBaseModel): - group_id: int +class IAMDeleteGroupUserRequest(GroupIDMixin): user_id: int class IAMDeleteGroupUserResponse(CustomBaseModel): @@ -85,10 +87,8 @@ class IAMPostPermissionRequest(CustomBaseModel): class IAMPostPermissionResponse(CustomBaseModel): permission: PermissionResponse -class IAMDeletePermissionRequest(CustomBaseModel): - service_id: int - resource: str - action: str +class IAMDeletePermissionRequest(PermIDMixin): + pass class IAMGetPermissionsSearchRequest(CustomBaseModel): service_id: Optional[int] = None