mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 20:40:55 +00:00
add service-types and cargo-types CRUD modules with pagination, filtering
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
Param,
|
||||
ParseUUIDPipe,
|
||||
Put,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags } from "@nestjs/swagger";
|
||||
|
||||
import { BackofficeService } from "./backoffice.service";
|
||||
import { UpdateEmployeeUserRolesDto } from "./dto/update-employee-user-roles.dto";
|
||||
|
||||
@ApiTags("backoffice")
|
||||
@Controller("backoffice")
|
||||
export class BackofficeController {
|
||||
constructor(private readonly backofficeService: BackofficeService) {}
|
||||
|
||||
@Get("organizations/:orgId/employee-users/:userId/roles")
|
||||
@ApiOperation({ summary: "Get org-scoped roles assigned to an employee user" })
|
||||
getEmployeeUserRoles(
|
||||
@Param("orgId", ParseUUIDPipe) organizationId: string,
|
||||
@Param("userId", ParseUUIDPipe) userId: string,
|
||||
) {
|
||||
return this.backofficeService.getEmployeeUserRoles(organizationId, userId);
|
||||
}
|
||||
|
||||
@Put("organizations/:orgId/employee-users/:userId/roles")
|
||||
@ApiOperation({ summary: "Replace org-scoped roles assigned to an employee user" })
|
||||
replaceEmployeeUserRoles(
|
||||
@Param("orgId", ParseUUIDPipe) organizationId: string,
|
||||
@Param("userId", ParseUUIDPipe) userId: string,
|
||||
@Body() dto: UpdateEmployeeUserRolesDto,
|
||||
) {
|
||||
return this.backofficeService.replaceEmployeeUserRoles(
|
||||
organizationId,
|
||||
userId,
|
||||
dto.roleIds,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { TypeOrmModule } from "@nestjs/typeorm";
|
||||
|
||||
import { Role } from "@tria-plc/iamapi-common/entities/iam/user/role.entity";
|
||||
import { UserRole } from "@tria-plc/iamapi-common/entities/iam/user/user-role.entity";
|
||||
import { User } from "@tria-plc/iamapi-common/entities/iam/user/user.entity";
|
||||
|
||||
import { BackofficeController } from "./backoffice.controller";
|
||||
import { BackofficeService } from "./backoffice.service";
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Role, UserRole, User])],
|
||||
controllers: [BackofficeController],
|
||||
providers: [BackofficeService],
|
||||
exports: [BackofficeService],
|
||||
})
|
||||
export class BackofficeModule {}
|
||||
@@ -0,0 +1,127 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { DataSource, In, IsNull, Repository } from "typeorm";
|
||||
|
||||
import { Role } from "@tria-plc/iamapi-common/entities/iam/user/role.entity";
|
||||
import { UserRole } from "@tria-plc/iamapi-common/entities/iam/user/user-role.entity";
|
||||
import { User } from "@tria-plc/iamapi-common/entities/iam/user/user.entity";
|
||||
|
||||
const RESERVED_ROLE_KEYS = new Set([
|
||||
"super_admin",
|
||||
"organization_admin",
|
||||
"unit_admin",
|
||||
]);
|
||||
|
||||
@Injectable()
|
||||
export class BackofficeService {
|
||||
constructor(
|
||||
@InjectRepository(Role)
|
||||
private readonly roleRepository: Repository<Role>,
|
||||
@InjectRepository(UserRole)
|
||||
private readonly userRoleRepository: Repository<UserRole>,
|
||||
@InjectRepository(User)
|
||||
private readonly userRepository: Repository<User>,
|
||||
private readonly dataSource: DataSource,
|
||||
) {}
|
||||
|
||||
async getEmployeeUserRoles(organizationId: string, userId: string) {
|
||||
await this.assertUserBelongsToOrganization(organizationId, userId);
|
||||
|
||||
const userRoles = await this.userRoleRepository.find({
|
||||
where: {
|
||||
userId,
|
||||
organizationId,
|
||||
unitId: IsNull(),
|
||||
},
|
||||
relations: {
|
||||
role: true,
|
||||
},
|
||||
order: {
|
||||
role: {
|
||||
key: "ASC",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return userRoles
|
||||
.map((userRole) => userRole.role)
|
||||
.filter((role): role is Role => Boolean(role))
|
||||
.map((role) => ({
|
||||
id: role.id,
|
||||
key: role.key,
|
||||
name: role.name,
|
||||
}));
|
||||
}
|
||||
|
||||
async replaceEmployeeUserRoles(
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
roleIds: string[],
|
||||
) {
|
||||
await this.assertUserBelongsToOrganization(organizationId, userId);
|
||||
|
||||
const uniqueRoleIds = [...new Set(roleIds)];
|
||||
const roles = uniqueRoleIds.length
|
||||
? await this.roleRepository.find({
|
||||
where: {
|
||||
id: In(uniqueRoleIds),
|
||||
},
|
||||
})
|
||||
: [];
|
||||
|
||||
if (roles.length !== uniqueRoleIds.length) {
|
||||
throw new NotFoundException("one_or_more_roles_not_found");
|
||||
}
|
||||
|
||||
const reservedRoles = roles.filter((role) => RESERVED_ROLE_KEYS.has(role.key));
|
||||
if (reservedRoles.length) {
|
||||
throw new BadRequestException("reserved_roles_must_use_admin_actions");
|
||||
}
|
||||
|
||||
await this.dataSource.transaction(async (manager) => {
|
||||
await manager.getRepository(UserRole).delete({
|
||||
userId,
|
||||
organizationId,
|
||||
unitId: IsNull(),
|
||||
});
|
||||
|
||||
if (!roles.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
await manager.getRepository(UserRole).insert(
|
||||
roles.map((role) => ({
|
||||
userId,
|
||||
roleId: role.id,
|
||||
organizationId,
|
||||
})),
|
||||
);
|
||||
});
|
||||
|
||||
return this.getEmployeeUserRoles(organizationId, userId);
|
||||
}
|
||||
|
||||
private async assertUserBelongsToOrganization(
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
) {
|
||||
const exists = await this.userRepository
|
||||
.createQueryBuilder("user")
|
||||
.innerJoin(
|
||||
"user.employee",
|
||||
"employee",
|
||||
"employee.organizationId = :organizationId AND employee.isCurrent = true",
|
||||
{ organizationId },
|
||||
)
|
||||
.where("user.id = :userId", { userId })
|
||||
.getExists();
|
||||
|
||||
if (!exists) {
|
||||
throw new NotFoundException("user_not_found_in_organization");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsArray, IsUUID } from "class-validator";
|
||||
|
||||
export class UpdateEmployeeUserRolesDto {
|
||||
@ApiProperty({ type: [String] })
|
||||
@IsArray()
|
||||
@IsUUID("4", { each: true })
|
||||
roleIds!: string[];
|
||||
}
|
||||
Reference in New Issue
Block a user