@forklaunch/implementation-iam-base 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,49 @@
1
+ import { IdiomaticSchema, LiteralSchema } from '@forklaunch/validator';
2
+ import {
3
+ array,
4
+ date,
5
+ enum_,
6
+ optional,
7
+ string,
8
+ unknown,
9
+ uuid,
10
+ ZodSchemaValidator
11
+ } from '@forklaunch/validator/zod';
12
+
13
+ export const CreateOrganizationSchema = {
14
+ name: string,
15
+ domain: string,
16
+ subscription: string,
17
+ logoUrl: optional(string),
18
+ extraFields: optional(unknown)
19
+ };
20
+
21
+ export const UpdateOrganizationSchema = (uuidId: boolean) => ({
22
+ id: uuidId ? uuid : string,
23
+ name: optional(string),
24
+ domain: optional(string),
25
+ subscription: optional(string),
26
+ logoUrl: optional(string),
27
+ extraFields: optional(unknown)
28
+ });
29
+
30
+ export const OrganizationSchema =
31
+ (uuidId: boolean) =>
32
+ <
33
+ UserDtoSchema extends IdiomaticSchema<ZodSchemaValidator>,
34
+ OrganizationStatus extends Record<string, LiteralSchema>
35
+ >(
36
+ UserDtoSchema: UserDtoSchema,
37
+ OrganizationStatus: OrganizationStatus
38
+ ) => ({
39
+ id: uuidId ? uuid : string,
40
+ name: string,
41
+ users: array(UserDtoSchema),
42
+ domain: string,
43
+ subscription: string,
44
+ status: enum_(OrganizationStatus),
45
+ logoUrl: optional(string),
46
+ extraFields: optional(unknown),
47
+ createdAt: optional(date),
48
+ updatedAt: optional(date)
49
+ });
@@ -0,0 +1,30 @@
1
+ import {
2
+ array,
3
+ date,
4
+ optional,
5
+ string,
6
+ unknown,
7
+ uuid
8
+ } from '@forklaunch/validator/zod';
9
+
10
+ export const CreatePermissionSchema = {
11
+ slug: string,
12
+ addToRolesIds: optional(array(string)),
13
+ extraFields: optional(unknown)
14
+ };
15
+
16
+ export const UpdatePermissionSchema = (uuidId: boolean) => ({
17
+ id: uuidId ? uuid : string,
18
+ slug: optional(string),
19
+ extraFields: optional(unknown),
20
+ addToRolesIds: optional(array(string)),
21
+ removeFromRolesIds: optional(array(string))
22
+ });
23
+
24
+ export const PermissionSchema = (uuidId: boolean) => ({
25
+ id: uuidId ? uuid : string,
26
+ slug: string,
27
+ extraFields: optional(unknown),
28
+ createdAt: optional(date),
29
+ updatedAt: optional(date)
30
+ });
@@ -0,0 +1,36 @@
1
+ import { IdiomaticSchema } from '@forklaunch/validator';
2
+ import {
3
+ array,
4
+ date,
5
+ optional,
6
+ string,
7
+ unknown,
8
+ uuid,
9
+ ZodSchemaValidator
10
+ } from '@forklaunch/validator/zod';
11
+
12
+ export const CreateRoleSchema = {
13
+ name: string,
14
+ permissionIds: optional(array(string)),
15
+ extraFields: optional(unknown)
16
+ };
17
+
18
+ export const UpdateRoleSchema = (uuidId: boolean) => ({
19
+ id: uuidId ? uuid : string,
20
+ name: optional(string),
21
+ permissionIds: optional(array(string)),
22
+ extraFields: optional(unknown)
23
+ });
24
+
25
+ export const RoleSchema =
26
+ (uuidId: boolean) =>
27
+ <PermissionSchema extends IdiomaticSchema<ZodSchemaValidator>>(
28
+ PermissionSchema: PermissionSchema
29
+ ) => ({
30
+ id: uuidId ? uuid : string,
31
+ name: string,
32
+ permissions: array(PermissionSchema),
33
+ extraFields: optional(unknown),
34
+ createdAt: optional(date),
35
+ updatedAt: optional(date)
36
+ });
@@ -0,0 +1,52 @@
1
+ import { IdiomaticSchema } from '@forklaunch/validator';
2
+ import {
3
+ array,
4
+ date,
5
+ email,
6
+ optional,
7
+ string,
8
+ unknown,
9
+ uuid,
10
+ ZodSchemaValidator
11
+ } from '@forklaunch/validator/zod';
12
+
13
+ export const CreateUserSchema = {
14
+ email: email,
15
+ password: string,
16
+ firstName: string,
17
+ lastName: string,
18
+ organizationId: string,
19
+ roleIds: array(string),
20
+ phoneNumber: optional(string),
21
+ subscription: optional(string),
22
+ extraFields: optional(unknown)
23
+ };
24
+
25
+ export const UpdateUserSchema = (uuidId: boolean) => ({
26
+ id: uuidId ? uuid : string,
27
+ email: optional(email),
28
+ password: optional(string),
29
+ firstName: optional(string),
30
+ lastName: optional(string),
31
+ roleIds: optional(array(string)),
32
+ phoneNumber: optional(string),
33
+ subscription: optional(string),
34
+ extraFields: optional(unknown)
35
+ });
36
+
37
+ export const UserSchema =
38
+ (uuidId: boolean) =>
39
+ <RoleDtoSchema extends IdiomaticSchema<ZodSchemaValidator>>(
40
+ RoleDtoSchema: RoleDtoSchema
41
+ ) => ({
42
+ id: uuidId ? uuid : string,
43
+ email: email,
44
+ firstName: string,
45
+ lastName: string,
46
+ roles: array(RoleDtoSchema),
47
+ phoneNumber: optional(string),
48
+ subscription: optional(string),
49
+ extraFields: optional(unknown),
50
+ createdAt: optional(date),
51
+ updatedAt: optional(date)
52
+ });
@@ -0,0 +1,146 @@
1
+ import {
2
+ CreateOrganizationDto,
3
+ OrganizationDto,
4
+ OrganizationService,
5
+ UpdateOrganizationDto
6
+ } from '@forklaunch/interfaces-iam';
7
+ import { IdDto, InstanceTypeRecord } from '@forklaunch/common';
8
+ import {
9
+ InternalDtoMapper,
10
+ RequestDtoMapperConstructor,
11
+ ResponseDtoMapperConstructor,
12
+ transformIntoInternalDtoMapper
13
+ } from '@forklaunch/core/dtoMapper';
14
+ import {
15
+ MetricsDefinition,
16
+ OpenTelemetryCollector
17
+ } from '@forklaunch/core/http';
18
+ import { MapNestedDtoArraysToCollections } from '@forklaunch/core/services';
19
+ import { AnySchemaValidator } from '@forklaunch/validator';
20
+ import { EntityManager } from '@mikro-orm/core';
21
+
22
+ export class BaseOrganizationService<
23
+ SchemaValidator extends AnySchemaValidator,
24
+ OrganizationStatus,
25
+ Metrics extends MetricsDefinition = MetricsDefinition,
26
+ Dto extends {
27
+ OrganizationDtoMapper: OrganizationDto<OrganizationStatus>;
28
+ CreateOrganizationDtoMapper: CreateOrganizationDto;
29
+ UpdateOrganizationDtoMapper: UpdateOrganizationDto;
30
+ } = {
31
+ OrganizationDtoMapper: OrganizationDto<OrganizationStatus>;
32
+ CreateOrganizationDtoMapper: CreateOrganizationDto;
33
+ UpdateOrganizationDtoMapper: UpdateOrganizationDto;
34
+ },
35
+ Entities extends {
36
+ OrganizationDtoMapper: MapNestedDtoArraysToCollections<
37
+ OrganizationDto<OrganizationStatus>,
38
+ 'users'
39
+ >;
40
+ CreateOrganizationDtoMapper: MapNestedDtoArraysToCollections<
41
+ OrganizationDto<OrganizationStatus>,
42
+ 'users'
43
+ >;
44
+ UpdateOrganizationDtoMapper: MapNestedDtoArraysToCollections<
45
+ OrganizationDto<OrganizationStatus>,
46
+ 'users'
47
+ >;
48
+ } = {
49
+ OrganizationDtoMapper: MapNestedDtoArraysToCollections<
50
+ OrganizationDto<OrganizationStatus>,
51
+ 'users'
52
+ >;
53
+ CreateOrganizationDtoMapper: MapNestedDtoArraysToCollections<
54
+ OrganizationDto<OrganizationStatus>,
55
+ 'users'
56
+ >;
57
+ UpdateOrganizationDtoMapper: MapNestedDtoArraysToCollections<
58
+ OrganizationDto<OrganizationStatus>,
59
+ 'users'
60
+ >;
61
+ }
62
+ > implements OrganizationService<OrganizationStatus>
63
+ {
64
+ #dtoMappers: InternalDtoMapper<
65
+ InstanceTypeRecord<typeof this.dtoMappers>,
66
+ Entities,
67
+ Dto
68
+ >;
69
+
70
+ constructor(
71
+ public em: EntityManager,
72
+ protected openTelemetryCollector: OpenTelemetryCollector<Metrics>,
73
+ protected schemaValidator: SchemaValidator,
74
+ protected dtoMappers: {
75
+ OrganizationDtoMapper: ResponseDtoMapperConstructor<
76
+ SchemaValidator,
77
+ Dto['OrganizationDtoMapper'],
78
+ Entities['OrganizationDtoMapper']
79
+ >;
80
+ CreateOrganizationDtoMapper: RequestDtoMapperConstructor<
81
+ SchemaValidator,
82
+ Dto['CreateOrganizationDtoMapper'],
83
+ Entities['CreateOrganizationDtoMapper']
84
+ >;
85
+ UpdateOrganizationDtoMapper: RequestDtoMapperConstructor<
86
+ SchemaValidator,
87
+ Dto['UpdateOrganizationDtoMapper'],
88
+ Entities['UpdateOrganizationDtoMapper']
89
+ >;
90
+ }
91
+ ) {
92
+ this.#dtoMappers = transformIntoInternalDtoMapper(
93
+ dtoMappers,
94
+ schemaValidator
95
+ );
96
+ }
97
+
98
+ async createOrganization(
99
+ organizationDto: Dto['CreateOrganizationDtoMapper'],
100
+ em?: EntityManager
101
+ ): Promise<Dto['OrganizationDtoMapper']> {
102
+ this.openTelemetryCollector.log('info', 'Creating organization');
103
+ const organization =
104
+ this.#dtoMappers.CreateOrganizationDtoMapper.deserializeDtoToEntity(
105
+ organizationDto
106
+ );
107
+ await (em ?? this.em).transactional(async (innerEm) => {
108
+ await innerEm.persist(organization);
109
+ });
110
+
111
+ return this.#dtoMappers.OrganizationDtoMapper.serializeEntityToDto(
112
+ organization
113
+ );
114
+ }
115
+
116
+ async getOrganization(
117
+ idDto: IdDto,
118
+ em?: EntityManager
119
+ ): Promise<Dto['OrganizationDtoMapper']> {
120
+ const organization = await (em ?? this.em).findOneOrFail(
121
+ 'Organization',
122
+ idDto
123
+ );
124
+ return this.#dtoMappers.OrganizationDtoMapper.serializeEntityToDto(
125
+ organization as Entities['OrganizationDtoMapper']
126
+ );
127
+ }
128
+
129
+ async updateOrganization(
130
+ organizationDto: Dto['UpdateOrganizationDtoMapper'],
131
+ em?: EntityManager
132
+ ): Promise<Dto['OrganizationDtoMapper']> {
133
+ const updatedOrganization =
134
+ this.#dtoMappers.UpdateOrganizationDtoMapper.deserializeDtoToEntity(
135
+ organizationDto
136
+ );
137
+ await (em ?? this.em).upsert(updatedOrganization);
138
+ return this.#dtoMappers.OrganizationDtoMapper.serializeEntityToDto(
139
+ updatedOrganization
140
+ );
141
+ }
142
+
143
+ async deleteOrganization(idDto: IdDto, em?: EntityManager): Promise<void> {
144
+ await (em ?? this.em).nativeDelete('Organization', idDto);
145
+ }
146
+ }
@@ -0,0 +1,349 @@
1
+ import {
2
+ CreatePermissionDto,
3
+ PermissionDto,
4
+ PermissionService,
5
+ RoleDto,
6
+ RoleService,
7
+ UpdatePermissionDto
8
+ } from '@forklaunch/interfaces-iam';
9
+ import { IdDto, IdsDto, InstanceTypeRecord } from '@forklaunch/common';
10
+ import {
11
+ InternalDtoMapper,
12
+ RequestDtoMapperConstructor,
13
+ ResponseDtoMapperConstructor,
14
+ transformIntoInternalDtoMapper
15
+ } from '@forklaunch/core/dtoMapper';
16
+ import {
17
+ MetricsDefinition,
18
+ OpenTelemetryCollector
19
+ } from '@forklaunch/core/http';
20
+ import { MapNestedDtoArraysToCollections } from '@forklaunch/core/services';
21
+ import { AnySchemaValidator } from '@forklaunch/validator';
22
+ import { EntityManager } from '@mikro-orm/core';
23
+
24
+ export class BasePermissionService<
25
+ SchemaValidator extends AnySchemaValidator,
26
+ Metrics extends MetricsDefinition = MetricsDefinition,
27
+ Dto extends {
28
+ PermissionDtoMapper: PermissionDto;
29
+ CreatePermissionDtoMapper: CreatePermissionDto;
30
+ UpdatePermissionDtoMapper: UpdatePermissionDto;
31
+ RoleDtoMapper: RoleDto;
32
+ } = {
33
+ PermissionDtoMapper: PermissionDto;
34
+ CreatePermissionDtoMapper: CreatePermissionDto;
35
+ UpdatePermissionDtoMapper: UpdatePermissionDto;
36
+ RoleDtoMapper: RoleDto;
37
+ },
38
+ Entities extends {
39
+ PermissionDtoMapper: PermissionDto;
40
+ CreatePermissionDtoMapper: PermissionDto;
41
+ UpdatePermissionDtoMapper: PermissionDto;
42
+ RoleDtoMapper: MapNestedDtoArraysToCollections<RoleDto, 'permissions'>;
43
+ } = {
44
+ PermissionDtoMapper: PermissionDto;
45
+ CreatePermissionDtoMapper: PermissionDto;
46
+ UpdatePermissionDtoMapper: PermissionDto;
47
+ RoleDtoMapper: MapNestedDtoArraysToCollections<RoleDto, 'permissions'>;
48
+ }
49
+ > implements PermissionService
50
+ {
51
+ #dtoMappers: InternalDtoMapper<
52
+ InstanceTypeRecord<typeof this.dtoMappers>,
53
+ Entities,
54
+ Dto
55
+ >;
56
+
57
+ constructor(
58
+ public em: EntityManager,
59
+ protected roleServiceFactory: () => RoleService,
60
+ protected openTelemetryCollector: OpenTelemetryCollector<Metrics>,
61
+ protected schemaValidator: SchemaValidator,
62
+ protected dtoMappers: {
63
+ PermissionDtoMapper: ResponseDtoMapperConstructor<
64
+ SchemaValidator,
65
+ Dto['PermissionDtoMapper'],
66
+ Entities['PermissionDtoMapper']
67
+ >;
68
+ CreatePermissionDtoMapper: RequestDtoMapperConstructor<
69
+ SchemaValidator,
70
+ Dto['CreatePermissionDtoMapper'],
71
+ Entities['CreatePermissionDtoMapper']
72
+ >;
73
+ UpdatePermissionDtoMapper: RequestDtoMapperConstructor<
74
+ SchemaValidator,
75
+ Dto['UpdatePermissionDtoMapper'],
76
+ Entities['UpdatePermissionDtoMapper']
77
+ >;
78
+ RoleDtoMapper: RequestDtoMapperConstructor<
79
+ SchemaValidator,
80
+ Dto['RoleDtoMapper'],
81
+ Entities['RoleDtoMapper']
82
+ >;
83
+ }
84
+ ) {
85
+ this.#dtoMappers = transformIntoInternalDtoMapper(
86
+ dtoMappers,
87
+ schemaValidator
88
+ );
89
+ }
90
+
91
+ // start: global helper functions
92
+ private async updateRolesWithPermissions(
93
+ roles: Entities['RoleDtoMapper'][],
94
+ permissions: Entities['PermissionDtoMapper'][]
95
+ ): Promise<Entities['RoleDtoMapper'][]> {
96
+ return await Promise.all(
97
+ roles.map(async (role) => {
98
+ permissions.forEach((permission) => role.permissions.add(permission));
99
+ return role;
100
+ })
101
+ );
102
+ }
103
+
104
+ private async removePermissionsFromRoles(
105
+ roles: Entities['RoleDtoMapper'][],
106
+ permissions: Entities['PermissionDtoMapper'][]
107
+ ): Promise<Entities['RoleDtoMapper'][]> {
108
+ return await Promise.all(
109
+ roles.map(async (role) => {
110
+ permissions.forEach((permission) =>
111
+ role.permissions.remove(permission)
112
+ );
113
+ return role;
114
+ })
115
+ );
116
+ }
117
+
118
+ private async getBatchRoles(
119
+ roleIds?: IdsDto,
120
+ em?: EntityManager
121
+ ): Promise<Entities['RoleDtoMapper'][]> {
122
+ return roleIds
123
+ ? (await this.roleServiceFactory().getBatchRoles(roleIds, em)).map(
124
+ (role) => {
125
+ return (em ?? this.em).merge(
126
+ this.#dtoMappers.RoleDtoMapper.deserializeDtoToEntity(role)
127
+ );
128
+ }
129
+ )
130
+ : [];
131
+ }
132
+ // end: global helper functions
133
+
134
+ // start: createPermission helper functions
135
+ private async createPermissionDto({
136
+ permission,
137
+ addToRoles
138
+ }: {
139
+ permission: Entities['PermissionDtoMapper'];
140
+ addToRoles: Entities['RoleDtoMapper'][];
141
+ }): Promise<{
142
+ permission: Entities['PermissionDtoMapper'];
143
+ roles: Entities['RoleDtoMapper'][];
144
+ }> {
145
+ let roles: Entities['RoleDtoMapper'][] = [];
146
+ if (addToRoles) {
147
+ roles = await this.updateRolesWithPermissions(addToRoles, [permission]);
148
+ }
149
+
150
+ return { permission, roles };
151
+ }
152
+
153
+ private async extractCreatePermissionDtoToEntityData(
154
+ permissionDto: Dto['CreatePermissionDtoMapper'],
155
+ em?: EntityManager
156
+ ): Promise<{
157
+ permission: Entities['PermissionDtoMapper'];
158
+ addToRoles: Entities['RoleDtoMapper'][];
159
+ }> {
160
+ return {
161
+ permission: (em ?? this.em).merge(
162
+ this.#dtoMappers.CreatePermissionDtoMapper.deserializeDtoToEntity(
163
+ permissionDto
164
+ )
165
+ ),
166
+ addToRoles: permissionDto.addToRolesIds
167
+ ? await this.getBatchRoles({ ids: permissionDto.addToRolesIds }, em)
168
+ : []
169
+ };
170
+ }
171
+ // end: createPermission helper functions
172
+
173
+ async createPermission(
174
+ createPermissionDto: Dto['CreatePermissionDtoMapper'],
175
+ em?: EntityManager
176
+ ): Promise<Dto['PermissionDtoMapper']> {
177
+ const { permission, roles } = await this.createPermissionDto(
178
+ await this.extractCreatePermissionDtoToEntityData(createPermissionDto, em)
179
+ );
180
+ await (em ?? this.em).transactional(async (innerEm) => {
181
+ await innerEm.persist([permission, ...roles]);
182
+ });
183
+ return this.#dtoMappers.PermissionDtoMapper.serializeEntityToDto(
184
+ permission
185
+ );
186
+ }
187
+
188
+ async createBatchPermissions(
189
+ permissionDtos: Dto['CreatePermissionDtoMapper'][],
190
+ em?: EntityManager
191
+ ): Promise<Dto['PermissionDtoMapper'][]> {
192
+ const rolesCache: Record<string, Entities['RoleDtoMapper']> = {};
193
+ const permissions: Entities['PermissionDtoMapper'][] = [];
194
+ await (em ?? this.em).transactional(async (em) => {
195
+ permissionDtos.map(async (createPermissionDto) => {
196
+ const { permission, roles } = await this.createPermissionDto(
197
+ await this.extractCreatePermissionDtoToEntityData(
198
+ createPermissionDto,
199
+ em
200
+ )
201
+ );
202
+ roles.forEach((role) => {
203
+ if (
204
+ rolesCache[role.id] &&
205
+ role.permissions !== rolesCache[role.id].permissions
206
+ ) {
207
+ role.permissions.getItems().forEach((permission) => {
208
+ if (!rolesCache[role.id].permissions.contains(permission)) {
209
+ rolesCache[role.id].permissions.add(permission);
210
+ }
211
+ });
212
+ } else {
213
+ rolesCache[role.id] = role;
214
+ }
215
+ });
216
+ permissions.push(permission);
217
+ });
218
+ await (em ?? this.em).persist([
219
+ ...permissions,
220
+ ...Object.values(rolesCache)
221
+ ]);
222
+ });
223
+
224
+ return permissions.map((permission) =>
225
+ this.#dtoMappers.PermissionDtoMapper.serializeEntityToDto(permission)
226
+ );
227
+ }
228
+
229
+ async getPermission(
230
+ idDto: IdDto,
231
+ em?: EntityManager
232
+ ): Promise<Dto['PermissionDtoMapper']> {
233
+ const permission = await (em ?? this.em).findOneOrFail('Permission', idDto);
234
+ return this.#dtoMappers.PermissionDtoMapper.serializeEntityToDto(
235
+ permission as Entities['PermissionDtoMapper']
236
+ );
237
+ }
238
+
239
+ async getBatchPermissions(
240
+ idsDto: IdsDto,
241
+ em?: EntityManager
242
+ ): Promise<Dto['PermissionDtoMapper'][]> {
243
+ return (await (em ?? this.em).find('Permission', idsDto)).map(
244
+ (permission) =>
245
+ this.#dtoMappers.PermissionDtoMapper.serializeEntityToDto(
246
+ permission as Entities['PermissionDtoMapper']
247
+ )
248
+ );
249
+ }
250
+
251
+ // start: updatePermission helper functions
252
+ private updatePermissionDto = async (
253
+ permissionDto: Dto['UpdatePermissionDtoMapper'],
254
+ em?: EntityManager
255
+ ): Promise<{
256
+ permission: Entities['PermissionDtoMapper'];
257
+ roles: Entities['RoleDtoMapper'][];
258
+ }> => {
259
+ const permission =
260
+ this.#dtoMappers.UpdatePermissionDtoMapper.deserializeDtoToEntity(
261
+ permissionDto
262
+ );
263
+ const addToRoles = permissionDto.addToRolesIds
264
+ ? await this.getBatchRoles({ ids: permissionDto.addToRolesIds }, em)
265
+ : [];
266
+ const removeFromRoles = permissionDto.removeFromRolesIds
267
+ ? await this.getBatchRoles({ ids: permissionDto.removeFromRolesIds }, em)
268
+ : [];
269
+
270
+ let roles: Entities['RoleDtoMapper'][] = [];
271
+
272
+ roles = roles.concat(
273
+ await this.updateRolesWithPermissions(addToRoles, [permission])
274
+ );
275
+ roles = roles.concat(
276
+ await this.removePermissionsFromRoles(removeFromRoles, [permission])
277
+ );
278
+
279
+ return {
280
+ permission,
281
+ roles
282
+ };
283
+ };
284
+ // end: updatePermission helper functions
285
+
286
+ async updatePermission(
287
+ permissionDto: Dto['UpdatePermissionDtoMapper'],
288
+ em?: EntityManager
289
+ ): Promise<Dto['PermissionDtoMapper']> {
290
+ const { permission, roles } = await this.updatePermissionDto(permissionDto);
291
+ await (em ?? this.em).upsertMany([permission, ...roles]);
292
+ if (!em) {
293
+ this.em.flush();
294
+ }
295
+ return this.#dtoMappers.PermissionDtoMapper.serializeEntityToDto(
296
+ permission
297
+ );
298
+ }
299
+
300
+ async updateBatchPermissions(
301
+ permissionDtos: Dto['UpdatePermissionDtoMapper'][],
302
+ em?: EntityManager
303
+ ): Promise<Dto['PermissionDtoMapper'][]> {
304
+ const rolesCache: Record<string, Entities['RoleDtoMapper']> = {};
305
+ const permissions: Entities['PermissionDtoMapper'][] = [];
306
+ await (em ?? this.em).transactional(async (em) => {
307
+ permissionDtos.map(async (updatePermissionDto) => {
308
+ const { permission, roles } =
309
+ await this.updatePermissionDto(updatePermissionDto);
310
+ roles.forEach((role) => {
311
+ if (
312
+ rolesCache[role.id] &&
313
+ role.permissions !== rolesCache[role.id].permissions
314
+ ) {
315
+ role.permissions.getItems().forEach((permission) => {
316
+ if (!rolesCache[role.id].permissions.contains(permission)) {
317
+ rolesCache[role.id].permissions.add(permission);
318
+ }
319
+ });
320
+ } else {
321
+ rolesCache[role.id] = role;
322
+ }
323
+ });
324
+ permissions.push(permission);
325
+ });
326
+ await (em ?? this.em).persist([
327
+ ...permissions,
328
+ ...Object.values(rolesCache)
329
+ ]);
330
+ });
331
+
332
+ return permissions.map((permission) =>
333
+ this.#dtoMappers.PermissionDtoMapper.serializeEntityToDto(permission)
334
+ );
335
+ }
336
+
337
+ async deletePermission(idDto: IdDto, em?: EntityManager): Promise<void> {
338
+ await (em ?? this.em).nativeDelete('Permission', idDto);
339
+ }
340
+
341
+ async deleteBatchPermissions(
342
+ idsDto: IdsDto,
343
+ em?: EntityManager
344
+ ): Promise<void> {
345
+ await (em ?? this.em).nativeDelete('Permission', {
346
+ id: { $in: idsDto.ids }
347
+ });
348
+ }
349
+ }