Compare commits

...
32 Commits
Author SHA1 Message Date
Gabriel Amorim f46b1b62db Merge pull request #220 from dadosfera/feat/new-customer-monitoring
FEAT: new customer monitoring dashboard
2024-06-28 16:37:38 -03:00
Gabriel Rosa 8b6cd8a88e FEAT: customer monitoring dashboard 2024-06-21 09:21:27 -03:00
Gabriel Rosa 0c333b476a FEAT: new customer monitoring 2024-06-20 10:50:07 -03:00
Gabriel Amorim c416a2cb97 Merge pull request #219 from dadosfera/feat/pipeline-monitoring-dashboard
Feat: pipeline monitoring dashboard
2024-05-06 16:52:26 -03:00
Gabriel Rosa d03021fc9d new protospack release 2024-05-06 15:28:26 -03:00
Gabriel Rosa 574cf48726 FIX: npm audit fix 2024-05-02 12:11:46 -03:00
Gabriel Rosa 7cef404acf FEAT: get monitoring dashboard url 2024-05-02 12:11:35 -03:00
Gabriel Rosa 3c32c3c7d4 CI: Update actions/checkout to v4 2024-04-22 14:57:01 -03:00
Gabriel Amorim d44531b963 Merge pull request #218 from dadosfera/feat/choose-deploy-dockerhub
[ TECN-6603 ] CI: update action versions and choose wether to upload to dockerhub
2024-01-10 10:05:47 -03:00
Gabriel Rosa 36c80b480e CI: update action versions and choose wether to upload to dockerhub 2024-01-04 14:58:47 -03:00
Rafael Santana eeef97679c Merge pull request #217 from dadosfera/ci/dockerhub
UPDATE: updating maestro to deploy image to dockerhub
2023-11-26 21:18:32 -03:00
Rafael Santana c789dae3f6 UPDATE: updating maestro to deploy image to dockerhub 2023-11-26 20:50:10 -03:00
Allan Sene 216defb76f Updated file 2023-06-11 22:43:43 -03:00
Gabriel Amorim 0970c748e0 Merge pull request #216 from dadosfera/feat/generate-token
Feat: generate token
2023-05-17 10:03:00 -03:00
Gabriel Amorim aabd741cad FEAT: new Customer Get Token Route 2023-05-16 09:05:05 -03:00
Gabriel Amorim 950c6414b6 FIX: update to new nestjs version 2023-05-12 08:28:33 -03:00
Gabriel Amorim d1149a4d52 Merge pull request #215 from dadosfera/alpha
FIX: permissions.enum.ts
2023-05-08 16:02:33 -03:00
Gabriel Amorim 4c6f4bfd84 FIX: renamed reference to intelligence permission 2023-05-08 15:56:52 -03:00
Gabriel Amorim 9caf3dc67f FIX: renamed reference to intelligence permission 2023-05-08 15:48:46 -03:00
Beatriz Antunes 635c4da48c Update permissions.enum.ts 2023-05-08 15:44:05 -03:00
Gabriel Amorim 44bb205483 Merge pull request #214 from dadosfera/fix/get-links-permission
FIX: remove permission check to get customer links
2023-05-05 13:52:38 -03:00
Gabriel Amorim edb4622684 FIX: remove permission to get customer links 2023-05-05 12:13:55 -03:00
Victor Radael abb46d78da Merge pull request #212 from dadosfera/feature/customer-links
SOLENG-1481 - Customer links endpoints
2023-04-17 17:01:41 -03:00
Victor Radael 04fdc0368a Merge pull request #213 from dadosfera/update/hubspot-tables
UPDATE: HubspotTables
2023-04-15 14:49:47 -03:00
Victor Radael 50d76622c5 UPDATE: HubspotTables 2023-04-15 14:45:18 -03:00
Victor Radael 238f56cb76 Merge branch 'SOLENG-1736' into feature/customer-links 2023-04-14 14:44:57 -03:00
Victor Radael e721d6f5f5 Merge branch 'main' into feature/customer-links 2023-04-14 13:30:57 -03:00
Victor Radael 44df13e820 UPDATE: Att protospack-v2 version 2023-04-14 13:13:47 -03:00
Colombo bf5b3484a1 FEAT: add controller method interfaces 2023-04-11 20:39:47 -03:00
Colombo eb1e248d4b FEAT: add customer (links) endpoint 2023-04-11 17:04:40 -03:00
Colombo 0827414051 FEAT: add new dto property 2023-04-10 19:36:36 -03:00
Colombo 081986607b CHORE: change protospack package to beta 2023-04-06 17:07:23 -03:00
28 changed files with 4663 additions and 3915 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
'prettier',
],
root: true,
env: {
+29 -7
View File
@@ -13,6 +13,11 @@ on:
- stg
- stg2
- prd
push_to_dockerhub:
description: "Push image to Dockerhub?"
required: true
type: boolean
default: false
jobs:
extract_environment:
@@ -39,15 +44,15 @@ jobs:
new_release_version: ${{ (steps.semantic.outputs.new_release_published == 'true' && steps.semantic.outputs.new_release_version) || (github.event_name == 'workflow_dispatch' && '0.0.0') }}
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- if: github.event_name != 'workflow_dispatch'
name: Semantic Release
uses: cycjimmy/semantic-release-action@v3
uses: cycjimmy/semantic-release-action@v4
id: semantic
with:
extra_plugins: |
conventional-changelog-eslint
conventional-changelog-eslint@4.0.0
branches: |
[
'main'
@@ -76,7 +81,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Update Pip
run: |
@@ -95,14 +100,14 @@ jobs:
python3 -m pip install awsebcli --upgrade
- name: Configure AWS Region
uses: aws-actions/configure-aws-credentials@v1-node16
uses: aws-actions/configure-aws-credentials@v4
id: aws
with:
aws-region: us-east-1
- name: Login to AWS ECR
id: login_ecr
uses: aws-actions/amazon-ecr-login@v1
uses: aws-actions/amazon-ecr-login@v2
- name: Build, Tag, and Push Image to AWS ECR
env:
@@ -113,6 +118,23 @@ jobs:
docker-compose -f build.docker-compose.yml build
docker-compose -f build.docker-compose.yml push
- name: Login to Docker Hub
if: ${{inputs.push_to_dockerhub}}
uses: docker/login-action@v2
with:
username: dadosfera
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Build, Tag, and Push Image to Dockerhub
if: ${{inputs.push_to_dockerhub}}
env:
ENV: ${{ needs.extract_environment.outputs.environment }}
IMAGE_TAG: ${{ needs.semantic_release.outputs.new_release_version }}
ACCOUNT_ID: ${{ steps.aws.outputs.aws-account-id }}
run: |
docker-compose -f build.docker-compose.dockerhub.yml build
docker-compose -f build.docker-compose.dockerhub.yml push
- name: Create ZIP file to Deploy AWS Beanstalk
env:
ENV: ${{ needs.extract_environment.outputs.environment }}
@@ -146,7 +168,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Extract Docs BlockId and PageId
env:
+1 -1
View File
@@ -1 +1 @@
18.3.0
18.10.0
+1
View File
@@ -12,6 +12,7 @@
"start:debug"
],
"runtimeExecutable": "npm",
"runtimeVersion": "18.10.0",
"skipFiles": [
"<node_internals>/**"
],
+3 -3
View File
@@ -1,5 +1,5 @@
# install all dependencies
FROM node:18.3.0-alpine3.15 as packages
FROM node:18.10-alpine as packages
WORKDIR /app
COPY package.json package-lock.json ./
RUN apk add --no-cache aws-cli \
@@ -7,12 +7,12 @@ RUN apk add --no-cache aws-cli \
&& npm install
# unit test specific build
FROM node:18.3.0-alpine3.15 as test
FROM node:18.10-alpine as test
WORKDIR /app
COPY --from=packages /app/node_modules ./node_modules
COPY . ./
FROM node:18.3.0-alpine3.15
FROM node:18.10-alpine
WORKDIR /app
COPY . /app/
COPY --from=packages /app/node_modules ./node_modules
+10
View File
@@ -0,0 +1,10 @@
LICENSE
Copyright (C) 2023 Dadosfera
All rights reserved.
This software and related documentation are provided under a license agreement containing restrictions on use and disclosure and are protected by intellectual property laws. Except as expressly permitted in your license agreement or allowed by law, you may not use, copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform, publish, or display any part, in any form, or by any means.
Reverse engineering, disassembly, or decompilation of this software, unless required by law for interoperability, is prohibited.
If you have any questions about this, please contact Dadosfera.ai at legal@dadosfera.ai
+1 -1
View File
@@ -12,7 +12,7 @@ These instructions will allow you to get a working copy of the project on your l
### 📋 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)
- [NodeJS v18.10.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
+5
View File
@@ -0,0 +1,5 @@
version: "3.8"
services:
maestro:
build: .
image: dadosfera/maestro_${ENV}:${IMAGE_TAG}
+29
View File
@@ -0,0 +1,29 @@
version: "3.8"
services:
maestro:
image: dadosfera/maestro_${ENV}:${IMAGE_TAG}
container_name: maestro
restart: always
ports:
- 3333:3333
env_file:
- .env
node_exporter:
image: ${NODE_EXPORTER_URL}
container_name: node_exporter
restart: always
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
- /run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket:ro
command:
- '--path.procfs=/host/proc'
- '--path.rootfs=/rootfs'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
- '--collector.systemd'
- '--collector.processes'
network_mode: host
pid: host
+48 -2
View File
@@ -490,6 +490,45 @@
]
}
},
"/pipelinesV2/monitoring-dashboard": {
"get": {
"operationId": "PipelinesController_getMonitoringDashboard",
"parameters": [
{
"name": "dadosfera-lang",
"in": "header",
"required": false,
"schema": {
"enum": [
"pt-br",
"en-us"
],
"type": "string"
}
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"PipelinesV2"
],
"security": [
{
"access-token": []
}
]
}
},
"/pipelinesV2": {
"post": {
"operationId": "PipelinesController_create",
@@ -1752,7 +1791,7 @@
}
},
"info": {
"title": "Maestro - feat/trigger-catalog-task",
"title": "Maestro - feat/new-customer-monitoring",
"description": "This is the Maestro API",
"version": "1.0.0",
"contact": {}
@@ -1812,6 +1851,12 @@
},
"scheduleLimit": {
"type": "string"
},
"links": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
@@ -1819,7 +1864,8 @@
"id",
"name",
"tier",
"scheduleLimit"
"scheduleLimit",
"links"
]
},
"AuthUser": {
+199 -2
View File
@@ -2663,6 +2663,45 @@
]
}
},
"/pipelinesV2/monitoring-dashboard": {
"get": {
"operationId": "PipelinesController_getMonitoringDashboard",
"parameters": [
{
"name": "dadosfera-lang",
"in": "header",
"required": false,
"schema": {
"enum": [
"pt-br",
"en-us"
],
"type": "string"
}
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"PipelinesV2"
],
"security": [
{
"access-token": []
}
]
}
},
"/pipelinesV2": {
"post": {
"operationId": "PipelinesController_create",
@@ -4959,6 +4998,129 @@
]
}
},
"/customers/{id}/links": {
"get": {
"operationId": "CustomersController_getCustomerLinks",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CustomerLinksResponse"
}
}
}
}
},
"tags": [
"Customers"
],
"security": [
{
"access-token": []
}
]
},
"put": {
"operationId": "CustomersController_setCustomerLinks",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CustomerDto"
}
}
}
},
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"Customers"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
]
}
},
"/customers/token": {
"get": {
"operationId": "CustomersController_getCustomerToken",
"parameters": [
{
"name": "exp",
"required": true,
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
},
"tags": [
"Customers"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
]
}
},
"/customers/monitoring-dashboard": {
"get": {
"operationId": "CustomersController_getCustomerMonitoringDashboard",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Customers"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
]
}
},
"/health": {
"get": {
"operationId": "HealthController_check",
@@ -4975,7 +5137,7 @@
}
},
"info": {
"title": "Maestro - feat/trigger-catalog-task",
"title": "Maestro - feat/new-customer-monitoring",
"description": "This is the Maestro API",
"version": "1.0.0",
"contact": {}
@@ -5030,6 +5192,12 @@
},
"scheduleLimit": {
"type": "string"
},
"links": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
@@ -5037,7 +5205,8 @@
"id",
"name",
"tier",
"scheduleLimit"
"scheduleLimit",
"links"
]
},
"AuthUser": {
@@ -7702,6 +7871,34 @@
"content",
"tags"
]
},
"CustomerLinksResponse": {
"type": "object",
"properties": {
"links": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"links"
]
},
"CustomerDto": {
"type": "object",
"properties": {
"links": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"links"
]
}
}
}
+3945 -3858
View File
File diff suppressed because it is too large Load Diff
+17 -18
View File
@@ -6,7 +6,7 @@
"private": true,
"license": "UNLICENSED",
"engines": {
"node": "18.3.0"
"node": "18.10.0"
},
"scripts": {
"preinstall": "aws codeartifact login --tool npm --namespace @dadosfera --repository dadosfera-npm --domain dadosfera --domain-owner 611330257153 --region us-east-1",
@@ -29,21 +29,23 @@
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.112.0",
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
"@dadosfera/protospack-v2": "3.30.0",
"@dadosfera/protospack-v2": "3.33.0",
"@grpc/grpc-js": "^1.6.7",
"@grpc/proto-loader": "^0.6.13",
"@nestjs/common": "^8.4.7",
"@nestjs/config": "^1.2.1",
"@nestjs/core": "^8.4.7",
"@nestjs/mapped-types": "*",
"@nestjs/microservices": "^8.4.7",
"@nestjs/passport": "^8.2.2",
"@nestjs/platform-express": "^8.4.7",
"@nestjs/schedule": "^1.1.0",
"@nestjs/swagger": "^5.2.1",
"@nestjs/cli": "^9.4.2",
"@nestjs/common": "^9.4.0",
"@nestjs/config": "^2.3.1",
"@nestjs/core": "^9.4.0",
"@nestjs/mapped-types": "^1.2.2",
"@nestjs/microservices": "^9.4.0",
"@nestjs/passport": "^9.0.3",
"@nestjs/platform-express": "^9.4.0",
"@nestjs/schematics": "^9.1.0",
"@nestjs/swagger": "^6.3.0",
"@nestjs/testing": "^9.4.0",
"axios": "^0.27.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"class-validator": "^0.14.0",
"cron-parser": "^4.4.0",
"dotenv": "^14.3.2",
"elastic-apm-node": "^3.36.0",
@@ -51,6 +53,7 @@
"jsonwebtoken": "^9.0.0",
"jwk-to-pem": "^2.0.5",
"mixpanel": "^0.17.0",
"ms": "^3.0.0-canary.1",
"passport": "^0.6.0",
"passport-facebook": "^3.0.0",
"passport-forcedotcom": "^0.2.0",
@@ -67,9 +70,6 @@
"multer": "1.4.5-lts.1"
},
"devDependencies": {
"@nestjs/cli": "^8.2.8",
"@nestjs/schematics": "^8.0.11",
"@nestjs/testing": "^8.4.7",
"@types/express": "^4.17.13",
"@types/jest": "27.0.2",
"@types/jsonwebtoken": "^8.5.8",
@@ -80,11 +80,10 @@
"@types/passport-google-oauth20": "^2.0.11",
"@types/passport-oauth2": "^1.4.11",
"@types/supertest": "^2.0.12",
"@typescript-eslint/eslint-plugin": "^5.29.0",
"@typescript-eslint/parser": "^5.29.0",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"eslint": "^8.18.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^27.5.1",
"nock": "^13.2.7",
"prettier": "^2.7.1",
+2
View File
@@ -25,6 +25,7 @@ import { ConfigModule } from '@nestjs/config';
import { PipelinesV2Module } from './modules/pipelinesV2/pipelines.module';
import { ProductboardModule } from './modules/productboard/productboard.module';
import { MixpanelModule } from './modules/mixpanel/mixpanel.module';
import { CustomersModule } from './modules/customers/customers.module';
@Module({
controllers: [],
@@ -56,6 +57,7 @@ import { MixpanelModule } from './modules/mixpanel/mixpanel.module';
OauthModule,
ProductboardModule,
MixpanelModule,
CustomersModule,
//Always leave HealthModule last, so it is on the bottom of swagger
HealthModule,
],
@@ -44,7 +44,7 @@ class NoClassAuthController {
@Get('has-all-permissions')
@RequireAllPermissions(
PERMISSIONS_GROUPS.ZENDESK.permissions.OPEN,
PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE,
PERMISSIONS_GROUPS.DATAVIZ.permissions.METABASE,
)
async hasAllPermissions(@Body() body) {
return { body };
@@ -53,7 +53,7 @@ class NoClassAuthController {
@Get('has-some-permission')
@RequireSomePermission(
PERMISSIONS_GROUPS.ZENDESK.permissions.OPEN,
PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE,
PERMISSIONS_GROUPS.DATAVIZ.permissions.METABASE,
)
async hasSomePermission(@Body() body) {
return { body };
@@ -62,7 +62,7 @@ class NoClassAuthController {
@Controller('class-auth-condition')
@AuthenticateCondition((req) => req.get('x-on-class') === 'ok')
@RequireSomePermission(PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE)
@RequireSomePermission(PERMISSIONS_GROUPS.DATAVIZ.permissions.METABASE)
class ClassAuthConditionController {
@Get('body')
async getBody(@Body() body) {
@@ -444,13 +444,13 @@ describe('authentication.guard', () => {
NoClassAuthTest(tokenZ, ['zendesk']);
ClassAuthConditionTest(tokenZ, ['zendesk']);
const tokenM = CreateToken([PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE]);
const tokenM = CreateToken([PERMISSIONS_GROUPS.DATAVIZ.permissions.METABASE]);
NoClassAuthTest(tokenM, ['metabase']);
ClassAuthConditionTest(tokenM, ['metabase']);
const tokenZM = CreateToken([
PERMISSIONS_GROUPS.ZENDESK.permissions.OPEN,
PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE,
PERMISSIONS_GROUPS.DATAVIZ.permissions.METABASE,
]);
NoClassAuthTest(tokenZM, ['zendesk', 'metabase']);
ClassAuthConditionTest(tokenZM, ['zendesk', 'metabase']);
+41 -13
View File
@@ -55,9 +55,18 @@ export const PERMISSIONS_GROUPS = {
'es-es': '',
},
},
GENERATE_TOKEN: {
seqid: 46,
claim: 'customer:generate-token',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Gerar Token de Acesso',
'en-us': 'Generate Acess Token',
'es-es': 'Gerar Token de Acceso',
},
},
},
},
PIPELINE: {
title: {
'pt-br': 'Coletar | Pipelines',
@@ -107,7 +116,6 @@ export const PERMISSIONS_GROUPS = {
},
},
},
CONNECTION: {
title: {
'pt-br': 'Coletar | Fontes de dados',
@@ -147,7 +155,6 @@ export const PERMISSIONS_GROUPS = {
},
},
},
NETWORK_CONFIG: {
title: {
'pt-br': 'Coletar | Redes',
@@ -177,7 +184,6 @@ export const PERMISSIONS_GROUPS = {
// },
},
},
OUTPUT: {
title: {
'pt-br': 'Output',
@@ -227,7 +233,6 @@ export const PERMISSIONS_GROUPS = {
},
},
},
TRANSFORMATIONS: {
title: {
'pt-br': 'Micro-transformações',
@@ -277,7 +282,6 @@ export const PERMISSIONS_GROUPS = {
},
},
},
CATALOG: {
title: {
'pt-br': 'Explorar | Catálogo',
@@ -358,7 +362,6 @@ export const PERMISSIONS_GROUPS = {
},
},
},
CONNECTORS: {
title: {
'pt-br': 'Conectores',
@@ -408,7 +411,6 @@ export const PERMISSIONS_GROUPS = {
},
},
},
SNOWFLAKE: {
title: {
'pt-br': 'Explorar | Consolidar',
@@ -428,7 +430,6 @@ export const PERMISSIONS_GROUPS = {
},
},
},
ZENDESK: {
title: {
'pt-br': 'Zendesk',
@@ -448,8 +449,7 @@ export const PERMISSIONS_GROUPS = {
},
},
},
ANALYZE: {
DATAVIZ: {
title: {
'pt-br': 'Analisar | Visualização',
'en-us': 'Analyze | Visualization',
@@ -466,6 +466,15 @@ export const PERMISSIONS_GROUPS = {
'es-es': 'Acceso Metabase',
},
},
},
},
INTELLIGENCE: {
title: {
'pt-br': 'Analisar | Inteligência',
'en-us': 'Analyze | Intelligence',
'es-es': 'Analizar | Inteligencia',
},
permissions: {
INTELLIGENCE: {
seqid: 31,
claim: 'intelligence:open',
@@ -478,7 +487,6 @@ export const PERMISSIONS_GROUPS = {
},
},
},
MODULES: {
title: {
'pt-br': 'Módulos da Dadosfera',
@@ -575,6 +583,25 @@ export const PERMISSIONS_GROUPS = {
},
},
},
CUSTOMER: {
title: {
'pt-br': 'Organização',
'en-us': 'Organization',
'es-es': 'Organización',
},
permissions: {
MONITORING_DASHBOARD: {
seqid: 47,
claim: 'customer:monitoring-dashboard',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Ver o dashboard de monitoramento',
'en-us': 'View the monitoring dashboard',
'es-es': 'Ver el dashboard de monitoreo',
},
},
},
},
};
export interface DadosferaModule {
name: string;
@@ -587,7 +614,8 @@ export const DADOSFERA_MODULES: Array<DadosferaModule> = [
name: 'Intelligence Module',
description: 'Orchest Module',
key: 'intelligence',
permissionSeqId: PERMISSIONS_GROUPS.ANALYZE.permissions.INTELLIGENCE.seqid,
permissionSeqId:
PERMISSIONS_GROUPS.INTELLIGENCE.permissions.INTELLIGENCE.seqid,
},
{
name: 'Proccessing Module',
+1 -1
View File
@@ -46,7 +46,7 @@ describe('user.decorator', () => {
const fakeUserPayload = {
user_id: 'd50d33c7-6c2b-463c-861f-e21667e7c125',
username: 'super.admin',
permissions: [PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE].map(
permissions: [PERMISSIONS_GROUPS.DATAVIZ.permissions.METABASE].map(
({ seqid }) => seqid,
),
customer_id: '9d18e8ae-24b9-41a3-9e8f-a25ce57555b11',
+3 -1
View File
@@ -164,6 +164,8 @@ export class AuthClientService implements OnModuleInit {
async oauthSignIn(data: { username: string; token: string }) {
const { username, token } = data;
return lastValueFrom(this.authService.AuthOauthSignIn({ token, username }));
return lastValueFrom(
this.authService.AuthOauthSignIn({ token, username, refreshToken: '' }),
);
}
}
+3
View File
@@ -1,3 +1,4 @@
import { Link } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/entities';
import {
AuthSignInRequest,
AuthSignInResponse,
@@ -74,6 +75,8 @@ export class AuthCustomer {
tier: string;
@ApiProperty()
scheduleLimit: string;
@ApiProperty()
links: Link[];
}
export class AuthSignInReq implements AuthSignInRequest {
@@ -0,0 +1,88 @@
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { IdResponse } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages';
import {
Body,
Controller,
Get,
Inject,
Param,
Put,
Query,
UseFilters,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import {
Authenticated,
RequireAllPermissions,
} from 'src/decorators/authentication.decorator';
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
import { CustomersService } from './customers.service';
import { CustomerDto, CustomerLinksResponse } from './dtos/customers';
import { RequestUser, User } from 'src/decorators/user.decorator';
import type { StringValue } from 'ms';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
@ApiInternalOnlyController()
@ApiTags('Customers')
@Controller('customers')
@Authenticated()
@UseFilters(GrpcToHttpExceptionFilter)
export class CustomersController {
logger: DadosferaLogger;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
private customersService: CustomersService,
) {
this.logger = dadosferaLogger.logger;
}
@Get(':id/links')
async getCustomerLinks(@Param('id') id): Promise<CustomerLinksResponse> {
this.logger.info('getCustomerLinks', { id });
const links = await this.customersService.getLinks(id);
return { links };
}
@Put(':id/links')
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
setCustomerLinks(
@Body() body: CustomerDto,
@Param('id') id,
): Promise<IdResponse> {
const { links } = body;
this.logger.info('setCustomerLinks', { id, links });
return this.customersService.setLinks(id, links);
}
@Get('token')
@RequireAllPermissions(PERMISSIONS_GROUPS.AUTH.permissions.GENERATE_TOKEN)
async getCustomerToken(
@Query('exp') exp: StringValue,
@User() user: RequestUser,
): Promise<string> {
this.logger.info('getCustomerToken', { exp, user });
const data = {
customerId: user.customer_id,
userId: user.user_id,
customerName: user.customer_name,
};
return this.customersService.generateToken(exp, data);
}
@Get('monitoring-dashboard')
@RequireAllPermissions(
PERMISSIONS_GROUPS.CUSTOMER.permissions.MONITORING_DASHBOARD,
)
async getCustomerMonitoringDashboard(
@User() user: RequestUser,
): Promise<{ url: string }> {
this.logger.info('getCustomerMonitoringDashboard');
const metadata = PackTheMetadata(user);
return this.customersService.getMonitoringDashboardUrl(metadata);
}
}
+23
View File
@@ -0,0 +1,23 @@
import { Module } from '@nestjs/common';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { ClientsModule } from '@nestjs/microservices';
import { DucClient } from '../duc/client.config';
import { CustomersController } from './customers.controller';
import { CustomersService } from './customers.service';
import { PipelinesClientConfiguration } from '../pipelinesV2/pipelines-client';
const ducClient = new DucClient();
const piFactoryClient = new PipelinesClientConfiguration();
@Module({
imports: [
ClientsModule.register([
ducClient.providerOptions,
piFactoryClient.providerOptions,
]),
],
controllers: [CustomersController],
providers: [CustomersService, DadosferaLogger],
exports: [CustomersService],
})
export class CustomersModule {}
+154
View File
@@ -0,0 +1,154 @@
import {
OnModuleInit,
Inject,
Injectable,
HttpException,
HttpStatus,
InternalServerErrorException,
} from '@nestjs/common';
import { firstValueFrom, lastValueFrom } from 'rxjs';
import { Link } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/entities';
import { DucClient } from '../duc/client.config';
import { ClientGrpc } from '@nestjs/microservices';
import { ProtoServices } from '@dadosfera/protospack-v2/dist/lib/Duc';
import { CustomerUpdateRequest } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages';
import { CustomersProtoService } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/write-service';
import ErrorCodes from 'src/utils/errorCodes';
import jwt from 'jsonwebtoken';
import {
GetSecretValueCommand,
SecretsManagerClient,
} from '@aws-sdk/client-secrets-manager';
import getEnv from 'src/utils/getEnv';
import { logger } from 'elastic-apm-node';
import {
ReadService,
ProtoServices as PipelineProtoServices,
} from '@dadosfera/protospack-v2/dist/lib/PipelineV2';
import { Metadata } from '@grpc/grpc-js';
import { PipelinesClientConfiguration } from '../pipelinesV2/pipelines-client';
// This function will accept any string, which may result in a bug.
@Injectable()
export class CustomersService implements OnModuleInit {
private customerService: CustomersProtoService;
private pipelineReadService: ReadService.PipelineV2ReadService;
constructor(
@Inject(DucClient.name) private readonly grpcClient: ClientGrpc,
@Inject(PipelinesClientConfiguration.name)
private readonly pipelinesGrpcClient: ClientGrpc,
) {}
onModuleInit() {
this.customerService = this.grpcClient.getService<CustomersProtoService>(
ProtoServices.CustomersProtoService,
);
this.pipelineReadService =
this.pipelinesGrpcClient.getService<ReadService.PipelineV2ReadService>(
PipelineProtoServices.PipelineV2ReadService,
);
}
async getLinks(customerId: string) {
try {
const result = await lastValueFrom(
this.customerService.CustomerFindOneById({ id: customerId }),
);
return result.customer?.links || [];
} catch (err) {
if (err.details === ErrorCodes.CUSTOMER.NOT_FOUND)
throw new HttpException(err.details, HttpStatus.NOT_FOUND);
throw err;
}
}
async setLinks(customerId: string, links: Link[]) {
if (!customerId || !links) {
throw new HttpException(null, HttpStatus.BAD_REQUEST);
}
try {
return await firstValueFrom(
this.customerService.CustomerUpdate({
id: customerId,
links,
} as CustomerUpdateRequest),
);
} catch (err) {
if (err.details === ErrorCodes.CUSTOMER.NOT_FOUND)
throw new HttpException(err.details, HttpStatus.NOT_FOUND);
else throw err;
}
}
async generateToken(
expiresIn = '30m',
data: { customerId: string; userId: string; customerName: string },
) {
const { customerId, userId: generatedById, customerName } = data;
const secretsManagerClient = new SecretsManagerClient({});
const getSecretComand = new GetSecretValueCommand({
SecretId: `${getEnv()}/${customerName}/jwt-signing-key`,
});
let private_key_pem;
await secretsManagerClient
.send(getSecretComand)
.then((res) => {
const secret = JSON.parse(res.SecretString);
private_key_pem = secret.private_key_pem;
})
.catch((err) => {
logger.error(err.stack);
throw new InternalServerErrorException(
'Error finding keys for customer',
);
});
let jwt_token;
try {
jwt_token = jwt.sign(
{
customerId,
generatedById,
},
private_key_pem,
{
algorithm: 'RS256',
expiresIn,
issuer: 'maestro',
},
);
} catch (err) {
logger.error(err.stack);
throw new InternalServerErrorException('Error generating token');
}
// const verify = jwt.verify(jwt_token, public_key_pem, {
// algorithms: ['RS256'],
// issuer: 'maestro',
// });
// const decoded = jwt.decode(jwt_token, { complete: true });
return jwt_token;
}
async getMonitoringDashboardUrl(metadata: Metadata) {
logger.info('CustomersService - getMonitoringDashboardUrl');
const res = await lastValueFrom(
this.pipelineReadService.PipelineV2GetDashboardUrl(
{
dashboard_id: '45',
exp: '15m',
metabase_customer_name: 'dadosferatech',
},
metadata,
),
);
logger.info('Done');
return res;
}
}
+12
View File
@@ -0,0 +1,12 @@
import { Link } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/entities';
import { ApiProperty } from '@nestjs/swagger';
export class CustomerDto {
@ApiProperty()
links: Link[];
}
export class CustomerLinksResponse {
@ApiProperty()
links: Link[];
}
-2
View File
@@ -5,7 +5,6 @@ import {
Inject,
Injectable,
} from '@nestjs/common';
import { Timeout } from '@nestjs/schedule';
import CronParser, { CronExpression } from 'cron-parser';
import { ClientGrpc } from '@nestjs/microservices';
import DadosferaLogger from '@dadosfera/dadosfera-logs/dist';
@@ -222,7 +221,6 @@ export class InputsService {
return lastValueFrom(this.inputWriteService.InputRemove(idRequest));
}
@Timeout(60000 * 10) // Timeout set for 10 minutes
async testConnection(data) {
try {
const testConnectionInputResponse =
@@ -14,6 +14,7 @@ import {
Patch,
HttpException,
BadRequestException,
CacheTTL,
} from '@nestjs/common';
import {
ApiCreatedResponse,
@@ -86,6 +87,18 @@ export class PipelinesController {
this.logger = dadosferaLogger.logger;
}
@Get('monitoring-dashboard')
async getMonitoringDashboard(@User() user: RequestUser) {
this.logger.info('PipelinesController - getMonitoringDashboard', { user });
const metadata = PackTheMetadata(user);
const response =
await this.pipelinesClientService.getMonitoringDashboardUrl(metadata);
return response;
}
@Post()
@ApiCreatedResponse({ type: IPipelineV2 })
async create(
@@ -321,4 +321,22 @@ export class PipelinesService implements OnModuleInit {
);
});
}
async getMonitoringDashboardUrl(metadata: Metadata) {
this.logger.info('PipelinesClientService - getMonitoringDashboardUrl');
const res = await lastValueFrom(
this.pipelineReadService.PipelineV2GetDashboardUrl(
{
dashboard_id: '83',
exp: '15m',
metabase_customer_name: 'dadosferatech',
},
metadata,
),
);
this.logger.info('Done');
return res;
}
}
+1
View File
@@ -39,6 +39,7 @@ export const CUSTOMER = {
INVALID_ID: 'CUSTOMER.INVALID_ID',
NOT_FOUND: 'CUSTOMER.NOT_FOUND',
ALREADY_EXISTS: 'CUSTOMER.ALREADY_EXISTS',
BAD_REQUEST: 'CUSTOMER.BAD_REQUEST',
};
const TERMS_OF_USE = {
UP_TO_DATE: 'TERMS_OF_USE.UP_TO_DATE',
+10
View File
@@ -0,0 +1,10 @@
const availableLocalEnvs: Array<typeof process.env.ENV> = ['stg', 'test'];
export default function getEnv(): typeof process.env.ENV {
if (process.env.ENV === 'local') {
if (availableLocalEnvs.includes(process.env.LOCAL_ENV))
return process.env.LOCAL_ENV;
return 'stg';
}
return process.env.ENV;
}