Compare commits

...
580 Commits
Author SHA1 Message Date
Gabriel Amorim 61cc238891 Merge pull request #196 from dadosfera/feat/cognito-mailing
FIX: send language on create users and resend invite
2023-01-10 18:06:06 -03:00
Gabriel Rosa b5df916511 Merge branch 'main' into feat/cognito-mailing 2023-01-10 15:05:18 -03:00
Gabriel Amorim 95da106fb8 Merge pull request #195 from dadosfera/fix/customer-schedule-limit
fix/customer-schedule-limit
2023-01-06 18:29:57 -03:00
Gabriel Rosa 5730402312 update protospack 2023-01-06 18:04:16 -03:00
Gabriel Rosa c2ea8b69da FIX: customer scheduleLimit on login 2023-01-06 15:24:01 -03:00
Gabriel Rosa 14081bb9ca FIX: send language on create users and resend invite 2023-01-06 15:18:49 -03:00
Victor Radael 82d9024f24 Merge pull request #193 from dadosfera/feat/update-connection
Feat/update connection
2022-12-27 17:21:25 -03:00
Gabriel Rosa 53a6d3957a Merge branch 'main' into feat/update-connection 2022-12-27 17:01:32 -03:00
Anderson Feitosa 7dab555009 Merge pull request #194 from dadosfera/feature/download-logs
feature/download-logs
2022-12-27 16:41:11 -03:00
Anderson Feitosa 27dacf1257 FEAT: update protospack version 2022-12-27 12:24:15 -03:00
Anderson Feitosa f71bb523ff FEAT: add download logs api route 2022-12-27 12:23:03 -03:00
Victor Radael db55a8abde FEAT: Update OAuth Connection 2022-12-26 17:47:30 -03:00
Victor Radael 8f40b159d6 FEAT: MERGE main to deploy 2022-12-26 17:43:31 -03:00
Anderson Feitosa 5c6f36a760 Merge pull request #192 from dadosfera/feature/pipeline-object-to-data-asset
feature/pipeline-object-to-data-asset
2022-12-23 14:07:33 -03:00
Anderson Feitosa db4a2d9d2e FEAT: update protospack version 2022-12-22 17:43:54 -03:00
Anderson Feitosa 9a1b3e0bf4 FEAT: update protospack 2022-12-22 17:38:58 -03:00
Gabriel Rosa 67d9b3a06e Send metabaseUserId undefined to user update 2022-12-22 17:14:51 -03:00
Anderson Feitosa 1150d21763 FEAT: remove metabase user id 2022-12-22 17:02:03 -03:00
Anderson Feitosa b38e9f26c3 FEAT: add route to get data asset by pipeline and object 2022-12-22 17:00:56 -03:00
Anderson Feitosa 5a23923e53 DOCS: docsfera 2022-12-22 13:16:56 -03:00
Anderson Feitosa 3db7e99d9e FEAT: parse objects 2022-12-22 13:16:44 -03:00
Anderson Feitosa c85cd37f3a FEAT: add new api route to get pipeline objects 2022-12-22 13:08:08 -03:00
Victor Radael 190a63f0eb FEAT: Update OAuth Connection 2022-12-20 17:01:00 -03:00
Gabriel Amorim 0fc8c427a2 Merge pull request #191 from dadosfera/fix/refresh-token
Fix/refresh token
2022-12-16 09:40:56 -03:00
Gabriel Rosa 59c3ce7ed9 FIX: do not use User() on non-authenticated routes 2022-12-16 08:09:20 -03:00
Victor Radael c5c428d3d4 FIX: Refresh token 2022-12-15 19:57:52 -03:00
Victor Radael cda7f9a9b5 FEAT: Edit connection 2022-12-15 16:01:24 -03:00
Victor Radael bb3b71d5f0 Merge remote-tracking branch 'origin' into feat/upload-csv 2022-12-15 16:01:02 -03:00
Victor Radael e47459eb9a FEAT: Edit connection 2022-12-15 16:00:54 -03:00
Gabriel Amorim a2de729e0e Merge pull request #190 from dadosfera/feat/cognito-app-client
Feat/cognito app client
2022-12-14 13:20:29 -03:00
Gabriel Rosa e2cb02e51a new protospack version 2022-12-14 10:49:33 -03:00
Gabriel Rosa 8a0c91eca5 new protospack version 2022-12-14 10:02:02 -03:00
Gabriel Rosa 15302d80bc Merge branch 'main' into feat/cognito-app-client 2022-12-13 16:12:19 -03:00
Gabriel Rosa 5aa63154c5 new protospack version 2022-12-13 15:34:57 -03:00
Gabriel Rosa 48af897e79 FEAT: send customer_name on refresh token 2022-12-13 09:28:42 -03:00
Victor Radael 9eb61a0ac9 Merge pull request #189 from dadosfera/feat/upload-csv
FIX: Upload CSV
2022-12-12 17:41:44 -03:00
Victor Radael 4a9e5b0ffc FIX: Upload CSV 2022-12-12 17:04:16 -03:00
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 Amorim 569c3cf573 Merge pull request #179 from dadosfera/feat/incremental-table
Feat/incremental table
2022-11-16 16:52:35 -03:00
Gabriel Rosa c420ef62ed new protospack version 2022-11-16 16:46:38 -03:00
Alexsander Pereira 966ba00fec Merge pull request #178 from dadosfera/stg2
FEAT: Adding stg2
2022-11-16 15:47:49 -03:00
Alexsander Pereira 0aadf7fc40 FEAT: Adding stg2 2022-11-16 15:18:18 -03:00
Gabriel Rosa 3e3268cb26 FIX: New getAvailableEntities payload 2022-11-16 10:37:21 -03:00
Anderson Feitosa 09bd623b62 Merge pull request #177 from dadosfera/catalog-permissions
FIX: create data asset permission public
2022-11-14 16:19:09 -03:00
Gabriel Rosa 4bf9a5831a FIX: create data asset permission public 2022-11-14 16:15:57 -03:00
Anderson Feitosa 264077289b Merge pull request #176 from dadosfera/catalog-permissions
FIX: renamed catalog create permission
2022-11-14 15:52:04 -03:00
Gabriel Rosa 14c686cff4 FIX: renamed catalog create permission
- Catalog controller using permission decorator on every route
2022-11-14 15:40:38 -03:00
Gabriel Amorim 0e57667419 Merge pull request #175 from dadosfera/feat/modules-permissions
Feat/modules permissions
2022-11-11 12:38:04 -03:00
Gabriel Rosa ac7dc4905e FIX: changed PROCESS permisison group title 2022-11-11 12:35:04 -03:00
Gabriel Rosa 94282718ad Changed permission group name 2022-11-11 12:27:57 -03:00
Gabriel Rosa 7c228c5c53 FIX: set new module permissions public 2022-11-11 12:26:14 -03:00
Gabriel Amorim 14e0f3d2d3 Merge pull request #174 from dadosfera/fix/event-tracker
Fix/event tracker
2022-11-11 10:18:42 -03:00
Victor Radael 85ef0d7c74 Merge remote-tracking branch 'origin' into fix/event-tracker 2022-11-11 10:16:07 -03:00
Victor Radael e00b6481d0 FIX: Tracker 2022-11-11 10:15:49 -03:00
Victor Radael 8906c73d84 Revert "FIX: Event Tracker"
This reverts commit 3bc37db891.
2022-11-11 10:13:24 -03:00
Victor Radael 3bc37db891 FIX: Event Tracker 2022-11-11 10:12:20 -03:00
Gabriel Rosa 3c877b8b8d Merge branch 'main' into feat/rest-api 2022-11-10 15:14:45 -03:00
Gabriel Amorim fe44664970 Merge pull request #173 from dadosfera/fix/modules-permissions
FIX: new modules permissions
2022-11-10 15:13:01 -03:00
Gabriel Rosa 0503732c1e new protospack version 2022-11-10 14:43:46 -03:00
Gabriel Rosa fa0855d631 FIX: new modules permissions 2022-11-10 12:57:15 -03:00
Gabriel Amorim 38aee30f2a Merge pull request #172 from dadosfera/fix/pipeline-details-bug
Fix/pipeline details bug
2022-11-10 10:32:42 -03:00
Gabriel Rosa 19f5c947bd Set release version on swagger when deploying main 2022-11-10 10:12:14 -03:00
Gabriel Rosa 44aa0e6010 improved run prod command 2022-11-10 09:47:30 -03:00
Gabriel Rosa cf4e7da1d8 Typing login route 2022-11-10 09:46:22 -03:00
Gabriel Rosa 8bd7d54aa7 new protospack version 2022-11-10 09:16:02 -03:00
Gabriel Rosa a00a66e0d0 Merge branch 'main' into fix/pipeline-details-bug 2022-11-10 08:41:36 -03:00
Victor Radael f4c5d03269 Merge pull request #171 from dadosfera/ft/mixpanel-track
FEAT: Mixpanel Tracker
2022-11-10 08:35:55 -03:00
Victor Radael 060ba7da8a FEAT: Mixpanel Tracker 2022-11-09 20:46:40 -03:00
Victor Radael 5ec2c01b20 FEAT: Mixpanel Tracker 2022-11-09 20:37:39 -03:00
Gabriel Rosa 4a7e660a49 FIX: fixed condition of getObjValueFromPath 2022-11-09 20:06:23 -03:00
Gabriel Rosa abc6258492 FIX: fixed condition to set default value on pipeline details 2022-11-09 19:30:13 -03:00
Gabriel Rosa 7ee1215da2 Deploy docs using github hosted runner 2022-11-09 18:48:50 -03:00
Gabriel Rosa cd5886337b FIX: customer modules 2022-11-09 18:40:53 -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 5fb8dae312 FIX: pipeline details now showing correct default values on s3 pipelines 2022-11-09 17:35:18 -03:00
Gabriel Amorim 5072a54ef6 Merge pull request #170 from dadosfera/fix/revert-action-version
FIX: return semantic release action to previous version
2022-11-09 16:05:04 -03:00
Gabriel Rosa 718f5cb12a FIX: return sematic release action to previous version 2022-11-09 15:56:28 -03:00
Gabriel Amorim 4c41dd8029 Merge pull request #169 from dadosfera/fix/revert-action-version
FIX: remove `conventional-changelog-eslint` plugin
2022-11-09 15:41:08 -03:00
Gabriel Rosa fe8a0b88b0 FIX: remove conventional-changelog-eslint plugin 2022-11-09 15:39:37 -03:00
Gabriel Rosa 3edf5c2416 Merge branch 'main' into feat/rest-api 2022-11-09 15:03:09 -03:00
Gabriel Amorim cd67ca61cd Merge pull request #168 from dadosfera/fix/customer-modules
FIX: customer modules
2022-11-09 14:59:54 -03:00
Gabriel Rosa b9439685f3 FIX: new swagger info 2022-11-09 14:29:32 -03:00
Gabriel Rosa 04edce0c56 FIX: new protospack version 2022-11-09 14:08:05 -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
Victor Radael ef098dd74d Merge pull request #167 from dadosfera/ft/create-data-asset
FEAT: Ft/create data asset
2022-11-08 19:48:48 -03:00
Victor Radael 2541960b44 FEAT: Create Data Asset 2022-11-08 19:32:26 -03:00
Victor Radael 2dc965ed90 FIX:delete and update data asset 2022-11-08 14:18:31 -03:00
Gabriel Rosa a9ee74724f FIX: better error handling 2022-11-08 12:11:05 -03:00
Victor Radael b2f1ce669d FIX: Save 2022-11-08 11:41:34 -03:00
Victor Radael 602d81e51f FIX: Save 2022-11-08 11:39:48 -03:00
Rodrigo Zamboni bbdb023dde Merge pull request #165 from dadosfera/feat/newCustomersInfo
Feat/new customers info
2022-11-07 16:05:33 -03:00
Gabriel Rosa 9cb4cd7093 FIX: fixed protospack version 2022-11-07 13:48:28 -03:00
Gabriel Rosa efc5870d87 FIX: fixed protospack version 2022-11-07 13:48:09 -03:00
Rodrigo Zamboni c3d33f8230 Merge branch 'main' into feat/newCustomersInfo 2022-11-07 12:38:13 -03:00
rodrigo.zamboni 0654e8fa04 FIX: updaetd protospack version 2022-11-07 12:35:51 -03:00
Gabriel Amorim 28ab892208 Merge pull request #164 from dadosfera/catalog-permissions
FIX: Catalog permissions
2022-11-07 10:44:02 -03:00
Gabriel Rosa d1522eb0ea FIX: new protospack version 2022-11-04 17:57:48 -03:00
Gabriel Rosa 6be9e06b22 FIX: new protospack version 2022-11-04 14:22:07 -03:00
Gabriel Rosa 7af261d56c New permissions for transformations 2022-11-04 12:03:15 -03:00
Gabriel Rosa 8fa924fdfb Changed delete description 2022-11-04 09:27:53 -03:00
Victor Radael 4b4bdfea61 FEAT: Create Data Asset 2022-11-03 17:18:20 -03:00
Gabriel Rosa d1064c852b rename workflow job 2022-11-03 12:03:25 -03:00
Gabriel Rosa 63338f5250 fixed deploy worflow file 2022-11-03 11:59:01 -03:00
Gabriel Rosa 5e1fb41930 FIX: identation 2022-11-03 11:57:52 -03:00
Gabriel Rosa a807da2414 test deploy 2022-11-03 11:48:46 -03:00
Gabriel Rosa 85f14fcf4b FIX: generate better summary on deploy 2022-11-03 11:28:09 -03:00
Gabriel Rosa d95898ce55 FIX: generate better summary on deploy 2022-11-03 11:18:02 -03:00
Gabriel Rosa 33075b0f85 FIX: generate better summary on deploy 2022-11-03 11:10:38 -03:00
Gabriel Rosa ca75f8f6e7 FIX: generate better summary on deploy 2022-11-03 11:00:55 -03:00
Gabriel Rosa af12a39959 FEAT: Deploy summary 2022-11-03 10:53:37 -03:00
Gabriel Rosa f77476b9ae FIX: echo text 2022-11-03 10:33:55 -03:00
Gabriel Rosa fb0c659cd1 FIX: permissions for catalog 2022-11-03 10:27:50 -03:00
Gabriel Rosa aea6815de7 Merge branch 'main' into catalog-permissions 2022-11-03 10:20:10 -03:00
Gabriel Amorim 0103f100f5 Merge pull request #163 from dadosfera/new-ecr-image
FIX: new ecr image
2022-11-01 15:59:49 -03:00
Gabriel Rosa 66b6be43b7 FIX: new ecr image 2022-11-01 15:33:14 -03:00
Gabriel Rosa c029e286b5 WIP 2022-11-01 15:31:45 -03:00
Gabriel Amorim a8f94a2d53 Merge pull request #162 from dadosfera/feat/platform-delete-pipeline
Feat: platform delete pipeline
2022-10-31 16:43:44 -03:00
Gabriel Rosa aadb3fcdee Better inputs error codes 2022-10-31 16:20:11 -03:00
Gabriel Rosa a26e88d2b6 Merge branch 'main' into feat/platform-delete-pipeline 2022-10-31 15:37:13 -03:00
Victor Radael b20f67e8b8 Merge pull request #161 from dadosfera/ft/delete-data-assets
Ft/delete data assets
2022-10-27 18:44:08 -03:00
Victor Radael 4a8a8eb463 FIX: Pipeline delete 2022-10-27 18:20:56 -03:00
Victor Radael d52f8b78c8 FIX: Pipeline delete 2022-10-27 18:06:39 -03:00
Victor Radael bfbe7cce87 Merge pull request #160 from dadosfera/ft/delete-data-assets
Ft/delete data assets
2022-10-27 17:14:22 -03:00
Victor Radael 1ab8c1dd10 FIX: Merge origin main 2022-10-27 15:24:04 -03:00
Gabriel Amorim 246de83142 Merge pull request #159 from dadosfera/ref/catalog
Catalog Refactor
2022-10-26 17:40:42 -03:00
Victor Radael dfa6222538 FIX: Delete data asset 2022-10-26 14:22:29 -03:00
Gabriel Rosa fc7a9c7909 FIX: do not throw errors when deleting input or transformation on pipeline delete 2022-10-26 10:52:12 -03:00
Gabriel Rosa 932616a578 Delete connection permission public 2022-10-26 09:09:28 -03:00
Victor Radael b64619ede1 FIX: Remove trash code 2022-10-25 19:29:23 -03:00
Gabriel Rosa 4a08e5f560 Merge branch 'main' into ref/catalog 2022-10-25 17:33:04 -03:00
Gabriel Rosa 4ffd0916c3 FIX: pipeline delete working 2022-10-25 16:21:58 -03:00
Victor Radael 92041f453c FIX: Remove trash code 2022-10-25 14:00:26 -03:00
Gabriel Rosa f2f09cc9c7 FIX: oauth redirect adjusted 2022-10-24 15:24:14 -03:00
Victor Radael d486231fd6 FEAT: RLS new barnch 2022-10-21 15:44:21 -03:00
Victor Radael 526a3bddcd Merge pull request #158 from dadosfera/ft/rls-old-catalog
FEAT: Rls first change
2022-10-21 15:18:01 -03:00
Victor Radael 45108d3019 FEAT: Rls first change 2022-10-21 14:49:28 -03:00
Victor Radael ac3e26b851 FIX: RLS 2022-10-21 14:36:59 -03:00
Gabriel Rosa 7fbc919716 FIX: catalog filters 2022-10-20 11:23:30 -03:00
Gabriel Rosa 5b1eb19511 FIX: catalog sort by 2022-10-20 10:27:38 -03:00
Victor Radael b714f3cf36 FIX: Filters 2022-10-20 10:04:45 -03:00
Victor Radael 48c1e29168 FIX: Filters 2022-10-20 09:45:12 -03:00
Victor Radael 04ea1d0f04 FIX: Get a total and fix owner type 2022-10-19 17:01:22 -03:00
Victor Radael 0de5e1d5d1 PATCH: Ref/Catalog new functions 2022-10-18 14:13:24 -03:00
Victor Radael b8c41fad1b PATCH: Ref/Catalog new functions 2022-10-18 13:43:18 -03:00
Victor Radael ef9ec5ad42 PATCH: Ref/Catalog new functions 2022-10-18 13:05:47 -03:00
Victor Radael 65e71f21a0 Merge branch 'ref/catalog' of github.com:dadosfera/maestro into ref/catalog 2022-10-18 13:05:27 -03:00
Victor Radael b921393ba1 PATCH: Ref/Catalog new functions 2022-10-18 13:05:05 -03:00
Gabriel Rosa 18aa7d8674 FIX: permission language fixed 2022-10-17 17:53:47 -03:00
Victor Radael f2dd871de2 FIX: Ref Catalogo new functions models 2022-10-17 16:16:31 -03:00
Victor Radael cf3fa88196 FIX: Ref Catalogo new functions models 2022-10-17 15:00:29 -03:00
Victor Radael 131810533c FIX: Ref Catalogo new functions models 2022-10-17 14:58:11 -03:00
Victor Radael ea06f3f571 FIX: Ref Catalogo new functions models 2022-10-17 14:51:28 -03:00
Victor Radael 81921a7eb2 FIX: Ref Catalogo new functions models 2022-10-17 14:38:31 -03:00
Victor Radael e9fdd0285b FIX: Ref Catalogo new functions models 2022-10-17 13:42:13 -03:00
Victor Radael 167470adba FIX: Ref Catalogo new functions models 2022-10-17 13:35:13 -03:00
Victor Radael fbb9a59214 FIX: Ref Catalogo new functions models 2022-10-17 13:32:41 -03:00
Gabriel Amorim ef6d8594a3 Merge pull request #157 from dadosfera/fix/get-user-permissions
FIX: new function to get all user permissions
2022-10-14 11:57:05 -03:00
Gabriel Rosa ac73c0b046 FIX: new function to get all user permissions 2022-10-14 11:33:15 -03:00
Gabriel Amorim 5a30bf08b2 Merge pull request #156 from dadosfera/fix/pipeline-properties
Fix/pipeline properties
2022-10-13 16:39:41 -03:00
Gabriel Rosa 62b4eb709e Return properties object on findOneProperties 2022-10-13 16:24:32 -03:00
Gabriel Rosa b37a18d1da Merge branch 'main' into fix/pipeline-properties 2022-10-13 15:59:53 -03:00
Gabriel Rosa 379bac704f FIX: getPipelineproperties 2022-10-13 14:59:27 -03:00
Gabriel Rosa 9178530a21 FEAT: get pipeline properties 2022-10-13 14:58:41 -03:00
Gabriel Amorim 667d3f874d Merge pull request #155 from dadosfera/fix/user-permissions
FIX: permissions array on user findOneById
2022-10-13 14:03:02 -03:00
Victor Radael 475af224bf Merge remote-tracking branch 'origin' into ref/catalog 2022-10-13 11:43:16 -03:00
Gabriel Rosa 11f1df5537 FIX: permissions array on user findOneById 2022-10-13 09:23:56 -03:00
Victor Radael e3b02571c8 Merge pull request #154 from dadosfera/fix/oauth
FIX: Public oauth route
2022-10-13 09:05:29 -03:00
Gabriel Rosa 979a12aa7f Merge branch 'main' into fix/oauth 2022-10-13 09:02:17 -03:00
Gabriel Rosa 7646d7a3c5 WIP 2022-10-13 08:57:21 -03:00
Victor Radael 8f0e851a88 FIX: Public oauth route 2022-10-12 23:12:33 -03:00
Victor Radael 779418f471 clear catalog 2022-10-11 22:23:36 -03:00
Gabriel Amorim 6e6d03f302 Merge pull request #153 from dadosfera/fix/user-roles
Fix/user roles
2022-10-11 16:40:12 -03:00
Victor Radael 85f41521ed Merge remote-tracking branch 'origin' into ref/catalog 2022-10-11 15:36:08 -03:00
Victor Radael e2bb119745 refactor/catalog 2022-10-11 15:35:29 -03:00
Gabriel Rosa 3d5ce59b52 FIX: user can get own info, even with no users:admin permission 2022-10-11 11:54:39 -03:00
Gabriel Rosa 1c63271f64 FIX: send language to request that need terms of use 2022-10-11 10:26:13 -03:00
Gabriel Rosa 31a51c20aa FIX: pass metadata to signIn request 2022-10-11 08:41:59 -03:00
Gabriel Rosa 62730eb969 FIX: terms of use dynamic language 2022-10-10 19:56:57 -03:00
Victor Radael 5a2c760bab Merge pull request #152 from dadosfera/fix/dashboards
FIX: Dashboard get all permisisons
2022-10-08 18:00:24 -03:00
Victor Radael 28b4f3ac4b FIX: Dashboard get all permisisons 2022-10-08 17:56:19 -03:00
Gabriel Amorim 43d181a429 Merge pull request #151 from dadosfera/fix/old-pipelines
FIX: Stop using old pipelines
2022-10-07 15:41:13 -03:00
Gabriel Rosa a72fe1b60d FIX: Stop using old pipelines 2022-10-07 15:37:36 -03:00
Gabriel Amorim b52a1227b1 Merge pull request #150 from dadosfera/fix/bulk-connectors-upload
fix/bulk-connectors-upload
2022-10-06 10:11:34 -03:00
Gabriel Rosa 31478ed61d FIX: new protospack version 2022-10-06 09:41:00 -03:00
Gabriel Rosa 79b1ba910e FIX: removed unused import 2022-10-06 09:17:27 -03:00
Gabriel Rosa 7fd929915b FIX: new bulk upload request 2022-10-06 09:15:42 -03:00
Victor Radael e4b27c5f76 Merge pull request #149 from dadosfera/ft/+200meltano
Ft/+200meltano
2022-10-05 17:22:40 -03:00
Victor Radael 92e449d6d3 FIX: Permissions and paths 2022-10-05 17:13:06 -03:00
Victor Radael 5073b2e188 FIX: Permissions and paths 2022-10-05 16:58:02 -03:00
Victor Radael 8a11eda24d FIX: +200 Meltano - Productboard API 2022-10-05 16:44:07 -03:00
Victor Radael 9d732d4a48 FIX: +200 Meltano - Productboard API 2022-10-05 16:42:41 -03:00
Gabriel Amorim 5fa10a939b Merge pull request #148 from dadosfera/fix/data-asset-sharing-permission
FIX: no permission needed for sharing data assets
2022-10-05 14:49:47 -03:00
Gabriel Rosa 4be3ffe3a2 FIX: no permission needed for sharing data assets 2022-10-05 14:45:06 -03:00
Victor Radael 8af9c638ef Merge pull request #147 from dadosfera/feat/openSearchCatalog
FIX: Individual data assets permissions
2022-10-05 08:45:58 -03:00
Victor Radael 97d6f914cc FIX: Individual data assets permissions 2022-10-05 08:43:20 -03:00
Victor Radael 9ad2e3770e FIX: Individual data assets permissions 2022-10-05 08:41:48 -03:00
Victor Radael ea2cc8809f FIX: Individual data assets permissions 2022-10-05 08:40:57 -03:00
Victor Radael 410e190e7c FIX: Individual data assets permissions 2022-10-05 08:39:40 -03:00
Victor Radael c1b213c34c Merge pull request #146 from dadosfera/feat/openSearchCatalog
Feat/open search catalog
2022-10-04 18:34:50 -03:00
Victor Radael a6c58eb82d FIX: unitary permitting 2022-10-04 18:29:39 -03:00
Victor Radael b756cb5a1e FIX: unitary permitting 2022-10-04 18:26:49 -03:00
Victor Radael 46cafc2d50 FIX: unitary permitting 2022-10-04 18:26:27 -03:00
Victor Radael a087775e3a Merge pull request #145 from dadosfera/feat/openSearchCatalog
Feat/open search catalog
2022-10-04 17:55:07 -03:00
Victor Radael 69305610ff FIX: unitary permitting 2022-10-04 17:41:01 -03:00
Victor Radael 69008a9ffb FIX: unitary permitting 2022-10-04 17:19:09 -03:00
Victor Radael 687b4e40e1 FIX: unitary permitting 2022-10-04 16:49:41 -03:00
Victor Radael d56544568b FIX: unitary permitting 2022-10-04 16:47:42 -03:00
Gabriel Amorim cad1e4b3de Merge pull request #144 from dadosfera/fix/delete-connection-permission
FIX: delete connection permission
2022-10-04 15:40:14 -03:00
Gabriel Rosa b311a84bde FIX: delete route reimplemented 2022-10-04 15:22:43 -03:00
Gabriel Rosa 28280dca8d FIX: Delete connections permission 2022-10-04 14:46:52 -03:00
Victor Radael 63fbfa6b52 FIX: unitary permitting 2022-10-04 13:20:34 -03:00
Victor Radael 2b03c4e4a9 FIX: Individual data assets permissions 2022-10-04 11:10:40 -03:00
Victor Radael 18c3c9c58c FIX: Permission data manager 2022-10-03 18:07:38 -03:00
Victor Radael 450c82446e Merge pull request #143 from dadosfera/fix/dadoferademo
FIX: unkown error get user by id
2022-10-03 16:56:55 -03:00
Victor Radael beb27a0f60 FIX: unkown error get user by id 2022-10-03 16:52:42 -03:00
Victor Radael 166c45728f FIX: unkown error get user by id 2022-10-03 16:48:12 -03:00
Victor Radael d0f5da0270 Merge remote-tracking branch 'origin' into feat/openSearchCatalog 2022-10-03 16:46:08 -03:00
Victor Radael dade8d59e5 FIX: Get user by id unkown error 2022-10-03 16:45:50 -03:00
Victor Radael fe261667f8 FIX: Change Revoke Permissions 2022-10-03 10:43:17 -03:00
Victor Radael 722bb1ec7c FIX: Data asset sharing 2022-09-30 18:38:45 -03:00
Victor Radael a371db355b FIX: Data asset sharing 2022-09-30 18:22:29 -03:00
Victor Radael 1ff135c0d7 FIX: Data asset sharing 2022-09-30 18:13:23 -03:00
Victor Radael 0360711ab4 Merge pull request #141 from dadosfera/feat/openSearchCatalog
Feat/open search catalog
2022-09-30 15:38:17 -03:00
Victor Radael b6ec2a83b2 FIX: Swagger 2022-09-30 15:15:24 -03:00
Victor Radael 812dc0c735 FIX: Swagger 2022-09-30 15:12:45 -03:00
Victor Radael 11715dd528 FIX: Swagger 2022-09-30 15:12:19 -03:00
Victor Radael be476c1a6d FIX: data asset owner 2022-09-30 14:38:42 -03:00
Victor Radael a8414f780a FIX: data asset owner 2022-09-30 14:28:06 -03:00
Victor Radael 1da61a4c13 FIX: Data asset permission owner 2022-09-30 12:27:55 -03:00
Victor Radael 7e8f5c49b5 FIX: Data asset permission owner 2022-09-30 11:11:59 -03:00
Victor Radael 96a485afd1 FIX: Revoke Permissions 2022-09-29 18:05:27 -03:00
Victor Radael e3c203d673 FIX: Data assets permissions 2022-09-29 15:04:31 -03:00
Gabriel Amorim d7da68241e Merge pull request #140 from dadosfera/fix/create-user
FIX: create user
2022-09-29 09:19:20 -03:00
Victor Radael 5d924f8a92 FIX: Manage Permissions Catalog 2022-09-28 23:06:52 -03:00
Victor Radael f9b4ddd070 FIX: Manage Permissions Catalog 2022-09-28 17:02:22 -03:00
Victor Radael c0e0732b7e FIX: Manage Permissions Catalog 2022-09-28 17:00:15 -03:00
Gabriel Rosa 37ea7c2f4d FIX: GetOneDataAsset only when table metadata has only one result 2022-09-28 16:59:45 -03:00
Victor Radael d42584fcfc FIX: Manage Permissions Catalog 2022-09-28 16:58:52 -03:00
Victor Radael a28781423c FIX: Manage Permissions Catalog 2022-09-28 14:39:25 -03:00
Gabriel Rosa 8c638610c7 Update description on open search 2022-09-28 11:52:59 -03:00
Victor Radael 55ff485fd0 FIX: Catalog Manage Permissions 2022-09-28 11:48:41 -03:00
Gabriel Rosa 4877fab945 new protospack 2022-09-28 11:20:17 -03:00
rodrigo.zamboni e724ef5ccc FIX: fix get all tags route 2022-09-27 16:33:56 -03:00
rodrigo.zamboni 9dc96416e8 Merge branch 'feat/openSearchCatalog' of https://github.com/dadosfera/maestro into feat/openSearchCatalog 2022-09-27 09:43:32 -03:00
rodrigo.zamboni 49663c4115 UPDATE: modifyed catalog tags route to use opensearch instead of nimbus 2022-09-27 09:35:48 -03:00
Gabriel Rosa c16664c7f9 new protospack version 2022-09-23 14:58:26 -03:00
Gabriel Rosa 7245942707 Function to synchronize user 2022-09-23 09:25:41 -03:00
Gabriel Rosa c29cf5aee1 FIX: sending metadata on creation of users 2022-09-20 17:48:27 -03:00
rodrigo.zamboni d96658c9cd FIX: fix catalog response 2022-09-19 17:42:30 -03:00
rodrigo.zamboni cbd736b87d FIX: fix catalog return response/ adding empty dashboard array 2022-09-19 16:28:33 -03:00
rodrigo.zamboni e4e6d95f8a Merge branch 'feat/openSearchCatalog' of https://github.com/dadosfera/maestro into feat/openSearchCatalog 2022-09-19 15:08:35 -03:00
rodrigo.zamboni a8e13c01d2 FIX: passing params with query params 2022-09-19 15:06:16 -03:00
Gabriel Rosa cdf2ce3cc2 FIX: create credentials on catalog's pi-factory client 2022-09-19 14:51:28 -03:00
rodrigo.zamboni c3877657ef FIX: fix catalog route to use openSearch 2022-09-19 11:14:23 -03:00
Gabriel Amorim 3d39affc61 Merge pull request #139 from dadosfera/fix/network-config-permissions
FIX: remove permission to delete VPNS
2022-09-16 11:55:50 -03:00
Gabriel Rosa 5d045b675c FIX: remove permission to delete VPNS 2022-09-15 09:48:37 -03:00
Gabriel Amorim bb61990f6e Merge pull request #138 from dadosfera/fix/permission-delete-connection
FIX: remove permission to delete connection
2022-09-15 08:50:41 -03:00
Gabriel Rosa 80442c509a FIX: remove permission to delete connection 2022-09-15 08:33:47 -03:00
Gabriel Amorim 8551239038 Merge pull request #137 from dadosfera/fix/update-user-email
FIX: update user email
2022-09-14 11:32:58 -03:00
Gabriel Rosa 4cf7c6e17b FIX: update user email 2022-09-14 10:18:03 -03:00
Gabriel Amorim 88c9c36eb0 Merge pull request #136 from dadosfera/fix/connections-migration
Fix: connections migration
2022-09-13 08:58:29 -03:00
Gabriel Rosa 4b317778f7 FIX: connections migration agora vai 2022-09-12 20:13:12 -03:00
Gabriel Rosa 2eea9787cd FIX: connections migration por favor funciona 2022-09-12 19:52:38 -03:00
Gabriel Rosa c1ab5d152f FIX: reseting productConnectionsMissing and productNetworkConfigsMissing 2022-09-12 18:58:24 -03:00
Gabriel Rosa 8798f5d54e FIX: DEBUG_ConnectionsMigrations - customer_connections 2022-09-12 18:47:42 -03:00
Gabriel Amorim 1da733b5bc Merge pull request #135 from dadosfera/fix/connections-migration
FIX: DEBUG-ConnectionsMigrations
2022-09-12 17:17:54 -03:00
Gabriel Rosa 930c8bc037 FIX: DEBUG-ConnectionsMigrations 2022-09-12 17:14:37 -03:00
Gabriel Amorim 0913741500 Merge pull request #134 from dadosfera/fix/connections-migration
Fix: connections migration
2022-09-12 16:42:08 -03:00
Gabriel Rosa 3e9d0063ae FIX: using DadosferaLogger 2022-09-12 16:35:58 -03:00
Gabriel Rosa 2bc0fe1e9e FIX: get logger from DadosferaLogger 2022-09-12 16:35:08 -03:00
Gabriel Rosa f0fb6e6b4a FIX: DEBUG-ConnectionsMigrations 2022-09-12 16:31:10 -03:00
Gabriel Amorim 74c27d9637 Merge pull request #133 from dadosfera/fix/connections-migration
FIX: get all connectors fixed
2022-09-12 16:11:08 -03:00
Gabriel Rosa 216c83d7fa FIX: get all connectors fixed 2022-09-12 16:08:11 -03:00
Gabriel Amorim 08e66eeb1e Merge pull request #132 from dadosfera/fix/connections-migration
Fix: connections migration
2022-09-12 15:28:45 -03:00
Gabriel Rosa cf3fd90787 FIX: network_config migration 2022-09-12 15:27:54 -03:00
Gabriel Rosa bb1decb08f FIX: typo on dadosfera:connections-migration fixed 2022-09-12 13:01:54 -03:00
Gabriel Rosa 642cb0e70b FIX: connections migration 2022-09-12 13:01:11 -03:00
Gabriel Amorim 0acf759e84 FIX: treating undefined responses from OpenSearch
Merge pull request #131 from dadosfera/fix/connections-undefineds
2022-09-12 07:41:56 -03:00
Gabriel Rosa 7bbb87a54a FIX: removed fake customer_name 2022-09-11 13:08:00 -03:00
Gabriel Rosa 69af7ba626 FIX: new route for synchronizing connections with platform 2022-09-11 13:07:21 -03:00
Gabriel Amorim 0b14221d5a FEAT: Connections manager
FEAT: Connections manager
2022-09-09 17:46:50 -03:00
Gabriel Rosa 16bddf3d40 Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-09-09 17:42:29 -03:00
Gabriel Rosa fb6ea7ba14 FIX: tests skipped 2022-09-09 17:42:01 -03:00
Gabriel Amorim 83d649a210 Merge branch 'main' into ft/connection-manager 2022-09-09 17:23:59 -03:00
Gabriel Rosa 319fc80bfe FIX: Checking if old pipelines exists 2022-09-09 11:56:39 -03:00
Gabriel Rosa 35172681ce FIX: checking if status is undefined 2022-09-09 10:17:22 -03:00
Gabriel Rosa 35db24dc59 FIX: find all pipelines 2022-09-09 09:48:19 -03:00
Gabriel Rosa ad9c1fc40c REFACTOR: changed old pipeline service to use lastValueFrom 2022-09-08 19:14:40 -03:00
Gabriel Rosa 4660751023 FIX: getting query params on find all pipelines 2022-09-08 17:59:15 -03:00
Gabriel Rosa 25cf13923b FIX: treating undefined language 2022-09-08 17:50:45 -03:00
Gabriel Rosa d724c1644b FIX: Findone pipeline 2022-09-08 17:12:24 -03:00
Gabriel Rosa c64529a37c FIX: adjust old pipeline input payload 2022-09-08 16:13:14 -03:00
Gabriel Rosa 8b06f0b12c Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-09-08 15:12:00 -03:00
Gabriel Rosa 311a4e4b93 FIX: salesforce oauth tye 2022-09-08 15:11:54 -03:00
rodrigo.zamboni 6f8985baa7 Merge branch 'ft/connection-manager' of https://github.com/dadosfera/maestro into ft/connection-manager 2022-09-08 15:06:52 -03:00
rodrigo.zamboni 11cb5a61da FIX: removing failing objectSnailtoCamel function 2022-09-08 15:06:12 -03:00
Gabriel Rosa 35c0520750 FIX: oauth conditionally setting state 2022-09-08 13:44:44 -03:00
Gabriel Rosa 8c6ec8b1b9 FIX: oauth creating connection 2022-09-08 13:34:51 -03:00
Gabriel Rosa 77db6f3771 New protospack 2022-09-07 17:31:21 -03:00
rodrigo.zamboni 952a76e905 FIX: fixing empty string netwoer_config_id field on test credentials 2022-09-07 11:22:03 -03:00
rodrigo.zamboni 2ec62dae45 FIX: Fix createInput columns field 2022-09-07 10:54:26 -03:00
rodrigo.zamboni 0d431a816b FIX: fix connection service client 2022-09-06 17:13:41 -03:00
rodrigo.zamboni 932e7413bd FIX: Solve merge conflicts 2022-09-06 17:02:55 -03:00
rodrigo.zamboni 5cb83ee679 FIX: Update protospack lib 2022-09-06 17:00:28 -03:00
Gabriel Rosa dcd558bd58 Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-09-06 15:38:39 -03:00
Gabriel Rosa 01e74473c0 FIX: pipeline accepting properties on payload 2022-09-06 15:38:25 -03:00
Victor Radael d0c15fe290 Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-09-06 12:29:39 -03:00
Victor Radael b9d07e3677 FIX: Connection Details 2022-09-06 12:22:30 -03:00
Gabriel Rosa 2c8ed40bc6 Inputs models refactor 2022-09-06 11:45:12 -03:00
Victor Radael 46d9fd8446 Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-09-06 10:10:05 -03:00
Victor Radael 1ca7e647d3 new local env 2022-09-06 10:07:56 -03:00
Gabriel Rosa 469f165cba DOCS: all deprecated fields on create input request 2022-09-06 09:17:24 -03:00
Gabriel Rosa 203a161879 Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-09-06 08:39:03 -03:00
Gabriel Rosa 31e9a07489 FIX: create input generic adjusted to new pipeline format 2022-09-06 08:38:46 -03:00
rodrigo.zamboni e24925036d Merge branch 'ft/connection-manager' of https://github.com/dadosfera/maestro into ft/connection-manager 2022-09-05 17:39:01 -03:00
rodrigo.zamboni 53f8f6986f FIX: fix default_value property parse 2022-09-05 17:38:22 -03:00
Gabriel Rosa 5e0a422b35 FIX: checking permission seqid on @AuthenticateCondition 2022-09-05 17:12:44 -03:00
rodrigo.zamboni 8294b5591b FIX: fix connectors permissions 2022-09-05 16:53:15 -03:00
rodrigo.zamboni 01d41a4586 FIX: fix merge conflicts 2022-09-05 16:22:34 -03:00
rodrigo.zamboni b8afdcf87d FIX: fixed permissions 2022-09-05 16:21:01 -03:00
Victor Radael fa216053c2 Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-09-05 15:54:40 -03:00
Victor Radael e9a4a77eae Local Connections 2022-09-05 15:53:45 -03:00
Gabriel Rosa fe041262eb FIX: pack metadata before sending to createConnection on connection-test 2022-09-05 15:35:09 -03:00
Victor Radael 7ef0ff1502 FIX: Transformations 2022-09-05 13:06:31 -03:00
Victor Radael d8c55def7e FIX: Transformations 2022-09-05 13:05:53 -03:00
rodrigo.zamboni dfcc3dcb53 FIX: fixed some merge conflicts 2022-09-05 11:30:16 -03:00
rodrigo.zamboni 080c8fc52a FIX: Ping route adapted to use connection_id 2022-09-05 11:01:18 -03:00
Victor Radael ecf0b1de51 FIX: Ad SSL 2022-09-05 09:37:04 -03:00
Victor Radael 2248dbe5a3 FIX: Get All Pipelines 2022-09-04 19:36:42 -03:00
Victor Radael f5ec6661ff FIX: Old Pipeline KeepCase 2022-09-02 20:17:23 -03:00
Victor Radael 0deee0ef9c FIX: Old Pipeline KeepCase 2022-09-02 20:15:15 -03:00
Victor Radael 85f79f14cd FIX: Pipeline Imports 2022-09-02 18:14:41 -03:00
Victor Radael 01bdf134ca FEAT: GET One Pipelinev2 2022-09-02 14:15:36 -03:00
Victor Radael 10a89632b5 Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-09-02 12:20:50 -03:00
Victor Radael 24d8f832fa Local Connections 2022-09-02 12:19:44 -03:00
Gabriel Rosa 8efe3d26f8 Add connection update permission (Internal only for now) 2022-09-02 09:11:52 -03:00
Victor Radael 6d21f29005 FEAT: Pipeline Version 2 2022-09-01 20:47:46 -03:00
Victor Radael e526180902 FEAT: Pipeline Version 2 2022-09-01 20:46:02 -03:00
Gabriel Rosa be37eb0321 New permissions 2022-09-01 17:49:38 -03:00
rodrigo.zamboni 8c85172554 Merge branch 'ft/connection-manager' of https://github.com/dadosfera/maestro into ft/connection-manager 2022-09-01 12:45:00 -03:00
rodrigo.zamboni 61296555fe FIX: not deleting failed connection when it comes from request body 2022-09-01 12:41:46 -03:00
Gabriel Rosa 5b6673a367 FIX: port can be either string or number on connection test ping 2022-09-01 09:15:06 -03:00
rodrigo.zamboni 2968647e73 FIX: add connection add parameter to function 2022-08-30 16:44:27 -03:00
rodrigo.zamboni a1a55d645a FIX: update protospack v2 version 2022-08-30 16:23:50 -03:00
rodrigo.zamboni b7748970cd FIX: Fix connectiontest ping dto 2022-08-30 15:37:11 -03:00
Victor Radael 8fb487435a FEAT: Connection Details new version 2022-08-26 19:25:01 -03:00
Victor Radael e94ace09d0 FEAT: Connection Details new version 2022-08-26 19:24:03 -03:00
Gabriel Rosa c713b65979 Better error handling on oauth 2022-08-23 16:14:57 -03:00
Gabriel Rosa 195fdae0e6 Saving oauth connections 2022-08-23 15:42:33 -03:00
Victor Radael 0f079a7b22 DOCS: Swagger 2022-08-23 15:03:13 -03:00
Victor Radael 93b44e8249 DOCS: Swagger 2022-08-23 15:01:28 -03:00
Victor Radael e18dc21670 Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-08-23 14:52:47 -03:00
Victor Radael ae443b5b03 DOCS: Swagger 2022-08-23 14:52:36 -03:00
Gabriel Rosa 3bfcc7a412 checking if env is local to disable ssl 2022-08-23 09:01:17 -03:00
Gabriel Rosa 09e3b3fd33 Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-08-22 11:35:22 -03:00
Gabriel Rosa 6b7500136f swagger back to normal 2022-08-22 11:35:08 -03:00
Victor Radael 7fa903fa1c FIX: Swagger 2022-08-22 11:27:46 -03:00
Victor Radael 19c35f5cc4 FIX: Swagger 2022-08-22 11:25:58 -03:00
Victor Radael 7b8b1bd8e0 FIX: Swagger 2022-08-22 11:22:41 -03:00
Gabriel Rosa 5cc2d704ea test swagger deploy 2022-08-22 11:13:22 -03:00
Gabriel Rosa d09bf96e6f FIX: added reference columns on get table metadata connection test 2022-08-22 10:23:06 -03:00
Victor Radael 0759f66144 FIX: Docs 2022-08-19 11:08:24 -03:00
Victor Radael 8bd5bf1526 FIX: Docs 2022-08-19 11:07:29 -03:00
Gabriel Rosa 9772e18332 Removed type and plugin from CreateNetworkConfigReq 2022-08-19 10:53:37 -03:00
Victor Radael 6f0f93d80d FIX: Docs Flow 2022-08-18 15:30:39 -03:00
Victor Radael 4b6d30859c FIX: Docs Flow 2022-08-18 15:24:30 -03:00
Victor Radael 5b4b1ae55e FIX: Docs Flow 2022-08-18 15:23:46 -03:00
Victor Radael 00dacfdbb9 FIX: Network_config 2022-08-18 14:22:14 -03:00
Victor Radael 7671567c8c FIX: Network_config 2022-08-18 14:21:46 -03:00
Victor Radael 64a8110649 FIX: Docs Flow 2022-08-18 12:03:31 -03:00
Victor Radael 4cbeea8281 Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-08-18 11:38:00 -03:00
Victor Radael adf9c11358 FIX: Docs Flow 2022-08-18 11:37:49 -03:00
Gabriel Rosa 033752789a FIX: connection test ping and connection test credentials 2022-08-17 19:25:03 -03:00
Victor Radael 71617612b9 DOCS: Add Docs to Docsfera 2022-08-17 18:43:14 -03:00
Victor Radael 6219d61fe1 DOCS: Add Docs to Docsfera 2022-08-17 18:32:47 -03:00
Victor Radael 2fd51804fc DOCS: Add Docs to Docsfera 2022-08-17 18:12:32 -03:00
Victor Radael 874a3aa3a0 FIX: Connection and Network Flows (Create and Delete) 2022-08-17 16:03:37 -03:00
Victor Radael a9f68b87ca FIX: Connection and Network Flows (Create and Delete) 2022-08-17 15:58:00 -03:00
Gabriel Rosa 6807b3e1a9 FEAT: inputs and transformation using protospack-v2 2022-08-16 10:18:54 -03:00
Victor Radael 5f17a7106f Update Network Config Manager 2022-08-15 14:49:54 -03:00
Victor Radael 0a0ecb20bb FIX: Swagger 2022-08-12 16:35:36 -03:00
Victor Radael 35abb24ea7 FIX: Swagger 2022-08-12 16:21:26 -03:00
Victor Radael 372fc74bcb FEAT: Managers 2022-08-12 14:47:44 -03:00
Victor Radael 626f785994 O auth module 2022-08-12 13:57:44 -03:00
Victor Radael f88f559b70 Remove Separated Clients 2022-08-12 13:36:20 -03:00
Victor Radael 3981751ac0 Transformations Refactor 2022-08-12 12:49:40 -03:00
Victor Radael 61752a547f Pipelines Refactor 2022-08-12 12:38:34 -03:00
Victor Radael 3356f306b3 Client Refactor 2022-08-12 12:24:22 -03:00
Victor Radael 6dd894e11b Client Refactor 2022-08-12 12:22:41 -03:00
Victor Radael 7a1b5c7dbf Duc Client Refactor 2022-08-12 12:13:04 -03:00
Victor Radael afc187d01a Merge Input Refactor 2022-08-12 10:44:09 -03:00
Victor Radael d0cd62cd3c Merge Input Refactor 2022-08-12 10:43:20 -03:00
Victor Radael acd4dafc57 Update feature 2022-08-12 10:38:20 -03:00
Gabriel Rosa d8ce82793d REFACTOR: removed inputs separated client service 2022-08-11 17:39:50 -03:00
Gabriel Rosa 117704cd8c REFACTOR: inputs inside its own module 2022-08-11 14:28:10 -03:00
Gabriel Rosa 430e09c159 removed some unused tests and new test config 2022-08-11 10:08:06 -03:00
Gabriel Rosa fa11df5684 FIX: create network_config type and plugin default values 2022-08-10 12:33:35 -03:00
Gabriel Amorim e9b85537d7 Merge pull request #129 from dadosfera/feat/role-usage
FEAT: role usage
2022-08-09 09:38:09 -03:00
Gabriel Rosa 17060332fd new protospack release 2022-08-09 09:34:52 -03:00
Gabriel Rosa fde6d0a74c remove unused imports 2022-08-08 12:07:43 -03:00
Gabriel Rosa 0ca6ed8636 MERGE MAIN 2022-08-08 12:07:37 -03:00
Victor Radael 7c5cf3f541 Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-08-08 11:01:50 -03:00
Victor Radael 54f4331bcc Update Managers 2022-08-08 10:55:22 -03:00
Gabriel Rosa 2f006c607c FIX: add usage on interfaces 2022-08-05 16:32:10 -03:00
Gabriel Rosa 9fbbfc2064 FIX: new protospack and better roles error handling 2022-08-05 16:20:20 -03:00
arthur simas ba12d45bf7 Merge pull request #128 from dadosfera/feat/snowflake-sso
FEAT: snowflake single sign-on
2022-08-04 17:40:35 -03:00
Arthur Simas ec418b00e7 FIX: relay state in response 2022-08-04 11:29:05 -03:00
Arthur Simas 89a02a4e8a FIX: added snowflake sso relaystate field 2022-08-04 11:11:42 -03:00
Gabriel Rosa cbee264182 FIX: Create VPN using multipart form data to fetch file 2022-08-03 16:30:32 -03:00
Gabriel Rosa 2514245a44 Merge main and conflicts solving 2022-08-03 13:36:31 -03:00
Gabriel Rosa 0761c42041 removed unused import 2022-08-03 11:34:02 -03:00
Gabriel Rosa 688bf49f3b FEAT: Connection test creating connection
- If any error occurs, connection is deleted
 - If operation_result is false, connection is deleted
2022-08-03 11:31:57 -03:00
Gabriel Rosa a1cdad42ab FIX: fixed tests modules 2022-08-03 10:37:17 -03:00
Gabriel Rosa 7546e6100d MERGE MAIN 2022-08-03 10:36:57 -03:00
Arthur Simas 7cf178db42 FEAT: fake commit 2022-08-02 16:50:35 -03:00
Arthur Simas 2673e75f81 CHORE: protospack-v2 bumped 2022-08-02 16:13:12 -03:00
Arthur Simas 6382939e1e FEAT: snowflake sso 2022-08-02 15:27:18 -03:00
arthur simas 3bea2e4cda Merge pull request #124 from dadosfera/feat/permissions
FEAT: permissions updated
2022-08-02 14:57:40 -03:00
Arthur Simas d9a7555d01 Merge branch 'main' into feat/permissions 2022-08-02 14:49:25 -03:00
arthur simas 5122dbde85 Merge pull request #126 from dadosfera/feat/scoped-packages
FEAT: scoped packages
2022-08-02 14:43:07 -03:00
Victor Radael 4e6883a404 Update Protospack Name and Network Config 2022-08-02 11:47:13 -03:00
Arthur Simas dcb3094890 FIX: protospack-v2 changes 2022-08-01 17:05:00 -03:00
Arthur Simas c8e4e90100 FIX: aws codeartifact region 2022-08-01 15:52:30 -03:00
Arthur Simas 09cff9fa15 CI: cleanup ci tests 2022-08-01 15:52:24 -03:00
Arthur Simas 79b624cea6 FEAT: using scoped package @dadosfera/dadosfera-logs 2022-08-01 15:52:18 -03:00
Arthur Simas 5356334258 FEAT: using scoped package @dadosfera/protospack-v2 2022-08-01 15:52:06 -03:00
Gabriel Amorim 5f6e4e88a5 Merge pull request #125 from dadosfera/fix/users-roles-management
FIX: sending access token to role function to evaluate editing permissions
2022-08-01 15:30:28 -03:00
Gabriel Rosa 32ab834834 FIX: fix user.decorator tests failing because of missing access_token on fakeUserPayload 2022-08-01 13:46:27 -03:00
Gabriel Rosa ebbfe0abff FIX: sending access token to role function to evaluate editing permissions 2022-08-01 09:17:08 -03:00
Arthur SimasandBeatriz Antunes 4fb24d5b5c FEAT: permissions updated
Co-Authored-By: Beatriz Antunes <beatrizaantunes@gmail.com>
2022-07-29 13:39:38 -03:00
arthur simas d76a2b4ab8 Merge pull request #123 from dadosfera/feat/user-management
FEAT: user management
2022-07-28 19:24:50 -03:00
Arthur Simas 047737eadd FIX: removing log from subscribe.complete method 2022-07-28 19:21:16 -03:00
Victor Radael 00687dc84e Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-07-28 17:31:38 -03:00
Victor Radael 61a1939c02 Save Connection Changes 2022-07-28 17:30:10 -03:00
Gabriel Rosa 43cec9b6fa FEAT: network config module using in-factory 2022-07-28 15:41:21 -03:00
Gabriel Rosa 97214280bc FEAT: network config module 2022-07-28 10:43:21 -03:00
Arthur Simas e20ae71672 FIX: resend invite endpoint renamed 2022-07-27 19:35:25 -03:00
Arthur Simas 97b6047cf1 FIX: avoiding to change user object received in adjustUsersPayload, returning modified object instead 2022-07-27 19:20:35 -03:00
Arthur Simas 9c6d2b499a FEAT: resend invite 2022-07-27 18:15:07 -03:00
Victor Radael 0de4a72388 Add OpenSearch 2022-07-27 15:56:04 -03:00
Victor Radael f65f1d01ce Add OpenSearch 2022-07-27 15:54:29 -03:00
Gabriel Rosa 6161865f1a FIX: Add authentication on connection-test routes 2022-07-27 14:25:25 -03:00
Gabriel Rosa d28684a9d0 Connected Connection Test routes to microservice 2022-07-27 14:19:25 -03:00
Arthur Simas f43c270c33 CHORE: protospack-v2 pre-release 2022-07-27 12:51:07 -03:00
Arthur Simas b0ccb39f2c FIX: adding error message on each failed user (BatchCreateUserRes) 2022-07-27 12:46:20 -03:00
Gabriel Rosa 54c2a41466 Merge branch 'ft/connection-manager' of github.com:dadosfera/maestro into ft/connection-manager 2022-07-27 08:42:33 -03:00
Gabriel Rosa 037f5cfec0 FEAT: new conection test module 2022-07-27 08:41:32 -03:00
Victor Radael 22631478b9 CRUD Connection 2022-07-25 17:08:01 -03:00
Gabriel Rosa 9f900882cb FIX: sending customerId on updateUser 2022-07-25 10:09:18 -03:00
Gabriel Rosa a24abed9ed updated protospack version 2022-07-22 08:53:27 -03:00
Gabriel Rosa b04a38bcc0 FIX: get departments and jobTitles 2022-07-22 08:45:58 -03:00
Victor Radael 349ae780a7 FEAT: Connection Manager 2022-07-21 15:19:05 -03:00
Victor Radael 60fb2ee7cb FEAT: Connection Manager 2022-07-21 09:31:37 -03:00
Gabriel Rosa 67706c5fc3 FIX: returning hierarchies the right way 2022-07-20 16:58:53 -03:00
Gabriel Rosa 0fa4dcb933 new protospack version 2022-07-20 15:37:01 -03:00
Gabriel Rosa 04284e1feb FIX: changing hierarchy strategy 2022-07-20 15:18:14 -03:00
Gabriel Rosa 3e7581e20c FIX: changing hierarchy strategy 2022-07-20 15:17:58 -03:00
Gabriel Rosa c61c37b268 FIX: new user columns 2022-07-20 09:50:58 -03:00
Gabriel Rosa 5ce8099c25 tests fixes 2022-07-19 16:22:24 -03:00
Gabriel Rosa 9cdb0a5d38 FIX: Update user accepting roleIds 2022-07-19 10:17:57 -03:00
Gabriel Rosa 57f47d3b2e FIX: get all hierarchies 2022-07-18 18:20:15 -03:00
Gabriel Rosa 4ab955a7a1 removed unused import 2022-07-18 18:00:44 -03:00
Gabriel Rosa 1ca3694b75 merge main 2022-07-18 18:00:18 -03:00
Gabriel Rosa a6a35c507a new Protospack 2022-07-18 17:56:50 -03:00
Gabriel Rosa cfcb8c1c42 FEAT: new user endpoints 2022-07-18 17:50:12 -03:00
Gabriel Rosa a55da8e20f FEAT: batch create user 2022-07-18 15:37:56 -03:00
Gabriel Rosa 82310c6314 FEAT: Users roles id = seqid 2022-07-18 14:04:35 -03:00
Gabriel Rosa 52f9d06ad0 FIX: get permissions route 2022-07-18 11:24:52 -03:00
Victor Radael a83f91a720 Merge pull request #122 from dadosfera/ft/connectors-manager
FEAT: Ft/connectors manager
2022-07-15 18:46:01 -03:00
Victor Radael ccef7628f9 FIX: Remove AuthController 2022-07-15 18:00:09 -03:00
Victor Radael a5e424c854 Update app.module.ts 2022-07-15 17:53:38 -03:00
Gabriel Rosa 339432df16 FIX: server urls on swagger 2022-07-15 15:24:42 -03:00
Victor Radael 7dfa10d5ee Merge branch 'ft/connectors-manager' of github.com:dadosfera/maestro into ft/connectors-manager 2022-07-15 15:10:40 -03:00
Victor Radael c87ceec77b FIX: Upload Imaga Files and add permissions 2022-07-15 15:10:11 -03:00
Gabriel Rosa 071c524a2e FIX: changed get roles to search roles 2022-07-15 14:39:30 -03:00
Gabriel Rosa 1de4eedd38 FEAT: new permission for user management 2022-07-15 12:27:49 -03:00
Gabriel Rosa 29276d6070 Merge branch 'main' into feat/user-management 2022-07-15 11:42:13 -03:00
Gabriel Rosa 344a251de1 merge main 2022-07-15 11:42:01 -03:00
Arthur Simas 3b95032554 Merge branch 'main' into ft/connectors-manager 2022-07-15 11:24:46 -03:00
arthur simas a0089b5d5d Merge pull request #121 from dadosfera/fix/terms-of-use-ip
FIX: terms of use ip:port
2022-07-15 11:15:12 -03:00
Gabriel Rosa 1b620b6fb0 FEAT: ROle management 2022-07-15 11:08:57 -03:00
Arthur Simas 1eb76d4b1c FIX: terms of use ip:port 2022-07-15 11:08:46 -03:00
Victor Radael 314bc5a562 Merge remote-tracking branch 'origin' into ft/connectors-manager 2022-07-14 17:34:17 -03:00
Victor Radael d01b0357ed FIX: Remove logs and add Authenticated 2022-07-14 17:31:12 -03:00
arthur simas a206aad8db Merge pull request #120 from dadosfera/feature/terms-of-use
FEAT: terms of use
2022-07-14 14:50:01 -03:00
Gabriel Rosa de57bfed1e FEAT: new roles routes working 2022-07-14 12:53:00 -03:00
Gabriel Rosa 14cfc46492 FEAT: Roles WIP 2022-07-14 10:23:04 -03:00
Victor Radael 9d10e58b1b FIX: SSL 2022-07-13 14:14:48 -03:00
Victor Radael 6dec2c1e56 FIX: Header Dadosfera-Lang 2022-07-13 14:11:35 -03:00
Victor Radael 23a65d18a6 Search Adapt fields 2022-07-12 17:04:25 -03:00
Gabriel Rosa d5cd562860 FEAT: get permissions working 2022-07-12 15:43:21 -03:00
Gabriel Rosa f5064420a7 FIX: missing import 2022-07-12 14:48:01 -03:00
Gabriel Rosa bb5befb2f6 FEAT: new route for updating Roles and changed hierarchy to string 2022-07-12 14:27:54 -03:00
Gabriel Rosa 398360fadb FEAT: new routes do add or remove permisisons from role 2022-07-12 12:11:03 -03:00
Victor Radael 13072978f5 FEAT: Accept-Language 2022-07-12 09:21:45 -03:00
Gabriel Rosa b9612609d9 FIX: add description on create role documentation 2022-07-11 16:58:40 -03:00
Victor Radael e7b37629a1 Insomnia File 2022-07-11 14:08:25 -03:00
Victor Radael 5b6994b247 Merge remote-tracking branch 'origin/main' into ft/connectors-manager 2022-07-11 12:26:02 -03:00
Gabriel Rosa 039f837914 FIX: tests fixing 2022-07-11 11:07:08 -03:00
Gabriel Rosa 83dcc7942c FIX: better code organization 2022-07-11 10:42:01 -03:00
Gabriel Rosa 5c079bb4f5 FIX: permissions contract 2022-07-11 10:09:06 -03:00
Arthur Simas f383cf49d5 FIX: added get token method 2022-07-11 02:13:53 -03:00
Arthur Simas db78ee3d8b FEAT: terms of use 2022-07-11 02:13:33 -03:00
Gabriel Rosa 730fab8ed1 FEAT: internationalization of permissions 2022-07-08 19:03:32 -03:00
Victor Radael 04e1e1ff2b New features to Connector's Search 2022-07-08 18:33:58 -03:00
Victor Radael d309c20cbf New features to Connector's Search 2022-07-08 18:32:06 -03:00
Gabriel Rosa 4cff593695 FEAT: Roles and permissions modules 2022-07-08 17:28:23 -03:00
Victor Radael 03d42df3fd Att Modules 2022-07-08 13:06:26 -03:00
Gabriel Rosa ea04f59e04 FIX: Fixed create user req 2022-07-08 12:28:40 -03:00
Gabriel Rosa d1961a9710 FEAT: User Management WIP 2022-07-08 12:04:56 -03:00
Gabriel Rosa 358dd6a15a merge main 2022-07-08 10:08:22 -03:00
arthur simas cc3b34d87e Merge pull request #119 from dadosfera/fix/error-handling
FIX: added exception filter to catch unhandled errors
2022-07-07 20:28:44 -03:00
Arthur Simas 88bc7fe625 FIX: added exception filter to catch unhandled errors 2022-07-07 20:24:27 -03:00
Gabriel Amorim 137f129e13 Merge pull request #118 from dadosfera/conditional-apm-import
FIX: Conditional apm import
2022-07-07 20:22:55 -03:00
Gabriel Rosa f49c5ac1c1 FIX: conditionally importing apm 2022-07-07 20:04:42 -03:00
Gabriel Rosa d288a4f357 FIX: conditionally importing apm 2022-07-07 18:18:53 -03:00
Gabriel Rosa 9f009309cb FIX: conditionally importing apm 2022-07-07 17:51:28 -03:00
Victor Radael 395db05b05 Merge main 2022-07-07 17:17:57 -03:00
Victor Radael 2d69e6db70 Merge main 2022-07-07 17:13:30 -03:00
Victor Radael 9514134db1 Merge main 2022-07-07 16:58:33 -03:00
Victor Radael 0c69cebca1 Merge main 2022-07-07 16:55:52 -03:00
Victor Radael 9791b8bdb0 Merge main 2022-07-07 16:55:04 -03:00
Victor Radael 6803ab3420 Merge main 2022-07-07 16:36:28 -03:00
Victor Radael 6aa7be98d2 Merge main 2022-07-07 16:32:17 -03:00
Gabriel Rosa f5665557c9 FIX: better parameter naming 2022-07-07 16:17:45 -03:00
arthur simas 366987399e Merge pull request #117 from dadosfera/refactor/protospack-v2
FEAT: protospack-v2 updated
2022-07-07 16:05:00 -03:00
Gabriel Rosa 4356adea65 FEAT: User module init 2022-07-07 15:57:40 -03:00
Arthur Simas 4c49dbc0ea FEAT: protospack-v2 updated 2022-07-07 15:00:59 -03:00
Victor Radael 8d23eaeea2 Code artifact and Get Connectors Tags 2022-06-30 16:55:46 -03:00
138 changed files with 14712 additions and 3710 deletions
+66 -12
View File
@@ -6,12 +6,12 @@ on:
workflow_dispatch:
inputs:
environment:
description: 'Deployment environment'
description: "Deployment environment"
required: true
type: choice
options:
- dev
- stg
- stg2
- prd
jobs:
@@ -26,9 +26,9 @@ jobs:
- name: Extract Environment
run: |
if [ ${EVENT} == "workflow_dispatch" ]; then
echo "##[set-output name=environment;]$(echo ${DEPLOY_ENV})"
echo "environment=${DEPLOY_ENV}" >> $GITHUB_OUTPUT
elif [ ${GITHUB_REF} == "refs/heads/main" ]; then
echo "##[set-output name=environment;]$(echo "prd")"
echo "environment=prd" >> $GITHUB_OUTPUT
fi
id: extract_environment
@@ -39,7 +39,7 @@ 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@v2
uses: actions/checkout@v3
- if: github.event_name != 'workflow_dispatch'
name: Semantic Release
@@ -56,20 +56,26 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
deploy:
if: ${{ github.event_name == 'workflow_dispatch' || needs.semantic_release.outputs.new_release_published == 'true' }}
deploy-info:
if: ${{ github.event_name == 'workflow_dispatch'}}
needs: [extract_environment, semantic_release]
runs-on:
[self-hosted, '${{ needs.extract_environment.outputs.environment }}']
runs-on: ubuntu-latest
steps:
- name: Printing stats
- name: Create summary
env:
EVENT: ${{ github.event_name }}
IMAGE_TAG: ${{ needs.semantic_release.outputs.new_release_version }}
ENV: ${{ needs.extract_environment.outputs.environment }}
run: echo ${GITHUB_REF#refs/heads/}
run: echo "### Deploy da branch \`$GITHUB_REF_NAME\` no ambiente **$ENV** :rocket:" >> $GITHUB_STEP_SUMMARY
deploy:
if: ${{ github.event_name == 'workflow_dispatch' || needs.semantic_release.outputs.new_release_published == 'true' }}
needs: [extract_environment, semantic_release]
runs-on:
[self-hosted, "${{ needs.extract_environment.outputs.environment }}"]
steps:
- name: Checkout
uses: actions/checkout@v2
@@ -90,7 +96,7 @@ jobs:
python3 -m pip install awsebcli --upgrade
- name: Configure AWS Region
uses: aws-actions/configure-aws-credentials@v1
uses: aws-actions/configure-aws-credentials@v1-node16
id: aws
with:
aws-region: us-east-1
@@ -113,10 +119,12 @@ jobs:
ENV: ${{ needs.extract_environment.outputs.environment }}
IMAGE_TAG: ${{ needs.semantic_release.outputs.new_release_version }}
ACCOUNT_ID: ${{ steps.aws.outputs.aws-account-id }}
NODE_EXPORTER_URL: ${{needs.extract_environment.outputs.environment == 'prd' && '611330257153.dkr.ecr.us-east-1.amazonaws.com\/monitoring\/node_exporter:latest' || '468720548566.dkr.ecr.us-east-1.amazonaws.com\/monitoring\/node_exporter:latest'}}
run: |
sed -i -e "s/\${ENV}/$ENV/g" docker-compose.yml
sed -i -e "s/\${IMAGE_TAG}/$IMAGE_TAG/g" docker-compose.yml
sed -i -e "s/\${ACCOUNT_ID}/$ACCOUNT_ID/g" docker-compose.yml
sed -i -e "s/\${NODE_EXPORTER_URL}/$NODE_EXPORTER_URL/g" docker-compose.yml
zip deploy.zip docker-compose.yml -r .ebextensions
- name: Deploy AWS Beanstalk
@@ -134,3 +142,49 @@ jobs:
run: |
docker system prune --volumes -a -f
docker system df
api_docs:
needs: [extract_environment, semantic_release, deploy]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Extract Docs BlockId and PageId
env:
ENV: ${{ needs.extract_environment.outputs.environment }}
STG2_DOCS_BLOCK_ID: ${{ secrets.DEV_DOCS_BLOCK_ID }}
STG2_DOCS_PAGE_ID: ${{ secrets.DEV_DOCS_PAGE_ID }}
STG_DOCS_BLOCK_ID: ${{ secrets.STG_DOCS_BLOCK_ID }}
STG_DOCS_PAGE_ID: ${{ secrets.STG_DOCS_PAGE_ID }}
PRD_DOCS_BLOCK_ID: ${{ secrets.PRD_DOCS_BLOCK_ID }}
PRD_DOCS_PAGE_ID: ${{ secrets.PRD_DOCS_PAGE_ID }}
shell: bash
run: |
if [ $ENV == "stg2" ]; then
echo "block_id=$STG2_DOCS_BLOCK_ID" >> $GITHUB_OUTPUT
echo "page_id=$STG2_DOCS_PAGE_ID" >> $GITHUB_OUTPUT
elif [ $ENV == "stg" ]; then
echo "block_id=$STG_DOCS_BLOCK_ID" >> $GITHUB_OUTPUT
echo "page_id=$STG_DOCS_PAGE_ID" >> $GITHUB_OUTPUT
elif [ $ENV == "prd" ]; then
echo "block_id=$PRD_DOCS_BLOCK_ID" >> $GITHUB_OUTPUT
echo "page_id=$PRD_DOCS_PAGE_ID" >> $GITHUB_OUTPUT
fi
id: extract_docs_info
- name: Generate API docs
env:
DOCS_URL: ${{ secrets.DOCS_URL }}
DOCS_API_TOKEN: ${{ secrets.DOCS_API_TOKEN }}
DOCS_PAGE_ID: ${{ steps.extract_docs_info.outputs.page_id }}
DOCS_BLOCK_ID: ${{ steps.extract_docs_info.outputs.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.json
fi
sed -i -e "s/\${DOCS_API_TOKEN}/$DOCS_API_TOKEN/g" docsfera.json
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
+3 -15
View File
@@ -11,30 +11,18 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Install Docker Compose
run: |
python3 -m pip install docker-compose --upgrade
- name: Build
env:
ENV: test
IMAGE_TAG: test
APP_NAME: ${{ github.event.repository.name }}
run: |
export ENV=test
export IMAGE_TAG=test
export ACCOUNT_ID=test
docker-compose -f build.docker-compose.yml build
docker build -t $APP_NAME --target test .
- name: Run Test
env:
ENV: test
IMAGE_TAG: test
ACCOUNT_ID: test
APP_NAME: ${{ github.event.repository.name }}
run: |
export ENV=test
export IMAGE_TAG=test
docker-compose -f build.docker-compose.yml run --rm --entrypoint="npm run test" $APP_NAME
docker run --rm --entrypoint="npm" $APP_NAME run test
- name: Remove Docker's Trash
if: always()
+1 -1
View File
@@ -37,4 +37,4 @@ lerna-debug.log*
# Ignore .env files
*.env
.env
.env
+22
View File
@@ -0,0 +1,22 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug NestJs",
"request": "launch",
"runtimeArgs": [
"run",
"start:debug"
],
"runtimeExecutable": "npm",
"skipFiles": [
"<node_internals>/**"
],
"type": "node",
"console": "integratedTerminal"
}
]
}
+12 -7
View File
@@ -1,16 +1,21 @@
# install all dependencies
FROM node:18.3.0-alpine3.15 as packages
WORKDIR /packages
COPY package.json .
COPY package-lock.json .
RUN apk update \
&& apk add --no-cache aws-cli \
&& aws codeartifact login --tool npm --repository dadosfera-npm --domain dadosfera --domain-owner 611330257153 --region us-east-1 \
WORKDIR /app
COPY package.json package-lock.json ./
RUN apk add --no-cache aws-cli \
&& aws codeartifact login --tool npm --namespace @dadosfera --repository dadosfera-npm --domain dadosfera --domain-owner 611330257153 --region us-east-1 \
&& npm install
# unit test specific build
FROM node:18.3.0-alpine3.15 as test
WORKDIR /app
COPY --from=packages /app/node_modules ./node_modules
COPY . ./
FROM node:18.3.0-alpine3.15
WORKDIR /app
COPY . /app/
COPY --from=packages /packages/node_modules /app/node_modules
COPY --from=packages /app/node_modules ./node_modules
RUN npm run build
EXPOSE 3333
ENTRYPOINT npm run start
Binary file not shown.
+4 -4
View File
@@ -110,7 +110,7 @@ This decorator requires that **all permissions** listed are granted to the reque
```ts
import { RequireAllPermissions } from '../../authentication/authentication.decorator';
import { Permissions } from '../../authentication/permissions.enum';
import { PERMISSIONS } from '../../authentication/permissions.enum';
@Controller('foo')
class FooController {
@@ -129,7 +129,7 @@ In the following case, the user is required to have **at least one** listed perm
```ts
import { RequireSomePermission } from '../../authentication/authentication.decorator';
import { Permissions } from '../../authentication/permissions.enum';
import { PERMISSIONS } from '../../authentication/permissions.enum';
@Controller('foo')
@RequireSomePermission(Permissions.FOO.MANAGE, Permissions.FOO.CREATE)
@@ -184,7 +184,7 @@ class FooController {
RequireSomePermission,
AuthenticateCondition,
} from '../../authentication/authentication.decorator';
import { Permissions } from '../../authentication/permissions.enum';
import { PERMISSIONS } from '../../authentication/permissions.enum';
import { Waa, Baz } from './authenticationFunctions'
@Controller('foo')
@@ -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:
+1 -1
View File
@@ -10,7 +10,7 @@ services:
- .env
node_exporter:
image: prom/node-exporter:v1.3.1
image: ${NODE_EXPORTER_URL}
container_name: node_exporter
restart: always
volumes:
+5896
View File
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
import type { Config } from '@jest/types';
const config: Config.InitialOptions = {
moduleFileExtensions: ['ts', 'js', 'json'],
modulePaths: ['<rootDir>'],
roots: ['<rootDir>/src/', '<rootDir>/test/'],
testRegex: '.*\\.(test|spec)\\.[jt]s$',
transform: { '\\.[jt]s$': 'ts-jest' },
collectCoverageFrom: ['**/*.[jt]s'],
coverageDirectory: 'coverage',
coveragePathIgnorePatterns: [
'<rootDir>/node_modules/',
'.*\\.module\\.[jt]s$',
],
// moduleDirectories: ['node_modules'], // default is already 'node_modules'
// rootDir: '.', //No need
// testEnvironment: 'node', //Defaults to 'node'
};
export default config;
+5 -1
View File
@@ -3,7 +3,11 @@
"sourceRoot": "src",
"compilerOptions": {
"assets": [
"**/*.proto"
"**/*.proto",
{
"include": "i18n/**/*",
"watchAssets": true
}
],
"plugins": [
"@nestjs/swagger"
+345 -288
View File
File diff suppressed because it is too large Load Diff
+12 -24
View File
@@ -9,13 +9,15 @@
"node": "18.3.0"
},
"scripts": {
"preinstall": "aws codeartifact login --tool npm --namespace @dadosfera --repository dadosfera-npm --domain dadosfera --domain-owner 611330257153 --region us-east-1",
"proto-update": "npm i @dadosfera/protospack-v2@latest --save-exact",
"prebuild": "rimraf dist",
"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": "node dist/main",
"start:prod": "npm run build && node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
@@ -25,6 +27,8 @@
},
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.112.0",
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
"@dadosfera/protospack-v2": "3.27.1",
"@grpc/grpc-js": "^1.6.7",
"@grpc/proto-loader": "^0.6.13",
"@nestjs/common": "^8.4.7",
@@ -36,22 +40,23 @@
"@nestjs/platform-express": "^8.4.7",
"@nestjs/schedule": "^1.1.0",
"@nestjs/swagger": "^5.2.1",
"axios": "^0.25.0",
"axios": "^0.27.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"cron-parser": "^4.4.0",
"dadosfera-logs": "^1.0.0-alpha.10",
"dotenv": "^14.3.2",
"elastic-apm-node": "^3.36.0",
"helmet": "^5.1.0",
"jsonwebtoken": "^8.5.1",
"jsonwebtoken": "^9.0.0",
"jwk-to-pem": "^2.0.5",
"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",
"protospack": "2.5.1",
"protospack-v2": "1.1.1",
"protospack": "2.5.2",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.5.5",
@@ -89,22 +94,5 @@
"ts-node": "^10.8.1",
"tsconfig-paths": "^3.14.1",
"typescript": "^4.6.3"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
+40 -93
View File
@@ -1,82 +1,35 @@
import { Module } from '@nestjs/common';
import { ClientsModule } from '@nestjs/microservices';
import { ConfigModule } from '@nestjs/config';
import { DadosferaLogger } from 'dadosfera-logs';
import { InputsController } from './modules/inputs/inputs.controller';
import { TransformationsController } from './modules/transformations/transformations.controller';
import { OutputsController } from './modules/outputs/outputs.controllers';
import { PipelinesController } from './modules/pipelines/pipelines.controller';
import { HealthController } from './modules/health/health.controller';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { InputsService } from './modules/inputs/inputs.service';
import { TransformationsService } from './modules/transformations/transformations.service';
import { OutputsService } from './modules/outputs/outputs.service';
import { PipelinesService } from './modules/pipelines/pipelines.service';
import { HealthService } from './modules/health/health.service';
import { AuthModule } from './modules/auth/auth.module';
import { InputsClientService } from './clients/inputs/client.service';
import { TransformationsClientService } from './clients/transformations/client.service';
import { OutputsClientService } from './clients/outputs/client.service';
import { PipelinesClientService } from './clients/pipelines/client.service';
import { PermissionsModule } from './modules/permissions/permissions.module';
import { OutputsClientConfiguration } from './clients/outputs/client.config';
import { TransformationsClientConfiguration } from './clients/transformations/client.config';
import { InputsClientConfiguration } from './clients/inputs/client.config';
import { PipelinesClientConfiguration } from './clients/pipelines/client.config';
import { CatalogController } from './modules/catalog/catalog.controller';
import { CatalogService } from './modules/catalog/catalog.service';
import { OauthController } from './modules/oauth/oauth.controller';
import { getOauthSecrets } from './utils/OauthSecrets';
import { HubspotStrategy } from './modules/oauth/passport-strategies/hubspot-strategy';
import { FacebookStrategy } from './modules/oauth/passport-strategies/facebook-strategy';
import { AuthenticationGuard } from './authentication/authentication.guard';
import { APP_GUARD } from '@nestjs/core';
import { GoogleStrategy } from './modules/oauth/passport-strategies/google-strategy';
import { MailChimpStrategy } from './modules/oauth/passport-strategies/mailchimp-strategy';
import { SalesforceStrategy } from './modules/oauth/passport-strategies/salesforce-strategy';
import { ConnectorClientConfiguration } from './clients/connector/client.config';
import { ConnectorController } from './modules/connector/connector.controller';
import { ConnectorClientService } from './clients/connector/client.service';
const inputClient = new InputsClientConfiguration();
const outputClient = new OutputsClientConfiguration();
const pipelineClient = new PipelinesClientConfiguration();
const transformationClient = new TransformationsClientConfiguration();
const connectorClient = new ConnectorClientConfiguration();
import { APP_GUARD } from '@nestjs/core';
import { UsersModule } from './modules/users/users.module';
import { RolesModule } from './modules/roles/roles.module';
import { ConnectorModule } from './modules/connector/connector.module';
import { AuthModule } from './modules/auth/auth.module';
import { PermissionsModule } from './modules/permissions/permissions.module';
import { TermsOfUseModule } from './modules/termsOfUse/termsOfUse.module';
import { ConnectionModule } from './modules/connection/connection.module';
import { ConnectionTestModule } from './modules/connection-test/connection-test.module';
import { NetworkConfigModule } from './modules/network-config/network-config.module';
import { InputsModule } from './modules/inputs/inputs.module';
import { OauthModule } from './modules/oauth/oauth.module';
import { PipelinesModule } from './modules/pipelines/pipelines.module';
import { TransformationsModule } from './modules/transformations/transformations.module';
import { HealthModule } from './modules/health/health.module';
import { CatalogModule } from './modules/catalog/catalog.module';
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';
@Module({
controllers: [
InputsController,
TransformationsController,
OutputsController,
PipelinesController,
HealthController,
CatalogController,
OauthController,
ConnectorController,
],
controllers: [],
providers: [
DadosferaLogger,
{ provide: 'OAUTH_SECRETS', useValue: getOauthSecrets() },
InputsService,
TransformationsService,
OutputsService,
PipelinesService,
ConnectorClientService,
HealthService,
InputsClientService,
TransformationsClientService,
OutputsClientService,
PipelinesClientService,
CatalogService,
HubspotStrategy,
FacebookStrategy,
GoogleStrategy,
MailChimpStrategy,
SalesforceStrategy,
{
provide: APP_GUARD,
useClass: AuthenticationGuard,
@@ -87,30 +40,24 @@ const connectorClient = new ConnectorClientConfiguration();
isGlobal: true,
}),
AuthModule,
ConnectorModule,
PermissionsModule,
ClientsModule.register([
{
name: 'INPUTS_PACKAGE',
...inputClient.config(),
},
{
name: 'TRANSFORMATIONS_PACKAGE',
...transformationClient.config(),
},
{
name: 'OUTPUTS_PACKAGE',
...outputClient.config(),
},
{
name: 'PIPELINES_PACKAGE',
...pipelineClient.config(),
},
{
name: 'CONNECTOR_PACKAGE',
...connectorClient.config(),
},
]),
TermsOfUseModule,
ConnectionModule,
NetworkConfigModule,
ConnectionTestModule,
PipelinesModule,
PipelinesV2Module,
TransformationsModule,
HealthModule,
CatalogModule,
UsersModule,
RolesModule,
InputsModule,
OauthModule,
CatalogModule,
ProductboardModule,
MixpanelModule,
],
})
export class AppModule {}
@@ -1,6 +1,6 @@
import { Request } from 'express';
import { CustomDecorator } from '@nestjs/common';
import { Permission } from './permissions.enum';
import { PermissionsObjectPermission } from './permissions.enum';
import { RequestUser } from './user.decorator';
export const AUTH_FUNCTION_KEY = '__AUTH_FUNCTION__';
@@ -31,13 +31,17 @@ function SetMultipleMetadata(metadataKey, metadataValue): CustomDecorator {
return decoratorFactory as any;
}
export function RequireAllPermissions(...permissions: Permission[]) {
export function RequireAllPermissions(
...permissions: PermissionsObjectPermission[]
) {
return SetMultipleMetadata(AUTH_FUNCTION_KEY, (req, user: RequestUser) =>
permissions.every(({ seqid }) => user.permissions.includes(seqid)),
);
}
export function RequireSomePermission(...permissions: Permission[]) {
export function RequireSomePermission(
...permissions: PermissionsObjectPermission[]
) {
return SetMultipleMetadata(AUTH_FUNCTION_KEY, (req, user: RequestUser) =>
permissions.some(({ seqid }) => user.permissions.includes(seqid)),
);
+22 -12
View File
@@ -5,7 +5,7 @@ import { APP_GUARD } from '@nestjs/core';
import jwt from 'jsonwebtoken';
import { Body, Controller, Get } from '@nestjs/common';
import { DadosferaLogger } from 'dadosfera-logs';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import {
AuthenticateCondition,
Authenticated,
@@ -13,11 +13,15 @@ import {
RequireSomePermission,
} from './authentication.decorator';
import { AuthenticationGuard } from './authentication.guard';
import { Permissions } from './permissions.enum';
import { PERMISSIONS_GROUPS } from './permissions.enum';
import { AuthClientService } from '../modules/auth/auth.service';
import ErrorCodes from '../utils/errorCodes';
const logger = {
info: (...args) => args,
error: (...args) => args,
};
@Controller('no-class-auth')
class NoClassAuthController {
@Get('body')
@@ -32,19 +36,25 @@ class NoClassAuthController {
}
@Get('required-permission')
@RequireSomePermission(Permissions.ZENDESK.OPEN)
@RequireSomePermission(PERMISSIONS_GROUPS.ZENDESK.permissions.OPEN)
async requiredPermission(@Body() body) {
return { body };
}
@Get('has-all-permissions')
@RequireAllPermissions(Permissions.ZENDESK.OPEN, Permissions.METABASE.OPEN)
@RequireAllPermissions(
PERMISSIONS_GROUPS.ZENDESK.permissions.OPEN,
PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE,
)
async hasAllPermissions(@Body() body) {
return { body };
}
@Get('has-some-permission')
@RequireSomePermission(Permissions.ZENDESK.OPEN, Permissions.METABASE.OPEN)
@RequireSomePermission(
PERMISSIONS_GROUPS.ZENDESK.permissions.OPEN,
PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE,
)
async hasSomePermission(@Body() body) {
return { body };
}
@@ -52,7 +62,7 @@ class NoClassAuthController {
@Controller('class-auth-condition')
@AuthenticateCondition((req) => req.get('x-on-class') === 'ok')
@RequireSomePermission(Permissions.METABASE.OPEN)
@RequireSomePermission(PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE)
class ClassAuthConditionController {
@Get('body')
async getBody(@Body() body) {
@@ -67,7 +77,7 @@ class ClassAuthConditionController {
@Get('required-permission')
@AuthenticateCondition((req) => req.get('x-on-route') === 'ok')
@RequireSomePermission(Permissions.ZENDESK.OPEN)
@RequireSomePermission(PERMISSIONS_GROUPS.ZENDESK.permissions.OPEN)
async requiredPermission(@Body() body) {
return { body };
}
@@ -104,7 +114,7 @@ describe('authentication.guard', () => {
},
{
provide: DadosferaLogger,
useValue: { logger: console },
useValue: { logger },
},
{
provide: APP_GUARD,
@@ -430,17 +440,17 @@ describe('authentication.guard', () => {
NoClassAuthTest(null, null);
ClassAuthConditionTest(null, null);
const tokenZ = CreateToken([Permissions.ZENDESK.OPEN]);
const tokenZ = CreateToken([PERMISSIONS_GROUPS.ZENDESK.permissions.OPEN]);
NoClassAuthTest(tokenZ, ['zendesk']);
ClassAuthConditionTest(tokenZ, ['zendesk']);
const tokenM = CreateToken([Permissions.METABASE.OPEN]);
const tokenM = CreateToken([PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE]);
NoClassAuthTest(tokenM, ['metabase']);
ClassAuthConditionTest(tokenM, ['metabase']);
const tokenZM = CreateToken([
Permissions.ZENDESK.OPEN,
Permissions.METABASE.OPEN,
PERMISSIONS_GROUPS.ZENDESK.permissions.OPEN,
PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE,
]);
NoClassAuthTest(tokenZM, ['zendesk', 'metabase']);
ClassAuthConditionTest(tokenZM, ['zendesk', 'metabase']);
+5 -5
View File
@@ -3,13 +3,12 @@ import {
CanActivate,
OnApplicationBootstrap,
ExecutionContext,
Logger,
Inject,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import assert from 'assert';
import jwt from 'jsonwebtoken';
import { DadosferaLogger } from 'dadosfera-logs';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { AuthClientService } from '../modules/auth/auth.service';
import {
AuthenticationFunction,
@@ -23,7 +22,7 @@ import ErrorCodes from '../utils/errorCodes';
export class AuthenticationGuard
implements CanActivate, OnApplicationBootstrap
{
logger: any;
logger: DadosferaLogger;
pems: Map<string, string>;
@@ -96,7 +95,7 @@ export class AuthenticationGuard
);*/
assert(
accessTokenDecoded.payload.token_use === 'access',
accessTokenDecoded?.payload?.token_use === 'access',
'should be an access token',
);
@@ -108,7 +107,7 @@ export class AuthenticationGuard
} catch (err) {
// log errors if authentication is required
if (mustBeAuthenticated) {
this.logger.error('Unable to verify duc access token\n' + err.stack);
this.logger.error('Unable to verify duc access token\n' + err?.stack);
}
return false;
@@ -122,6 +121,7 @@ export class AuthenticationGuard
customer_id: accessTokenPayload.customer_id,
customer_name: accessTokenPayload.customer_name,
customer_tier: accessTokenPayload.customer_tier,
access_token: accessToken,
};
// TODO: for backwards compatibility. remove in the future
request.body.info = {
+490 -155
View File
@@ -1,5 +1,6 @@
import { Logger } from '@nestjs/common';
import assert from 'assert';
import { LanguageEnum } from 'src/utils/languages.enum';
const logger = new Logger();
@@ -8,10 +9,24 @@ export enum PermissionUsages {
INTERNAL = 'internal',
}
export interface Permission {
export interface PermissionsObjectPermission {
seqid: number;
claim: string;
usage: PermissionUsages;
name?: Record<LanguageEnum, string>;
}
export interface PermissionsObjectPermissionTranslated {
seqid: number;
claim: string;
usage: PermissionUsages;
name?: string;
}
export interface PermissionsObjectGroup {
title: {
'pt-br': string;
'en-us': string;
};
permissions: Record<string, PermissionsObjectPermission>;
}
/*
@@ -22,216 +37,536 @@ export interface Permission {
/*export const Permissions: {
[P in keyof any]: { [Q in keyof any]: Permission };
} = {*/
export const Permissions = {
export const PERMISSIONS_GROUPS = {
AUTH: {
CREATE: {
seqid: 18,
claim: 'POST /auth',
usage: PermissionUsages.PUBLIC,
title: {
'pt-br': 'Autenticação',
'en-us': 'Authentication',
'es-es': 'Authentication',
},
permissions: {
CREATE: {
seqid: 18,
claim: 'POST /auth',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': '',
'en-us': '',
'es-es': '',
},
},
},
},
PIPELINE: {
CREATE: {
seqid: 23,
claim: 'POST /pipelines',
usage: PermissionUsages.PUBLIC,
title: {
'pt-br': 'Coletar | Pipelines',
'en-us': 'Collect | Pipelines',
'es-es': 'Colecta | Pipelines',
},
GET: {
seqid: 13,
claim: 'GET /pipelines',
usage: PermissionUsages.PUBLIC,
},
UPDATE: {
seqid: 29,
claim: 'PUT /pipelines',
usage: PermissionUsages.PUBLIC,
},
DELETE: {
seqid: 5,
claim: 'DELETE /pipelines',
usage: PermissionUsages.PUBLIC,
permissions: {
CREATE: {
seqid: 23,
claim: 'POST /pipelines',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Criar pipelines',
'en-us': 'Create pipelines',
'es-es': 'Crear pipelines',
},
},
GET: {
seqid: 13,
claim: 'GET /pipelines',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Buscar pipelines',
'en-us': 'Get pipelines',
'es-es': 'Obtener pipelines',
},
},
UPDATE: {
seqid: 29,
claim: 'PUT /pipelines',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Atualizar pipeline',
'en-us': 'Update pipeline',
'es-es': 'Actualizar pipeline',
},
},
DELETE: {
seqid: 5,
claim: 'DELETE /pipelines',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Excluir pipeline',
'en-us': 'Delete pipeline',
'es-es': 'Eliminar pipeline',
},
},
},
},
INPUT: {
CREATE: {
seqid: 21,
claim: 'POST /inputs',
usage: PermissionUsages.PUBLIC,
CONNECTION: {
title: {
'pt-br': 'Coletar | Fontes de dados',
'en-us': 'Collect | Sources',
'es-es': 'Colecta | Sources',
},
GET: {
seqid: 9,
claim: 'GET /inputs',
usage: PermissionUsages.PUBLIC,
permissions: {
CREATE: {
seqid: 37,
claim: 'connection:create',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Cadastrar Fonte',
'en-us': 'Create Source',
'es-es': 'Crear Source',
},
},
DELETE: {
seqid: 38,
claim: 'connection:delete',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Excluir Fonte',
'en-us': 'Remove Source',
'es-es': 'Eliminar Source',
},
},
UPDATE: {
seqid: 39,
claim: 'connection:update',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Editar Fonte',
'en-us': 'Edit Source',
'es-es': 'Editar Source',
},
},
},
UPDATE: {
seqid: 27,
claim: 'PUT /inputs',
usage: PermissionUsages.PUBLIC,
},
NETWORK_CONFIG: {
title: {
'pt-br': 'Coletar | Redes',
'en-us': 'Collect | Network',
'es-es': 'Colecta | Network',
},
UPDATE_PARTIAL: {
seqid: 17,
claim: 'PATCH /inputs',
usage: PermissionUsages.PUBLIC,
},
DELETE: {
seqid: 3,
claim: 'DELETE /inputs',
usage: PermissionUsages.PUBLIC,
},
GET_ENTITIES: {
seqid: 10,
claim: 'GET /inputs/available-entities',
usage: PermissionUsages.PUBLIC,
permissions: {
CREATE: {
seqid: 35,
claim: 'network_config:create',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Cadastrar VPN',
'en-us': 'Create VPN',
'es-es': 'Crear VPN',
},
},
// DELETE: {
// seqid: 36,
// claim: 'network_config:delete',
// usage: PermissionUsages.PUBLIC,
// name: {
// 'pt-br': 'Excluir VPN',
// 'en-us': 'Remove VPN',
// 'es-es': 'Eliminar VPN',
// },
// },
},
},
OUTPUT: {
CREATE: {
seqid: 22,
claim: 'POST /outputs',
usage: PermissionUsages.PUBLIC,
title: {
'pt-br': 'Output',
'en-us': 'Output',
'es-es': 'Output',
},
GET: {
seqid: 12,
claim: 'GET /outputs',
usage: PermissionUsages.PUBLIC,
},
UPDATE: {
seqid: 28,
claim: 'PUT /outputs',
usage: PermissionUsages.PUBLIC,
},
DELETE: {
seqid: 4,
claim: 'DELETE /outputs',
usage: PermissionUsages.PUBLIC,
permissions: {
CREATE: {
seqid: 22,
claim: 'POST /outputs',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Criar outputs',
'en-us': 'Create outputs',
'es-es': 'Crear outputs',
},
},
GET: {
seqid: 12,
claim: 'GET /outputs',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Buscar outputs',
'en-us': 'Get outputs',
'es-es': 'Obtener outputs',
},
},
UPDATE: {
seqid: 28,
claim: 'PUT /outputs',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Editar outputs',
'en-us': 'Edit outputs',
'es-es': 'Editar outputs',
},
},
DELETE: {
seqid: 4,
claim: 'DELETE /outputs',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Excluir outputs',
'en-us': 'Remove outputs',
'es-es': 'Eliminar outputs',
},
},
},
},
TRANSFORMATIONS: {
CREATE: {
seqid: 24,
claim: 'POST /transformations',
usage: PermissionUsages.PUBLIC,
title: {
'pt-br': 'Micro-transformações',
'en-us': 'Micro-transformations',
'es-es': 'Micro-transformaciones',
},
GET: {
seqid: 15,
claim: 'GET /transformations',
usage: PermissionUsages.PUBLIC,
},
UPDATE: {
seqid: 30,
claim: 'PUT /transformations',
usage: PermissionUsages.PUBLIC,
},
DELETE: {
seqid: 6,
claim: 'DELETE /transformations',
usage: PermissionUsages.PUBLIC,
permissions: {
CREATE: {
seqid: 24,
claim: 'POST /transformations',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Criar micro-transformações',
'en-us': 'Create micro-transformations',
'es-es': 'Crear micro-transformaciones',
},
},
GET: {
seqid: 15,
claim: 'GET /transformations',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Buscar micro-transformações',
'en-us': 'Get micro-transformations',
'es-es': 'Obtener micro-transformaciones',
},
},
UPDATE: {
seqid: 30,
claim: 'PUT /transformations',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Editar micro-transformações',
'en-us': 'Edit micro-transformations',
'es-es': 'Editar micro-transformaciones',
},
},
DELETE: {
seqid: 6,
claim: 'DELETE /transformations',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Excluir micro-transformações',
'en-us': 'Remove micro-transformations',
'es-es': 'Eliminar micro-transformaciones',
},
},
},
},
CATALOG: {
CREATE: {
seqid: 19,
claim: 'POST /catalog',
usage: PermissionUsages.PUBLIC,
title: {
'pt-br': 'Explorar | Catálogo',
'en-us': 'Explore | Catalog',
'es-es': 'Explorar | Catalogar',
},
GET: {
seqid: 7,
claim: 'GET /catalog',
usage: PermissionUsages.PUBLIC,
},
UPDATE: {
seqid: 25,
claim: 'PUT /catalog',
usage: PermissionUsages.PUBLIC,
},
DELETE: {
seqid: 1,
claim: 'DELETE /catalog',
usage: PermissionUsages.PUBLIC,
permissions: {
GET: {
seqid: 7,
claim: 'GET /catalog',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Acessar lista de Ativos e visualizar atributos',
'en-us': 'Access Assets list and its attributes',
'es-es': 'Acceda a la lista de Activos y vea los atributos',
},
},
CREATE: {
seqid: 19,
claim: 'catalog:create',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Criar Ativos',
'en-us': 'Create Assets',
'es-es': 'Crear Activos',
},
},
UPDATE: {
seqid: 25,
claim: 'catalog:edit',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Criar e editar atributos no catálogo',
'en-us': 'Create and edit attributes on the catalog',
'es-es': 'Crear y editar atributos en el catálogo',
},
},
DELETE: {
seqid: 1,
claim: 'catalog:delete',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Excluir Ativos do catálogo',
'en-us': 'Remove Assets from the catalog',
'es-es': 'Eliminar Activos del catálogo',
},
},
DATA_MANAGER: {
seqid: 42,
claim: 'catalog:data_manager',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br':
'Gerente do catálogo. Consegue vizualizar e editar todos os ativos.',
'en-us': 'Catalog manager. Able to view and edit all assets.',
'es-es': 'Gestor de catálogos. Puede ver y editar todos los activos.',
},
},
},
},
CONNECTORS: {
CREATE: {
seqid: 20,
claim: 'POST /connectors',
usage: PermissionUsages.PUBLIC,
title: {
'pt-br': 'Conectores',
'en-us': 'Connectors',
'es-es': 'Conectores',
},
GET: {
seqid: 8,
claim: 'GET /connectors',
usage: PermissionUsages.PUBLIC,
},
UPDATE: {
seqid: 26,
claim: 'PUT /connectors',
usage: PermissionUsages.PUBLIC,
},
DELETE: {
seqid: 2,
claim: 'DELETE /connectors',
usage: PermissionUsages.PUBLIC,
permissions: {
CREATE: {
seqid: 20,
claim: 'POST /connectors',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Criar conectores',
'en-us': 'Create connectors',
'es-es': 'Crear conectores',
},
},
GET: {
seqid: 8,
claim: 'GET /connectors',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Buscar conectores',
'en-us': 'Get connectors',
'es-es': 'Obtener conectores',
},
},
UPDATE: {
seqid: 26,
claim: 'PUT /connectors',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Editar conectores',
'en-us': 'Edit connectors',
'es-es': 'Editar conectores',
},
},
DELETE: {
seqid: 2,
claim: 'DELETE /connectors',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Excluir conectores',
'en-us': 'Remove connectors',
'es-es': 'Eliminar conectores',
},
},
},
},
SNOWFLAKE: {
OPEN: {
seqid: 14,
claim: 'GET /snowflake',
usage: PermissionUsages.PUBLIC,
title: {
'pt-br': 'Explorar | Consolidar',
'en-us': 'Explore | Data consolidation',
'es-es': 'Explorar | Consolidación de datos',
},
permissions: {
OPEN: {
seqid: 14,
claim: 'GET /snowflake',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Acessar Snowflake',
'en-us': 'Access Snowflake',
'es-es': 'Acceso Snowflake',
},
},
},
},
ZENDESK: {
OPEN: {
seqid: 16,
claim: 'GET /zendesk',
usage: PermissionUsages.PUBLIC,
title: {
'pt-br': 'Zendesk',
'en-us': 'Zendesk',
'es-es': 'Zendesk',
},
permissions: {
OPEN: {
seqid: 16,
claim: 'GET /zendesk',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Acessar Zendesk',
'en-us': 'Access Zendesk',
'es-es': 'Acceso Zendesk',
},
},
},
},
METABASE: {
OPEN: {
seqid: 11,
claim: 'GET /metabase',
usage: PermissionUsages.PUBLIC,
ANALYZE: {
title: {
'pt-br': 'Analisar | Visualização',
'en-us': 'Analyze | Visualization',
'es-es': 'Analizar | Visualización',
},
permissions: {
METABASE: {
seqid: 11,
claim: 'GET /metabase',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Acessar Metabase',
'en-us': 'Access Metabase',
'es-es': 'Acceso Metabase',
},
},
INTELLIGENCE: {
seqid: 31,
claim: 'intelligence:open',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Acessar Módulo de Inteligência',
'en-us': 'Access Intelligence Module',
'es-s': 'Acceder Módulo de Inteligencia',
},
},
},
},
ORCHEST: {
INTELLIGENCE: {
seqid: 31,
claim: 'intelligence:open',
usage: PermissionUsages.PUBLIC,
MODULES: {
title: {
'pt-br': 'Módulos da Dadosfera',
'en-us': 'Dadosfera Modules',
'es-es': 'Módulos de la Dadosfera',
},
APP_BUILDER: {
seqid: 32,
claim: 'app-builder:open',
usage: PermissionUsages.PUBLIC,
permissions: {
APP_BUILDER: {
seqid: 32,
claim: 'app-builder:open',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Acessar App Builder',
'en-us': 'Access App Builder',
'es-es': 'Acceder App Builder',
},
},
MACHINE_LEARNING: {
seqid: 33,
claim: 'machine-learning:open',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Acessar Machine Learning',
'en-us': 'Access Machine Learning',
'es-es': 'Acceder Machine Learning',
},
},
},
MACHINE_LEARNING: {
seqid: 33,
claim: 'machine-learning:open',
usage: PermissionUsages.PUBLIC,
},
USERS: {
title: {
'pt-br': 'Usuários',
'en-us': 'Users',
'es-es': 'Usuarios',
},
permissions: {
ADMIN: {
seqid: 34,
claim: 'users:admin',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Gestão de usuários e grupos',
'en-us': 'Manage user and roles',
'es-es': 'Administrar usuarios y roles',
},
},
},
},
PROCESS: {
title: {
'pt-br': 'Processar',
'en-us': 'Process',
'es-es': 'Procesar',
},
permissions: {
TRANSFORMATION: {
seqid: 43,
claim: 'process:open',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Acessar Módulo de Transformação',
'en-us': 'Access Transformation Module',
'es-es': 'Acceder Módulo de transformación',
},
},
},
},
DADOSFERA: {
title: {
'pt-br': 'Usuários',
'en-us': 'Users',
'es-es': 'Usuarios',
},
permissions: {
CONNECTIONS_MIGRATION: {
seqid: 40,
claim: 'dadosfera:connections-migration',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'connections-migration',
'en-us': 'connections-migration',
'es-es': 'connections-migration',
},
},
SYNC_USER: {
seqid: 41,
claim: 'dadosfera:sync-user',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'sync-user',
'en-us': 'sync-user',
'es-es': 'sync-user',
},
},
},
},
};
// traverses the object searching for duplicate seqids or claims (executes at runtime)
let nextAvailableSeqid = 0;
const seqids = Object.values(Permissions).flatMap((namespace) =>
Object.values(namespace).map(({ seqid }) => seqid),
const seqids = Object.values(PERMISSIONS_GROUPS).flatMap((namespace) =>
Object.values(namespace.permissions).map(({ seqid }) => seqid),
);
const claims = Object.values(Permissions).flatMap((namespace) =>
Object.values(namespace).map(({ claim }) => claim),
const claims = Object.values(PERMISSIONS_GROUPS).flatMap((namespace) =>
Object.values(namespace.permissions).map(({ claim }) => claim),
);
Object.values(Permissions).map((namespace) =>
Object.values(namespace).map(({ seqid, claim }) => {
Object.values(PERMISSIONS_GROUPS).map((namespace) =>
Object.values(namespace.permissions).map(({ seqid, claim }) => {
const seqidsCount = seqids.filter((x) => x === seqid).length;
assert(seqidsCount === 1, `seqid ${seqid} count is not 1`);
+12 -4
View File
@@ -5,14 +5,18 @@ import { APP_GUARD } from '@nestjs/core';
import jwt from 'jsonwebtoken';
import { Controller, Get } from '@nestjs/common';
import { DadosferaLogger } from 'dadosfera-logs';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { AuthenticationGuard } from './authentication.guard';
import { AuthClientService } from '../modules/auth/auth.service';
import ErrorCodes from '../utils/errorCodes';
import { User } from './user.decorator';
import { Permissions } from './permissions.enum';
import { PERMISSIONS_GROUPS } from './permissions.enum';
const logger = {
info: (...args) => args,
error: (...args) => args,
};
@Controller('user')
class UserController {
@Get()
@@ -45,10 +49,13 @@ describe('user.decorator', () => {
const fakeUserPayload = {
user_id: 'd50d33c7-6c2b-463c-861f-e21667e7c125',
username: 'super.admin',
permissions: [Permissions.METABASE.OPEN].map(({ seqid }) => seqid),
permissions: [PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE].map(
({ seqid }) => seqid,
),
customer_id: '9d18e8ae-24b9-41a3-9e8f-a25ce57555b11',
customer_name: 'dadosfera',
customer_tier: 'BASIC',
access_token: '',
};
beforeAll(async () => {
@@ -64,7 +71,7 @@ describe('user.decorator', () => {
},
{
provide: DadosferaLogger,
useValue: { logger: console },
useValue: { logger },
},
{
provide: APP_GUARD,
@@ -170,5 +177,6 @@ describe('user.decorator', () => {
UserTest(null);
const token = CreateToken();
fakeUserPayload.access_token = token;
UserTest(token);
});
+1 -1
View File
@@ -10,6 +10,7 @@ export interface RequestUser {
customer_id: string;
customer_name: string;
customer_tier: string;
access_token: string;
}
export const User: (options?: { required?: boolean }) => ParameterDecorator =
@@ -19,6 +20,5 @@ export const User: (options?: { required?: boolean }) => ParameterDecorator =
if (!request.user && options?.required) {
throw new ErrorBuilder(ErrorCodes.AUTH.UNAUTHORIZED);
}
return request.user;
});
-31
View File
@@ -1,31 +0,0 @@
import { credentials } from '@grpc/grpc-js';
import { ClientOptions, Transport } from '@nestjs/microservices';
import { ConnectorManager } from 'protospack-v2';
export class ConnectorClientConfiguration {
config(): ClientOptions {
return {
transport: Transport.GRPC,
options: {
url: process.env.INFACTORY_URL,
package: [
ConnectorManager.ProtoPackages.WritePackage,
ConnectorManager.ProtoPackages.ReadPackage,
],
credentials:
process.env.LOCAL_ENV === 'local'
? undefined
: credentials.createSsl(),
protoPath: [
ConnectorManager.ProtoPaths.WriteFilePath,
ConnectorManager.ProtoPaths.ReadFilePath,
],
loader: {
enums: String,
objects: true,
arrays: true,
},
},
};
}
}
-307
View File
@@ -1,307 +0,0 @@
import {
OnModuleInit,
Inject,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { DadosferaLogger } from 'dadosfera-logs';
import { ClientGrpc } from '@nestjs/microservices';
import { ConnectorManager } from 'protospack-v2';
import { from } from 'rxjs';
export class ConnectorClientService implements OnModuleInit {
private connectorServiceRead: ConnectorManager.ReadService.ConnectorManagerReadServices;
private connectorServiceWrite: ConnectorManager.WriteService.ConnectorManagerWriteServices;
logger: any;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
@Inject('CONNECTOR_PACKAGE') private readonly grpcClient: ClientGrpc,
) {
this.logger = dadosferaLogger.logger;
}
onModuleInit() {
this.connectorServiceWrite =
this.grpcClient.getService<ConnectorManager.WriteService.ConnectorManagerWriteServices>(
ConnectorManager.ProtoServices.ConnectorManagerWriteServices,
);
this.connectorServiceRead =
this.grpcClient.getService<ConnectorManager.ReadService.ConnectorManagerReadServices>(
ConnectorManager.ProtoServices.ConnectorManagerReadServices,
);
}
async uploadConnector(uploadConnector) {
const connector: ConnectorManager.Entities.ConnectorCreateRequest = {
file: {
buffer: uploadConnector.file.buffer,
mimetypes: uploadConnector.file.mimetype,
},
connector: JSON.stringify(uploadConnector.connector),
};
const serviceBody: ConnectorManager.Messages.RegisterConnectorRequest = {
connector,
};
const observable = from(
this.connectorServiceWrite.RegisterConnector(serviceBody),
);
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
//console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.details);
this.logger.error(err);
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
this.logger.info('ConnectorClientService - Upload');
return result;
}
async uploadFile(uploadFile) {
const body: ConnectorManager.Messages.UploadFileRequest = {
file: {
buffer: uploadFile.file.buffer,
mimetypes: uploadFile.file.mimetype,
},
name: uploadFile.name,
};
const observable = from(this.connectorServiceWrite.UploadFile(body));
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
//console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.details);
this.logger.error(err);
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
this.logger.info('ConnectorClientService - Upload');
return result;
}
async getAllConnectors(body) {
const observable = from(
this.connectorServiceRead.GetAllConnectors({
search: body.search,
filters: JSON.stringify(body.filters),
}),
);
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
//console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err);
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
this.logger.info('ConnectorClientService - getAllConnectors');
return result;
}
async getConnectorDetails(plugin: string) {
const observable = from(
this.connectorServiceRead.GetConnectorDetails({
plugin,
}),
);
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
//console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err);
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
this.logger.info('ConnectorClientService - getAllConnectors');
return result;
}
async getConnector(plugin: string) {
const observable = from(
this.connectorServiceRead.GetConnector({
plugin,
}),
);
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
//console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err);
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
this.logger.info('ConnectorClientService - getAllConnectors');
return result;
}
async deleteConnector(plugin: string, version: string) {
const observable = from(
this.connectorServiceWrite.DeleteConnector({
version,
plugin,
}),
);
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
//console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err);
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
this.logger.info('ConnectorClientService - getAllConnectors');
return result;
}
async updateConnector({ plugin, changes }) {
const observable = from(
this.connectorServiceWrite.UpdateConnector({
plugin,
changes,
}),
);
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
//console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err);
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
this.logger.info('ConnectorClientService - getAllConnectors');
return result;
}
}
-28
View File
@@ -1,28 +0,0 @@
import { credentials } from '@grpc/grpc-js';
import { ClientOptions, Transport } from '@nestjs/microservices';
import {
ProtoPackages,
ProtoPaths,
} from 'protospack-v2/dist/lib/Duc';
export class DucClient {
config(): ClientOptions {
return {
transport: Transport.GRPC,
options: {
url: process.env.DUC_URL,
package: ProtoPackages.WritePackage,
credentials: process.env.LOCAL_ENV
? undefined
: credentials.createSsl(),
protoPath: ProtoPaths.WriteFilePath,
loader: {
keepCase: true,
enums: String,
objects: true,
arrays: true,
},
},
};
}
}
-25
View File
@@ -1,25 +0,0 @@
import { credentials } from '@grpc/grpc-js';
import { ClientOptions, Transport } from '@nestjs/microservices';
import { InputPackages, InputProtoFilePath } from 'protospack';
export class InputsClientConfiguration {
config(): ClientOptions {
return {
transport: Transport.GRPC,
options: {
url: process.env.INFACTORY_URL,
package: InputPackages,
credentials: process.env.LOCAL_ENV
? undefined
: credentials.createSsl(),
protoPath: InputProtoFilePath,
loader: {
enums: String,
objects: true,
arrays: true,
},
},
};
}
}
-310
View File
@@ -1,310 +0,0 @@
import {
OnModuleInit,
Inject,
HttpException,
HttpStatus,
NotFoundException,
InternalServerErrorException,
} from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import {
DecodeGrpcStruct,
EncodeJsonToGrpcStruct,
InputCreateS3Request,
InputNewCreateRequest,
InputService,
TestConnectionGetColumnsRequest,
TestConnectionRequest,
} from 'protospack';
import axios, { AxiosRequestConfig } from 'axios';
import { lastValueFrom } from 'rxjs';
import { InputModel } from 'src/modules/inputs/dtos/input.model';
import {
objectCamelToSnake,
objectSnakeToCamel,
} from 'src/utils/CaseConverter';
import { mustache } from 'src/utils/mustache';
import { DadosferaLogger } from 'dadosfera-logs';
import { OauthSecrets } from 'src/utils/OauthSecrets';
import { URLSearchParams } from 'url';
import { IIdRequest, UpdateInputRequest } from './interfaces';
export class InputsClientService implements OnModuleInit {
private inputService: InputService;
logger: any;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
@Inject('INPUTS_PACKAGE') private readonly grpcClient: ClientGrpc,
@Inject('OAUTH_SECRETS') private readonly oauthSecrets: OauthSecrets,
) {
this.logger = dadosferaLogger.logger;
}
async onModuleInit() {
this.inputService =
this.grpcClient.getService<InputService>('InputService');
}
async newCreate(createInputDto: InputNewCreateRequest) {
this.logger.info('InputClientService - Create');
const input = await lastValueFrom(
this.inputService.NewCreate(objectSnakeToCamel(createInputDto)),
);
objectCamelToSnake(input);
return input;
}
async createGeneric(createInputGeneric) {
this.logger.info('InputClientService - Create');
const { info, ...data } = createInputGeneric;
// data.credentials = await this.getInputTokens(data);
if (data.options) delete data.options;
if (data.credentials.oauth_code) delete data.credentials.oauth_code;
const grpcPayload = {
input: EncodeJsonToGrpcStruct(data),
info,
};
objectSnakeToCamel(grpcPayload);
const structReturn = await lastValueFrom(
this.inputService.Create(grpcPayload),
).catch((err: { details: string }) => {
if (err.details === 'Item Not found!') {
throw new NotFoundException('Input not found');
}
throw new InternalServerErrorException(err.details);
});
objectCamelToSnake(structReturn);
const inputCreated = DecodeGrpcStruct(structReturn.input);
return { input: inputCreated };
}
async createS3Inputs(createInputDto: InputCreateS3Request) {
this.logger.info('InputClientService - Create');
objectSnakeToCamel(createInputDto);
const createInputResponse = await lastValueFrom(
this.inputService.CreateS3(createInputDto),
).catch((e) => {
throw new HttpException(e.details, 500);
});
this.logger.info('Done');
objectCamelToSnake(createInputResponse);
return createInputResponse;
}
async findOne(data: IIdRequest) {
this.logger.info('InputClientService - FindOne');
const findOneInputResponse = await lastValueFrom(
this.inputService.FindOne(objectSnakeToCamel(data)),
).catch((e) => {
this.logger.error(e.details);
throw new HttpException(e.details, HttpStatus.INTERNAL_SERVER_ERROR);
});
objectCamelToSnake(findOneInputResponse);
return findOneInputResponse;
}
async findAll(data) {
this.logger.info('InputClientService - FindAll');
const findAllInputResponse = await lastValueFrom(
this.inputService.FindAll(objectSnakeToCamel(data)),
).catch((e) => {
this.logger.error(e.details);
throw new HttpException(e.details, HttpStatus.INTERNAL_SERVER_ERROR);
});
findAllInputResponse.inputs.forEach((input) => objectCamelToSnake(input));
return findAllInputResponse;
}
async update(updateInputDTO: UpdateInputRequest) {
this.logger.info('InputClientService - Update');
const updateInputResponse = await new Promise((resolve, reject) => {
this.inputService.Update(objectSnakeToCamel(updateInputDTO)).subscribe({
next(x) {
resolve(objectCamelToSnake(x));
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return updateInputResponse;
}
async remove(idRequest: IIdRequest) {
this.logger.info('InputClientService - Remove');
const removeInputResponse = await new Promise((resolve, reject) => {
this.inputService.Remove(objectSnakeToCamel(idRequest)).subscribe({
next(x) {
resolve(objectCamelToSnake(x));
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return removeInputResponse;
}
async testConnection(data: TestConnectionRequest) {
this.logger.info('InputClientService - TestConnection');
const testConnectionResponse = await new Promise((resolve, reject) => {
this.inputService.NewTestConnection(objectSnakeToCamel(data)).subscribe({
next(x) {
resolve(objectCamelToSnake(x));
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return testConnectionResponse;
}
async getColumns(data: TestConnectionGetColumnsRequest) {
this.logger.info('InputClientService - TestConnection/Get-Columns');
const getColumnsResponse = await new Promise((resolve, reject) => {
this.inputService.GetColumns(objectSnakeToCamel(data)).subscribe({
next(x) {
resolve(objectCamelToSnake(x));
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return getColumnsResponse;
}
async getAuthSecrets(plugin) {
switch (plugin) {
case 'hubspot':
return {
client_id: this.oauthSecrets.hubspot.client_id || '',
client_secret: this.oauthSecrets.hubspot.client_secret || '',
};
}
return {};
}
async getInputTokens(input: InputModel) {
const { credentials } = input;
let credentialsTokens = {};
switch (credentials.connection_type) {
case 'oauth':
credentialsTokens = await this.getOauthTokens(input);
break;
}
return { ...credentials, ...credentialsTokens };
}
async getOauthTokens(input: InputModel) {
const tokens: Record<string, any> = {};
const { options, credentials } = input;
const { oauth } = options;
const { get_tokens_url_params, get_tokens_set_response } = oauth;
const secrets = await this.getAuthSecrets(input.plugin);
const get_tokens_url_params_string = mustache(get_tokens_url_params, {
...secrets,
...credentials,
});
let get_tokens_url_params_obj: Record<string, any> = {};
try {
get_tokens_url_params_obj = JSON.parse(get_tokens_url_params_string);
} catch (error) {
throw new HttpException('Erro transformando get_tokens_url_params', 400);
}
let params = {};
switch (oauth.content_type) {
case 'application/x-www-form-urlencoded':
params = new URLSearchParams(get_tokens_url_params_obj);
params = params.toString();
break;
default:
break;
}
const axiosRequestConfig: AxiosRequestConfig = {
url: oauth.get_tokens_url,
method: oauth.get_tokens_method || 'POST',
data: params,
headers: { 'content-type': oauth.content_type || 'application/json' },
};
const { data } = await axios(axiosRequestConfig).catch((err) => {
this.logger.error(err.response.data);
throw new HttpException(err.response.data.message, err.response.status);
});
for (const key in get_tokens_set_response) {
const responseKey = get_tokens_set_response[key];
tokens[key] = data[responseKey];
}
const { redirect_uri } = get_tokens_url_params_obj;
tokens.redirect_uri = redirect_uri;
return tokens;
}
async getAvailableEntities(data) {
this.logger.info('InputClientService - GetAvailableEntities');
objectSnakeToCamel(data);
const response = await lastValueFrom(
this.inputService.GetAvailableEntities(data),
).catch((err) => {
this.logger.info(err.details);
if (err.details && err.details.includes('400'))
throw new HttpException('Plugin inválido', HttpStatus.BAD_REQUEST);
throw new HttpException(err.details, HttpStatus.INTERNAL_SERVER_ERROR);
});
objectCamelToSnake(response);
return response;
}
}
-24
View File
@@ -1,24 +0,0 @@
import { OutputPackages, OutputProtoFilePath } from 'protospack';
import { ClientOptions, Transport } from '@nestjs/microservices';
import { credentials } from '@grpc/grpc-js';
export class OutputsClientConfiguration {
config(): ClientOptions {
return {
transport: Transport.GRPC,
options: {
url: process.env.OTFACTORY_URL,
package: OutputPackages,
credentials: process.env.LOCAL_ENV
? undefined
: credentials.createSsl(),
protoPath: OutputProtoFilePath,
loader: {
enums: String,
objects: true,
arrays: true,
},
},
};
}
}
-181
View File
@@ -1,181 +0,0 @@
import { Controller, Inject, OnModuleInit } from '@nestjs/common';
import { ClientGrpc, Payload } from '@nestjs/microservices';
import { DadosferaLogger } from 'dadosfera-logs';
import {
OutputServicesNames,
OutputsServiceInterface,
} from 'protospack';
import {
objectCamelToSnake,
objectSnakeToCamel,
} from 'src/utils/CaseConverter';
import {
ICreateOutputRequest,
IIdRequest,
IOutputUpdateRequest,
} from './interfaces';
@Controller('output')
export class OutputsClientService implements OnModuleInit {
private outputService: OutputsServiceInterface;
logger: any;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
@Inject('OUTPUTS_PACKAGE') private readonly grpcClient: ClientGrpc,
) {
this.logger = dadosferaLogger.logger;
}
onModuleInit() {
this.outputService = this.grpcClient.getService<OutputsServiceInterface>(
OutputServicesNames.OutputService,
);
}
async create(@Payload() createOutputDto: ICreateOutputRequest) {
this.logger.info('OutputClientService - Create');
const createOutputResponse = await new Promise((resolve, reject) => {
this.outputService.Create(objectSnakeToCamel(createOutputDto)).subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
const convertedItem = objectCamelToSnake(createOutputResponse['output']);
createOutputResponse['output'] = convertedItem;
return createOutputResponse;
}
async findAll(data) {
this.logger.info('OutputClientService - FindAll');
const findAllOutputResponse = await new Promise((resolve, reject) => {
this.outputService.FindAll(objectSnakeToCamel(data)).subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
const convertedOutputs = findAllOutputResponse['outputs'].map((ot) => {
return objectCamelToSnake(ot);
});
return { outputs: convertedOutputs };
}
async findOne(data: IIdRequest) {
this.logger.info('OutputClientService - FindOne');
const findOneOutputResponse = await new Promise((resolve, reject) => {
this.outputService.FindOne(objectSnakeToCamel(data)).subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return objectCamelToSnake(findOneOutputResponse);
}
async update(updateOutPutDTO: IOutputUpdateRequest) {
this.logger.info('OutputClientService - Update');
const updateOutputResponse = await new Promise((resolve, reject) => {
this.outputService.Update(objectSnakeToCamel(updateOutPutDTO)).subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return objectCamelToSnake(updateOutputResponse);
}
async remove(data: IIdRequest) {
this.logger.info('OutputClientService - Remove');
const removeOutputResponse = await new Promise((resolve, reject) => {
this.outputService.Remove(objectSnakeToCamel(data)).subscribe({
next(x) {
resolve(objectCamelToSnake(x));
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return removeOutputResponse;
}
}
-29
View File
@@ -1,29 +0,0 @@
export interface ICreateOutputRequest {
operation: string;
name: string;
plugin: string;
values: Values;
}
export interface Values {
prefix: string;
}
interface Info {
user_id: string;
customer_id: string;
}
export interface IIdRequest {
id: string;
info: Info;
}
export interface IOutputUpdateRequest {
id: string;
operation: string;
values: Values;
plugin: string;
name: string;
info: Info;
}
-27
View File
@@ -1,27 +0,0 @@
import { ClientOptions, Transport } from '@nestjs/microservices';
import {
PipelinePackages,
PipelineProtoFilePath,
} from 'protospack';
import { credentials } from '@grpc/grpc-js';
export class PipelinesClientConfiguration {
config(): ClientOptions {
return {
transport: Transport.GRPC,
options: {
url: process.env.PIFACTORY_URL,
package: PipelinePackages,
credentials: process.env.LOCAL_ENV
? undefined
: credentials.createSsl(),
protoPath: PipelineProtoFilePath,
loader: {
enums: String,
objects: true,
arrays: true,
},
},
};
}
}
-273
View File
@@ -1,273 +0,0 @@
import {
BadRequestException,
Inject,
InternalServerErrorException,
OnModuleInit,
} from '@nestjs/common';
import { ClientGrpc, Payload } from '@nestjs/microservices';
import { PipelineServicesNames, PipelinesServiceInterface } from 'protospack';
import { lastValueFrom } from 'rxjs';
import {
objectCamelToSnake,
objectSnakeToCamel,
} from 'src/utils/CaseConverter';
import {
ICreatePipelineDto,
IGetPipelineLogsRequest,
IIdRequest,
IUpdatePipelineRequest,
} from './interfaces';
import { DadosferaLogger } from 'dadosfera-logs';
export class PipelinesClientService implements OnModuleInit {
private pipelineService: PipelinesServiceInterface;
logger: any;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
@Inject('PIPELINES_PACKAGE') private readonly grpcClient: ClientGrpc,
) {
this.logger = dadosferaLogger.logger;
}
onModuleInit() {
this.pipelineService =
this.grpcClient.getService<PipelinesServiceInterface>(
PipelineServicesNames.PipelineService,
);
}
async create(@Payload() createPipelineDto: ICreatePipelineDto) {
this.logger.info('PipelinesClientService - Create');
const createPipelineResponse = await lastValueFrom(
this.pipelineService.Create(objectSnakeToCamel(createPipelineDto)),
)
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((error: { details: string }) => {
if (error.details.includes('INVALID_REQUEST')) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [errorType, message] = error.details.split('|');
throw new BadRequestException(message);
}
throw new InternalServerErrorException(error.details);
});
return createPipelineResponse;
}
async findAll(data: IIdRequest) {
this.logger.info('PipelinesClientService - FindAll');
const findAllPipelineResponse = await new Promise((resolve, reject) => {
this.pipelineService.FindAll(objectSnakeToCamel(data)).subscribe({
next(x) {
resolve(x.pipelines);
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return findAllPipelineResponse;
}
async findOne(data: IIdRequest) {
this.logger.info('PipelinesClientService - FindOne');
const findOnePipelineResponse = await new Promise((resolve, reject) => {
this.pipelineService.FindOne(objectSnakeToCamel(data)).subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return findOnePipelineResponse;
}
async update(UpdatePipelineRequest: IUpdatePipelineRequest) {
this.logger.info('PipelinesClientService - Update');
const updatePipelineResponse = await new Promise((resolve, reject) => {
this.pipelineService
.Update(objectSnakeToCamel(UpdatePipelineRequest))
.subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
//console.log('done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return updatePipelineResponse;
}
async remove(data: IIdRequest) {
this.logger.info('PipelinesClientService - Remove');
const removePipelineResponse = await new Promise((resolve, reject) => {
this.pipelineService.remove(objectSnakeToCamel(data)).subscribe({
next(x) {
resolve(objectCamelToSnake(x));
},
error(err) {
reject(err);
},
complete() {
// this.logger.info('Done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return removePipelineResponse;
}
async getPipelineLogsMessages(data: IGetPipelineLogsRequest) {
this.logger.info('PipelinesClientService - GetPipelineLogsMessages');
const logsPipelineResponse = await new Promise((resolve, reject) => {
this.pipelineService.getPipelineLogs(data).subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
// this.logger.info('Done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return logsPipelineResponse;
}
async getPipelineStatus(data) {
this.logger.info('PipelinesClientService - GetPipelineStatus');
const statusPipelineResponse = await new Promise((resolve, reject) => {
this.pipelineService
.getPipelineStatus(objectSnakeToCamel(data))
.subscribe({
next(x) {
const statusArray = x.status.sort((a, b) => {
if (a.id < b.id) {
return 1;
} else {
return -1;
}
});
resolve({ status: statusArray });
},
error(err) {
reject(err);
},
complete() {
// this.logger.info('Done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return statusPipelineResponse;
}
async runPipeline({ id, info }: IIdRequest) {
this.logger.info('PipelinesClientService - RunPipeline');
const statusPipelineResponse = await new Promise((resolve, reject) => {
this.pipelineService
.triggerPipeline(objectSnakeToCamel({ id, info }))
.subscribe({
next(x) {
if (x.status == false) {
reject(
'This pipeline is not ready yet to execute, Try again later!',
);
}
resolve(x);
},
error(err) {
this.logger.error('Observable Error');
reject(err);
},
complete() {
this.logger.info('Done');
},
});
})
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return statusPipelineResponse;
}
}
@@ -1,25 +0,0 @@
import { ClientOptions, Transport } from '@nestjs/microservices';
import {
TransformationPackages,
TransformationProtoFilePath,
} from 'protospack';
import { credentials } from '@grpc/grpc-js';
export class TransformationsClientConfiguration {
config(): ClientOptions {
return {
transport: Transport.GRPC,
options: {
url: process.env.INFACTORY_URL,
package: TransformationPackages,
credentials: credentials.createSsl(),
protoPath: TransformationProtoFilePath,
loader: {
enums: String,
objects: true,
arrays: true,
},
},
};
}
}
@@ -1,194 +0,0 @@
import { Controller, Inject, OnModuleInit, Post } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { TransformationsServiceInterface } from 'protospack';
import { DadosferaLogger } from 'dadosfera-logs';
import {
objectCamelToSnake,
objectSnakeToCamel,
} from 'src/utils/CaseConverter';
import { ICreateTransformationsRequest, IIdRequest } from './interfaces';
@Controller('transformation')
export class TransformationsClientService implements OnModuleInit {
private transformationService: TransformationsServiceInterface;
logger: any;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
@Inject('TRANSFORMATIONS_PACKAGE') private readonly grpcClient: ClientGrpc,
) {
this.logger = dadosferaLogger.logger;
}
onModuleInit() {
this.transformationService =
this.grpcClient.getService<TransformationsServiceInterface>(
'TransformationService',
);
}
@Post()
async create(createTransformationsDto: ICreateTransformationsRequest) {
this.logger.info('TransformationClientService - Create');
const createTransformationResponse = await new Promise(
(resolve, reject) => {
this.transformationService
.Create(objectSnakeToCamel(createTransformationsDto))
.subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
},
)
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
const convertedTransforms = createTransformationResponse[
'transformations'
].map((tr) => {
return objectCamelToSnake(tr);
});
return { transformations: convertedTransforms };
}
async findAll(data) {
this.logger.info('TransformationClientService - FindAll');
const findAllTransformationResponse = await new Promise(
(resolve, reject) => {
this.transformationService.FindAll(objectSnakeToCamel(data)).subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
},
)
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
const convertedTransforms = findAllTransformationResponse[
'transformations'
].map((tr) => {
return objectCamelToSnake(tr);
});
return { transformations: convertedTransforms };
}
async findOne(data: IIdRequest) {
this.logger.info('TransformationClientService - FindOne');
const findOneTransformationResponse = await new Promise(
(resolve, reject) => {
this.transformationService.FindOne(objectSnakeToCamel(data)).subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
},
)
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return objectCamelToSnake(findOneTransformationResponse);
}
async update(updateTransformationDTO) {
this.logger.info('TransformationClientService - Update');
const updateTransformationResponse = await new Promise(
(resolve, reject) => {
this.transformationService
.Update(objectSnakeToCamel(updateTransformationDTO))
.subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
},
)
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return objectCamelToSnake(updateTransformationResponse);
}
async remove(data: IIdRequest) {
this.logger.info('TransformationClientService - Remove');
const removeTransformationResponse = await new Promise(
(resolve, reject) => {
this.transformationService.Remove(objectSnakeToCamel(data)).subscribe({
next(x) {
resolve(x);
},
error(err) {
reject(err);
},
complete() {
// console.log('done');
},
});
},
)
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
return objectCamelToSnake(removeTransformationResponse);
}
}
@@ -0,0 +1,37 @@
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
} from '@nestjs/common';
import { Response } from 'express';
import ErrorBuilder from '../utils/ErrorBuilder';
/**
* ExceptionFilter to handle RpcException thrown by our microservices
*
* If it detects that the exception is already an **HttpException** or it is generated by our **ErrorBuilder**,
* it will return the exception without any treatment.
*/
@Catch(Error)
export class GrpcToHttpExceptionFilter implements ExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
if (exception instanceof HttpException) {
return response
.status(exception.getStatus())
.json(exception.getResponse());
}
const err =
exception.constructor.name === ErrorBuilder.name
? exception
: new ErrorBuilder(exception.details);
const { statusCode } = err.response;
return response.status(statusCode).json(err.response);
}
}
+42 -30
View File
@@ -1,35 +1,22 @@
import 'elastic-apm-node/start';
if (process.env.ENV !== 'local') require('elastic-apm-node/start');
import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { writeFileSync } from 'fs';
import helmet from 'helmet';
import { DadosferaLogger } from 'dadosfera-logs';
import documentEmpty from '../swagger_empty.json';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { AppModule } from './app.module';
import { writeFileSync } from 'fs';
import { execSync } from 'child_process';
import { INestApplication } from '@nestjs/common';
async function bootstrap() {
DadosferaLogger.setupLogger({
serviceName: 'maestro',
serviceEnvironment: process.env.ENV,
});
const logger = new DadosferaLogger().logger;
const orginalWinstonLog = logger.log.bind(logger);
logger.log = function (...kwargs: any[]) {
if (kwargs[0] in logger.levels) {
if (kwargs[0] == 'error') {
orginalWinstonLog('error', kwargs[2]);
}
} else {
orginalWinstonLog('info', ...kwargs);
}
};
const logger = new DadosferaLogger();
const app = await NestFactory.create(AppModule, {
logger: logger,
logger,
cors: {
origin: '*',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
@@ -39,22 +26,47 @@ async function bootstrap() {
});
app.use(helmet());
configureSwagger(app);
await app.listen(3333);
}
function configureSwagger(app: INestApplication) {
let branchName = '';
try {
branchName = execSync('git rev-parse --abbrev-ref HEAD')
.toString()
.replace('\n', '')
.trim();
} catch (error) {
console.log("Can't get branch name", error);
}
const swaggerTitle = branchName ? `Maestro - ${branchName}` : 'Maestro';
const config = new DocumentBuilder()
.setTitle('Maestro')
.setTitle(swaggerTitle)
.setDescription('Documentation for Maestro gateway')
.setVersion('1.0')
.addBearerAuth()
.addBearerAuth(
{ type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
'Authorization',
)
.build();
const document = SwaggerModule.createDocument(app, config);
if (process.env.ENV != 'stg' && process.env.ENV != 'prd')
SwaggerModule.setup('api', app, document);
const swaggerDoc = process.env.ENV === 'dev' ? document : documentEmpty;
SwaggerModule.setup('api', app, swaggerDoc);
await app.listen(3333);
if (process.env.ENV === 'local') SwaggerModule.setup('api', app, document);
writeFileSync(
'docsfera.json',
JSON.stringify(
{
service: '${DOCS_API_TOKEN}',
pageId: '${DOCS_PAGE_ID}',
blockId: '${DOCS_BLOCK_ID}',
schema: document,
},
null,
2,
),
);
}
bootstrap();
+57 -9
View File
@@ -6,11 +6,11 @@ import {
HttpCode,
HttpStatus,
Inject,
UseFilters,
Get,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import {
AuthSignInRequest,
AuthRefreshAccessTokenRequest,
AuthChangePasswordRequest,
AuthResetPasswordRequest,
AuthVerifyResetPasswordCodeRequest,
@@ -18,15 +18,30 @@ import {
AuthEnableTotpMfaRequest,
AuthDisableTotpMfaRequest,
AuthVerifyTotpMfaRequest,
} from 'protospack-v2/dist/lib/Duc/interfaces/messages';
} from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import {
Authenticated,
RequireAllPermissions,
} from 'src/authentication/authentication.decorator';
import { AuthClientService } from './auth.service';
import { DadosferaLogger } from 'dadosfera-logs';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { GrpcToHttpExceptionFilter } from '../../error/grpc-to-http-exception.filter';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { Metadata } from '@grpc/grpc-js';
import {
AuthRefreshAccessTokenReq,
AuthSignInReq,
AuthSignInRes,
} from './dtos/login';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
@ApiTags('Auth')
@UseFilters(new GrpcToHttpExceptionFilter())
@Controller('auth')
export class AuthController {
logger: any;
logger: DadosferaLogger;
constructor(
@Inject(DadosferaLogger)
@@ -38,20 +53,46 @@ export class AuthController {
@Post('sign-in')
@HttpCode(HttpStatus.OK)
async signIn(@Body() { username, password, totp }: AuthSignInRequest) {
async signIn(
@Body() { username, password, totp }: AuthSignInReq,
@Headers('Dadosfera-Lang') language: string,
): Promise<AuthSignInRes> {
this.logger.info('/auth - SignIn');
const metadata = new Metadata();
metadata.add('language', language || 'pt-br');
return this.authClient.signIn({ username, password, totp }, metadata);
}
return this.authClient.signIn({ username, password, totp });
@Post('/sso/snowflake')
@RequireAllPermissions(PERMISSIONS_GROUPS.SNOWFLAKE.permissions.OPEN)
@HttpCode(HttpStatus.OK)
async snowflakeSignIn(
@User() user: RequestUser,
@Body('RelayState') relayState: string,
) {
this.logger.info('/auth - snowflakeSignIn');
return this.authClient.snowflakeSignIn({
userId: user.user_id,
relayState,
});
}
@Post('refresh-access-token')
@HttpCode(HttpStatus.OK)
async refreshAccessToken(
@Body() { refreshToken }: AuthRefreshAccessTokenRequest,
@Body()
{ refreshToken, customerName: customer_name }: AuthRefreshAccessTokenReq,
@Headers('Dadosfera-Lang') language: string,
) {
this.logger.info('/auth - RefreshAccessToken');
return this.authClient.refreshAccessToken({ refreshToken });
const metadata = PackTheMetadata({
customer_name,
language,
});
return this.authClient.refreshAccessToken({ refreshToken }, metadata);
}
@Post('change-password')
@@ -156,4 +197,11 @@ export class AuthController {
return this.authClient.verifyTotp({ accessToken, totp });
}
@Authenticated()
@Get('verify-access-token')
@HttpCode(HttpStatus.OK)
verifyAccessToken() {
return { access_token_status: 'valid' };
}
}
+4 -11
View File
@@ -1,22 +1,15 @@
import { Module } from '@nestjs/common';
import { ClientsModule } from '@nestjs/microservices';
import { DadosferaLogger } from 'dadosfera-logs';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { AuthController } from './auth.controller';
import { AuthClientService } from './auth.service';
import { DucClient } from '../../clients/duc/client.config';
const ducClient = new DucClient();
import { DucClient } from '../duc/client.config';
const client = new DucClient();
@Module({
imports: [
ClientsModule.register([
{
name: 'DUC_PACKAGE',
...ducClient.config(),
},
]),
],
imports: [ClientsModule.register([client.providerOptions])],
controllers: [AuthController],
providers: [AuthClientService, DadosferaLogger],
exports: [AuthClientService],
+37 -40
View File
@@ -1,44 +1,35 @@
import { OnModuleInit, Inject, Injectable } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { DadosferaLogger } from 'dadosfera-logs';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { lastValueFrom } from 'rxjs';
import { ProtoServices } from 'protospack-v2/dist/lib/Duc';
import { AuthProtoService as AuthServiceInterface } from 'protospack-v2/dist/lib/Duc/interfaces/write-service';
import { ProtoServices } from '@dadosfera/protospack-v2/dist/lib/Duc';
import { AuthProtoService as AuthServiceInterface } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/write-service';
import {
AuthGetPublicKeysResponse,
AuthSnowflakeSignInRequest,
AuthSignInRequest,
AuthSignInResponse,
AuthRefreshAccessTokenRequest,
AuthRefreshAccessTokenResponse,
AuthEnableTotpMfaRequest,
AuthEnableTotpMfaResponse,
AuthDisableTotpMfaRequest,
AuthDisableTotpMfaResponse,
AuthDismissTotpMfaRequest,
AuthDismissTotpMfaResponse,
AuthVerifyTotpMfaRequest,
AuthVerifyTotpMfaResponse,
AuthChangePasswordRequest,
AuthChangePasswordResponse,
AuthResetPasswordRequest,
AuthResetPasswordResponse,
AuthVerifyResetPasswordCodeRequest,
AuthVerifyResetPasswordCodeResponse,
AuthConfirmResetPasswordRequest,
AuthConfirmResetPasswordResponse,
} from 'protospack-v2/dist/lib/Duc/interfaces/messages';
import grpcHandler from '../../utils/grpcHandler';
} from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages';
import { DucClient } from '../duc/client.config';
import { Metadata } from '@grpc/grpc-js';
@Injectable()
export class AuthClientService implements OnModuleInit {
logger: any;
logger: DadosferaLogger;
private authService: AuthServiceInterface;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
@Inject('DUC_PACKAGE') private readonly grpcClient: ClientGrpc,
@Inject(DucClient.name) private readonly grpcClient: ClientGrpc,
) {
this.logger = dadosferaLogger.logger;
}
@@ -52,24 +43,34 @@ export class AuthClientService implements OnModuleInit {
async getPublicKeys() {
this.logger.info('GetPublicKeys');
return grpcHandler<AuthGetPublicKeysResponse>(
this.authService.AuthGetPublicKeys({}),
);
return lastValueFrom(this.authService.AuthGetPublicKeys({}));
}
async signIn({ username, password, totp }: AuthSignInRequest) {
async snowflakeSignIn(input: AuthSnowflakeSignInRequest) {
this.logger.info('snowflakeSignIn');
return lastValueFrom(this.authService.AuthSnowflakeSignIn(input));
}
async signIn(
{ username, password, totp }: AuthSignInRequest,
metadata: Metadata,
) {
this.logger.info('SignIn');
return grpcHandler<AuthSignInResponse>(
this.authService.AuthSignIn({ username, password, totp }),
return lastValueFrom(
this.authService.AuthSignIn({ username, password, totp }, metadata),
);
}
async refreshAccessToken({ refreshToken }: AuthRefreshAccessTokenRequest) {
async refreshAccessToken(
{ refreshToken }: AuthRefreshAccessTokenRequest,
metadata: Metadata,
) {
this.logger.info('RefreshAccessToken');
return grpcHandler<AuthRefreshAccessTokenResponse>(
this.authService.AuthRefreshAccessToken({ refreshToken }),
return lastValueFrom(
this.authService.AuthRefreshAccessToken({ refreshToken }, metadata),
);
}
@@ -80,7 +81,7 @@ export class AuthClientService implements OnModuleInit {
}: AuthChangePasswordRequest) {
this.logger.info('ChangePassword');
return grpcHandler<AuthChangePasswordResponse>(
return lastValueFrom(
this.authService.AuthChangePassword({
accessToken,
oldPassword,
@@ -92,9 +93,7 @@ export class AuthClientService implements OnModuleInit {
async resetPassword({ username }: AuthResetPasswordRequest) {
this.logger.info('resetPassword');
return grpcHandler<AuthResetPasswordResponse>(
this.authService.AuthResetPassword({ username }),
);
return lastValueFrom(this.authService.AuthResetPassword({ username }));
}
async verifyResetPasswordCode({
@@ -103,7 +102,7 @@ export class AuthClientService implements OnModuleInit {
}: AuthVerifyResetPasswordCodeRequest) {
this.logger.info('verifyResetPasswordCode');
return grpcHandler<AuthVerifyResetPasswordCodeResponse>(
return lastValueFrom(
this.authService.AuthVerifyResetPasswordCode({ username, code }),
);
}
@@ -115,7 +114,7 @@ export class AuthClientService implements OnModuleInit {
}: AuthConfirmResetPasswordRequest) {
this.logger.info('confirmResetPassword');
return grpcHandler<AuthConfirmResetPasswordResponse>(
return lastValueFrom(
this.authService.AuthConfirmResetPassword({
username,
code,
@@ -127,7 +126,7 @@ export class AuthClientService implements OnModuleInit {
async enableTotpMFA({ accessToken, password }: AuthEnableTotpMfaRequest) {
this.logger.info('enableTotpMFA');
return grpcHandler<AuthEnableTotpMfaResponse>(
return lastValueFrom(
this.authService.AuthEnableTotpMfa({ accessToken, password }),
);
}
@@ -135,7 +134,7 @@ export class AuthClientService implements OnModuleInit {
async disableTotpMFA({ accessToken, password }: AuthDisableTotpMfaRequest) {
this.logger.info('disableTotpMFA');
return grpcHandler<AuthDisableTotpMfaResponse>(
return lastValueFrom(
this.authService.AuthDisableTotpMfa({ accessToken, password }),
);
}
@@ -143,15 +142,13 @@ export class AuthClientService implements OnModuleInit {
async dismissTotpMFA({ accessToken }: AuthDismissTotpMfaRequest) {
this.logger.info('dismissTotpMFA');
return grpcHandler<AuthDismissTotpMfaResponse>(
this.authService.AuthDismissTotpMfa({ accessToken }),
);
return lastValueFrom(this.authService.AuthDismissTotpMfa({ accessToken }));
}
async verifyTotp({ accessToken, totp }: AuthVerifyTotpMfaRequest) {
this.logger.info('disableTotpMFA');
return grpcHandler<AuthVerifyTotpMfaResponse>(
return lastValueFrom(
this.authService.AuthVerifyTotpMfa({ accessToken, totp }),
);
}
+97 -1
View File
@@ -1,4 +1,8 @@
import { ApiProperty } from '@nestjs/swagger';
import {
AuthSignInRequest,
AuthSignInResponse,
} from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
export class LoginDto {
@ApiProperty()
@@ -10,3 +14,95 @@ export class LoginDto {
@ApiProperty({ required: false })
totp: string;
}
export class AuthTokens {
@ApiProperty()
accessToken: string;
@ApiProperty()
refreshToken: string;
@ApiPropertyOptional()
termsOfUseToken: string;
@ApiProperty({ deprecated: true })
idToken: string;
}
export enum MfaStatuses {
PENDING = 'pending',
NONE = 'none',
TOTP = 'totp',
}
export enum TouStatuses {
PENDING = 'pending',
REQUIRED = 'required',
OK = 'ok',
}
export class TermsOfUse {
@ApiProperty()
version: number;
@ApiProperty()
publicUrl: string;
@ApiProperty()
enforceDate: string;
@ApiProperty()
createdAt: string;
}
export class TermsOfUseStatus {
@ApiProperty({ enum: TouStatuses })
status: string;
@ApiPropertyOptional()
lastSigned?: TermsOfUse;
@ApiPropertyOptional()
next?: TermsOfUse;
}
export class AuthUser {
@ApiProperty()
id: string;
@ApiProperty()
name: string;
@ApiProperty()
username: string;
@ApiProperty()
createdAt: string;
}
export class AuthCustomer {
@ApiProperty()
modules: string[];
@ApiProperty()
id: string;
@ApiProperty()
name: string;
@ApiProperty()
tier: string;
@ApiProperty()
scheduleLimit: string;
}
export class AuthSignInReq implements AuthSignInRequest {
@ApiProperty()
username: string;
@ApiProperty()
password: string;
@ApiPropertyOptional()
totp: string;
}
export class AuthSignInRes implements AuthSignInResponse {
@ApiProperty()
permissions: string[];
@ApiProperty({ enum: MfaStatuses })
mfaStatus: string;
@ApiPropertyOptional()
customer?: AuthCustomer;
@ApiPropertyOptional()
user?: AuthUser;
@ApiPropertyOptional()
tokens?: AuthTokens;
@ApiPropertyOptional()
termsOfUse?: TermsOfUseStatus;
}
export class AuthRefreshAccessTokenReq {
@ApiProperty()
refreshToken: string;
@ApiProperty()
customerName: string;
}
+38
View File
@@ -0,0 +1,38 @@
import {
ClientsProviderAsyncOptions,
GrpcOptions,
Transport,
} from '@nestjs/microservices';
import { credentials } from '@grpc/grpc-js';
import { Catalog } from '@dadosfera/protospack-v2';
export class CatalogClientConfiguration {
public name = 'CatalogClientConfiguration';
private config: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: process.env.PIFACTORY_URL,
package: [
Catalog.ProtoPackages.ReadPackage,
Catalog.ProtoPackages.WritePackage,
],
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
protoPath: [
Catalog.ProtoPaths.ReadFilePath,
Catalog.ProtoPaths.WriteFilePath,
],
loader: {
keepCase: true,
enums: String,
defaults: false,
},
},
};
providerOptions: ClientsProviderAsyncOptions = {
name: this.name,
...this.config,
};
}
+489 -339
View File
@@ -3,39 +3,44 @@ import {
Controller,
Delete,
Get,
Headers,
HttpException,
Inject,
Param,
Post,
Put,
Query,
UseFilters,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AuthenticateCondition } from '../../authentication/authentication.decorator';
import { Permissions } from '../../authentication/permissions.enum';
import {
Authenticated,
RequireSomePermission,
} from '../../authentication/authentication.decorator';
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
import { CatalogService } from './catalog.service';
import { DadosferaLogger } from 'dadosfera-logs';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
import { RequestUser, User } from 'src/authentication/user.decorator';
import {
ICatalogAllResponse,
IColumnsMetadataResponse,
ICreateDataAsset,
IDeleteComment,
IDocsResponse,
IMakeAComment,
IOneDataAsset,
IPreviewResponse,
IUpdateDataRequest,
} from './dtos';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
@ApiTags('Catalog')
@Controller('catalog')
@AuthenticateCondition((req, user) => {
let action;
switch (req.method) {
case 'POST':
action = 'CREATE';
break;
case 'PUT':
action = 'UPDATE';
break;
default:
action = req.method;
}
return user.permissions.includes(Permissions.CATALOG[action].seqid);
})
@UseFilters(new GrpcToHttpExceptionFilter())
@Authenticated()
export class CatalogController {
logger: any;
logger: DadosferaLogger;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
@@ -44,377 +49,522 @@ export class CatalogController {
this.logger = dadosferaLogger.logger;
}
@Get('all')
async catalogAll(@Body() body) {
this.logger.info(`/catalog - ON CATALOG ALL ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
@Get()
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async searchCatalog(
@User() user: RequestUser,
@Query() query,
): Promise<ICatalogAllResponse> {
const { user_id, customer_name, customer_id, username, permissions } = user;
this.logger.info(`/catalog - searchCatalog`, {
user_id,
customer_name,
});
const res = await this.catalogService.catalogAll(body);
const is_data_manager = permissions.includes(
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER.seqid,
);
const roles = await this.catalogService.getUserRolesIds(user_id);
const metadata = PackTheMetadata({
user_id,
customer_id,
customer_name,
username,
roles,
is_data_manager,
});
const res = await this.catalogService.searchDataAssets(
query,
metadata,
customer_id,
);
return res;
}
@Get('data_apps')
async dataAppsAll(@Body() body) {
this.logger.info(`/catalog - ON FIND ALL DATA APPS ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
@Get('data-asset')
async findByPipelineAndObject(@User() user: RequestUser, @Query() query) {
const { username, user_id, customer_id, customer_name, permissions } = user;
const { pipeline, object } = query;
this.logger.info(`/catalog - ON GET DATA ASSET BY PIPELINE AND OBJECT`, {
username,
customer_name,
});
const res = await this.catalogService.dataAppsAll(body);
return res;
}
@Delete('data_apps/:id')
async dataAppsOne(@Param() params, @Body() body) {
this.logger.info(`/catalog - ON FIND ONE DATA APP ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const { id } = params;
const res = await this.catalogService.dataAppsOne(id, body);
return res;
}
@Get('dashboard-metabase')
async getAllDashboardMetabase(@Body() body) {
this.logger.info(`/catalog - ON GET ALL DASHBOARDS METABASE ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.getAllDashboardMetabase(body);
return res;
}
@Get('dashboard-metabase/:id')
async getOneDashboardMetabase(@Body() body, @Param() params) {
const { id } = params;
this.logger.info(`/catalog - ON GET ONE DASHBOARD METABASE ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.getOneDashboardMetabase(id, body);
return res;
}
@Get('table-metadata')
async getAllTableMetadata(@Body() body, @Query() query) {
this.logger.info(`/catalog - ON GET ALL TABLES METADATA ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
if (!query) {
const res = await this.catalogService.getAllTableMetadata(body);
return res;
} else {
const res = await this.catalogService.getOneTableMetadata(body, query);
return res;
if (!pipeline || !object) {
throw new HttpException('Query params not provided', 400);
}
}
@Delete('table-metadata/:id')
async deleteOneTableMetadata(@Param() params, @Body() body) {
const { id } = params;
this.logger.info(`/catalog - ON DELETE ONE TABLE METADATA ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
const is_data_manager = permissions.includes(
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER.seqid,
);
let has_permission = false;
const metadata = PackTheMetadata({
username,
user_id: undefined,
customer_id,
customer_name,
});
const res = await this.catalogService.deleteOneTableMetadata(id, body);
const user_roles = await this.catalogService.getUserRolesIds(user_id);
return res;
}
const { data_asset } =
await this.catalogService.getOneDataAssetByPipelineAndObject({
pipeline: query.pipeline,
object: query.object,
customer_id,
metadata,
});
@Get('column-metadata')
async getOneColumnMetadata(@Body() body, @Query() params) {
this.logger.info(`/catalog - ON GET ONE COLUMN METADATA ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
if (data_asset?.owner === username) has_permission = true;
const res = await this.catalogService.getOneColumnMetadata(body, params);
for (const role of user_roles) {
if (data_asset.p_roles.includes(role)) has_permission = true;
}
return res;
}
if (data_asset.p_users.includes(user_id)) has_permission = true;
@Delete('column-metadata/:id')
async deleteOneColumnMetadata(@Param() params, @Body() body) {
this.logger.info(`/catalog - ON DELETE ONE COLUMN METADATA ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const { id } = params;
if (is_data_manager || has_permission) {
delete data_asset.p_roles;
delete data_asset.p_users;
return { data_asset };
}
const res = await this.catalogService.deleteOneColumnMetadata(id, body);
return res;
}
@Get('data-preview')
async getOneDataPreview(@Body() body, @Query() params) {
this.logger.info(`/catalog - ON GET ONE DATAPREVIEW ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.getOneDataPreview(body, params);
return res;
}
@Get('data-status')
async getDataStatus(@Body() body) {
this.logger.info(`/catalog - ON GET DATA STATUS ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.getDataStatus(body);
return res;
}
@Get('data-status')
async createDataStatus(@Body() body) {
this.logger.info(`/catalog - ON CREATE DATA STATUS ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.createDataStatus(body);
return res;
}
@Get('data-description')
async getDataDescription(@Body() body) {
this.logger.info(`/catalog - ON GET DATA DESCRIPTION ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.getDataDescription(body);
return res;
}
@Post('data-description')
async createDataDescription(@Body() body) {
this.logger.info(`/catalog - ON CREATE DATA DESCRIPTION ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.createDataDescription(body);
return res;
}
@Get('data-docs')
async getDataDocs(@Body() body) {
this.logger.info(`/catalog - ON GET DATA DOCS ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.getDataDocs(body);
return res;
}
@Post('data-docs')
async createDataDocs(@Body() body) {
this.logger.info(`/catalog - ON CREATE DATA DOCS ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.createDataDocs(body);
return res;
}
@Get('data-rating')
async getDataRating(@Body() body) {
this.logger.info(`/catalog - ON GET DATA RATING ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.getDataRating(body);
return res;
}
@Post('data-rating')
async createDataRating(@Body() body) {
this.logger.info(`/catalog - ON GET DATA RATING ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.createDataRating(body);
return res;
}
@Get('summary-rating/:id')
async getSummaryRating() {
this.logger.info(`/catalog - ON GET SUMMARY RATING ROUTE`);
//const { id } = params;
//
//const res = await this.catalogService.getSummaryRating(id, body);
return {
avg_rating: 0,
rating_count: 0,
};
}
@Get('data-comment')
async getDataComment(@Body() body) {
this.logger.info(`/catalog - ON GET DATA COMMENT ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.getDataComment(body);
return res;
}
@Post('data-comment')
async createDataComment(@Body() body) {
this.logger.info(`/catalog - ON GET DATA COMMENT ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.createDataComment(body);
return res;
}
@Get('data-review')
async getDataReview(@Body() body, @Query() params) {
this.logger.info(`/catalog - ON GET DATA REVIEW ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.getDataReview(body, params);
return res;
}
@Post('tags')
async createTags(@Body() body) {
this.logger.info(`/catalog - ON CREATE TAG ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.createTags(body);
return res;
throw new HttpException(
'You do not have permission to access this data asset.',
403,
);
}
@Get('tags')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async findAllTags(@Body() body) {
this.logger.info(`/catalog - ON FIND ALL TAGS ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const res = await this.catalogService.findAllTags(body);
const { user_id, customer, customer_id } = body.info;
const metadata = PackTheMetadata({
user_id,
customer_id,
customer_name: customer,
});
const res = await this.catalogService.findAllTags(body, metadata);
return res;
}
@Delete('tags/:id')
async deleteTags(@Param() params, @Body() body) {
this.logger.info(`/catalog - ON DELETE TAG ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
});
const { id } = params;
@Get('data-asset/:id')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async getDataAsset(
@User() user: RequestUser,
@Headers() headers,
@Param('id') id,
) {
const { username, user_id, customer_id, customer_name, permissions } = user;
const res = await this.catalogService.deleteTags(id, body);
this.logger.info(`/catalog - ON GET ONE DASHBOARD METABASE ROUTE`, {
username,
customer_name,
});
const is_data_manager = permissions.includes(
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER.seqid,
);
let has_permission = false;
const metadata = PackTheMetadata({
username,
user_id: undefined,
customer_id,
customer_name,
});
const user_roles = await this.catalogService.getUserRolesIds(user_id);
const { data_asset } = await this.catalogService.getOneDataAsset({
customer_id,
id,
metadata,
});
if (data_asset?.owner === username) has_permission = true;
for (const role of user_roles) {
if (data_asset.p_roles.includes(role)) has_permission = true;
}
if (data_asset.p_users.includes(user_id)) has_permission = true;
if (is_data_manager || has_permission) {
delete data_asset.p_roles;
delete data_asset.p_users;
return { data_asset };
}
throw new HttpException(
'You do not have permission to access this data asset.',
403,
);
}
@Get('data-asset/rls/:id')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async getDataAssetRls(
@User() user: RequestUser,
@Headers() headers,
@Param('id') id,
) {
const { username, user_id, customer_id, customer_name, permissions } = user;
this.logger.info(`/catalog - ON GET ONE DASHBOARD METABASE ROUTE`, {
username,
customer_name,
});
const is_data_manager = permissions.includes(
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER.seqid,
);
let has_permission = false;
const metadata = PackTheMetadata({
username,
user_id,
customer_id,
customer_name,
});
const user_roles = await this.catalogService.getUserRolesIds(user_id);
const { data_asset } = await this.catalogService.getOneDataAsset({
customer_id,
id,
metadata,
});
if (data_asset?.owner === username) has_permission = true;
for (const role of user_roles) {
if (data_asset.p_roles.includes(role)) has_permission = true;
}
if (data_asset.p_users.includes(user_id)) has_permission = true;
if (is_data_manager || has_permission) {
delete data_asset.p_roles;
delete data_asset.p_users;
return { data_asset };
}
throw new HttpException(
'You do not have permission to access this data asset.',
403,
);
}
@Get('data-asset/:id/columns-metadata')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async getDataAssetColumnsMetadata(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Param('id') id,
): Promise<IColumnsMetadataResponse> {
const { customer_name, customer_id, user_id, username } = user;
this.logger.info(`/catalog - columns-metadata`, {
user_id,
customer_name,
});
const metadata = PackTheMetadata({
customer_name,
customer_id,
user_id,
username,
language,
});
const columns_metadata =
await this.catalogService.getDatasetColumnsMetadata(id, metadata);
return { columns_metadata };
}
@Get('data-asset/:id/preview')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async getDataAssetPreview(
@User() user: RequestUser,
@Headers('Dadosfera-lang') language,
@Param('id') id,
): Promise<IPreviewResponse> {
const { customer_name, customer_id, user_id, username } = user;
this.logger.info(`/catalog - ON GET DATA DOCS ROUTE`, {
user_id,
customer_name,
});
const metadata = PackTheMetadata({
customer_name,
customer_id,
user_id,
username,
language,
});
const preview = await this.catalogService.getDatasetPreview(id, metadata);
return { preview };
}
@Get('data-asset/:id/docs')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async getDataAssetDocs(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Param('id') id,
): Promise<IDocsResponse> {
const { customer_name, customer_id, user_id, username } = user;
this.logger.info(`/catalog - ON GET DATA DOCS ROUTE`, {
user_id,
customer_name,
});
const metadata = PackTheMetadata({
customer_name,
customer_id,
user_id,
username,
language,
});
const docs = await this.catalogService.getDataDocs(id, metadata);
return { docs };
}
@Put('data-asset/:id')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async updateDataAsset(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Param('id') id,
@Body() body: IUpdateDataRequest,
): Promise<IOneDataAsset> {
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
customer_id,
customer_name,
user_id,
username,
language,
});
const result = await this.catalogService.updateOneDataAsset({
body,
data_asset_id: id,
customer_id,
metadata,
});
delete result.data_asset.p_roles;
delete result.data_asset.p_users;
return result;
}
@Post('data-asset/:id/docs')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async manageDataAssetDocs(
@User() user: RequestUser,
@Headers() headers,
@Param('id') table_id: string,
@Body('docs') docs: string,
) {
const { user_id, customer_name } = user;
this.logger.info(`/catalog - ON GET DATA DOCS ROUTE`, {
user_id,
customer_name,
});
const res = await this.catalogService.createDataDocs({
table_id,
docs,
info: {
customer: customer_name,
},
});
return res;
}
@Post('table-tags')
async createTableTags(@Body() body) {
this.logger.info(`/catalog - ON CREATE TABLE TAG ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
@Put('data-asset/:id/manage-permissions')
async manageDataAssetPermissions(
@Param('id') id: string,
@User() user: RequestUser,
@Body() body,
) {
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
customer_id,
customer_name,
user_id,
username,
});
const response = await this.catalogService.managePermissions(
{ ...body, id },
metadata,
);
const res = await this.catalogService.createTableTags(body);
return res;
return { data_asset: JSON.parse(response.data_asset) };
}
@Get('table-tags')
async getAllTableTags(@Body() body) {
this.logger.info(`/catalog - ON GET ALL TABLE TAGS ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
@Put('data-asset/:id/revoke-permissions')
async revokeDataAssetPermissions(
@Param('id') id: string,
@User() user: RequestUser,
@Body() body,
) {
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
customer_id,
customer_name,
user_id,
username,
});
const response = await this.catalogService.revokePermissions(
{ ...body, id },
metadata,
);
const res = await this.catalogService.findAllTableTags(body);
return res;
return { message: response.message };
}
@Delete('table-tags/:id')
async deleteTableTags(@Param() params, @Body() body) {
this.logger.info(`/catalog - ON CREATE TABLE TAGS ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
@Post()
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.CREATE,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async createDataAsset(
@User() user: RequestUser,
@Body() body: ICreateDataAsset,
) {
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
customer_id,
customer_name,
user_id,
username,
});
const { id } = params;
const { data_asset } = await this.catalogService.createDataAsset(
body,
metadata,
);
const res = await this.catalogService.deleteTableTags(id, body);
return res;
return { data_asset: JSON.parse(data_asset) };
}
@Get('table-rules')
async getTableRules(@Body() body) {
this.logger.info(`/catalog - ON GET TABLE RULES ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
@Post('data-asset/:id/comment')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async commentOnDataAsset(
@Param('id') id: string,
@User() user: RequestUser,
@Body() body: IMakeAComment,
) {
const { message } = body;
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
customer_id,
customer_name,
user_id,
username,
});
const response = await this.catalogService.commentOnDataAsset(
{ data_asset_id: id, username, message },
metadata,
);
const res = await this.catalogService.getTableRules(body);
return res;
return response;
}
@Delete('table-rules/:id')
async deleteTableRules(@Param() params, @Body() body) {
this.logger.info(`/catalog - ON DELETE TABLE RULES ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
@Delete('data-asset/:id')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.DELETE,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async deleteDataAsset(@Param('id') id: string, @User() user: RequestUser) {
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
customer_id,
customer_name,
user_id,
username,
});
const { id } = params;
const response = await this.catalogService.deleteDataAsset(
{ id, type: undefined },
metadata,
);
const res = await this.catalogService.deleteTableRules(id, body);
return response;
}
return res;
@Delete('data-asset/:id/comment')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
async deleteComment(
@Param('id') id: string,
@User() user: RequestUser,
@Body() body: IDeleteComment,
) {
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
customer_id,
customer_name,
user_id,
username,
});
const response = await this.catalogService.deleteComment(
{ data_asset_id: id, comment: body.comment },
metadata,
);
return response;
}
}
+26
View File
@@ -0,0 +1,26 @@
import { Module } from '@nestjs/common';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { CatalogController } from './catalog.controller';
import { CatalogService } from './catalog.service';
import { CatalogClientConfiguration } from './catalog-client';
import { ClientsModule } from '@nestjs/microservices';
import { PipelinesModule as OldPipelineModule } from 'src/modules/pipelines/pipelines.module';
import { UsersModule } from '../users/users.module';
import { RolesModule } from '../roles/roles.module';
const client = new CatalogClientConfiguration();
@Module({
imports: [
ClientsModule.register([client.providerOptions]),
OldPipelineModule,
UsersModule,
RolesModule,
],
controllers: [CatalogController],
providers: [CatalogService, DadosferaLogger],
exports: [CatalogService],
})
export class CatalogModule {}
+290 -214
View File
@@ -1,6 +1,51 @@
import DadosferaLogger from '@dadosfera/dadosfera-logs/dist';
import {
WriteService,
ReadService,
ProtoServices,
Messages,
} from '@dadosfera/protospack-v2/dist/lib/Catalog';
import {
HttpException,
HttpStatus,
Inject,
OnModuleInit,
} from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import axios from 'axios';
import { lastValueFrom } from 'rxjs';
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;
catalogWriteService: WriteService.CatalogWriteServices;
logger: any;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
@Inject(CatalogClientConfiguration.name)
private readonly grpcClient: ClientGrpc,
private readonly userService: UsersService,
private readonly roleService: RolesService,
) {
this.logger = dadosferaLogger.logger;
}
onModuleInit() {
this.catalogReadService =
this.grpcClient.getService<ReadService.CatalogReadServices>(
ProtoServices.CatalogReadServices,
);
this.catalogWriteService =
this.grpcClient.getService<WriteService.CatalogWriteServices>(
ProtoServices.CatalogWriteServices,
);
}
class CatalogService {
_getNimbusUrl(body) {
const customer = body.info.customer.toLowerCase();
@@ -8,138 +53,228 @@ class CatalogService {
return `https://nimbus-${customer}.dadosfera.ai`;
}
return `https://nimbus-${customer}.${process.env.ENV}.dadosfera.ai`;
return `https://nimbus-${customer}.${process.env.ENV.replace(
'local',
'stg',
)}.dadosfera.ai`;
}
async catalogAll(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(`${nimbusUrl}/api/catalog/all/`);
async createDataAsset(data: Messages.CreateDataAssetRequest, metadata) {
this.logger.info('CatalogService - Manage Data assets permissions');
if (!data.embed) data.embed = undefined;
return data;
}
async dataAppsAll(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(`${nimbusUrl}/api/catalog/data_apps/`);
return data;
}
async dataAppsOne(id, body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(
`${nimbusUrl}/api/catalog/data_apps/${id}/`,
return lastValueFrom(
this.catalogWriteService.CreateDataAsset(data, metadata),
);
return data;
}
async getAllDashboardMetabase(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(
`${nimbusUrl}/api/catalog/dashboard-metabase/`,
);
return data;
}
async managePermissions(data: Messages.ManagePermissionRequest, metadata) {
this.logger.info('CatalogService - Manage Data assets permissions');
async getOneDashboardMetabase(id, body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(
`${nimbusUrl}/api/catalog/dashboard-metabase/${id}`,
);
// const [, path] = data.iframe_url.split('.dadosfera');
// const host = `httpss://metabase-${body.info.customer.toLowerCase()}.dadosfera.ai`;
// data.iframe_url = host + path;
return data;
}
async getAllTableMetadata(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(
`${nimbusUrl}/api/catalog/table-metadata/`,
);
return data;
}
async getOneTableMetadata(body, params) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(
`${nimbusUrl}/api/catalog/table-metadata/`,
{ params: params },
);
return data;
}
async deleteOneTableMetadata(id, body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.delete(
`${nimbusUrl}/api/catalog/table-metadata/${id}`,
);
return data;
}
async getOneColumnMetadata(body, params) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(
`${nimbusUrl}/api/catalog/column-metadata/`,
{ params: params },
);
return data;
}
async deleteOneColumnMetadata(id, body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.delete(
`${nimbusUrl}/api/catalog/column-metadata/${id}/`,
);
return data;
}
async getOneDataPreview(body, params) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(`${nimbusUrl}/api/catalog/data-preview/`, {
params: params,
return lastValueFrom(
this.catalogWriteService.ManagePermission(data, metadata),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 404,
);
});
return data;
}
async getDataStatus(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(`${nimbusUrl}/api/catalog/data-status/`);
return data;
async revokePermissions(data: Messages.RevokePermissionRequest, metadata) {
this.logger.info('CatalogService - Manage Data assets permissions');
return lastValueFrom(
this.catalogWriteService.RevokePermission(data, metadata),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 404,
);
});
}
async createDataStatus(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.post(
`${nimbusUrl}/api/catalog/data-status/`,
body,
async commentOnDataAsset(data: Messages.MakeACommentRequest, metadata) {
this.logger.info('CatalogService - Manage Data assets permissions');
return lastValueFrom(
this.catalogWriteService.MakeAComment(data, metadata),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 404,
);
});
}
async deleteComment(data: Messages.UpdateACommentRequest, metadata) {
this.logger.info('CatalogService - Manage Data assets permissions');
return lastValueFrom(
this.catalogWriteService.UpdateAComment(data, metadata),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 404,
);
});
}
async deleteDataAsset(data: Messages.DeleteDataAssetRequest, metadata) {
this.logger.info('CatalogService - Manage Data assets permissions');
return lastValueFrom(
this.catalogWriteService.DeleteDataAsset(data, metadata),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 404,
);
});
}
async getUserRolesIds(userId: string) {
const result = await this.userService.findOneById(userId).catch(() => null);
const roles_ids = result.user.roles.map((role) => role.id);
return roles_ids;
}
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;
const { data_assets, total } = await lastValueFrom(
this.catalogReadService.GetAllDataAssets(
{
search,
page,
size,
sort_by,
order,
filters: JSON.stringify(filters),
},
metadata,
),
);
return data;
}
async getDataDescription(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(
`${nimbusUrl}/api/catalog/data-description/`,
const result = JSON.parse(data_assets);
const response = await this.getAssetsUsersAndRoles(
result.data_assets,
customer_id,
);
return data;
return { data_assets: response, total };
}
async createDataDescription(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.post(
`${nimbusUrl}/api/catalog/data-description/`,
body,
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, type: undefined },
metadata,
),
);
return data;
let asset = JSON.parse(data_asset);
asset = {
...asset,
p_roles: asset.roles,
p_users: asset.users,
};
asset = await this.getAssetsUsersAndRoles([asset], customer_id);
return { data_asset: asset[0] };
}
async getDataDocs(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(`${nimbusUrl}/api/catalog/data-docs/`);
return data;
async getOneDataAssetByPipelineAndObject(data: {
customer_id: string;
pipeline: string;
object: string;
metadata: Metadata;
}) {
const { customer_id, metadata, pipeline, object } = data;
const { data_asset } = await lastValueFrom(
this.catalogReadService.GetOneDataAssetByPipelineAndObject(
{ pipeline, object },
metadata,
),
);
let asset = JSON.parse(data_asset);
asset = {
...asset,
p_roles: asset.roles,
p_users: asset.users,
};
asset = await this.getAssetsUsersAndRoles([asset], customer_id);
return { data_asset: asset[0] };
}
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);
return { data_asset: asset[0] };
}
async getDataDocs(id: string, metadata: Metadata) {
const { documentation } = await lastValueFrom(
this.catalogReadService.GetDatasetDoc({ id, type: undefined }, metadata),
);
console.log(documentation);
const docs = JSON.parse(documentation);
return docs;
}
async getDatasetPreview(id: string, metadata: Metadata) {
const { preview } = await lastValueFrom(
this.catalogReadService.GetDatasetPreview(
{ id, type: undefined },
metadata,
),
);
const result = JSON.parse(preview);
return result;
}
async getDatasetColumnsMetadata(id: string, metadata: Metadata) {
const { columns_metadata } = await lastValueFrom(
this.catalogReadService.GetDatasetColumnsMetadata(
{ id, type: undefined },
metadata,
),
);
const result = JSON.parse(columns_metadata);
return result;
}
async createDataDocs(body) {
@@ -151,111 +286,52 @@ class CatalogService {
return data;
}
async getDataRating(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(`${nimbusUrl}/api/catalog/data-rating/`);
return data;
}
async findAllTags(data, metadata) {
this.logger.info('CatalogService - findAllCustomerTags');
async createDataRating(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.post(
`${nimbusUrl}/api/catalog/data-rating/`,
body,
const response = await lastValueFrom(
this.catalogReadService.GetCustomerTags(data, metadata),
)
.then((res) => {
this.logger.info('Done');
return res;
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
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;
}
return data_assets.map((data_asset) => {
const owner = customer_users.find(
(u) => u.id === data_asset.owner,
)?.username;
async getSummaryRating(id, body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(
`${nimbusUrl}/api/catalog/summary-rating/${id}`,
);
return data;
}
async getDataComment(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(`${nimbusUrl}/api/catalog/data-comment/`);
return data;
}
async createDataComment(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.post(
`${nimbusUrl}/api/catalog/data-comment/`,
body,
);
return data;
}
async getDataReview(body, params) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(`${nimbusUrl}/api/catalog/data-review/`, {
params: params,
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;
});
return data;
}
async createTags(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.post(`${nimbusUrl}/api/catalog/tags/`, body);
return data;
}
async findAllTags(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(`${nimbusUrl}/api/catalog/tags/`, body);
return data;
}
async findAllTableTags(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(
`${nimbusUrl}/api/catalog/table-tags/`,
body,
);
return data;
}
async deleteTags(id, body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.delete(`${nimbusUrl}/api/catalog/tags/${id}`);
return data;
}
async createTableTags(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.post(
`${nimbusUrl}/api/catalog/table-tags/`,
body,
);
return data;
}
async deleteTableTags(id, body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.delete(
`${nimbusUrl}/api/catalog/table-tags/${id}`,
);
return data;
}
async getTableRules(body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.get(
`${nimbusUrl}/api/catalog/table-rules/`,
body,
);
return data;
}
async deleteTableRules(id, body) {
const nimbusUrl = this._getNimbusUrl(body);
const { data } = await axios.delete(
`${nimbusUrl}/api/catalog/table-rules/${id}`,
);
return data;
}
}
+226
View File
@@ -0,0 +1,226 @@
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;
@ApiProperty()
id: string;
}
export class IUser {
@ApiProperty()
username: string;
@ApiProperty()
id: string;
}
export class IComment {
@ApiProperty()
id: number;
@ApiProperty()
message: string;
@ApiProperty()
created_at: string;
@ApiProperty()
username: string;
}
export class IDataAsset {
@ApiProperty()
id: number;
@ApiPropertyOptional()
database_name?: string;
@ApiPropertyOptional()
table_name?: string;
@ApiPropertyOptional()
num_columns?: number;
@ApiPropertyOptional()
location?: string;
@ApiPropertyOptional()
created_time?: string;
@ApiPropertyOptional()
table_type?: string;
@ApiPropertyOptional()
size_in_bytes?: number;
@ApiPropertyOptional()
num_files?: number;
@ApiPropertyOptional()
data_encrypted?: string;
@ApiPropertyOptional()
num_rows?: number;
@ApiProperty()
display_name: string;
@ApiProperty()
pipeline_id: string;
@ApiProperty()
user_id: string;
@ApiProperty()
description: string;
@ApiProperty()
data_asset_type: string;
@ApiProperty()
tags: string[];
@ApiProperty()
owner: string;
@ApiProperty({ type: [IRole] })
roles: IRole[];
@ApiProperty({ type: [IUser] })
users: IUser[];
@ApiPropertyOptional()
dashboard_id?: number;
@ApiPropertyOptional()
name?: string;
@ApiPropertyOptional()
parameters?: string[];
@ApiPropertyOptional()
embedding_params?: object;
@ApiProperty()
created_at: string;
@ApiPropertyOptional()
updated_at?: string;
@ApiProperty({ type: [IComment] })
comments: IComment[];
@ApiPropertyOptional()
embed?: EmbedObject;
}
export class IOneDataAsset {
@ApiProperty()
data_asset: IDataAsset;
}
export class IMakeAComment {
@ApiProperty()
message: string;
}
export class IDeleteComment {
@ApiProperty()
comment: IComment;
}
export class ICatalogAllResponse {
@ApiProperty({ type: [IDataAsset] })
data_assets: IDataAsset[];
@ApiProperty()
total: number;
}
export class IData {
@ApiProperty()
var: number;
@ApiProperty()
date: string;
@ApiProperty()
last: number;
@ApiProperty()
maximum: number;
@ApiProperty()
minimum: number;
@ApiProperty()
day_opening: number;
}
export class IUpdateDataRequest {
@ApiProperty()
name: string;
@ApiProperty()
description: string;
@ApiProperty()
tags: string[];
@ApiPropertyOptional()
embed: EmbedObject;
}
export class ICreateDataAsset implements CreateDataAssetRequest {
@ApiProperty()
display_name: string;
@ApiProperty()
description: string;
@ApiProperty()
data_asset_type: string;
@ApiProperty()
external_url: string;
@ApiProperty()
location: string;
@ApiPropertyOptional()
embed: EmbedObject;
}
export class IPreview {
@ApiProperty()
id: string;
@ApiProperty()
database_name: string;
@ApiProperty()
table_name: string;
@ApiProperty({ type: [IData] })
data: IData[];
}
export class IDocs {
@ApiProperty()
id: string;
@ApiProperty()
docs: string;
@ApiProperty()
updated_at: string;
@ApiProperty()
table_id: string;
}
export class IColumnMetadata {
@ApiProperty()
id: string;
@ApiProperty()
table_name: string;
@ApiProperty()
column_name: string;
@ApiProperty()
data_type: string;
@ApiProperty()
missing_count: string;
@ApiProperty()
min: string;
@ApiProperty()
max: string;
@ApiProperty()
count: string;
@ApiProperty()
histogram: string;
@ApiProperty()
mean: string;
@ApiProperty()
median: string;
@ApiProperty()
missing_rate: string;
@ApiProperty()
stddev: string;
@ApiProperty()
unique_count: string;
@ApiProperty()
unique_rate: string;
@ApiProperty()
analyzer_rules: string[];
@ApiProperty()
version: string;
}
export class IPreviewResponse {
@ApiProperty()
preview: IPreview;
}
export class IDocsResponse {
@ApiProperty()
docs: IDocs;
}
export class IColumnsMetadataResponse {
@ApiProperty({ type: [IColumnMetadata] })
columns_metadata: IColumnMetadata[];
}
@@ -0,0 +1,30 @@
import { credentials } from '@grpc/grpc-js';
import {
ClientProviderOptions,
GrpcOptions,
Transport,
} from '@nestjs/microservices';
import { ConnectionTest } from '@dadosfera/protospack-v2';
export class ConnectionTestClientConfiguration {
private config: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: process.env.INFACTORY_URL,
package: [ConnectionTest.ProtoPackages.ReadPackage],
credentials:
process.env.ENV === 'local' ? undefined : credentials.createSsl(),
protoPath: [ConnectionTest.ProtoPaths.ReadFilePath],
loader: {
keepCase: true,
enums: String,
objects: true,
arrays: true,
},
},
};
providerOptions: ClientProviderOptions = {
name: 'ConnectionTestGrpcClient',
...this.config,
};
}
@@ -0,0 +1,122 @@
import {
Body,
Controller,
HttpCode,
HttpStatus,
Inject,
Post,
UseFilters,
ValidationPipe,
} from '@nestjs/common';
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { User, RequestUser } from 'src/authentication/user.decorator';
import { ConnectionTestService } from './connection-test.service';
import {
ConnectionTestPingRes,
ConnectionTestPingReq,
ConnectionTestCredentialsReq,
ConnectionTestCredentialsRes,
ConnectionTestListSchemasReq,
ConnectionTestListSchemasRes,
ConnectionTestListTablesReq,
ConnectionTestListTablesRes,
GetTableMetadataRes,
GetTableMetadataReq,
} from './dto/connection-test';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { Authenticated } from 'src/authentication/authentication.decorator';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
@ApiTags('Connection Test')
@Controller('connection-test')
@UseFilters(new GrpcToHttpExceptionFilter())
@Authenticated()
export class ConnectionTestController {
logger: any;
constructor(
private connectionTestService: ConnectionTestService,
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
) {
this.logger = dadosferaLogger.logger;
}
@Post('ping')
@ApiOkResponse({ type: ConnectionTestPingRes })
@HttpCode(HttpStatus.OK)
async connectionTestPing(
@User() user: RequestUser,
@Body(new ValidationPipe()) body: ConnectionTestPingReq,
) {
this.logger.info('/connection-test/ping', {
user: user.user_id,
customer: user.customer_name,
});
return this.connectionTestService.connectionTestPing(body, user);
}
@Post('credentials')
@ApiOkResponse({ type: ConnectionTestCredentialsRes })
@HttpCode(HttpStatus.OK)
async connectionTestCredentials(
@User() user: RequestUser,
@Body() body: ConnectionTestCredentialsReq,
) {
this.logger.info('/connection-test/credentials', {
user: user.user_id,
customer: user.customer_name,
});
return this.connectionTestService.connectionTestCredentials(body, user);
}
@Post('schemas')
@ApiOkResponse({ type: ConnectionTestListSchemasRes })
@HttpCode(HttpStatus.OK)
async connectionTestListSchemas(
@User() user: RequestUser,
@Body(new ValidationPipe()) body: ConnectionTestListSchemasReq,
) {
this.logger.info('/connection-test/schemas', {
user: user.user_id,
customer: user.customer_name,
});
return this.connectionTestService.connectionTestListSchemas(
body,
user.customer_name,
);
}
@Post('tables')
@ApiOkResponse({ type: ConnectionTestListTablesRes })
@HttpCode(HttpStatus.OK)
async connectionTestListTables(
@User() user: RequestUser,
@Body(new ValidationPipe()) body: ConnectionTestListTablesReq,
) {
this.logger.info('/connection-test/tables', {
user: user.user_id,
customer: user.customer_name,
});
return this.connectionTestService.connectionTestListTables(
body,
user.customer_name,
);
}
@Post('table-metadata')
@ApiOkResponse({ type: GetTableMetadataRes })
@HttpCode(HttpStatus.OK)
async getTableMetadata(
@User() user: RequestUser,
@Body(new ValidationPipe()) body: GetTableMetadataReq,
) {
this.logger.info('/connection-test/table-metadata', {
user: user.user_id,
customer: user.customer_name,
});
return this.connectionTestService.getTableMetadata(
body,
user.customer_name,
);
}
}
@@ -0,0 +1,14 @@
import { Module } from '@nestjs/common';
import { ConnectionTestController } from './connection-test.controller';
import { ConnectionTestService } from './connection-test.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { ClientsModule } from '@nestjs/microservices';
import { ConnectionTestClientConfiguration } from './connection-test-client.config';
import { ConnectionModule } from '../connection/connection.module';
const client = new ConnectionTestClientConfiguration();
@Module({
controllers: [ConnectionTestController],
providers: [ConnectionTestService, DadosferaLogger],
imports: [ClientsModule.register([client.providerOptions]), ConnectionModule],
})
export class ConnectionTestModule {}
@@ -0,0 +1,191 @@
import { Inject, Injectable } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { ConnectionTest } from '@dadosfera/protospack-v2';
import { lastValueFrom } from 'rxjs';
import {
ConnectionTestCredentialsReq,
ConnectionTestCredentialsRes,
ConnectionTestListSchemasReq,
ConnectionTestListSchemasRes,
ConnectionTestListTablesReq,
ConnectionTestListTablesRes,
ConnectionTestPingReq,
ConnectionTestPingRes,
GetTableMetadataReq,
GetTableMetadataRes,
} from './dto/connection-test';
import { ConnectionClientService } from '../connection/client.service';
import {
CreateConnectionDto,
DatabaseConnectionPropertiesDto,
} from '../connection/dtos/connection';
import { RequestUser } from 'src/authentication/user.decorator';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
@Injectable()
export class ConnectionTestService {
private connectionTestReadClient: ConnectionTest.ReadService.ConnectionTestReadServices;
constructor(
@Inject('ConnectionTestGrpcClient') private readonly grpcClient: ClientGrpc,
private connectionsService: ConnectionClientService,
) {
this.connectionTestReadClient =
grpcClient.getService<ConnectionTest.ReadService.ConnectionTestReadServices>(
ConnectionTest.ProtoServices.ConnectionTestReadServices,
);
}
async connectionTestPing(
body: ConnectionTestPingReq,
user: RequestUser,
): Promise<ConnectionTestPingRes> {
const {
host: endpoint,
plugin,
port,
network_config_id,
connection_id,
} = body;
const { user_id, customer_id, customer_name } = user;
const metadata = PackTheMetadata({
customer_name,
customer_id,
user_id,
});
if (connection_id) {
const con = await this.connectionsService.getConnectionDetails({
body,
metadata,
});
const conPayload = JSON.parse(con.connection.properties);
const { plugin, network_config_id } = con.connection;
const { host, port, endpoint } = conPayload;
return lastValueFrom(
this.connectionTestReadClient.ConnectionTestPing({
customer_name,
endpoint: endpoint || host,
network_config_id,
plugin,
port: port ? port.toString() : undefined,
connection_id,
}),
);
} else {
return lastValueFrom(
this.connectionTestReadClient.ConnectionTestPing({
customer_name,
endpoint,
network_config_id,
plugin,
port: port ? port.toString() : undefined,
connection_id,
}),
);
}
}
async connectionTestCredentials(
body: ConnectionTestCredentialsReq,
user: RequestUser,
): Promise<ConnectionTestCredentialsRes> {
const { plugin, ...connectionBody } = body;
let { connection_id } = body;
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
customer_id,
customer_name,
user_id,
username,
});
if (body.network_config_id == '') {
body.network_config_id = undefined;
}
/********* CREATE CONNECTION *********/
if (!connection_id) {
const properties: DatabaseConnectionPropertiesDto = {
...connectionBody.properties,
plugin,
credentials_type: 'basic_auth',
};
const createConnectionBody: CreateConnectionDto = {
...body,
properties,
};
const { connection } = await this.connectionsService.createConnection(
createConnectionBody,
metadata,
);
connection_id = connection.id;
}
/************************************/
const { operation_result } = await lastValueFrom(
this.connectionTestReadClient.ConnectionTestCredentials({
connection_id,
customer_name,
plugin,
}),
).catch(async (e) => {
if (!body.connection_id) {
await this.connectionsService.deleteConnection({
body: { id: connection_id },
metadata,
});
}
throw e;
});
if (!operation_result && !body.connection_id) {
await this.connectionsService.deleteConnection({
body: { id: connection_id },
metadata,
});
connection_id = null;
}
return { operation_result, connection_id };
}
async connectionTestListSchemas(
body: ConnectionTestListSchemasReq,
customer_name: string,
): Promise<ConnectionTestListSchemasRes> {
const { connection_id, plugin } = body;
return lastValueFrom(
this.connectionTestReadClient.ListSchemas({
connection_id,
customer_name,
plugin,
}),
);
}
async connectionTestListTables(
body: ConnectionTestListTablesReq,
customer_name: string,
): Promise<ConnectionTestListTablesRes> {
const { connection_id, plugin, schema } = body;
return lastValueFrom(
this.connectionTestReadClient.ListTables({
connection_id,
customer_name,
plugin,
schema,
}),
);
}
async getTableMetadata(
body: GetTableMetadataReq,
customer_name: string,
): Promise<GetTableMetadataRes> {
const { schema, plugin, table_list, connection_id } = body;
return lastValueFrom(
this.connectionTestReadClient.GetTableMetadata({
connection_id,
customer_name,
plugin,
schema,
table_list,
}),
);
}
}
@@ -0,0 +1,133 @@
import { ApiProperty, ApiPropertyOptional, OmitType } from '@nestjs/swagger';
import { IsString, IsOptional } from 'class-validator';
import { DatabaseConnectionPropertiesDto } from 'src/modules/connection/dtos/connection';
import { CreateConnectionDto } from 'src/modules/connection/dtos/connection';
export class ColumnDto {
@ApiProperty()
name: string;
@ApiProperty()
type: string;
}
export class TableMetadataDto {
@ApiProperty()
table_name: string;
@ApiProperty({ type: [ColumnDto] })
columns: ColumnDto[];
@ApiProperty({ type: [ColumnDto] })
references: ColumnDto[];
}
export class ConnectionTestPingReq {
@ApiPropertyOptional()
@IsString()
@IsOptional()
plugin: string;
@ApiPropertyOptional()
@IsString()
@IsOptional()
host: string;
@ApiPropertyOptional()
@IsOptional()
port: number;
@ApiPropertyOptional()
@IsOptional()
@IsString()
network_config_id?: string;
@ApiPropertyOptional()
@IsOptional()
@IsString()
connection_id: string;
}
export class ConnectionTestPingRes {
@ApiProperty()
operation_result: boolean;
}
export class ConnectionTestCredentialsProperties extends OmitType(
DatabaseConnectionPropertiesDto,
['plugin', 'credentials_type'],
) {}
export class ConnectionTestCredentialsReq extends OmitType(
CreateConnectionDto,
['properties'],
) {
@ApiProperty()
properties: ConnectionTestCredentialsProperties;
@ApiPropertyOptional()
connection_id?: string;
}
export class ConnectionTestCredentialsRes {
@ApiProperty()
operation_result: boolean;
@ApiProperty()
connection_id: string;
}
export class ConnectionTestListSchemasReq {
@ApiProperty()
@IsString()
plugin: string;
@ApiProperty()
@IsString()
connection_id: string;
}
export class ConnectionTestListSchemasRes {
@ApiProperty()
operation_result: boolean;
@ApiProperty()
schema_list: string[];
}
export class ConnectionTestListTablesReq {
@ApiProperty()
@IsString()
plugin: string;
@ApiProperty()
@IsString()
connection_id: string;
@ApiProperty()
@IsString()
schema: string;
}
export class ConnectionTestListTablesRes {
@ApiProperty()
operation_result: boolean;
@ApiProperty()
table_list: string[];
}
export class GetTableMetadataReq {
@ApiProperty()
@IsString()
connection_id: string;
@ApiProperty()
@IsString()
plugin: string;
@ApiProperty()
@IsString()
schema: string;
@ApiProperty()
@IsString({ each: true })
table_list: string[];
}
export class GetTableMetadataRes {
@ApiProperty()
operation_result: boolean;
@ApiProperty({ type: [TableMetadataDto] })
tables_metadata: TableMetadataDto[];
}
+40
View File
@@ -0,0 +1,40 @@
import { credentials } from '@grpc/grpc-js';
import {
ClientsProviderAsyncOptions,
GrpcOptions,
Transport,
} from '@nestjs/microservices';
import { ConnectionManager } from '@dadosfera/protospack-v2';
export class ConnectionClientConfiguration {
public name = 'ConnectionClientConfiguration';
private config: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: process.env.INFACTORY_URL,
package: [
ConnectionManager.ProtoPackages.WritePackage,
ConnectionManager.ProtoPackages.ReadPackage,
],
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
protoPath: [
ConnectionManager.ProtoPaths.WriteFilePath,
ConnectionManager.ProtoPaths.ReadFilePath,
],
loader: {
keepCase: true,
enums: String,
objects: true,
arrays: true,
},
},
};
providerOptions: ClientsProviderAsyncOptions = {
name: this.name,
...this.config,
};
}
+340
View File
@@ -0,0 +1,340 @@
import { OnModuleInit, Inject } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { ConnectionManager } from '@dadosfera/protospack-v2';
import { lastValueFrom } from 'rxjs';
import {
ConnectionApiConnection,
ConnectionRes,
ConnectionsRes,
ConnectionToCatalogDto,
CreateConnectionDto,
UpdateConnectionDto,
} from './dtos/connection';
import { ConnectionClientConfiguration } from './client.config';
import {
GetConnectionDetailsResponse,
INTERNAL_GetAllConnectionsResponse,
} from '@dadosfera/protospack-v2/dist/lib/ConnectionManager/interfaces/messages';
import { UsersService } from '../users/users.service';
import { ConnectorClientService } from '../connector/client.service';
import {
ConnectionsApiNetworkConfig,
NetworkConfigDto,
} from '../network-config/dto/network-config';
import DadosferaLogger from '@dadosfera/dadosfera-logs/dist';
export class ConnectionClientService implements OnModuleInit {
private connectionServiceRead: ConnectionManager.ReadService.ConnectionManagerReadServices;
private connectionServiceWrite: ConnectionManager.WriteService.ConnectionManagerWriteServices;
logger: DadosferaLogger;
constructor(
@Inject(ConnectionClientConfiguration.name)
private readonly grpcClient: ClientGrpc,
private usersService: UsersService,
private connectorService: ConnectorClientService,
private dadosferaLogger: DadosferaLogger,
) {
this.logger = dadosferaLogger.logger;
}
onModuleInit() {
this.connectionServiceWrite =
this.grpcClient.getService<ConnectionManager.WriteService.ConnectionManagerWriteServices>(
ConnectionManager.ProtoServices.ConnectionManagerWriteServices,
);
this.connectionServiceRead =
this.grpcClient.getService<ConnectionManager.ReadService.ConnectionManagerReadServices>(
ConnectionManager.ProtoServices.ConnectionManagerReadServices,
);
}
async createConnection(
body: CreateConnectionDto,
metadata,
): Promise<ConnectionRes> {
const {
connector_id,
description,
image_url,
name,
network_config_id,
properties,
type,
connector_name,
plugin,
} = body;
return lastValueFrom(
this.connectionServiceWrite.CreateConnection(
{
connector_id,
connector_name,
description,
image_url,
name,
network_config_id,
properties: JSON.stringify(properties),
type,
plugin,
},
metadata,
),
);
}
async updateConnection(
id: string,
body: UpdateConnectionDto,
metadata,
): Promise<ConnectionRes> {
const { description, name, network_config_id, properties } = body;
return lastValueFrom(
this.connectionServiceWrite.UpdateConnection(
{
id,
description,
name,
network_config_id,
properties: JSON.stringify(properties),
},
metadata,
),
);
}
async deleteConnection({ body, metadata }): Promise<ConnectionRes> {
const { id } = body;
return lastValueFrom(
this.connectionServiceWrite.DeleteConnection(
{
id,
},
metadata,
),
);
}
async getAllConnections({ body, metadata }): Promise<ConnectionsRes> {
const { search, filters, size, page } = body;
return lastValueFrom(
this.connectionServiceRead.GetAllConnection(
{ search, filters: JSON.stringify(filters), size, page },
metadata,
),
);
}
async getConnectionDetails({
body,
metadata,
}): Promise<GetConnectionDetailsResponse> {
const id = body.connection_id || body.id;
return lastValueFrom(
this.connectionServiceRead.GetConnectionDetails({ id }, metadata),
);
}
async INTERNAL_getAllConnections({
customer_name,
}: {
customer_name: string;
}): Promise<INTERNAL_GetAllConnectionsResponse> {
return lastValueFrom(
this.connectionServiceRead.INTERNAL_GetAllConnections({ customer_name }),
);
}
async catalogExistingConnection(data: {
connection?: ConnectionToCatalogDto;
networkConfig?: NetworkConfigDto;
}) {
return lastValueFrom(
this.connectionServiceRead.INTERNAL_CatalogExistingConnection({
data_str: JSON.stringify(data),
}),
);
}
async synchronizeConnections(apply: boolean) {
const connectors = await this.connectorService
.getAllConnectors({
search: undefined,
filters: undefined,
language: 'pt-br',
page: 1,
size: 500,
})
.then(({ connectors: connectorsStr }) =>
JSON.parse(connectorsStr).map((c) => c),
);
const { customers } = await this.usersService.findAllCustomers();
const customer_connections: {
customer_name: string;
customer_id: string;
productConnections: Record<string, any>[];
platformConnections: ConnectionApiConnection[];
productNetworkConfigs: Record<string, any>[];
platformNetworkConfigs: ConnectionsApiNetworkConfig[];
}[] = [];
for (const customer of customers) {
const { name: customer_name, id: customer_id } = customer;
const customer_connection = await this.INTERNAL_getAllConnections({
customer_name,
}).then((res) => ({
customer_name,
customer_id,
platformConnections: res.platformConnections
? JSON.parse(res.platformConnections)
: [],
productConnections: res.productConnections
? JSON.parse(res.productConnections)
: [],
productNetworkConfigs: res.productNetworkConfigs
? JSON.parse(res.productNetworkConfigs)
: [],
platformNetworkConfigs: res.platformNetworkConfigs
? JSON.parse(res.platformNetworkConfigs)
: [],
}));
customer_connections.push(customer_connection);
}
this.logger.info(
'DEBUG_ConnectionsMigrations - ' + JSON.stringify(customer_connections),
);
const migrations: {
customer_name: string;
status: any[];
productConnectionsMissing: ConnectionApiConnection[];
productNetworkConfigsMissing: ConnectionsApiNetworkConfig[];
}[] = [];
for (const customer_connection of customer_connections) {
const productConnectionsMissing: ConnectionApiConnection[] = [];
const productNetworkConfigsMissing: ConnectionsApiNetworkConfig[] = [];
const status: any[] = [];
let updatePromises: Promise<any>[] = [];
this.logger.info(
'DEBUG_ConnectionsMigrations - customer_connections ' +
JSON.stringify(customer_connection),
);
const {
customer_name,
productConnections,
platformConnections,
productNetworkConfigs,
platformNetworkConfigs,
customer_id,
} = customer_connection;
platformConnections?.forEach((plc) => {
const productConnection = productConnections.find(
(prc) => prc.id === plc.config_id,
);
if (!productConnection) productConnectionsMissing.push(plc);
});
platformNetworkConfigs?.forEach((platNetConfig) => {
const productNetworkConfig = productNetworkConfigs.find(
(prodNetConfig) => prodNetConfig.id === platNetConfig.config_id,
);
if (!productNetworkConfig)
productNetworkConfigsMissing.push(platNetConfig);
});
if (apply) {
for (const network_config of productNetworkConfigsMissing) {
const networkConfigToCatalog = {
id: network_config.config_id,
created_at: network_config.created_at,
updated_at: network_config.updated_at,
customer_name: customer_name,
customer_id: customer_id,
user_id: '',
network_type_id: '',
network_type_name: network_config.type,
type: network_config.type,
plugin: network_config.plugin,
name: network_config.name,
description: network_config.description,
properties: undefined,
keywords: undefined,
tags: undefined,
};
updatePromises.push(
this.catalogExistingConnection({
networkConfig: networkConfigToCatalog,
}),
);
}
this.logger.info(
'DEBUG_ConnectionsMigrations - Creating missing network configs for customer' +
customer_name +
' - ' +
JSON.stringify(customer_connection),
);
const updateStatuses = await Promise.all(updatePromises);
status.push(...updateStatuses);
updatePromises = [];
for (const connection of productConnectionsMissing) {
const connector = connectors.find(
(c) => c._source.plugin === connection.plugin,
);
const connectionToCatalog = {
id: connection.config_id,
created_at: connection.created_at,
updated_at: new Date().toISOString(),
customer_id: customer_id,
user_id: '',
plugin: connection.plugin,
name: connection.name,
description: connection.description,
image_url: connector._source.image,
network_config_id: connection.network_config_id,
type: connection.type,
connector_id: connector._id,
connector_name: connector._source.name,
in_use: 1,
username: '',
customer_name,
};
updatePromises.push(
this.catalogExistingConnection({ connection: connectionToCatalog }),
);
}
this.logger.info(
'DEBUG_ConnectionsMigrations - Creating missing connections for customer' +
' - ' +
customer_name +
JSON.stringify(customer_connection),
);
const updateStatuses_2 = await Promise.all(updatePromises);
status.push(...updateStatuses_2);
}
this.logger.info(
'DEBUG_ConnectionsMigrations - migrations for customer ' +
customer_name +
' - ' +
JSON.stringify(customer_connection),
);
migrations.push({
customer_name,
status,
productConnectionsMissing,
productNetworkConfigsMissing,
});
}
return { migrations };
}
}
@@ -0,0 +1,212 @@
import {
Body,
Controller,
Post,
Inject,
Put,
Param,
Delete,
Get,
Headers,
Query,
UseFilters,
} from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { ConnectionClientService } from './client.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import {
Authenticated,
RequireAllPermissions,
} from 'src/authentication/authentication.decorator';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { ValidationPipe } from '../../pipes/object-validation.pipe';
import {
ConnectionDetailsRes,
ConnectionRes,
ConnectionsRes,
UpdateConnectionDto,
} 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()
@Controller('connections')
export class ConnectionController {
logger: any;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
private clientService: ConnectionClientService,
) {
this.logger = dadosferaLogger.logger;
}
@Get('connections-migration')
@RequireAllPermissions(
PERMISSIONS_GROUPS.DADOSFERA.permissions.CONNECTIONS_MIGRATION,
)
async synchronizeConnections(@Query('apply') apply: string) {
return this.clientService.synchronizeConnections(apply === 'true');
}
@Post()
@RequireAllPermissions(connectionPermissions.CREATE)
async createConnection(
@User() user: RequestUser,
@Body(new ValidationPipe()) body: CreateConnectionDto,
): Promise<ConnectionRes> {
this.logger.info('/connections - Create Connection');
const { user_id, customer_id, customer_name, username } = user;
const metadata = PackTheMetadata({
user_id,
customer_id,
customer_name,
username,
});
const response: any = await this.clientService.createConnection(
body,
metadata,
);
return response;
}
@Put('/:id')
@RequireAllPermissions(connectionPermissions.CREATE)
async updateConnection(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language: string,
@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({
user_id,
customer_id,
customer_name,
language,
username,
});
const response: any = await this.clientService.updateConnection(
id,
body,
metadata,
);
return response;
}
@Delete('/:id')
@RequireAllPermissions(connectionPermissions.DELETE)
async deleteConnection(
@User() user: RequestUser,
@Param('id') id: string,
): Promise<ConnectionRes> {
this.logger.info('/connections - Delete Connection');
const { user_id, customer_id, customer_name, username } = user;
const metadata = PackTheMetadata({
user_id,
customer_id,
customer_name,
username,
});
const response: any = await this.clientService.deleteConnection({
body: { id },
metadata,
});
return response;
}
@Get()
async getAllConnections(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@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;
const metadata = PackTheMetadata({
user_id,
customer_id,
customer_name,
language,
username,
});
const response = await this.clientService.getAllConnections({
body: { search, size, page, filters },
metadata,
});
return response;
}
@Get('/:id')
async getConnectionDetails(
@Headers('Dadosfera-Lang') language,
@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);
const { details, sensitive } = queries;
const { user_id, customer_id, customer_name, username } = user;
const metadata = PackTheMetadata({
user_id,
customer_id,
customer_name,
username,
details,
language,
sensitive,
});
const response: any = await this.clientService.getConnectionDetails({
body: { id },
metadata,
});
if (details === 'true') {
const properties = JSON.parse(response.connection.properties);
Object.assign(response.connection, {
pipelines: JSON.parse(response.connection.pipelines),
connection_controls: properties.connection_controls,
config_controls: properties.config_controls,
connection_steps: properties.connection_steps,
});
delete response.connection.properties;
} else {
Object.assign(response.connection, {
properties: JSON.parse(response.connection.properties),
pipelines: JSON.parse(response.connection.pipelines),
});
}
return response;
}
}
@@ -0,0 +1,22 @@
import { Module } from '@nestjs/common';
import { ClientsModule } from '@nestjs/microservices';
import { ConnectionClientService } from './client.service';
import { ConnectionClientConfiguration } from './client.config';
import { ConnectionController } from './connection.controller';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { UsersModule } from '../users/users.module';
import { ConnectorModule } from '../connector/connector.module';
const client = new ConnectionClientConfiguration();
@Module({
imports: [
ClientsModule.register([client.providerOptions]),
UsersModule,
ConnectorModule,
],
controllers: [ConnectionController],
providers: [ConnectionClientService, DadosferaLogger],
exports: [ConnectionClientService],
})
export class ConnectionModule {}
+189
View File
@@ -0,0 +1,189 @@
import {
ApiProperty,
ApiPropertyOptional,
OmitType,
PickType,
} from '@nestjs/swagger';
import {
Connection,
ConnectionToCatalog,
} from '@dadosfera/protospack-v2/dist/lib/ConnectionManager/interfaces/entities';
import {
GetAllConnectionResponse,
GetConnectionDetailsResponse,
GetConnectionResponse,
} from '@dadosfera/protospack-v2/dist/lib/ConnectionManager/interfaces/messages';
export type ConnectionTypes = 'database' | 'file' | 'application';
export type ConnectionCredentialsType =
| 'basic_auth'
| 'iam_user'
| 'role_name'
| 'oauth'
| 'api_key'
| 'service_account'
| 'headers_authF';
export interface ConnectionApiConnection {
config_id: string;
plugin: string;
secret_id: string;
created_at: string;
network_config_id: null;
type: ConnectionTypes;
credentials_type: ConnectionCredentialsType;
credentials: Record<string, any>;
sensitive_fields: string[];
name: string;
customer_name: string;
description: string;
updated_at: string;
}
export class ConnectionDto implements Connection {
// ---Automatically generated information will not be sent by the frontend--- //
@ApiProperty()
id: string;
@ApiProperty()
customer_id: string;
@ApiProperty()
customer_name: string;
@ApiProperty()
user_id: string;
@ApiProperty()
updated_at: string;
@ApiProperty()
created_at: string;
@ApiProperty()
pipelines: string;
// ---Information sent by the frontend--- //
@ApiProperty()
name: string;
@ApiProperty()
description: string;
@ApiProperty()
type: string;
@ApiPropertyOptional()
network_config_id: string | null;
@ApiProperty()
properties: DatabaseConnectionPropertiesDto | any;
// ---Information sent by the frontend (Heirs of Connector)--- //
@ApiProperty()
connector_id: string;
@ApiProperty()
connector_name: string;
@ApiProperty()
plugin: string;
@ApiProperty()
image_url: string;
}
export class ConnectionToCatalogDto implements ConnectionToCatalog {
// ---Automatically generated information - will not be sent by the frontend--- //
id: string;
customer_id: string;
updated_at: string;
created_at: string;
// ---Information extracted from token--- //
user_id: string;
username: string;
customer_name: string;
// ---Information sent by the frontend--- //
@ApiProperty()
name: string;
@ApiProperty()
description: string;
@ApiProperty()
type: string;
@ApiPropertyOptional()
network_config_id: string | null;
// ---Information sent by the frontend (Heirs of Connector)--- //
@ApiProperty()
connector_id: string;
@ApiProperty()
connector_name: string;
@ApiProperty()
plugin: string;
@ApiProperty()
image_url: string;
}
export class CreateConnectionDto extends OmitType(ConnectionDto, [
'id',
'customer_id',
'customer_name',
'user_id',
'created_at',
'updated_at',
'pipelines',
]) {}
export class UpdateConnectionDto extends PickType(ConnectionDto, [
'name',
'description',
'network_config_id',
'properties',
]) {}
export class ConnectionsRes implements GetAllConnectionResponse {
@ApiProperty({ type: [ConnectionToCatalogDto] })
connections: ConnectionToCatalogDto[];
@ApiProperty()
message: string;
}
export class ConnectionRes implements GetConnectionResponse {
@ApiProperty()
connection?: ConnectionToCatalogDto;
@ApiProperty()
message: string;
}
export class ConnectionDetailsRes implements GetConnectionDetailsResponse {
@ApiProperty()
connection?: ConnectionDto;
@ApiProperty()
message: string;
}
export class DatabaseConnectionPropertiesDto {
@ApiProperty()
credentials_type: 'basic_auth';
@ApiProperty()
plugin: string;
@ApiProperty()
host: string;
@ApiProperty()
port: string;
@ApiProperty()
username: string;
@ApiProperty()
password: string;
@ApiProperty()
database: string;
}
+39
View File
@@ -0,0 +1,39 @@
import { credentials } from '@grpc/grpc-js';
import {
ClientsProviderAsyncOptions,
GrpcOptions,
Transport,
} from '@nestjs/microservices';
import { ConnectorManager } from '@dadosfera/protospack-v2';
export class ConnectorClientConfiguration {
public name = 'ConnectorClientConfiguration';
private config: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: process.env.INFACTORY_URL,
package: [
ConnectorManager.ProtoPackages.WritePackage,
ConnectorManager.ProtoPackages.ReadPackage,
],
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
protoPath: [
ConnectorManager.ProtoPaths.WriteFilePath,
ConnectorManager.ProtoPaths.ReadFilePath,
],
loader: {
keepCase: true,
enums: String,
objects: true,
arrays: true,
},
},
};
providerOptions: ClientsProviderAsyncOptions = {
name: this.name,
...this.config,
};
}
+204
View File
@@ -0,0 +1,204 @@
import { Metadata } from '@grpc/grpc-js';
import {
OnModuleInit,
Inject,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { ConnectorManager } from '@dadosfera/protospack-v2';
import { lastValueFrom } from 'rxjs';
import { ConnectorClientConfiguration } from './client.config';
export class ConnectorClientService implements OnModuleInit {
private connectorServiceRead: ConnectorManager.ReadService.ConnectorManagerReadServices;
private connectorServiceWrite: ConnectorManager.WriteService.ConnectorManagerWriteServices;
constructor(
@Inject(ConnectorClientConfiguration.name)
private readonly grpcClient: ClientGrpc,
) {}
onModuleInit() {
this.connectorServiceWrite =
this.grpcClient.getService<ConnectorManager.WriteService.ConnectorManagerWriteServices>(
ConnectorManager.ProtoServices.ConnectorManagerWriteServices,
);
this.connectorServiceRead =
this.grpcClient.getService<ConnectorManager.ReadService.ConnectorManagerReadServices>(
ConnectorManager.ProtoServices.ConnectorManagerReadServices,
);
}
async uploadConnector(uploadConnector) {
const connector: ConnectorManager.Entities.ConnectorCreateRequest = {
file: {
buffer: uploadConnector.file.buffer,
mimetypes: uploadConnector.file.mimetype,
},
connector: JSON.stringify(uploadConnector.connector),
};
const serviceBody: ConnectorManager.Messages.RegisterConnectorRequest = {
connector,
};
return lastValueFrom(
this.connectorServiceWrite.RegisterConnector(serviceBody),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
}
async uploadFile(uploadFile) {
const body: ConnectorManager.Messages.UploadFileRequest = {
file: {
buffer: uploadFile.file.buffer,
mimetypes: uploadFile.file.mimetype,
},
name: uploadFile.name,
};
return lastValueFrom(this.connectorServiceWrite.UploadFile(body)).catch(
(err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
},
);
}
async uploadConnectorsFile(uploadFile: Express.Multer.File) {
const res = await lastValueFrom(
this.connectorServiceWrite.RegisterMultipleConnectorsWithoutImage({
connectors: uploadFile.buffer,
}),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
const responseParsed = JSON.parse(res.message);
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 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: connectorErrors,
created: connectorCreated,
updated: connectorUpdated,
noop: connectorNoop,
};
}
async getAllConnectors(body) {
const meta = new Metadata();
meta.add('Language', body.language);
return lastValueFrom(
this.connectorServiceRead.GetAllConnectors(
{
search: body.search,
filters: JSON.stringify(body.filters),
language: body.language,
page: body.page,
size: body.size,
},
meta,
),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
}
async getConnectorDetails(connectorId: string, language: string) {
const meta = new Metadata();
meta.add('Language', language);
return lastValueFrom(
this.connectorServiceRead.GetConnectorDetails(
{
plugin: connectorId,
},
meta,
),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
}
async getConnector(plugin: string, language: string) {
const meta = new Metadata();
meta.add('Language', language);
return lastValueFrom(
this.connectorServiceRead.GetConnector(
{
plugin,
},
meta,
),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
}
async getConnectorsTags() {
return lastValueFrom(this.connectorServiceRead.GetConnectorsTags({})).catch(
(err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
},
);
}
async deleteConnector(plugin: string, version: string) {
return lastValueFrom(
this.connectorServiceWrite.DeleteConnector({
version,
plugin,
}),
);
}
async updateConnector({ plugin, changes }) {
return lastValueFrom(
this.connectorServiceWrite.UpdateConnector({
plugin,
changes,
}),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
}
}
+91 -20
View File
@@ -11,24 +11,31 @@ import {
UploadedFile,
UseInterceptors,
Inject,
Headers,
UploadedFiles,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
import { ApiBearerAuth, ApiConsumes, ApiTags } from '@nestjs/swagger';
import { ConnectorClientService } from 'src/clients/connector/client.service';
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';
import { UploadFileDto } from './dtos/upload-file';
import { DadosferaLogger } from 'dadosfera-logs';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import {
Authenticated,
RequireAllPermissions,
RequireSomePermission,
} from 'src/authentication/authentication.decorator';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
@ApiTags('connectors')
@ApiBearerAuth()
@Authenticated()
@Controller('connectors')
export class ConnectorController {
logger: any;
logger: DadosferaLogger;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
@@ -38,6 +45,7 @@ export class ConnectorController {
}
@Post()
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.CREATE)
@ApiConsumes('multipart/form-data')
@UseInterceptors(FileInterceptor('file'))
async uploadConnector(
@@ -54,32 +62,59 @@ export class ConnectorController {
return response;
}
@Post('/upload')
@Post('/uploads')
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.CREATE)
@ApiConsumes('multipart/form-data')
@UseInterceptors(FileInterceptor('file'))
async uploadFile(@UploadedFile() file, @Body() { name }: UploadFileDto) {
@UseInterceptors(FilesInterceptor('files'))
async uploadFile(@UploadedFiles() files) {
this.logger.info('/upload - Upload Connector Route');
const response = await this.connectorClientService.uploadFile({
file,
name,
const promises = files.map(async (file) => {
return await this.connectorClientService.uploadFile({
file,
name: file.originalname.split('.')[0],
});
});
const response = await Promise.all(promises);
return response;
}
@Get()
async getAllConnectors(@Query() queries: GetAllDto) {
this.logger.info('/upload - Upload Connector Route');
@Post('/multiple-connectors-upload')
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.CREATE)
@ApiConsumes('multipart/form-data')
@UseInterceptors(FileInterceptor('file'))
async uploadConnectorsFile(@UploadedFile() file: Express.Multer.File) {
this.logger.info(`/upload`, 'Upload Connector Route');
const { search, ...filters } = queries;
return await this.connectorClientService.uploadConnectorsFile(file);
}
@Get()
@RequireSomePermission(
PERMISSIONS_GROUPS.CONNECTORS.permissions.GET,
PERMISSIONS_GROUPS.PIPELINE.permissions.CREATE,
PERMISSIONS_GROUPS.PIPELINE.permissions.GET,
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE,
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
)
async getAllConnectors(
@Headers('dadosfera-lang') language,
@Query() queries: GetAllDto,
) {
this.logger.info('/GET - getAllConnectors Route');
if (!language) language = 'en-us';
const { search, size, page, ...filters } = queries;
const response: any = await this.connectorClientService.getAllConnectors({
filters: filters || {},
search: search || '',
language: language || 'pt-br',
size: size || 10,
page: page || 1,
});
const connectors = JSON.parse(response.connectors).connectors;
const connectors = JSON.parse(response.connectors);
return {
message: response.message,
@@ -87,17 +122,39 @@ export class ConnectorController {
};
}
@Get('/tags')
@RequireSomePermission(
PERMISSIONS_GROUPS.CONNECTORS.permissions.GET,
PERMISSIONS_GROUPS.PIPELINE.permissions.CREATE,
PERMISSIONS_GROUPS.PIPELINE.permissions.GET,
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE,
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
)
async getConnectorsTags() {
return await this.connectorClientService.getConnectorsTags();
}
@Get('/:plugin')
@RequireSomePermission(
PERMISSIONS_GROUPS.CONNECTORS.permissions.GET,
PERMISSIONS_GROUPS.PIPELINE.permissions.CREATE,
PERMISSIONS_GROUPS.PIPELINE.permissions.GET,
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE,
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
)
async getConnector(
@Headers('dadosfera-lang') language,
@Param('plugin') plugin: string,
@Query('version') version: string,
) {
this.logger.info('/upload - Upload Connector Route');
this.logger.info('/GET/:plugin - getConnector Route');
if (!language) language = 'en-us';
const pluginId = `${plugin}-${version}`;
const response: any = await this.connectorClientService.getConnector(
pluginId,
language,
);
return {
@@ -107,16 +164,26 @@ export class ConnectorController {
}
@Get('/:plugin/details')
@RequireSomePermission(
PERMISSIONS_GROUPS.CONNECTORS.permissions.GET,
PERMISSIONS_GROUPS.PIPELINE.permissions.CREATE,
PERMISSIONS_GROUPS.PIPELINE.permissions.GET,
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE,
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
)
async getConnectorDetails(
@Headers('dadosfera-lang') language,
@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(
pluginId,
language || 'pt-br',
);
return {
@@ -126,6 +193,7 @@ export class ConnectorController {
}
@Put('/:plugin')
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.UPDATE)
@ApiConsumes('multipart/form-data')
async updateConnector(
@Param('plugin') plugin: string,
@@ -147,6 +215,7 @@ export class ConnectorController {
}
@Put('/:plugin/add-tag')
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.UPDATE)
async addTagOnConnector(
@Param('plugin') plugin: string,
@Body() body: AddTagDto,
@@ -173,6 +242,7 @@ export class ConnectorController {
}
@Put('/:plugin/remove-tag')
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.UPDATE)
async removeTagOnConnector(
@Param('plugin') plugin: string,
@Body() body: RemoveTagDto,
@@ -200,9 +270,10 @@ export class ConnectorController {
}
@Delete('/:plugin')
@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');
+16
View File
@@ -0,0 +1,16 @@
import { Module } from '@nestjs/common';
import { ClientsModule } from '@nestjs/microservices';
import { ConnectorClientService } from './client.service';
import { ConnectorClientConfiguration } from './client.config';
import { ConnectorController } from './connector.controller';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
const client = new ConnectorClientConfiguration();
@Module({
controllers: [ConnectorController],
providers: [ConnectorClientService, DadosferaLogger],
imports: [ClientsModule.register([client.providerOptions])],
exports: [ConnectorClientService],
})
export class ConnectorModule {}
@@ -0,0 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';
export class UploadConnectorsFileDto {
@ApiProperty({ format: 'binary' })
file: string;
}
+9
View File
@@ -4,6 +4,15 @@ export class GetAllDto {
@ApiProperty()
search: string;
@ApiProperty()
language: string;
@ApiProperty()
size: string;
@ApiProperty()
page: string;
@ApiProperty()
filters: any;
}
+38
View File
@@ -0,0 +1,38 @@
import { credentials } from '@grpc/grpc-js';
import {
ClientsProviderAsyncOptions,
GrpcOptions,
Transport,
} from '@nestjs/microservices';
import {
ProtoPackages,
ProtoPaths,
} from '@dadosfera/protospack-v2/dist/lib/Duc';
export class DucClient {
public name = 'DucClient';
private config: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: process.env.DUC_URL,
package: [ProtoPackages.WritePackage, ProtoPackages.ReadPackage],
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
protoPath: [ProtoPaths.WriteFilePath, ProtoPaths.ReadFilePath],
loader: {
keepCase: true,
enums: String,
objects: true,
arrays: true,
},
},
};
providerOptions: ClientsProviderAsyncOptions = {
name: this.name,
...this.config,
};
}
+2 -2
View File
@@ -1,12 +1,12 @@
import { Controller, Get, Inject } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { HealthService } from './health.service';
import { DadosferaLogger } from 'dadosfera-logs';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
@ApiTags('Health')
@Controller('health')
export class HealthController {
logger: any;
logger: DadosferaLogger;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
+12
View File
@@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { HealthController } from './health.controller';
import { HealthService } from './health.service';
@Module({
controllers: [HealthController],
providers: [HealthService, DadosferaLogger],
})
export class HealthModule {}
+2 -2
View File
@@ -1,9 +1,9 @@
import { Inject, Injectable } from '@nestjs/common';
import { DadosferaLogger } from 'dadosfera-logs';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
@Injectable()
export class HealthService {
logger: any;
logger: DadosferaLogger;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
+38 -195
View File
@@ -1,135 +1,45 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Info } from 'src/clients/inputs/interfaces';
import { Method } from 'axios';
import { ApiProperty, ApiPropertyOptional, OmitType } from '@nestjs/swagger';
export class InputModel {
category: string;
plugin: string;
name: string;
cron?: string;
credentials?: {
connection_type: string;
oauth: string;
oauth_code: string;
start_date: string;
};
options?: {
oauth?: {
get_tokens_url: string;
get_tokens_method?: Method;
get_tokens_url_params: string;
get_tokens_set_response: Record<string, string>;
content_type: string;
};
};
}
class GoogleAnalyticsClientSecrets {
@ApiProperty()
type: string;
@ApiProperty()
project_id: string;
@ApiProperty()
private_key_id: string;
@ApiProperty()
private_key: string;
@ApiProperty()
client_email: string;
@ApiProperty()
client_id: string;
@ApiProperty()
auth_uri: string;
@ApiProperty()
token_uri: string;
@ApiProperty()
auth_provider_x509_cert_url: string;
@ApiProperty()
client_x509_cert_url: string;
}
class OauthObject {
@ApiPropertyOptional()
get_tokens_url: string;
@ApiPropertyOptional()
get_tokens_url_params: string;
@ApiPropertyOptional()
get_tokens_set_response: Record<string, any>;
@ApiPropertyOptional()
content_type: string;
}
class InputOptions {
@ApiPropertyOptional()
oauth: OauthObject;
@ApiPropertyOptional()
skip_select_columns: true;
@ApiPropertyOptional()
skip_select_entities: false;
@ApiPropertyOptional()
skip_transformation: true;
}
class CredentialsJdbc {
@ApiPropertyOptional()
jdbc_user: string;
@ApiPropertyOptional()
jdbc_password: string;
@ApiPropertyOptional()
database: string;
@ApiPropertyOptional()
endpoint: string;
@ApiPropertyOptional()
port: string;
@ApiPropertyOptional()
engine: string;
@ApiPropertyOptional()
schema: string;
}
class FileFormatParams {
@ApiPropertyOptional()
file_format: string;
@ApiPropertyOptional()
encoding: string;
}
class Credentials extends CredentialsJdbc {
@ApiProperty()
connection_type: string;
@ApiPropertyOptional()
client_aws_access_key_id: string;
@ApiPropertyOptional()
client_aws_secret_access_key: string;
@ApiPropertyOptional()
client_bucket: string;
@ApiPropertyOptional()
file_to_extract: string;
@ApiPropertyOptional()
file_format_params: FileFormatParams;
@ApiPropertyOptional()
view_id: string;
@ApiPropertyOptional()
client_secrets: GoogleAnalyticsClientSecrets;
@ApiPropertyOptional()
start_date: string;
@ApiPropertyOptional()
end_date: string;
@ApiPropertyOptional()
oauth_code: string;
}
class Column {
export class Column {
@ApiProperty()
name: string;
@ApiProperty()
type: string;
}
class TableColumns {
export class TableColumns {
@ApiProperty()
name: string;
@ApiProperty()
columns: Column[];
columns: string[];
@ApiProperty()
references: Column[];
@ApiProperty()
type: string;
}
export class AvailableEntity {
@ApiProperty()
name: string;
@ApiProperty()
replication_methods: string[];
}
export class Input {
@ApiProperty()
id: string;
@ApiProperty({ type: [TableColumns] })
tables: TableColumns[];
@ApiProperty()
name: string;
@ApiProperty()
description: string;
@ApiProperty()
plugin: string;
@ApiPropertyOptional()
type?: string;
@ApiProperty()
created_at: string;
@ApiProperty()
updated_at: string;
}
export class GetAvailableEntitiesReq {
@ApiProperty()
@@ -137,79 +47,12 @@ export class GetAvailableEntitiesReq {
}
export class GetAvailableEntitiesRes {
@ApiProperty()
entities: string[];
@ApiProperty({ type: [AvailableEntity] })
entities: AvailableEntity[];
}
export class TestConnectionGetColumnsReq {
@ApiProperty()
plugin: string;
@ApiProperty()
tables: string[];
@ApiPropertyOptional()
credentials: CredentialsJdbc;
@ApiPropertyOptional()
id: string;
@ApiPropertyOptional()
info: Info;
}
export class TestConnectionGetColumnsRes {
@ApiProperty()
tables: TableColumns[];
}
export class TestConnectionReq {
@ApiProperty()
plugin: string;
@ApiProperty()
credentials: CredentialsJdbc;
@ApiPropertyOptional()
info: Info;
}
export class TestConnectionRes {
@ApiProperty()
connection_state: boolean;
@ApiProperty()
total_entities: number;
@ApiProperty()
database_tables: string[];
}
export class CreateInputReq {
@ApiPropertyOptional()
id: string;
@ApiProperty()
plugin: string;
@ApiProperty()
category: string;
@ApiProperty()
credentials: Credentials;
@ApiProperty()
name: string;
@ApiPropertyOptional()
options: InputOptions;
@ApiPropertyOptional()
info: Info;
}
export class Input {
@ApiProperty()
id: string;
@ApiProperty()
category: string;
@ApiProperty()
plugin: string;
@ApiProperty()
name: string;
@ApiProperty()
cron: string;
@ApiProperty()
credentials: Credentials;
@ApiProperty()
client_id: string;
@ApiProperty()
created_at: string;
@ApiProperty()
updated_at: string;
@ApiPropertyOptional()
info: Info;
}
export class CreateInputReq extends OmitType(Input, [
'id',
'created_at',
'updated_at',
]) {}
@@ -1,3 +1,5 @@
import { Info } from 'protospack/dist/lib/interfaces';
interface Values {
jdbc_user: string;
jdbc_password: string;
@@ -9,32 +11,6 @@ interface Values {
schema: string;
}
interface Cron {
hours: string[];
hour_interval: boolean;
hour_resourse: boolean;
hour_resourse_value: number;
month_day: string[];
month_day_interval: boolean;
month_day_resourse: boolean;
month_day_resourse_value: number;
month: string[];
month_interval: boolean;
month_resourse: boolean;
month_resourse_value: number;
week_days: string[];
week_days_interval: boolean;
week_days_resourse: boolean;
week_days_resourse_value: number;
}
export interface Info {
customer_id: string;
user_id: string;
customer: string;
customer_tier: string;
}
export interface ICreateInputRequest {
cron: string;
name: string;
@@ -56,6 +32,7 @@ export interface UpdateInputRequest {
values: Values;
operation: string;
info: Info;
tables: any[];
}
export interface ITestConnectionRequest {
@@ -0,0 +1,38 @@
import { Input } from '@dadosfera/protospack-v2';
import { credentials } from '@grpc/grpc-js';
import {
ClientProviderOptions,
GrpcOptions,
Transport,
} from '@nestjs/microservices';
export class InputsGrpcClient {
public readonly name = 'InputsGrpcClient';
private config: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: process.env.INFACTORY_URL,
package: [
Input.ProtoPackages.WritePackage,
Input.ProtoPackages.ReadPackage,
],
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
protoPath: [
Input.ProtoPaths.WriteFilePath,
Input.ProtoPaths.ReadFilePath,
],
loader: {
keepCase: true,
enums: String,
defaults: false,
},
},
};
providerOptions: ClientProviderOptions = {
name: this.name,
...this.config,
};
}
+58 -84
View File
@@ -7,12 +7,11 @@ import {
Param,
Patch,
Post,
UseFilters,
} from '@nestjs/common';
import { InputsService } from './inputs.service';
import { DadosferaLogger } from 'dadosfera-logs';
import { InputsClientService } from 'src/clients/inputs/client.service';
import { UpdateInputRequest } from 'src/clients/inputs/interfaces';
import { Permissions } from '../../authentication/permissions.enum';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
import { AuthenticateCondition } from 'src/authentication/authentication.decorator';
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
import {
@@ -20,127 +19,102 @@ import {
GetAvailableEntitiesReq,
GetAvailableEntitiesRes,
Input,
TestConnectionGetColumnsReq,
TestConnectionGetColumnsRes,
TestConnectionReq,
TestConnectionRes,
} from './dtos/input.model';
import { UpdateInputRequest } from './dtos/old_interfaces';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { Info } from '@dadosfera/protospack-v2/dist/lib/Input/interfaces/entities';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
@ApiTags('inputs')
@ApiTags('Inputs')
@Controller('inputs')
@AuthenticateCondition((req, user) => {
let action: any;
switch (req.method) {
case 'POST':
action = 'CREATE';
break;
case 'PUT':
action = 'UPDATE';
break;
case 'PATCH':
action = 'UPDATE_PARTIAL';
break;
return (
user.permissions.includes(
PERMISSIONS_GROUPS.PIPELINE.permissions.CREATE.seqid,
) ||
user.permissions.includes(
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE.seqid,
)
);
default:
action = req.method;
return (
user.permissions.includes(
PERMISSIONS_GROUPS.PIPELINE.permissions.CREATE.seqid,
) ||
user.permissions.includes(
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE.seqid,
) ||
user.permissions.includes(
PERMISSIONS_GROUPS.PIPELINE.permissions.GET.seqid,
)
);
}
if (
`${req.method} ${req.route.path}` ===
'GET /inputs/available-entities/:plugin'
) {
action = 'GET_ENTITIES';
}
return user.permissions.includes(Permissions.INPUT[action].seqid);
})
@UseFilters(new GrpcToHttpExceptionFilter())
export class InputsController {
inputService: InputsService;
logger: any;
logger: DadosferaLogger;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
private inputsClientService: InputsClientService,
private inputService: InputsService,
) {
this.logger = dadosferaLogger.logger;
this.inputService = new InputsService(this.inputsClientService);
}
@Get('available-entities/:plugin')
@ApiOkResponse({ type: GetAvailableEntitiesRes })
async getAvailableEntities(
@Body() body,
@Param() params: GetAvailableEntitiesReq,
@User() user: RequestUser,
) {
const { info } = body;
const { plugin } = params;
return await this.inputService.getAvailableEntities({ info, plugin });
}
@Post('/test-connection')
@ApiOkResponse({ type: TestConnectionRes })
async testConnection(@Body() data: TestConnectionReq) {
this.logger.info(`/test-connection - ON TEST CONNECTION ROUTE`, {
user: data.info.user_id,
customer: data.info.customer,
});
const response = await this.inputService.testConnection(data);
return response;
}
@Post('/test-connection/get-columns')
@ApiOkResponse({ type: TestConnectionGetColumnsRes })
async getColumns(@Body() data: TestConnectionGetColumnsReq) {
this.logger.info(
`/test-connection/get-columns - ON TEST CONNECTION GET COLUMNS ROUTE`,
{
user: data.info.user_id,
customer: data.info.customer,
const availableEntities = await this.inputService.getAvailableEntities({
info: {
customer: user.customer_name,
customer_id: user.customer_id,
user_id: user.user_id,
},
);
const response = await this.inputService.getColumns(data);
return response;
plugin,
});
return availableEntities;
}
@Post()
@ApiOkResponse({ type: Input })
async create(@Body() createInputDto: CreateInputReq) {
async create(@Body() body: CreateInputReq, @User() user: RequestUser) {
const info: Info = {
user_id: user.user_id,
customer: user.customer_name,
customer_id: user.customer_id,
};
this.logger.info(`/input - ON CREATE ROUTE`, {
user: createInputDto.info.user_id,
customer: createInputDto.info.customer,
user: info.user_id,
customer: info.customer,
});
const response = await this.inputService.create(createInputDto);
return response;
}
@Post(':id')
@ApiOkResponse({ type: Input })
async reCreate(@Param('id') id: string, @Body() input: CreateInputReq) {
if (!input.id) input.id = id;
this.logger.info(`POST /${id}`, 'ON RECREATE ROUTE');
const response = await this.inputService.reCreate(input);
const response = await this.inputService.create({ body, info });
return response;
}
@Get()
async findAll(@Body() body) {
async findAll(@User() user: RequestUser) {
const { user_id, customer_id, customer_name: customer } = user;
this.logger.info(`/input - ON FIND ALL ROUTE`, {
user: body.info.user_id,
customer: body.info.customer,
user: user.user_id,
customer,
});
const response = await this.inputService.findAll(body);
const info: Info = {
customer,
customer_id,
user_id,
};
const response = await this.inputService.findAll(info);
return response;
}
+16
View File
@@ -0,0 +1,16 @@
import { Module } from '@nestjs/common';
import { ClientsModule } from '@nestjs/microservices';
import { InputsGrpcClient } from './inputs-client.config';
import { InputsController } from './inputs.controller';
import { InputsService } from './inputs.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
const client = new InputsGrpcClient();
@Module({
controllers: [InputsController],
providers: [InputsService, DadosferaLogger],
imports: [ClientsModule.register([client.providerOptions])],
exports: [InputsService],
})
export class InputsModule {}
+161 -92
View File
@@ -1,20 +1,132 @@
import { Body, HttpException, HttpStatus, Injectable } from '@nestjs/common';
import {
ForbiddenException,
HttpException,
HttpStatus,
Inject,
Injectable,
} from '@nestjs/common';
import { Timeout } from '@nestjs/schedule';
import { DecodeGrpcStruct } from 'protospack';
import CronParser, { CronExpression } from 'cron-parser';
import { InputsClientService } from 'src/clients/inputs/client.service';
import { IIdRequest, Info } from 'src/clients/inputs/interfaces';
import { ClientGrpc } from '@nestjs/microservices';
import DadosferaLogger from '@dadosfera/dadosfera-logs/dist';
import { lastValueFrom } from 'rxjs';
import { objectCamelToSnake } from 'src/utils/CaseConverter';
import { IIdRequest, UpdateInputRequest } from './dtos/old_interfaces';
import { Input } from '@dadosfera/protospack-v2';
import {
GetAvailableEntitiesRequest,
InputCreateGenericRequest,
InputCreateS3Request,
InputNewCreateRequest,
TestConnectionRequest,
} from '@dadosfera/protospack-v2/dist/lib/Input/interfaces/messages';
import { Info } from '@dadosfera/protospack-v2/dist/lib/Input/interfaces/entities';
import { CreateInputReq } from './dtos/input.model';
@Injectable()
//TODO refactor this class to remove OLD_inputClient
export class InputsService {
constructor(private inputClient: InputsClientService) { }
logger: DadosferaLogger;
inputWriteService: Input.WriteService.InputWriteService;
inputReadService: Input.ReadService.InputReadService;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
@Inject('InputsGrpcClient') private readonly grpcClient: ClientGrpc,
) {
this.logger = dadosferaLogger.logger;
}
async onModuleInit() {
this.inputWriteService =
this.grpcClient.getService<Input.WriteService.InputWriteService>(
Input.ProtoServices.InputWriteService,
);
this.inputReadService =
this.grpcClient.getService<Input.ReadService.InputReadService>(
Input.ProtoServices.InputReadService,
);
}
OLD_inputClient = {
newCreate: async (createInputDto: InputNewCreateRequest) => {
this.logger.info('InputClientService - Create');
const input = await lastValueFrom(
this.inputWriteService.InputNewCreate(createInputDto),
);
objectCamelToSnake(input);
return input;
},
createS3Inputs: async (createInputDto: InputCreateS3Request) => {
this.logger.info('InputClientService - Create');
createInputDto;
const createInputResponse = await lastValueFrom(
this.inputWriteService.InputCreateS3(createInputDto),
).catch((e) => {
throw new HttpException(e.details, 500);
});
this.logger.info('Done');
objectCamelToSnake(createInputResponse);
return createInputResponse;
},
update: async (updateInputDTO: UpdateInputRequest) => {
this.logger.info('InputClientService - Update');
const updateInputResponse = await lastValueFrom(
this.inputWriteService.InputUpdate(updateInputDTO),
);
return updateInputResponse;
},
testConnection: async (data: TestConnectionRequest) => {
this.logger.info('InputClientService - TestConnection');
const testConnectionResponse = await lastValueFrom(
this.inputReadService.NewTestConnection(data),
);
return testConnectionResponse;
},
getAvailableEntities: async (data) => {
this.logger.info('InputClientService - GetAvailableEntities');
data;
const response = await lastValueFrom(
this.inputReadService.GetAvailableEntities(data),
).catch((err) => {
this.logger.info(err.details);
if (err.details && err.details.includes('400'))
throw new HttpException('Plugin inválido', HttpStatus.BAD_REQUEST);
throw new HttpException(err.details, HttpStatus.INTERNAL_SERVER_ERROR);
});
objectCamelToSnake(response);
return response;
},
};
secondsInADay = 60 * 60 * 24;
secondsInAnHour = 60 * 60;
adjustInputPayload(payload) {
if (payload?.input_generic) return DecodeGrpcStruct(payload.input_generic);
if (!payload.input_s3 && !payload.input_jdbc) return payload;
return payload?.input_s3 || payload?.input_jdbc;
if (payload) {
if (payload.input_generic) {
const { credentials } = payload.input_generic;
return {
...payload.input_generic,
credentials: credentials && JSON.parse(credentials),
};
}
if (payload.input_s3) return payload.input_s3;
if (payload.input_jdbc) return payload.input_jdbc;
const { credentials } = payload;
return {
...payload,
credentials: credentials && JSON.parse(credentials),
};
}
return payload;
}
getDifferenceInSeconds(date1: Date, date2: Date) {
const diffInMs = Math.abs(date2.getTime() - date1.getTime());
@@ -37,86 +149,61 @@ export class InputsService {
const afterNextDate = interval.next().toDate();
const secondsApart = this.getDifferenceInSeconds(nextDate, afterNextDate);
if (customer_tier === 'BASIC' && secondsApart < this.secondsInADay) {
throw new HttpException(
throw new ForbiddenException(
'Intervalo de tempo não pode ser inferior a um dia.',
HttpStatus.FORBIDDEN,
);
} else if (secondsApart < this.secondsInAnHour) {
throw new HttpException(
throw new ForbiddenException(
'Intervalo de tempo não pode ser inferior a uma hora.',
HttpStatus.FORBIDDEN,
);
}
}
async create(@Body() data) {
this.validateCron(data);
let response;
switch (data.plugin.toLowerCase()) {
case 'csv':
case 'json':
case 'parquet':
const { info, ...input } = data;
const inputPayload = this.generateInputS3Payload(input);
response = await this.inputClient.createS3Inputs({
input: inputPayload,
info,
});
break;
case 'oracle':
case 'mysql':
case 'postgresql':
case 'sqlserver':
response = await this.inputClient.newCreate(data);
break;
default:
response = await this.inputClient.createGeneric(data);
break;
}
const adjustedInput = this.adjustInputPayload(response.input);
return { ...response, input: adjustedInput };
async create(data: { body: CreateInputReq; info: Info }) {
// this.validateCron(data);
const { body, info } = data;
const inputCreateGenericRequest: InputCreateGenericRequest = {
input: {
...body,
},
info,
};
const { input } = await lastValueFrom(
this.inputWriteService.InputCreate(inputCreateGenericRequest),
);
const adjustedInput = this.adjustInputPayload(input);
return { input: adjustedInput };
}
async reCreate(data) {
const { info, cron } = data;
if (cron) this.validateCron({ info, cron });
const response = await this.inputClient.createGeneric(data);
const adjustedInput = this.adjustInputPayload(response.input);
return { ...response, input: adjustedInput };
async getAvailableEntities(data: GetAvailableEntitiesRequest) {
return lastValueFrom(this.inputReadService.GetAvailableEntities(data));
}
async getAvailableEntities(data): Promise<{ entities: string[] }> {
return await this.inputClient.getAvailableEntities(data);
}
async findAll(body) {
try {
const findAllInputResponse: any = await this.inputClient.findAll(body);
if (findAllInputResponse?.inputs?.length) {
findAllInputResponse.inputs = findAllInputResponse.inputs.map((input) =>
this.adjustInputPayload(input),
);
}
return findAllInputResponse;
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
async findAll(info: Info) {
const { inputs } = await lastValueFrom(
this.inputReadService.InputFindAll({ info }),
);
if (!inputs) return { inputs: [] };
const inputsReturn = inputs.map((i) => this.adjustInputPayload(i));
return { inputs: inputsReturn };
}
async findOne(idRequest: IIdRequest) {
try {
const findOneInputResponse: any = await this.inputClient.findOne(
idRequest,
);
findOneInputResponse.input = this.adjustInputPayload(
findOneInputResponse.input,
);
return findOneInputResponse;
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
const findOneInputResponse: any = await lastValueFrom(
this.inputReadService.InputFindOne(idRequest),
);
findOneInputResponse.input = this.adjustInputPayload(
findOneInputResponse.input,
);
return findOneInputResponse;
}
async update(id: string, data, info: Info) {
this.validateCron({ ...data, info });
try {
const updateInputResponse: any = await this.inputClient.update({
const updateInputResponse: any = await this.OLD_inputClient.update({
id,
info,
...data,
@@ -132,21 +219,14 @@ export class InputsService {
}
async remove(idRequest: IIdRequest) {
try {
const removeInputResponse = await this.inputClient.remove(idRequest);
return removeInputResponse;
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
return lastValueFrom(this.inputWriteService.InputRemove(idRequest));
}
@Timeout(60000 * 10) // Timeout set for 10 minutes
async testConnection(data) {
try {
const testConnectionInputResponse = await this.inputClient.testConnection(
data,
);
const testConnectionInputResponse =
await this.OLD_inputClient.testConnection(data);
return testConnectionInputResponse;
} catch (err) {
@@ -154,17 +234,6 @@ export class InputsService {
}
}
async getColumns(data) {
try {
const testConnectionGetColumnsResponse =
await this.inputClient.getColumns(data);
return testConnectionGetColumnsResponse;
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
}
generateInputS3Payload(payload) {
const { credentials, plugin, cron } = payload;
if (!credentials) return payload;
@@ -0,0 +1,33 @@
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';
@Authenticated()
@Controller('trackEvent')
export class MixpanelController {
constructor(
@Inject('MIXPANEL_TOKEN')
private readonly mixpanelToken: string,
) {}
@Post(':id')
async trackEvent(@Param('id') id, @Body() body, @User() user: RequestUser) {
delete body.info;
const mixpanel = init(this.mixpanelToken);
await mixpanel.people.set(user.username, {
$name: user.username,
$email: user.username,
customer_name: user.customer_name,
});
await mixpanel.track(id, {
distinct_id: user.username,
customer: user.customer_name,
env: process.env.ENV,
...body,
});
return { id, body, user: user.username };
}
}
+16
View File
@@ -0,0 +1,16 @@
import { Module } from '@nestjs/common';
import { getSecreteFromSecreteManager } from 'src/utils/SecretManager';
import { MixpanelController } from './mixpanel.controller';
@Module({
controllers: [MixpanelController],
providers: [
{
provide: 'MIXPANEL_TOKEN',
useValue: getSecreteFromSecreteManager(
`${process.env.ENV}/root/mixpanel_token`,
),
},
],
})
export class MixpanelModule {}
@@ -0,0 +1,172 @@
import {
NetworkConfigEntity,
NetworkConfigToCatalog,
} from '@dadosfera/protospack-v2/dist/lib/NetworkConfig/interfaces/entities';
import {
ApiProperty,
ApiPropertyOptional,
OmitType,
PickType,
} from '@nestjs/swagger';
export enum NetworkConfigTypesEnum {
vpn = 'vpn',
}
export enum NetworkConfigPluginsEnum {
openvpn = 'openvpn',
}
export interface ConnectionsApiNetworkConfig {
config_id: string;
created_at: string;
credentials: {
CERTIFICATE_FILE: string;
OVPN_CREDENTIALS: string;
TLS_AUTH_FILE: string;
OVPN_FILE: string;
};
customer_name: string;
description: string;
name: string;
plugin: string;
secret_id: string;
sensitive_fields: string[];
type: string;
updated_at: string;
}
export class NetworkConfigDto implements NetworkConfigEntity {
@ApiProperty()
id: string;
@ApiProperty()
created_at: string;
@ApiProperty()
updated_at: string;
@ApiProperty()
customer_name: string;
@ApiProperty()
customer_id: string;
@ApiProperty()
properties: any;
@ApiProperty()
user_id: string;
@ApiProperty()
keywords: string;
@ApiProperty()
tags: string;
@ApiProperty()
network_type_id: string;
@ApiProperty()
network_type_name: string;
@ApiProperty({ enum: NetworkConfigTypesEnum })
type: string;
@ApiProperty({ enum: NetworkConfigPluginsEnum })
plugin: string;
@ApiProperty()
name: string;
@ApiProperty()
description: string;
}
export class CreateNetworkConfigReq extends PickType(NetworkConfigDto, [
'network_type_id',
'network_type_name',
'name',
'description',
]) {
@ApiProperty({ format: 'binary' })
ovpn_file: string;
}
export class NetworkConfigOpenVpnProperties {
@ApiProperty({ enum: NetworkConfigPluginsEnum })
plugin: NetworkConfigPluginsEnum;
@ApiProperty()
OVPN_FILE: string;
@ApiPropertyOptional()
CERTIFICATE_FILE?: string;
@ApiPropertyOptional()
OVPN_CREDENTIALS?: string;
@ApiPropertyOptional()
TLS_AUTH_FILE?: string;
}
export class NetworkConfigToCatalogDto implements NetworkConfigToCatalog {
@ApiProperty()
id: string;
@ApiProperty()
customer_id: string;
@ApiProperty()
plugin: string;
@ApiProperty()
type: string;
@ApiProperty()
name: string;
@ApiProperty()
description: string;
@ApiProperty()
created_at: string;
@ApiProperty()
updated_at: string;
@ApiProperty()
network_type_id: string;
@ApiProperty()
network_type_name: string;
}
export class FindAllNetworkConfigsRes {
@ApiProperty({ type: [NetworkConfigToCatalogDto] })
network_configs: NetworkConfigToCatalogDto[];
@ApiProperty()
message: string;
}
export class FindNetworkConfigByidRes {
@ApiProperty()
network_config: NetworkConfigToCatalogDto;
}
export class FindNetworkConfigByidDetails extends PickType(NetworkConfigDto, [
'id',
'name',
'description',
'type',
'network_type_id',
'customer_name',
]) {
@ApiProperty()
properties: NetworkConfigOpenVpnProperties | string;
}
export class FindNetworkConfigByidDetailsRes {
@ApiProperty()
network_config: FindNetworkConfigByidDetails;
}
export class CreateNetworkConfigRes {
@ApiProperty()
network_config: NetworkConfigToCatalogDto;
}
export class UpdateNetworkConfigReq {
@ApiProperty()
name: string;
@ApiProperty()
description: string;
}
export class UpdateNetworkConfigRes {
@ApiProperty()
network_config: NetworkConfigToCatalogDto;
}
export class DeleteNetworkConfigRes {
@ApiProperty()
message: string;
}
@@ -0,0 +1,38 @@
import { credentials } from '@grpc/grpc-js';
import {
ClientProviderOptions,
GrpcOptions,
Transport,
} from '@nestjs/microservices';
import { NetworkConfig } from '@dadosfera/protospack-v2';
export class NetworkConfigGrpcClient {
public name = 'NetworkConfigGrpcClient';
private config: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: process.env.INFACTORY_URL,
package: [
NetworkConfig.ProtoPackages.ReadPackage,
NetworkConfig.ProtoPackages.WritePackage,
],
credentials:
process.env.ENV === 'local' ? undefined : credentials.createSsl(),
protoPath: [
NetworkConfig.ProtoPaths.ReadFilePath,
NetworkConfig.ProtoPaths.WriteFilePath,
],
loader: {
keepCase: true,
enums: String,
objects: true,
arrays: true,
},
},
};
providerOptions: ClientProviderOptions = {
name: this.name,
...this.config,
};
}
@@ -0,0 +1,152 @@
import {
Body,
Controller,
Delete,
Get,
Headers,
Inject,
Param,
Patch,
Post,
Query,
UploadedFile,
UseInterceptors,
} from '@nestjs/common';
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 {
CreateNetworkConfigReq,
CreateNetworkConfigRes,
FindAllNetworkConfigsRes,
} from './dto/network-config';
import { FileInterceptor } from '@nestjs/platform-express';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import {
Authenticated,
RequireAllPermissions,
} from 'src/authentication/authentication.decorator';
const networkConfigPermissions = PERMISSIONS_GROUPS.NETWORK_CONFIG.permissions;
@ApiTags('Network Config')
@Authenticated()
@Controller('network-config')
export class NetworkConfigController {
logger: any;
constructor(
private networkConfigService: NetworkConfigService,
@Inject(DadosferaLogger) dadosferaLogger: DadosferaLogger,
) {
this.logger = dadosferaLogger.logger;
}
@Get()
@ApiOkResponse({ type: FindAllNetworkConfigsRes })
async findAllNetworkConfigs(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@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;
return this.networkConfigService.findAllNetworkConfigs({
body: { search, size, page, filters },
info: { user_id, customer_id, customer_name, language },
});
}
@Get(':id')
@ApiOkResponse({ type: FindAllNetworkConfigsRes })
async findNetworkConfigById(
@User() user: RequestUser,
@Param('id') id: string,
) {
this.logger.info('GET /network-config/:id', {
user: user.user_id,
customer: user.customer_name,
});
return this.networkConfigService.findNetworkConfigById(id);
}
@Get(':id/details')
@ApiOkResponse({ type: FindAllNetworkConfigsRes })
async findNetworkConfigByIdDetails(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@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,
language,
});
}
@Post()
@ApiOkResponse({ type: CreateNetworkConfigRes })
@RequireAllPermissions(networkConfigPermissions.CREATE)
@ApiConsumes('multipart/form-data')
@UseInterceptors(FileInterceptor('ovpn_file'))
async createNetworkConfigs(
@User() user: RequestUser,
@UploadedFile() file: Express.Multer.File,
@Body() body: CreateNetworkConfigReq,
) {
this.logger.info('POST /network-config', {
user: user.user_id,
customer: user.customer_name,
});
const { customer_id, customer_name, user_id } = user;
return this.networkConfigService.createNetworkConfig(body, file, {
customer_name,
customer_id,
user_id,
});
}
// @Patch(':id')
// @ApiOkResponse({ type: UpdateNetworkConfigRes })
// @RequireAllPermissions(networkConfigPermissions.CREATE)
// async updateNetworkConfig(
// @User() user: RequestUser,
// @Param('id') network_config_id: string,
// @Body() body: UpdateNetworkConfigReq,
// ) {
// this.logger.info('PATCH /network-config/:id', {
// user: user.user_id,
// customer: user.customer_name,
// });
// return this.networkConfigService.updateNetworkConfig(
// body,
// network_config_id,
// );
// }
// @Delete(':id')
// @ApiOkResponse({ type: DeleteNetworkConfigRes })
// async deleteNetworkConfig(
// @User() user: RequestUser,
// @Param('id') network_config_id: string,
// ) {
// this.logger.info('DELETE /network-config', {
// user: user.user_id,
// customer: user.customer_name,
// });
// return this.networkConfigService.deleteNetworkConfig(network_config_id, {
// customer_name: user.customer_name,
// customer_id: user.customer_id,
// });
// }
}
@@ -0,0 +1,14 @@
import { Module } from '@nestjs/common';
import { NetworkConfigController } from './network-config.controller';
import { NetworkConfigService } from './network-config.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { ClientsModule } from '@nestjs/microservices';
import { NetworkConfigGrpcClient } from './network-config-client.config';
const client = new NetworkConfigGrpcClient();
@Module({
controllers: [NetworkConfigController],
providers: [NetworkConfigService, DadosferaLogger],
imports: [ClientsModule.register([client.providerOptions])],
})
export class NetworkConfigModule {}
@@ -0,0 +1,158 @@
import { Metadata } from '@grpc/grpc-js';
import { Inject, Injectable } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { NetworkConfig } from '@dadosfera/protospack-v2';
import { lastValueFrom } from 'rxjs';
import {
CreateNetworkConfigReq,
CreateNetworkConfigRes,
DeleteNetworkConfigRes,
FindAllNetworkConfigsRes,
FindNetworkConfigByidDetailsRes,
FindNetworkConfigByidRes,
UpdateNetworkConfigReq,
UpdateNetworkConfigRes,
} from './dto/network-config';
import { NetworkConfigGrpcClient } from './network-config-client.config';
@Injectable()
export class NetworkConfigService {
private networkConfigReadClient: NetworkConfig.ReadService.NetworkConfigReadService;
private networkConfigWriteClient: NetworkConfig.WriteService.NetworkConfigWriteService;
constructor(
@Inject(NetworkConfigGrpcClient.name)
private readonly grpcClient: ClientGrpc,
) {
this.networkConfigReadClient =
grpcClient.getService<NetworkConfig.ReadService.NetworkConfigReadService>(
NetworkConfig.ProtoServices.NetworkConfigReadService,
);
this.networkConfigWriteClient =
grpcClient.getService<NetworkConfig.WriteService.NetworkConfigWriteService>(
NetworkConfig.ProtoServices.NetworkConfigWriteService,
);
}
async findAllNetworkConfigs({
body,
info,
}): Promise<FindAllNetworkConfigsRes> {
const { search, page, size, filters } = body;
const { language, customer_id, customer_name, user_id } = info;
const meta = new Metadata();
meta.add('language', language);
meta.add('customer_id', customer_id);
meta.add('customer_name', customer_name);
meta.add('user_id', user_id);
return lastValueFrom(
this.networkConfigReadClient.NetworkConfigFindAll(
{ search, filters: JSON.stringify(filters), page, size },
meta,
),
);
}
async findNetworkConfigById(id: string): Promise<FindNetworkConfigByidRes> {
const { network_config } = await lastValueFrom(
this.networkConfigReadClient.NetworkConfigFindOneById({
id,
}),
);
return { network_config };
}
async findNetworkConfigByIdDetails(
id: string,
info?,
): Promise<FindNetworkConfigByidDetailsRes> {
const { customer_name, customer_id, language } = info;
const meta = new Metadata();
meta.add('customer_name', customer_name);
meta.add('customer_id', customer_id);
meta.add('language', language);
const { network_config } = await lastValueFrom(
this.networkConfigReadClient.NetworkConfigFindOneDetailsById(
{ id },
meta,
),
);
Object.assign(network_config, {
properties: JSON.parse(network_config.properties),
});
return { network_config };
}
async createNetworkConfig(
body: CreateNetworkConfigReq,
file: Express.Multer.File,
{ customer_name, customer_id, user_id },
): Promise<CreateNetworkConfigRes> {
const { description, name, network_type_id, network_type_name } = body;
const type = 'vpn';
const plugin = 'openvpn';
const OVPN_FILE_STRING = Buffer.from(file.buffer).toString();
const meta = new Metadata();
meta.add('customer_id', customer_id);
meta.add('customer_name', customer_name);
meta.add('user_id', user_id);
const { network_config } = await lastValueFrom(
this.networkConfigWriteClient.NetworkConfigCreate(
{
description,
name,
properties: JSON.stringify({
OVPN_FILE: OVPN_FILE_STRING,
plugin,
}),
type,
network_type_id,
network_type_name,
plugin,
},
meta,
),
);
return { network_config };
}
async updateNetworkConfig(
body: UpdateNetworkConfigReq,
network_config_id: string,
): Promise<UpdateNetworkConfigRes> {
const { description, name } = body;
const { network_config } = await lastValueFrom(
this.networkConfigWriteClient.NetworkConfigUpdate({
id: network_config_id,
description,
name,
}),
);
return { network_config };
}
async deleteNetworkConfig(
network_config_id: string,
{ customer_name, customer_id },
): Promise<DeleteNetworkConfigRes> {
const meta = new Metadata();
meta.add('customer_id', customer_id);
meta.add('customer_name', customer_name);
return lastValueFrom(
this.networkConfigWriteClient.NetworkConfigDelete(
{ id: network_config_id },
meta,
),
);
}
}
+78 -35
View File
@@ -1,27 +1,29 @@
import { Controller, Get, Redirect, Req, UseGuards } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AuthGuard } from '@nestjs/passport';
import { InputsClientService } from 'src/clients/inputs/client.service';
import { InputsService } from '../inputs/inputs.service';
import { Request } from 'express';
import { ConnectionClientService } from '../connection/client.service';
import jwt from 'jsonwebtoken';
import DadosferaLogger from '@dadosfera/dadosfera-logs/dist';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
@ApiTags('oauth')
@Controller('oauth')
export class OauthController {
inputService: InputsService;
frontendRedirectUri = '';
constructor(private inputsClientService: InputsClientService) {
this.inputService = new InputsService(this.inputsClientService);
redirectUrl: string;
constructor(
private connectionService: ConnectionClientService,
private logger: DadosferaLogger,
) {
switch (process.env.ENV) {
case 'dev':
case 'stg':
this.frontendRedirectUri = `https://app.${process.env.ENV}.dadosfera.ai/coletix/auth-callback`;
this.redirectUrl = `https://app.${process.env.ENV}.dadosfera.ai/collect/auth-callback`;
break;
case 'prd':
this.frontendRedirectUri = `https://app.dadosfera.ai/coletix/auth-callback`;
this.redirectUrl = `https://app.dadosfera.ai/collect/auth-callback`;
break;
default:
this.frontendRedirectUri = `http://localhost:4200/coletix/auth-callback`;
this.redirectUrl = `http://localhost:4200/collect/auth-callback`;
}
}
@Get('hubspot')
@@ -34,7 +36,7 @@ export class OauthController {
@UseGuards(AuthGuard('hubspot'))
@Redirect()
async oauthHubspotCallback(@Req() req) {
return await this.callback(req, 'hubspot');
return await this.callback(req);
}
@Get('googleads')
@@ -47,7 +49,7 @@ export class OauthController {
@UseGuards(AuthGuard('google'))
@Redirect()
async oauthGoogleAdsCallback(@Req() req) {
return await this.callback(req, 'googleads');
return await this.callback(req);
}
@Get('google-sheets')
@@ -60,7 +62,7 @@ export class OauthController {
@UseGuards(AuthGuard('google'))
@Redirect()
async oauthGoogleSheetsCallback(@Req() req) {
return await this.callback(req, 'google-sheets');
return await this.callback(req);
}
@Get('facebook')
@@ -73,7 +75,7 @@ export class OauthController {
@UseGuards(AuthGuard('facebook'))
@Redirect()
async oauthFacebookCallback(@Req() req) {
return await this.callback(req, 'facebook');
return await this.callback(req);
}
@Get('mailchimp')
@@ -86,7 +88,7 @@ export class OauthController {
@UseGuards(AuthGuard('mailchimp'))
@Redirect()
async oauthMailchimpCallback(@Req() req) {
return await this.callback(req, 'mailchimp');
return await this.callback(req);
}
@Get('salesforce')
@@ -99,32 +101,73 @@ export class OauthController {
@UseGuards(AuthGuard('salesforce'))
@Redirect()
async oauthSalesforceCallback(@Req() req) {
return await this.callback(req, 'salesforce');
return await this.callback(req);
}
async callback(@Req() req: Request, plugin) {
const { error, state: customer_id } = req.query;
async callback(@Req() req) {
const { error, state } = req.query;
const url = new URL(this.redirectUrl);
if (error)
return {
url: `${this.frontendRedirectUri}?error=${error}`,
};
const request: any = req;
const { authInfo } = request;
if (error) {
this.logger.error(error);
url.searchParams.set('error', 'Erro ao autorizar');
url.searchParams.set(
'error_description',
`Credenciais inválidas. Erro: [${error}]`,
);
return { url: url.href };
}
if (!authInfo)
return {
url: `${this.frontendRedirectUri}?error=invalid_credentials`,
};
const { authInfo } = req;
if (!authInfo) {
this.logger.error('No authInfo', req);
url.searchParams.set('error', 'Erro ao autorizar');
url.searchParams.set('error_description', `Credenciais inválidas.`);
return { url: url.href };
}
const { accessToken: access_token, refreshToken: refresh_token } = authInfo;
const response = await this.inputService.create({
info: { customer_id, customer: 'customer', user_id: 'empty' },
plugin,
credentials: { access_token, refresh_token },
});
let connectionInfo: any;
try {
connectionInfo = jwt.verify(state as string, process.env.JWT_PRIVATE_KEY);
} catch (error) {
this.logger.error('Invalid state JWT', { state, req, error });
url.searchParams.set('error', 'Erro ao autorizar');
url.searchParams.set(
'error_description',
'Ocorreu um erro ao autorizá-lo. Por favor tente novamente',
);
return { url: url.href };
}
return { url: `${this.frontendRedirectUri}?input_id=${response.input.id}` };
connectionInfo.properties.access_token = access_token;
connectionInfo.properties.refresh_token = refresh_token;
const { customer_id, customer_name, user_id } = connectionInfo;
try {
const response = connectionInfo.id
? await this.connectionService.updateConnection(
connectionInfo.id,
connectionInfo,
PackTheMetadata({ customer_id, customer_name, user_id }),
)
: await this.connectionService.createConnection(
connectionInfo,
PackTheMetadata({ customer_id, customer_name, user_id }),
);
url.searchParams.set('connection_id', response.connection.id);
return { url: url.href };
} catch (error) {
this.logger.error(error);
url.searchParams.set('error', 'Erro ao autorizar');
url.searchParams.set(
'error_description',
'Ocorreu um erro interno ao autorizá-lo. Por favor tente novamente mais tarde',
);
return { url: url.href };
}
}
}
+29
View File
@@ -0,0 +1,29 @@
import { Module } from '@nestjs/common';
import { OauthController } from './oauth.controller';
import { getOauthSecrets } from '../../utils/OauthSecrets';
import { HubspotStrategy } from './passport-strategies/hubspot-strategy';
import { FacebookStrategy } from './passport-strategies/facebook-strategy';
import { GoogleStrategy } from './passport-strategies/google-strategy';
import { MailChimpStrategy } from './passport-strategies/mailchimp-strategy';
import { SalesforceStrategy } from './passport-strategies/salesforce-strategy';
import { ConnectionModule } from '../connection/connection.module';
import { OauthService } from './oauth.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
@Module({
providers: [
DadosferaLogger,
{ provide: 'OAUTH_SECRETS', useValue: getOauthSecrets() },
HubspotStrategy,
FacebookStrategy,
GoogleStrategy,
MailChimpStrategy,
SalesforceStrategy,
OauthService,
],
controllers: [OauthController],
imports: [ConnectionModule],
})
export class OauthModule {}
+53
View File
@@ -0,0 +1,53 @@
import { Injectable } from '@nestjs/common';
import { ConnectionDto } from '../connection/dtos/connection';
import jwt from 'jsonwebtoken';
import { PartialType } from '@nestjs/swagger';
class PartialConnection extends PartialType(ConnectionDto) {}
@Injectable()
export class OauthService {
generateStateFromRequest(prevState, req, type): string {
if (req.route.path.includes('callback')) {
return prevState;
}
const plugin: string = req.route.path.replace('/oauth/', '');
const { query } = req;
const {
name,
description,
connector_id,
connector_name,
image_url,
user_id,
customer_id,
customer_name,
id,
} = query;
const properties = { plugin, credentials_type: 'oauth' };
for (const key in query) {
if (key.includes('properties.')) {
const propertyKey = key.split('.')[1];
properties[propertyKey] = query[key];
}
}
const newConnection: PartialConnection = {
name,
description,
connector_id,
connector_name,
image_url,
user_id,
customer_id,
customer_name,
type,
properties,
plugin,
id,
};
return jwt.sign({ ...newConnection }, process.env.JWT_PRIVATE_KEY);
}
}
@@ -10,12 +10,14 @@ import { OauthSecrets } from 'src/utils/OauthSecrets';
import { Request } from 'express';
import { ParamsDictionary } from 'express-serve-static-core';
import { ParsedQs } from 'qs';
import { OauthService } from '../oauth.service';
@Injectable()
export class FacebookStrategy extends PassportStrategy(Strategy) {
constructor(
@Inject('OAUTH_SECRETS')
private readonly oauthSecrets: OauthSecrets,
private oauthService: OauthService,
) {
const options: StrategyOption = {
clientID: oauthSecrets.facebook.client_id,
@@ -37,8 +39,11 @@ export class FacebookStrategy extends PassportStrategy(Strategy) {
req: Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>,
options?: any,
): void {
const { customer_id } = req.query;
options.state = customer_id;
options.state = this.oauthService.generateStateFromRequest(
options.state,
req,
'application',
);
options.scope = 'ads_read ads_management';
super.authenticate(req, options);
}
@@ -2,6 +2,7 @@ import { Profile, Strategy, StrategyOptions } from 'passport-google-oauth20';
import { PassportStrategy } from '@nestjs/passport';
import { Inject, Injectable } from '@nestjs/common';
import { OauthSecrets } from 'src/utils/OauthSecrets';
import { OauthService } from '../oauth.service';
@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
@@ -9,6 +10,7 @@ export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
constructor(
@Inject('OAUTH_SECRETS')
private readonly oauthSecrets: OauthSecrets,
private oauthService: OauthService,
) {
const options: StrategyOptions = {
clientID: oauthSecrets.google.client_id,
@@ -44,23 +46,30 @@ export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
const plugin: string = req.route.path
.replace('/oauth/', '')
.replace('/callback', '');
const { customer_id } = req.query;
options.scope = ['https://www.googleapis.com/auth/userinfo.email'];
options.callbackURL = `${this.redirect_uri}/${plugin}/callback`;
switch (plugin) {
case 'googleads':
options.state = this.oauthService.generateStateFromRequest(
options.state,
req,
'application',
);
options.scope.push('https://www.googleapis.com/auth/adwords');
break;
case 'google-sheets':
options.state = this.oauthService.generateStateFromRequest(
options.state,
req,
'file',
);
options.scope.push(
'https://www.googleapis.com/auth/drive.metadata.readonly',
'https://www.googleapis.com/auth/spreadsheets.readonly',
);
break;
}
options.state = customer_id;
options.accessType = 'offline';
options.prompt = 'consent';
super.authenticate(req, options);
@@ -2,12 +2,14 @@ import { Strategy } from 'passport-hubspot-oauth2';
import { PassportStrategy } from '@nestjs/passport';
import { Inject, Injectable } from '@nestjs/common';
import { OauthSecrets } from 'src/utils/OauthSecrets';
import { OauthService } from '../oauth.service';
@Injectable()
export class HubspotStrategy extends PassportStrategy(Strategy) {
constructor(
@Inject('OAUTH_SECRETS')
private readonly oauthSecrets: OauthSecrets,
private oauthService: OauthService,
) {
super(
{
@@ -25,8 +27,11 @@ export class HubspotStrategy extends PassportStrategy(Strategy) {
}
authenticate(req, options) {
const { customer_id } = req.query;
options.state = customer_id;
options.state = this.oauthService.generateStateFromRequest(
options.state,
req,
'application',
);
super.authenticate(req, options);
}
}
@@ -2,12 +2,14 @@ import { Strategy } from 'passport-mailchimp';
import { PassportStrategy } from '@nestjs/passport';
import { Inject, Injectable, Req } from '@nestjs/common';
import { OauthSecrets } from 'src/utils/OauthSecrets';
import { OauthService } from '../oauth.service';
@Injectable()
export class MailChimpStrategy extends PassportStrategy(Strategy, 'mailchimp') {
constructor(
@Inject('OAUTH_SECRETS')
private readonly oauthSecrets: OauthSecrets,
private oauthService: OauthService,
) {
const options = {
clientID: oauthSecrets.mailchimp.client_id,
@@ -28,8 +30,12 @@ export class MailChimpStrategy extends PassportStrategy(Strategy, 'mailchimp') {
}
authenticate(@Req() req, options) {
const { customer_id } = req.query;
options.state = customer_id;
if (!req.route.path.includes('callback'))
options.state = this.oauthService.generateStateFromRequest(
options.state,
req,
'application',
);
super.authenticate(req, options);
}
}
@@ -2,6 +2,7 @@ import { Strategy } from 'passport-forcedotcom';
import { PassportStrategy } from '@nestjs/passport';
import { Inject, Injectable } from '@nestjs/common';
import { OauthSecrets } from 'src/utils/OauthSecrets';
import { OauthService } from '../oauth.service';
@Injectable()
export class SalesforceStrategy extends PassportStrategy(
@@ -11,6 +12,7 @@ export class SalesforceStrategy extends PassportStrategy(
constructor(
@Inject('OAUTH_SECRETS')
private readonly oauthSecrets: OauthSecrets,
private oauthService: OauthService,
) {
const options = {
clientID: oauthSecrets.salesforce.client_id,
@@ -40,8 +42,11 @@ export class SalesforceStrategy extends PassportStrategy(
}
authenticate(req, options) {
const { customer_id } = req.query;
options.state = customer_id;
options.state = this.oauthService.generateStateFromRequest(
options.state,
req,
'application',
);
super.authenticate(req, options);
}
}
-121
View File
@@ -1,121 +0,0 @@
import {
Body,
Controller,
Delete,
Get,
Inject,
Param,
Post,
Put,
} from '@nestjs/common';
import { Payload } from '@nestjs/microservices';
import { ApiTags } from '@nestjs/swagger';
import { OutputsClientService } from 'src/clients/outputs/client.service';
import { AuthenticateCondition } from 'src/authentication/authentication.decorator';
import { Permissions } from '../../authentication/permissions.enum';
import { OutputsService } from './outputs.service';
import { DadosferaLogger } from 'dadosfera-logs';
@ApiTags('Outputs')
@Controller('outputs')
@AuthenticateCondition((req, user) => {
let action;
switch (req.method) {
case 'POST':
action = 'CREATE';
break;
case 'PUT':
action = 'UPDATE';
break;
default:
action = req.method;
}
return user.permissions.includes(Permissions.OUTPUT[action].seqid);
})
export class OutputsController {
logger: any;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
private outputsClientService: OutputsClientService,
) {
this.logger = dadosferaLogger.logger;
}
@Post()
async create(@Body() createOutputDto) {
this.logger.info(process.env.DEV_URL + `/output - ON CREATE ROUTE`, {
user: createOutputDto.info.user_id,
customer: createOutputDto.info.customer,
});
const outputService = new OutputsService(this.outputsClientService);
const response = await outputService.create(createOutputDto);
return response;
}
@Get()
async findAll(@Body() data) {
this.logger.info(process.env.DEV_URL + `/output - ON Find All ROUTE`, {
user: data.info.user_id,
customer: data.info.customer,
});
const outputService = new OutputsService(this.outputsClientService);
const response = await outputService.findAll(data);
return response;
}
@Get('/:id')
async findOne(@Body() data, @Param() params) {
const { id } = params;
this.logger.info(
process.env.DEV_URL + `/output/${id} - ON Find One ROUTE`,
{
user: data.info.user_id,
customer: data.info.customer,
},
);
const outputService = new OutputsService(this.outputsClientService);
const response = await outputService.findOne({ id, ...data });
return response;
}
@Put(':id')
async update(@Payload() updateOutputDto, @Param() params) {
const { id } = params;
const { info } = updateOutputDto;
this.logger.info(process.env.DEV_URL + `/output/${id} - ON UPDATE ROUTE`, {
user: updateOutputDto.info.user_id,
customer: updateOutputDto.info.customer,
});
delete updateOutputDto.info;
const outputService = new OutputsService(this.outputsClientService);
const response = await outputService.update(id, updateOutputDto, info);
return response;
}
@Delete(':id')
async delete(@Body() data, @Param() params) {
const { id } = params;
this.logger.info(process.env.DEV_URL + `/output/${id} - ON DELETE ROUTE`, {
user: data.info.user_id,
customer: data.info.customer,
});
const outputService = new OutputsService(this.outputsClientService);
const response = await outputService.remove({ id, ...data });
return response;
}
}
-63
View File
@@ -1,63 +0,0 @@
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { IIdRequest, Info } from 'src/clients/outputs/interfaces';
import { OutputsClientService } from 'src/clients/outputs/client.service';
@Injectable()
export class OutputsService {
constructor(private outputClient: OutputsClientService) {}
async create(createOutputDto) {
try {
const createOutputResponse = await this.outputClient.create(
createOutputDto,
);
return createOutputResponse;
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
}
async findOne(data: IIdRequest) {
try {
const findOneOutputResponse = await this.outputClient.findOne(data);
return findOneOutputResponse;
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
}
async findAll(data) {
try {
const findAllOutputResponse = await this.outputClient.findAll(data);
return findAllOutputResponse;
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
}
async update(id: string, data, info: Info) {
try {
const updateOutputResponse = await this.outputClient.update({
id,
info,
...data,
});
return updateOutputResponse;
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
}
async remove(data: IIdRequest) {
try {
const removeOutputResponse = await this.outputClient.remove(data);
return removeOutputResponse;
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
}
}
+49
View File
@@ -0,0 +1,49 @@
import { ApiProperty } from '@nestjs/swagger';
export class PermissionGroupPermission {
@ApiProperty()
name: string;
@ApiProperty()
id: number;
}
export class PermissionGroup {
@ApiProperty()
title: string;
@ApiProperty({ type: [PermissionGroupPermission] })
permissions: PermissionGroupPermission[];
}
export class Permission {
@ApiProperty()
id: string;
@ApiProperty()
seqid: number;
@ApiProperty()
name: string;
@ApiProperty()
claim: string;
@ApiProperty()
createdAt: string;
@ApiProperty()
updatedAt: string;
}
export class PermissionDto {
@ApiProperty()
id: number;
@ApiProperty()
seqid: number;
@ApiProperty()
name: string;
@ApiProperty()
claim: string;
@ApiProperty()
createdAt: string;
@ApiProperty()
updatedAt: string;
}
export class GetPublicPermissionsRes {
@ApiProperty({ type: [PermissionGroup] })
permissionGroups: PermissionGroup[];
}
@@ -0,0 +1,35 @@
import { ClientsModule } from '@nestjs/microservices';
import { Test, TestingModule } from '@nestjs/testing';
// import { DucClient } from 'src/clients/duc/client.config';
import { PermissionsController } from './permissions.controller';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { PermissionsService } from './permissions.service';
// const client = new DucClient();
const logger = {
info: (...args) => args,
error: (...args) => args,
};
describe.skip('PermissionsController', () => {
let controller: PermissionsController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
// imports: [ClientsModule.register([client.providerOptions])],
controllers: [PermissionsController],
providers: [
{
provide: DadosferaLogger,
useValue: { logger },
},
PermissionsService,
],
}).compile();
controller = module.get<PermissionsController>(PermissionsController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
@@ -0,0 +1,45 @@
import { Controller, Get, Headers, 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 { PermissionUsages } from 'src/authentication/permissions.enum';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { LanguageEnum } from 'src/utils/languages.enum';
import { GetPublicPermissionsRes } from './dto/entities';
import { PermissionsService } from './permissions.service';
@ApiTags('Permissions')
@Authenticated()
@Controller('permissions')
@ApiHeader({
name: 'dadosfera-lang',
enum: LanguageEnum,
required: false,
description: 'Defaults to pt-br',
})
export class PermissionsController {
logger: DadosferaLogger;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
private permissionsService: PermissionsService,
) {
this.logger = dadosferaLogger.logger;
}
@Get()
@ApiOkResponse({ type: GetPublicPermissionsRes })
getPublicPermissions(
@User() user: RequestUser,
@Headers('dadosfera-lang') language,
) {
this.logger.info('getPublicPermissions', { user });
if (!language) language = 'en-us';
const permissionGroups = this.permissionsService.getPermissionsGrouped(
PermissionUsages.PUBLIC,
language,
);
return { permissionGroups };
}
}
+10 -13
View File
@@ -1,21 +1,18 @@
import { Module } from '@nestjs/common';
import { ClientsModule } from '@nestjs/microservices';
import { DadosferaLogger } from 'dadosfera-logs';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { PermissionsClientService } from './permissions.service';
import { PermissionsService } from './permissions.service';
import { DucClient } from '../../clients/duc/client.config';
const ducClient = new DucClient();
import { DucClient } from '../duc/client.config';
import { PermissionsController } from './permissions.controller';
const client = new DucClient();
@Module({
imports: [
ClientsModule.register([
{
name: 'DUC_PACKAGE',
...ducClient.config(),
},
]),
],
providers: [PermissionsClientService, DadosferaLogger],
imports: [ClientsModule.register([client.providerOptions])],
providers: [PermissionsService, DadosferaLogger],
controllers: [PermissionsController],
exports: [PermissionsService],
})
export class PermissionsModule {}
+64 -18
View File
@@ -5,35 +5,40 @@ import {
Injectable,
} from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { lastValueFrom } from 'rxjs';
import { ProtoServices } from 'protospack-v2/dist/lib/Duc';
import { PermissionsProtoService as PermissionsServiceInterface } from 'protospack-v2/dist/lib/Duc/interfaces/write-service';
import { ProtoServices } from '@dadosfera/protospack-v2/dist/lib/Duc';
import { PermissionsProtoService as PermissionsServiceInterface } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/write-service';
import { InjectPermissionsRequest } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import {
Empty,
InjectPermissionsRequest,
} from 'protospack-v2/dist/lib/Duc/interfaces/messages';
import { DadosferaLogger } from 'dadosfera-logs';
import grpcHandler from '../../utils/grpcHandler';
import { Permissions } from '../../authentication/permissions.enum';
PERMISSIONS_GROUPS,
PermissionUsages,
PermissionsObjectGroup,
PermissionsObjectPermissionTranslated,
} from '../../authentication/permissions.enum';
import ErrorBuilder from '../../utils/ErrorBuilder';
import { PermissionGroupPermission, PermissionGroup } from './dto/entities';
import { LanguageEnum } from 'src/utils/languages.enum';
import { DucClient } from '../duc/client.config';
@Injectable()
export class PermissionsClientService
export class PermissionsService
implements OnModuleInit, OnApplicationBootstrap
{
logger: any;
logger: DadosferaLogger;
private permissionsService: PermissionsServiceInterface;
private permissionsClientService: PermissionsServiceInterface;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
@Inject('DUC_PACKAGE') private readonly grpcClient: ClientGrpc,
@Inject(DucClient.name) private readonly grpcClient: ClientGrpc,
) {
this.logger = dadosferaLogger.logger;
}
onModuleInit() {
this.permissionsService =
this.permissionsClientService =
this.grpcClient.getService<PermissionsServiceInterface>(
ProtoServices.PermissionsProtoService,
);
@@ -43,8 +48,8 @@ export class PermissionsClientService
async onApplicationBootstrap() {
this.logger.info('sending permissions to DUC...');
const permissions = Object.values(Permissions).flatMap((namespace) =>
Object.values(namespace),
const permissions = Object.values(PERMISSIONS_GROUPS).flatMap((namespace) =>
Object.values(namespace.permissions),
);
return this.injectPermissions({
@@ -52,7 +57,7 @@ export class PermissionsClientService
}).catch((err: ErrorBuilder) => {
if (
err.code === 'No connection established' &&
process.env.LOCAL_ENV === 'true'
(process.env.LOCAL_ENV === 'true' || process.env.ENV === 'local')
) {
return this.logger.info(
"couldn't connect to DUC. suppresing in local env",
@@ -66,8 +71,49 @@ export class PermissionsClientService
async injectPermissions({ permissions }: InjectPermissionsRequest) {
this.logger.info('InjectPermissions');
return grpcHandler<Empty>(
this.permissionsService.InjectPermissions({ permissions }),
return lastValueFrom(
this.permissionsClientService.InjectPermissions({ permissions }),
);
}
getPermissionsGrouped(
permissionUsage?: PermissionUsages,
language: LanguageEnum = LanguageEnum.ptbr,
): PermissionGroup[] {
const groups: PermissionGroup[] = [];
for (const key in PERMISSIONS_GROUPS) {
const permissionGroup: PermissionsObjectGroup = PERMISSIONS_GROUPS[key];
const title = permissionGroup.title[language];
const permissions: PermissionGroupPermission[] = Object.values(
permissionGroup.permissions,
)
.filter(({ usage }) =>
permissionUsage ? usage === permissionUsage : true,
)
.map(({ seqid, name }) => ({ id: seqid, name: name[language] }));
if (permissions?.length)
groups.push({
title,
permissions,
});
}
return groups;
}
getAllPermissions(language: LanguageEnum = LanguageEnum.ptbr) {
let permissions: PermissionsObjectPermissionTranslated[] = [];
for (const key in PERMISSIONS_GROUPS) {
const permissionGroup: PermissionsObjectGroup = PERMISSIONS_GROUPS[key];
const permissionGroupPermissions: PermissionsObjectPermissionTranslated[] =
Object.values(permissionGroup.permissions).map((p) => ({
...p,
name: p.name[language],
}));
permissions = permissions.concat(permissionGroupPermissions);
}
return permissions;
}
getPermissionsBySeqId(seqIds: number[]) {
const permissionGroupPermissions = this.getAllPermissions();
return permissionGroupPermissions.filter((p) => seqIds.includes(p.seqid));
}
}
+74
View File
@@ -0,0 +1,74 @@
import { ConflictException, Inject, OnModuleInit } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { PipelineServicesNames, PipelinesServiceInterface } from 'protospack';
import { lastValueFrom } from 'rxjs';
import { IIdRequest } from './interfaces';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { PipelinesClientConfiguration } from './pipelines-client';
export class PipelinesClientService implements OnModuleInit {
private pipelineService: PipelinesServiceInterface;
logger: DadosferaLogger;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
@Inject(PipelinesClientConfiguration.name)
private readonly grpcClient: ClientGrpc,
) {
this.logger = dadosferaLogger.logger;
}
onModuleInit() {
this.pipelineService =
this.grpcClient.getService<PipelinesServiceInterface>(
PipelineServicesNames.PipelineService,
);
}
async getPipelineStatus(data) {
this.logger.info('PipelinesClientService - GetPipelineStatus');
const statusPipelineResponse = await lastValueFrom(
this.pipelineService.getPipelineStatus(data),
)
.then((res) => {
const statusArray =
res.status?.sort((a, b) => {
if (a.id < b.id) {
return 1;
} else {
return -1;
}
}) || [];
return { status: statusArray };
})
.catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
this.logger.info('Done');
return statusPipelineResponse;
}
async runPipeline({ id, info }: IIdRequest) {
this.logger.info('PipelinesClientService - RunPipeline');
const statusPipelineResponse = await lastValueFrom(
this.pipelineService.triggerPipeline({ id, info }),
).catch((err) => {
this.logger.error(err.message);
throw new Error(err);
});
if (statusPipelineResponse.status == false) {
throw new ConflictException(
'This pipeline is not ready yet to execute, Try again later!',
);
}
this.logger.info('Done');
return statusPipelineResponse;
}
}
@@ -1,3 +1,5 @@
import { Info } from 'protospack/dist/lib/interfaces';
export interface ICreatePipelineDto {
input: IdRequest;
transformations: IdRequest[];
@@ -8,11 +10,6 @@ export interface ICreatePipelineDto {
info: Info;
}
export interface Info {
customer_id: sting;
user_id: string;
}
export interface IdRequest {
id: string;
}
+32
View File
@@ -0,0 +1,32 @@
import {
ClientsProviderAsyncOptions,
GrpcOptions,
Transport,
} from '@nestjs/microservices';
import { PipelinePackages, PipelineProtoFilePath } from 'protospack';
import { credentials } from '@grpc/grpc-js';
export class PipelinesClientConfiguration {
public name = 'PipelinesClientConfiguration';
private config: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: process.env.PIFACTORY_URL,
package: PipelinePackages,
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
protoPath: PipelineProtoFilePath,
loader: {
keepCase: true,
enums: String,
defaults: false,
},
},
};
providerOptions: ClientsProviderAsyncOptions = {
name: this.name,
...this.config,
};
}
+15 -94
View File
@@ -1,22 +1,16 @@
import {
Body,
Controller,
Delete,
Get,
Inject,
Param,
Post,
Put,
} from '@nestjs/common';
import { Body, Controller, Get, Inject, Param, Post } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { PipelinesClientService } from 'src/clients/pipelines/client.service';
import { AuthenticateCondition } from 'src/authentication/authentication.decorator';
import { Permissions } from '../../authentication/permissions.enum';
import {
AuthenticateCondition,
Authenticated,
} from 'src/authentication/authentication.decorator';
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
import { PipelinesService } from './pipelines.service';
import { DadosferaLogger } from 'dadosfera-logs';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
@ApiTags('Pipelines')
@Controller('pipelines')
@Authenticated()
@AuthenticateCondition((req, user) => {
let action;
@@ -33,14 +27,16 @@ import { DadosferaLogger } from 'dadosfera-logs';
action = req.method;
}
return user.permissions.includes(Permissions.PIPELINE[action].seqid);
return user.permissions.includes(
PERMISSIONS_GROUPS.PIPELINE.permissions[action].seqid,
);
})
export class PipelinesController {
logger: any;
logger: DadosferaLogger;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
private pipelinesClientService: PipelinesClientService,
private pipelineService: PipelinesService,
) {
this.logger = dadosferaLogger.logger;
}
@@ -58,8 +54,7 @@ export class PipelinesController {
},
);
const pipelineService = new PipelinesService(this.pipelinesClientService);
const response = await pipelineService.runPipeline({ id, info });
const response = await this.pipelineService.runPipeline({ id, info });
return response;
}
@@ -77,81 +72,7 @@ export class PipelinesController {
},
);
const pipelineService = new PipelinesService(this.pipelinesClientService);
const response = await pipelineService.getPipelineStatus(body);
return response;
}
@Get(':id/:details')
async getPipelineLogs(@Param() params) {
const { id, details } = params;
this.logger.info(
process.env.DEV_URL + `/pipeline/${id} - ON GET PIPELINE LOGS ROUTE`,
{},
);
const pipelineService = new PipelinesService(this.pipelinesClientService);
const response = await pipelineService.getPipelineLogsMessages(id, details);
return response;
}
@Post()
async create(@Body() createPipelineDto) {
this.logger.info(process.env.DEV_URL + `/pipelines ON CREATE ROUTE`);
const pipelineService = new PipelinesService(this.pipelinesClientService);
const response = await pipelineService.create(createPipelineDto);
return response;
}
@Get()
async findAll(@Body() data) {
this.logger.info(process.env.DEV_URL + `/pipeline ON Find All ROUTE`, {
user: data.info.user_id,
customer: data.info.customer,
});
const pipelineService = new PipelinesService(this.pipelinesClientService);
const response = await pipelineService.findAll(data);
return response;
}
@Get('/:id')
async findOne(@Body() data, @Param() params) {
const { id } = params;
this.logger.info(process.env.DEV_URL + `/pipeline/${id} ON Find One ROUTE`);
const pipelineService = new PipelinesService(this.pipelinesClientService);
const response = await pipelineService.findOne({ id, ...data });
return response;
}
@Put(':id')
async update(@Body() updatePipelineDto, @Param() params) {
const { id } = params;
const { info } = updatePipelineDto;
delete updatePipelineDto.info;
this.logger.info(process.env.DEV_URL + `/pipeline/${id} ON UPDATE ROUTE`);
const pipelineService = new PipelinesService(this.pipelinesClientService);
const response = await pipelineService.update(id, updatePipelineDto, info);
return response;
}
@Delete(':id')
async delete(@Body() data, @Param() params) {
const { id } = params;
this.logger.info(process.env.DEV_URL + `/pipeline/${id} ON DELETE ROUTE`);
const pipelineService = new PipelinesService(this.pipelinesClientService);
const response = await pipelineService.remove({ id, ...data });
const response = await this.pipelineService.getPipelineStatus(body);
return response;
}
+19
View File
@@ -0,0 +1,19 @@
import { Module } from '@nestjs/common';
import { ClientsModule } from '@nestjs/microservices';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { PipelinesController } from './pipelines.controller';
import { PipelinesService } from './pipelines.service';
import { PipelinesClientConfiguration } from './pipelines-client';
import { PipelinesClientService } from './client.service';
const client = new PipelinesClientConfiguration();
@Module({
imports: [ClientsModule.register([client.providerOptions])],
controllers: [PipelinesController],
providers: [PipelinesService, PipelinesClientService, DadosferaLogger],
exports: [PipelinesService],
})
export class PipelinesModule {}
+2 -87
View File
@@ -1,97 +1,12 @@
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { DecodeGrpcStruct } from 'protospack';
import { PipelinesClientService } from 'src/clients/pipelines/client.service';
import { IIdRequest, Info } from 'src/clients/pipelines/interfaces';
import { PipelinesClientService } from './client.service';
import { IIdRequest } from './interfaces';
import { objectCamelToSnake } from 'src/utils/CaseConverter';
@Injectable()
export class PipelinesService {
constructor(private pipelineClient: PipelinesClientService) {}
adjustPayload(payload) {
if (payload.input?.input_generic) {
payload.input = DecodeGrpcStruct(payload.input?.input_generic);
} else {
payload.input = payload.input?.input_s3 || payload.input?.input_jdbc;
}
}
async create(createPipelineDto) {
const createPipelineResponse = await this.pipelineClient.create(
createPipelineDto,
);
const pipeline = objectCamelToSnake(createPipelineResponse);
this.adjustPayload(pipeline.pipeline);
return pipeline;
}
async findOne(data: IIdRequest) {
try {
const findOnePipelineResponse = await this.pipelineClient.findOne(data);
const pipeline = objectCamelToSnake(findOnePipelineResponse);
this.adjustPayload(pipeline.pipeline);
return pipeline;
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
}
async findAll(data) {
try {
const findAllPipelineResponse = await this.pipelineClient.findAll(data);
const pipelines = objectCamelToSnake(findAllPipelineResponse);
pipelines.forEach((pipeline) => {
this.adjustPayload(pipeline);
});
return { pipelines };
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
}
async update(id: string, data, info: Info) {
try {
const updatePipelineResponse = await this.pipelineClient.update({
id,
info,
...data,
});
const pipeline = objectCamelToSnake(updatePipelineResponse);
this.adjustPayload(pipeline);
return pipeline;
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
}
async remove(data: IIdRequest) {
try {
const removePipelineResponse = await this.pipelineClient.remove(data);
return removePipelineResponse;
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
}
async getPipelineLogsMessages(id: string, details: string) {
try {
const pipelineLogsResponse =
await this.pipelineClient.getPipelineLogsMessages({ id, details });
return objectCamelToSnake(pipelineLogsResponse);
} catch (err) {
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
}
async getPipelineStatus(data: IIdRequest) {
try {
const pipelineStatusResponse =
+88
View File
@@ -0,0 +1,88 @@
import { ApiProperty, ApiPropertyOptional, OmitType } from '@nestjs/swagger';
import { Info } from 'protospack/dist/lib/interfaces';
export class IPipelineV2 {
@ApiProperty()
id: string;
@ApiProperty()
name: string;
@ApiProperty()
description: string;
@ApiProperty()
connection_id: string;
@ApiProperty()
cron: string;
@ApiPropertyOptional()
input_id?: string;
@ApiPropertyOptional()
transformations_ids?: string[];
@ApiPropertyOptional()
tags?: string[];
@ApiPropertyOptional()
properties?: any;
@ApiProperty()
connector_name: string;
@ApiProperty()
connector_plugin: string;
@ApiProperty()
connector_version: string;
@ApiProperty()
image_url: string;
@ApiProperty()
created_at: string;
@ApiProperty()
updated_at: string;
}
export class ICreatePipelineV2Req extends OmitType(IPipelineV2, [
'id',
'created_at',
'updated_at',
]) {}
export interface IdRequest {
id: string;
}
export interface IIdRequest {
id: string;
info: Info;
}
export interface IUpdatePipelineRequest {
input: IdRequest;
transformations: IdRequest[];
output: IdRequest;
tags: string[];
name: string;
description: string;
id: string;
info: Info;
}
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;
}
@@ -0,0 +1,36 @@
import {
ClientsProviderAsyncOptions,
GrpcOptions,
Transport,
} from '@nestjs/microservices';
import {
ProtoPackages,
ProtoPaths,
} from '@dadosfera/protospack-v2/dist/lib/PipelineV2';
import { credentials } from '@grpc/grpc-js';
export class PipelinesClientConfiguration {
public name = 'PipelinesClientConfiguration';
private config: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: process.env.PIFACTORY_URL,
package: [ProtoPackages.ReadPackage, ProtoPackages.WritePackage],
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
protoPath: [ProtoPaths.ReadFilePath, ProtoPaths.WriteFilePath],
loader: {
keepCase: true,
enums: String,
objects: true,
arrays: true,
},
},
};
providerOptions: ClientsProviderAsyncOptions = {
name: this.name,
...this.config,
};
}
@@ -0,0 +1,372 @@
import {
Body,
Controller,
Delete,
Get,
Inject,
Param,
Post,
Put,
Headers,
Query,
UseFilters,
HttpCode,
HttpStatus,
Patch,
UseInterceptors,
UploadedFile,
HttpException,
} from '@nestjs/common';
import {
ApiConsumes,
ApiCreatedResponse,
ApiNoContentResponse,
ApiTags,
} from '@nestjs/swagger';
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';
import { Messages } from '@dadosfera/protospack-v2/dist/lib/PipelineV2';
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,
IUploadCSVFile,
} from './interfaces';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
import { FileInterceptor } from '@nestjs/platform-express';
@UseFilters(new GrpcToHttpExceptionFilter())
@ApiTags('PipelinesV2')
@Controller('pipelinesV2')
@AuthenticateCondition((req, user) => {
let action;
switch (req.method) {
case 'POST':
action = 'CREATE';
break;
case 'PUT':
action = 'UPDATE';
break;
case 'PATCH':
action = 'UPDATE';
break;
default:
action = req.method;
}
return user.permissions.includes(
PERMISSIONS_GROUPS.PIPELINE.permissions[action].seqid,
);
})
export class PipelinesController {
logger: DadosferaLogger;
constructor(
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
private pipelinesClientService: PipelinesService,
private oldPipelinesService: OldPipelineService,
) {
this.logger = dadosferaLogger.logger;
}
@Post()
@ApiCreatedResponse({ type: IPipelineV2 })
async create(
@Headers('Dadosfera-Lang') language,
@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,
customer_name,
username,
user_id,
language,
});
const response = await this.pipelinesClientService.create(
createPipelineDto,
metadata,
);
return response;
}
@Get()
async findAll(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@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,
customer_name,
user_id,
username,
language,
});
const response = await this.pipelinesClientService.findAll(data, metadata);
return {
pipelines: [...response.pipelines],
};
}
@Get('/download-logs')
async downloadLogs(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Query() query,
) {
this.logger.info('PipelinesController - downloadLogs', { user });
if (!language) language = 'en-us';
if (!query) {
throw new HttpException('Query params not provided', 400);
}
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
customer_id,
customer_name,
user_id,
username,
language,
});
const url = await this.pipelinesClientService.downloadLogs(
query.pipeline_run_id,
metadata,
);
return {
url,
};
}
@Get(':id/config')
async getPipelineproperties(
@Headers('Dadosfera-Lang') language,
@User() user: RequestUser,
@Param('id') id,
) {
this.logger.info('PipelinesController - getPipelineproperties', { user });
const metadata = PackTheMetadata({
...user,
language: language || 'pt-br',
});
return this.pipelinesClientService.findOneProperties(id, metadata);
}
@Get(':id/objects')
async getPipelineObjects(
@Headers('Dadosfera-Lang') language,
@User() user: RequestUser,
@Param('id') id,
) {
this.logger.info('PipelinesController - getPipelineObjects', { user });
const metadata = PackTheMetadata({
...user,
language: language || 'pt-br',
});
return this.pipelinesClientService.findOneObjects(id, metadata);
}
@Get('/:id')
async findOne(
@Headers('Dadosfera-Lang') language,
@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({
customer_id,
customer_name,
user_id,
username,
language,
});
const result = await this.pipelinesClientService
.findOne({ id }, metadata)
.then((res) => {
//{pipeline:{tables: {tables: [], input_id: ''}}}
let tables = JSON.parse(res.pipeline.config.tables);
if (tables?.tables) tables = tables.tables;
Object.assign(res.pipeline, {
transformations: res.pipeline.transformations
? JSON.parse(res.pipeline.transformations)
: [],
config: {
cron: res.pipeline.config.cron,
tables,
},
properties: res.pipeline.properties
? JSON.parse(res.pipeline.properties)
: {},
});
return res;
});
return result;
}
@Put('/:id')
async update(
@Headers('Dadosfera-Lang') language,
@Body() updatePipelineDto,
@Param('id') id,
@User() user: RequestUser,
) {
this.logger.info('PipelinesController - update', { user });
const { info } = updatePipelineDto;
delete updatePipelineDto.info;
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;
}
@Delete(':id')
@ApiNoContentResponse()
@HttpCode(HttpStatus.NO_CONTENT)
async delete(@Param() params, @User() user: RequestUser) {
this.logger.info('PipelinesController - delete', { user });
const { id } = params;
const metadata = PackTheMetadata({
customer_id: user.customer_id,
customer_name: user.customer_name,
user_id: user.user_id,
});
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 });
const parts_of_file_name = file.originalname.split('.');
const file_format = parts_of_file_name.pop();
const file_name = parts_of_file_name.join('.');
let name = `${new Date().getTime()}_${file_name}`;
body.name ? (name = `${new Date().getTime()}_${body.name}`) : name;
const source_prefix = `${user.customer_name}/${name}.${file_format}`;
const response = await this.pipelinesClientService.uploadFile(
{
file,
name,
},
metadata,
);
if (!response.url) {
this.logger.info('pipeline/upload - Failed File pipeline');
throw new HttpException(
'Upload failed, try again in a few minutes, if the problem persists, contact support.',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
const { sep, header, encoding, description } = body;
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,
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;
}
}

Some files were not shown because too many files have changed in this diff Show More