diff --git a/package-lock.json b/package-lock.json index 2f0c031..adaeabe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9017,7 +9017,7 @@ "node_modules/protospack-v2": { "version": "0.0.0", "resolved": "file:../protospack-v2/protospack-v2-0.0.0.tgz", - "integrity": "sha512-kj/mJbme5CULhsRW4fyXdRUtJKzG5Q5zVYg4BSYMRovHi/jcZUgOIXWwOn0rnqLlMlzdl2msx0S9mA7b62IQzQ==", + "integrity": "sha512-ABgU0d8MFh0VhWkGFa3nnSLzmm8Her2rof9Ajoi46FMjwp3N0895F6e7IecM13CUJgcOtkFqbmQF7JU33hB+BA==", "license": "ISC", "dependencies": { "@grpc/grpc-js": "^1.6.7", @@ -17247,7 +17247,7 @@ }, "protospack-v2": { "version": "file:../protospack-v2/protospack-v2-0.0.0.tgz", - "integrity": "sha512-kj/mJbme5CULhsRW4fyXdRUtJKzG5Q5zVYg4BSYMRovHi/jcZUgOIXWwOn0rnqLlMlzdl2msx0S9mA7b62IQzQ==", + "integrity": "sha512-ABgU0d8MFh0VhWkGFa3nnSLzmm8Her2rof9Ajoi46FMjwp3N0895F6e7IecM13CUJgcOtkFqbmQF7JU33hB+BA==", "requires": { "@grpc/grpc-js": "^1.6.7", "rxjs": "^7.5.5", diff --git a/src/authentication/authentication.guard.ts b/src/authentication/authentication.guard.ts index 6e04694..062a87f 100644 --- a/src/authentication/authentication.guard.ts +++ b/src/authentication/authentication.guard.ts @@ -107,7 +107,7 @@ export class AuthenticationGuard } catch (err) { // log errors if authentication is required if (mustBeAuthenticated) { - this.logger.error('Unable to verify duc access token\n' + err.stack); + this.logger.error('Unable to verify duc access token\n' + err?.stack); } return false; diff --git a/src/authentication/permissions.enum.ts b/src/authentication/permissions.enum.ts index 3a8f1cc..bf5da2f 100644 --- a/src/authentication/permissions.enum.ts +++ b/src/authentication/permissions.enum.ts @@ -3,6 +3,11 @@ import assert from 'assert'; const logger = new Logger(); +export enum LanguageEnum { + ptbr = 'pt-br', + enus = 'en-us', +} + export enum PermissionUsages { PUBLIC = 'public', INTERNAL = 'internal', @@ -12,10 +17,7 @@ export interface PermissionsObjectPermission { seqid: number; claim: string; usage: PermissionUsages; - name?: { - 'pt-br': string; - 'en-us': string; - }; + name?: Record; } export interface PermissionsObjectPermissionTranslated { seqid: number; diff --git a/src/modules/permissions/dto/entities.ts b/src/modules/permissions/dto/entities.ts index 9e084d5..4fee93f 100644 --- a/src/modules/permissions/dto/entities.ts +++ b/src/modules/permissions/dto/entities.ts @@ -33,12 +33,3 @@ export class GetPublicPermissionsRes { @ApiProperty({ type: [PermissionGroup] }) permissionGroups: PermissionGroup[]; } - -export enum LanguageEnum { - ptbr = 'pt-br', - enus = 'en-us', -} -export class GetPublicPermissionsHeader { - @ApiPropertyOptional({ enum: LanguageEnum }) - 'dadosfera-lang'; -} diff --git a/src/modules/permissions/permissions.controller.ts b/src/modules/permissions/permissions.controller.ts index d63f3af..aa2e6e6 100644 --- a/src/modules/permissions/permissions.controller.ts +++ b/src/modules/permissions/permissions.controller.ts @@ -1,13 +1,12 @@ import { Controller, Get, Headers, Inject } from '@nestjs/common'; import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; import { DadosferaLogger } from 'dadosfera-logs'; -import { PermissionUsages } from 'src/authentication/permissions.enum'; -import { RequestUser, User } from 'src/authentication/user.decorator'; import { - GetPublicPermissionsHeader, - GetPublicPermissionsRes, LanguageEnum, -} from './dto/entities'; + PermissionUsages, +} from 'src/authentication/permissions.enum'; +import { RequestUser, User } from 'src/authentication/user.decorator'; +import { GetPublicPermissionsRes } from './dto/entities'; import { PermissionsService } from './permissions.service'; @ApiTags('Permissions') @@ -27,11 +26,9 @@ export class PermissionsController { @ApiOkResponse({ type: GetPublicPermissionsRes }) getPublicPermissions( @User() user: RequestUser, - @Headers() headers: GetPublicPermissionsHeader, + @Headers('dadosfera-lang') language: LanguageEnum, ) { this.logger.info('getPublicPermissions', { user }); - - const language: LanguageEnum = headers['dadosfera-lang']; return this.permissionsService.getPermissionsGrouped( PermissionUsages.PUBLIC, language, diff --git a/src/modules/permissions/permissions.service.ts b/src/modules/permissions/permissions.service.ts index 026dcbd..55d774f 100644 --- a/src/modules/permissions/permissions.service.ts +++ b/src/modules/permissions/permissions.service.ts @@ -16,9 +16,10 @@ import { PermissionUsages, PermissionsObjectGroup, PermissionsObjectPermissionTranslated, + LanguageEnum, } from '../../authentication/permissions.enum'; import ErrorBuilder from '../../utils/ErrorBuilder'; -import { LanguageEnum, PermissionDto, PermissionGroup } from './dto/entities'; +import { PermissionDto, PermissionGroup } from './dto/entities'; @Injectable() export class PermissionsService @@ -97,7 +98,7 @@ export class PermissionsService return groups; } getAllPermissions(language: LanguageEnum = LanguageEnum.ptbr) { - const permissions: PermissionsObjectPermissionTranslated[] = []; + let permissions: PermissionsObjectPermissionTranslated[] = []; for (const key in PERMISSIONS) { const permissionGroup: PermissionsObjectGroup = PERMISSIONS[key]; const permissionGroupPermissions: PermissionsObjectPermissionTranslated[] = @@ -105,7 +106,7 @@ export class PermissionsService ...p, name: p.name[language], })); - permissions.concat(permissionGroupPermissions); + permissions = permissions.concat(permissionGroupPermissions); } return permissions; } diff --git a/src/modules/roles/dto/entities.ts b/src/modules/roles/dto/entities.ts index 70e9e8f..50ab808 100644 --- a/src/modules/roles/dto/entities.ts +++ b/src/modules/roles/dto/entities.ts @@ -82,13 +82,31 @@ export class UpdateRoleReq { name: string; @ApiPropertyOptional() description: string; - @ApiPropertyOptional() - userIds: string[]; - @ApiPropertyOptional() - permissionIds: number[]; } export class UpdateRoleRes { @ApiProperty() role: Role; } + +export class SetRolePermissionsReq { + @ApiProperty() + roleId: string; + @ApiProperty() + permissionIds: number[]; +} +export class SetRolePermissionsRes { + @ApiProperty() + role: Role; +} + +export class SetRoleUsersReq { + @ApiProperty() + roleId: string; + @ApiProperty() + userIds: string[]; +} +export class SetRoleUsersRes { + @ApiProperty() + role: Role; +} diff --git a/src/modules/roles/roles.controller.ts b/src/modules/roles/roles.controller.ts index 53771d7..0260665 100644 --- a/src/modules/roles/roles.controller.ts +++ b/src/modules/roles/roles.controller.ts @@ -3,6 +3,7 @@ import { Controller, Delete, Get, + Headers, Inject, Param, Patch, @@ -11,7 +12,12 @@ import { Query, UseFilters, } from '@nestjs/common'; -import { ApiCreatedResponse, ApiOkResponse, ApiTags } from '@nestjs/swagger'; +import { + ApiCreatedResponse, + ApiHeader, + ApiOkResponse, + ApiTags, +} from '@nestjs/swagger'; import { RequestUser, User } from 'src/authentication/user.decorator'; import { DadosferaLogger } from 'dadosfera-logs'; import { RolesService } from './roles.service'; @@ -26,11 +32,25 @@ import { RevokePermissionsFromRoleRes, UpdateRoleReq, UpdateRoleRes, + Role, + SetRolePermissionsReq, + SetRolePermissionsRes, + SetRoleUsersRes, + SetRoleUsersReq, } from './dto/entities'; import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter'; +import { LanguageEnum } from 'src/authentication/permissions.enum'; +import { Authenticated } from 'src/authentication/authentication.decorator'; @ApiTags('Roles') +@ApiHeader({ + name: 'dadosfera-lang', + enum: LanguageEnum, + required: false, + description: 'Defaults to pt-br', +}) @UseFilters(new GrpcToHttpExceptionFilter()) +@Authenticated() @Controller('roles') export class RolesController { logger: any; @@ -48,8 +68,10 @@ export class RolesController { async getRolesByCustomer( @User() user: RequestUser, @Query() filters: GetRolesByCustomerReq, + @Headers('dadosfera-lang') language, ) { this.logger.info('getRolesByCustomer', { user }); + this.rolesService.setLanguage(language); return await this.rolesService.getRolesByCustomer( filters, user.customer_id, @@ -58,24 +80,25 @@ export class RolesController { @Post() @ApiCreatedResponse({ type: CreateRoleRes }) - async createRole(@User() user: RequestUser, @Body() body: CreateRoleReq) { + async createRole( + @User() user: RequestUser, + @Body() body: CreateRoleReq, + @Headers('dadosfera-lang') language, + ) { this.logger.info('createRole', { user }); + this.rolesService.setLanguage(language); return await this.rolesService.createRole(body, user.customer_id); } - @Delete(':id') - async deleteRole(@User() user: RequestUser, @Param('id') id: string) { - this.logger.info('deleteRole', { user }); - return await this.rolesService.removeRole(id); - } - @Put('permissions') @ApiOkResponse({ type: GrantPermissionsToRoleRes }) async grantPermissionsToRole( @User() user: RequestUser, @Body() body: GrantPermissionsToRoleReq, + @Headers('dadosfera-lang') language, ) { this.logger.info('grantPermissionsToRole', { user }); + this.rolesService.setLanguage(language); return await this.rolesService.grantPermissionsToRole(body); } @@ -84,19 +107,69 @@ export class RolesController { async revokePermissionsFromRole( @User() user: RequestUser, @Body() body: RevokePermissionsFromRoleReq, + @Headers('dadosfera-lang') language, ) { this.logger.info('revokePermissionsToRole', { user }); + this.rolesService.setLanguage(language); return await this.rolesService.revokePermissionFromRole(body); } + @Patch('permissions') + @ApiOkResponse({ type: SetRolePermissionsRes }) + async setRolePermissions( + @User() user: RequestUser, + @Body() body: SetRolePermissionsReq, + @Headers('dadosfera-lang') language, + ) { + this.logger.info('setRolePermissions', { user }); + this.rolesService.setLanguage(language); + return this.rolesService.setRolePermissions(body); + } + @Patch('users') + @ApiOkResponse({ type: SetRoleUsersRes }) + async setRoleUsers( + @User() user: RequestUser, + @Body() body: SetRoleUsersReq, + @Headers('dadosfera-lang') language, + ) { + this.logger.info('setRoleUsers', { user }); + this.rolesService.setLanguage(language); + return this.rolesService.setRoleUsers(body); + } + + @Get(':id') + @ApiOkResponse({ type: Role }) + async getRoleById( + @User() user: RequestUser, + @Param('id') id: string, + @Headers('dadosfera-lang') language, + ) { + this.logger.info('getRoleById', { user }); + this.rolesService.setLanguage(language); + return await this.rolesService.getRolesById(id); + } + + @Delete(':id') + async deleteRole( + @User() user: RequestUser, + @Param('id') id: string, + @Headers('dadosfera-lang') language, + ) { + this.logger.info('deleteRole', { user }); + this.rolesService.setLanguage(language); + return await this.rolesService.removeRole(id); + } + @Patch(':id') @ApiOkResponse({ type: UpdateRoleRes }) async updateRole( @User() user: RequestUser, @Param('id') id: string, @Body() body: UpdateRoleReq, + @Headers('dadosfera-lang') language, ) { this.logger.info('updateRole', { user }); + this.rolesService.setLanguage(language); return this.rolesService.updateRole(id, body); } } diff --git a/src/modules/roles/roles.service.ts b/src/modules/roles/roles.service.ts index a8197ee..58857f1 100644 --- a/src/modules/roles/roles.service.ts +++ b/src/modules/roles/roles.service.ts @@ -7,17 +7,20 @@ import { GrantPermissionsToRoleReq, RevokePermissionsFromRoleReq, Role, + SetRolePermissionsReq, + SetRoleUsersReq, UpdateRoleReq, } from './dto/entities'; import { DadosferaLogger } from 'dadosfera-logs'; import { ClientGrpc } from '@nestjs/microservices'; import { lastValueFrom } from 'rxjs'; import { PermissionsService } from '../permissions/permissions.service'; +import { LanguageEnum } from 'src/authentication/permissions.enum'; @Injectable() export class RolesService { logger: any; - + private language: LanguageEnum = LanguageEnum.ptbr; private rolesClientService: RolesProtoService; constructor( @Inject(DadosferaLogger) @@ -27,12 +30,24 @@ export class RolesService { ) { this.logger = dadosferaLogger.logger; } + setLanguage(lang: LanguageEnum = LanguageEnum.ptbr) { + this.language = lang; + } onModuleInit() { this.rolesClientService = this.grpcClient.getService( ProtoServices.RolesProtoService, ); } + async getRolesById(id: string) { + const role = await lastValueFrom( + this.rolesClientService.RoleFindOneById({ + id, + }), + ); + const [roleTreated] = this.getRolesPermissionsName([role.role]); + return { role: roleTreated }; + } async getRolesByCustomer(filters: GetRolesByCustomerReq, customerId: string) { let { permissionIds } = filters; if (permissionIds && !Array.isArray(permissionIds)) @@ -109,15 +124,41 @@ export class RolesService { } async updateRole(id: string, req: UpdateRoleReq) { - const { description, name, permissionIds, userIds } = req; + const { description, name } = req; const role = await lastValueFrom( this.rolesClientService.RoleUpdate({ id, description, name, - permissionIds: [], - permissionReqIds: permissionIds, + }), + ); + const [roleTreated] = this.getRolesPermissionsName([role.role]); + return { role: roleTreated }; + } + + async setRolePermissions(req: SetRolePermissionsReq) { + const { roleId: id, permissionIds } = req; + const clearPermissions = + Array.isArray(permissionIds) && permissionIds.length === 0; + const role = await lastValueFrom( + this.rolesClientService.RoleSetPermissions({ + id, + permissionSeqIds: permissionIds, + clearPermissions, + }), + ); + const [roleTreated] = this.getRolesPermissionsName([role.role]); + return { role: roleTreated }; + } + + async setRoleUsers(req: SetRoleUsersReq) { + const { roleId: id, userIds } = req; + const clearUsers = Array.isArray(userIds) && userIds.length === 0; + const role = await lastValueFrom( + this.rolesClientService.RoleSetUsers({ + id, userIds, + clearUsers, }), ); const [roleTreated] = this.getRolesPermissionsName([role.role]); @@ -125,9 +166,9 @@ export class RolesService { } getRolesPermissionsName(roles: Role[]) { for (const role of roles) { - const permisisonSeqIds = role.permissions.map((p) => p.seqid); - const permissions = - this.permissionsService.getPermissionsBySeqId(permisisonSeqIds); + const permissions = this.permissionsService.getAllPermissions( + this.language, + ); role.permissions.forEach((p) => { const permission = permissions.find((per) => per.seqid === p.seqid); p.name = permission.name; diff --git a/src/utils/ErrorBuilder.ts b/src/utils/ErrorBuilder.ts index b00e8f1..e89f2d1 100644 --- a/src/utils/ErrorBuilder.ts +++ b/src/utils/ErrorBuilder.ts @@ -119,6 +119,13 @@ export function EnrichErrorCode(code: string) { message: 'Não é possível criar um grupo com esse nome', code, }; + case ErrorCodes.ROLE.NOT_FOUND: + return { + statusCode: HttpStatus.NOT_FOUND, + error: 'Grupo não encontrado', + message: 'Grupo solicitado não encontrado', + code, + }; case ErrorCodes.INTERNAL: case ErrorCodes.UNKNOWN: default: @@ -138,9 +145,9 @@ const logger = new Logger(); export default class ErrorBuilder extends HttpException { code: string; - constructor(code: string | RpcException) { + constructor(code: string | RpcException = '') { if (typeof code !== 'string') { - logger.log(code.stack); + logger.log(code?.stack); code = (code as any).details as string; } else { logger.log(code); diff --git a/src/utils/errorCodes.ts b/src/utils/errorCodes.ts index 74a60ec..4eb3671 100644 --- a/src/utils/errorCodes.ts +++ b/src/utils/errorCodes.ts @@ -15,6 +15,7 @@ export const AUTH = { }; export const ROLE = { ALREADY_EXIST: 'ROLE.ALREADY_EXISTS', + NOT_FOUND: 'ROLE.NOT_FOUND', }; const ErrorCodes = { UNKNOWN: 'UNKNOWN',