Compare commits

...

12 commits

Author SHA1 Message Date
71f26a4c9b feat: example .env 2026-05-28 14:32:08 +01:00
00dcf7ce35 minor: service schema nomenclature 2026-05-28 14:27:14 +01:00
33e78d4a9b docs: org docstrings
issue: #13
2026-05-28 14:23:36 +01:00
82c2b13a7f minor: contact endpoints allowed preapproval 2026-05-28 14:05:31 +01:00
9a1975c389 minor: iam schema nomenclature 2026-05-28 13:37:32 +01:00
7a0f43d34f minor: org schema nomenclature 2026-05-28 13:32:59 +01:00
0e169af456 docs: iam docstrings
Issue: #13
2026-05-28 13:22:24 +01:00
0c1c9f62ee fix: permission dependency 2026-05-28 13:19:54 +01:00
39d3f2d560 docs: contact docstrings
Issue: #13
2026-05-28 11:22:47 +01:00
42349b0182 docs: auth docstrings
Issue: #13
2026-05-28 11:22:47 +01:00
a86cfea65a minor: type hint 2026-05-28 11:22:37 +01:00
d8abe17618 docs: admin module docstrings
Issue: #13
2026-05-28 11:22:37 +01:00
48 changed files with 168 additions and 284 deletions

10
example.env Normal file
View file

@ -0,0 +1,10 @@
SECRET_KEY=""
OIDC_CONFIG="https://sso.sr2.uk/realms/sr2/.well-known/openid-configuration"
OIDC_ISSUER="https://sso.sr2.uk/realms/sr2"
OIDC_AUDIENCE="account"
CLIENT_ID=""
DATABASE_NAME="cloud-api"
DATABASE_PORT="5432"
DATABASE_HOSTNAME="localhost"
DATABASE_CREDENTIALS="user:password"

View file

@ -1,7 +1,3 @@
"""
Configurations for the admin module
Configurations:
- List: Description
- Configs: Description
"""

View file

@ -1,7 +1,3 @@
"""
Constants and error codes for the admin module
Constants:
- List: Description
- Consts: Description
Constants for the admin module
"""

View file

@ -1,11 +1,3 @@
"""
Router dependencies for the admin module
Classes:
- List: Description
- Classes: Description
Functions:
- List: Description
- Functions: Description
Dependencies for the admin module
"""

View file

@ -1,7 +1,3 @@
"""
Module specific exceptions for the admin module
Exceptions:
- List: Description
- Exceptions: Description
Custom exceptions for the admin module
"""

View file

@ -1,7 +1,3 @@
"""
Database models for the admin module
Models:
- List: Description
- Models: Description
"""

View file

@ -1,9 +1,8 @@
"""
Router endpoints for the admin module
Endpoints:
- List: Description
- Endpoints: Description
Exports:
- router: fastapi.APIRouter
"""
from fastapi import APIRouter

View file

@ -1,7 +1,3 @@
"""
Pydantic models for the admin module
Models:
- List: Description
- Models: Description
"""

View file

@ -1,11 +1,3 @@
"""
Module specific business logic for the admin module
Classes:
- List: Description
- Classes: Description
Functions:
- List: Description
- Functions: Description
"""

View file

@ -1,11 +1,3 @@
"""
Non-business logic reusable functions and classes for the admin module
Classes:
- List: Description
- Classes: Description
Functions:
- List: Description
- Functions: Description
"""

View file

@ -1,9 +1,8 @@
"""
Configurations for auth module, import auth_settings
Configurations for the auth module
Configurations:
- List: Description
- Configs: Description
Exports:
- auth_settings: Contains OIDC information
"""
from src.config import CustomBaseSettings

View file

@ -1,7 +1,3 @@
"""
Constants and error codes for auth module
Constants:
- List: Description
- Consts: Description
Constants for the auth module
"""

View file

@ -1,18 +1,17 @@
"""
Router dependencies for auth module
Auth dependencies
Classes:
- List: Description
- Classes: Description
Functions:
- List: Description
- Functions: Description
Exports:
- org_query_user_claims_dependency: bool: Verifies user belongs to org
- org_model_root_claim_query_dependency: org_model: verifies org exists and user is either root or su, gets org from query
- org_model_root_claim_body_dependency: org_model: verifies org exists and user is either root or su, gets org from body
- super_admin_dependency: user_model: verifies the user is a super admin
"""
from typing import Annotated
from fastapi import Depends
from src.user.dependencies import user_model_claims_dependency
from src.user.models import User
from src.organisation.dependencies import org_model_query_dependency, org_model_body_dependency
from src.organisation.models import Organisation as Org
@ -69,4 +68,4 @@ async def user_model_super_admin(user_model: user_model_claims_dependency):
raise UnauthorizedException()
super_admin_dependency = Annotated[bool, Depends(user_model_super_admin)]
super_admin_dependency = Annotated[type[User], Depends(user_model_super_admin)]

View file

@ -1,9 +1,8 @@
"""
Module specific exceptions for auth module
Module specific exceptions for the auth module
Exceptions:
- List: Description
- Exceptions: Description
- UnauthorizedException: Takes an optional message string
"""
from typing import Optional

View file

@ -1,7 +1,3 @@
"""
Database models for auth module
Models:
- List: Description
- Models: Description
Database models for the auth module
"""

View file

@ -1,8 +1,8 @@
"""
Router endpoints for auth module
Contains oauth registration
Router endpoints for the auth module
Endpoints:
Exports:
- router: fastapi.APIRouter
"""
from fastapi import APIRouter

View file

@ -1,7 +1,3 @@
"""
Pydantic models for auth module
Models:
- List: Description
- Models: Description
Pydantic models for the auth module
"""

View file

@ -1,8 +1,8 @@
"""
Module specific business logic for auth module
Module specific business logic for the auth module
Exports:
- claims_dependency
- claims_dependency: Dict[str, Any] containing OIDC claims and database ID
"""
import json
import requests

View file

@ -1,11 +1,3 @@
"""
Non-business logic reusable functions and classes for auth module
Classes:
- List: Description
- Classes: Description
Functions:
- List: Description
- Functions: Description
Non-business logic reusable functions and classes for the auth module
"""

View file

@ -1,7 +1,3 @@
"""
Configurations for contact module
Configurations:
- List: Description
- Configs: Description
Configurations for the contact module
"""

View file

@ -1,7 +1,3 @@
"""
Constants and error codes for contact module
Constants:
- List: Description
- Consts: Description
Constants for the contact module
"""

View file

@ -1,11 +1,3 @@
"""
Router dependencies for contact module
Classes:
- List: Description
- Classes: Description
Functions:
- List: Description
- Functions: Description
Dependencies for the contact module
"""

View file

@ -1,9 +1,8 @@
"""
Module specific exceptions for contact module
Exceptions related to the contact module
Exceptions:
- List: Description
- Exceptions: Description
Exports:
- ContactNotFoundException: Takes an optional contact ID int
"""
from typing import Optional

View file

@ -1,9 +1,9 @@
"""
Database models for contact module
Database models for the contact module
Models:
- Contact: id[pk], email, first_name, last_name, phonenumber, vat_number
street_address, post_office_box_number, address_locality, country_code, address_region, postal_code
street_address, street_address_line_2, post_office_box_number, address_locality, country_code, address_region, postal_code
"""
from sqlalchemy import Column, Integer, String, ForeignKey

View file

@ -1,13 +1,5 @@
"""
Router endpoints for contact module
Endpoints:
- [get]/{contact_id} - Returns non-address type details for contact
- [get]/{contact_id}/address - Returns address details for contact
- [get]/{contact_id}/orgs - Returns a list of orgs which the contact is assigned to, and what they are assigned as
- [post]/ - Creates a new contact
- [patch]/{contact_id} - Updates the details of an existing contact
- [delete]/{contact_id} - Deletes a contact by ID
Router endpoints for the contact module
"""
from fastapi import APIRouter

View file

@ -1,9 +1,9 @@
"""
Pydantic models for contact module
Pydantic models for the contact module
Models:
- List: Description
- Models: Description
- ContactAddress
- ContactModel: Contains ContactAddress as a property
"""
from typing import Optional

View file

@ -1,11 +1,3 @@
"""
Module specific business logic for contact module
Classes:
- List: Description
- Classes: Description
Functions:
- List: Description
- Functions: Description
Module specific business logic for the contact module
"""

View file

@ -1,11 +1,3 @@
"""
Non-business logic reusable functions and classes for contact module
Classes:
- List: Description
- Classes: Description
Functions:
- List: Description
- Functions: Description
Non-business logic reusable functions and classes for the contact module
"""

View file

@ -1,7 +1,3 @@
"""
Configurations for <this module>
Configurations:
- List: Description
- Configs: Description
Configurations for the IAM module
"""

View file

@ -1,7 +1,3 @@
"""
Constants and error codes for <this module>
Constants:
- List: Description
- Consts: Description
Constants for the IAM module
"""

View file

@ -1,13 +1,10 @@
"""
Router dependencies for the IAM module
Dependencies for the IAM module
Classes:
- List: Description
- Classes: Description
Functions:
- List: Description
- Functions: Description
Exports:
- group_model_query_dependency: group_model: Gets group model from db, if it exists. Uses group_id from query param.
- group_model_body_dependency: group_model: Gets group model from db, if it exists. Uses group_id from request body.
- perm_model_body_dependency: perm_model: Gets perm model from db, if it exists. Uses perm_id from request body.
"""
from typing import Annotated, Optional
@ -15,7 +12,7 @@ from fastapi import Depends, Query
from src.database import db_dependency
from src.iam.models import Group
from src.iam.models import Group, Permission
from src.iam.exceptions import GroupNotFoundException, PermNotFoundException
from src.iam.schemas import GroupIDMixin, PermIDMixin
@ -43,14 +40,14 @@ def get_group_model_body(db: db_dependency, request_model: Optional[GroupIDMixin
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]:
def get_perm_model_body(db: db_dependency, request_model: Optional[PermIDMixin] = None) -> type[Permission]:
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:
perm_model = db.get(Permission, perm_id)
if perm_model is None:
raise PermNotFoundException(perm_id)
return group_model
return perm_model
perm_model_body_dependency = Annotated[type[Group], Depends(get_perm_model_body)]
perm_model_body_dependency = Annotated[type[Permission], Depends(get_perm_model_body)]

View file

@ -1,9 +1,9 @@
"""
Module specific exceptions for the IAM module
Exceptions related to the IAM module
Exceptions:
- List: Description
- Exceptions: Description
- GroupNotFoundException: Takes an optional group_id int
- PermNotFoundException: Takes an optional perm_id int
"""
from typing import Optional

View file

@ -2,8 +2,11 @@
Database models for the IAM module
Models:
- List: Description
- Models: Description
- Permission:
- id[PK], resource[U1], action[U1], service_id[FK][U1]
- service_rel: ORM relationship over service_id FK
- group_rel: ORM relationship backpops to Group.permission_rel
- service_name: Calc property service_rel.name
"""
from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint
from sqlalchemy.orm import relationship

View file

@ -1,9 +1,19 @@
"""
Router endpoints for <this module>
Router endpoints for IAM
Endpoints:
- List: Description
- Endpoints: Description
- [POST](/iam/can_act_on_resource): [API key & user claim]: Service access point to verify user permissions
- [GET](/iam/group/permissions): [root user]: Gets list of perms(service, resource, action) the given group(id) has
- [DELETE](/iam/group/permissions): [root user]: Removes a given perm(id) from the given group(id)
- [GET](/iam/group/users): [root user]: Gets a list of users(id, name, email) that are assigned to the given group(id)
- [POST](/iam/group): [root user]: Creates a new group for the given org(id)
- [PUT](/iam/group/permission): [root user]: Assigns a perm(id) to the given group(id)
- [PUT](/iam/group/user): [root user]: Assigns a user(id) to a group(id)
- [DELETE](/iam/group/user): [root user]: Removes a user(id) from the given group(id)
- [GET](/iam/permissions): [root user]: Gets a list of all permissions
- [POST](/iam/permission): [super admin]: Creates a new permission
- [DELETE](/iam/permission): [super admin]: Removes a permission
- [GET](/iam/permissions/search): [root user]: Returns a list of permissions matching a filter(service|resource|action)
"""
from fastapi import APIRouter, status
from sqlalchemy.exc import IntegrityError
@ -25,10 +35,10 @@ from src.iam.service import service_key_dependency
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
from src.iam.schemas import IAMGetGroupPermissionsResponse, IAMGetGroupUsersResponse, IAMPostGroupRequest, \
GroupResponse, IAMPostGroupResponse, IAMPutGroupPermissionRequest, IAMPutGroupPermissionResponse, \
GroupSchema, IAMPostGroupResponse, IAMPutGroupPermissionRequest, IAMPutGroupPermissionResponse, \
IAMPutGroupUserRequest, IAMPutGroupUserResponse, IAMDeleteGroupPermissionRequest, IAMDeleteGroupPermissionResponse, \
IAMDeleteGroupUserRequest, IAMDeleteGroupUserResponse, IAMGetPermissionsResponse, IAMPostPermissionRequest, \
IAMPostPermissionResponse, PermissionResponse, IAMDeletePermissionRequest, IAMGetPermissionsSearchRequest, IAMGetPermissionsSearchResponse
IAMPostPermissionResponse, PermissionSchema, IAMDeletePermissionRequest, IAMGetPermissionsSearchRequest, IAMGetPermissionsSearchResponse
router = APIRouter(
tags=["IAM"],
@ -91,7 +101,7 @@ async def create_group(db: db_dependency, org_model: org_model_root_claim_body_d
except IntegrityError as e:
if isinstance(e.orig, errors.UniqueViolation):
raise Conflict("Group with this name already exists")
response = GroupResponse(**group_model.__dict__)
response = GroupSchema(**group_model.__dict__)
db.commit()
return {"group": response}
@ -107,7 +117,7 @@ async def add_group_permission(db: db_dependency, group_model: group_model_body_
group_model.permission_rel.append(perm_model)
db.flush()
response = IAMPutGroupPermissionResponse(group=GroupResponse(**group_model.__dict__), permissions=group_model.permission_rel)
response = IAMPutGroupPermissionResponse(group=GroupSchema(**group_model.__dict__), permissions=group_model.permission_rel)
db.commit()
return response
@ -122,7 +132,7 @@ async def add_group_user(db: db_dependency, group_model: group_model_body_depend
group_model.user_rel.append(user_model)
db.flush()
response = IAMPutGroupUserResponse(group=GroupResponse(**group_model.__dict__), users=group_model.user_rel)
response = IAMPutGroupUserResponse(group=GroupSchema(**group_model.__dict__), users=group_model.user_rel)
db.commit()
return response
@ -134,8 +144,8 @@ async def remove_group_permissions(db: db_dependency, group_model: group_model_b
group_model.permission_rel.remove(perm_model)
db.flush()
response = IAMDeleteGroupPermissionResponse(group=GroupResponse(**group_model.__dict__),
permissions=group_model.permission_rel)
response = IAMDeleteGroupPermissionResponse(group=GroupSchema(**group_model.__dict__),
permissions=group_model.permission_rel)
db.commit()
return response
@ -147,7 +157,7 @@ async def remove_group_user(db: db_dependency, group_model: group_model_body_dep
user_model.group_rel.remove(group_model)
db.flush()
response = IAMDeleteGroupUserResponse(group=GroupResponse(**group_model.__dict__), users=group_model.user_rel)
response = IAMDeleteGroupUserResponse(group=GroupSchema(**group_model.__dict__), users=group_model.user_rel)
db.commit()
return response
@ -169,7 +179,7 @@ async def create_new_permission(db: db_dependency, su: super_admin_dependency, r
if isinstance(e.orig, errors.UniqueViolation):
raise Conflict(message="Permission already exists")
db.flush()
response = IAMPostPermissionResponse(permission=PermissionResponse(**perm_model.__dict__))
response = IAMPostPermissionResponse(permission=PermissionSchema(**perm_model.__dict__))
db.commit()
return response

View file

@ -1,9 +1,10 @@
"""
Pydantic models for the IAM module
Models:
- List: Description
- Models: Description
Models follow the nomenclature of:
- Sub-models: "<Resource><Opt:>Schema"
- Mixins: "<Attribute>Mixin"
- Models: "<Module><Method><Resource><Opt:Resource><Direction>" ie "IAMGetGroupPermissionsResponse"
"""
from typing import Optional
@ -14,20 +15,20 @@ from src.schemas import CustomBaseModel
from user.schemas import UserIDMixin
class UserResponse(CustomBaseModel):
class UserSchema(CustomBaseModel):
id: int
first_name: str
last_name: str
email: EmailStr
class PermissionResponse(CustomBaseModel):
class PermissionSchema(CustomBaseModel):
model_config = ConfigDict(from_attributes=True, extra="ignore")
service_name: str
resource: str
action: str
class GroupResponse(CustomBaseModel):
class GroupSchema(CustomBaseModel):
id: int
name: str
@ -38,47 +39,47 @@ class PermIDMixin(CustomBaseModel):
permission_id: int
class IAMGetGroupPermissionsResponse(CustomBaseModel):
permissions: list[PermissionResponse]
permissions: list[PermissionSchema]
class IAMGetGroupUsersResponse(CustomBaseModel):
users : list[UserResponse]
users : list[UserSchema]
class IAMPostGroupRequest(OrgIDMixin):
name: str
class IAMPostGroupResponse(CustomBaseModel):
group: GroupResponse
group: GroupSchema
class IAMPutGroupPermissionRequest(GroupIDMixin, PermIDMixin):
pass
class IAMPutGroupPermissionResponse(CustomBaseModel):
group: GroupResponse
permissions: list[PermissionResponse]
group: GroupSchema
permissions: list[PermissionSchema]
class IAMPutGroupUserRequest(GroupIDMixin, UserIDMixin):
pass
class IAMPutGroupUserResponse(CustomBaseModel):
group: GroupResponse
users: list[UserResponse]
group: GroupSchema
users: list[UserSchema]
class IAMDeleteGroupPermissionRequest(GroupIDMixin, PermIDMixin):
pass
class IAMDeleteGroupPermissionResponse(CustomBaseModel):
group: GroupResponse
permissions: list[PermissionResponse]
group: GroupSchema
permissions: list[PermissionSchema]
class IAMDeleteGroupUserRequest(GroupIDMixin, UserIDMixin):
pass
class IAMDeleteGroupUserResponse(CustomBaseModel):
group: GroupResponse
users: list[UserResponse]
group: GroupSchema
users: list[UserSchema]
class IAMGetPermissionsResponse(CustomBaseModel):
permissions: list[PermissionResponse]
permissions: list[PermissionSchema]
class IAMPostPermissionRequest(CustomBaseModel):
service_id: int
@ -86,7 +87,7 @@ class IAMPostPermissionRequest(CustomBaseModel):
action: str
class IAMPostPermissionResponse(CustomBaseModel):
permission: PermissionResponse
permission: PermissionSchema
class IAMDeletePermissionRequest(PermIDMixin):
pass
@ -97,4 +98,4 @@ class IAMGetPermissionsSearchRequest(CustomBaseModel):
action: Optional[str] = None
class IAMGetPermissionsSearchResponse(CustomBaseModel):
permissions: list[PermissionResponse]
permissions: list[PermissionSchema]

View file

@ -1,7 +1,8 @@
"""
Module specific business logic for <this module>
Business logic reusable functions related to IAM
Exports service_key_dependency
Exports:
- service_key_dependency: bool: verifies request headers contain the correct api key for the service
"""
from typing import Annotated

View file

@ -1,11 +1,3 @@
"""
Non-business logic reusable functions and classes for <this module>
Classes:
- List: Description
- Classes: Description
Functions:
- List: Description
- Functions: Description
Non-business logic reusable functions and classes for the IAM module
"""

View file

@ -1,7 +1,3 @@
"""
Configurations for organisation module
Configurations:
- List: Description
- Configs: Description
Configurations for the organisation module
"""

View file

@ -1,5 +1,5 @@
"""
Constants and error codes for organisation module
Constants for the organisation module
Classes:
- Status(StrEnum): PARTIAL, SUBMITTED, REMEDIATION, APPROVED, REJECTED, REMOVED

View file

@ -1,13 +1,9 @@
"""
Router dependencies for organisation module
Dependencies related to the organisation module
Classes:
- List: Description
- Classes: Description
Functions:
- List: Description
- Functions: Description
Exports:
- org_model_query_dependency: org_model: Gets org model from db, if it exists. Uses org_id from query param. Also verifies if the org has been approved.
- org_model_body_dependency: org_model: Gets org model from db, if it exists. Uses org_id from request body. Also verifies if the org has been approved.
"""
from typing import Annotated, Optional
@ -26,7 +22,7 @@ def get_org_model(db, request: Request, org_id: int):
if org_model is None:
raise OrgNotFoundException(org_id)
pre_approval_endpoints = ["PATCH/org/status", "PATCH/org/questionnaire", "GET/org/id"]
pre_approval_endpoints = ["PATCH/org/status", "PATCH/org/questionnaire", "GET/org/id", "GET/org/contact", "PATCH/org/contact"]
current_request = f"{request.method}{request.url.path}"
if current_request not in pre_approval_endpoints and org_model.status != OrgStatus.APPROVED:
raise AwaitingApprovalException(org_id)

View file

@ -1,9 +1,9 @@
"""
Module specific exceptions for organisation module
Exceptions related to the organisation module
Exceptions:
- List: Description
- Exceptions: Description
- OrgNotFoundException: Takes an optional org_id int
- AwaitingApprovalException: Takes an optional org_id int
"""
from typing import Optional

View file

@ -2,9 +2,16 @@
Database models for organisation module
Models:
- Organisation: id[pk], name, status, intake_questionnaire,
billing_contact_id[fk], security_contact_id[fk], owner_contact_id[fk]
- OrgUsers: org_id[fk][cpk], user_id[fk][cpk], is_admin
- Organisation:
- id[PK], name, status, intake_questionnaire, root_user_id[FK], billing_contact_id[FK], security_contact_id[FK], owner_contact_id[FK]
- user_rel: ORM relationship to User via OrgUsers relationship table
- group_rel: ORM relationship to Group, backprops Group.org_rel
- root_user_rel: ORM relationship to User with root_user_id FK
- root_user_email: Calc property root_user_rel.email
- billing_contact_rel: ORM relationship to Contact with billing_contact FK
- security_contact_rel: ORM relationship to Contact with security_contact FK
- owner_contact_rel: ORM relationship to Contact with owner_contact FK
- OrgUsers: org_id[FK][PK], user_id[FK][PK]
"""
from sqlalchemy import Column, Integer, String, ForeignKey, JSON
from sqlalchemy.orm import relationship

View file

@ -2,15 +2,18 @@
Router endpoints for organisation module
Endpoints:
- [get]/id/{org_id} - Retrieves an organisation by its ID
- [post]/ - Creates a new organisation
- [patch]/{org_id}/questionnaire - Updates the questionnaire data for an organisation (can be partial or final submission)
- [patch]/{org_id}/status - Updates the status of an organisation
- [patch]/{org_id}/contact - Assigns a contact to an organisation (as billing, security, or owner)
- [get]/{org_id}/users - Retrieves all users associated with an organisation
- [post]/{org_id}/users - Adds a new user to an organisation
- [delete]/{org_id} - Deletes an organisation by ID
- [get]/{org_id}/contact/{contact_type} - Retrieves the contact of a specific type (owner, billing, security) for an organisation
- [GET](/org/id): [root user]: Get details about an organisation(id)
- [POST](/org/): [oidc claim]: Creates an organisation, adds the current user as a user and sets them to be the root user
- [PATCH](/org/questionnaire): [root user]: Updates the org's intake questionnaire and optionally be submitted for review
- [PATCH](/org/status): [super admin]: Allows a super admin to update an org(id) status(Status enum)
- [GET](/org/users): [root user]: Gets a list of the org(id) users(email)
- [POST](/org/users): [root user]: Adds a new user(id) to the org(id)
- [DELETE](/org/): [super admin]: Deletes an organisation(id)
- [PATCH](/org/root_user): [super admin]: Updates an org(id) root user(id)
- [GET](/org/groups): [root user]: Gets a list of the org(id) groups(name)
- [DELETE](/org/user): [root user]: Removes a user(id) from an org(id)
- [GET](/org/contact): [root user]: Gets the (contact_type) contact for an org(id)
- [PATCH](/org/contact): [root user]: Updates the (contact_type) contact for an org(id). Any number of details can be changed.
"""
from typing import Annotated, Optional

View file

@ -1,9 +1,10 @@
"""
Pydantic models for organisation module
Models:
- List: Description
- Models: Description
Models follow the nomenclature of:
- Sub-models: "<Resource><Opt:>Schema"
- Mixins: "<Attribute>Mixin"
- Models: "<Module><Method><Resource><Opt:Resource><Direction>" ie "OrgPostOrgRequest"
"""
from typing import Optional
@ -16,7 +17,7 @@ from src.user.schemas import UserIDMixin
from src.organisation.constants import Status, ContactType
class OrgQuestionnaire(CustomBaseModel):
class Questionnaire(CustomBaseModel):
question_one: str
question_two: str
question_three: str
@ -27,10 +28,10 @@ class OrgIDMixin(CustomBaseModel):
class OrgPostOrgRequest(CustomBaseModel):
name: str
intake_questionnaire: Optional[OrgQuestionnaire] = None
intake_questionnaire: Optional[Questionnaire] = None
class OrgPatchQuestionnaireRequest(OrgIDMixin):
intake_questionnaire: OrgQuestionnaire
intake_questionnaire: Questionnaire
partial: bool
class OrgPatchStatusRequest(OrgIDMixin):

View file

@ -1,11 +1,3 @@
"""
Module specific business logic for organisation module
Classes:
- List: Description
- Classes: Description
Functions:
- List: Description
- Functions: Description
Reusable business logic functions for the organisation module
"""

View file

@ -1,11 +1,3 @@
"""
Non-business logic reusable functions and classes for organisation module
Classes:
- List: Description
- Classes: Description
Functions:
- List: Description
- Functions: Description
Non-business logic reusable functions and classes for the organisation module
"""

View file

@ -17,7 +17,7 @@ from src.service.models import Service
from src.service.utils import generate_api_key
from src.service.dependencies import service_model_body_dependency
from src.service.schemas import ServiceGetServiceResponse, ServicePostServiceRequest, ServicePostServiceResponse, \
ServiceWithKeyResponse, ServicePatchKeyResponse, ServicePatchKeyRequest, ServiceDeleteServiceRequest
ServiceWithKeySchema, ServicePatchKeyResponse, ServicePatchKeyRequest, ServiceDeleteServiceRequest
router = APIRouter(
tags=["Service"],
@ -42,7 +42,7 @@ async def register_service(db: db_dependency, su: super_admin_dependency, servic
if isinstance(e.orig, UniqueViolation):
raise Conflict(message="Service with this name already exists")
db.commit()
response = ServiceWithKeyResponse(**service_model.__dict__)
response = ServiceWithKeySchema(**service_model.__dict__)
db.commit()
return {"service": response}
@ -52,7 +52,7 @@ async def regenerate_api_key(db: db_dependency, su: super_admin_dependency, serv
service_model.api_key = key
db.flush()
response = ServiceWithKeyResponse(**service_model.__dict__)
response = ServiceWithKeySchema(**service_model.__dict__)
db.commit()
return {"service": response}

View file

@ -12,29 +12,29 @@ from src.schemas import CustomBaseModel
class ServiceIDMixin(CustomBaseModel):
service_id: int
class ServiceResponse(CustomBaseModel):
class ServiceSchema(CustomBaseModel):
model_config = ConfigDict(from_attributes=True, extra="ignore")
id: int
name: str
class ServiceWithKeyResponse(ServiceResponse):
class ServiceWithKeySchema(ServiceSchema):
api_key: str
class ServiceGetServiceResponse(CustomBaseModel):
services: list[ServiceResponse]
services: list[ServiceSchema]
class ServicePostServiceRequest(CustomBaseModel):
name: str
class ServicePostServiceResponse(CustomBaseModel):
service: ServiceWithKeyResponse
service: ServiceWithKeySchema
class ServicePatchKeyRequest(ServiceIDMixin):
pass
class ServicePatchKeyResponse(CustomBaseModel):
service: ServiceWithKeyResponse
service: ServiceWithKeySchema
class ServiceDeleteServiceRequest(ServiceIDMixin):
pass