fix: create permission endpoint

Verifies service exists before attaching permission.

Response built manually because calculated properties are not handled by .__dict()__

Request model uses Service ID mixin.

Service ID mixin verifies ID > 0
This commit is contained in:
Chris Milne 2026-06-02 15:36:05 +01:00
parent 5d1606aa9d
commit ae0181c3ff
3 changed files with 13 additions and 9 deletions

View file

@ -19,6 +19,7 @@ from fastapi import APIRouter, status
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from psycopg import errors from psycopg import errors
from service.exceptions import ServiceNotFoundException
from src.exceptions import ConflictException from src.exceptions import ConflictException
from src.database import db_dependency from src.database import db_dependency
from src.schemas import ResourceName from src.schemas import ResourceName
@ -170,18 +171,21 @@ async def get_permissions(db: db_dependency, org_model: org_model_root_claim_que
return {"permissions": permission_models} return {"permissions": permission_models}
@router.post("/permission") @router.post("/permission", response_model=IAMPostPermissionResponse)
async def create_new_permission(db: db_dependency, su: super_admin_dependency, request_mode: IAMPostPermissionRequest): async def create_new_permission(db: db_dependency, su: super_admin_dependency, request_model: IAMPostPermissionRequest):
perm_model = Perm(**request_mode.__dict__) service_model = db.get(Service, request_model.service_id)
if service_model is None:
raise ServiceNotFoundException(service_id=request_model.service_id)
perm_model = Perm(**request_model.__dict__)
try: try:
db.add(perm_model) db.add(perm_model)
except IntegrityError as e: except IntegrityError as e:
if isinstance(e.orig, errors.UniqueViolation): if isinstance(e.orig, errors.UniqueViolation):
raise ConflictException(message="Permission already exists") raise ConflictException(message="Permission already exists")
db.flush() db.flush()
response = IAMPostPermissionResponse(permission=PermissionSchema(**perm_model.__dict__)) response = {"service_name": perm_model.service_name, "resource": perm_model.resource, "action": perm_model.action}
db.commit() db.commit()
return response return {"permission": response}
@router.delete("/permission", status_code=status.HTTP_204_NO_CONTENT) @router.delete("/permission", status_code=status.HTTP_204_NO_CONTENT)

View file

@ -10,6 +10,7 @@ from typing import Optional
from pydantic import EmailStr, ConfigDict, Field from pydantic import EmailStr, ConfigDict, Field
from src.service.schemas import ServiceIDMixin
from src.organisation.schemas import OrgIDMixin from src.organisation.schemas import OrgIDMixin
from src.schemas import CustomBaseModel from src.schemas import CustomBaseModel
from user.schemas import UserIDMixin from user.schemas import UserIDMixin
@ -83,8 +84,7 @@ class IAMDeleteGroupUserResponse(CustomBaseModel):
class IAMGetPermissionsResponse(CustomBaseModel): class IAMGetPermissionsResponse(CustomBaseModel):
permissions: list[PermissionSchema] permissions: list[PermissionSchema]
class IAMPostPermissionRequest(CustomBaseModel): class IAMPostPermissionRequest(ServiceIDMixin):
service_id: int
resource: str resource: str
action: str action: str

View file

@ -6,12 +6,12 @@ Models follow the nomenclature of:
- Mixins: "<Attribute>Mixin" - Mixins: "<Attribute>Mixin"
- Models: "<Module><Method><Resource><Opt:Resource><Direction>" ie "ServiceGetServiceResponse" - Models: "<Module><Method><Resource><Opt:Resource><Direction>" ie "ServiceGetServiceResponse"
""" """
from pydantic import ConfigDict from pydantic import ConfigDict, Field
from src.schemas import CustomBaseModel from src.schemas import CustomBaseModel
class ServiceIDMixin(CustomBaseModel): class ServiceIDMixin(CustomBaseModel):
service_id: int service_id: int = Field(gt=0)
class ServiceSchema(CustomBaseModel): class ServiceSchema(CustomBaseModel):
model_config = ConfigDict(from_attributes=True, extra="ignore") model_config = ConfigDict(from_attributes=True, extra="ignore")