Compare commits

...
33 Commits
Author SHA1 Message Date
marcos.rodrigues 740540d4dc Merge pull request #517 from dadosfera/bugfix/sync-proto
FIX: sync proto
2026-08-28 13:33:27 -03:00
marcos.rodrigues 94c9ab7939 FIX: add missing helm value 2026-08-28 12:25:44 -03:00
marcos.rodrigues a211b8593e FIX: sync proto 2026-08-28 12:23:25 -03:00
marcos.rodrigues 25661613d5 Merge pull request #516 from dadosfera/bugfix/add-jest-file-in-exclude-build
FIX: add-jest-file-in-exclude-build
2026-08-27 17:29:08 -03:00
marcos.rodrigues 3d8ea3576d FIX: add-jest-file-in-exclude-build 2026-08-27 17:10:37 -03:00
marcos.rodrigues e3a2eba5c3 Merge pull request #515 from dadosfera/release/2026-08-27-beta
Release/2026 08 27 beta
2026-08-27 16:09:16 -03:00
marcos.rodrigues 81c446354b FIX: mock process.env and dadosfera logger 2026-08-27 14:33:30 -03:00
RafaelandWOZCODE bf0314f5b1 FIX: trigger release for /auth/me permission seqids (PR #513)
PR #513 merged to beta but no semantic-release ran: its commits used
conventional-commits prefixes (feat(auth):, fix(auth):) which the
.releaserc.json eslint preset does not recognise, so commit-analyzer
found no release-worthy change. This empty FIX: commit matches the
eslint preset's releaseRules (tag FIX -> patch) to cut a beta release
that includes the /auth/me permission-seqids change, so stg can deploy it.

Co-Authored-By: WOZCODE <contact@withwoz.com>
2026-08-24 19:18:59 -03:00
Rafael Santana c97180ac95 Merge pull request #513 from dadosfera/feat/auth-me-orchest-identity
feat(auth): return the user's permission seqids from /auth/me
2026-08-24 17:00:15 -03:00
RafaelandWOZCODE cac36f2c60 refactor(auth): /auth/me returns raw permission seqids
Return payload.permissions verbatim (numeric seqids) instead of
translating them to claim strings. Consumers own the seqid->meaning
mapping. Drops permission-claims.ts entirely; UserDTO.permissions is
now number[].

Co-Authored-By: WOZCODE <contact@withwoz.com>
2026-08-24 16:56:23 -03:00
RafaelandWOZCODE cd21fd0b7b refactor(auth): /auth/me returns permissions only (drop roles/modules)
Keep Maestro a pure identity provider: /auth/me exposes the user's
permission claim strings and nothing consumer-specific. Consumers derive
whatever meaning they need (roles, module access, groups) from the claim
vocabulary — claims are already namespaced group:action.

- UserDTO: drop roles[]/modules[], keep permissions[].
- Helper shrinks to a generic seqid->claim translation
  (orchest-identity.ts -> permission-claims.ts, translateSeqidsToClaims).
- api-key branch: permissions: [] only.

The roles/modules derivation moves entirely to the consumer (Orchest's
auth-server adapter).

Co-Authored-By: WOZCODE <contact@withwoz.com>
2026-08-24 16:30:33 -03:00
RafaelandWOZCODE a5a685ee3f fix(auth): derive Orchest identity from numeric seqids (JWT carries seqids not claim strings)
The JWT `permissions` claim is an array of numeric seqids at runtime
(see authentication.guard.ts / authentication.decorator.ts), not claim
strings. deriveOrchestIdentity previously matched claim strings against
this numeric array, so roles[]/modules[] were always empty for every
real user.

- deriveOrchestIdentity now takes number[] | undefined and matches
  seqids sourced from PERMISSIONS_GROUPS (permissions.enum.ts) instead
  of hand-copied literals.
- permissions is translated back to claim strings via a full
  seqid->claim catalog built once from PERMISSIONS_GROUPS; unknown
  seqids are dropped (auth-server ignores permissions[] in v1).
- auth.controller.ts's api-key branch literal is now annotated
  `: UserDTO` so tsc enforces the three fields there.
- Both spec files re-fixtured with numeric seqid inputs, including a
  mixed admin+module case and an exact claim-string translation
  assertion.

Co-Authored-By: WOZCODE <contact@withwoz.com>
2026-08-24 16:03:20 -03:00
Rafael a16fefe691 feat(auth): return permissions/roles/modules from /auth/me (all branches) 2026-08-24 15:45:09 -03:00
Rafael 9c57485031 feat(auth): pure helper deriving Orchest identity from permissions 2026-08-24 15:39:40 -03:00
marcos.rodrigues 7051b21d86 Merge pull request #509 from dadosfera/release/2026-08-12
FIX: require collect module in endpoints
2026-08-12 15:06:04 -03:00
marcos.rodrigues 0c4888ccdb FIX: require collect module in endpoints 2026-08-12 15:02:37 -03:00
marcos.rodrigues e1b0e88bd8 Merge pull request #507 from dadosfera/bugfix/catalog-module-main
Bugfix/catalog module main
2026-08-12 09:59:08 -03:00
marcos.rodrigues cef1184908 Merge branch 'beta' into bugfix/catalog-module-main 2026-08-12 09:58:58 -03:00
marcos.rodrigues 31dda867d1 FIX: require collect module in endpoints 2026-08-12 09:57:23 -03:00
marcos.rodrigues 8a92da470c Merge pull request #506 from dadosfera/bugfix/catalog-module-main
FIX: skip nimbus update when customer haven't catalog module
2026-08-07 16:27:19 -03:00
marcos.rodrigues b89909ad66 FIX: skip nimbus update when customer haven't catalog module 2026-08-07 14:48:46 -03:00
marcos.rodrigues 2bb280e8de Merge pull request #505 from dadosfera/bugfix/catalog-module
Bugfix/catalog module
2026-08-07 12:26:21 -03:00
marcos.rodrigues 00cbadbb45 Merge branch 'beta' into bugfix/catalog-module 2026-08-07 12:26:11 -03:00
marcos.rodrigues 47ad527d38 FIX: skip nimbus update when customer haven't catalog module 2026-08-07 12:18:37 -03:00
iruy-fr 51044a23b3 FIX: trigger cache connections rollout 2026-08-03 09:19:27 -03:00
yuri.rodrigues bb29d126c1 Merge pull request #503 from dadosfera/feat/cache-connections-rollout
feat(connection-test): refresh connection catalog cache
2026-07-31 20:56:11 -03:00
iruy-fr 9d0f449eeb feat(connection-test): refresh connection catalog cache 2026-07-31 16:33:15 -03:00
marcos.rodrigues d54f381998 Merge pull request #499 from dadosfera/release/2026-07-27
Release/2026 07 27
2026-07-27 17:59:56 -03:00
viniciusgadea 3fd586753e FEAT: add endpoint and logic to update data asset certification status 2026-07-27 17:07:19 -03:00
viniciusgadea 9b3894f9e4 FIX: pin npm version to 10.8.2 in Dockerfile for consistency 2026-07-27 17:07:10 -03:00
viniciusgadea 4a5f8f679a FEAT: rename documentation_status to certification_status in docs and update package.json for protospack versioning 2026-07-27 17:06:58 -03:00
viniciusgadea a444f5e5ec FEAT: add documentation status enum and property to data asset 2026-07-27 17:06:25 -03:00
marcos.rodrigues 0d30c1cf83 FEAT: remove deprecated protospack lib 2026-07-27 17:06:10 -03:00
28 changed files with 684 additions and 62 deletions
+2
View File
@@ -56,6 +56,8 @@ maestro:
redis_tls: "true"
cookie_secret: "13cc5e136d3074bcc05bec8697092ec1f5f376bf"
firebase_base_url: https://feature-flag-25bf6-default-rtdb.firebaseio.com/prd
connections_api_url: https://wv6fw7ayj4.execute-api.us-east-1.amazonaws.com
autoscaling:
enabled: false
minReplicas: 1
+234
View File
@@ -900,6 +900,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -949,6 +952,9 @@
"connections"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -997,6 +1003,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -1033,6 +1042,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -1066,6 +1078,9 @@
"connections"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -2403,6 +2418,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -2486,6 +2504,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -2525,6 +2546,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -2564,6 +2588,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -2601,6 +2628,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -2640,6 +2670,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -2681,6 +2714,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -2722,6 +2758,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -3071,6 +3110,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3120,6 +3162,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3190,6 +3235,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3230,6 +3278,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3270,6 +3321,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3310,6 +3364,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3350,6 +3407,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3397,6 +3457,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3442,6 +3505,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3490,6 +3556,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3528,6 +3597,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3586,6 +3658,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3634,6 +3709,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3674,6 +3752,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3716,6 +3797,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3765,6 +3849,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3814,6 +3901,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -3861,6 +3951,9 @@
"PipelinesV2"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4031,6 +4124,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4056,6 +4152,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4092,6 +4191,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4126,6 +4228,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4160,6 +4265,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4187,6 +4295,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4214,6 +4325,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4241,6 +4355,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4277,6 +4394,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4313,6 +4433,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4340,6 +4463,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4367,6 +4493,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4404,6 +4533,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4440,6 +4572,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4484,6 +4619,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4520,6 +4658,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4564,6 +4705,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4656,6 +4800,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4690,6 +4837,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4726,6 +4876,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4762,6 +4915,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4799,6 +4955,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4826,6 +4985,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -4853,6 +5015,9 @@
"Platform API"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -5264,6 +5429,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -5307,6 +5475,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -5416,6 +5587,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -5448,6 +5622,9 @@
"Catalog"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -5490,6 +5667,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -5625,6 +5805,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -5683,6 +5866,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -5731,6 +5917,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -5824,6 +6013,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -5874,6 +6066,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -5932,6 +6127,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -5988,6 +6186,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -6048,6 +6249,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -6088,6 +6292,9 @@
"Catalog"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -6128,6 +6335,9 @@
"Catalog"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -6188,6 +6398,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -6246,6 +6459,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -6622,6 +6838,9 @@
{
"access-token": []
},
{
"access-token": []
},
{
"access-token": []
}
@@ -7075,6 +7294,9 @@
"Connection Test"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -7111,6 +7333,9 @@
"Connection Test"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -7147,6 +7372,9 @@
"Connection Test"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -7183,6 +7411,9 @@
"Connection Test"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -7219,6 +7450,9 @@
"Connection Test"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
+1
View File
@@ -11,6 +11,7 @@ const config: Config.InitialOptions = {
'<rootDir>/node_modules/',
'.*\\.module\\.[jt]s$',
],
setupFiles: ['<rootDir>/jest.setup.ts'],
// moduleDirectories: ['node_modules'], // default is already 'node_modules'
// rootDir: '.', //No need
// testEnvironment: 'node', //Defaults to 'node'
+3
View File
@@ -0,0 +1,3 @@
process.env.DUC_URL="duc:50051"
process.env.INFACTORY_URL="in-factory:50052"
process.env.PIFACTORY_URL="pi-factory:50053"
+5 -4
View File
@@ -16,7 +16,7 @@
"@aws-sdk/lib-dynamodb": "^3.414.0",
"@aws-sdk/signature-v4": "^3.370.0",
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
"@dadosfera/protospack-v2": "^3.40.0-beta.14",
"@dadosfera/protospack-v2": "3.40.0",
"@grpc/grpc-js": "^1.9.3",
"@grpc/proto-loader": "^0.7.9",
"@nestjs/cli": "^9.5.0",
@@ -1735,9 +1735,10 @@
}
},
"node_modules/@dadosfera/protospack-v2": {
"version": "3.40.0-beta.14",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.40.0-beta.14.tgz",
"integrity": "sha512-pv3pxq0x1XcBgf3ajD6QOFRLOduh8iEozKFA3AKlIW4gid+gT4iL0GcU2M+O7h0QFeO4JIzRZe/nEMN82nqk7A==",
"version": "3.40.0",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.40.0.tgz",
"integrity": "sha512-tzYAGosFjGUgi3pAvXqv+Eqqjca9tH1kU9kJdRI5d1rLXNimo0fIuPWxWng0C4OBH/2sIgC1WLHseq+DZ6qgdw==",
"license": "ISC",
"dependencies": {
"@grpc/grpc-js": "^1.9.3",
"rxjs": "^7.5.5"
+1 -1
View File
@@ -34,7 +34,7 @@
"@aws-sdk/lib-dynamodb": "^3.414.0",
"@aws-sdk/signature-v4": "^3.370.0",
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
"@dadosfera/protospack-v2": "^3.40.0-beta.14",
"@dadosfera/protospack-v2": "3.40.0",
"@grpc/grpc-js": "^1.9.3",
"@grpc/proto-loader": "^0.7.9",
"@nestjs/cli": "^9.5.0",
+2
View File
@@ -722,6 +722,8 @@ export const DADOSFERA_MODULES_KEYS = {
PII: 'pii',
EMBED: 'embedded-analytics',
EMBED_ASSIGNED: 'embed-assigned',
CATALOG: 'catalog',
COLLECT: 'collect',
}
export const DADOSFERA_MODULES: Array<DadosferaModule> = [
+4 -2
View File
@@ -37,6 +37,7 @@ import {
RequireAllPermissions,
} from 'src/decorators/authentication.decorator';
import { AuthClientService } from './auth.service';
import { UserDTO } from './dtos/login';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { GrpcToHttpExceptionFilter } from '../../error/grpc-to-http-exception.filter';
import { RequestUser, User } from 'src/decorators/user.decorator';
@@ -486,7 +487,7 @@ export class AuthController {
this.logger.info('Authenticating via X-Api-key header');
const { api_key } = await this.apiKeyService.get(apiKey);
const userDto = {
const userDto: UserDTO = {
id: api_key.user_id,
name: api_key.username,
email: api_key.username,
@@ -494,7 +495,8 @@ export class AuthController {
id: api_key.customer_id,
name: api_key.customer_name,
tier: api_key.customer_tier,
}
},
permissions: [],
};
return res.status(200).json(userDto);
+3
View File
@@ -447,6 +447,9 @@ export class AuthClientService implements OnModuleInit {
name: payload.customer_name,
tier: payload.customer_tier,
},
// Raw permission seqids from the JWT. Consumers own the seqid->meaning
// mapping (e.g. Orchest's auth-server); Maestro reports them as-is.
permissions: payload.permissions ?? [],
};
return userDto;
+2 -1
View File
@@ -152,5 +152,6 @@ export type UserDTO = {
id: string,
name: string,
tier: string,
}
},
permissions: number[],
}
+54
View File
@@ -85,6 +85,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async searchCatalog(
@User() user: RequestUser,
@Query() query: ICatalogAllRequest,
@@ -124,6 +127,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async dowloadAsserts(
@User() user: RequestUser,
@Query() query: ICatalogAllRequest,
@@ -167,6 +173,9 @@ export class CatalogController {
@ApiInternalOnlyEndpoint()
@Get('data-asset')
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async findByPipelineAndObject(@User() user: RequestUser, @Query() query) {
const { username, user_id, customer_id, customer_name, permissions } = user;
const { pipeline, object } = query;
@@ -225,6 +234,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async findAllTags(@Body() body) {
this.logger.info(`/catalog - ON FIND ALL TAGS ROUTE`, {
user: body.info.user_id,
@@ -293,6 +305,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async getDataAsset(
@User() user: RequestUser,
@Param('id') id: string,
@@ -404,6 +419,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async getDataAssetColumnsMetadata(
@User() user: RequestUser,
@Language() language: LanguageEnum,
@@ -435,6 +453,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async getDataAssetPreview(
@User() user: RequestUser,
@Language() language: LanguageEnum,
@@ -466,6 +487,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async getDataAssetDocs(
@User() user: RequestUser,
@Language() language: LanguageEnum,
@@ -497,6 +521,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async updateDataAsset(
@User() user: RequestUser,
@Language() language: LanguageEnum,
@@ -532,6 +559,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.CERTIFY,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async updateDataAssetCertificationStatus(
@User() user: RequestUser,
@Language() language: LanguageEnum,
@@ -559,6 +589,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async manageDataAssetDocs(
@User() user: RequestUser,
@Headers() headers,
@@ -596,6 +629,9 @@ export class CatalogController {
@ApiInternalOnlyEndpoint()
@Put('data-asset/:id/manage-permissions')
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async manageDataAssetPermissions(
@Param('id') id: string,
@User() user: RequestUser,
@@ -618,6 +654,9 @@ export class CatalogController {
@ApiInternalOnlyEndpoint()
@Put('data-asset/:id/revoke-permissions')
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async revokeDataAssetPermissions(
@Param('id') id: string,
@User() user: RequestUser,
@@ -643,6 +682,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.CREATE,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async createDataAsset(
@User() user: RequestUser,
@Body() body: ICreateDataAsset,
@@ -667,6 +709,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async commentOnDataAsset(
@Param('id') id: string,
@User() user: RequestUser,
@@ -693,6 +738,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.DELETE,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async deleteDataAsset(@Param('id') id: string, @User() user: RequestUser) {
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
@@ -714,6 +762,9 @@ export class CatalogController {
PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE,
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async deleteComment(
@Param('id') id: string,
@User() user: RequestUser,
@@ -867,6 +918,9 @@ export class CatalogController {
@Get('nimbus-dashboards')
@RequireAllPermissions(PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER)
@RequireModule(
DADOSFERA_MODULES_KEYS.CATALOG
)
async getNimbusDashboards(
@User() user: RequestUser,
@Body() body: GetNimbusDashboardsRequest,
@@ -22,17 +22,24 @@ import {
ConnectionTestListTablesRes,
GetTableMetadataRes,
GetTableMetadataReq,
RefreshCatalogReq,
RefreshCatalogRes,
RefreshCatalogStatusReq,
} from './dto/connection-test';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { Authenticated } from 'src/decorators/authentication.decorator';
import { Authenticated, RequireModule } from 'src/decorators/authentication.decorator';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
import { DADOSFERA_MODULES_KEYS } from 'src/authentication/permissions.enum';
@ApiInternalOnlyController()
@ApiTags('Connection Test')
@Controller('connection-test')
@UseFilters(new GrpcToHttpExceptionFilter())
@Authenticated()
@RequireModule(
DADOSFERA_MODULES_KEYS.COLLECT
)
export class ConnectionTestController {
logger: any;
constructor(
@@ -121,4 +128,35 @@ export class ConnectionTestController {
user,
);
}
@Post('refresh-catalog')
@ApiOkResponse({ type: RefreshCatalogRes })
@HttpCode(HttpStatus.ACCEPTED)
async refreshCatalog(
@User() user: RequestUser,
@Body(new ValidationPipe()) body: RefreshCatalogReq,
) {
this.logger.info('/connection-test/refresh-catalog', {
user: user.user_id,
customer: user.customer_name,
connection: body.connection_id,
});
return this.connectionTestService.refreshCatalog(body, user);
}
@Post('refresh-catalog/status')
@ApiOkResponse({ type: RefreshCatalogRes })
@HttpCode(HttpStatus.OK)
async refreshCatalogStatus(
@User() user: RequestUser,
@Body(new ValidationPipe()) body: RefreshCatalogStatusReq,
) {
this.logger.info('/connection-test/refresh-catalog/status', {
user: user.user_id,
customer: user.customer_name,
connection: body.connection_id,
session: body.session_id,
});
return this.connectionTestService.refreshCatalogStatus(body, user);
}
}
@@ -6,6 +6,7 @@ import { ClientsModule } from '@nestjs/microservices';
import { ConnectionTestClientConfiguration } from './connection-test-client.config';
import { ConnectionModule } from '../connection/connection.module';
import { ConnectionsApiModule } from '../connections-api/connections-api.module';
import { PlatformApiModule } from '../platform-api/platform-api.module';
const client = new ConnectionTestClientConfiguration();
@Module({
controllers: [ConnectionTestController],
@@ -14,6 +15,7 @@ const client = new ConnectionTestClientConfiguration();
ClientsModule.register([client.providerOptions]),
ConnectionModule,
ConnectionsApiModule,
PlatformApiModule,
],
})
export class ConnectionTestModule {}
@@ -16,6 +16,7 @@ describe('ConnectionTestService catalog cache', () => {
const grpcClient = { getService: jest.fn().mockReturnValue({}) };
const connectionsService = {};
const connectionsApiService = { proxy: jest.fn() };
const platformApiService = { proxy: jest.fn() };
let service: ConnectionTestService;
beforeEach(() => {
@@ -24,6 +25,7 @@ describe('ConnectionTestService catalog cache', () => {
grpcClient as any,
connectionsService as any,
connectionsApiService as any,
platformApiService as any,
);
});
@@ -106,4 +108,98 @@ describe('ConnectionTestService catalog cache', () => {
user,
);
});
it('submits a catalog refresh without holding the request open', async () => {
platformApiService.proxy.mockResolvedValue({
session_id: 'session-id',
date: '20260731',
});
await expect(
service.refreshCatalog(
{ connection_id: 'config-id', plugin: 'postgresql' },
user,
),
).resolves.toEqual({
operation_result: true,
status: 'PENDING',
session_id: 'session-id',
date: '20260731',
});
expect(platformApiService.proxy).toHaveBeenCalledWith(
'POST',
'/connection_test',
user,
{
customer_id: user.customer_name,
plugin: 'postgresql',
task: {
task_type: 'refresh_catalog',
connection: {
provider: 'connection_manager',
config_id: 'config-id',
},
},
},
);
});
it('keeps polling without changing the catalog pointer while pending', async () => {
platformApiService.proxy.mockResolvedValue({ status: 'PENDING' });
await expect(
service.refreshCatalogStatus(
{
connection_id: 'config-id',
plugin: 'postgresql',
session_id: 'session-id',
date: '20260731',
},
user,
),
).resolves.toEqual({
operation_result: false,
status: 'PENDING',
session_id: 'session-id',
date: '20260731',
});
expect(connectionsApiService.proxy).not.toHaveBeenCalled();
});
it('publishes the catalog pointer after the refresh finishes', async () => {
platformApiService.proxy.mockResolvedValue({ status: 'DONE' });
connectionsApiService.proxy.mockResolvedValue({
last_catalog_refresh_status: 'SUCCESS',
});
await expect(
service.refreshCatalogStatus(
{
connection_id: 'config/id',
plugin: 'postgresql',
session_id: 'session-id',
date: '20260731',
},
user,
),
).resolves.toEqual({
operation_result: true,
status: 'DONE',
session_id: 'session-id',
date: '20260731',
});
expect(connectionsApiService.proxy).toHaveBeenCalledWith(
'PUT',
'/connection_config/config%2Fid/catalog_metadata',
user,
{
last_catalog_refresh_status: 'SUCCESS',
last_catalog_connection_test_date: '20260731',
last_catalog_connection_test_session_id: 'session-id',
},
);
});
});
@@ -1,4 +1,4 @@
import { Inject, Injectable } from '@nestjs/common';
import { HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { ConnectionTest } from '@dadosfera/protospack-v2';
import { lastValueFrom } from 'rxjs';
@@ -13,6 +13,9 @@ import {
ConnectionTestPingRes,
GetTableMetadataReq,
GetTableMetadataRes,
RefreshCatalogReq,
RefreshCatalogRes,
RefreshCatalogStatusReq,
} from './dto/connection-test';
import { ConnectionClientService } from '../connection/client.service';
import {
@@ -22,6 +25,7 @@ import {
import { RequestUser } from 'src/decorators/user.decorator';
import { PackTheMetadata } from 'src/utils/PackTheMetadata';
import { ConnectionsApiService } from '../connections-api/connections-api.service';
import { PlatformApiService } from '../platform-api/platform-api.service';
@Injectable()
export class ConnectionTestService {
@@ -30,6 +34,7 @@ export class ConnectionTestService {
@Inject('ConnectionTestGrpcClient') private readonly grpcClient: ClientGrpc,
private connectionsService: ConnectionClientService,
private connectionsApiService: ConnectionsApiService,
private platformApiService: PlatformApiService,
) {
this.connectionTestReadClient =
grpcClient.getService<ConnectionTest.ReadService.ConnectionTestReadServices>(
@@ -204,4 +209,82 @@ export class ConnectionTestService {
);
return { operation_result: true, tables_metadata };
}
async refreshCatalog(
body: RefreshCatalogReq,
user: RequestUser,
): Promise<RefreshCatalogRes> {
const task = await this.platformApiService.proxy(
'POST',
'/connection_test',
user,
{
customer_id: user.customer_name,
plugin: body.plugin,
task: {
task_type: 'refresh_catalog',
connection: {
provider: 'connection_manager',
config_id: body.connection_id,
},
},
},
);
if (!task.session_id || !task.date) {
throw new HttpException(
'Platform API did not return a catalog refresh task identifier',
HttpStatus.BAD_GATEWAY,
);
}
return {
operation_result: true,
status: 'PENDING',
session_id: task.session_id,
date: task.date,
};
}
async refreshCatalogStatus(
body: RefreshCatalogStatusReq,
user: RequestUser,
): Promise<RefreshCatalogRes> {
const result = await this.platformApiService.proxy(
'POST',
'/connection_test/status',
user,
{
session_id: body.session_id,
date: body.date,
},
);
if (result.status === 'DONE') {
await this.connectionsApiService.proxy(
'PUT',
`/connection_config/${encodeURIComponent(
body.connection_id,
)}/catalog_metadata`,
user,
{
last_catalog_refresh_status: 'SUCCESS',
last_catalog_connection_test_date: body.date,
last_catalog_connection_test_session_id: body.session_id,
},
);
} else if (result.status === 'ERROR' || result.status === 'EXPIRED') {
throw new HttpException(
`Catalog refresh finished with status ${result.status}`,
HttpStatus.BAD_GATEWAY,
);
}
return {
operation_result: result.status === 'DONE',
status: result.status,
session_id: body.session_id,
date: body.date,
};
}
}
@@ -1,5 +1,5 @@
import { ApiProperty, ApiPropertyOptional, OmitType } from '@nestjs/swagger';
import { IsString, IsOptional } from 'class-validator';
import { IsIn, IsString, IsOptional } from 'class-validator';
import { DatabaseConnectionPropertiesDto } from 'src/modules/connection/dtos/connection';
import { CreateConnectionDto } from 'src/modules/connection/dtos/connection';
export class ColumnDto {
@@ -133,3 +133,37 @@ export class GetTableMetadataRes {
@ApiProperty({ type: [TableMetadataDto] })
tables_metadata: TableMetadataDto[];
}
export class RefreshCatalogReq {
@ApiProperty()
@IsString()
connection_id: string;
@ApiProperty({ enum: ['oracle', 'mysql', 'postgresql', 'sqlserver'] })
@IsIn(['oracle', 'mysql', 'postgresql', 'sqlserver'])
plugin: string;
}
export class RefreshCatalogStatusReq extends RefreshCatalogReq {
@ApiProperty()
@IsString()
session_id: string;
@ApiProperty()
@IsString()
date: string;
}
export class RefreshCatalogRes {
@ApiProperty()
operation_result: boolean;
@ApiProperty()
status: string;
@ApiProperty()
session_id: string;
@ApiProperty()
date: string;
}
@@ -16,8 +16,9 @@ import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import {
Authenticated,
RequireAllPermissions,
RequireModule,
} from 'src/decorators/authentication.decorator';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import { DADOSFERA_MODULES_KEYS, PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import { RequestUser, User } from 'src/decorators/user.decorator';
import { ValidationPipe } from '../../pipes/object-validation.pipe';
import {
@@ -39,6 +40,9 @@ const connectionPermissions = PERMISSIONS_GROUPS.CONNECTION.permissions;
@ApiTags('connections')
@Authenticated()
@Controller('connections')
@RequireModule(
DADOSFERA_MODULES_KEYS.COLLECT
)
export class ConnectionController {
logger: any;
constructor(
@@ -27,9 +27,19 @@ export class ConnectionsApiService {
method: string,
path: string,
user: RequestUser,
body?: any,
query?: Record<string, string>,
): Promise<any> {
const baseUrl = CONNECTIONS_API_CONFIG.getUrl();
const url = new URL(`${baseUrl}${path}`);
if (query) {
Object.entries(query).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
url.searchParams.set(key, String(value));
}
});
}
const headers: Record<string, string> = {
host: url.hostname,
'content-type': 'application/json',
@@ -45,8 +55,9 @@ export class ConnectionsApiService {
protocol: url.protocol,
hostname: url.hostname,
port: url.port ? parseInt(url.port, 10) : undefined,
path: url.pathname,
path: url.pathname + url.search,
headers,
body: body ? JSON.stringify(body) : undefined,
};
try {
@@ -55,6 +66,7 @@ export class ConnectionsApiService {
method: method as Method,
url: url.href,
headers: signedRequest.headers as Record<string, string>,
data: body,
timeout: CONNECTIONS_API_CONFIG.timeout,
validateStatus: () => true,
});
+26 -1
View File
@@ -25,9 +25,10 @@ import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import {
Authenticated,
RequireAllPermissions,
RequireModule,
RequireSomePermission,
} from 'src/decorators/authentication.decorator';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import { DADOSFERA_MODULES_KEYS, PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import { Language } from 'src/decorators/language.decorator';
import { LanguageEnum } from 'src/utils/languages.enum';
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
@@ -99,6 +100,9 @@ export class ConnectorController {
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE,
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.COLLECT
)
async getAllConnectors(
@Language() language: LanguageEnum,
@Query() queries: GetAllDto,
@@ -131,6 +135,9 @@ export class ConnectorController {
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE,
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.COLLECT
)
async getConnectorsTags() {
return await this.connectorClientService.getConnectorsTags();
}
@@ -143,6 +150,9 @@ export class ConnectorController {
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE,
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.COLLECT
)
async getConnector(
@Language() language: LanguageEnum,
@Param('plugin') plugin: string,
@@ -171,6 +181,9 @@ export class ConnectorController {
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE,
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
)
@RequireModule(
DADOSFERA_MODULES_KEYS.COLLECT
)
async getConnectorDetails(
@Language() language: LanguageEnum,
@Param('plugin') plugin: string,
@@ -193,6 +206,9 @@ export class ConnectorController {
@Put('/:plugin')
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.UPDATE)
@ApiConsumes('multipart/form-data')
@RequireModule(
DADOSFERA_MODULES_KEYS.COLLECT
)
async updateConnector(
@Param('plugin') plugin: string,
@Body() body: UpdateDto,
@@ -214,6 +230,9 @@ export class ConnectorController {
@Put('/:plugin/add-tag')
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.UPDATE)
@RequireModule(
DADOSFERA_MODULES_KEYS.COLLECT
)
async addTagOnConnector(
@Param('plugin') plugin: string,
@Body() body: AddTagDto,
@@ -241,6 +260,9 @@ export class ConnectorController {
@Put('/:plugin/remove-tag')
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.UPDATE)
@RequireModule(
DADOSFERA_MODULES_KEYS.COLLECT
)
async removeTagOnConnector(
@Param('plugin') plugin: string,
@Body() body: RemoveTagDto,
@@ -269,6 +291,9 @@ export class ConnectorController {
@Delete('/:plugin')
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.DELETE)
@RequireModule(
DADOSFERA_MODULES_KEYS.COLLECT
)
async deleteConnector(
@Param('plugin') plugin: string,
@Query('version') version: string,
+5 -4
View File
@@ -23,6 +23,7 @@ import {
} 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';
import { Metadata } from '@grpc/grpc-js';
@Injectable()
@@ -73,10 +74,10 @@ export class InputsService {
objectCamelToSnake(createInputResponse);
return createInputResponse;
},
update: async (updateInputDTO: UpdateInputRequest): Promise<InputUpdateResponse> => {
update: async (updateInputDTO: UpdateInputRequest, metadata: Metadata): Promise<InputUpdateResponse> => {
this.logger.info('InputClientService - Update' + JSON.stringify(updateInputDTO));
const updateInputResponse = await lastValueFrom(
this.inputWriteService.InputUpdate(updateInputDTO),
this.inputWriteService.InputUpdate(updateInputDTO, metadata),
);
return updateInputResponse;
@@ -206,7 +207,7 @@ export class InputsService {
return findOneInputResponse;
}
async update(id: string, data, info: Info) {
async update(id: string, data, info: Info, metadata?: Metadata) {
// this.validateCron({ ...data, info });
try {
const {
@@ -217,7 +218,7 @@ export class InputsService {
id,
...data,
info,
});
}, metadata);
const updateInputResponse = this.adjustInputPayload(
input,
@@ -1,6 +1,6 @@
import { ClientsModule } from '@nestjs/microservices';
import { Test, TestingModule } from '@nestjs/testing';
// import { DucClient } from 'src/clients/duc/client.config';
// import { DucClient } from '../duc/client.config'
import { PermissionsController } from './permissions.controller';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { PermissionsService } from './permissions.service';
@@ -22,7 +22,7 @@ describe.skip('PermissionsController', () => {
provide: DadosferaLogger,
useValue: { logger },
},
PermissionsService,
PermissionsService
],
}).compile();
@@ -15,7 +15,6 @@ import {
HttpException,
BadRequestException,
UseGuards,
Res,
} from '@nestjs/common';
import {
ApiCreatedResponse,
@@ -26,9 +25,10 @@ import {
} from '@nestjs/swagger';
import {
RequireAllPermissions,
RequireModule,
RequireSomePermission,
} from 'src/decorators/authentication.decorator';
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
import { DADOSFERA_MODULES_KEYS, 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';
@@ -58,6 +58,9 @@ type PipelineTablesConfig = { input_id?: string; tables: PipelineTable[] };
@ApiHeaders([{ name: 'dadosfera-lang', enum: LanguageEnum, required: false }])
@UseFilters(new GrpcToHttpExceptionFilter())
@Controller('pipelinesV2')
@RequireModule(
DADOSFERA_MODULES_KEYS.COLLECT
)
export class PipelinesController {
logger: DadosferaLogger;
constructor(
@@ -318,7 +321,6 @@ export class PipelinesController {
) {
this.logger.info('PipelinesController - update', { user });
const { customer_id, customer_name, user_id, username } = user;
const info: Info = {
user_id: user.user_id,
customer: user.customer_name,
@@ -326,13 +328,7 @@ export class PipelinesController {
pipeline_id: pipelineId
};
const metadata = PackTheMetadata({
customer_id,
customer_name,
user_id,
username,
language,
});
const metadata = PackTheMetadata(user);
const response = await this.pipelinesClientService.updatePipelineInput(
pipelineId,
+31 -28
View File
@@ -383,7 +383,8 @@ export class PipelinesService implements OnModuleInit {
const updateInputResponse = await this.inputsService.update(
inputId,
updateInputDTO,
info
info,
metadata
);
const inputRollback = () => {
@@ -404,34 +405,36 @@ export class PipelinesService implements OnModuleInit {
const nimbusUpdates = updateInputResponse?.tablesUpdate || [];
nimbusUpdates.forEach(update => {
const nimbusRollback = () => {
return this.nimbusService.renameTable(
info.customer,
update.database,
{
table_name: update.table_name,
table_schema: update.table_schema
},
{
table_name: update.old_table_name,
table_schema: update.old_table_schema
}
);
if (user.customer_modules.includes('catalog')) {
nimbusUpdates.forEach(update => {
const nimbusRollback = () => {
return this.nimbusService.renameTable(
info.customer,
update.database,
{
table_name: update.table_name,
table_schema: update.table_schema
},
{
table_name: update.old_table_name,
table_schema: update.old_table_schema
}
);
}
rollback.push(nimbusRollback);
});
try {
await this.updateNimbus(info.customer, nimbusUpdates);
} catch (error) {
this.logger.error(error);
if (error instanceof AxiosError) {
this.logger.error(JSON.stringify(error.response.data));
}
await this.executeRenameRollback(rollback);
throw new Error("Error Nimbus updating tables");
}
rollback.push(nimbusRollback);
});
try {
await this.updateNimbus(info.customer, nimbusUpdates);
} catch (error) {
this.logger.error(error);
if (error instanceof AxiosError) {
this.logger.error(JSON.stringify(error.response.data));
}
await this.executeRenameRollback(rollback);
throw new Error("Error Nimbus updating tables");
}
try {
@@ -20,10 +20,11 @@ import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import {
Authenticated,
RequireAllPermissions,
RequireModule,
} from '../../decorators/authentication.decorator';
import { User, RequestUser } from '../../decorators/user.decorator';
import { PlatformApiService } from './platform-api.service';
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
import { DADOSFERA_MODULES_KEYS, PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
import { ElasticsearchService } from '../../services/elasticsearch';
import { DynamoDBService, ReferenceColumn } from '../../services/dynamodb';
import { CustomersService } from '../customers/customers.service';
@@ -49,6 +50,7 @@ type RenameTablesBody = {
@ApiTags('Platform API')
@Controller('platform')
@RequireModule(DADOSFERA_MODULES_KEYS.COLLECT)
export class PlatformApiController {
private logger: any;
@@ -1,14 +1,25 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ReleaseNoteController } from './release_note.controller';
import { ReleaseNoteService } from './release_note.service';
import DadosferaLogger from '@dadosfera/dadosfera-logs';
describe('ReleaseNoteController', () => {
let controller: ReleaseNoteController;
const logger = {
info: (...args) => args,
error: (...args) => args,
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [ReleaseNoteController],
providers: [ReleaseNoteService],
providers: [
{
provide: DadosferaLogger,
useValue: { logger },
},
ReleaseNoteService
],
}).compile();
controller = module.get<ReleaseNoteController>(ReleaseNoteController);
@@ -1,12 +1,23 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ReleaseNoteService } from './release_note.service';
import DadosferaLogger from '@dadosfera/dadosfera-logs';
describe('ReleaseNoteService', () => {
let service: ReleaseNoteService;
const logger = {
info: (...args) => args,
error: (...args) => args,
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ReleaseNoteService],
providers: [
{
provide: DadosferaLogger,
useValue: { logger },
},
ReleaseNoteService
],
}).compile();
service = module.get<ReleaseNoteService>(ReleaseNoteService);
+1
View File
@@ -9,6 +9,7 @@ interface IMetadata {
details?: string;
sensitive?: string;
roles?: string[];
customer_modules?: string[];
is_data_manager?: boolean;
access_token?: string;
host?: string;
+1 -1
View File
@@ -1,4 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "test", "dist", "**/*spec.ts", "jest.config.ts"]
"exclude": ["node_modules", "test", "dist", "**/*spec.ts", "jest.*.ts"]
}