This commit is contained in:
Michael Abebe
2026-06-02 12:12:28 +03:00
parent 88219ee9b8
commit 2a489ca18d
6 changed files with 353 additions and 75 deletions

View File

@@ -6,7 +6,7 @@ import {
import { InjectRepository } from "@nestjs/typeorm";
import { hashPassword } from "@tria-plc/api-common/utils/argon";
import { EUserStatus } from "@tria-plc/api-common/utils/enums/user.enum";
import { DataSource, In, IsNull, Repository } from "typeorm";
import { DataSource, EntityManager, In, IsNull, Repository } from "typeorm";
import { Employee, Organization, UserCredential } from "@tria-plc/iamapi-common";
import { Role } from "@tria-plc/iamapi-common/entities/iam/user/role.entity";
@@ -21,6 +21,8 @@ const RESERVED_ROLE_KEYS = new Set([
"unit_admin",
]);
const DEFAULT_USER_PASSWORD = "12345678";
const ORGANIZATION_ADMIN_ROLE_KEY = "organization_admin";
const EDR_ORG_MANAGER_ROLE_KEY = "edr_org_manager";
@Injectable()
export class BackofficeService {
@@ -51,6 +53,7 @@ export class BackofficeService {
const email = dto.email.trim().toLowerCase();
const username = dto.username.trim().toLowerCase();
const phoneNumber = dto.phoneNumber?.trim() || undefined;
const assignOrganizationAdmin = dto.assignOrganizationAdmin === true;
const name = {
en: dto.name.en.trim(),
...(dto.name.am?.trim() ? { am: dto.name.am.trim() } : {}),
@@ -168,6 +171,16 @@ export class BackofficeService {
throw new NotFoundException("employee_create_failed");
}
const userId = user.id;
if (!userId) {
throw new NotFoundException("user_create_failed");
}
if (assignOrganizationAdmin) {
await this.ensureOrganizationAdminAccess(manager, organizationId, userId);
}
return employee;
});
}
@@ -268,4 +281,57 @@ export class BackofficeService {
throw new NotFoundException("user_not_found_in_organization");
}
}
private async ensureOrganizationAdminAccess(
manager: EntityManager,
organizationId: string,
userId: string,
) {
const roles = await manager.getRepository(Role).find({
where: [
{ key: ORGANIZATION_ADMIN_ROLE_KEY },
{ key: EDR_ORG_MANAGER_ROLE_KEY },
],
select: { id: true, key: true },
});
const requiredRoles = [ORGANIZATION_ADMIN_ROLE_KEY, EDR_ORG_MANAGER_ROLE_KEY].map((key) => {
const role = roles.find((item) => item.key === key);
if (!role?.id) {
throw new NotFoundException(`required_role_not_seeded:${key}`);
}
return {
id: role.id,
key: role.key,
};
});
const existingRoleIds = new Set(
(
await manager.getRepository(UserRole).find({
where: {
userId,
organizationId,
},
select: { roleId: true },
})
).map((userRole) => userRole.roleId),
);
const rolesToInsert = requiredRoles
.filter((role) => !existingRoleIds.has(role.id))
.map((role) => ({
userId,
roleId: role.id,
organizationId,
}));
if (!rolesToInsert.length) {
return;
}
await manager.getRepository(UserRole).insert(rolesToInsert);
}
}

View File

@@ -1,5 +1,5 @@
import { ApiProperty } from "@nestjs/swagger";
import { IsEmail, IsObject, IsOptional, IsString, MinLength } from "class-validator";
import { IsBoolean, IsEmail, IsObject, IsOptional, IsString, MinLength } from "class-validator";
class CreateOrganizationUserNameDto {
@ApiProperty()
@@ -31,4 +31,9 @@ export class CreateOrganizationUserDto {
@ApiProperty({ type: CreateOrganizationUserNameDto })
@IsObject()
name!: CreateOrganizationUserNameDto;
@ApiProperty({ required: false, default: false })
@IsOptional()
@IsBoolean()
assignOrganizationAdmin?: boolean;
}