diff --git a/src/exceptions.py b/src/exceptions.py index 5d90f95..83099e0 100644 --- a/src/exceptions.py +++ b/src/exceptions.py @@ -13,3 +13,12 @@ class UnprocessableContent(HTTPException): status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, detail=detail, ) + + +class Conflict(HTTPException): + def __init__(self, message: Optional[str] = None) -> None: + detail = "Conflict" if not message else message + super().__init__( + status_code=status.HTTP_409_CONFLICT, + detail=detail, + ) diff --git a/src/iam/router.py b/src/iam/router.py index a87baf0..4b2bbb4 100644 --- a/src/iam/router.py +++ b/src/iam/router.py @@ -6,8 +6,10 @@ Endpoints: - Endpoints: Description """ from fastapi import APIRouter, status +from sqlalchemy.exc import IntegrityError +from psycopg import errors - +from src.exceptions import Conflict from src.database import db_dependency from src.schemas import ResourceName from src.auth.exceptions import UnauthorizedException @@ -84,7 +86,11 @@ async def create_group(db: db_dependency, org_model: org_model_root_claim_body_d group_model = Group(name=request_model.name, org_id=org_model.id) db.add(group_model) - db.flush() + try: + db.flush() + except IntegrityError as e: + if isinstance(e.orig, errors.UniqueViolation): + raise Conflict("Group with this name already exists") response = GroupResponse(**group_model.__dict__) db.commit() return {"group": response} @@ -95,6 +101,9 @@ async def add_group_permission(db: db_dependency, group_model: group_model_body_ if group_model.org_id == org_model.id: raise UnauthorizedException() + if perm_model in group_model.permission_rel: + raise Conflict("Group already has this permission") + group_model.permission_rel.append(perm_model) db.flush() @@ -108,6 +117,9 @@ async def add_group_user(db: db_dependency, group_model: group_model_body_depend if group_model.org_id == org_model.id: raise UnauthorizedException() + if user_model in group_model.user_rel: + raise Conflict("User already in group") + group_model.user_rel.append(user_model) db.flush() response = IAMPutGroupUserResponse(group=GroupResponse(**group_model.__dict__), users=group_model.user_rel) @@ -151,8 +163,11 @@ async def get_permissions(db: db_dependency, org_model: org_model_root_claim_bod @router.post("/permission") async def create_new_permission(db: db_dependency, su: super_admin_dependency, request_mode: IAMPostPermissionRequest): perm_model = Perm(**request_mode.__dict__) - - db.add(perm_model) + try: + db.add(perm_model) + except IntegrityError as e: + if isinstance(e.orig, errors.UniqueViolation): + raise Conflict(message="Permission already exists") db.flush() response = IAMPostPermissionResponse(permission=PermissionResponse(**perm_model.__dict__)) db.commit() diff --git a/src/organisation/router.py b/src/organisation/router.py index 0811457..e1193f0 100644 --- a/src/organisation/router.py +++ b/src/organisation/router.py @@ -16,8 +16,10 @@ from typing import Annotated, Optional from fastapi import APIRouter, status from fastapi.params import Query +from psycopg.errors import UniqueViolation +from sqlalchemy.exc import IntegrityError -from src.exceptions import UnprocessableContent +from src.exceptions import UnprocessableContent, Conflict from src.contact.models import Contact from src.contact.schemas import ContactAddress from src.contact.exceptions import ContactNotFoundException @@ -66,9 +68,12 @@ async def create_org(db: db_dependency, user_model: user_model_claims_dependency org_model.status = "partial" # Status is always set to partial at first, see update_questionnaire() doc db.add(org_model) - db.flush() + try: + db.flush() + except IntegrityError as e: + if isinstance(e.orig, UniqueViolation): + raise Conflict(message="Organisation with this name already exists") # Adds currently logged-in user to org users list and sets them as root_user - user_model = db.get(User, db_id) org_model.user_rel.append(user_model) org_model.root_user_rel = user_model for contact_type in ["billing_contact_id", "security_contact_id", "owner_contact_id"]: @@ -110,7 +115,7 @@ async def get_users(org_model: org_model_root_claim_query_dependency): @router.post("/users") 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: OrgUserPostRequest): if user_model in org_model.user_rel: - return + raise Conflict(message="User already a part of this organisation") org_model.user_rel.append(user_model) db.commit() diff --git a/src/service/router.py b/src/service/router.py index f380d8a..a90a540 100644 --- a/src/service/router.py +++ b/src/service/router.py @@ -6,7 +6,11 @@ Endpoints: - Endpoints: Description """ from fastapi import APIRouter, status +from psycopg.errors import UniqueViolation +from sqlalchemy.exc import IntegrityError +from auth.exceptions import UnauthorizedException +from exceptions import Conflict from src.database import db_dependency from src.auth.service import claims_dependency from src.auth.dependencies import super_admin_dependency, org_model_root_claim_query_dependency, org_model_root_claim_body_dependency @@ -34,7 +38,12 @@ async def register_service(db: db_dependency, su: super_admin_dependency, servic service_model = Service(name=service_request.name, api_key=key) db.add(service_model) - db.flush() + try: + db.flush() + except IntegrityError as e: + if isinstance(e.orig, UniqueViolation): + raise Conflict(message="Service with this name already exists") + db.commit() response = ServiceWithKeyResponse(**service_model.__dict__) db.commit() return {"service": response}