feat: iam dependencies
IAM endpoints now use dependencies to perform most initial database get requests. Issue #6
This commit is contained in:
parent
d4f1b73deb
commit
c6a2b301dc
4 changed files with 100 additions and 61 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
"""
|
"""
|
||||||
Router dependencies for <this module>
|
Router dependencies for the IAM module
|
||||||
|
|
||||||
Classes:
|
Classes:
|
||||||
- List: Description
|
- List: Description
|
||||||
|
|
@ -9,3 +9,48 @@ Functions:
|
||||||
- List: Description
|
- List: Description
|
||||||
- Functions: Description
|
- Functions: Description
|
||||||
"""
|
"""
|
||||||
|
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)]
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,28 @@
|
||||||
"""
|
"""
|
||||||
Module specific exceptions for <this module>
|
Module specific exceptions for the IAM module
|
||||||
|
|
||||||
Exceptions:
|
Exceptions:
|
||||||
- List: Description
|
- List: Description
|
||||||
- Exceptions: Description
|
- Exceptions: Description
|
||||||
"""
|
"""
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ from src.iam.schemas import IAMGetGroupPermissionsResponse, IAMGetGroupUsersResp
|
||||||
IAMPostPermissionResponse, PermissionResponse, IAMDeletePermissionRequest, IAMGetPermissionsSearchRequest, IAMGetPermissionsSearchResponse
|
IAMPostPermissionResponse, PermissionResponse, IAMDeletePermissionRequest, IAMGetPermissionsSearchRequest, IAMGetPermissionsSearchResponse
|
||||||
from src.schemas import ResourceName
|
from src.schemas import ResourceName
|
||||||
from src.auth.service import claims_dependency
|
from src.auth.service import claims_dependency
|
||||||
|
from src.user.exceptions import UserNotFoundException
|
||||||
from src.user.models import User
|
from src.user.models import User
|
||||||
from src.organisation.models import Organisation as Org
|
from src.organisation.models import Organisation as Org
|
||||||
from src.service.models import Service
|
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.service import service_key_dependency
|
||||||
from src.iam.models import Permission as Perm, GroupPermissions as GPerms, Group, UserGroups
|
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(
|
router = APIRouter(
|
||||||
tags=["IAM"],
|
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)
|
@router.get("/group/permissions", response_model=IAMGetGroupPermissionsResponse)
|
||||||
async def get_group_permissions(db: db_dependency, group_id: Annotated[int, Query(gt=0)]):
|
async def get_group_permissions(db: db_dependency, group_model: group_model_query_dependency):
|
||||||
# TODO: root_user_dependency & org_id query param
|
# TODO: root_user_dependency
|
||||||
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")
|
|
||||||
|
|
||||||
return {"permissions": group_model.permission_rel}
|
return {"permissions": group_model.permission_rel}
|
||||||
|
|
||||||
|
|
||||||
@router.get("/group/users", response_model=IAMGetGroupUsersResponse)
|
@router.get("/group/users", response_model=IAMGetGroupUsersResponse)
|
||||||
async def get_group_users(db: db_dependency, group_id: Annotated[int, Query(gt=0)]):
|
async def get_group_users(db: db_dependency, group_model: group_model_query_dependency):
|
||||||
# TODO: root_user_dependency & org_id query param
|
# TODO: root_user_dependency
|
||||||
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")
|
|
||||||
|
|
||||||
return {"users": group_model.user_rel}
|
return {"users": group_model.user_rel}
|
||||||
|
|
||||||
|
|
||||||
@router.post("/group", response_model=IAMPostGroupResponse)
|
@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)]):
|
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: 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)
|
group_model = Group(name=group_request.name, org_id=org_id)
|
||||||
|
|
||||||
db.add(group_model)
|
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)
|
@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
|
# 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)
|
group_model.permission_rel.append(perm_model)
|
||||||
|
|
||||||
db.flush()
|
db.flush()
|
||||||
|
|
@ -114,14 +102,12 @@ async def add_group_permission(db: db_dependency, request_model: IAMPutGroupPerm
|
||||||
|
|
||||||
|
|
||||||
@router.put("/group/user")
|
@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
|
# TODO: root_user_dependency
|
||||||
group_model = db.get(Group, request_model.group_id)
|
# TODO: user_model_dependency
|
||||||
if group_model is None:
|
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Group not found")
|
|
||||||
user_model = db.get(User, request_model.user_id)
|
user_model = db.get(User, request_model.user_id)
|
||||||
if user_model is None:
|
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)
|
group_model.user_rel.append(user_model)
|
||||||
db.flush()
|
db.flush()
|
||||||
|
|
@ -131,15 +117,8 @@ async def add_group_user(db: db_dependency, request_model: IAMPutGroupUserReques
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/group/permissions")
|
@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
|
# 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)
|
group_model.permission_rel.remove(perm_model)
|
||||||
db.flush()
|
db.flush()
|
||||||
response = IAMDeleteGroupPermissionResponse(group=GroupResponse(**group_model.__dict__),
|
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")
|
@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
|
# TODO: root_user_dependency
|
||||||
group_model = db.get(Group, request_model.group_id)
|
# TODO: User model dependency
|
||||||
if group_model is None:
|
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Group not found")
|
|
||||||
user_model = db.get(User, request_model.user_id)
|
user_model = db.get(User, request_model.user_id)
|
||||||
if user_model is None:
|
if user_model is None:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
|
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)
|
@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
|
# TODO: root_user_dependency
|
||||||
permission_models = db.query(Perm).all()
|
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)
|
@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
|
# 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.delete(perm_model)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,12 @@ class GroupResponse(CustomBaseModel):
|
||||||
id: int
|
id: int
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
|
class GroupIDMixin(CustomBaseModel):
|
||||||
|
group_id: int
|
||||||
|
|
||||||
|
class PermIDMixin(CustomBaseModel):
|
||||||
|
permission_id: int
|
||||||
|
|
||||||
class IAMGetGroupPermissionsResponse(CustomBaseModel):
|
class IAMGetGroupPermissionsResponse(CustomBaseModel):
|
||||||
permissions: list[PermissionResponse]
|
permissions: list[PermissionResponse]
|
||||||
|
|
||||||
|
|
@ -42,32 +48,28 @@ class IAMPostGroupRequest(CustomBaseModel):
|
||||||
class IAMPostGroupResponse(CustomBaseModel):
|
class IAMPostGroupResponse(CustomBaseModel):
|
||||||
group: GroupResponse
|
group: GroupResponse
|
||||||
|
|
||||||
class IAMPutGroupPermissionRequest(CustomBaseModel):
|
class IAMPutGroupPermissionRequest(GroupIDMixin, PermIDMixin):
|
||||||
group_id: int
|
pass
|
||||||
permission_id: int
|
|
||||||
|
|
||||||
class IAMPutGroupPermissionResponse(CustomBaseModel):
|
class IAMPutGroupPermissionResponse(CustomBaseModel):
|
||||||
group: GroupResponse
|
group: GroupResponse
|
||||||
permissions: list[PermissionResponse]
|
permissions: list[PermissionResponse]
|
||||||
|
|
||||||
class IAMPutGroupUserRequest(CustomBaseModel):
|
class IAMPutGroupUserRequest(GroupIDMixin):
|
||||||
group_id: int
|
|
||||||
user_id: int
|
user_id: int
|
||||||
|
|
||||||
class IAMPutGroupUserResponse(CustomBaseModel):
|
class IAMPutGroupUserResponse(CustomBaseModel):
|
||||||
group: GroupResponse
|
group: GroupResponse
|
||||||
users: list[UserResponse]
|
users: list[UserResponse]
|
||||||
|
|
||||||
class IAMDeleteGroupPermissionRequest(CustomBaseModel):
|
class IAMDeleteGroupPermissionRequest(GroupIDMixin, PermIDMixin):
|
||||||
group_id: int
|
pass
|
||||||
permission_id: int
|
|
||||||
|
|
||||||
class IAMDeleteGroupPermissionResponse(CustomBaseModel):
|
class IAMDeleteGroupPermissionResponse(CustomBaseModel):
|
||||||
group: GroupResponse
|
group: GroupResponse
|
||||||
permissions: list[PermissionResponse]
|
permissions: list[PermissionResponse]
|
||||||
|
|
||||||
class IAMDeleteGroupUserRequest(CustomBaseModel):
|
class IAMDeleteGroupUserRequest(GroupIDMixin):
|
||||||
group_id: int
|
|
||||||
user_id: int
|
user_id: int
|
||||||
|
|
||||||
class IAMDeleteGroupUserResponse(CustomBaseModel):
|
class IAMDeleteGroupUserResponse(CustomBaseModel):
|
||||||
|
|
@ -85,10 +87,8 @@ class IAMPostPermissionRequest(CustomBaseModel):
|
||||||
class IAMPostPermissionResponse(CustomBaseModel):
|
class IAMPostPermissionResponse(CustomBaseModel):
|
||||||
permission: PermissionResponse
|
permission: PermissionResponse
|
||||||
|
|
||||||
class IAMDeletePermissionRequest(CustomBaseModel):
|
class IAMDeletePermissionRequest(PermIDMixin):
|
||||||
service_id: int
|
pass
|
||||||
resource: str
|
|
||||||
action: str
|
|
||||||
|
|
||||||
class IAMGetPermissionsSearchRequest(CustomBaseModel):
|
class IAMGetPermissionsSearchRequest(CustomBaseModel):
|
||||||
service_id: Optional[int] = None
|
service_id: Optional[int] = None
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue