diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..25bf17f --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +18 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 65c90cb..71467ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,8 +19,9 @@ "@nestjs/platform-express": "^8.4.3", "@nestjs/schedule": "^1.1.0", "@nestjs/swagger": "^5.2.1", - "@victorradael/protospack": "2.4.1-1", + "@victorradael/protospack": "2.4.2-1", "axios": "^0.25.0", + "cron-parser": "^4.4.0", "dotenv": "^14.2.0", "helmet": "^5.0.2", "jsonwebtoken": "^8.5.1", @@ -2360,9 +2361,9 @@ } }, "node_modules/@victorradael/protospack": { - "version": "2.4.1-1", - "resolved": "https://registry.npmjs.org/@victorradael/protospack/-/protospack-2.4.1-1.tgz", - "integrity": "sha512-QpdnjOiSil1sPvOVuSC1mu5Z76ZDF1+QbDDe/RI3WVWo39dxARBxOxp7/biRY6KLxTPvSUOQbrBAg7Bfx0ul+A==", + "version": "2.4.2-1", + "resolved": "https://registry.npmjs.org/@victorradael/protospack/-/protospack-2.4.2-1.tgz", + "integrity": "sha512-wdcGaK0DIEJeOHga1br11kq264JNdhdB1G2toy/u6TvAk90wwBKHNs/cZko0p9WFVuqHQOVehoHj7WJbJ3K25Q==", "dependencies": { "rxjs": "^7.5.5" } @@ -3541,6 +3542,17 @@ "moment-timezone": "^0.5.x" } }, + "node_modules/cron-parser": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.4.0.tgz", + "integrity": "sha512-TrE5Un4rtJaKgmzPewh67yrER5uKM0qI9hGLDBfWb8GGRe9pn/SDkhVrdHa4z7h0SeyeNxnQnogws/H+AQANQA==", + "dependencies": { + "luxon": "^1.28.0" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -6641,6 +6653,14 @@ "node": ">=10" } }, + "node_modules/luxon": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", + "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==", + "engines": { + "node": "*" + } + }, "node_modules/macos-release": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.0.tgz", @@ -10978,9 +10998,9 @@ } }, "@victorradael/protospack": { - "version": "2.4.1-1", - "resolved": "https://registry.npmjs.org/@victorradael/protospack/-/protospack-2.4.1-1.tgz", - "integrity": "sha512-QpdnjOiSil1sPvOVuSC1mu5Z76ZDF1+QbDDe/RI3WVWo39dxARBxOxp7/biRY6KLxTPvSUOQbrBAg7Bfx0ul+A==", + "version": "2.4.2-1", + "resolved": "https://registry.npmjs.org/@victorradael/protospack/-/protospack-2.4.2-1.tgz", + "integrity": "sha512-wdcGaK0DIEJeOHga1br11kq264JNdhdB1G2toy/u6TvAk90wwBKHNs/cZko0p9WFVuqHQOVehoHj7WJbJ3K25Q==", "requires": { "rxjs": "^7.5.5" } @@ -11927,6 +11947,14 @@ "moment-timezone": "^0.5.x" } }, + "cron-parser": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.4.0.tgz", + "integrity": "sha512-TrE5Un4rtJaKgmzPewh67yrER5uKM0qI9hGLDBfWb8GGRe9pn/SDkhVrdHa4z7h0SeyeNxnQnogws/H+AQANQA==", + "requires": { + "luxon": "^1.28.0" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -14314,6 +14342,11 @@ "yallist": "^4.0.0" } }, + "luxon": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", + "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==" + }, "macos-release": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.0.tgz", diff --git a/package.json b/package.json index 6575622..1d35ac3 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@nestjs/swagger": "^5.2.1", "@victorradael/protospack": "2.4.2-1", "axios": "^0.25.0", + "cron-parser": "^4.4.0", "dotenv": "^14.2.0", "helmet": "^5.0.2", "jsonwebtoken": "^8.5.1", @@ -42,8 +43,8 @@ "rxjs": "^7.5.5", "swagger-ui-express": "^4.3.0" }, - "overrides":{ - "busboy@<1.6.0":"1.6.0" + "overrides": { + "busboy@<1.6.0": "1.6.0" }, "devDependencies": { "@nestjs/cli": "^8.2.4", diff --git a/src/middlewares/authentication.ts b/src/middlewares/authentication.ts index 6ff77b1..8cab798 100644 --- a/src/middlewares/authentication.ts +++ b/src/middlewares/authentication.ts @@ -32,9 +32,10 @@ export class LoggerMiddleware implements NestMiddleware { const permissions = jwtDecoded.user.permissions; - const clienId = jwtDecoded.user.customerId; + const clientId = jwtDecoded.user.customerId; const customer = jwtDecoded.user.customer; const userId = jwtDecoded.user.id; + const customer_tier = jwtDecoded.user.customer_tier; await verifyToken(accessToken); @@ -55,11 +56,11 @@ export class LoggerMiddleware implements NestMiddleware { if (havePermission) { request.body.info = { - customer_id: clienId, + customer_id: clientId, user_id: userId, customer, + customer_tier, }; - next(); } else { throw new ForbiddenException(); diff --git a/src/modules/inputs/inputs.controller.ts b/src/modules/inputs/inputs.controller.ts index 918aa1a..08f1817 100644 --- a/src/modules/inputs/inputs.controller.ts +++ b/src/modules/inputs/inputs.controller.ts @@ -3,6 +3,8 @@ import { Controller, Delete, Get, + Header, + Headers, Param, Patch, Post, diff --git a/src/modules/inputs/inputs.service.ts b/src/modules/inputs/inputs.service.ts index f9caada..bf864f7 100644 --- a/src/modules/inputs/inputs.service.ts +++ b/src/modules/inputs/inputs.service.ts @@ -1,16 +1,43 @@ import { Body, HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { Timeout } from '@nestjs/schedule'; +import CronParser from 'cron-parser'; import { InputsClientService } from 'src/clients/inputs/client.service'; import { IIdRequest, Info } from 'src/clients/inputs/interfaces'; @Injectable() export class InputsService { constructor(private inputClient: InputsClientService) {} + secondsInADay = 60 * 60 * 24; + secondsInAnHour = 60 * 60; adjustInputPayload(payload) { return payload?.input_s3 || payload?.input_jdbc; } + getDifferenceInSeconds(date1, date2) { + const diffInMs = Math.abs(date2 - date1); + return diffInMs / 1000; + } + validateCron(data) { + const { info, cron } = data; + const { customer_tier } = info; + const interval = CronParser.parseExpression(cron); + const nextDate = interval.next().toDate(); + const afterNextDate = interval.next().toDate(); + const secondsApart = this.getDifferenceInSeconds(nextDate, afterNextDate); + if (customer_tier === 'BASIC' && secondsApart < this.secondsInADay) { + throw new HttpException( + 'Não é possível criar um input com intervalo de tempo menor do que um dia.', + HttpStatus.FORBIDDEN, + ); + } else if (secondsApart < this.secondsInAnHour) { + throw new HttpException( + 'Não é possível criar um input com intervalo de tempo menor do que uma hora.', + HttpStatus.FORBIDDEN, + ); + } + } async create(@Body() data) { + this.validateCron(data); try { if ( data.plugin == 'csv' || @@ -65,6 +92,7 @@ export class InputsService { } async update(id: string, data, info: Info) { + this.validateCron(data); try { const updateInputResponse: any = await this.inputClient.update({ id,