diff --git a/src/auth-google/auth-google.service.ts b/src/auth-google/auth-google.service.ts index cef0842a..312f3778 100644 --- a/src/auth-google/auth-google.service.ts +++ b/src/auth-google/auth-google.service.ts @@ -4,7 +4,7 @@ import { OAuth2Client } from 'google-auth-library'; import { SocialInterface } from '../social/interfaces/social.interface'; import { AuthGoogleLoginDto } from './dto/auth-google-login.dto'; import { AllConfigType } from 'src/config/config.type'; -import { HttpErrorMessages } from 'src/utils/enums/http-error-messages.enum'; +import { HttpStatusMessage } from 'src/utils/enums/http-error-message.enum'; @Injectable() export class AuthGoogleService { @@ -32,7 +32,7 @@ export class AuthGoogleService { if (!data) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { user: 'wrongToken', }, diff --git a/src/auth-licensee/auth-licensee.controller.ts b/src/auth-licensee/auth-licensee.controller.ts index ed52a4cd..a33fda9b 100644 --- a/src/auth-licensee/auth-licensee.controller.ts +++ b/src/auth-licensee/auth-licensee.controller.ts @@ -16,6 +16,7 @@ import { AuthLicenseeLoginDto } from './dto/auth-licensee-login.dto'; import { AuthRegisterLicenseeDto } from './dto/auth-register-licensee.dto'; import { IALConcludeRegistration } from './interfaces/al-conclude-registration.interface'; import { IALInviteProfile } from './interfaces/al-invite-profile.interface'; +import { RoleEnum } from 'src/roles/roles.enum'; @ApiTags('Auth') @Controller({ @@ -34,7 +35,7 @@ export class AuthLicenseeController { @Body() loginDto: AuthLicenseeLoginDto, ): Promise { - return this.authLicenseeService.validateLogin(loginDto, false); + return this.authLicenseeService.validateLogin(loginDto, RoleEnum.user); } @Post('invite/:hash') diff --git a/src/auth-licensee/auth-licensee.service.ts b/src/auth-licensee/auth-licensee.service.ts index 0d428df9..6532efde 100644 --- a/src/auth-licensee/auth-licensee.service.ts +++ b/src/auth-licensee/auth-licensee.service.ts @@ -4,14 +4,15 @@ import * as bcrypt from 'bcryptjs'; import { AuthProvidersEnum } from 'src/auth/auth-providers.enum'; import { InviteStatusEnum } from 'src/mail-history-statuses/mail-history-status.enum'; import { MailHistoryService } from 'src/mail-history/mail-history.service'; -import { MailService } from 'src/mail/mail.service'; import { RoleEnum } from 'src/roles/roles.enum'; import { Status } from 'src/statuses/entities/status.entity'; import { StatusEnum } from 'src/statuses/statuses.enum'; +import { User } from 'src/users/entities/user.entity'; import { UsersService } from 'src/users/users.service'; -import { HttpErrorMessages } from 'src/utils/enums/http-error-messages.enum'; +import { HttpStatusMessage } from 'src/utils/enums/http-error-message.enum'; +import { CommonHttpException } from 'src/utils/http-exception/common-http-exception'; import { LoginResponseType } from 'src/utils/types/auth/login-response.type'; -import { BaseValidator } from 'src/utils/validators/base-validator'; +import { NullableType } from '../utils/types/nullable.type'; import { AuthLicenseeLoginDto } from './dto/auth-licensee-login.dto'; import { AuthRegisterLicenseeDto } from './dto/auth-register-licensee.dto'; import { IALConcludeRegistration } from './interfaces/al-conclude-registration.interface'; @@ -27,35 +28,18 @@ export class AuthLicenseeService { private jwtService: JwtService, private usersService: UsersService, private mailHistoryService: MailHistoryService, - private baseValidator: BaseValidator, - private mailService: MailService, ) {} async validateLogin( loginDto: AuthLicenseeLoginDto, - onlyAdmin: boolean, + role: RoleEnum, ): Promise { - const user = await this.usersService.findOne({ + const user = await this.usersService.getOne({ permitCode: loginDto.permitCode, }); - if ( - !user || - (user?.role && - !(onlyAdmin ? [RoleEnum.admin] : [RoleEnum.user]).includes( - user.role.id, - )) - ) { - throw new HttpException( - { - error: HttpErrorMessages.UNAUTHORIZED, - details: { - email: 'notFound', - }, - }, - HttpStatus.UNAUTHORIZED, - ); - } + await this.validateDuplicatedUser(user); + this.validateRole(user, role); if ( user?.status?.id === undefined || @@ -63,7 +47,7 @@ export class AuthLicenseeService { ) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { status: 'notActive', }, @@ -75,7 +59,7 @@ export class AuthLicenseeService { if (user.provider !== AuthProvidersEnum.email) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { email: `needLoginViaProvider:${user.provider}`, }, @@ -90,13 +74,9 @@ export class AuthLicenseeService { ); if (!isValidPassword) { - throw new HttpException( - { - error: HttpErrorMessages.UNAUTHORIZED, - details: { - password: 'incorrectPassword', - }, - }, + throw CommonHttpException.simpleDetail( + 'password', + 'incorrectPassword', HttpStatus.UNAUTHORIZED, ); } @@ -109,13 +89,62 @@ export class AuthLicenseeService { return { token, user }; } + validateRole(user: User, role: RoleEnum) { + if (!user?.role || user.role.id !== role) { + throw new HttpException( + { + error: HttpStatusMessage.UNAUTHORIZED, + details: { + user: { + error: 'invalidRole', + role: user?.role?.id, + expectedRole: role, + }, + }, + }, + HttpStatus.UNAUTHORIZED, + ); + } + } + + async validateDuplicatedUser(user: NullableType) { + if (!user) { + return; + } + const duplicatedMail = user.email + ? await this.usersService.findMany({ email: user.email }) + : []; + const duplicatedPermitCode = user.permitCode + ? await this.usersService.findMany({ permitCode: user.permitCode }) + : []; + if (duplicatedMail.length > 1 || duplicatedPermitCode.length > 1) { + throw new HttpException( + { + error: HttpStatusMessage.UNAUTHORIZED, + details: { + ...(duplicatedMail.length > 1 + ? { email: 'duplicated', emailValue: duplicatedMail[0]?.email } + : {}), + ...(duplicatedPermitCode.length > 1 + ? { + permitCode: 'duplicated', + permitCodeValue: duplicatedPermitCode[0]?.permitCode, + } + : {}), + }, + }, + HttpStatus.UNAUTHORIZED, + ); + } + } + async getInviteProfile(hash: string): Promise { const invite = await this.mailHistoryService.getOne({ hash }); if (invite.inviteStatus.id !== InviteStatusEnum.sent) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { invite: { inviteStatus: `Invite is not 'sent' yet`, @@ -136,7 +165,7 @@ export class AuthLicenseeService { ) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { user: { ...(user.id !== invite.user.id && { @@ -171,7 +200,7 @@ export class AuthLicenseeService { if (!invite) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { invite: { hash: 'inviteHashNotFound', @@ -185,7 +214,7 @@ export class AuthLicenseeService { if (invite.inviteStatus.id !== InviteStatusEnum.sent) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { invite: { inviteStatus: `inviteAlreadyUsed'`, @@ -205,7 +234,7 @@ export class AuthLicenseeService { ) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { user: { ...(user.id !== invite.user.id && { diff --git a/src/auth-licensee/dto/auth-licensee-login.dto.ts b/src/auth-licensee/dto/auth-licensee-login.dto.ts index 6a0d5fd0..91959a4d 100644 --- a/src/auth-licensee/dto/auth-licensee-login.dto.ts +++ b/src/auth-licensee/dto/auth-licensee-login.dto.ts @@ -2,7 +2,7 @@ import { HttpStatus } from '@nestjs/common'; import { ApiProperty } from '@nestjs/swagger'; import { IsNotEmpty, Validate } from 'class-validator'; import { customValidationOptions } from 'src/utils/all-exteptions-filter/custom-validation-options'; -import { HttpErrorMessages } from 'src/utils/enums/http-error-messages.enum'; +import { HttpStatusMessage } from 'src/utils/enums/http-error-message.enum'; import { IsExist } from 'src/utils/validators/is-exists.validator'; export class AuthLicenseeLoginDto { @@ -13,7 +13,7 @@ export class AuthLicenseeLoginDto { ['User'], customValidationOptions({ statusCode: HttpStatus.UNAUTHORIZED, - message: HttpErrorMessages.UNAUTHORIZED, + message: HttpStatusMessage.UNAUTHORIZED, details: 'permitCodeNotExists', }), ) diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index f28370a5..cce86d90 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -16,7 +16,7 @@ import { SocialInterface } from 'src/social/interfaces/social.interface'; import { Status } from 'src/statuses/entities/status.entity'; import { StatusEnum } from 'src/statuses/statuses.enum'; import { UsersService } from 'src/users/users.service'; -import { HttpErrorMessages } from 'src/utils/enums/http-error-messages.enum'; +import { HttpStatusMessage } from 'src/utils/enums/http-error-message.enum'; import { formatLog } from 'src/utils/logging'; import { User } from '../users/entities/user.entity'; import { LoginResponseType } from '../utils/types/auth/login-response.type'; @@ -56,7 +56,7 @@ export class AuthService { ) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { email: 'notFound', }, @@ -68,7 +68,7 @@ export class AuthService { if (user.provider !== AuthProvidersEnum.email) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { email: `needLoginViaProvider:${user.provider}`, }, @@ -85,7 +85,7 @@ export class AuthService { if (!isValidPassword) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { password: 'incorrectPassword', }, @@ -155,7 +155,7 @@ export class AuthService { if (!user) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { user: 'userNotFound', }, @@ -408,7 +408,7 @@ export class AuthService { else { throw new HttpException( { - error: HttpErrorMessages.INTERNAL_SERVER_ERROR, + error: HttpStatusMessage.INTERNAL_SERVER_ERROR, details: { mailSentInfo: mailSentInfo, }, @@ -432,7 +432,7 @@ export class AuthService { if (!forgot) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { error: 'hash not found', hash, diff --git a/src/bank-statements/bank-statements.service.spec.ts b/src/bank-statements/bank-statements.service.spec.ts index d02ee5ce..8e6164e8 100644 --- a/src/bank-statements/bank-statements.service.spec.ts +++ b/src/bank-statements/bank-statements.service.spec.ts @@ -11,6 +11,7 @@ import { TimeIntervalEnum } from 'src/utils/enums/time-interval.enum'; import { BankStatementsRepositoryService } from './bank-statements-repository.service'; import { BankStatementsService } from './bank-statements.service'; import { IBankStatement } from './interfaces/bank-statement.interface'; +import { SettingsService } from 'src/settings/settings.service'; const allBankStatements = [ { id: 1, date: '2023-01-27', amount: 1 }, @@ -58,6 +59,13 @@ describe('BankStatementsService', () => { getMe: jest.fn(), }, } as Provider; + const settingsServiceMock = { + provide: SettingsService, + useValue: { + getOneBySettingData: jest.fn(), + findOneBySettingData: jest.fn(), + }, + } as Provider; const module: TestingModule = await Test.createTestingModule({ providers: [ @@ -67,6 +75,7 @@ describe('BankStatementsService', () => { bigqueryServiceMock, usersServiceMock, ticketRevenuesServiceMock, + settingsServiceMock, ], }).compile(); diff --git a/src/config/app.config.ts b/src/config/app.config.ts index 472d3ec1..9523af4c 100644 --- a/src/config/app.config.ts +++ b/src/config/app.config.ts @@ -12,8 +12,9 @@ import { } from 'class-validator'; export enum Environment { - Development = 'development', Production = 'production', + Homologation = 'homologation', + Development = 'development', Local = 'local', Test = 'test', } diff --git a/src/database/seeds/setting/setting-seed.service.ts b/src/database/seeds/setting/setting-seed.service.ts index 236629bd..2ff98ddf 100644 --- a/src/database/seeds/setting/setting-seed.service.ts +++ b/src/database/seeds/setting/setting-seed.service.ts @@ -6,6 +6,8 @@ import { ISettingData } from 'src/settings/interfaces/setting-data.interface'; import { Enum } from 'src/utils/enum'; import { IsNull, Repository } from 'typeorm'; import { settingSeedData } from './setting-seed-data'; +import { Environment } from 'src/config/app.config'; +import { BigqueryEnvironment } from 'src/settings/enums/bigquery-env.enum'; @Injectable() export class SettingSeedService { @@ -20,6 +22,14 @@ export class SettingSeedService { async run() { let id = 1; + console.log('SEED', process.env.NODE_ENV); + console.log( + 'VALUE', + process.env.NODE_ENV === Environment.Local || + process.env.NODE_ENV === Environment.Test + ? BigqueryEnvironment.Development + : BigqueryEnvironment.Production, + ); for (const item of settingSeedData) { const settings: ISettingData[] = (item as any)?.data || [item]; for (const setting of settings) { diff --git a/src/mail-history/mail-history.service.ts b/src/mail-history/mail-history.service.ts index 85734254..950068db 100644 --- a/src/mail-history/mail-history.service.ts +++ b/src/mail-history/mail-history.service.ts @@ -8,7 +8,7 @@ import { IMailHistoryStatusCount } from 'src/mail-history-statuses/interfaces/ma import { InviteStatusEnum } from 'src/mail-history-statuses/mail-history-status.enum'; import { RoleEnum } from 'src/roles/roles.enum'; import { User } from 'src/users/entities/user.entity'; -import { HttpErrorMessages } from 'src/utils/enums/http-error-messages.enum'; +import { HttpStatusMessage } from 'src/utils/enums/http-error-message.enum'; import { formatLog } from 'src/utils/logging'; import { EntityCondition } from 'src/utils/types/entity-condition.type'; import { NullableType } from 'src/utils/types/nullable.type'; @@ -175,7 +175,7 @@ export class MailHistoryService { if (!invite) { throw new HttpException( { - error: HttpErrorMessages.NOT_FOUND, + error: HttpStatusMessage.NOT_FOUND, }, HttpStatus.NOT_FOUND, ); diff --git a/src/mail-history/pipes/mail-history-validation.pipe.ts b/src/mail-history/pipes/mail-history-validation.pipe.ts index bd4f28c0..f839c727 100644 --- a/src/mail-history/pipes/mail-history-validation.pipe.ts +++ b/src/mail-history/pipes/mail-history-validation.pipe.ts @@ -7,7 +7,7 @@ import { ValidationPipeOptions, } from '@nestjs/common'; import { InviteStatusEnum } from 'src/mail-history-statuses/mail-history-status.enum'; -import { HttpErrorMessages } from 'src/utils/enums/http-error-messages.enum'; +import { HttpStatusMessage } from 'src/utils/enums/http-error-message.enum'; import { MailHistoryService } from '../mail-history.service'; @Injectable() @@ -31,7 +31,7 @@ export class MailHistoryValidationPipe extends ValidationPipe { if (!inviteFound) { throw new HttpException( { - message: HttpErrorMessages.UNAUTHORIZED, + message: HttpStatusMessage.UNAUTHORIZED, details: { [fieldName]: 'invalid invite hash', }, @@ -41,7 +41,7 @@ export class MailHistoryValidationPipe extends ValidationPipe { } else if (inviteFound.getMailStatus() === InviteStatusEnum.used) { throw new HttpException( { - message: HttpErrorMessages.UNAUTHORIZED, + message: HttpStatusMessage.UNAUTHORIZED, details: { inviteStatus: "is already 'sent'. Cant be reused.", }, diff --git a/src/settings/app.settings.ts b/src/settings/app.settings.ts index 1a834662..4727884b 100644 --- a/src/settings/app.settings.ts +++ b/src/settings/app.settings.ts @@ -1,5 +1,6 @@ import { CronExpression } from '@nestjs/schedule'; import { SettingTypeEnum } from 'src/setting-types/setting-type.enum'; +import { BigqueryEnvironment } from './enums/bigquery-env.enum'; import { ISettingDataGroup } from './interfaces/setting-data-group.interface'; import { ISettingData } from './interfaces/setting-data.interface'; @@ -88,6 +89,14 @@ export const appSettings = { ], } as ISettingDataGroup, + any__bigquery_env: { + name: 'bigquery_env', + value: BigqueryEnvironment.Development, + version: null, + editable: false, + settingType: SettingTypeEnum.string, + } as ISettingData, + // v1 v1__ab_test_enabled: { diff --git a/src/settings/entities/setting.entity.ts b/src/settings/entities/setting.entity.ts index 41d9682a..d7824532 100644 --- a/src/settings/entities/setting.entity.ts +++ b/src/settings/entities/setting.entity.ts @@ -2,7 +2,7 @@ import { HttpException, HttpStatus } from '@nestjs/common'; import { ApiProperty } from '@nestjs/swagger'; import { Exclude } from 'class-transformer'; import { SettingType } from 'src/setting-types/entities/setting-type.entity'; -import { HttpErrorMessages } from 'src/utils/enums/http-error-messages.enum'; +import { HttpStatusMessage } from 'src/utils/enums/http-error-message.enum'; import { BaseEntity, Column, @@ -62,7 +62,7 @@ export class SettingEntity extends BaseEntity { } catch (error) { throw new HttpException( { - error: HttpErrorMessages.INTERNAL_SERVER_ERROR, + error: HttpStatusMessage.INTERNAL_SERVER_ERROR, details: { value: `should be valid JSON, received '${this.value}' instead`, }, @@ -79,7 +79,7 @@ export class SettingEntity extends BaseEntity { } else { throw new HttpException( { - error: HttpErrorMessages.INTERNAL_SERVER_ERROR, + error: HttpStatusMessage.INTERNAL_SERVER_ERROR, details: { value: 'should not be null', }, @@ -108,7 +108,7 @@ export class SettingEntity extends BaseEntity { } else { throw new HttpException( { - error: HttpErrorMessages.INTERNAL_SERVER_ERROR, + error: HttpStatusMessage.INTERNAL_SERVER_ERROR, details: { value: 'should not be null', }, @@ -122,7 +122,7 @@ export class SettingEntity extends BaseEntity { if (!this?.value) { throw new HttpException( { - error: HttpErrorMessages.INTERNAL_SERVER_ERROR, + error: HttpStatusMessage.INTERNAL_SERVER_ERROR, details: { value: 'should not be null', }, diff --git a/src/settings/enums/bigquery-env.enum.ts b/src/settings/enums/bigquery-env.enum.ts new file mode 100644 index 00000000..de361202 --- /dev/null +++ b/src/settings/enums/bigquery-env.enum.ts @@ -0,0 +1,4 @@ +export enum BigqueryEnvironment { + Production = 'production', + Development = 'development', +} diff --git a/src/settings/settings.controller.ts b/src/settings/settings.controller.ts index 65314074..fa4fd1af 100644 --- a/src/settings/settings.controller.ts +++ b/src/settings/settings.controller.ts @@ -6,24 +6,32 @@ import { HttpStatus, Param, Patch, - SerializeOptions, + UseGuards, } from '@nestjs/common'; -import { SettingsService } from './settings.service'; -import { ApiParam, ApiTags } from '@nestjs/swagger'; +import { AuthGuard } from '@nestjs/passport'; +import { ApiBearerAuth, ApiParam, ApiTags } from '@nestjs/swagger'; +import { Roles } from 'src/roles/roles.decorator'; +import { RoleEnum } from 'src/roles/roles.enum'; +import { RolesGuard } from 'src/roles/roles.guard'; import { NullableType } from 'src/utils/types/nullable.type'; -import { SettingEntity } from './entities/setting.entity'; import { UpdateSettingsDto } from './dto/update-settings.dto'; +import { SettingEntity } from './entities/setting.entity'; +import { SettingsService } from './settings.service'; -@ApiTags('Settings') @Controller('settings') +@ApiTags('Settings') export class SettingsController { constructor(private readonly settingsService: SettingsService) {} @Get() + @ApiBearerAuth() + @UseGuards(AuthGuard('jwt')) async getAll(): Promise> { return this.settingsService.find(); } + @ApiBearerAuth() + @UseGuards(AuthGuard('jwt')) @Get('v:version') @ApiParam({ name: 'version', example: '1' }) getByVersion( @@ -32,11 +40,11 @@ export class SettingsController { return this.settingsService.findByVersion(version); } - @SerializeOptions({ - groups: ['admin'], - }) - @Patch() + @ApiBearerAuth() + @Roles(RoleEnum.admin) + @UseGuards(AuthGuard('jwt'), RolesGuard) @HttpCode(HttpStatus.OK) + @Patch() update(@Body() updateSettingDto: UpdateSettingsDto): Promise { return this.settingsService.update(updateSettingDto); } diff --git a/src/settings/settings.service.ts b/src/settings/settings.service.ts index 1ded9a92..2f7557ed 100644 --- a/src/settings/settings.service.ts +++ b/src/settings/settings.service.ts @@ -67,7 +67,7 @@ export class SettingsService { if (defaultValueIfNotFound && !dbSetting) { this.logger.warn( formatLog( - `Configuração 'setting.${setting.name}' não encontrada. Usando valor padrão.`, + `Configuração 'setting.${setting.name}' não encontrada. Usando valor padrão: '${setting.value}'.`, `${this.getOneBySettingData.name}()`, logContext, ), diff --git a/src/ticket-revenues/ticket-revenues-repository.service.ts b/src/ticket-revenues/ticket-revenues-repository.service.ts index b249c096..59ce552c 100644 --- a/src/ticket-revenues/ticket-revenues-repository.service.ts +++ b/src/ticket-revenues/ticket-revenues-repository.service.ts @@ -17,6 +17,9 @@ import { TRPaymentTypeMap, TRTransactionTypeMap, } from './maps/ticket-revenues.map'; +import { SettingsService } from 'src/settings/settings.service'; +import { appSettings } from 'src/settings/app.settings'; +import { BigqueryEnvironment } from 'src/settings/enums/bigquery-env.enum'; @Injectable() export class TicketRevenuesRepositoryService { @@ -24,7 +27,10 @@ export class TicketRevenuesRepositoryService { timestamp: true, }); - constructor(private readonly bigqueryService: BigqueryService) {} + constructor( + private readonly bigqueryService: BigqueryService, + private readonly settingsService: SettingsService, + ) {} /** * TODO: use it only for repository services @@ -58,7 +64,7 @@ export class TicketRevenuesRepositoryService { async fetchTicketRevenues( args?: IFetchTicketRevenues, ): Promise<{ data: ITicketRevenue[]; countAll: number }> { - const qArgs = this.getQueryArgs(args); + const qArgs = await this.getQueryArgs(args); const query = ` SELECT @@ -119,7 +125,7 @@ export class TicketRevenuesRepositoryService { }; } - private getQueryArgs(args?: IFetchTicketRevenues): { + private async getQueryArgs(args?: IFetchTicketRevenues): Promise<{ qWhere: string; bucket: string; transacao: string; @@ -130,17 +136,23 @@ export class TicketRevenuesRepositoryService { countQuery: string; offset?: number; limit?: number; - } { - const IS_PROD = process.env.NODE_ENV === 'production'; + }> { + const IS_BQ_PROD = + ( + await this.settingsService.getOneBySettingData( + appSettings.any__bigquery_env, + true, + ) + ).getValueAsString() === BigqueryEnvironment.Production; const Q_CONSTS = { - bucket: IS_PROD ? 'rj-smtr' : 'rj-smtr-dev', - transacao: IS_PROD + bucket: IS_BQ_PROD ? 'rj-smtr' : 'rj-smtr-dev', + transacao: IS_BQ_PROD ? 'rj-smtr.br_rj_riodejaneiro_bilhetagem.transacao' : 'rj-smtr-dev.br_rj_riodejaneiro_bilhetagem_cct.transacao', - integracao: IS_PROD + integracao: IS_BQ_PROD ? 'rj-smtr.br_rj_riodejaneiro_bilhetagem.integracao' : 'rj-smtr-dev.br_rj_riodejaneiro_bilhetagem_cct.integracao', - tTipoPgto: IS_PROD ? 'tipo_pagamento' : 'id_tipo_pagamento', + tTipoPgto: IS_BQ_PROD ? 'tipo_pagamento' : 'id_tipo_pagamento', }; // Args let offset = args?.offset; diff --git a/src/ticket-revenues/ticket-revenues.module.ts b/src/ticket-revenues/ticket-revenues.module.ts index d25da5ca..707e8695 100644 --- a/src/ticket-revenues/ticket-revenues.module.ts +++ b/src/ticket-revenues/ticket-revenues.module.ts @@ -4,9 +4,10 @@ import { UsersModule } from 'src/users/users.module'; import { TicketRevenuesRepositoryService } from './ticket-revenues-repository.service'; import { TicketRevenuesController } from './ticket-revenues.controller'; import { TicketRevenuesService } from './ticket-revenues.service'; +import { SettingsModule } from 'src/settings/settings.module'; @Module({ - imports: [UsersModule, BigqueryModule, UsersModule], + imports: [UsersModule, BigqueryModule, UsersModule, SettingsModule], providers: [TicketRevenuesService, TicketRevenuesRepositoryService], controllers: [TicketRevenuesController], exports: [TicketRevenuesService, TicketRevenuesRepositoryService], diff --git a/src/ticket-revenues/ticket-revenues.service.spec.ts b/src/ticket-revenues/ticket-revenues.service.spec.ts index b5a00144..b50bca3d 100644 --- a/src/ticket-revenues/ticket-revenues.service.spec.ts +++ b/src/ticket-revenues/ticket-revenues.service.spec.ts @@ -6,6 +6,7 @@ import { UsersService } from 'src/users/users.service'; import { ITicketRevenue } from './interfaces/ticket-revenue.interface'; import { TicketRevenuesRepositoryService } from './ticket-revenues-repository.service'; import { TicketRevenuesService } from './ticket-revenues.service'; +import { SettingsService } from 'src/settings/settings.service'; describe('TicketRevenuesService', () => { let ticketRevenuesService: TicketRevenuesService; @@ -25,12 +26,20 @@ describe('TicketRevenuesService', () => { runQuery: jest.fn(), }, } as Provider; + const settingsServiceMock = { + provide: SettingsService, + useValue: { + getOneBySettingData: jest.fn(), + findOneBySettingData: jest.fn(), + }, + } as Provider; const module: TestingModule = await Test.createTestingModule({ providers: [ TicketRevenuesService, TicketRevenuesRepositoryService, usersServiceMock, bigqueryServiceMock, + settingsServiceMock, ], }).compile(); jest diff --git a/src/users/users.service.ts b/src/users/users.service.ts index 1e237fb3..a92dffb7 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -15,7 +15,7 @@ import { Status } from 'src/statuses/entities/status.entity'; import { StatusEnum } from 'src/statuses/statuses.enum'; import { isArrayContainEqual } from 'src/utils/array-utils'; import { Enum } from 'src/utils/enum'; -import { HttpErrorMessages } from 'src/utils/enums/http-error-messages.enum'; +import { HttpStatusMessage } from 'src/utils/enums/http-error-message.enum'; import { formatLog } from 'src/utils/logging'; import { stringUppercaseUnaccent } from 'src/utils/string-utils'; import { EntityCondition } from 'src/utils/types/entity-condition.type'; @@ -310,7 +310,7 @@ export class UsersService { if (!user) { throw new HttpException( { - error: HttpErrorMessages.NOT_FOUND, + error: HttpStatusMessage.NOT_FOUND, details: { ...(!user && { user: 'userNotFound' }), }, @@ -327,7 +327,7 @@ export class UsersService { if (!userId) { throw new HttpException( { - error: HttpErrorMessages.UNAUTHORIZED, + error: HttpStatusMessage.UNAUTHORIZED, details: { ...(!request.user && { loggedUser: 'loggedUserNotExists' }), ...(!userId && { loggedUser: 'loggedUserIdNotExists' }), diff --git a/src/utils/enums/http-error-messages.enum.ts b/src/utils/enums/http-error-message.enum.ts similarity index 91% rename from src/utils/enums/http-error-messages.enum.ts rename to src/utils/enums/http-error-message.enum.ts index 4c6fd2fe..323ee2ae 100644 --- a/src/utils/enums/http-error-messages.enum.ts +++ b/src/utils/enums/http-error-message.enum.ts @@ -1,6 +1,6 @@ import { HttpStatus } from '@nestjs/common'; -export enum HttpErrorMessages { +export enum HttpStatusMessage { INTERNAL_SERVER_ERROR = 'InternalServerError', AUTHENTICATION_FAILED = 'AuthenticationFailed', SETTING_NOT_FOUND = 'SettingNotFound', diff --git a/src/utils/http-exception/common-http-exception.ts b/src/utils/http-exception/common-http-exception.ts index f1c7573b..2c7e839c 100644 --- a/src/utils/http-exception/common-http-exception.ts +++ b/src/utils/http-exception/common-http-exception.ts @@ -1,4 +1,5 @@ import { HttpException, HttpStatus } from '@nestjs/common'; +import { getHttpStatusMessage } from './http-exception-utils'; export const CommonHttpException = { simpleDetail: ( @@ -8,12 +9,46 @@ export const CommonHttpException = { ) => new HttpException( { + error: getHttpStatusMessage(httpStatusCode), details: { [field]: message, }, }, httpStatusCode, ), + errDetail: ( + error: string, + detailField: string, + detailMessage: string, + httpStatusCode: HttpStatus = 500, + ) => + new HttpException( + { + error, + details: { + [detailField]: detailMessage, + }, + }, + httpStatusCode, + ), + notFound: ( + notFoundField: string, + httpStatusCode: HttpStatus = HttpStatus.NOT_FOUND, + error?: string, + ) => + new HttpException( + { + error: error || getHttpStatusMessage(httpStatusCode), + ...(notFoundField + ? { + details: { + [notFoundField]: 'not found', + }, + } + : {}), + }, + httpStatusCode, + ), argNotType: ( field: string, expectedType: string, diff --git a/src/utils/http-exception/http-exception-utils.ts b/src/utils/http-exception/http-exception-utils.ts new file mode 100644 index 00000000..f5a3b791 --- /dev/null +++ b/src/utils/http-exception/http-exception-utils.ts @@ -0,0 +1,10 @@ +import { HttpStatus } from '@nestjs/common'; +import { Enum } from '../enum'; +import { HttpStatusMessage } from '../enums/http-error-message.enum'; + +export function getHttpStatusMessage( + httpStatusCode: HttpStatus, +): HttpStatusMessage { + const statusKey = Enum.getKey(HttpStatus, httpStatusCode); + return HttpStatusMessage[statusKey]; +} diff --git a/src/utils/validators/base-validator.ts b/src/utils/validators/base-validator.ts index 66386afb..2d6adafc 100644 --- a/src/utils/validators/base-validator.ts +++ b/src/utils/validators/base-validator.ts @@ -1,7 +1,7 @@ import { validate } from 'class-validator'; import { plainToClass } from 'class-transformer'; import { HttpException, HttpStatus, Injectable, Type } from '@nestjs/common'; -import { HttpErrorMessages } from '../enums/http-error-messages.enum'; +import { HttpStatusMessage } from '../enums/http-error-message.enum'; @Injectable() export class BaseValidator { @@ -10,8 +10,8 @@ export class BaseValidator { schemaMeta: Type, httpStatus: HttpStatus = HttpStatus.UNPROCESSABLE_ENTITY, httpErrorMessage: - | HttpErrorMessages - | undefined = HttpErrorMessages.UNPROCESSABLE_ENTITY, + | HttpStatusMessage + | undefined = HttpStatusMessage.UNPROCESSABLE_ENTITY, ): Promise { const schema: T = plainToClass(schemaMeta, inputs); const errors = await validate(schema as Record, { diff --git a/test/ticket-revenues/ticket-revenues.e2e-spec.ts b/test/ticket-revenues/ticket-revenues.e2e-spec.ts index f399dce2..bcc7a88b 100644 --- a/test/ticket-revenues/ticket-revenues.e2e-spec.ts +++ b/test/ticket-revenues/ticket-revenues.e2e-spec.ts @@ -52,7 +52,7 @@ describe('Ticket revenues (e2e)', () => { SELECT CAST(t.data AS STRING) AS partitionDate, FROM \`rj-smtr-dev.br_rj_riodejaneiro_bilhetagem_cct.transacao\` t - LEFT JOIN \`rj-smtr.cadastro.consorcios\` c ON c.id_consorcio = t.id_consorcio + LEFT JOIN \`rj-smtr-dev.cadastro.consorcios\` c ON c.id_consorcio = t.id_consorcio WHERE c.cnpj = '${licenseeCnpj}' ORDER BY data DESC, hora DESC LIMIT 1 `, )