@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.
- package/LICENSE +21 -0
- package/__test__/schemaEquality.test.ts +293 -0
- package/index.ts +8 -0
- package/package.json +48 -0
- package/schemas/organization.schema.ts +28 -0
- package/schemas/permission.schema.ts +28 -0
- package/schemas/role.schema.ts +28 -0
- package/schemas/typebox/organization.schema.ts +49 -0
- package/schemas/typebox/permission.schema.ts +30 -0
- package/schemas/typebox/role.schema.ts +36 -0
- package/schemas/typebox/user.schema.ts +52 -0
- package/schemas/user.schema.ts +28 -0
- package/schemas/zod/organization.schema.ts +49 -0
- package/schemas/zod/permission.schema.ts +30 -0
- package/schemas/zod/role.schema.ts +36 -0
- package/schemas/zod/user.schema.ts +52 -0
- package/services/organization.service.ts +146 -0
- package/services/permission.service.ts +349 -0
- package/services/role.service.ts +182 -0
- package/services/user.service.ts +225 -0
- package/tsconfig.json +7 -0
|
@@ -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
|
+
}
|