Skip to content

Commit

Permalink
feat: patient-type + diagnosis
Browse files Browse the repository at this point in the history
  • Loading branch information
wermarter committed Jan 25, 2024
1 parent 1f9cd2c commit 8fb0a42
Show file tree
Hide file tree
Showing 75 changed files with 1,208 additions and 400 deletions.
4 changes: 4 additions & 0 deletions apps/hcdc-access-service/src/domain/auth/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import { AuthSubject, AuthSubjectUnionType } from './subject'
import {
BioProductAction,
BranchAction,
DiagnosisAction,
DoctorAction,
InstrumentAction,
PatientTypeAction,
RoleAction,
SampleTypeAction,
TestCategoryAction,
Expand All @@ -22,6 +24,8 @@ export const AuthAction = {
Instrument: stringEnumValues(InstrumentAction),
SampleType: stringEnumValues(SampleTypeAction),
Doctor: stringEnumValues(DoctorAction),
PatientType: stringEnumValues(PatientTypeAction),
Diagnosis: stringEnumValues(DiagnosisAction),
} satisfies Record<keyof typeof AuthSubject, string[]>

export const AuthActionValues = [
Expand Down
6 changes: 6 additions & 0 deletions apps/hcdc-access-service/src/domain/auth/subject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { RecordTypes } from '@casl/mongoose'
import {
BioProduct,
Branch,
Diagnosis,
Doctor,
Instrument,
PatientType,
Role,
SampleType,
TestCategory,
Expand All @@ -22,6 +24,8 @@ export const AuthSubject = {
Instrument: 'Instrument',
SampleType: 'SampleType',
Doctor: 'Doctor',
PatientType: 'PatientType',
Diagnosis: 'Diagnosis',
} satisfies Record<keyof RecordTypes, keyof RecordTypes>

export type AuthSubjectUnionType = keyof typeof AuthSubject
Expand All @@ -40,4 +44,6 @@ export type SubjectEntityMapping = {
Instrument: Instrument
SampleType: SampleType
Doctor: Doctor
PatientType: PatientType
Diagnosis: Diagnosis
}
14 changes: 14 additions & 0 deletions apps/hcdc-access-service/src/domain/entity/diagnosis/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import '@casl/mongoose'

export enum DiagnosisAction {
Create = 'Create',
Read = 'Read',
Update = 'Update',
Delete = 'Delete',
}

declare module '@casl/mongoose' {
interface RecordTypes {
Diagnosis: true
}
}
10 changes: 10 additions & 0 deletions apps/hcdc-access-service/src/domain/entity/diagnosis/entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { BaseEntity } from '../base-entity'
import { Branch } from '../branch'

export type Diagnosis = BaseEntity & {
displayIndex: number
name: string

branchId: string
branch?: Branch | null
}
17 changes: 17 additions & 0 deletions apps/hcdc-access-service/src/domain/entity/diagnosis/example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { exampleMongoObjectId } from '@diut/nest-core'

import { EntityDataExample } from '../base-entity'
import { Diagnosis } from './entity'

export const exampleDiagnosis = {
displayIndex: {
example: 1,
},
name: {
example: 'CHIV Advia centaur',
},
branchId: exampleMongoObjectId,
branch: {
required: false,
},
} satisfies EntityDataExample<Diagnosis>
3 changes: 3 additions & 0 deletions apps/hcdc-access-service/src/domain/entity/diagnosis/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './entity'
export * from './example'
export * from './auth'
2 changes: 2 additions & 0 deletions apps/hcdc-access-service/src/domain/entity/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export * from './base-entity'

export * from './bio-product'
export * from './diagnosis'
export * from './patient-type'
export * from './doctor'
export * from './instrument'
export * from './sample-type'
Expand Down
14 changes: 14 additions & 0 deletions apps/hcdc-access-service/src/domain/entity/patient-type/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import '@casl/mongoose'

export enum PatientTypeAction {
Create = 'Create',
Read = 'Read',
Update = 'Update',
Delete = 'Delete',
}

declare module '@casl/mongoose' {
interface RecordTypes {
PatientType: true
}
}
10 changes: 10 additions & 0 deletions apps/hcdc-access-service/src/domain/entity/patient-type/entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { BaseEntity } from '../base-entity'
import { Branch } from '../branch'

export type PatientType = BaseEntity & {
displayIndex: number
name: string

branchId: string
branch?: Branch | null
}
17 changes: 17 additions & 0 deletions apps/hcdc-access-service/src/domain/entity/patient-type/example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { exampleMongoObjectId } from '@diut/nest-core'

import { EntityDataExample } from '../base-entity'
import { PatientType } from './entity'

export const examplePatientType = {
displayIndex: {
example: 1,
},
name: {
example: 'CHIV Advia centaur',
},
branchId: exampleMongoObjectId,
branch: {
required: false,
},
} satisfies EntityDataExample<PatientType>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './entity'
export * from './example'
export * from './auth'
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Diagnosis } from 'src/domain/entity'
import { IRepository } from './interface'

export const DiagnosisRepositoryToken = Symbol('DiagnosisRepository')

export interface IDiagnosisRepository extends IRepository<Diagnosis> {}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export * from './interface'

export * from './bio-product'
export * from './patient-type'
export * from './diagnosis'
export * from './doctor'
export * from './test-category'
export * from './user'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { PatientType } from 'src/domain/entity'
import { IRepository } from './interface'

export const PatientTypeRepositoryToken = Symbol('PatientTypeRepository')

export interface IPatientTypeRepository extends IRepository<PatientType> {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Inject, Injectable } from '@nestjs/common'

import { Diagnosis } from 'src/domain/entity'
import { EEntityNotFound } from 'src/domain/exception'
import {
DiagnosisRepositoryToken,
EntityFindOneOptions,
IDiagnosisRepository,
} from 'src/domain/interface'

@Injectable()
export class DiagnosisAssertExistsUseCase {
constructor(
@Inject(DiagnosisRepositoryToken)
private readonly diagnosisRepository: IDiagnosisRepository,
) {}

async execute(input: EntityFindOneOptions<Diagnosis>['filter']) {
const rv = await this.diagnosisRepository.findOne({ filter: input })

if (rv === null) {
throw new EEntityNotFound(`Diagnosis ${JSON.stringify(input)}`)
}

return rv
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Inject, Injectable } from '@nestjs/common'

import { AuthSubject, authorizePopulates } from 'src/domain/auth'
import { BranchAction, Diagnosis } from 'src/domain/entity'
import { EEntityPopulatePathUnknown } from 'src/domain/exception'
import {
AuthContextToken,
EntityFindOneOptions,
IAuthContext,
} from 'src/domain/interface'

@Injectable()
export class DiagnosisAuthorizePopulatesUseCase {
constructor(
@Inject(AuthContextToken)
private readonly authContext: IAuthContext,
) {}
execute(input: EntityFindOneOptions<Diagnosis>['populates']) {
const { ability } = this.authContext.getData()

return authorizePopulates(ability, input, (path) => {
switch (path) {
case 'branch':
return { subject: AuthSubject.Branch, action: BranchAction.Read }
default:
throw new EEntityPopulatePathUnknown(path)
}
})
}
}
37 changes: 37 additions & 0 deletions apps/hcdc-access-service/src/domain/use-case/diagnosis/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Inject, Injectable } from '@nestjs/common'

import {
AuthContextToken,
DiagnosisRepositoryToken,
IAuthContext,
IDiagnosisRepository,
} from 'src/domain/interface'
import { Diagnosis, DiagnosisAction, EntityData } from 'src/domain/entity'
import { AuthSubject, assertPermission } from 'src/domain/auth'
import { DiagnosisValidateUseCase } from './validate'

@Injectable()
export class DiagnosisCreateUseCase {
constructor(
@Inject(AuthContextToken)
private readonly authContext: IAuthContext,
@Inject(DiagnosisRepositoryToken)
private readonly diagnosisRepository: IDiagnosisRepository,
private readonly diagnosisValidateUseCase: DiagnosisValidateUseCase,
) {}

async execute(input: EntityData<Diagnosis>) {
const { ability } = this.authContext.getData()
assertPermission(
ability,
AuthSubject.Diagnosis,
DiagnosisAction.Create,
input,
)
await this.diagnosisValidateUseCase.execute(input)

const entity = await this.diagnosisRepository.create(input)

return entity
}
}
39 changes: 39 additions & 0 deletions apps/hcdc-access-service/src/domain/use-case/diagnosis/delete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Inject, Injectable } from '@nestjs/common'

import { DiagnosisAction } from 'src/domain/entity'
import { AuthSubject, assertPermission } from 'src/domain/auth'
import {
AuthContextToken,
DiagnosisRepositoryToken,
IAuthContext,
IDiagnosisRepository,
} from 'src/domain/interface'
import { DiagnosisAssertExistsUseCase } from './assert-exists'

@Injectable()
export class DiagnosisDeleteUseCase {
constructor(
@Inject(AuthContextToken)
private readonly authContext: IAuthContext,
@Inject(DiagnosisRepositoryToken)
private readonly diagnosisRepository: IDiagnosisRepository,
private readonly diagnosisAssertExistsUseCase: DiagnosisAssertExistsUseCase,
) {}

async execute(input: { id: string }) {
const entity = await this.diagnosisAssertExistsUseCase.execute({
_id: input.id,
})
const { ability } = this.authContext.getData()
assertPermission(
ability,
AuthSubject.Diagnosis,
DiagnosisAction.Delete,
entity,
)

await this.diagnosisRepository.deleteById(input.id)

return entity
}
}
39 changes: 39 additions & 0 deletions apps/hcdc-access-service/src/domain/use-case/diagnosis/find-one.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Inject, Injectable } from '@nestjs/common'

import { Diagnosis, DiagnosisAction } from 'src/domain/entity'
import { AuthSubject, assertPermission } from 'src/domain/auth'
import {
AuthContextToken,
DiagnosisRepositoryToken,
EntityFindOneOptions,
IAuthContext,
IDiagnosisRepository,
} from 'src/domain/interface'
import { DiagnosisAuthorizePopulatesUseCase } from './authorize-populates'

@Injectable()
export class DiagnosisFindOneUseCase {
constructor(
@Inject(DiagnosisRepositoryToken)
private readonly diagnosisRepository: IDiagnosisRepository,
@Inject(AuthContextToken)
private readonly authContext: IAuthContext,
private readonly diagnosisAuthorizePopulatesUseCase: DiagnosisAuthorizePopulatesUseCase,
) {}

async execute(input: EntityFindOneOptions<Diagnosis>) {
input.populates = this.diagnosisAuthorizePopulatesUseCase.execute(
input.populates,
)
const entity = await this.diagnosisRepository.findOne(input)
const { ability } = this.authContext.getData()
assertPermission(
ability,
AuthSubject.Diagnosis,
DiagnosisAction.Read,
entity,
)

return entity
}
}
44 changes: 44 additions & 0 deletions apps/hcdc-access-service/src/domain/use-case/diagnosis/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Inject, Injectable } from '@nestjs/common'
import { accessibleBy } from '@casl/mongoose'

import {
AuthContextToken,
DiagnosisRepositoryToken,
IAuthContext,
IDiagnosisRepository,
EntitySearchOptions,
} from 'src/domain/interface'
import { Diagnosis, DiagnosisAction } from 'src/domain/entity'
import { AuthSubject, assertPermission } from 'src/domain/auth'
import { DiagnosisAuthorizePopulatesUseCase } from './authorize-populates'

@Injectable()
export class DiagnosisSearchUseCase {
constructor(
@Inject(DiagnosisRepositoryToken)
private readonly diagnosisRepository: IDiagnosisRepository,
@Inject(AuthContextToken)
private readonly authContext: IAuthContext,
private readonly diagnosisAuthorizePopulatesUseCase: DiagnosisAuthorizePopulatesUseCase,
) {}

async execute(input: EntitySearchOptions<Diagnosis>) {
const { ability } = this.authContext.getData()
assertPermission(ability, AuthSubject.Diagnosis, DiagnosisAction.Read)
input.populates = this.diagnosisAuthorizePopulatesUseCase.execute(
input.populates,
)

const paginationResult = await this.diagnosisRepository.search({
...input,
filter: {
$and: [
input.filter ?? {},
accessibleBy(ability, DiagnosisAction.Read).Diagnosis,
],
},
})

return paginationResult
}
}
Loading

0 comments on commit 8fb0a42

Please sign in to comment.