From d3bdfe84699e51698bbf2c4758419212dfeee64f Mon Sep 17 00:00:00 2001 From: luxferre Date: Thu, 28 May 2026 16:43:39 +0100 Subject: [PATCH] docs: org router decorators Issue: #13 --- src/organisation/router.py | 122 +++++++++++++++++++++++++++++++++---- 1 file changed, 110 insertions(+), 12 deletions(-) diff --git a/src/organisation/router.py b/src/organisation/router.py index 2e71fba..8e5433c 100644 --- a/src/organisation/router.py +++ b/src/organisation/router.py @@ -47,7 +47,16 @@ router = APIRouter( ) -@router.get("/id", response_model=OrgGetOrgResponse) +@router.get("/id", + summary="Get org details by ID.", + response_model=OrgGetOrgResponse, + status_code=status.HTTP_200_OK, + responses={ + status.HTTP_200_OK: {"description": "Successful retrieval from database"}, + status.HTTP_404_NOT_FOUND: {"description": "Organisation not found"}, + status.HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Missing or invalid org_id query parameter"}, + status.HTTP_401_UNAUTHORIZED: {"description": "Not authorised. Must be org root user."}, + }) async def get_org_by_id(org_model: org_model_root_claim_query_dependency): response = { "name": org_model.name, @@ -61,8 +70,17 @@ async def get_org_by_id(org_model: org_model_root_claim_query_dependency): return response -@router.post("/") +@router.post("/", + summary="Create new organisation.", + status_code=status.HTTP_201_CREATED, + responses={ + status.HTTP_201_CREATED: {"description": "Successfully created organisation."}, + status.HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid data in request."}, + status.HTTP_401_UNAUTHORIZED: {"description": "User must be logged in with OIDC to create organisation."}, + status.HTTP_409_CONFLICT: {"description": "Organisation with this name already exists."}, + }) async def create_org(db: db_dependency, user_model: user_model_claims_dependency, request_model: OrgPostOrgRequest): + # TODO: Response model if request_model.intake_questionnaire: intake_questionnaire = request_model.intake_questionnaire.model_dump() else: @@ -88,13 +106,21 @@ async def create_org(db: db_dependency, user_model: user_model_claims_dependency db.commit() -@router.patch("/questionnaire") +@router.patch("/questionnaire", + summary="Update questionnaire.", + status_code=status.HTTP_200_OK, + responses={ + status.HTTP_200_OK: {"description": "Successfully updated questionnaire."}, + status.HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid data in request."}, + status.HTTP_401_UNAUTHORIZED: {"description": "Not authorised. Must be org root user."}, + }) async def update_questionnaire(db: db_dependency, org_model: org_model_root_claim_query_dependency, request_model: OrgPatchQuestionnaireRequest): """ Route for updating questionnaire. The partial bool allows for submission of partially completed questionnaire and/or final "are you sure" check before setting the org to be in "submitted" status, awaiting admin approval. """ + # TODO: Response model org_model.intake_questionnaire = request_model.intake_questionnaire.model_dump() # Allows for partially completed questionnaires to be saved without being submitted for review @@ -104,45 +130,101 @@ async def update_questionnaire(db: db_dependency, org_model: org_model_root_clai db.commit() -@router.patch("/status") +@router.patch("/status", + summary="Update status of organisation.", + status_code=status.HTTP_200_OK, + responses={ + status.HTTP_200_OK: {"description": "Successfully updated organisation status."}, + status.HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid data in request."}, + status.HTTP_401_UNAUTHORIZED: {"description": "Not authorised. Must be super admin."}, + }) async def update_status(db: db_dependency, org_model: org_model_body_dependency, su: super_admin_dependency, request_model: OrgPatchStatusRequest): + # TODO: Response model org_model.status = request_model.status db.commit() -@router.get("/users", response_model=OrgGetUserResponse) +@router.get("/users", + summary="Get email addresses of users of the organisation.", + status_code=status.HTTP_200_OK, + response_model=OrgGetUserResponse, + responses={ + status.HTTP_200_OK: {"description": "Successful retrieval of users."}, + status.HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Org ID missing or invalid."}, + status.HTTP_401_UNAUTHORIZED: {"description": "Not authorised. Must be org root user."}, + }) async def get_users(org_model: org_model_root_claim_query_dependency): return {"users": [user.email for user in org_model.user_rel]} -@router.post("/users") +@router.post("/users", + summary="All user to the organisation.", + status_code=status.HTTP_200_OK, + responses={ + status.HTTP_200_OK: {"description": "Successfully added user to the organisation."}, + status.HTTP_401_UNAUTHORIZED: {"description": "Not authorised. Must be org root user."}, + status.HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid data in request."}, + status.HTTP_409_CONFLICT: {"description": "User is already a member of the organisation."}, + }) async def add_user_to_org(db: db_dependency, org_model: org_model_root_claim_body_dependency, user_model: user_model_body_dependency, request_model: OrgPostUserRequest): + # TODO: response model if user_model in org_model.user_rel: raise Conflict(message="User already a part of this organisation") org_model.user_rel.append(user_model) db.commit() -@router.delete("/", status_code=status.HTTP_204_NO_CONTENT) +@router.delete("/", + summary="Delete organisation from the hub.", + status_code=status.HTTP_204_NO_CONTENT, + responses={ + status.HTTP_204_NO_CONTENT: {"description": "Successfully deleted organisation."}, + status.HTTP_401_UNAUTHORIZED: {"description": "Not authorised. Must be super admin."}, + status.HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Org ID missing or invalid."}, + }) async def delete_organisation_by_id(db: db_dependency, org_model: org_model_body_dependency, su: super_admin_dependency, request_model: OrgDeleteOrgRequest): db.delete(org_model) db.commit() -@router.patch("/root_user", status_code=status.HTTP_204_NO_CONTENT) +@router.patch("/root_user", + summary="Update the root user of the organisation.", + status_code=status.HTTP_200_OK, + responses={ + status.HTTP_200_OK: {"description": "Successfully updated root user."}, + status.HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid data in request."}, + status.HTTP_401_UNAUTHORIZED: {"description": "Not authorised. Must be super admin."}, + }) async def update_root_user(db: db_dependency, org_model: org_model_body_dependency, user_model: user_model_body_dependency, su: super_admin_dependency, request_model: OrgPatchRootRequest): + # TODO: response model org_model.root_user_rel = user_model db.commit() -@router.get("/groups", response_model=OrgGetGroupResponse) +@router.get("/groups", + summary="Get all organisation IAM groups.", + status_code=status.HTTP_200_OK, + response_model=OrgGetGroupResponse, + responses={ + status.HTTP_200_OK: {"description": "Successful retrieval of IAM groups."}, + status.HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Org ID missing or invalid."}, + status.HTTP_401_UNAUTHORIZED: {"description": "Not authorised. Must be org root user."}, + }) async def get_org_groups(org_model: org_model_root_claim_query_dependency): return {"groups": [group.name for group in org_model.group_rel]} -@router.delete("/user", status_code=status.HTTP_204_NO_CONTENT) +@router.delete("/user", + summary="Remove user from organisation.", + status_code=status.HTTP_204_NO_CONTENT, + responses={ + status.HTTP_204_NO_CONTENT: {"description": "Successfully removed user."}, + status.HTTP_401_UNAUTHORIZED: {"description": "Not authorised. Must be org root user."}, + status.HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid data in request."}, + }) async def remove_user_from_org(db: db_dependency, org_model: org_model_root_claim_body_dependency, user_model: user_model_body_dependency, request_model: OrgDeleteUserRequest): + # TODO: response model if user_model not in org_model.user_rel: return @@ -150,7 +232,15 @@ async def remove_user_from_org(db: db_dependency, org_model: org_model_root_clai db.commit() -@router.get("/contact", response_model=OrgGetContactResponse) +@router.get("/contact", + summary="Get contact for organisation.", + status_code=status.HTTP_200_OK, + response_model=OrgGetContactResponse, + responses={ + status.HTTP_200_OK: {"description": "Successful retrieval of contact."}, + status.HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid data in request."}, + status.HTTP_401_UNAUTHORIZED: {"description": "Not authorised. Must be org root user."}, + }) async def get_contact(org_model: org_model_root_claim_query_dependency, contact_type: Annotated[ContactType, Query()]): match contact_type: case "billing": @@ -171,7 +261,15 @@ async def get_contact(org_model: org_model_root_claim_query_dependency, contact_ return {"contact": contact_response} -@router.patch("/contact", response_model=OrgGetContactResponse) +@router.patch("/contact", + summary="Update contact for organisation.", + status_code=status.HTTP_200_OK, + response_model=OrgGetContactResponse, + responses={ + status.HTTP_200_OK: {"description": "Successfully updated contact."}, + status.HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid data in request."}, + status.HTTP_401_UNAUTHORIZED: {"description": "Not authorised. Must be org root user."}, + }) async def update_contact(db: db_dependency, org_model: org_model_root_claim_body_dependency, request_model: OrgPatchContactRequest): match request_model.contact_type: case "billing":