Skip to content

Commit 58293c4

Browse files
committed
Validate field region/zone directors have the appropriate role
1 parent 78513ce commit 58293c4

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

src/components/field-region/field-region.service.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import { Injectable } from '@nestjs/common';
22
import {
33
type ID,
4+
InputException,
5+
NotFoundException,
46
type ObjectView,
57
ServerException,
68
type UnsecuredDto,
79
} from '~/common';
810
import { HandleIdLookup } from '~/core';
911
import { IEventBus } from '~/core/events';
1012
import { Privileges } from '../authorization';
13+
import { UserService } from '../user';
1114
import {
1215
type CreateFieldRegion,
1316
FieldRegion,
@@ -23,11 +26,13 @@ export class FieldRegionService {
2326
constructor(
2427
private readonly privileges: Privileges,
2528
private readonly events: IEventBus,
29+
private readonly users: UserService,
2630
private readonly repo: FieldRegionRepository,
2731
) {}
2832

2933
async create(input: CreateFieldRegion): Promise<FieldRegion> {
3034
this.privileges.for(FieldRegion).verifyCan('create');
35+
await this.validateDirectorRole(input.directorId);
3136
const dto = await this.repo.create(input);
3237
return this.secure(dto);
3338
}
@@ -53,6 +58,10 @@ export class FieldRegionService {
5358
const changes = this.repo.getActualChanges(fieldRegion, input);
5459
this.privileges.for(FieldRegion, fieldRegion).verifyChanges(changes);
5560

61+
if (changes.directorId) {
62+
await this.validateDirectorRole(changes.directorId);
63+
}
64+
5665
if (Object.keys(changes).length === 0) {
5766
return this.secure(fieldRegion);
5867
}
@@ -68,6 +77,25 @@ export class FieldRegionService {
6877
return this.secure(updated);
6978
}
7079

80+
private async validateDirectorRole(directorId: ID<'User'>) {
81+
let director;
82+
try {
83+
director = await this.users.readOneUnsecured(directorId);
84+
} catch (e) {
85+
if (e instanceof NotFoundException) {
86+
throw e.withField('fieldRegion.directorId');
87+
}
88+
throw e;
89+
}
90+
if (!director.roles.includes('RegionalDirector')) {
91+
throw new InputException(
92+
'User does not have the Regional Director role',
93+
'fieldRegion.directorId',
94+
);
95+
}
96+
return director;
97+
}
98+
7199
async delete(id: ID): Promise<void> {
72100
const object = await this.readOne(id);
73101

src/components/field-zone/field-zone.service.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import { Injectable } from '@nestjs/common';
22
import {
33
type ID,
4+
InputException,
5+
NotFoundException,
46
type ObjectView,
57
ServerException,
68
type UnsecuredDto,
79
} from '~/common';
810
import { HandleIdLookup } from '~/core';
911
import { IEventBus } from '~/core/events';
1012
import { Privileges } from '../authorization';
13+
import { UserService } from '../user';
1114
import {
1215
type CreateFieldZone,
1316
FieldZone,
@@ -23,11 +26,13 @@ export class FieldZoneService {
2326
constructor(
2427
private readonly privileges: Privileges,
2528
private readonly events: IEventBus,
29+
private readonly users: UserService,
2630
private readonly repo: FieldZoneRepository,
2731
) {}
2832

2933
async create(input: CreateFieldZone): Promise<FieldZone> {
3034
this.privileges.for(FieldZone).verifyCan('create');
35+
await this.validateDirectorRole(input.directorId);
3136
const dto = await this.repo.create(input);
3237
return this.secure(dto);
3338
}
@@ -53,6 +58,10 @@ export class FieldZoneService {
5358
const changes = this.repo.getActualChanges(fieldZone, input);
5459
this.privileges.for(FieldZone, fieldZone).verifyChanges(changes);
5560

61+
if (changes.directorId) {
62+
await this.validateDirectorRole(changes.directorId);
63+
}
64+
5665
if (Object.keys(changes).length === 0) {
5766
return this.secure(fieldZone);
5867
}
@@ -68,6 +77,25 @@ export class FieldZoneService {
6877
return this.secure(updated);
6978
}
7079

80+
private async validateDirectorRole(directorId: ID<'User'>) {
81+
let director;
82+
try {
83+
director = await this.users.readOneUnsecured(directorId);
84+
} catch (e) {
85+
if (e instanceof NotFoundException) {
86+
throw e.withField('fieldZone.directorId');
87+
}
88+
throw e;
89+
}
90+
if (!director.roles.includes('FieldOperationsDirector')) {
91+
throw new InputException(
92+
'User does not have the Field Operations Director role',
93+
'fieldZone.directorId',
94+
);
95+
}
96+
return director;
97+
}
98+
7199
async delete(id: ID): Promise<void> {
72100
const object = await this.readOne(id);
73101

0 commit comments

Comments
 (0)