Compare commits

...
23 Commits
Author SHA1 Message Date
Gabriel Amorim ee8c5e7a93 Merge pull request #206 from dadosfera/feat/docs-refactor
Feat: docs refactor
2023-02-17 14:36:19 -03:00
Gabriel Rosa 7ecb50315f Update action 2023-02-17 11:01:29 -03:00
Gabriel Rosa 84b3370826 Update action 2023-02-17 11:01:08 -03:00
Gabriel Rosa aa9e0536a7 FIX: tests 2023-02-17 09:55:10 -03:00
Gabriel Rosa 544d13fac5 FIX: readme improved 2023-02-16 17:01:49 -03:00
Gabriel Rosa a4ff07a285 FIX: removed connection test from external docs 2023-02-16 12:07:47 -03:00
Gabriel Rosa 28578d3aa8 FIX: better query params on catalog get all 2023-02-15 16:46:32 -03:00
Gabriel Rosa b8ea729a33 FIX: add external docs to docsfera 2023-02-15 14:16:28 -03:00
Gabriel Rosa b383070b68 Internal docs 2023-02-15 14:07:26 -03:00
Gabriel Rosa 87882b5afc FIX: add multiple servers 2023-02-15 13:14:53 -03:00
Gabriel Rosa 6a14c2b459 FIX: hide internal endpoints 2023-02-15 13:13:43 -03:00
Gabriel Rosa f0bfb6ba8e FIX: new semantic release 2023-02-14 16:57:45 -03:00
Gabriel Rosa 99288fa805 FIX: new sematic release version 2023-02-14 16:55:39 -03:00
Gabriel Rosa 35cc0094b3 FIX: new sematic release 2023-02-14 16:51:53 -03:00
Gabriel Rosa 98262bcba9 FIX: Run semantic release on manual deploy 2023-02-14 16:48:46 -03:00
Gabriel Rosa a2c9a462e4 Run semantic release on manual deploy 2023-02-14 16:46:54 -03:00
Gabriel Rosa c5c089e5d5 Better error handling and documentation on refresh token 2023-02-14 09:25:14 -03:00
Gabriel Rosa de06512249 FIX: changed language strategy to use new custom decorator 2023-02-14 08:56:23 -03:00
Gabriel Rosa 9058b80383 Merge branch 'main' into feat/docs-refactor 2023-02-13 12:16:12 -03:00
Gabriel Rosa be64c582e1 Inject permissions more safe 2023-02-13 12:03:28 -03:00
Gabriel Rosa fbc0d2eede FIX: moved decorators to a separate folder 2023-02-10 14:23:27 -03:00
Gabriel Rosa 9fcbeda470 FIX: deprecating old pipeline routes 2023-02-08 18:07:06 -03:00
Gabriel Rosa 8043635b1c FIX: add authentication to swagger 2023-02-08 15:23:49 -03:00
45 changed files with 6225 additions and 1855 deletions
+20 -4
View File
@@ -43,10 +43,9 @@ jobs:
- if: github.event_name != 'workflow_dispatch'
name: Semantic Release
uses: cycjimmy/semantic-release-action@v2
uses: cycjimmy/semantic-release-action@v3
id: semantic
with:
semantic_version: 16
extra_plugins: |
conventional-changelog-eslint
branches: |
@@ -77,7 +76,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Update Pip
run: |
@@ -147,7 +146,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Extract Docs BlockId and PageId
env:
@@ -188,3 +187,20 @@ jobs:
sed -i -e "s/\${DOCS_PAGE_ID}/$DOCS_PAGE_ID/g" docsfera.json
sed -i -e "s/\${DOCS_BLOCK_ID}/$DOCS_BLOCK_ID/g" docsfera.json
curl -X POST -H 'Content-Type: application/json' -d @docsfera.json $DOCS_URL
- name: Generate External API docs
env:
DOCS_URL: ${{ secrets.DOCS_URL }}
DOCS_API_TOKEN: ${{ secrets.DOCS_API_TOKEN }}
DOCS_PAGE_ID: ${{secrets.EXTERNAL_DOCS_PAGE_ID}}
DOCS_BLOCK_ID: ${{secrets.EXTERNAL_DOCS_BLOCK_ID}}
EVENT: ${{ github.event_name }}
RELEASE_VERSION: ${{ needs.semantic_release.outputs.new_release_version }}
run: |
if [ ${EVENT} != "workflow_dispatch" ]; then
sed -i -E "s/(\"title\": )\"Maestro.+\"/\1\"Maestro - $RELEASE_VERSION\"/g" docsfera.external.json
fi
sed -i -e "s/\${DOCS_API_TOKEN}/$DOCS_API_TOKEN/g" docsfera.external.json
sed -i -e "s/\${DOCS_PAGE_ID}/$DOCS_PAGE_ID/g" docsfera.external.json
sed -i -e "s/\${DOCS_BLOCK_ID}/$DOCS_BLOCK_ID/g" docsfera.external.json
curl -X POST -H 'Content-Type: application/json' -d @docsfera.external.json $DOCS_URL
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
runs-on: self-hosted
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Build
env:
+120 -71
View File
@@ -1,67 +1,98 @@
<p align="center">
<image src="./assets/maestro.svg" style="width:10rem">
</p>
</p>
# Maestro
Maestro is the Dadosfera's gateway, it's responsible for the communication between the frontend application and Dadosfera's microservices.
## 🚀 Starting
These instructions will allow you to get a working copy of the project on your local machine for development and testing purposes.
### 📋 Requirements
- [NodeJS v18.3.0 LTS / NPM v8.11](https://nodejs.org/pt-br/download/) (you can opt to use [NVM](https://github.com/nvm-sh/nvm) to easily manage node versions)
- Request access to AWS Console dev account for **all services** (avoid gradually asking for each needed service. it will slow down your development cycle)
- Create your Access Key on the "Security credentials" menu
- Set the Access Key on your local development machine
- Create your Access Key on the "Security credentials" menu
- Set the Access Key on your local development machine
- Request access to the dev, stg and prd VPNs
### 🔧 Installation<a id="installation"></a>
- Clone the repository
- SSH
```
git clone git@github.com:dadosfera/maestro.git
```
or
- HTTPS
```
git clone https://github.com/dadosfera/maestro.git
```
- Clone the repository
- SSH
```
git clone git@github.com:dadosfera/maestro.git
```
or
- HTTPS
```
git clone https://github.com/dadosfera/maestro.git
```
- Select the correct node version (optional, only if using [NVM](https://github.com/nvm-sh/nvm)):
```sh
nvm use
```
```sh
nvm use
```
- Install the project dependencies:
```sh
npm i
```
```sh
npm i
```
- Setup the following enviroment variables:
```
ENV=
DUC_URL=
INFACTORY_URL=
OTFACTORY_URL=
PIFACTORY_URL=
SM_OAUTH_PATH=
```
```
ENV=
DUC_URL=
INFACTORY_URL=
OTFACTORY_URL=
PIFACTORY_URL=
SM_OAUTH_PATH=
```
- Start the server:
```sh
# dev mode
npm run start:dev
# or in debug mode
npm run start:debug
```
The service should start successfully.
```sh
# dev mode
npm run start:dev
# or in debug mode
npm run start:debug
```
The service should start successfully.
## 📄 Documentation
NestJs makes it easy to document each route using decorators on all requests and responses properties. It automatically generates a swagger for given information and provides a route to access it http://localhost:3333/api.
For more info check the [official documentation](https://docs.nestjs.com/openapi/introduction).
### - Multiple documentations
We are currently generating **2 different** documentations: Internal and External.
All routes that have the decorator `@ApiInternalOnly()` will not be visible on the **External** API swagger.
- When you start the application with `npm run start` it will serve and generate the swagger JSON of the **External** API
- When you start the application with `npm run start:internal` it will serve and generate the swagger JSON of the **Internal** API
- When you run `npm run docs` it will generate the swagger JSON of both **Internal** and **External** API, and save them to `docsfera.json` and `docsfera.external.json` respectively;
It is important to run `npm run docs` before every deploy so we can always have the most updated docs published.
## Authentication decorators
Maestro have utilities to ease the user authentication on every controller and route. The following decorators are available:
### `@Authenticated`
If the user must be authenticated to make request, we can use the `@Authenticated` decorator in the controller or route, as needed.
```ts
@@ -106,6 +137,7 @@ class FooController {
```
### `@RequireAllPermissions`
This decorator requires that **all permissions** listed are granted to the requesting user.
```ts
@@ -125,6 +157,7 @@ class FooController {
```
### `@RequireSomePermission`
In the following case, the user is required to have **at least one** listed permission.
```ts
@@ -144,9 +177,11 @@ class FooController {
```
### `@AuthenticateCondition`
If a more complicated authentication check needs to be done, we can use the `@AuthenticateCondition` decorator to define it. The custom function must return `true` to authenticate the request.
In the following example:
- all routes on the `FooController` controller can only be requested from localhost
- `POST /foo/bar` can only be requested from localhost **and** by users from customer id `111...eef`
@@ -166,7 +201,10 @@ class FooController {
@Post('bar')
// allow requests only from a specific customer
@AuthenticateCondition((request: Request, user: RequestUser) => user.customer_id === '1113e943-2187-4fdd-9c2c-54338fedaeef')
@AuthenticateCondition(
(request: Request, user: RequestUser) =>
user.customer_id === '1113e943-2187-4fdd-9c2c-54338fedaeef',
)
async postBar() {
/* ... */
}
@@ -174,51 +212,55 @@ class FooController {
```
### Note on authentication decorators
- The old authentication method placed the user data in the `request.body.info` field, this imposes certain issues regarding the request body because this data should be from the frontend without any modification by Maestro. Now this usage is ⚠️ **DEPRECATED** ⚠️. We are working to migrate to the `@User` parameter decorator. The old method is working while the migration is in progress.
- Authentication decorators can be used together and all of them **must** pass to the request be authenticated, but in the general case you don't need to (*and wouldn't like to...*) use all of them together, as you can code all of the authentication logic in the `@AuthenticateCondition` decorator.
- Authentication decorators can be used together and all of them **must** pass to the request be authenticated, but in the general case you don't need to (_and wouldn't like to..._) use all of them together, as you can code all of the authentication logic in the `@AuthenticateCondition` decorator.
```ts
import {
RequireAllPermissions,
RequireSomePermission,
AuthenticateCondition,
} from '../../authentication/authentication.decorator';
import { PERMISSIONS } from '../../authentication/permissions.enum';
import { Waa, Baz } from './authenticationFunctions'
```ts
import {
RequireAllPermissions,
RequireSomePermission,
AuthenticateCondition,
} from '../../authentication/authentication.decorator';
import { PERMISSIONS } from '../../authentication/permissions.enum';
import { Waa, Baz } from './authenticationFunctions';
@Controller('foo')
@RequireAllPermissions(Permissions.FOO.USE, Permissions.FOO.REQUEST)
@RequireSomePermission(Permissions.FOO.MANAGE, Permissions.FOO.ADMIN)
@AuthenticateCondition(Waa)
@AuthenticateCondition(Baz)
class FooController {
@Controller('foo')
@RequireAllPermissions(Permissions.FOO.USE, Permissions.FOO.REQUEST)
@RequireSomePermission(Permissions.FOO.MANAGE, Permissions.FOO.ADMIN)
@AuthenticateCondition(Waa)
@AuthenticateCondition(Baz)
class FooController {
/* ... */
@Get('bar')
async getBar() {
/* ... */
@Get('bar')
async getBar() {
/* ... */
}
@Post('bar')
@RequireAllPermissions(Permissions.BAR.MANAGE, Permissions.BAR.USE, Permissions.BAR.REQUEST)
async postBar() {
/* ... */
}
}
```
@Post('bar')
@RequireAllPermissions(
Permissions.BAR.MANAGE,
Permissions.BAR.USE,
Permissions.BAR.REQUEST,
)
async postBar() {
/* ... */
}
}
```
- If `@RequireAllPermissions` and `@RequireSomePermission` are used with **only a single permission**, they present the **exactly same behavior**.
```ts
// same behavior
@RequireAllPermissions(Permissions.BAR.MANAGE)
@RequireSomePermission(Permissions.BAR.MANAGE)
```
```ts
// same behavior
@RequireAllPermissions(Permissions.BAR.MANAGE)
@RequireSomePermission(Permissions.BAR.MANAGE)
```
## `@User` parameter decorator
The requesting user data can be obtained using the @User parameter decorator, like in the following snippet:
```ts
@@ -264,12 +306,15 @@ class UserController {
```
## 📦 Development
### ⌨️ Coding Style
By default, we use [ESLint](https://eslint.org/) + [Prettier](https://prettier.io/) with default settings.
**We recommend using Visual Studio Code and installing the recommended extensions to ease the development process.**
### Commits pattern
Our workflow pipeline follows the conventional commits specs ([cheat sheets](https://cheatography.com/albelop/cheat-sheets/conventional-commits/)) to release versions accordingly.
Format: `<type>[optional scope]: <description>`
@@ -277,25 +322,29 @@ Format: `<type>[optional scope]: <description>`
Example: `FIX: ensure Range headers adhere more closely to RFC 2616`
### Branching naming convention
- **Feature**: Any code changes for a new module or use case should be done on a feature branch. This branch is created based on the `main` branch. When all changes are done, a Pull Request/Merge Request is needed to put all of these changes back to the `main` branch. Examples: `feature/integrate-swagger`, `feature/JIRA-1234`, `feature/JIRA-1234_support-dark-theme`.
**It is recommended to use all lower caps letters and hyphen (-) to separate words unless it is a specific item name or ID. Underscore (_) could be used to separate the ID and description.**
**It is recommended to use all lower caps letters and hyphen (-) to separate words unless it is a specific item name or ID. Underscore (\_) could be used to separate the ID and description.**
- **Bug Fix**: If the code changes made from the feature branch were rejected after a release, sprint or demo, any necessary fixes after that should be done on the bugfix branch. Examples: `bugfix/more-gray-shades`, `bugfix/JIRA-1444_gray-on-blur-fix`.
- **Bug Fix**: If the code changes made from the feature branch were rejected after a release, sprint or demo, any necessary fixes after that should be done on the bugfix branch. Examples: `bugfix/more-gray-shades`, `bugfix/JIRA-1444_gray-on-blur-fix`.
- **Hot Fix**: If there is a need to fix a blocker, do a temporary patch, apply a critical framework or configuration change that should be handled immediately, it should be created as a Hotfix. Examples: `hotfix/disable-endpoint-zero-day-exploit`, `hotfix/increase-scaling-threshold`.
- **Experimental**: A branch for playing around. Any new feature or idea that is not part of a release or a sprint. Example: `experimental/dark-theme-support`.
### Making a Pull Request
1. Commit your changes
2. Open the Pull Request on GitHub
3. Send Pull Request link in Microsfera Google Chat Group for review and possible approval
## 🛠️ Built with
Some technologies used in this project:
- [NestJS](https://docs.nestjs.com) - Framework for building efficient and scalable NodeJS server-side applications
## ⚙️ Back-end Architecture
The architecture can be found at [this link](https://sites.google.com/dadosfera.ai/wikidoproduto/time/back-end).
File diff suppressed because it is too large Load Diff
+2758 -1506
View File
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
declare global {
namespace NodeJS {
interface ProcessEnv {
NODE_ENV: 'test';
ENV: 'local' | 'stg' | 'prd' | 'test';
LOCAL_ENV: 'stg' | 'prd';
DUC_URL: string;
INFACTORY_URL: string;
PIFACTORY_URL: string;
INTERNAL_SWAGGER: 'true' | 'false';
AWS_REGION: string;
}
}
}
export {};
+5 -4
View File
@@ -15,9 +15,10 @@
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "npm run build && node dist/main",
"start:dev": "export INTERNAL_SWAGGER=true && nest start --watch",
"start:debug": "npm run start:dev",
"start:prod": "node dist/main",
"docs": "export KILL_AFTER_START=1 && nest start && export INTERNAL_SWAGGER=true && nest start",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
@@ -95,4 +96,4 @@
"tsconfig-paths": "^3.14.1",
"typescript": "^4.6.3"
}
}
}
+7 -7
View File
@@ -40,24 +40,24 @@ import { MixpanelModule } from './modules/mixpanel/mixpanel.module';
isGlobal: true,
}),
AuthModule,
ConnectionModule,
NetworkConfigModule,
InputsModule,
PipelinesV2Module,
CatalogModule,
ConnectorModule,
PermissionsModule,
TermsOfUseModule,
ConnectionModule,
NetworkConfigModule,
ConnectionTestModule,
PipelinesModule,
PipelinesV2Module,
TransformationsModule,
HealthModule,
CatalogModule,
UsersModule,
RolesModule,
InputsModule,
OauthModule,
CatalogModule,
ProductboardModule,
MixpanelModule,
//Always leave HealthModule last, so it is on the bottom of swagger
HealthModule,
],
})
export class AppModule {}
@@ -1,56 +0,0 @@
import { Request } from 'express';
import { CustomDecorator } from '@nestjs/common';
import { PermissionsObjectPermission } from './permissions.enum';
import { RequestUser } from './user.decorator';
export const AUTH_FUNCTION_KEY = '__AUTH_FUNCTION__';
export type AuthenticationFunction = (req: Request, user: any) => boolean;
// implementation copied from SetMetadata, but tweaked to get existing values
// of the metadataKey and accumulate it with the new metadataValue
function SetMultipleMetadata(metadataKey, metadataValue): CustomDecorator {
const decoratorFactory = (target, key, descriptor) => {
// .start: tweak
// descriptor?.value = function decorator; target = class decorator
const accumulatedVal =
Reflect.getMetadata(metadataKey, descriptor?.value ?? target) ?? [];
accumulatedVal.push(metadataValue);
// .end: tweak
if (descriptor) {
Reflect.defineMetadata(metadataKey, accumulatedVal, descriptor.value);
return descriptor;
}
Reflect.defineMetadata(metadataKey, accumulatedVal, target);
return target;
};
decoratorFactory.KEY = metadataKey;
return decoratorFactory as any;
}
export function RequireAllPermissions(
...permissions: PermissionsObjectPermission[]
) {
return SetMultipleMetadata(AUTH_FUNCTION_KEY, (req, user: RequestUser) =>
permissions.every(({ seqid }) => user.permissions.includes(seqid)),
);
}
export function RequireSomePermission(
...permissions: PermissionsObjectPermission[]
) {
return SetMultipleMetadata(AUTH_FUNCTION_KEY, (req, user: RequestUser) =>
permissions.some(({ seqid }) => user.permissions.includes(seqid)),
);
}
export function AuthenticateCondition(func: AuthenticationFunction) {
return SetMultipleMetadata(AUTH_FUNCTION_KEY, func);
}
export function Authenticated() {
return SetMultipleMetadata(AUTH_FUNCTION_KEY, () => true);
}
@@ -11,7 +11,7 @@ import {
Authenticated,
RequireAllPermissions,
RequireSomePermission,
} from './authentication.decorator';
} from '../decorators/authentication.decorator';
import { AuthenticationGuard } from './authentication.guard';
import { PERMISSIONS_GROUPS } from './permissions.enum';
import { AuthClientService } from '../modules/auth/auth.service';
+2 -2
View File
@@ -13,8 +13,8 @@ import { AuthClientService } from '../modules/auth/auth.service';
import {
AuthenticationFunction,
AUTH_FUNCTION_KEY,
} from './authentication.decorator';
import { RequestUser } from './user.decorator';
} from '../decorators/authentication.decorator';
import { RequestUser } from '../decorators/user.decorator';
import ErrorBuilder from '../utils/ErrorBuilder';
import ErrorCodes from '../utils/errorCodes';
@@ -0,0 +1,41 @@
import { applyDecorators } from '@nestjs/common';
import { ApiSecurity } from '@nestjs/swagger';
import { type Request } from 'express';
import { type PermissionsObjectPermission } from '../authentication/permissions.enum';
import { type RequestUser } from './user.decorator';
import { SetMultipleMetadata } from './shared';
export const AUTH_FUNCTION_KEY = '__AUTH_FUNCTION__';
export type AuthenticationFunction = (req: Request, user: any) => boolean;
export function RequireAllPermissions(
...permissions: PermissionsObjectPermission[]
) {
return createAuthenticatedDecorator((req, user: RequestUser) =>
permissions.every(({ seqid }) => user.permissions.includes(seqid)),
);
}
export function RequireSomePermission(
...permissions: PermissionsObjectPermission[]
) {
return createAuthenticatedDecorator((req, user: RequestUser) =>
permissions.some(({ seqid }) => user.permissions.includes(seqid)),
);
}
export function AuthenticateCondition(func: AuthenticationFunction) {
return createAuthenticatedDecorator(func);
}
export function Authenticated() {
return createAuthenticatedDecorator(() => true);
}
function createAuthenticatedDecorator(metadataValue: AuthenticationFunction) {
return applyDecorators(
ApiSecurity('access-token'),
SetMultipleMetadata(AUTH_FUNCTION_KEY, metadataValue),
);
}
+25
View File
@@ -0,0 +1,25 @@
import { createParamDecorator, type ExecutionContext } from '@nestjs/common';
import { LanguageEnum } from 'src/utils/languages.enum';
export const Language: () => ParameterDecorator = createParamDecorator(
(options: any, ctx: ExecutionContext): LanguageEnum => {
const headers = ctx.switchToHttp()?.getRequest()?.headers;
if (!headers) return LanguageEnum.ptbr;
let language: LanguageEnum =
headers['dadosfera-lang'] ?? headers['accept-language'];
language = language?.toLowerCase().trim() as LanguageEnum;
if (!language) return LanguageEnum.ptbr;
Object.values(LanguageEnum).some((l) => {
if (language === l || l.includes(language)) {
language = l;
return true;
}
language = LanguageEnum.enus;
});
return language;
},
);
+28
View File
@@ -0,0 +1,28 @@
import { type CustomDecorator } from '@nestjs/common';
// implementation copied from SetMetadata, but tweaked to get existing values
// of the metadataKey and accumulate it with the new metadataValue
export function SetMultipleMetadata(
metadataKey,
metadataValue,
): CustomDecorator {
const decoratorFactory: CustomDecorator = (target, key?, descriptor?) => {
// .start: tweak
// descriptor?.value = function decorator; target = class decorator
const accumulatedVal =
Reflect.getMetadata(metadataKey, descriptor?.value ?? target) ?? [];
accumulatedVal.push(metadataValue);
// .end: tweak
if (descriptor) {
Reflect.defineMetadata(metadataKey, accumulatedVal, descriptor.value);
return descriptor;
}
Reflect.defineMetadata(metadataKey, accumulatedVal, target);
return target;
};
decoratorFactory.KEY = metadataKey;
return decoratorFactory;
}
+13
View File
@@ -0,0 +1,13 @@
import { applyDecorators } from '@nestjs/common';
import { ApiExcludeController, ApiExcludeEndpoint } from '@nestjs/swagger';
export function ApiInternalOnlyEndpoint() {
if (process.env.INTERNAL_SWAGGER !== 'true')
return applyDecorators(ApiExcludeEndpoint());
return () => null;
}
export function ApiInternalOnlyController() {
if (process.env.INTERNAL_SWAGGER !== 'true')
return applyDecorators(ApiExcludeController());
return () => null;
}
@@ -1,17 +1,14 @@
import request from 'supertest';
import { Test } from '@nestjs/testing';
import { HttpStatus, INestApplication } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import jwt from 'jsonwebtoken';
import { Controller, Get } from '@nestjs/common';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { AuthenticationGuard } from './authentication.guard';
import { Controller, Get, HttpStatus, INestApplication } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { Test } from '@nestjs/testing';
import jwt from 'jsonwebtoken';
import request from 'supertest';
import { AuthenticationGuard } from '../authentication/authentication.guard';
import { PERMISSIONS_GROUPS } from '../authentication/permissions.enum';
import { AuthClientService } from '../modules/auth/auth.service';
import ErrorCodes from '../utils/errorCodes';
import { User } from './user.decorator';
import { PERMISSIONS_GROUPS } from './permissions.enum';
const logger = {
info: (...args) => args,
@@ -1,4 +1,4 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { createParamDecorator, type ExecutionContext } from '@nestjs/common';
import ErrorBuilder from '../utils/ErrorBuilder';
import ErrorCodes from '../utils/errorCodes';
+18 -8
View File
@@ -24,11 +24,10 @@ async function bootstrap() {
optionsSuccessStatus: 204,
},
});
app.use(helmet());
configureSwagger(app);
await app.listen(3333);
if (process.env.KILL_AFTER_START) await app.close();
}
function configureSwagger(app: INestApplication) {
@@ -39,24 +38,35 @@ function configureSwagger(app: INestApplication) {
.replace('\n', '')
.trim();
} catch (error) {
console.log("Can't get branch name", error);
console.warn("Can't get branch name", error);
}
const swaggerTitle = branchName ? `Maestro - ${branchName}` : 'Maestro';
const config = new DocumentBuilder()
.setTitle(swaggerTitle)
.setDescription('Documentation for Maestro gateway')
.addBearerAuth(
{ type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
'Authorization',
)
.addSecurity('access-token', {
type: 'apiKey',
name: 'Authorization',
in: 'header',
})
.setDescription('This is the Maestro API')
.addServer('https://maestro.stg.dadosfera.ai', 'Ambiente STG')
.addServer('https://maestro-2.stg.dadosfera.ai', 'Ambiente STG2')
.addServer('https://maestro.dadosfera.ai', 'Ambiente PRD')
.build();
const document = SwaggerModule.createDocument(app, config);
const swaggerJsonFile =
process.env.INTERNAL_SWAGGER === 'true'
? 'docsfera.json'
: 'docsfera.external.json';
if (process.env.ENV === 'local') SwaggerModule.setup('api', app, document);
writeFileSync(
'docsfera.json',
swaggerJsonFile,
JSON.stringify(
{
service: '${DOCS_API_TOKEN}',
+48 -23
View File
@@ -13,7 +13,12 @@ import {
Req,
Param,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import {
ApiHeaders,
ApiOkResponse,
ApiSecurity,
ApiTags,
} from '@nestjs/swagger';
import {
AuthChangePasswordRequest,
AuthResetPasswordRequest,
@@ -28,13 +33,14 @@ import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import {
Authenticated,
RequireAllPermissions,
} from 'src/authentication/authentication.decorator';
} from 'src/decorators/authentication.decorator';
import { AuthClientService } from './auth.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { GrpcToHttpExceptionFilter } from '../../error/grpc-to-http-exception.filter';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { RequestUser, User } from 'src/decorators/user.decorator';
import {
AuthRefreshAccessTokenReq,
AuthRefreshAccessTokenRes,
AuthSignInReq,
AuthSignInRes,
} from './dtos/login';
@@ -43,8 +49,12 @@ import { AuthGuard } from '@nestjs/passport';
import { Request } from 'express';
import ErrorCodes, { OauthErrors } from 'src/utils/errorCodes';
import jwt from 'jsonwebtoken';
import { LanguageEnum } from 'src/utils/languages.enum';
import { Language } from 'src/decorators/language.decorator';
import { ApiInternalOnlyEndpoint } from 'src/decorators/swagger.decorator';
@ApiTags('Auth')
@ApiHeaders([{ name: 'dadosfera-lang', enum: LanguageEnum, required: false }])
@UseFilters(new GrpcToHttpExceptionFilter())
@Controller('auth')
export class AuthController {
@@ -74,13 +84,32 @@ export class AuthController {
@HttpCode(HttpStatus.OK)
async signIn(
@Body() { username, password, totp }: AuthSignInReq,
@Headers('Dadosfera-Lang') language: string,
@Language() language: LanguageEnum,
): Promise<AuthSignInRes> {
this.logger.info('/auth - SignIn');
const metadata = PackTheMetadata({ language: language || 'pt-br' });
const metadata = PackTheMetadata({ language });
return this.authClient.signIn({ username, password, totp }, metadata);
}
@Post('refresh-access-token')
@HttpCode(HttpStatus.OK)
@ApiOkResponse({ type: AuthRefreshAccessTokenRes })
async refreshAccessToken(
@Body() body: AuthRefreshAccessTokenReq,
@Language() language: LanguageEnum,
) {
this.logger.info('/auth - RefreshAccessToken');
const { refreshToken, customerName: customer_name } = body;
const metadata = PackTheMetadata({
customer_name,
language,
});
return this.authClient.refreshAccessToken({ refreshToken }, metadata);
}
@ApiInternalOnlyEndpoint()
@Post('/sso/snowflake')
@RequireAllPermissions(PERMISSIONS_GROUPS.SNOWFLAKE.permissions.OPEN)
@HttpCode(HttpStatus.OK)
@@ -96,23 +125,7 @@ export class AuthController {
});
}
@Post('refresh-access-token')
@HttpCode(HttpStatus.OK)
async refreshAccessToken(
@Body()
{ refreshToken, customerName: customer_name }: AuthRefreshAccessTokenReq,
@Headers('Dadosfera-Lang') language: string,
) {
this.logger.info('/auth - RefreshAccessToken');
const metadata = PackTheMetadata({
customer_name,
language,
});
return this.authClient.refreshAccessToken({ refreshToken }, metadata);
}
@ApiInternalOnlyEndpoint()
@Post('change-password')
@HttpCode(HttpStatus.OK)
async changePassword(
@@ -131,11 +144,12 @@ export class AuthController {
});
}
@ApiInternalOnlyEndpoint()
@Post('reset-password')
@HttpCode(HttpStatus.OK)
async resetPassword(
@Body() body: AuthResetPasswordRequest,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('/auth - reset-password');
const metadata = PackTheMetadata({
@@ -147,6 +161,7 @@ export class AuthController {
return this.authClient.resetPassword({ username }, metadata);
}
@ApiInternalOnlyEndpoint()
@Post('verify-reset-password-code')
@HttpCode(HttpStatus.OK)
async verifyResetPasswordCode(
@@ -159,6 +174,7 @@ export class AuthController {
return this.authClient.verifyResetPasswordCode({ username, code });
}
@ApiInternalOnlyEndpoint()
@Post('confirm-reset-password')
@HttpCode(HttpStatus.OK)
async confirmResetPassword(@Body() body: AuthConfirmResetPasswordRequest) {
@@ -173,6 +189,7 @@ export class AuthController {
});
}
@ApiInternalOnlyEndpoint()
@Post('enable-totp')
@HttpCode(HttpStatus.OK)
async enableTotpMFA(
@@ -187,6 +204,7 @@ export class AuthController {
return this.authClient.enableTotpMFA({ accessToken, password });
}
@ApiInternalOnlyEndpoint()
@Post('disable-totp')
@HttpCode(HttpStatus.OK)
async disableTotpMFA(
@@ -201,6 +219,7 @@ export class AuthController {
return this.authClient.disableTotpMFA({ accessToken, password });
}
@ApiInternalOnlyEndpoint()
@Post('dismiss-totp')
@HttpCode(HttpStatus.OK)
async dismissTotpMFA(@Headers() headers) {
@@ -211,6 +230,7 @@ export class AuthController {
return this.authClient.dismissTotpMFA({ accessToken });
}
@ApiInternalOnlyEndpoint()
@Post('verify-totp')
@HttpCode(HttpStatus.OK)
async verifyTotp(@Body() body: AuthVerifyTotpMfaRequest, @Headers() headers) {
@@ -222,17 +242,21 @@ export class AuthController {
return this.authClient.verifyTotp({ accessToken, totp });
}
@ApiInternalOnlyEndpoint()
@Authenticated()
@ApiSecurity('access-token')
@Get('verify-access-token')
verifyAccessToken() {
return { access_token_status: 'valid' };
}
@ApiInternalOnlyEndpoint()
@Get('session/:session')
getSession(@Param('session') session: string) {
return this.authClient.getSession(session);
}
@ApiInternalOnlyEndpoint()
@Get('oauth/google')
@UseGuards(AuthGuard('google-login'))
googleOauth() {
@@ -240,6 +264,7 @@ export class AuthController {
return true;
}
@ApiInternalOnlyEndpoint()
@Get('oauth/google/callback')
@UseGuards(AuthGuard('google-login'))
@Redirect()
+10 -1
View File
@@ -81,7 +81,10 @@ export class AuthSignInReq implements AuthSignInRequest {
username: string;
@ApiProperty()
password: string;
@ApiPropertyOptional()
@ApiPropertyOptional({
description:
'TOTP code used to login when Multi-Factor Authentication is enabled',
})
totp: string;
}
@@ -106,3 +109,9 @@ export class AuthRefreshAccessTokenReq {
@ApiProperty()
customerName: string;
}
export class AuthRefreshAccessTokenRes {
@ApiProperty()
permissions: string[];
@ApiProperty()
accessToken: string;
}
+22 -10
View File
@@ -6,7 +6,6 @@ import {
ForbiddenException,
Get,
Headers,
HttpException,
Inject,
NotFoundException,
Param,
@@ -15,17 +14,18 @@ import {
Query,
UseFilters,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { ApiHeaders, ApiTags } from '@nestjs/swagger';
import {
Authenticated,
RequireSomePermission,
} from '../../authentication/authentication.decorator';
} from '../../decorators/authentication.decorator';
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
import { CatalogService } from './catalog.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { RequestUser, User } from 'src/decorators/user.decorator';
import {
ICatalogAllRequest,
ICatalogAllResponse,
IColumnsMetadataResponse,
ICreateDataAsset,
@@ -37,8 +37,12 @@ import {
IUpdateDataRequest,
} from './dtos';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
import { Language } from 'src/decorators/language.decorator';
import { LanguageEnum } from 'src/utils/languages.enum';
import { ApiInternalOnlyEndpoint } from 'src/decorators/swagger.decorator';
@ApiTags('Catalog')
@ApiHeaders([{ name: 'dadosfera-lang', enum: LanguageEnum, required: false }])
@Controller('catalog')
@UseFilters(new GrpcToHttpExceptionFilter())
@Authenticated()
@@ -59,7 +63,7 @@ export class CatalogController {
)
async searchCatalog(
@User() user: RequestUser,
@Query() query,
@Query() query: ICatalogAllRequest,
): Promise<ICatalogAllResponse> {
const { user_id, customer_name, customer_id, username, permissions } = user;
this.logger.info(`/catalog - searchCatalog`, {
@@ -91,6 +95,7 @@ export class CatalogController {
return res;
}
@ApiInternalOnlyEndpoint()
@Get('data-asset')
async findByPipelineAndObject(@User() user: RequestUser, @Query() query) {
const { username, user_id, customer_id, customer_name, permissions } = user;
@@ -144,6 +149,7 @@ export class CatalogController {
);
}
@ApiInternalOnlyEndpoint()
@Get('tags')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
@@ -222,6 +228,7 @@ export class CatalogController {
return { data_asset };
}
@ApiInternalOnlyEndpoint()
@Get('data-asset/rls/:id')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
@@ -284,7 +291,7 @@ export class CatalogController {
)
async getDataAssetColumnsMetadata(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Language() language: LanguageEnum,
@Param('id') id,
): Promise<IColumnsMetadataResponse> {
const { customer_name, customer_id, user_id, username } = user;
@@ -315,7 +322,7 @@ export class CatalogController {
)
async getDataAssetPreview(
@User() user: RequestUser,
@Headers('Dadosfera-lang') language,
@Language() language: LanguageEnum,
@Param('id') id,
): Promise<IPreviewResponse> {
const { customer_name, customer_id, user_id, username } = user;
@@ -345,7 +352,7 @@ export class CatalogController {
)
async getDataAssetDocs(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Language() language: LanguageEnum,
@Param('id') id,
): Promise<IDocsResponse> {
const { customer_name, customer_id, user_id, username } = user;
@@ -375,7 +382,7 @@ export class CatalogController {
)
async updateDataAsset(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Language() language: LanguageEnum,
@Param('id') data_asset_id,
@Body() body: IUpdateDataRequest,
): Promise<IOneDataAsset> {
@@ -430,6 +437,7 @@ export class CatalogController {
return res;
}
@ApiInternalOnlyEndpoint()
@Put('data-asset/:id/manage-permissions')
async manageDataAssetPermissions(
@Param('id') id: string,
@@ -451,6 +459,7 @@ export class CatalogController {
return { data_asset: JSON.parse(response.data_asset) };
}
@ApiInternalOnlyEndpoint()
@Put('data-asset/:id/revoke-permissions')
async revokeDataAssetPermissions(
@Param('id') id: string,
@@ -561,7 +570,10 @@ export class CatalogController {
username,
});
const response = await this.catalogService.deleteComment(
{ data_asset_id: id, comment: body.comment },
{
data_asset_id: id,
comment: { ...body.comment, created_at: undefined, message: undefined },
},
metadata,
);
+43 -3
View File
@@ -1,4 +1,4 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { ApiProperty, ApiPropertyOptional, PickType } from '@nestjs/swagger';
import { CreateDataAssetRequest } from '@dadosfera/protospack-v2/dist/lib/Catalog/interfaces/messages';
export enum DataAssetShareType {
@@ -6,6 +6,10 @@ export enum DataAssetShareType {
public = 'public',
private = 'private',
}
export enum OrderEnum {
asc = 'asc',
desc = 'desc',
}
export class EmbedObject {
@ApiProperty()
url: string;
@@ -92,6 +96,8 @@ export class IDataAsset {
comments: IComment[];
@ApiPropertyOptional()
embed?: EmbedObject;
@ApiPropertyOptional({ enum: DataAssetShareType })
share_type?: DataAssetShareType;
}
export class IOneDataAsset {
@@ -104,9 +110,43 @@ export class IMakeAComment {
message: string;
}
export class CommentToDelete extends PickType(IComment, ['id', 'username']) {}
export class IDeleteComment {
@ApiProperty()
comment: IComment;
comment: CommentToDelete;
}
export class ICatalogAllRequest {
@ApiPropertyOptional({
description: 'Texto usado para filtrar os ativos no catálogo.',
})
search;
@ApiPropertyOptional({
description: 'Número de registros a ser retornado',
maximum: 10000,
minimum: 1,
})
size: number;
@ApiPropertyOptional({
description: 'Usado para paginação, em conjunto com `size`',
minimum: 1,
})
page: number;
@ApiPropertyOptional({
description:
'Campo do data asset para usar na ordenação. Padrão: `created_at` ',
})
sort_by: string;
@ApiPropertyOptional({
enum: OrderEnum,
default: OrderEnum.asc,
description: 'Tipo de ordenação - `asc`: crescente; `desc`: decrescente ',
})
order?: OrderEnum;
}
export class ICatalogAllResponse {
@@ -141,7 +181,7 @@ export class IUpdateDataRequest {
@ApiPropertyOptional()
embed: EmbedObject;
@ApiPropertyOptional({ enum: DataAssetShareType })
share_type: DataAssetShareType;
share_type?: DataAssetShareType;
}
export class ICreateDataAsset implements CreateDataAssetRequest {
@ApiProperty()
@@ -9,7 +9,7 @@ import {
ValidationPipe,
} from '@nestjs/common';
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { User, RequestUser } from 'src/authentication/user.decorator';
import { User, RequestUser } from 'src/decorators/user.decorator';
import { ConnectionTestService } from './connection-test.service';
import {
ConnectionTestPingRes,
@@ -24,9 +24,11 @@ import {
GetTableMetadataReq,
} from './dto/connection-test';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { Authenticated } from 'src/authentication/authentication.decorator';
import { Authenticated } from 'src/decorators/authentication.decorator';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
@ApiInternalOnlyController()
@ApiTags('Connection Test')
@Controller('connection-test')
@UseFilters(new GrpcToHttpExceptionFilter())
@@ -19,7 +19,7 @@ import {
CreateConnectionDto,
DatabaseConnectionPropertiesDto,
} from '../connection/dtos/connection';
import { RequestUser } from 'src/authentication/user.decorator';
import { RequestUser } from 'src/decorators/user.decorator';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
@Injectable()
+11 -11
View File
@@ -7,19 +7,18 @@ import {
Param,
Delete,
Get,
Headers,
Query,
UseFilters,
} from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { ApiExcludeEndpoint, ApiTags } from '@nestjs/swagger';
import { ConnectionClientService } from './client.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import {
Authenticated,
RequireAllPermissions,
} from 'src/authentication/authentication.decorator';
} from 'src/decorators/authentication.decorator';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { RequestUser, User } from 'src/decorators/user.decorator';
import { ValidationPipe } from '../../pipes/object-validation.pipe';
import {
ConnectionDetailsRes,
@@ -30,11 +29,13 @@ import {
import { CreateConnectionDto } from './dtos/connection';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
import { Language } from 'src/decorators/language.decorator';
import { LanguageEnum } from 'src/utils/languages.enum';
import { ApiInternalOnlyEndpoint } from 'src/decorators/swagger.decorator';
const connectionPermissions = PERMISSIONS_GROUPS.CONNECTION.permissions;
@UseFilters(new GrpcToHttpExceptionFilter())
@ApiTags('connections')
@ApiBearerAuth()
@Authenticated()
@Controller('connections')
export class ConnectionController {
@@ -47,7 +48,9 @@ export class ConnectionController {
this.logger = dadosferaLogger.logger;
}
@ApiInternalOnlyEndpoint()
@Get('connections-migration')
@ApiExcludeEndpoint()
@RequireAllPermissions(
PERMISSIONS_GROUPS.DADOSFERA.permissions.CONNECTIONS_MIGRATION,
)
@@ -83,12 +86,11 @@ export class ConnectionController {
@RequireAllPermissions(connectionPermissions.CREATE)
async updateConnection(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language: string,
@Language() language: LanguageEnum,
@Param('id') id: string,
@Body(new ValidationPipe()) body: UpdateConnectionDto,
): Promise<ConnectionRes> {
this.logger.info('/connections - Update Connection');
if (!language) language = 'en-us';
const { user_id, customer_id, customer_name, username } = user;
const metadata = PackTheMetadata({
@@ -135,11 +137,10 @@ export class ConnectionController {
@Get()
async getAllConnections(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Language() language: LanguageEnum,
@Query() queries,
): Promise<ConnectionsRes> {
this.logger.info('/connections - Get All Connection');
if (!language) language = 'en-us';
const { user_id, customer_id, customer_name, username } = user;
const { search, size, page, ...filters } = queries;
@@ -161,13 +162,12 @@ export class ConnectionController {
@Get('/:id')
async getConnectionDetails(
@Headers('Dadosfera-Lang') language,
@Language() language: LanguageEnum,
@User() user: RequestUser,
@Param('id') id,
@Query() queries,
): Promise<ConnectionDetailsRes> {
this.logger.info('/connections - Get Connection Details');
if (!language) language = 'en-us';
console.log(queries);
+9 -11
View File
@@ -11,11 +11,10 @@ import {
UploadedFile,
UseInterceptors,
Inject,
Headers,
UploadedFiles,
} from '@nestjs/common';
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
import { ApiBearerAuth, ApiConsumes, ApiTags } from '@nestjs/swagger';
import { ApiConsumes, ApiTags } from '@nestjs/swagger';
import { ConnectorClientService } from './client.service';
import { AddTagDto } from './dtos/add-tag';
import { CreateConnectorDto } from './dtos/create-connector';
@@ -27,11 +26,14 @@ import {
Authenticated,
RequireAllPermissions,
RequireSomePermission,
} from 'src/authentication/authentication.decorator';
} from 'src/decorators/authentication.decorator';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import { Language } from 'src/decorators/language.decorator';
import { LanguageEnum } from 'src/utils/languages.enum';
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
@ApiInternalOnlyController()
@ApiTags('connectors')
@ApiBearerAuth()
@Authenticated()
@Controller('connectors')
export class ConnectorController {
@@ -98,11 +100,10 @@ export class ConnectorController {
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
)
async getAllConnectors(
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
@Query() queries: GetAllDto,
) {
this.logger.info('/GET - getAllConnectors Route');
if (!language) language = 'en-us';
const { search, size, page, ...filters } = queries;
@@ -143,12 +144,11 @@ export class ConnectorController {
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
)
async getConnector(
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
@Param('plugin') plugin: string,
@Query('version') version: string,
) {
this.logger.info('/GET/:plugin - getConnector Route');
if (!language) language = 'en-us';
const pluginId = `${plugin}-${version}`;
@@ -172,13 +172,11 @@ export class ConnectorController {
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
)
async getConnectorDetails(
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
@Param('plugin') plugin: string,
@Query('version') version: string,
) {
this.logger.info('/upload - Upload Connector Route');
if (!language) language = 'en-us';
const pluginId = `${plugin}-${version}`;
const response: any = await this.connectorClientService.getConnectorDetails(
+7 -2
View File
@@ -12,7 +12,7 @@ import {
import { InputsService } from './inputs.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
import { AuthenticateCondition } from 'src/authentication/authentication.decorator';
import { AuthenticateCondition } from 'src/decorators/authentication.decorator';
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
import {
CreateInputReq,
@@ -21,9 +21,10 @@ import {
Input,
} from './dtos/input.model';
import { UpdateInputRequest } from './dtos/old_interfaces';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { RequestUser, User } from 'src/decorators/user.decorator';
import { Info } from '@dadosfera/protospack-v2/dist/lib/Input/interfaces/entities';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
import { ApiInternalOnlyEndpoint } from 'src/decorators/swagger.decorator';
@ApiTags('Inputs')
@Controller('inputs')
@@ -66,6 +67,7 @@ export class InputsController {
this.logger = dadosferaLogger.logger;
}
@ApiInternalOnlyEndpoint()
@Get('available-entities/:plugin')
@ApiOkResponse({ type: GetAvailableEntitiesRes })
async getAvailableEntities(
@@ -102,6 +104,7 @@ export class InputsController {
return response;
}
@ApiInternalOnlyEndpoint()
@Get()
async findAll(@User() user: RequestUser) {
const { user_id, customer_id, customer_name: customer } = user;
@@ -132,6 +135,7 @@ export class InputsController {
return response;
}
@ApiInternalOnlyEndpoint()
@Patch(':id')
async update(@Body() updateInputDto: UpdateInputRequest, @Param() params) {
const { id } = params;
@@ -147,6 +151,7 @@ export class InputsController {
return response;
}
@ApiInternalOnlyEndpoint()
@Delete(':id')
async delete(@Body() data, @Param() params) {
const { id } = params;
+4 -2
View File
@@ -1,8 +1,10 @@
import { Body, Controller, Inject, Param, Post } from '@nestjs/common';
import { init } from 'mixpanel';
import { Authenticated } from 'src/authentication/authentication.decorator';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { Authenticated } from 'src/decorators/authentication.decorator';
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
import { RequestUser, User } from 'src/decorators/user.decorator';
@ApiInternalOnlyController()
@Authenticated()
@Controller('trackEvent')
export class MixpanelController {
@@ -6,6 +6,8 @@ import {
} from '@nestjs/microservices';
import { NetworkConfig } from '@dadosfera/protospack-v2';
const isLocalConnection = !!process.env.INFACTORY_URL?.includes('0.0.0.0');
export class NetworkConfigGrpcClient {
public name = 'NetworkConfigGrpcClient';
@@ -17,8 +19,7 @@ export class NetworkConfigGrpcClient {
NetworkConfig.ProtoPackages.ReadPackage,
NetworkConfig.ProtoPackages.WritePackage,
],
credentials:
process.env.ENV === 'local' ? undefined : credentials.createSsl(),
credentials: isLocalConnection ? undefined : credentials.createSsl(),
protoPath: [
NetworkConfig.ProtoPaths.ReadFilePath,
NetworkConfig.ProtoPaths.WriteFilePath,
@@ -1,12 +1,9 @@
import {
Body,
Controller,
Delete,
Get,
Headers,
Inject,
Param,
Patch,
Post,
Query,
UploadedFile,
@@ -15,7 +12,7 @@ import {
import { NetworkConfigService } from './network-config.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { ApiConsumes, ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { RequestUser, User } from 'src/decorators/user.decorator';
import {
CreateNetworkConfigReq,
CreateNetworkConfigRes,
@@ -26,7 +23,9 @@ import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import {
Authenticated,
RequireAllPermissions,
} from 'src/authentication/authentication.decorator';
} from 'src/decorators/authentication.decorator';
import { Language } from 'src/decorators/language.decorator';
import { LanguageEnum } from 'src/utils/languages.enum';
const networkConfigPermissions = PERMISSIONS_GROUPS.NETWORK_CONFIG.permissions;
@ApiTags('Network Config')
@@ -40,18 +39,18 @@ export class NetworkConfigController {
) {
this.logger = dadosferaLogger.logger;
}
@Get()
@ApiOkResponse({ type: FindAllNetworkConfigsRes })
async findAllNetworkConfigs(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Language() language: LanguageEnum,
@Query() queries,
) {
this.logger.info('GET /network-config', {
user: user.user_id,
customer: user.customer_name,
});
if (!language) language = 'en-us';
const { user_id, customer_id, customer_name } = user;
const { search, size, page, ...filters } = queries;
@@ -79,14 +78,14 @@ export class NetworkConfigController {
@ApiOkResponse({ type: FindAllNetworkConfigsRes })
async findNetworkConfigByIdDetails(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Language() language: LanguageEnum,
@Param('id') id: string,
) {
this.logger.info('GET /network-config/:id', {
user: user.user_id,
customer: user.customer_name,
});
if (!language) language = 'en-us';
return this.networkConfigService.findNetworkConfigByIdDetails(id, {
customer_name: user.customer_name,
customer_id: user.customer_id,
+7 -1
View File
@@ -5,6 +5,7 @@ import { ConnectionClientService } from '../connection/client.service';
import jwt from 'jsonwebtoken';
import DadosferaLogger from '@dadosfera/dadosfera-logs/dist';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
import { ApiInternalOnlyEndpoint } from 'src/decorators/swagger.decorator';
@ApiTags('oauth')
@Controller('oauth')
export class OauthController {
@@ -15,7 +16,6 @@ export class OauthController {
private logger: DadosferaLogger,
) {
switch (process.env.ENV) {
case 'dev':
case 'stg':
this.redirectUrl = `https://app.${process.env.ENV}.dadosfera.ai/collect/auth-callback`;
break;
@@ -32,6 +32,7 @@ export class OauthController {
return true;
}
@ApiInternalOnlyEndpoint()
@Get('hubspot/callback')
@UseGuards(AuthGuard('hubspot'))
@Redirect()
@@ -45,6 +46,7 @@ export class OauthController {
return true;
}
@ApiInternalOnlyEndpoint()
@Get('googleads/callback')
@UseGuards(AuthGuard('google'))
@Redirect()
@@ -58,6 +60,7 @@ export class OauthController {
return true;
}
@ApiInternalOnlyEndpoint()
@Get('google-sheets/callback')
@UseGuards(AuthGuard('google'))
@Redirect()
@@ -71,6 +74,7 @@ export class OauthController {
return true;
}
@ApiInternalOnlyEndpoint()
@Get('facebook/callback')
@UseGuards(AuthGuard('facebook'))
@Redirect()
@@ -84,6 +88,7 @@ export class OauthController {
return true;
}
@ApiInternalOnlyEndpoint()
@Get('mailchimp/callback')
@UseGuards(AuthGuard('mailchimp'))
@Redirect()
@@ -97,6 +102,7 @@ export class OauthController {
return true;
}
@ApiInternalOnlyEndpoint()
@Get('salesforce/callback')
@UseGuards(AuthGuard('salesforce'))
@Redirect()
@@ -29,7 +29,6 @@ export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
super(options, verify);
switch (process.env.ENV) {
case 'dev':
case 'stg':
this.redirect_uri = `https://maestro.${process.env.ENV}.dadosfera.ai/oauth`;
break;
@@ -1,13 +1,16 @@
import { Controller, Get, Headers, Inject } from '@nestjs/common';
import { Controller, Get, Inject } from '@nestjs/common';
import { ApiHeader, ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { Authenticated } from 'src/authentication/authentication.decorator';
import { Authenticated } from 'src/decorators/authentication.decorator';
import { PermissionUsages } from 'src/authentication/permissions.enum';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { RequestUser, User } from 'src/decorators/user.decorator';
import { LanguageEnum } from 'src/utils/languages.enum';
import { GetPublicPermissionsRes } from './dto/entities';
import { PermissionsService } from './permissions.service';
import { Language } from 'src/decorators/language.decorator';
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
@ApiInternalOnlyController()
@ApiTags('Permissions')
@Authenticated()
@Controller('permissions')
@@ -32,10 +35,10 @@ export class PermissionsController {
@ApiOkResponse({ type: GetPublicPermissionsRes })
getPublicPermissions(
@User() user: RequestUser,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('getPublicPermissions', { user });
if (!language) language = 'en-us';
const permissionGroups = this.permissionsService.getPermissionsGrouped(
PermissionUsages.PUBLIC,
language,
@@ -44,8 +44,11 @@ export class PermissionsService
);
}
// internally used to send permissions to duc on microservice startup
async onApplicationBootstrap() {
// Do not sent permissions if running local but pointing to a remote DUC url
if (process.env.ENV == 'local' && !process.env.DUC_URL.includes('0.0.0.0'))
return;
this.logger.info('sending permissions to DUC...');
const permissions = Object.values(PERMISSIONS_GROUPS).flatMap((namespace) =>
@@ -57,10 +60,10 @@ export class PermissionsService
}).catch((err: ErrorBuilder) => {
if (
err.code === 'No connection established' &&
(process.env.LOCAL_ENV === 'true' || process.env.ENV === 'local')
process.env.ENV === 'local'
) {
return this.logger.info(
"couldn't connect to DUC. suppresing in local env",
"couldn't connect to DUC. suppressing in local env",
);
}
+14 -2
View File
@@ -1,13 +1,15 @@
import { Body, Controller, Get, Inject, Param, Post } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import {
AuthenticateCondition,
Authenticated,
} from 'src/authentication/authentication.decorator';
} from 'src/decorators/authentication.decorator';
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
import { PipelinesService } from './pipelines.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
@ApiInternalOnlyController()
@ApiTags('Pipelines')
@Controller('pipelines')
@Authenticated()
@@ -42,6 +44,11 @@ export class PipelinesController {
}
@Post('start/:id')
@ApiOperation({
deprecated: true,
description:
'This method is deprecated. Please use route /pipelinesV2/start/:id instead',
})
async activate(@Param() params, @Body() body) {
const { id } = params;
const { info } = body;
@@ -60,6 +67,11 @@ export class PipelinesController {
}
@Get(':id/status')
@ApiOperation({
deprecated: true,
description:
'This method is deprecated. Please use route /pipelinesV2/:id/status instead',
})
async getPipelineStatus(@Body() body, @Param() params) {
const { id } = params;
body.id = id;
+75 -38
View File
@@ -7,28 +7,30 @@ import {
Param,
Post,
Put,
Headers,
Query,
UseFilters,
HttpCode,
HttpStatus,
Patch,
HttpException,
BadRequestException,
} from '@nestjs/common';
import {
ApiCreatedResponse,
ApiHeaders,
ApiNoContentResponse,
ApiOperation,
ApiTags,
} from '@nestjs/swagger';
import {
AuthenticateCondition,
RequireAllPermissions,
} from 'src/authentication/authentication.decorator';
} from 'src/decorators/authentication.decorator';
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
import { PipelinesService } from './pipelines.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { Messages } from '@dadosfera/protospack-v2/dist/lib/PipelineV2';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { RequestUser, User } from 'src/decorators/user.decorator';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
import { PipelinesService as OldPipelineService } from 'src/modules/pipelines/pipelines.service';
@@ -40,9 +42,13 @@ import {
IInitUploadCSVFile,
} from './interfaces';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
import { LanguageEnum } from 'src/utils/languages.enum';
import { Language } from 'src/decorators/language.decorator';
import { ApiInternalOnlyEndpoint } from 'src/decorators/swagger.decorator';
@UseFilters(new GrpcToHttpExceptionFilter())
@ApiTags('PipelinesV2')
@ApiHeaders([{ name: 'dadosfera-lang', enum: LanguageEnum, required: false }])
@UseFilters(new GrpcToHttpExceptionFilter())
@Controller('pipelinesV2')
@AuthenticateCondition((req, user) => {
let action;
@@ -82,12 +88,12 @@ export class PipelinesController {
@Post()
@ApiCreatedResponse({ type: IPipelineV2 })
async create(
@Headers('Dadosfera-Lang') language,
@Language() language: LanguageEnum,
@User() user: RequestUser,
@Body() createPipelineDto: ICreatePipelineV2Req,
) {
this.logger.info('PipelinesController - create', { user });
if (!language) language = 'en-us';
const { customer_id, customer_name, username, user_id } = user;
const metadata = PackTheMetadata({
customer_id,
@@ -108,13 +114,11 @@ export class PipelinesController {
@Get()
async findAll(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Language() language: LanguageEnum,
@Query() data,
) {
this.logger.info('PipelinesController - findAll', { user });
if (!language) language = 'en-us';
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
customer_id,
@@ -134,16 +138,13 @@ export class PipelinesController {
@Get('/download-logs')
async downloadLogs(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Query() query,
@Language() language: LanguageEnum,
@Query('pipeline_run_id') pipeline_run_id: string,
) {
this.logger.info('PipelinesController - downloadLogs', { user });
if (!language) language = 'en-us';
if (!query) {
throw new HttpException('Query params not provided', 400);
}
if (!pipeline_run_id)
throw new BadRequestException('Missing pipeline_run_id');
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
@@ -155,7 +156,7 @@ export class PipelinesController {
});
const url = await this.pipelinesClientService.downloadLogs(
query.pipeline_run_id,
pipeline_run_id,
metadata,
);
@@ -166,42 +167,52 @@ export class PipelinesController {
@Get(':id/config')
async getPipelineproperties(
@Headers('Dadosfera-Lang') language,
@Language() language: LanguageEnum,
@User() user: RequestUser,
@Param('id') id,
) {
this.logger.info('PipelinesController - getPipelineproperties', { user });
const metadata = PackTheMetadata({
...user,
language: language || 'pt-br',
});
const metadata = PackTheMetadata({ ...user, language: language });
return this.pipelinesClientService.findOneProperties(id, metadata);
}
@Get(':id/objects')
async getPipelineObjects(
@Headers('Dadosfera-Lang') language,
@Language() language: LanguageEnum,
@User() user: RequestUser,
@Param('id') id,
) {
this.logger.info('PipelinesController - getPipelineObjects', { user });
const metadata = PackTheMetadata({
...user,
language: language || 'pt-br',
});
const metadata = PackTheMetadata({ ...user, language: language });
return this.pipelinesClientService.findOneObjects(id, metadata);
}
@Get(':id/status')
async getPipelineStatus(@Body() body, @Param() params) {
const { id } = params;
body.id = id;
this.logger.info(
process.env.DEV_URL + `/pipeline/${id} - ON GET PIPELINE STATUS ROUTE`,
{
user: body.info.user_id,
customer: body.info.customer,
},
);
const response = await this.oldPipelinesService.getPipelineStatus(body);
return response;
}
@Get('/:id')
async findOne(
@Headers('Dadosfera-Lang') language,
@Language() language: LanguageEnum,
@User() user: RequestUser,
@Param('id') id,
): Promise<Messages.PipelineV2FindOneResponse> {
this.logger.info('PipelinesController - findOne', { user });
if (!language) language = 'en-us';
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
@@ -235,9 +246,9 @@ export class PipelinesController {
return result;
}
@Put('/:id')
@Patch('/:id')
async update(
@Headers('Dadosfera-Lang') language,
@Language() language: LanguageEnum,
@Body() updatePipelineDto,
@Param('id') id,
@User() user: RequestUser,
@@ -247,7 +258,6 @@ export class PipelinesController {
delete updatePipelineDto.info;
const { customer_id, customer_name, user_id, username } = user;
if (!language) language = 'en-us';
const metadata = PackTheMetadata({
customer_id,
@@ -270,16 +280,21 @@ export class PipelinesController {
return response;
}
@Patch('/:id')
async updateByPatch(
@Headers('Dadosfera-Lang') language,
@ApiInternalOnlyEndpoint()
@Put('/:id')
@ApiOperation({
deprecated: true,
description: 'This method is deprecated. Please use PATCH instead',
})
async updateDeprecated(
@Language() language: LanguageEnum,
@Body() updatePipelineDto,
@Param('id') id,
@User() user: RequestUser,
) {
this.logger.info('PipelinesController - patch', { user });
this.logger.info('PipelinesController - put', { user });
const response = await this.update(language, updatePipelineDto, id, user);
this.logger.info('PipelinesController - patch: OK', { user });
this.logger.info('PipelinesController - put: OK', { user });
return response;
}
@@ -298,6 +313,7 @@ export class PipelinesController {
this.logger.info('PipelinesController - delete: OK');
}
@ApiInternalOnlyEndpoint()
@Post('/init-upload')
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.CREATE)
async initUploadFile(
@@ -329,6 +345,7 @@ export class PipelinesController {
return { urls: JSON.parse(urls), upload_id };
}
@ApiInternalOnlyEndpoint()
@Post('/complete-upload')
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.CREATE)
async completeUploadFile(
@@ -346,6 +363,7 @@ export class PipelinesController {
);
}
@ApiInternalOnlyEndpoint()
@Post('/file')
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.CREATE)
async uploadedFile(
@@ -387,4 +405,23 @@ export class PipelinesController {
return pipeline;
}
@ApiInternalOnlyEndpoint()
@Post('start/:id')
async activate(@Param() params, @Body() body) {
const { id } = params;
const { info } = body;
this.logger.info(
process.env.DEV_URL + `/pipeline/start/${id} - ON START PIPELINE ROUTE`,
{
user: body.info.user_id,
customer: body.info.customer,
},
);
const response = await this.oldPipelinesService.runPipeline({ id, info });
return response;
}
}
+1 -1
View File
@@ -21,7 +21,7 @@ import { PipelineV2CreateRequest } from '@dadosfera/protospack-v2/dist/lib/Pipel
import { Metadata } from '@grpc/grpc-js';
import { ConnectorClientService } from '../connector/client.service';
import { InputsService } from '../inputs/inputs.service';
import { RequestUser } from 'src/authentication/user.decorator';
import { RequestUser } from 'src/decorators/user.decorator';
import { TransformationsService } from '../transformations/transformations.service';
import { getObjValueFromPath } from 'src/utils/ObjValueFromPath';
import ErrorCodes from 'src/utils/errorCodes';
@@ -1,12 +1,16 @@
import { Body, Controller, HttpException, Post } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import axios from 'axios';
import { User, RequestUser } from 'src/authentication/user.decorator';
import { Authenticated } from 'src/decorators/authentication.decorator';
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
import { User, RequestUser } from 'src/decorators/user.decorator';
import { getSecretFromSecretsManager } from 'src/utils/SecretManager';
import { INote } from './dtos';
@ApiInternalOnlyController()
@ApiTags('Productboard')
@Controller('productboard')
@Authenticated()
export class ProductboardController {
@Post('notes')
async sendNote(@Body() note: INote, @User() user: RequestUser) {
+16 -19
View File
@@ -3,7 +3,6 @@ import {
Controller,
Delete,
Get,
Headers,
Inject,
Param,
Patch,
@@ -14,11 +13,11 @@ import {
} from '@nestjs/common';
import {
ApiCreatedResponse,
ApiHeader,
ApiHeaders,
ApiOkResponse,
ApiTags,
} from '@nestjs/swagger';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { RequestUser, User } from 'src/decorators/user.decorator';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { RolesService } from './roles.service';
import {
@@ -43,16 +42,14 @@ import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import {
Authenticated,
RequireAllPermissions,
} from 'src/authentication/authentication.decorator';
} from 'src/decorators/authentication.decorator';
import { LanguageEnum } from 'src/utils/languages.enum';
import { Language } from 'src/decorators/language.decorator';
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
@ApiInternalOnlyController()
@ApiTags('Roles')
@ApiHeader({
name: 'dadosfera-lang',
enum: LanguageEnum,
required: false,
description: 'Defaults to pt-br',
})
@ApiHeaders([{ name: 'dadosfera-lang', enum: LanguageEnum, required: false }])
@Authenticated()
@UseFilters(new GrpcToHttpExceptionFilter())
@Controller('roles')
@@ -72,7 +69,7 @@ export class RolesController {
async searchRoles(
@User() user: RequestUser,
@Query() params: GetRolesByCustomerReq,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('searchRoles', { user });
this.rolesService.setLanguage(language);
@@ -85,7 +82,7 @@ export class RolesController {
async createRole(
@User() user: RequestUser,
@Body() body: CreateRoleReq,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('createRole', { user });
this.rolesService.setLanguage(language);
@@ -98,7 +95,7 @@ export class RolesController {
async grantPermissionsToRole(
@User() user: RequestUser,
@Body() body: GrantPermissionsToRoleReq,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('grantPermissionsToRole', { user });
this.rolesService.setLanguage(language);
@@ -111,7 +108,7 @@ export class RolesController {
async revokePermissionsFromRole(
@User() user: RequestUser,
@Body() body: RevokePermissionsFromRoleReq,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('revokePermissionsToRole', { user });
this.rolesService.setLanguage(language);
@@ -124,7 +121,7 @@ export class RolesController {
async setRolePermissions(
@User() user: RequestUser,
@Body() body: SetRolePermissionsReq,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('setRolePermissions', { user });
this.rolesService.setLanguage(language);
@@ -137,7 +134,7 @@ export class RolesController {
async setRoleUsers(
@User() user: RequestUser,
@Body() body: SetRoleUsersReq,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('setRoleUsers', { user });
this.rolesService.setLanguage(language);
@@ -150,7 +147,7 @@ export class RolesController {
async getRoleById(
@User() user: RequestUser,
@Param('id') id: string,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('getRoleById', { user });
this.rolesService.setLanguage(language);
@@ -162,7 +159,7 @@ export class RolesController {
async deleteRole(
@User() user: RequestUser,
@Param('id') id: string,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('deleteRole', { user });
this.rolesService.setLanguage(language);
@@ -176,7 +173,7 @@ export class RolesController {
@User() user: RequestUser,
@Param('id') id: string,
@Body() body: UpdateRoleReq,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('updateRole', { user });
this.rolesService.setLanguage(language);
+1 -1
View File
@@ -18,7 +18,7 @@ import { Permission } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/ent
import { lastValueFrom } from 'rxjs';
import { PermissionsService } from '../permissions/permissions.service';
import { LanguageEnum } from 'src/utils/languages.enum';
import { RequestUser } from 'src/authentication/user.decorator';
import { RequestUser } from 'src/decorators/user.decorator';
import { DucClient } from '../duc/client.config';
interface GetRolesPermissionsName {
@@ -9,17 +9,22 @@ import {
Headers,
UseFilters,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { ApiHeaders, ApiTags } from '@nestjs/swagger';
import { TermsOfUseAcceptRequest } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages';
import { TermsOfUseClientService } from './termsOfUse.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { GrpcToHttpExceptionFilter } from '../../error/grpc-to-http-exception.filter';
import { RequestUser, User } from '../../authentication/user.decorator';
import { RequestUser, User } from '../../decorators/user.decorator';
import { Metadata } from '@grpc/grpc-js';
import { Language } from 'src/decorators/language.decorator';
import { LanguageEnum } from 'src/utils/languages.enum';
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
@ApiInternalOnlyController()
@ApiTags('TermsOfUse')
@ApiHeaders([{ name: 'dadosfera-lang', enum: LanguageEnum, required: false }])
@UseFilters(new GrpcToHttpExceptionFilter())
@Controller('terms-of-use')
export class TermsOfUseController {
@@ -36,7 +41,7 @@ export class TermsOfUseController {
@Get('token')
async getToken(
@User({ required: true }) user: RequestUser,
@Headers('Dadosfera-Lang') language: string,
@Language() language: LanguageEnum,
) {
this.logger.info('/terms-of-use - get token');
const metadata = new Metadata();
@@ -12,15 +12,17 @@ import { ApiTags } from '@nestjs/swagger';
import { TransformationsClientService } from './client.service';
import { IIdRequest } from './interfaces';
import {
AuthenticateCondition,
Authenticated,
RequireSomePermission,
} from 'src/authentication/authentication.decorator';
} from 'src/decorators/authentication.decorator';
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
import { TransformationsService } from './transformations.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { RequestUser, User } from 'src/decorators/user.decorator';
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
const pipelinePermissions = PERMISSIONS_GROUPS.PIPELINE.permissions;
@ApiInternalOnlyController()
@ApiTags('Transformations')
@Controller('transformations')
@Authenticated()
+26 -29
View File
@@ -1,9 +1,9 @@
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import {
Body,
Controller,
Delete,
Get,
Headers,
HttpCode,
HttpStatus,
Inject,
@@ -16,18 +16,22 @@ import {
} from '@nestjs/common';
import {
ApiCreatedResponse,
ApiHeader,
ApiHeaders,
ApiOkResponse,
ApiTags,
} from '@nestjs/swagger';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import {
Authenticated,
RequireAllPermissions,
} from 'src/authentication/authentication.decorator';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import { RequestUser, User } from 'src/authentication/user.decorator';
} from 'src/decorators/authentication.decorator';
import { Language } from 'src/decorators/language.decorator';
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
import { RequestUser, User } from 'src/decorators/user.decorator';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
import ErrorBuilder from 'src/utils/ErrorBuilder';
import ErrorCodes from 'src/utils/errorCodes';
import { LanguageEnum } from 'src/utils/languages.enum';
import {
AssignRoleToUserReq,
@@ -40,26 +44,19 @@ import {
GetAllHierarchiesRes,
GetAllJobTitlesRes,
GetAllUsersByCustomerIdRes,
IUserByCustomer,
SetUserRolesReq,
SetUserRolesRes,
UnassignRoleToUserReq,
UpdateUserReq,
UpdateUserRes,
IUserByCustomer,
} from './dtos/entities';
import { UsersService } from './users.service';
import ErrorBuilder from 'src/utils/ErrorBuilder';
import ErrorCodes from 'src/utils/errorCodes';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
@ApiInternalOnlyController()
@ApiTags('Users')
@Controller('users')
@ApiHeader({
name: 'dadosfera-lang',
enum: LanguageEnum,
required: false,
description: 'Defaults to pt-br',
})
@ApiHeaders([{ name: 'dadosfera-lang', enum: LanguageEnum, required: false }])
@Authenticated()
@UseFilters(GrpcToHttpExceptionFilter)
export class UsersController {
@@ -76,7 +73,7 @@ export class UsersController {
@Get()
async getAllUsersByCustomerId(
@User() user: RequestUser,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
): Promise<GetAllUsersByCustomerIdRes> {
this.logger.info('getAllUsersByCustomerId', { user });
this.userService.setLanguage(language);
@@ -88,7 +85,7 @@ export class UsersController {
@ApiOkResponse({ type: GetAllHierarchiesRes })
async getAllHierarchies(
@User() user: RequestUser,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
): Promise<GetAllHierarchiesRes> {
this.logger.info('getAllHierarchies', { user });
this.userService.setLanguage(language);
@@ -100,7 +97,7 @@ export class UsersController {
@ApiOkResponse({ type: GetAllDepartmentsRes })
async getAllDepartments(
@User() user: RequestUser,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
): Promise<GetAllDepartmentsRes> {
this.logger.info('getAllHierarchies', { user });
this.userService.setLanguage(language);
@@ -112,7 +109,7 @@ export class UsersController {
@ApiOkResponse({ type: GetAllDepartmentsRes })
async getAllJobTitles(
@User() user: RequestUser,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
): Promise<GetAllJobTitlesRes> {
this.logger.info('getAllHierarchies', { user });
this.userService.setLanguage(language);
@@ -126,7 +123,7 @@ export class UsersController {
async findOneById(
@User() user: RequestUser,
@Param('id') id: string,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('findOneById', { user });
this.userService.setLanguage(language);
@@ -147,7 +144,7 @@ export class UsersController {
async createUser(
@User() user: RequestUser,
@Body() body: CreateUserReq,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
const metadata = PackTheMetadata({
access_token: user.access_token,
@@ -165,7 +162,7 @@ export class UsersController {
async batchCreateUser(
@User() user: RequestUser,
@Body() body: BatchCreateUserReq,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('batchCreateUser', { user });
this.userService.setLanguage(language);
@@ -184,7 +181,7 @@ export class UsersController {
async resendInvite(
@User() user: RequestUser,
@Param('id') id: string,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('resendInvite', { user });
this.userService.setLanguage(language);
@@ -200,7 +197,7 @@ export class UsersController {
async unassignRoleToUser(
@User() user: RequestUser,
@Query() request: UnassignRoleToUserReq,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('unassignRoleToUser', { user });
this.userService.setLanguage(language);
@@ -213,7 +210,7 @@ export class UsersController {
async deleteUser(
@User() user: RequestUser,
@Param('id') id: string,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('deleteUser', { user });
this.userService.setLanguage(language);
@@ -226,7 +223,7 @@ export class UsersController {
async setUserRoles(
@User() user: RequestUser,
@Body() body: SetUserRolesReq,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('createUser', { user });
this.userService.setLanguage(language);
@@ -238,7 +235,7 @@ export class UsersController {
async assignRoleToUser(
@User() user: RequestUser,
@Body() body: AssignRoleToUserReq,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('assignRoleToUser', { user });
this.userService.setLanguage(language);
@@ -252,7 +249,7 @@ export class UsersController {
@User() user: RequestUser,
@Body() body: UpdateUserReq,
@Param('id') id: string,
@Headers('dadosfera-lang') language,
@Language() language: LanguageEnum,
) {
this.logger.info('updateUser', { user });
this.userService.setLanguage(language);
+8
View File
@@ -119,6 +119,14 @@ export function EnrichErrorCode(code: string) {
code,
};
case ErrorCodes.AUTH.INVALID_REFRESH_TOKEN:
return {
statusCode: HttpStatus.UNAUTHORIZED,
error: 'Acesso expirado!',
message: 'Seu acesso expirou, favor fazer login novamente.',
code,
};
case ErrorCodes.AUTH.FORBIDDEN:
return {
statusCode: HttpStatus.FORBIDDEN,
+1
View File
@@ -1,5 +1,6 @@
export const AUTH = {
UNAUTHORIZED: 'AUTH.UNAUTHORIZED',
INVALID_REFRESH_TOKEN: 'AUTH.INVALID_REFRESH_TOKEN',
FORBIDDEN: 'AUTH.FORBIDDEN',
WRONG_CREDENTIALS: 'AUTH.WRONG_CREDENTIALS',
WRONG_PASSWORD_CONFIRMATION: 'AUTH.WRONG_PASSWORD_CONFIRMATION',