Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ lerna-debug.log*
# ignore the .env
.env
.vstags

# ignore the prisma client
src/generated/prisma
2 changes: 1 addition & 1 deletion backend/bin/pgsql-migrate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Logger } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { PrismaClient } from 'src/generated/prisma/client';
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as path from 'path';
Expand Down
2,420 changes: 1,683 additions & 737 deletions backend/package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
"@nestjs/schedule": "^6.0.0",
"@nestjs/serve-static": "^5.0.3",
"@nestjs/swagger": "^11.2.0",
"@prisma/client": "^6.11.1",
"@prisma/adapter-pg": "^6.11.1",
"@prisma/client": "^6.12.0",
"@ts-graphviz/adapter": "^2.0.6",
"@turf/simplify": "^7.2.0",
"@types/geojson": "^7946.0.16",
Expand Down Expand Up @@ -122,7 +123,7 @@
"jest": "30.0.4",
"mjml": "^4.15.3",
"prettier": "^3.6.2",
"prisma": "^6.11.1",
"prisma": "^6.12.0",
"source-map-support": "^0.5.21",
"supertest": "^7.1.3",
"ts-jest": "29.4.0",
Expand Down
6 changes: 4 additions & 2 deletions backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
generator client {
provider = "prisma-client-js"
previewFeatures = ["views", "relationJoins"]
provider = "prisma-client"
output = "../src/generated/prisma" // `output` is required
moduleFormat = "cjs" // or `"cjs"` for CommonJS
previewFeatures = ["views", "relationJoins", "driverAdapters", "queryCompiler", "typedSql"]
}

datasource db {
Expand Down
2 changes: 1 addition & 1 deletion backend/prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
Prisma,
PrismaClient,
Privilegio,
} from '@prisma/client';
} from 'src/generated/prisma/client';
import { ListaDePrivilegios } from '../src/common/ListaDePrivilegios';
import {
CONST_COD_NOTA_DIST_RECURSO,
Expand Down
2 changes: 1 addition & 1 deletion backend/src/any-error.filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class AllExceptionsFilter implements ExceptionFilter {
const ctx = host.switchToHttp();
const request = ctx.getRequest<AuthRequest>();
let ehAdmin: boolean = false;
if (request.user && request.user.hasSomeRoles(['SMAE.superadmin'])) ehAdmin = true;
if (request.user && typeof request.user.hasSomeRoles === 'function' && request.user.hasSomeRoles(['SMAE.superadmin'])) ehAdmin = true;

const httpStatusCode =
exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;
Expand Down
2 changes: 1 addition & 1 deletion backend/src/api-logs/backup-scheduler.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { task_type } from '@prisma/client';
import { task_type } from 'src/generated/prisma/client';
import { DateTime } from 'luxon';
import { SmaeConfigService } from 'src/common/services/smae-config.service';
import { PrismaService } from 'src/prisma/prisma.service';
Expand Down
2 changes: 1 addition & 1 deletion backend/src/api-logs/restore/api-log-restore.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Body, Controller, Post, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiOkResponse, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { task_type } from '@prisma/client';
import { task_type } from 'src/generated/prisma/client';
import { Roles } from 'src/auth/decorators/roles.decorator';
import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard';
import { RolesGuard } from 'src/auth/guards/roles.guard';
Expand Down
2 changes: 1 addition & 1 deletion backend/src/atividade/atividade.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BadRequestException, HttpException, Injectable, Logger } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { Prisma } from 'src/generated/prisma/client';
import { CronogramaAtrasoGrau } from 'src/common/dto/CronogramaAtrasoGrau.dto';
import { PessoaFromJwt } from '../auth/models/PessoaFromJwt';
import { UniqueNumbers } from '../common/UniqueNumbers';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BadRequestException, forwardRef, Inject, Injectable, Logger, NotFoundException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Prisma, TipoAtualizacaoEmLote } from '@prisma/client';
import { Prisma, TipoAtualizacaoEmLote } from 'src/generated/prisma/client';
import { DateTime } from 'luxon';
import { PessoaFromJwt } from 'src/auth/models/PessoaFromJwt';
import { SYSTEM_TIMEZONE } from 'src/common/date2ymd';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ApiProperty, ApiPropertyOptional, OmitType } from '@nestjs/swagger';
import { ModuloSistema, StatusAtualizacaoEmLote, TipoAtualizacaoEmLote } from '@prisma/client';
import { ModuloSistema, StatusAtualizacaoEmLote, TipoAtualizacaoEmLote } from 'src/generated/prisma/client';
import { Transform } from 'class-transformer';
import { IsDateString, IsEnum, IsInt, IsOptional, Max, Min } from 'class-validator';
import { NumberTransformOrUndef } from '../../auth/transforms/number.transform';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { DateTime } from 'luxon';
import { UpdateOperacaoDto } from '../../task/run_update/dto/create-run-update.dto';
import { PrismaService } from '../../prisma/prisma.service';
import { OperacaoProcessadaDto, OperacaoProcessadaItemDto } from '../dto/atualizacao-em-lote.dto';
import { ProjetoStatus, TipoAtualizacaoEmLote } from '@prisma/client';
import { ProjetoStatus, TipoAtualizacaoEmLote } from 'src/generated/prisma/client';
import { FormatCurrency } from '../../common/format-currency';

// Mapeia nomes de colunas para rótulos legíveis por humanos com cobertura abrangente de todos os campos
Expand Down
19 changes: 15 additions & 4 deletions backend/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,32 @@ import { PrivController } from './priv.controller';
import { PrivService } from './priv.service';
import { JwtStrategy } from './strategies/jwt.strategy';
import { LocalStrategy } from './strategies/local.strategy';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
imports: [
PrismaModule,
PessoaModule,
PassportModule,
FeatureFlagModule,
JwtModule.register({
secret: process.env.SESSION_JWT_SECRET,
signOptions: { expiresIn: '30d' },

ConfigModule.forRoot({
isGlobal: true,
}),

JwtModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
// Agora, o secret é carregado de forma segura
secret: configService.get<string>('SESSION_JWT_SECRET'),
signOptions: { expiresIn: '30d' },
}),
}),
],
controllers: [AuthController, PrivController, PerfilAcessoController],
providers: [AuthService, LocalStrategy, JwtStrategy, PrivService, PerfilAcessoService],
exports: [AuthService],
exports: [AuthService, JwtModule],
})
export class AuthModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
Expand Down
3 changes: 2 additions & 1 deletion backend/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { ModuloSistema } from '@prisma/client';
import { ModuloSistema } from 'src/generated/prisma/client';
import { FeatureFlagService } from '../feature-flag/feature-flag.service';
import { Pessoa } from '../pessoa/entities/pessoa.entity';
import { PessoaService } from '../pessoa/pessoa.service';
Expand Down Expand Up @@ -75,6 +75,7 @@ export class AuthService {
}

async pessoaJwtFromId(pessoa_id: number): Promise<PessoaFromJwt> {
console.log(`pessoaJwtFromId: ${pessoa_id}`);
const pessoa = await this.pessoaPeloId(pessoa_id);

const modPriv = await this.listaPrivilegiosPessoa(pessoa.id as number, undefined);
Expand Down
31 changes: 22 additions & 9 deletions backend/src/auth/guards/roles.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,53 @@ import { Reflector } from '@nestjs/core';
import { ListaDePrivilegios } from '../../common/ListaDePrivilegios';
import { ROLES_KEY } from './../decorators/roles.decorator';
import { PessoaFromJwt } from './../models/PessoaFromJwt';
import { IS_PUBLIC_KEY } from '../decorators/is-public.decorator';

@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}

canActivate(context: ExecutionContext): boolean {
const handler = context.getHandler();
const className = context.getClass().name;
// const handler = context.getHandler();
// const className = context.getClass().name;

const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
]);

if (isPublic) {
return true;
}

const requiredRoles = this.reflector.getAllAndOverride<ListaDePrivilegios[]>(ROLES_KEY, [
handler,
context.getHandler(),
context.getClass(),
]);

if (!requiredRoles) {
return true;
}

const request = context.switchToHttp().getRequest();
const { user } = request;
const requestUrl = request.originalUrl || request.url;
const debug = `requestUrl = ${requestUrl}, controller = ${className}, smae-sistemas = ${request.headers['smae-sistemas'] ?? '-'}`;
///const debug = `requestUrl = ${requestUrl}, controller = ${className}, smae-sistemas = ${request.headers['smae-sistemas'] ?? '-'}`;

if (!user)
if (!user) {
throw new UnauthorizedException(
`Usuário não encontrado, necessário para verificar os acessos:\n${requiredRoles.join(', ')}\n\n${debug}`
`Usuário não encontrado, necessário para verificar os acessos: \n${requiredRoles.join(', ')}`
);
}

const jwtUser = user instanceof PessoaFromJwt ? user : new PessoaFromJwt(user);

const JwtUser = user as PessoaFromJwt;
if (JwtUser.hasSomeRoles(requiredRoles)) {
if (jwtUser.hasSomeRoles(requiredRoles)) {
return true;
}

throw new UnauthorizedException(
`Ao menos um dos seguintes privilégios é necessário para o acesso:\n\n${requiredRoles.join(', ')}\n\n${debug}`
`Ao menos um dos seguintes privilégios é necessário para o acesso: \n${requiredRoles.join(', ')}`
);
}
}
2 changes: 1 addition & 1 deletion backend/src/auth/models/PessoaFromJwt.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BadRequestException, HttpException } from '@nestjs/common';
import { ModuloSistema, PdmPerfilTipo, Prisma } from '@prisma/client';
import { ModuloSistema, PdmPerfilTipo, Prisma } from 'src/generated/prisma/client';
import { plainToInstance } from 'class-transformer';
import { TipoPdmType } from '../../common/decorators/current-tipo-pdm';
import { ListaDePrivilegios } from '../../common/ListaDePrivilegios';
Expand Down
2 changes: 1 addition & 1 deletion backend/src/auth/models/PessoaFromJwtBase.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ApiProperty } from '@nestjs/swagger';
import { ModuloSistema, PerfilResponsavelEquipe } from '@prisma/client';
import { ModuloSistema, PerfilResponsavelEquipe } from 'src/generated/prisma/client';
import { ListaDePrivilegios } from '../../common/ListaDePrivilegios';
import { FeatureFlagDto } from './FeatureFlagDto';

Expand Down
2 changes: 1 addition & 1 deletion backend/src/auth/models/Privilegios.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BadRequestException } from '@nestjs/common';
import { ApiProperty } from '@nestjs/swagger';
import { ModuloSistema } from '@prisma/client';
import { ModuloSistema } from 'src/generated/prisma/client';
import { Transform, TransformFnParams } from 'class-transformer';
import { IsArray, IsOptional } from 'class-validator';

Expand Down
2 changes: 1 addition & 1 deletion backend/src/auth/perfilAcesso.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BadRequestException, HttpException, Injectable } from '@nestjs/common';
import { PessoaFromJwt } from '../auth/models/PessoaFromJwt';
import { PrismaService } from '../prisma/prisma.service';
import { CreatePerfilAcessoDto, PerfilAcessoSimplesDto, UpdatePerfilAcessoDto } from './models/PerfilAcesso.dto';
import { Prisma } from '@prisma/client';
import { Prisma } from 'src/generated/prisma/client';

@Injectable()
export class PerfilAcessoService {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/auth/pessoaPrivilegio.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable, InternalServerErrorException } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { Prisma } from 'src/generated/prisma/client';
import { ListaDePrivilegios } from '../common/ListaDePrivilegios';
import { PrismaService } from '../prisma/prisma.service';

Expand Down
14 changes: 9 additions & 5 deletions backend/src/auth/strategies/jwt.strategy.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ModuloSistema } from '@prisma/client';
import { ModuloSistema } from 'src/generated/prisma/client';
import { Request } from 'express';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { ExtractJwt, Strategy, StrategyOptionsWithRequest } from 'passport-jwt';
import { extractIpAddress } from '../../common/decorators/current-ip';
import { JwtPessoaPayload } from '../models/JwtPessoaPayload';
import { PessoaFromJwt } from '../models/PessoaFromJwt';
import { ValidateModuloSistema } from '../models/Privilegios.dto';
import { AuthService } from './../auth.service';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
constructor(
private authService: AuthService,
configService: ConfigService
) {
const secret = process.env.SESSION_JWT_SECRET;
if (!secret) throw new Error('SESSION_JWT_SECRET environment variable is required');

super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: secret,
secretOrKey: configService.get<string>('SESSION_JWT_SECRET'),
audience: 'l',
passReqToCallback: true,
});
} as StrategyOptionsWithRequest);
}

async validate(req: Request, payload: JwtPessoaPayload): Promise<PessoaFromJwt> {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/aviso-email/aviso-email.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { AvisoEmailService } from './aviso-email.service';
import { CreateAvisoEmailDto } from './dto/create-aviso-email.dto';
import { UpdateAvisoEmailDto } from './dto/update-aviso-email.dto';
import { FilterAvisoEamilDto, ListAvisoEmailDto } from './entities/aviso-email.entity';
import { Prisma } from '@prisma/client';
import { Prisma } from 'src/generated/prisma/client';

//const roles: ListaDePrivilegios[] = [];

Expand Down
2 changes: 1 addition & 1 deletion backend/src/aviso-email/aviso-email.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BadRequestException, Inject, Injectable, Logger, NotFoundException, forwardRef } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { Prisma } from 'src/generated/prisma/client';
import { PessoaFromJwt } from '../auth/models/PessoaFromJwt';
import { RecordWithId } from '../common/dto/record-with-id.dto';
import { PrismaService } from '../prisma/prisma.service';
Expand Down
8 changes: 4 additions & 4 deletions backend/src/aviso-email/dto/create-aviso-email.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';
import { AvisoPeriodo, TipoAviso } from '@prisma/client';
import { IsArray, IsBoolean, IsEmail, IsEnum, IsInt, IsOptional, IsString, Max, Min } from 'class-validator';
import { IsArray, IsBoolean, IsEmail, IsInt, IsOptional, IsString, Max, Min } from 'class-validator';
import { AvisoPeriodo, TipoAviso } from 'src/generated/prisma/client';

export class CreateAvisoEmailDto {
@IsInt()
Expand All @@ -13,15 +13,15 @@ export class CreateAvisoEmailDto {
enum: AvisoPeriodo,
enumName: 'AvisoPeriodo',
})
@IsEnum(AvisoPeriodo)
//@IsEnum(AvisoPeriodo)
numero_periodo: AvisoPeriodo;

@ApiProperty({
description: 'qual regra de negocio o aviso de trata',
enum: TipoAviso,
enumName: 'TipoAviso',
})
@IsEnum(TipoAviso)
//@IsEnum(TipoAviso)
tipo: TipoAviso;

@IsBoolean()
Expand Down
2 changes: 1 addition & 1 deletion backend/src/aviso-email/entities/aviso-email.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AvisoPeriodo, TipoAviso } from '@prisma/client';
import { AvisoPeriodo, TipoAviso } from 'src/generated/prisma/client';
import { Transform } from 'class-transformer';
import { IsInt, IsOptional, IsString } from 'class-validator';
import { IdDesc } from '../../atividade/entities/atividade.entity';
Expand Down
2 changes: 1 addition & 1 deletion backend/src/bloco-nota/bloco-nota/bloco-nota.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HttpException, Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Prisma } from '@prisma/client';
import { Prisma } from 'src/generated/prisma/client';
import { PessoaFromJwt } from '../../auth/models/PessoaFromJwt';
import { PrismaService } from '../../prisma/prisma.service';
import { BlocoNotaItem, CreateBlocoNotaDto } from './dto/bloco-nota.dto';
Expand Down
2 changes: 1 addition & 1 deletion backend/src/bloco-nota/nota/dto/nota.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BadRequestException } from '@nestjs/common';
import { ApiProperty, IntersectionType, PartialType, PickType } from '@nestjs/swagger';
import { StatusNota } from '@prisma/client';
import { StatusNota } from 'src/generated/prisma/client';
import { Transform, TransformFnParams, Type } from 'class-transformer';
import {
IsArray,
Expand Down
2 changes: 1 addition & 1 deletion backend/src/bloco-nota/nota/nota.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Nota, Prisma, TipoNota } from '@prisma/client';
import { Nota, Prisma, TipoNota } from 'src/generated/prisma/client';
import { DateTime } from 'luxon';
import { SmaeConfigService } from 'src/common/services/smae-config.service';
import { uuidv7 } from 'uuidv7';
Expand Down
2 changes: 1 addition & 1 deletion backend/src/bloco-nota/tipo-nota/dto/tipo-nota.dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ApiProperty, OmitType, PartialType } from '@nestjs/swagger';
import { ModuloSistema } from '@prisma/client';
import { ModuloSistema } from 'src/generated/prisma/client';
import { Transform } from 'class-transformer';
import { IsArray, IsBoolean, IsEnum, IsInt, IsOptional, IsString, MaxLength, MinLength } from 'class-validator';
import { NumberTransform } from '../../../auth/transforms/number.transform';
Expand Down
2 changes: 1 addition & 1 deletion backend/src/bloco-nota/tipo-nota/tipo-nota.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BadRequestException, HttpException, Injectable, NotFoundException } from '@nestjs/common';
import { Prisma, TipoNota } from '@prisma/client';
import { Prisma, TipoNota } from 'src/generated/prisma/client';
import { PessoaFromJwt } from '../../auth/models/PessoaFromJwt';
import { PrismaService } from '../../prisma/prisma.service';
import { CreateTipoNotaDto, FilterTipoNota, TipoNotaItem, UpdateTipoNotaDto } from './dto/tipo-nota.dto';
Expand Down
2 changes: 1 addition & 1 deletion backend/src/busca-global/dto/busca-global.entity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// dto/unified-search.dto.ts
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { ModuloSistema } from '@prisma/client';
import { ModuloSistema } from 'src/generated/prisma/client';

export class UnifiedTableMetadadoDto {
@ApiProperty()
Expand Down
Loading