Compare commits

...
57 Commits
Author SHA1 Message Date
Victor Radael 23fe522cc1 Merge pull request #188 from dadosfera/feat/upload-csv
Feat/upload csv
2022-12-09 17:14:36 -03:00
Victor Radael ea8dfa2e12 FEAT: Deploy Merge 2022-12-09 17:10:50 -03:00
Anderson Feitosa 9477223bec Merge pull request #187 from dadosfera/hotfix/semantic-release
hotfix/semantic-release
2022-12-09 11:32:54 -03:00
Anderson Feitosa 519070bd82 FIX: change docs 2022-12-09 11:32:23 -03:00
Anderson Feitosa 99fc7e8a96 Merge pull request #186 from dadosfera/feature/verify-refresh-token
feature/verify-refresh-token
2022-12-09 11:25:44 -03:00
Anderson Feitosa 9fedd4bb80 Merge branch 'main' into feature/verify-refresh-token 2022-12-09 11:19:45 -03:00
Victor Radael ff5e735121 FEAT: Find a file pipeline 2022-12-09 08:29:27 -03:00
Gabriel Amorim c450d16445 Merge pull request #184 from dadosfera/feat/embed-data-asset
Feat/embed data asset
2022-12-07 16:26:49 -03:00
Gabriel Rosa 3acda53e8a npm audit fix 2022-12-07 16:17:21 -03:00
Gabriel Rosa a0f21b763a new protospack version 2022-12-07 16:14:57 -03:00
Gabriel Amorim c83d8ab1b2 Merge branch 'main' into feat/embed-data-asset 2022-12-07 15:48:04 -03:00
Gabriel Amorim 610d08fa11 Merge pull request #185 from dadosfera/fix/data-asset-docs
FIX: removed split on id on catalog POST docs route
2022-12-07 14:55:49 -03:00
Gabriel Rosa 21f68b466d FIX: removed split on id on catalog POST docs route 2022-12-07 14:49:58 -03:00
Anderson Feitosa 18b5dc980c FEAT: add verify access token path 2022-12-07 12:58:58 -03:00
Gabriel Rosa 6fdd73c58c removing treatment of undefined embed field 2022-12-07 08:36:21 -03:00
Victor Radael eaddca7eb3 FEAT: Creat a Upload CSV Pipeline 2022-12-06 18:06:32 -03:00
Gabriel Rosa 1c0377a4fa FIX: treat empty embed on update 2022-12-06 11:04:18 -03:00
Gabriel Rosa 64816e5578 FIX: treat empty embed 2022-12-06 10:07:30 -03:00
Gabriel Rosa f9064417ce docsfera.json 2022-12-06 09:11:32 -03:00
Gabriel Rosa 0b8bf9a535 Merge branch 'main' into feat/embed-data-asset 2022-12-06 09:09:43 -03:00
Victor Radael 98e865c48a FEAT: Create Upload CSV Pipeline 2022-12-05 20:35:35 -03:00
Victor Radael 2c207f068c FEAT: Create Upload CSV Pipeline 2022-12-05 20:34:04 -03:00
Gabriel Amorim 6f1e5d08c9 Merge pull request #182 from dadosfera/feat/view-table
Feat/view table
2022-12-05 18:15:05 -03:00
Gabriel Rosa b611c1eb9d Merge branch 'main' into feat/view-table 2022-12-05 18:13:36 -03:00
Gabriel Amorim d7062efc60 Merge pull request #183 from dadosfera/feat/rest-api
Feat/rest api
2022-12-05 15:22:05 -03:00
Gabriel Rosa 4a3dd98977 Merge branch 'main' into feat/rest-api 2022-12-05 13:58:22 -03:00
Gabriel Rosa 81d93ff103 FEAT: embed data asset 2022-12-05 13:22:23 -03:00
Victor Radael ea7ec52e1f FEAT: upload 50MB file 2022-12-01 18:55:48 -03:00
Victor Radael be228b7425 FEAT: upload 50MB file 2022-12-01 17:50:44 -03:00
Victor Radael 90edc6552a FEAT: Upload CSV 2022-12-01 14:57:44 -03:00
Victor Radael ed96609011 FEAT: Upload CSV 2022-12-01 14:56:41 -03:00
Gabriel Rosa d55563f62f FIX: removed split on data_asset id on DELETE route 2022-11-30 16:21:36 -03:00
Gabriel Rosa ba9575c53e FIX: return only owner username 2022-11-30 15:43:30 -03:00
Gabriel Rosa d88b154d43 FIX: new id strategy for data assets 2022-11-30 15:29:31 -03:00
Gabriel Amorim 06f4260b61 Merge pull request #181 from dadosfera/stg2
Stg2
2022-11-29 19:16:48 -03:00
Gabriel Rosa 64717c8d92 Merge branch 'main' into stg2 2022-11-29 14:41:11 -03:00
Anderson Feitosa e6e66c77e1 Merge pull request #180 from dadosfera/feature/update-pipeline-cron
feature/update-pipeline-cron
2022-11-29 14:04:31 -03:00
Gabriel Rosa 131e82b4c5 FIX: connection details improvements 2022-11-29 09:47:19 -03:00
Gabriel Rosa 32d37ecadf Removed dev deploy environment 2022-11-29 08:42:26 -03:00
Gabriel Rosa 4d667acb86 removed unused import 2022-11-25 18:21:58 -03:00
Gabriel Rosa 9d417ff61b FIX: treating new connectors upload reponse 2022-11-25 18:21:43 -03:00
Anderson Feitosa b01c4c6c25 UPGRADE: change protospack version 2022-11-25 13:00:09 -03:00
Anderson Feitosa 449a1abb63 FEAT: update auth guard to patch method 2022-11-25 12:11:51 -03:00
Anderson Feitosa 04ca17a69d FEAT: update protospack 2022-11-25 11:37:34 -03:00
Anderson Feitosa 34a0eb40a7 DOCS: docsfera patch 2022-11-23 14:58:17 -03:00
Anderson Feitosa 2df69fba84 FEAT: add log on update 2022-11-23 13:35:02 -03:00
Anderson Feitosa dcbcc5ff36 FEAT: add patch method on pipeline controller 2022-11-23 13:02:32 -03:00
Gabriel Rosa 703b5f36b3 Merge branch 'main' into feat/rest-api 2022-11-21 13:36:13 -03:00
Gabriel Rosa 54d10cb873 FIX: try to delete pipeline even if it does not exists in opensearch 2022-11-17 09:25:05 -03:00
Gabriel Rosa 3c877b8b8d Merge branch 'main' into feat/rest-api 2022-11-10 15:14:45 -03:00
Gabriel Rosa e6b0034805 Merge branch 'main' into feat/rest-api 2022-11-09 18:29:04 -03:00
Gabriel Rosa b9c1f784d3 FIX: treatingconnector upload response 2022-11-09 18:25:57 -03:00
Gabriel Rosa 3edf5c2416 Merge branch 'main' into feat/rest-api 2022-11-09 15:03:09 -03:00
Gabriel Rosa f3e00a15c8 Remove unused imports 2022-11-09 14:06:30 -03:00
Gabriel Rosa 0422c7a369 Set branch name on swagger version 2022-11-09 14:06:12 -03:00
Gabriel Rosa f22d9370db test new upload documentation 2022-11-09 11:27:54 -03:00
Gabriel Rosa a9ee74724f FIX: better error handling 2022-11-08 12:11:05 -03:00
20 changed files with 574 additions and 564 deletions
-1
View File
@@ -10,7 +10,6 @@ on:
required: true
type: choice
options:
- dev
- stg
- stg2
- prd
+1 -1
View File
@@ -290,7 +290,7 @@ Example: `FIX: ensure Range headers adhere more closely to RFC 2616`
### 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
3. Send Pull Request link in Microsfera Google Chat Group for review and possible approval
## 🛠️ Built with
Some technologies used in this project:
+140 -26
View File
@@ -264,6 +264,20 @@
]
}
},
"/auth/verify-access-token": {
"get": {
"operationId": "AuthController_verifyAccessToken",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Auth"
]
}
},
"/connectors": {
"post": {
"operationId": "ConnectorController_uploadConnector",
@@ -505,18 +519,16 @@
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeleteConnectorDto"
}
},
{
"name": "version",
"required": true,
"in": "query",
"schema": {
"type": "string"
}
}
},
],
"responses": {
"200": {
"description": ""
@@ -948,7 +960,7 @@
],
"responses": {
"200": {
"description": "List of users of a customer",
"description": "",
"content": {
"application/json": {
"schema": {
@@ -2351,6 +2363,25 @@
"PipelinesV2"
]
},
"patch": {
"operationId": "PipelinesController_updateByPatch",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"PipelinesV2"
]
},
"delete": {
"operationId": "PipelinesController_delete",
"parameters": [],
@@ -2364,6 +2395,37 @@
]
}
},
"/pipelinesV2/upload": {
"post": {
"operationId": "PipelinesController_uploadFile",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/IUploadCSVFile"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"PipelinesV2"
]
}
},
"/inputs/available-entities/{plugin}": {
"get": {
"operationId": "InputsController_getAvailableEntities",
@@ -2609,7 +2671,7 @@
},
"/catalog": {
"get": {
"operationId": "CatalogController_catalogAll",
"operationId": "CatalogController_searchCatalog",
"parameters": [],
"responses": {
"200": {
@@ -2820,7 +2882,16 @@
},
"post": {
"operationId": "CatalogController_manageDataAssetDocs",
"parameters": [],
"parameters": [
{
"name": "id",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
}
],
"responses": {
"201": {
"description": "",
@@ -3216,9 +3287,9 @@
}
},
"info": {
"title": "Maestro - feat/incremental-table",
"title": "Maestro - feat/upload-csv",
"description": "Documentation for Maestro gateway",
"version": "16.11.2022 - 16:46",
"version": "1.0.0",
"contact": {}
},
"tags": [],
@@ -3486,17 +3557,6 @@
"tags"
]
},
"DeleteConnectorDto": {
"type": "object",
"properties": {
"version": {
"type": "string"
}
},
"required": [
"version"
]
},
"PermissionGroupPermission": {
"type": "object",
"properties": {
@@ -5092,6 +5152,38 @@
"updated_at"
]
},
"IUploadCSVFile": {
"type": "object",
"properties": {
"file": {
"type": "string",
"format": "binary"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"encoding": {
"type": "string"
},
"sep": {
"type": "string"
},
"header": {
"type": "boolean"
}
},
"required": [
"file",
"name",
"description",
"encoding",
"sep",
"header"
]
},
"AvailableEntity": {
"type": "object",
"properties": {
@@ -5276,6 +5368,17 @@
"username"
]
},
"EmbedObject": {
"type": "object",
"properties": {
"url": {
"type": "string"
}
},
"required": [
"url"
]
},
"IDataAsset": {
"type": "object",
"properties": {
@@ -5374,10 +5477,14 @@
"items": {
"$ref": "#/components/schemas/IComment"
}
},
"embed": {
"$ref": "#/components/schemas/EmbedObject"
}
},
"required": [
"id",
"display_name",
"pipeline_id",
"user_id",
"description",
@@ -5386,6 +5493,7 @@
"owner",
"roles",
"users",
"created_at",
"comments"
]
},
@@ -5615,6 +5723,9 @@
"items": {
"type": "string"
}
},
"embed": {
"$ref": "#/components/schemas/EmbedObject"
}
},
"required": [
@@ -5651,6 +5762,9 @@
},
"location": {
"type": "string"
},
"embed": {
"$ref": "#/components/schemas/EmbedObject"
}
},
"required": [
+54 -61
View File
@@ -12,7 +12,7 @@
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.112.0",
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
"@dadosfera/protospack-v2": "3.20.0",
"@dadosfera/protospack-v2": "3.23.0",
"@grpc/grpc-js": "^1.6.7",
"@grpc/proto-loader": "^0.6.13",
"@nestjs/common": "^8.4.7",
@@ -36,7 +36,7 @@
"mixpanel": "^0.17.0",
"passport": "^0.6.0",
"passport-facebook": "^3.0.0",
"passport-forcedotcom": "^0.1.5",
"passport-forcedotcom": "^0.2.0",
"passport-google-oauth20": "^2.0.0",
"passport-hubspot-oauth2": "^1.0.3",
"passport-mailchimp": "^1.1.0",
@@ -1727,9 +1727,9 @@
}
},
"node_modules/@dadosfera/protospack-v2": {
"version": "3.20.0",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.20.0.tgz",
"integrity": "sha512-eatmjfYmfD2Rqxi3L6/XDOqkImYc9PvChTTXO03RgiOk2IDEALvacPGp6j1bce2jfNMA2LoP3Bd1ugklecDPgg==",
"version": "3.23.0",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.23.0.tgz",
"integrity": "sha512-pe2s7aJYaNlUhQ+QoMGkJoFjTS8Dh+xSgUClSJuCsTia17oidRAucfpeMUX9ws1a3+tDrXTpH519CxeHzuZQPA==",
"dependencies": {
"@grpc/grpc-js": "^1.6.7",
"rxjs": "^7.5.5",
@@ -3699,8 +3699,9 @@
},
"node_modules/asap": {
"version": "2.0.6",
"dev": true,
"license": "MIT"
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
"dev": true
},
"node_modules/asn1.js": {
"version": "5.4.1",
@@ -4705,9 +4706,10 @@
}
},
"node_modules/dezalgo": {
"version": "1.0.3",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
"integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
"dev": true,
"license": "ISC",
"dependencies": {
"asap": "^2.0.0",
"wrappy": "1"
@@ -5902,23 +5904,28 @@
}
},
"node_modules/formidable": {
"version": "2.0.1",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.1.tgz",
"integrity": "sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"dezalgo": "1.0.3",
"hexoid": "1.0.0",
"once": "1.4.0",
"qs": "6.9.3"
"dezalgo": "^1.0.4",
"hexoid": "^1.0.0",
"once": "^1.4.0",
"qs": "^6.11.0"
},
"funding": {
"url": "https://ko-fi.com/tunnckoCore/commissions"
}
},
"node_modules/formidable/node_modules/qs": {
"version": "6.9.3",
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.0.4"
},
"engines": {
"node": ">=0.6"
},
@@ -8713,24 +8720,11 @@
}
},
"node_modules/passport-forcedotcom": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/passport-forcedotcom/-/passport-forcedotcom-0.1.5.tgz",
"integrity": "sha512-raDRQqBJtTEHDxLkxLG+9sYE0xpPy9PqriMPbMy9jmpIcU2+mOq9PgczvUPrU8UjfcZp3gqkDHqujcUWiGOVNQ==",
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/passport-forcedotcom/-/passport-forcedotcom-0.2.0.tgz",
"integrity": "sha512-gRI5+zQK9iVAZ1hJgt3TkWLeDw8SYrNWUsmVk0d0RyvUviQ4mT52x3JbYRiyZefoeID8afmLsJH8VOHjWdPf3Q==",
"dependencies": {
"passport-oauth2": "1.3.x"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/passport-forcedotcom/node_modules/passport-oauth2": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.3.0.tgz",
"integrity": "sha512-AisRXcC7Vx8WSx5C9O8UNib/Y91/IOphs5tImlOMs7T+QTEJdmS+OxgXSskbnDdGQT/8mU5T3yMT6136rBjYXg==",
"dependencies": {
"oauth": "0.9.x",
"passport-strategy": "1.x.x",
"uid2": "0.0.x"
"passport-oauth2": "^1.6.1"
},
"engines": {
"node": ">= 0.4.0"
@@ -12330,9 +12324,9 @@
}
},
"@dadosfera/protospack-v2": {
"version": "3.20.0",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.20.0.tgz",
"integrity": "sha512-eatmjfYmfD2Rqxi3L6/XDOqkImYc9PvChTTXO03RgiOk2IDEALvacPGp6j1bce2jfNMA2LoP3Bd1ugklecDPgg==",
"version": "3.23.0",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.23.0.tgz",
"integrity": "sha512-pe2s7aJYaNlUhQ+QoMGkJoFjTS8Dh+xSgUClSJuCsTia17oidRAucfpeMUX9ws1a3+tDrXTpH519CxeHzuZQPA==",
"requires": {
"@grpc/grpc-js": "^1.6.7",
"rxjs": "^7.5.5",
@@ -13675,6 +13669,8 @@
},
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
"dev": true
},
"asn1.js": {
@@ -14372,7 +14368,9 @@
"dev": true
},
"dezalgo": {
"version": "1.0.3",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
"integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
"dev": true,
"requires": {
"asap": "^2.0.0",
@@ -15214,18 +15212,25 @@
}
},
"formidable": {
"version": "2.0.1",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.1.tgz",
"integrity": "sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ==",
"dev": true,
"requires": {
"dezalgo": "1.0.3",
"hexoid": "1.0.0",
"once": "1.4.0",
"qs": "6.9.3"
"dezalgo": "^1.0.4",
"hexoid": "^1.0.0",
"once": "^1.4.0",
"qs": "^6.11.0"
},
"dependencies": {
"qs": {
"version": "6.9.3",
"dev": true
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"dev": true,
"requires": {
"side-channel": "^1.0.4"
}
}
}
},
@@ -17093,23 +17098,11 @@
}
},
"passport-forcedotcom": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/passport-forcedotcom/-/passport-forcedotcom-0.1.5.tgz",
"integrity": "sha512-raDRQqBJtTEHDxLkxLG+9sYE0xpPy9PqriMPbMy9jmpIcU2+mOq9PgczvUPrU8UjfcZp3gqkDHqujcUWiGOVNQ==",
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/passport-forcedotcom/-/passport-forcedotcom-0.2.0.tgz",
"integrity": "sha512-gRI5+zQK9iVAZ1hJgt3TkWLeDw8SYrNWUsmVk0d0RyvUviQ4mT52x3JbYRiyZefoeID8afmLsJH8VOHjWdPf3Q==",
"requires": {
"passport-oauth2": "1.3.x"
},
"dependencies": {
"passport-oauth2": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.3.0.tgz",
"integrity": "sha512-AisRXcC7Vx8WSx5C9O8UNib/Y91/IOphs5tImlOMs7T+QTEJdmS+OxgXSskbnDdGQT/8mU5T3yMT6136rBjYXg==",
"requires": {
"oauth": "0.9.x",
"passport-strategy": "1.x.x",
"uid2": "0.0.x"
}
}
"passport-oauth2": "^1.6.1"
}
},
"passport-google-oauth20": {
+2 -2
View File
@@ -28,7 +28,7 @@
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.112.0",
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
"@dadosfera/protospack-v2": "3.20.0",
"@dadosfera/protospack-v2": "3.23.0",
"@grpc/grpc-js": "^1.6.7",
"@grpc/proto-loader": "^0.6.13",
"@nestjs/common": "^8.4.7",
@@ -52,7 +52,7 @@
"mixpanel": "^0.17.0",
"passport": "^0.6.0",
"passport-facebook": "^3.0.0",
"passport-forcedotcom": "^0.1.5",
"passport-forcedotcom": "^0.2.0",
"passport-google-oauth20": "^2.0.0",
"passport-hubspot-oauth2": "^1.0.3",
"passport-mailchimp": "^1.1.0",
+1 -7
View File
@@ -30,12 +30,8 @@ async function bootstrap() {
await app.listen(3333);
}
function configureSwagger(app: INestApplication) {
const date = new Date();
const swaggerVersion = `${date.getDate()}.${
date.getMonth() + 1
}.${date.getFullYear()} - ${date.getHours()}:${date.getMinutes()}`;
function configureSwagger(app: INestApplication) {
let branchName = '';
try {
branchName = execSync('git rev-parse --abbrev-ref HEAD')
@@ -50,7 +46,6 @@ function configureSwagger(app: INestApplication) {
const config = new DocumentBuilder()
.setTitle(swaggerTitle)
.setDescription('Documentation for Maestro gateway')
.setVersion(swaggerVersion)
.addBearerAuth(
{ type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
'Authorization',
@@ -60,7 +55,6 @@ function configureSwagger(app: INestApplication) {
const document = SwaggerModule.createDocument(app, config);
if (process.env.ENV === 'local') SwaggerModule.setup('api', app, document);
writeFileSync(
'docsfera.json',
JSON.stringify(
+12 -1
View File
@@ -7,6 +7,7 @@ import {
HttpStatus,
Inject,
UseFilters,
Get,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import {
@@ -21,7 +22,10 @@ import {
} from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import { RequireAllPermissions } from 'src/authentication/authentication.decorator';
import {
Authenticated,
RequireAllPermissions,
} from 'src/authentication/authentication.decorator';
import { AuthClientService } from './auth.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { GrpcToHttpExceptionFilter } from '../../error/grpc-to-http-exception.filter';
@@ -185,4 +189,11 @@ export class AuthController {
return this.authClient.verifyTotp({ accessToken, totp });
}
@Authenticated()
@Get('verify-access-token')
@HttpCode(HttpStatus.OK)
verifyAccessToken() {
return { access_token_status: 'valid' };
}
}
+14 -49
View File
@@ -10,7 +10,7 @@ import {
Post,
Put,
Query,
UnsupportedMediaTypeException,
UseFilters,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import {
@@ -33,9 +33,11 @@ import {
IPreviewResponse,
IUpdateDataRequest,
} from './dtos';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
@ApiTags('Catalog')
@Controller('catalog')
@UseFilters(new GrpcToHttpExceptionFilter())
@Authenticated()
export class CatalogController {
logger: DadosferaLogger;
@@ -52,12 +54,12 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async catalogAll(
async searchCatalog(
@User() user: RequestUser,
@Query() query,
): Promise<ICatalogAllResponse> {
const { user_id, customer_name, customer_id, username, permissions } = user;
this.logger.info(`/catalog - Catalog all data assets`, {
this.logger.info(`/catalog - searchCatalog`, {
user_id,
customer_name,
});
@@ -77,13 +79,13 @@ export class CatalogController {
is_data_manager,
});
const res = await this.catalogService.getAllOpenSearchDataAssets(
const res = await this.catalogService.searchDataAssets(
query,
metadata,
customer_id,
);
return { ...res };
return res;
}
@Get('tags')
@@ -120,7 +122,6 @@ export class CatalogController {
@Param('id') id,
) {
const { username, user_id, customer_id, customer_name, permissions } = user;
const [data_asset_type, data_asset_id] = id.split('-');
this.logger.info(`/catalog - ON GET ONE DASHBOARD METABASE ROUTE`, {
username,
@@ -142,8 +143,7 @@ export class CatalogController {
const { data_asset } = await this.catalogService.getOneDataAsset({
customer_id,
data_asset_id,
data_asset_type,
id,
metadata,
});
@@ -178,7 +178,6 @@ export class CatalogController {
@Param('id') id,
) {
const { username, user_id, customer_id, customer_name, permissions } = user;
const [data_asset_type, data_asset_id] = id.split('-');
this.logger.info(`/catalog - ON GET ONE DASHBOARD METABASE ROUTE`, {
username,
@@ -200,8 +199,7 @@ export class CatalogController {
const { data_asset } = await this.catalogService.getOneDataAsset({
customer_id,
data_asset_id,
data_asset_type,
id,
metadata,
});
@@ -236,17 +234,8 @@ export class CatalogController {
@Param('id') id,
): Promise<IColumnsMetadataResponse> {
const { customer_name, customer_id, user_id, username } = user;
const data_asset_type = id.split('-')[0];
const supported_data_assets = ['dataset'];
if (!supported_data_assets.includes(data_asset_type)) {
throw new UnsupportedMediaTypeException(
`${data_asset_type} does not have a preview function for the time being.`,
);
}
this.logger.info(`/catalog - ON GET DATA DOCS ROUTE`, {
this.logger.info(`/catalog - columns-metadata`, {
user_id,
customer_name,
});
@@ -276,15 +265,6 @@ export class CatalogController {
@Param('id') id,
): Promise<IPreviewResponse> {
const { customer_name, customer_id, user_id, username } = user;
const data_asset_type = id.split('-')[0];
const supported_data_assets = ['dataset'];
if (!supported_data_assets.includes(data_asset_type)) {
throw new UnsupportedMediaTypeException(
`${data_asset_type} does not have a preview function for the time being.`,
);
}
this.logger.info(`/catalog - ON GET DATA DOCS ROUTE`, {
user_id,
@@ -315,15 +295,6 @@ export class CatalogController {
@Param('id') id,
): Promise<IDocsResponse> {
const { customer_name, customer_id, user_id, username } = user;
const data_asset_type = id.split('-')[0];
const supported_data_assets = ['dataset'];
if (!supported_data_assets.includes(data_asset_type)) {
throw new UnsupportedMediaTypeException(
`${data_asset_type} does not have a documentation function for the time being.`,
);
}
this.logger.info(`/catalog - ON GET DATA DOCS ROUTE`, {
user_id,
@@ -384,11 +355,10 @@ export class CatalogController {
async manageDataAssetDocs(
@User() user: RequestUser,
@Headers() headers,
@Param('id') data_asset_id,
@Param('id') table_id: string,
@Body('docs') docs: string,
) {
const { user_id, customer_name } = user;
const [, id] = data_asset_id.split('-');
this.logger.info(`/catalog - ON GET DATA DOCS ROUTE`, {
user_id,
@@ -396,7 +366,7 @@ export class CatalogController {
});
const res = await this.catalogService.createDataDocs({
table_id: id,
table_id,
docs,
info: {
customer: customer_name,
@@ -503,10 +473,7 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.DELETE,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async deleteDataAsset(
@Param('id') data_asset_id: string,
@User() user: RequestUser,
) {
async deleteDataAsset(@Param('id') id: string, @User() user: RequestUser) {
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
customer_id,
@@ -514,10 +481,8 @@ export class CatalogController {
user_id,
username,
});
const [type, id] = data_asset_id.split('-');
const response = await this.catalogService.deleteDataAsset(
{ id, type },
{ id, type: undefined },
metadata,
);
+81 -170
View File
@@ -18,6 +18,7 @@ import { CatalogClientConfiguration } from './catalog-client';
import { UsersService } from '../users/users.service';
import { RolesService } from '../roles/roles.service';
import { Metadata } from '@grpc/grpc-js';
import { IUpdateDataRequest } from './dtos';
class CatalogService implements OnModuleInit {
catalogReadService: ReadService.CatalogReadServices;
@@ -60,15 +61,11 @@ class CatalogService implements OnModuleInit {
async createDataAsset(data: Messages.CreateDataAssetRequest, metadata) {
this.logger.info('CatalogService - Manage Data assets permissions');
if (!data.embed) data.embed = undefined;
return lastValueFrom(
this.catalogWriteService.CreateDataAsset(data, metadata),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 404,
);
});
);
}
async managePermissions(data: Messages.ManagePermissionRequest, metadata) {
@@ -144,34 +141,12 @@ class CatalogService implements OnModuleInit {
return roles_ids;
}
async getUsernamesAndRolesByCustomerId(customerId: string) {
const resultUsers = await this.userService.findAllUsersByCustomerId(
customerId,
);
const resultRoles = await this.roleService.roleSearch(
{},
{ customer_id: customerId },
);
const customer_users = resultUsers.users.map((user) => {
return {
id: user.id,
username: user.username,
};
});
const customer_roles = resultRoles.roles.map((role) => {
return {
id: role.id,
name: role.name,
};
});
return [customer_users, customer_roles];
}
async getAllOpenSearchDataAssets(query, metadata, customer_id) {
this.logger.info('CatalogService - getAllOpenSearchDashboard');
async searchDataAssets(
query: Record<string, any>,
metadata: Metadata,
customer_id: string,
) {
this.logger.info('CatalogService - searchDataAssets');
const { search, page, size, sort_by, order, ...filters } = query;
@@ -187,171 +162,79 @@ class CatalogService implements OnModuleInit {
},
metadata,
),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 404,
);
});
);
const result = JSON.parse(data_assets);
const [customer_users, customer_roles] =
await this.getUsernamesAndRolesByCustomerId(customer_id);
const response = await this.getAssetsUsersAndRoles(
result.data_assets,
customer_id,
);
for (const asset of result.data_assets) {
const condition =
asset.owner && !asset.owner.includes('@') ? true : false;
const result = condition
? await this.userService.findOneById(asset.owner).catch(() => null)
: null;
const owner = result !== null ? result.user.username : null;
const roles = [];
const users = [];
for (const role of customer_roles) {
for (const role_id of asset.roles) {
if (role.id === role_id) roles.push(role);
}
}
for (const user of customer_users) {
for (const user_id of asset.users) {
if (user.id === user_id) users.push(user);
}
}
Object.assign(asset, {
...asset,
owner,
roles,
users,
});
}
return { data_assets: result.data_assets, total };
return { data_assets: response, total };
}
async getOneDataAsset({
data_asset_id,
data_asset_type,
customer_id,
metadata,
async getOneDataAsset(data: {
id: string;
customer_id: string;
metadata: Metadata;
}) {
const { customer_id, id, metadata } = data;
const { data_asset } = await lastValueFrom(
this.catalogReadService.GetOneDataAsset(
{ id: data_asset_id, type: data_asset_type },
{ id, type: undefined },
metadata,
),
);
const opensearchTable = JSON.parse(data_asset);
let asset = JSON.parse(data_asset);
asset = {
...asset,
p_roles: asset.roles,
p_users: asset.users,
};
asset = await this.getAssetsUsersAndRoles([asset], customer_id);
const result = opensearchTable.owner
? await this.userService
.findOneById(opensearchTable.owner)
.catch(() => null)
: null;
const owner = result !== null ? result.user.username : null;
const [customer_users, customer_roles] =
await this.getUsernamesAndRolesByCustomerId(customer_id);
const users = [];
const roles = [];
for (const role of customer_roles) {
for (const role_id of opensearchTable.roles) {
if (role.id === role_id) roles.push(role);
}
}
for (const user of customer_users) {
for (const user_id of opensearchTable.users) {
if (user.id === user_id) users.push(user);
}
}
Object.assign(opensearchTable, {
p_roles: opensearchTable.roles,
p_users: opensearchTable.users,
roles,
users,
owner,
});
return { data_asset: opensearchTable };
return { data_asset: asset[0] };
}
async updateOneDataAsset({ data_asset_id, customer_id, body, metadata }) {
async updateOneDataAsset(data: {
data_asset_id: string;
customer_id: string;
body: IUpdateDataRequest;
metadata: Metadata;
}) {
const { body, customer_id, data_asset_id, metadata } = data;
const { data_asset } = await lastValueFrom(
this.catalogWriteService.UpdateDataAsset(
{ id: data_asset_id, changes: JSON.stringify(body) },
metadata,
),
);
let asset = JSON.parse(data_asset);
asset = {
...asset,
p_roles: asset.roles,
p_users: asset.users,
};
asset = await this.getAssetsUsersAndRoles([asset], customer_id);
const opensearchTable = JSON.parse(data_asset);
const result = opensearchTable.owner
? await this.userService
.findOneById(opensearchTable.owner)
.catch(() => null)
: null;
const owner = result !== null ? result.user.username : null;
const [customer_users, customer_roles] =
await this.getUsernamesAndRolesByCustomerId(customer_id);
const users = [];
const roles = [];
for (const role of customer_roles) {
for (const role_id of opensearchTable.roles) {
if (role.id === role_id) roles.push(role);
}
}
for (const user of customer_users) {
for (const user_id of opensearchTable.users) {
if (user.id === user_id) users.push(user);
}
}
Object.assign(opensearchTable, {
p_roles: opensearchTable.roles,
p_users: opensearchTable.users,
roles,
users,
owner,
});
return { data_asset: opensearchTable };
return { data_asset: asset[0] };
}
async getDataDocs(data_asset_id: string, metadata: Metadata) {
const [data_asset_type, id] = data_asset_id.split('-');
async getDataDocs(id: string, metadata: Metadata) {
const { documentation } = await lastValueFrom(
this.catalogReadService.GetDatasetDoc(
{ id, type: data_asset_type },
metadata,
),
this.catalogReadService.GetDatasetDoc({ id, type: undefined }, metadata),
);
console.log(documentation);
const docs = JSON.parse(documentation);
return docs;
}
async getDatasetPreview(data_asset_id: string, metadata: Metadata) {
const [data_asset_type, id] = data_asset_id.split('-');
async getDatasetPreview(id: string, metadata: Metadata) {
const { preview } = await lastValueFrom(
this.catalogReadService.GetDatasetPreview(
{ id, type: data_asset_type },
{ id, type: undefined },
metadata,
),
);
@@ -359,12 +242,10 @@ class CatalogService implements OnModuleInit {
return result;
}
async getDatasetColumnsMetadata(data_asset_id: string, metadata: Metadata) {
const [data_asset_type, id] = data_asset_id.split('-');
async getDatasetColumnsMetadata(id: string, metadata: Metadata) {
const { columns_metadata } = await lastValueFrom(
this.catalogReadService.GetDatasetColumnsMetadata(
{ id, type: data_asset_type },
{ id, type: undefined },
metadata,
),
);
@@ -398,6 +279,36 @@ class CatalogService implements OnModuleInit {
return response;
}
async getAssetsUsersAndRoles(data_assets: Array<any>, customer_id: string) {
const { users: customer_users } =
await this.userService.findAllUsersByCustomerId(customer_id);
const { roles: customer_roles } = await this.roleService.roleSearch(
{},
{ customer_id },
);
return data_assets.map((data_asset) => {
const owner = customer_users.find(
(u) => u.id === data_asset.owner,
)?.username;
const roles = [];
const users = [];
for (const role_id of data_asset.roles) {
const role = customer_roles.find((r) => r.id === role_id);
if (role) roles.push({ id: role.id, name: role.name });
}
for (const user_id of data_asset.users) {
const user = customer_users.find((r) => r.id === user_id);
if (user) users.push({ id: user.id, username: user.username });
}
return {
...data_asset,
roles,
users,
owner,
} as typeof data_asset;
});
}
}
export { CatalogService };
+14 -5
View File
@@ -1,6 +1,10 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { CreateDataAssetRequest } from '@dadosfera/protospack-v2/dist/lib/Catalog/interfaces/messages';
export class EmbedObject {
@ApiProperty()
url: string;
}
export class IRole {
@ApiProperty()
name: string;
@@ -49,8 +53,8 @@ export class IDataAsset {
data_encrypted?: string;
@ApiPropertyOptional()
num_rows?: number;
@ApiPropertyOptional()
display_name?: string;
@ApiProperty()
display_name: string;
@ApiProperty()
pipeline_id: string;
@ApiProperty()
@@ -75,12 +79,14 @@ export class IDataAsset {
parameters?: string[];
@ApiPropertyOptional()
embedding_params?: object;
@ApiPropertyOptional()
created_at?: string;
@ApiProperty()
created_at: string;
@ApiPropertyOptional()
updated_at?: string;
@ApiProperty({ type: [IComment] })
comments: IComment[];
@ApiPropertyOptional()
embed?: EmbedObject;
}
export class IOneDataAsset {
@@ -127,8 +133,9 @@ export class IUpdateDataRequest {
description: string;
@ApiProperty()
tags: string[];
@ApiPropertyOptional()
embed: EmbedObject;
}
export class ICreateDataAsset implements CreateDataAssetRequest {
@ApiProperty()
display_name: string;
@@ -140,6 +147,8 @@ export class ICreateDataAsset implements CreateDataAssetRequest {
external_url: string;
@ApiProperty()
location: string;
@ApiPropertyOptional()
embed: EmbedObject;
}
export class IPreview {
+6 -36
View File
@@ -1,9 +1,4 @@
import {
OnModuleInit,
Inject,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { OnModuleInit, Inject } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { ConnectionManager } from '@dadosfera/protospack-v2';
import { lastValueFrom } from 'rxjs';
@@ -86,12 +81,7 @@ export class ConnectionClientService implements OnModuleInit {
},
metadata,
),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
);
}
async updateConnection(
@@ -112,12 +102,7 @@ export class ConnectionClientService implements OnModuleInit {
},
metadata,
),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
);
}
async deleteConnection({ body, metadata }): Promise<ConnectionRes> {
@@ -130,12 +115,7 @@ export class ConnectionClientService implements OnModuleInit {
},
metadata,
),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
);
}
async getAllConnections({ body, metadata }): Promise<ConnectionsRes> {
@@ -146,12 +126,7 @@ export class ConnectionClientService implements OnModuleInit {
{ search, filters: JSON.stringify(filters), size, page },
metadata,
),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
);
}
async getConnectionDetails({
@@ -162,12 +137,7 @@ export class ConnectionClientService implements OnModuleInit {
return lastValueFrom(
this.connectionServiceRead.GetConnectionDetails({ id }, metadata),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
);
}
async INTERNAL_getAllConnections({
@@ -9,6 +9,7 @@ import {
Get,
Headers,
Query,
UseFilters,
} from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { ConnectionClientService } from './client.service';
@@ -28,8 +29,10 @@ import {
} from './dtos/connection';
import { CreateConnectionDto } from './dtos/connection';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
const connectionPermissions = PERMISSIONS_GROUPS.CONNECTION.permissions;
@UseFilters(new GrpcToHttpExceptionFilter())
@ApiTags('connections')
@ApiBearerAuth()
@Authenticated()
+22 -160
View File
@@ -83,163 +83,30 @@ export class ConnectorClientService implements OnModuleInit {
);
});
const responseParsed = JSON.parse(res.message);
const connectorErrors = responseParsed.items
.filter((i) => i.update._index === 'connectors' && i.update.error)
const connectorsResponse = responseParsed.items.filter(
(i) => i.update._index === process.env.CONNECTORS_INDEX,
);
const connectorErrors = connectorsResponse
.filter((i) => i.update.error)
.map((i) => ({
id: i.update._id,
reason: i.update.error,
status: i.error.status,
}));
const connectionControlsErrors = responseParsed.items
.filter(
(i) => i.update._index === 'connection_controls' && i.update.error,
)
.map((i) => ({
id: i.update._id,
reason: i.update.error,
status: i.error.status,
}));
const connectionStepsErrors = responseParsed.items
.filter((i) => i.update._index === 'connection_steps' && i.update.error)
.map((i) => ({
id: i.update._id,
reason: i.update.error,
status: i.error.status,
}));
const configControlsErrors = responseParsed.items
.filter((i) => i.update._index === 'config_controls' && i.update.error)
.map((i) => ({
id: i.update._id,
reason: i.update.error,
status: i.error.status,
}));
const connectorCreated = responseParsed.items
.filter(
(i) =>
i.update._index === 'connectors' && i.update.result === 'created',
)
.map((i) => ({
id: i.update._id,
}));
const connectionControlsCreated = responseParsed.items
.filter(
(i) =>
i.update._index === 'connection_controls' &&
i.update.result === 'created',
)
.map((i) => ({
id: i.update._id,
}));
const connectionStepsCreated = responseParsed.items
.filter(
(i) =>
i.update._index === 'connection_steps' &&
i.update.result === 'created',
)
.map((i) => ({
id: i.update._id,
}));
const configControlsCreated = responseParsed.items
.filter(
(i) =>
i.update._index === 'config_controls' &&
i.update.result === 'created',
)
.map((i) => ({
id: i.update._id,
}));
const connectorUpdated = responseParsed.items
.filter(
(i) =>
i.update._index === 'connectors' && i.update.result === 'updated',
)
.map((i) => ({
id: i.update._id,
}));
const connectionControlsUpdated = responseParsed.items
.filter(
(i) =>
i.update._index === 'connection_controls' &&
i.update.result === 'updated',
)
.map((i) => ({
id: i.update._id,
}));
const connectionStepsUpdated = responseParsed.items
.filter(
(i) =>
i.update._index === 'connection_steps' &&
i.update.result === 'updated',
)
.map((i) => ({
id: i.update._id,
}));
const configControlsUpdated = responseParsed.items
.filter(
(i) =>
i.update._index === 'config_controls' &&
i.update.result === 'updated',
)
.map((i) => ({
id: i.update._id,
}));
const connectorNoop = responseParsed.items
.filter(
(i) => i.update._index === 'connectors' && i.update.result === 'noop',
)
.map((i) => ({
id: i.update._id,
}));
const connectionControlsNoop = responseParsed.items
.filter(
(i) =>
i.update._index === 'connection_controls' &&
i.update.result === 'noop',
)
.map((i) => ({
id: i.update._id,
}));
const connectionStepsNoop = responseParsed.items
.filter(
(i) =>
i.update._index === 'connection_steps' && i.update.result === 'noop',
)
.map((i) => ({
id: i.update._id,
}));
const configControlsNoop = responseParsed.items
.filter(
(i) =>
i.update._index === 'config_controls' && i.update.result === 'noop',
)
.map((i) => ({
id: i.update._id,
id: i.update?._id,
reason: i.update?.error,
status: i.error?.status,
}));
const connectorCreated = connectorsResponse
.filter((i) => i.update.result === 'created')
.map((i) => i.update._id);
const connectorUpdated = connectorsResponse
.filter((i) => i.update.result === 'updated')
.map((i) => i.update._id);
const connectorNoop = connectorsResponse
.filter((i) => i.update.result === 'noop')
.map((i) => i.update._id);
return {
errors: {
connectors: connectorErrors,
connection_controls: connectionControlsErrors,
connection_steps: connectionStepsErrors,
config_controls: configControlsErrors,
},
created: {
connectors: connectorCreated,
connection_controls: connectionControlsCreated,
connection_steps: connectionStepsCreated,
config_controls: configControlsCreated,
},
updated: {
connectors: connectorUpdated,
connection_controls: connectionControlsUpdated,
connection_steps: connectionStepsUpdated,
config_controls: configControlsUpdated,
},
noop: {
connectors: connectorNoop,
connection_controls: connectionControlsNoop,
connection_steps: connectionStepsNoop,
config_controls: configControlsNoop,
},
errors: connectorErrors,
created: connectorCreated,
updated: connectorUpdated,
noop: connectorNoop,
};
}
@@ -318,12 +185,7 @@ export class ConnectorClientService implements OnModuleInit {
version,
plugin,
}),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
);
}
async updateConnector({ plugin, changes }) {
@@ -19,7 +19,6 @@ import { ApiBearerAuth, ApiConsumes, ApiTags } from '@nestjs/swagger';
import { ConnectorClientService } from './client.service';
import { AddTagDto } from './dtos/add-tag';
import { CreateConnectorDto } from './dtos/create-connector';
import { DeleteConnectorDto } from './dtos/delete-connector';
import { GetAllDto } from './dtos/get-all';
import { RemoveTagDto } from './dtos/remove-tag';
import { UpdateDto } from './dtos/update';
@@ -274,7 +273,7 @@ export class ConnectorController {
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.DELETE)
async deleteConnector(
@Param('plugin') plugin: string,
@Body() { version }: DeleteConnectorDto,
@Query('version') version: string,
) {
this.logger.info('/upload - Upload Connector Route');
+20
View File
@@ -66,3 +66,23 @@ export interface IGetPipelineLogsRequest {
id: string;
details: string;
}
export class IUploadCSVFile {
@ApiProperty({ format: 'binary' })
file: string;
@ApiProperty()
name: string;
@ApiProperty()
description: string;
@ApiProperty()
encoding: string;
@ApiProperty()
sep: string;
@ApiProperty()
header: boolean;
}
+109 -7
View File
@@ -12,13 +12,20 @@ import {
UseFilters,
HttpCode,
HttpStatus,
Patch,
UseInterceptors,
UploadedFile,
} from '@nestjs/common';
import {
ApiConsumes,
ApiCreatedResponse,
ApiNoContentResponse,
ApiTags,
} from '@nestjs/swagger';
import { AuthenticateCondition } from 'src/authentication/authentication.decorator';
import {
AuthenticateCondition,
RequireAllPermissions,
} from 'src/authentication/authentication.decorator';
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
import { PipelinesService } from './pipelines.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
@@ -27,8 +34,13 @@ import { RequestUser, User } from 'src/authentication/user.decorator';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
import { PipelinesService as OldPipelineService } from 'src/modules/pipelines/pipelines.service';
import { ICreatePipelineV2Req, IPipelineV2 } from './interfaces';
import {
ICreatePipelineV2Req,
IPipelineV2,
IUploadCSVFile,
} from './interfaces';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
import { FileInterceptor } from '@nestjs/platform-express';
@UseFilters(new GrpcToHttpExceptionFilter())
@ApiTags('PipelinesV2')
@@ -45,6 +57,10 @@ import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filt
action = 'UPDATE';
break;
case 'PATCH':
action = 'UPDATE';
break;
default:
action = req.method;
}
@@ -175,20 +191,49 @@ export class PipelinesController {
@Put('/:id')
async update(
@Headers('Dadosfera-Lang') language,
@Body() updatePipelineDto,
@Param('id') id,
@User() user: RequestUser,
) {
this.logger.info('PipelinesController - findOne', { user });
this.logger.info('PipelinesController - update', { user });
const { info } = updatePipelineDto;
delete updatePipelineDto.info;
const response = await this.pipelinesClientService.update({
...updatePipelineDto,
info,
id,
const { customer_id, customer_name, user_id, username } = user;
if (!language) language = 'en-us';
const metadata = PackTheMetadata({
customer_id,
customer_name,
user_id,
username,
language,
});
const response = await this.pipelinesClientService.update(
{
...updatePipelineDto,
info,
id,
},
metadata,
);
this.logger.info('PipelinesController - update: OK', { user });
return response;
}
@Patch('/:id')
async updateByPatch(
@Headers('Dadosfera-Lang') language,
@Body() updatePipelineDto,
@Param('id') id,
@User() user: RequestUser,
) {
this.logger.info('PipelinesController - patch', { user });
const response = await this.update(language, updatePipelineDto, id, user);
this.logger.info('PipelinesController - patch: OK', { user });
return response;
}
@@ -206,4 +251,61 @@ export class PipelinesController {
await this.pipelinesClientService.remove({ id, metadata, user });
this.logger.info('PipelinesController - delete: OK');
}
@Post('/upload')
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.CREATE)
@ApiConsumes('multipart/form-data')
@UseInterceptors(
FileInterceptor('file', { limits: { fileSize: 50 * 1000 * 1000 + 1 } }),
)
async uploadFile(
@User() user: RequestUser,
@UploadedFile() file,
@Body() body: IUploadCSVFile,
) {
this.logger.info('/upload - Upload Connector Route');
const metadata = PackTheMetadata({ ...user });
let name = `${new Date().getTime()}_${file.originalname.split('.')[0]}`;
body.name ? (name = `${new Date().getTime()}_${body.name}`) : name;
const response = await this.pipelinesClientService.uploadFile(
{
file,
name,
},
metadata,
);
const { sep, header, encoding, description } = body;
const [file_name, file_format] = file.originalname.split('.');
const upload_pipeline = {
connection_id: process.env.UPLOAD_FILE_AGENT_CONNECTION,
connector_name: 'Amazon S3',
connector_plugin: 'aws_s3',
connector_version: '1.0.0',
image_url: 'https://assets.dadosfera.ai/images/connectors/csv.svg',
name: body.name || file_name,
description,
transformations_ids: [],
tags: [],
cron: '@once',
config: { cron: '@once', tables: [] },
properties: {
engine: 'csv',
source_bucket: process.env.BUCKET_CUSTOMER_CSV_ASSETS,
source_prefix: `${user.customer_name}/${name}.${file_format}`,
file_format_params: { sep, encoding, header: Boolean(header) },
is_a_upload_csv: true,
},
input_id: undefined,
};
const pipeline = await this.pipelinesClientService.create(
upload_pipeline,
metadata,
);
return pipeline;
}
}
+67 -31
View File
@@ -1,7 +1,8 @@
import {
BadRequestException,
HttpException,
HttpStatus,
Inject,
InternalServerErrorException,
OnModuleInit,
} from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
@@ -23,6 +24,8 @@ import { InputsService } from '../inputs/inputs.service';
import { RequestUser } from 'src/authentication/user.decorator';
import { TransformationsService } from '../transformations/transformations.service';
import { getObjValueFromPath } from 'src/utils/ObjValueFromPath';
import ErrorCodes from 'src/utils/errorCodes';
import ErrorBuilder from 'src/utils/ErrorBuilder';
export class PipelinesService implements OnModuleInit {
logger: DadosferaLogger;
@@ -99,7 +102,7 @@ export class PipelinesService implements OnModuleInit {
const [errorType, message] = error.details.split('|');
throw new BadRequestException(message);
}
throw new InternalServerErrorException(error.details);
throw new ErrorBuilder(error.details);
});
this.logger.info('Done');
@@ -140,11 +143,17 @@ export class PipelinesService implements OnModuleInit {
return findOnePipelineResponse;
}
async update(UpdatePipelineRequest: Messages.PipelineV2UpdateRequest) {
async update(
UpdatePipelineRequest: Messages.PipelineV2UpdateRequest,
metadata,
) {
this.logger.info('PipelinesClientService - Update');
const updatePipelineResponse = await lastValueFrom(
this.pipelineWriteService.PipelineV2Update(UpdatePipelineRequest),
this.pipelineWriteService.PipelineV2Update(
UpdatePipelineRequest,
metadata,
),
);
this.logger.info('Done');
@@ -158,45 +167,53 @@ export class PipelinesService implements OnModuleInit {
customer_id: user.customer_id,
customer: user.customer_name,
};
let existsInProduct = true;
const { pipeline } = await lastValueFrom(
this.pipelineReadService.PipelineV2FindOne({ id }, metadata),
);
).catch((e) => {
if (e.details === ErrorCodes.PIPELINE.NOT_FOUND) existsInProduct = false;
else throw new ErrorBuilder(e.details);
return { pipeline: undefined };
});
await lastValueFrom(
this.pipelineWriteService.PipelineV2Remove({ id }, metadata),
);
//{pipeline:{tables: {tables: [], input_id: ''}}}
const input = pipeline.config.tables
? JSON.parse(pipeline.config.tables)
: null;
if (input)
await this.inputsService
.remove({
id: input.input_id,
info,
})
.catch((error) =>
this.logger.error('Could not delete input', {
data: { input, error },
}),
);
const transformations: { id: string }[] = pipeline.transformations
? JSON.parse(pipeline.transformations)
: null;
if (transformations && transformations.length)
for (const transformation of transformations) {
await this.transformationsService
if (existsInProduct) {
//{pipeline:{tables: {tables: [], input_id: ''}}}
const input = pipeline.config.tables
? JSON.parse(pipeline.config.tables)
: null;
if (input)
await this.inputsService
.remove({
id: transformation.id,
id: input.input_id,
info,
})
.catch((error) =>
this.logger.error('Could not delete transformation', {
data: { transformation, error },
this.logger.error('Could not delete input', {
data: { input, error },
}),
);
}
const transformations: { id: string }[] = pipeline.transformations
? JSON.parse(pipeline.transformations)
: null;
if (transformations && transformations.length)
for (const transformation of transformations) {
await this.transformationsService
.remove({
id: transformation.id,
info,
})
.catch((error) =>
this.logger.error('Could not delete transformation', {
data: { transformation, error },
}),
);
}
}
}
async findOneProperties(id: string, metadata: Metadata) {
@@ -232,4 +249,23 @@ export class PipelinesService implements OnModuleInit {
},
};
}
async uploadFile(uploadFile, metadata) {
const body: Messages.PipelineV2UploadFileRequest = {
file: {
buffer: uploadFile.file.buffer,
mimetypes: uploadFile.file.mimetype,
},
name: uploadFile.name,
};
return lastValueFrom(
this.pipelineWriteService.PipelineV2UploadFile(body, metadata),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
}
}
-5
View File
@@ -52,7 +52,6 @@ import { Metadata } from '@grpc/grpc-js';
import ErrorBuilder from 'src/utils/ErrorBuilder';
import ErrorCodes from 'src/utils/errorCodes';
// TODO GET de hierarquias e do PATCH em usuário
@ApiTags('Users')
@Controller('users')
@ApiHeader({
@@ -75,10 +74,6 @@ export class UsersController {
}
@Get()
@ApiOkResponse({
type: GetAllUsersByCustomerIdRes,
description: 'List of users of a customer',
})
async getAllUsersByCustomerId(
@User() user: RequestUser,
@Headers('dadosfera-lang') language,
+18
View File
@@ -214,6 +214,16 @@ export function EnrichErrorCode(code: string) {
message: 'Id encontra-se num formato inválido',
code,
};
case ErrorCodes.CONNECTION.NOT_FOUND:
case ErrorCodes.CONNECTION.PLATFORM_NOT_FOUND:
return {
statusCode: HttpStatus.NOT_FOUND,
error: 'Conexão não encontrada',
message:
'Não encontramos a conexão solicitada. Caso o erro persista, entre em contato com o suporte',
code,
};
case ErrorCodes.CONNECTION_TEST.ERROR:
return {
statusCode: HttpStatus.BAD_REQUEST,
@@ -282,6 +292,14 @@ export function EnrichErrorCode(code: string) {
message: 'Caso o erro persista, entre em contato com o suporte',
code,
};
case ErrorCodes.CATALOG.DATA_ASSET_NOT_FOUND:
return {
statusCode: HttpStatus.NOT_FOUND,
error: 'Não encontramos o ativo solicitado',
message:
'Tente realizar a ação novamente. Caso o erro persista, entre em contato com o suporte',
code,
};
case ErrorCodes.INTERNAL:
case ErrorCodes.UNKNOWN:
default:
+9
View File
@@ -60,9 +60,16 @@ const PIPELINE = {
const INPUT = {
NOT_FOUND: 'INPUT.NOT_FOUND',
};
const CONNECTION = {
NOT_FOUND: 'CONNECTION.NOT_FOUND',
PLATFORM_NOT_FOUND: 'CONNECTION.PLATFORM_NOT_FOUND',
};
const TRANSFORMATION = {
NOT_FOUND: 'TRANSFORMATION.NOT_FOUND',
};
const CATALOG = {
DATA_ASSET_NOT_FOUND: 'CATALOG.DATA_ASSET_NOT_FOUND',
};
const ErrorCodes = {
UNKNOWN: 'UNKNOWN',
RATE_LIMIT: 'RATE_LIMIT',
@@ -77,6 +84,8 @@ const ErrorCodes = {
PIPELINE,
INPUT,
TRANSFORMATION,
CONNECTION,
CATALOG,
};
export default ErrorCodes;