import { OnModuleInit, Inject, Injectable } from '@nestjs/common'; import { ClientGrpc } from '@nestjs/microservices'; import { DadosferaLogger } from '@dadosfera/dadosfera-logs'; import { ProtoServices } from '@dadosfera/protospack-v2/dist/lib/Duc'; import { CustomersProtoService, UsersProtoService, } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/write-service'; import { AssignRoleToUserRequest, IdRequest, UnassignRoleFromUserRequest, UserCreateRequest, } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages'; import { lastValueFrom } from 'rxjs'; import { BatchCreateUserReq, CreateUserReq, Hierarchy, IUserByCustomer, SetUserRolesReq, UpdateUserReq, UserReporter, } from './dtos/entities'; import { RolesService } from '../roles/roles.service'; import { HIERARCHIES } from './hierarchies'; import { LanguageEnum } from 'src/utils/languages.enum'; import { UserByCustomer } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/entities'; import { EnrichErrorCode } from 'src/utils/ErrorBuilder'; import { DucClient } from '../duc/client.config'; import { Metadata } from '@grpc/grpc-js'; import { ParserBuilder } from 'src/utils/FileParser/parser.builder'; @Injectable() export class UsersService implements OnModuleInit { logger: DadosferaLogger; language: LanguageEnum = LanguageEnum.ptbr; private usersClientService: UsersProtoService; private customersClientService: CustomersProtoService; constructor( @Inject(DadosferaLogger) dadosferaLogger: DadosferaLogger, @Inject(DucClient.name) private readonly grpcClient: ClientGrpc, private rolesService: RolesService, ) { this.logger = dadosferaLogger.logger; } onModuleInit() { this.usersClientService = this.grpcClient.getService( ProtoServices.UsersProtoService, ); this.customersClientService = this.grpcClient.getService( ProtoServices.CustomersProtoService, ); } setLanguage(l: LanguageEnum = LanguageEnum.ptbr) { if (Object.values(LanguageEnum).includes(l)) this.language = l; this.rolesService.setLanguage(l); } async findAllUsersByCustomerId(customerId: string) { const { users } = await lastValueFrom( this.usersClientService.UserFindAllByCustomerId({ customerId }), ); const usersAdj = this.adjustUsersPayload(users); const dintinctDepartments = [...new Set(usersAdj.map((u) => u.department))] .filter((value) => value != null) .sort(); const dintinctJobTitles = [...new Set(usersAdj.map((u) => u.jobTitle))] .filter((value) => value != null) .sort(); return { users: usersAdj, jobTitles: dintinctJobTitles, departments: dintinctDepartments, }; } async downloadUsersInCsv(customerId: string) { const { users } = await lastValueFrom( this.usersClientService.UserFindAllByCustomerId({ customerId }), ); const formatUsers: UserReporter[] = users.map(user => ({ createdAt: user.createdAt, email: user.email, lastLogin: user.lastLogin, mfaStatus: user.mfaStatus, name: user.name, status: user.status, updatedAt: user.updatedAt })) const parser = ParserBuilder.build('csv'); const file = await parser.parse(formatUsers); const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const filename = `dadosfera_users_${timestamp}.csv`; return { file, filename } } async findOneById(id: string): Promise<{ user: IUserByCustomer }> { const { user } = await lastValueFrom( this.usersClientService.UserFindOneById({ id }), ); const res: { user: IUserByCustomer } = { user: this.adjustUsersPayload([user])[0], }; const { permissions } = await lastValueFrom( this.usersClientService.GetUserPermissions({ id }), ).catch((error) => { this.logger.error('UsersService.findOneById - GetUserPermissions', { error, }); const permissions: string[] = []; return { permissions }; }); res.user.permissions = permissions; res.user.authProvider = process.env.AUTH_PROVIDER || 'cognito'; return res; } async createUser(req: CreateUserReq, meta?: Metadata) { const { email, department, hierarchy, jobTitle, name, roleNames } = req; const { user } = await lastValueFrom( this.usersClientService.UserCreate( { email, hierarchy, name, roleIds: [], department, jobTitle, roleNames, }, meta, ), ); return { user: this.adjustUsersPayload([user])[0] }; } async updateUser(req: UpdateUserReq, id: string, customerId: string) { const { roleNames, ...updateUserDTO } = req; if (roleNames && roleNames.length > 0) { await this.setRoles({ roleNames, userId: id }, customerId); } const { user } = await lastValueFrom( this.usersClientService.UserUpdate({ department: updateUserDTO.department, email: updateUserDTO.email, hierarchy: updateUserDTO.hierarchy, jobTitle: updateUserDTO.jobTitle, name: updateUserDTO.name, bio: updateUserDTO.bio, companyName: updateUserDTO.companyName, personalSite: updateUserDTO.personalSite, customerId, id, metabaseUserId: undefined, }), ); return { user: this.adjustUsersPayload([user])[0] }; } async setRoles(body: SetUserRolesReq, customerId: string) { const { roleNames, userId } = body; const clearRoles = roleNames && roleNames.length === 0; const { user } = await lastValueFrom( this.usersClientService.UserSetRoles({ userId, roleIds: [], roleNames, clearRoles, customerId, }), ); return { user: this.adjustUsersPayload([user])[0] }; } async batchCreateUser(req: BatchCreateUserReq, meta?: Metadata) { const { users } = req; const usersToCreate: UserCreateRequest[] = users.map( ({ roleNames, email, department, hierarchy, jobTitle, name }) => ({ roleNames, email, department, hierarchy, jobTitle, name, roleIds: [], }), ); const { errorUsers, usersCreated } = await lastValueFrom( this.usersClientService.UserBatchCreate( { users: usersToCreate, }, meta, ), ); return { usersCreated: this.adjustUsersPayload(usersCreated), errorUsers: errorUsers.map(({ user, error }) => ({ user, error: EnrichErrorCode(error).message, })), }; } async resendInvite(body: IdRequest, metadata: Metadata) { return lastValueFrom( this.usersClientService.UserResendInvite(body, metadata), ); } async assignRoleToUser(body: AssignRoleToUserRequest) { return lastValueFrom(this.usersClientService.AssignRoleToUser(body)); } async unassignRoleFromUser(body: UnassignRoleFromUserRequest) { return lastValueFrom(this.usersClientService.UnassignRoleFromUser(body)); } async deleteUser(id: IdRequest) { return lastValueFrom(this.usersClientService.UserRemove(id)); } getAllHierarchies(): { hierarchies: Hierarchy[] } { const hierarchies = Object.keys(HIERARCHIES).map((key) => ({ id: key, name: HIERARCHIES[key]?.name[this.language] || key, })); return { hierarchies }; } async getAllDepartments(customerId?: string) { return lastValueFrom( this.usersClientService.FindDistinctDepartments({ customerId }), ); } async getAllJobTitles(customerId?: string) { return lastValueFrom( this.usersClientService.FindDistinctJobTitles({ customerId }), ); } private adjustUsersPayload(users: UserByCustomer[]) { return users.map((u) => { if (!u) return undefined; return { ...u, roles: this.rolesService.getRolesPermissionsName(u.roles), hierarchy: HIERARCHIES[u.hierarchy]?.name[this.language] || u.hierarchy, }; }); } async findAllCustomers() { return await lastValueFrom(this.customersClientService.CustomerFindAll({})); } async synchronizeUser(userId: string) { return await lastValueFrom( this.usersClientService.INTERNAL_UserSynchronize({ userId }), ); } }