From bdba903db16aece22731b1855ca3bc8e6d25f44e Mon Sep 17 00:00:00 2001 From: luxferre Date: Wed, 10 Jun 2026 10:15:27 +0100 Subject: [PATCH] feat: deleted owned org endpoint --- src/organisation/constants.py | 4 ++++ src/organisation/dependencies.py | 1 + src/organisation/router.py | 36 +++++++++++++++++++++++++++++++- test/test_organisation.py | 10 +++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/organisation/constants.py b/src/organisation/constants.py index 79c22fd..da4d60e 100644 --- a/src/organisation/constants.py +++ b/src/organisation/constants.py @@ -29,6 +29,10 @@ class Status(StrEnum): REJECTED = auto() REMOVED = auto() + @property + def is_pre_approval(self): + return self in (self.PARTIAL, self.SUBMITTED) + class ContactType(StrEnum): """ diff --git a/src/organisation/dependencies.py b/src/organisation/dependencies.py index 35b09fc..5ad9e0d 100644 --- a/src/organisation/dependencies.py +++ b/src/organisation/dependencies.py @@ -32,6 +32,7 @@ def get_org_model(db: Session, request: Request, org_id: int): f"GET{root}/org", f"GET{root}/org/contact", f"PATCH{root}/org/contact", + f"DELETE{root}/org/self", ] current_request = f"{request.method}{request.url.path}" if ( diff --git a/src/organisation/router.py b/src/organisation/router.py index 0f3e62b..96c59e1 100644 --- a/src/organisation/router.py +++ b/src/organisation/router.py @@ -22,6 +22,7 @@ from fastapi import APIRouter, status from fastapi.params import Query from sqlalchemy.exc import IntegrityError +from src.auth.exceptions import UnauthorizedException from src.contact.schemas import ContactModel from src.exceptions import UnprocessableContentException, ConflictException from src.contact.models import Contact @@ -43,7 +44,7 @@ from src.organisation.dependencies import ( org_model_body_dependency, org_model_query_dependency, ) -from src.organisation.constants import ContactType +from src.organisation.constants import ContactType, Status as StatusEnum from src.organisation.models import Organisation as Org from src.organisation.schemas import ( OrgPostOrgRequest, @@ -346,6 +347,39 @@ async def delete_organisation_by_id( db.commit() +@router.delete( + "/self", + summary="Delete organisation from the hub as root user before it has been approved.", + 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 root user." + }, + status.HTTP_422_UNPROCESSABLE_CONTENT: { + "description": "Org ID missing or invalid." + }, + }, +) +async def delete_preapproved_organisation_by_id( + db: db_dependency, + org_model: org_model_root_claim_query_dependency, +): + """ + Removes an organisation from the hub before it has been approved, if user is root. + """ + org_status = StatusEnum(org_model.status) + if not org_status.is_pre_approval: + raise UnauthorizedException( + message="Organisation is no longer in pre-approval state." + ) + + db.delete(org_model) + db.commit() + + @router.patch( "/root_user", summary="Update the root user of the organisation.", diff --git a/test/test_organisation.py b/test/test_organisation.py index d63213f..69e3eac 100644 --- a/test/test_organisation.py +++ b/test/test_organisation.py @@ -572,3 +572,13 @@ async def test_delete_org_users_success(db_session, default_client: AsyncClient) resp = await default_client.delete("/org/user?org_id=1&user_id=2") assert resp.status_code == 204 + + +@pytest.mark.anyio +async def test_delete_preapproval_org_success(db_session, default_client: AsyncClient): + org_model = db_session.get(Organisation, 1) + org_model.status = "partial" + db_session.flush() + resp = await default_client.delete("/org/self?org_id=1") + + assert resp.status_code == 204