mirror of
https://github.com/dadosfera/maestro.git
synced 2026-11-14 02:19:09 +00:00
Compare commits
36
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b736cddf07 | ||
|
|
007f3911ff | ||
|
|
d3c5c0fa63 | ||
|
|
5dbc644d1d | ||
|
|
8eddb9e1bf | ||
|
|
76485f929d | ||
|
|
a18bdccc09 | ||
|
|
b27298501d | ||
|
|
33ebc91826 | ||
|
|
6948156693 | ||
|
|
0aaa4384c3 | ||
|
|
1f9d0c29ec | ||
|
|
039c652b28 | ||
|
|
653d4f53b5 | ||
|
|
31f8c2c1a6 | ||
|
|
8b93d4e97b | ||
|
|
adeb022818 | ||
|
|
f61c241dde | ||
|
|
e326cab44d | ||
|
|
61109f8ae9 | ||
|
|
3f8dc5cabe | ||
|
|
7f5d157739 | ||
|
|
bce73fb11f | ||
|
|
9473e65deb | ||
|
|
9c55c22230 | ||
|
|
77b9acd2d0 | ||
|
|
e99306adba | ||
|
|
96b947ebdc | ||
|
|
fb521f53cd | ||
|
|
6f7436f33f | ||
|
|
865140e681 | ||
|
|
c4a664572a | ||
|
|
acb631e33d | ||
|
|
7a10f88113 | ||
|
|
e616061c21 | ||
|
|
e7f410831f |
+2
-1
@@ -1,4 +1,5 @@
|
|||||||
FROM node:18.17-alpine AS base_image
|
FROM node:20-alpine AS base_image
|
||||||
|
RUN npm install -g npm@latest
|
||||||
|
|
||||||
FROM base_image AS build_base
|
FROM base_image AS build_base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
FROM node:20-alpine AS base_image
|
||||||
|
RUN npm install -g npm@latest
|
||||||
|
|
||||||
|
FROM base_image AS build_base
|
||||||
|
WORKDIR /app
|
||||||
|
RUN apk update
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
aws-cli \
|
||||||
|
chromium \
|
||||||
|
nss \
|
||||||
|
freetype \
|
||||||
|
harfbuzz \
|
||||||
|
ca-certificates \
|
||||||
|
ttf-freefont
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
|
||||||
|
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
|
||||||
|
|
||||||
|
|
||||||
|
# Local build with secrets
|
||||||
|
FROM build_base AS build
|
||||||
|
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
|
||||||
|
aws codeartifact login --tool npm --namespace @dadosfera --repository dadosfera-npm --domain dadosfera --domain-owner 611330257153 --region us-east-1
|
||||||
|
RUN npm ci
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
|
||||||
|
FROM base_image
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=build /app/dist ./dist
|
||||||
|
COPY --from=build /app/node_modules ./node_modules
|
||||||
|
COPY --from=build /app/package*.json ./
|
||||||
|
RUN apk update
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
chromium \
|
||||||
|
nss \
|
||||||
|
freetype \
|
||||||
|
harfbuzz \
|
||||||
|
ca-certificates \
|
||||||
|
ttf-freefont
|
||||||
|
|
||||||
|
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
|
||||||
|
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
|
||||||
|
|
||||||
|
ENTRYPOINT ["npm", "run", "start:prod"]
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
<image src="./assets/maestro.svg" style="width:10rem">
|
<image src="./assets/maestro.svg" style="width:10rem">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
# Maestro
|
# Maestro
|
||||||
|
|
||||||
Maestro é a API principal da Dadosfera. É responsável pela comunicação do Frontend com nossos microsserviços.
|
Maestro é a API principal da Dadosfera. É responsável pela comunicação do Frontend com nossos microsserviços.
|
||||||
|
|||||||
+54
-30
@@ -1321,9 +1321,6 @@
|
|||||||
"Users"
|
"Users"
|
||||||
],
|
],
|
||||||
"security": [
|
"security": [
|
||||||
{
|
|
||||||
"access-token": []
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"access-token": []
|
"access-token": []
|
||||||
}
|
}
|
||||||
@@ -7225,33 +7222,6 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/platform/pipeline/pipeline_run": {
|
|
||||||
"post": {
|
|
||||||
"operationId": "PlatformApiController_createPipelineRun",
|
|
||||||
"summary": "Create a pipeline run",
|
|
||||||
"parameters": [],
|
|
||||||
"responses": {
|
|
||||||
"201": {
|
|
||||||
"description": "",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Platform API"
|
|
||||||
],
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"access-token": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/platform/pipeline/{pipelineId}/pipeline_run": {
|
"/platform/pipeline/{pipelineId}/pipeline_run": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "PlatformApiController_getPipelineRuns",
|
"operationId": "PlatformApiController_getPipelineRuns",
|
||||||
@@ -8193,6 +8163,15 @@
|
|||||||
"hierarchy": {
|
"hierarchy": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"bio": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"companyName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"companySite": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"mfaStatus": {
|
"mfaStatus": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@@ -8223,6 +8202,9 @@
|
|||||||
"jobTitle",
|
"jobTitle",
|
||||||
"department",
|
"department",
|
||||||
"hierarchy",
|
"hierarchy",
|
||||||
|
"bio",
|
||||||
|
"companyName",
|
||||||
|
"companySite",
|
||||||
"mfaStatus",
|
"mfaStatus",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
"updatedAt",
|
"updatedAt",
|
||||||
@@ -8356,6 +8338,15 @@
|
|||||||
"hierarchy": {
|
"hierarchy": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"bio": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"companyName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"companySite": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"customer": {
|
"customer": {
|
||||||
"$ref": "#/components/schemas/Customer"
|
"$ref": "#/components/schemas/Customer"
|
||||||
},
|
},
|
||||||
@@ -8383,6 +8374,9 @@
|
|||||||
"jobTitle",
|
"jobTitle",
|
||||||
"department",
|
"department",
|
||||||
"hierarchy",
|
"hierarchy",
|
||||||
|
"bio",
|
||||||
|
"companyName",
|
||||||
|
"companySite",
|
||||||
"mfaStatus",
|
"mfaStatus",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
"updatedAt",
|
"updatedAt",
|
||||||
@@ -8523,6 +8517,15 @@
|
|||||||
"hierarchy": {
|
"hierarchy": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"bio": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"companySite": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"companyName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"roleNames": {
|
"roleNames": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@@ -8563,6 +8566,15 @@
|
|||||||
"hierarchy": {
|
"hierarchy": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"bio": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"companyName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"companySite": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"mfaStatus": {
|
"mfaStatus": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@@ -8586,6 +8598,9 @@
|
|||||||
"jobTitle",
|
"jobTitle",
|
||||||
"department",
|
"department",
|
||||||
"hierarchy",
|
"hierarchy",
|
||||||
|
"bio",
|
||||||
|
"companyName",
|
||||||
|
"companySite",
|
||||||
"mfaStatus",
|
"mfaStatus",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
"updatedAt",
|
"updatedAt",
|
||||||
@@ -9634,6 +9649,9 @@
|
|||||||
"public",
|
"public",
|
||||||
"private"
|
"private"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"docs": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -9888,6 +9906,9 @@
|
|||||||
"public",
|
"public",
|
||||||
"private"
|
"private"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"docs": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -9927,6 +9948,9 @@
|
|||||||
},
|
},
|
||||||
"embed": {
|
"embed": {
|
||||||
"$ref": "#/components/schemas/EmbedObject"
|
"$ref": "#/components/schemas/EmbedObject"
|
||||||
|
},
|
||||||
|
"docs": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
|||||||
Generated
+2110
-2969
File diff suppressed because it is too large
Load Diff
+10
-4
@@ -30,12 +30,12 @@
|
|||||||
"@aws-crypto/sha256-js": "^5.2.0",
|
"@aws-crypto/sha256-js": "^5.2.0",
|
||||||
"@aws-sdk/client-dynamodb": "^3.414.0",
|
"@aws-sdk/client-dynamodb": "^3.414.0",
|
||||||
"@aws-sdk/client-secrets-manager": "^3.414.0",
|
"@aws-sdk/client-secrets-manager": "^3.414.0",
|
||||||
"@aws-sdk/lib-dynamodb": "^3.414.0",
|
|
||||||
"@aws-sdk/credential-provider-node": "^3.940.0",
|
"@aws-sdk/credential-provider-node": "^3.940.0",
|
||||||
|
"@aws-sdk/lib-dynamodb": "^3.414.0",
|
||||||
"@aws-sdk/signature-v4": "^3.370.0",
|
"@aws-sdk/signature-v4": "^3.370.0",
|
||||||
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
|
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
|
||||||
"@dadosfera/protospack": "2.5.3",
|
"@dadosfera/protospack": "2.5.3",
|
||||||
"@dadosfera/protospack-v2": "3.38.0-beta.16",
|
"@dadosfera/protospack-v2": "3.38.0-beta.19",
|
||||||
"@grpc/grpc-js": "^1.9.3",
|
"@grpc/grpc-js": "^1.9.3",
|
||||||
"@grpc/proto-loader": "^0.7.9",
|
"@grpc/proto-loader": "^0.7.9",
|
||||||
"@nestjs/cli": "^9.5.0",
|
"@nestjs/cli": "^9.5.0",
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
"@nestjs/schematics": "^9.2.0",
|
"@nestjs/schematics": "^9.2.0",
|
||||||
"@nestjs/swagger": "^6.3.0",
|
"@nestjs/swagger": "^6.3.0",
|
||||||
"@nestjs/testing": "^9.4.3",
|
"@nestjs/testing": "^9.4.3",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.30.2",
|
||||||
"cache-manager": "^5.1.4",
|
"cache-manager": "^5.1.4",
|
||||||
"cache-manager-ioredis-yet": "^1.1.0",
|
"cache-manager-ioredis-yet": "^1.1.0",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
@@ -80,7 +80,13 @@
|
|||||||
"swagger-ui-express": "^4.6.3"
|
"swagger-ui-express": "^4.6.3"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"multer": "1.4.5-lts.1"
|
"multer": "2.0.2",
|
||||||
|
"form-data": "^4.0.4",
|
||||||
|
"body-parser": "^1.20.3",
|
||||||
|
"cross-spawn": "^7.0.5",
|
||||||
|
"glob": "^10.5.0",
|
||||||
|
"path-to-regexp": "^3.3.0",
|
||||||
|
"semver": "^7.5.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/cache-manager": "^4.0.6",
|
"@types/cache-manager": "^4.0.6",
|
||||||
|
|||||||
@@ -98,6 +98,8 @@ export class IDataAsset {
|
|||||||
embed?: EmbedObject;
|
embed?: EmbedObject;
|
||||||
@ApiPropertyOptional({ enum: DataAssetShareType })
|
@ApiPropertyOptional({ enum: DataAssetShareType })
|
||||||
share_type?: DataAssetShareType;
|
share_type?: DataAssetShareType;
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
docs?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IOneDataAsset {
|
export class IOneDataAsset {
|
||||||
@@ -200,6 +202,8 @@ export class IUpdateDataRequest {
|
|||||||
embed: EmbedObject;
|
embed: EmbedObject;
|
||||||
@ApiPropertyOptional({ enum: DataAssetShareType })
|
@ApiPropertyOptional({ enum: DataAssetShareType })
|
||||||
share_type?: DataAssetShareType;
|
share_type?: DataAssetShareType;
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
docs?: string;
|
||||||
}
|
}
|
||||||
export class ICreateDataAsset implements CreateDataAssetRequest {
|
export class ICreateDataAsset implements CreateDataAssetRequest {
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@@ -214,6 +218,8 @@ export class ICreateDataAsset implements CreateDataAssetRequest {
|
|||||||
location: string;
|
location: string;
|
||||||
@ApiPropertyOptional()
|
@ApiPropertyOptional()
|
||||||
embed: EmbedObject;
|
embed: EmbedObject;
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
docs: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IPreview {
|
export class IPreview {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import { User, RequestUser } from '../../decorators/user.decorator';
|
|||||||
import { PlatformApiService } from './platform-api.service';
|
import { PlatformApiService } from './platform-api.service';
|
||||||
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
|
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
|
||||||
import { ElasticsearchService } from '../../services/elasticsearch';
|
import { ElasticsearchService } from '../../services/elasticsearch';
|
||||||
import { DynamoDBService } from '../../services/dynamodb';
|
import { DynamoDBService, ReferenceColumn } from '../../services/dynamodb';
|
||||||
import { CustomersService } from '../customers/customers.service';
|
import { CustomersService } from '../customers/customers.service';
|
||||||
import { validateCronAgainstScheduleLimit } from '../../utils/cron-validation';
|
import { validateCronAgainstScheduleLimit } from '../../utils/cron-validation';
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ export class PlatformApiController {
|
|||||||
* Extract and transform tables from jobs for DynamoDB input.
|
* Extract and transform tables from jobs for DynamoDB input.
|
||||||
* Maps connector-specific fields to a common table format.
|
* Maps connector-specific fields to a common table format.
|
||||||
*
|
*
|
||||||
* - JDBC: load_type, table_name, column_include_list (columns), incremental_column_name (reference_column)
|
* - JDBC: load_type, table_name, column_include_list (columns), incremental_column_name/type (reference_column object)
|
||||||
* - Singer: type maps replication_method (FULL_TABLE -> full_load, INCREMENTAL -> incremental), no columns
|
* - Singer: type maps replication_method (FULL_TABLE -> full_load, INCREMENTAL -> incremental), no columns
|
||||||
* - S3: same mapping as Singer, no columns
|
* - S3: same mapping as Singer, no columns
|
||||||
*/
|
*/
|
||||||
@@ -163,7 +163,7 @@ export class PlatformApiController {
|
|||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
columns?: string[];
|
columns?: string[];
|
||||||
reference_column?: string;
|
reference_column?: ReferenceColumn;
|
||||||
}> {
|
}> {
|
||||||
if (!jobs || jobs.length === 0) return [];
|
if (!jobs || jobs.length === 0) return [];
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ export class PlatformApiController {
|
|||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
columns?: string[];
|
columns?: string[];
|
||||||
reference_column?: string;
|
reference_column?: ReferenceColumn;
|
||||||
}> = [];
|
}> = [];
|
||||||
|
|
||||||
for (const job of jobs) {
|
for (const job of jobs) {
|
||||||
@@ -179,12 +179,12 @@ export class PlatformApiController {
|
|||||||
if (!input) continue;
|
if (!input) continue;
|
||||||
|
|
||||||
if (connector === 'jdbc') {
|
if (connector === 'jdbc') {
|
||||||
// JDBC: table_name, load_type, column_include_list, incremental_column_name
|
// JDBC: table_name, load_type, column_include_list, incremental_column_name/type
|
||||||
const table: {
|
const table: {
|
||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
columns?: string[];
|
columns?: string[];
|
||||||
reference_column?: string;
|
reference_column?: ReferenceColumn;
|
||||||
} = {
|
} = {
|
||||||
name: input.table_name || '',
|
name: input.table_name || '',
|
||||||
type: input.load_type || 'full_load',
|
type: input.load_type || 'full_load',
|
||||||
@@ -193,8 +193,11 @@ export class PlatformApiController {
|
|||||||
table.columns = input.column_include_list;
|
table.columns = input.column_include_list;
|
||||||
}
|
}
|
||||||
if (input.incremental_column_name) {
|
if (input.incremental_column_name) {
|
||||||
// reference_column is stored as a string (column name)
|
// reference_column is stored as an object with name and type
|
||||||
table.reference_column = input.incremental_column_name;
|
table.reference_column = {
|
||||||
|
name: input.incremental_column_name,
|
||||||
|
type: input.incremental_column_type || 'unknown',
|
||||||
|
};
|
||||||
}
|
}
|
||||||
tables.push(table);
|
tables.push(table);
|
||||||
} else if (connector === 'singer' || connector === 's3') {
|
} else if (connector === 'singer' || connector === 's3') {
|
||||||
@@ -317,11 +320,11 @@ export class PlatformApiController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build changes for DynamoDB table entry
|
// Build changes for DynamoDB table entry
|
||||||
// reference_column is stored as a string (column name), not an object
|
// reference_column is stored as an object with name and type
|
||||||
const changes: {
|
const changes: {
|
||||||
type?: string;
|
type?: string;
|
||||||
columns?: string[];
|
columns?: string[];
|
||||||
reference_column?: string | null;
|
reference_column?: ReferenceColumn | null;
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
|
|
||||||
@@ -332,8 +335,15 @@ export class PlatformApiController {
|
|||||||
changes.columns = body.column_include_list;
|
changes.columns = body.column_include_list;
|
||||||
}
|
}
|
||||||
if ('incremental_column_name' in body) {
|
if ('incremental_column_name' in body) {
|
||||||
// reference_column is just the column name as a string
|
// reference_column is stored as an object with name and type
|
||||||
changes.reference_column = body.incremental_column_name || null;
|
if (body.incremental_column_name) {
|
||||||
|
changes.reference_column = {
|
||||||
|
name: body.incremental_column_name,
|
||||||
|
type: body.incremental_column_type || 'unknown',
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
changes.reference_column = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update DynamoDB if there are changes
|
// Update DynamoDB if there are changes
|
||||||
@@ -466,11 +476,13 @@ export class PlatformApiController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pipelineType = this.mapConnectorToDynamoType(connectorType);
|
||||||
this.logger.info('Syncing pipeline to Elasticsearch', {
|
this.logger.info('Syncing pipeline to Elasticsearch', {
|
||||||
customerName: user.customer_name,
|
customerName: user.customer_name,
|
||||||
pipelineId: body.id,
|
pipelineId: body.id,
|
||||||
plugin,
|
plugin,
|
||||||
connector: connectorType,
|
connector: connectorType,
|
||||||
|
type: pipelineType,
|
||||||
properties,
|
properties,
|
||||||
inputId,
|
inputId,
|
||||||
});
|
});
|
||||||
@@ -490,6 +502,7 @@ export class PlatformApiController {
|
|||||||
cron: body.cron,
|
cron: body.cron,
|
||||||
tables: inputId,
|
tables: inputId,
|
||||||
properties,
|
properties,
|
||||||
|
type: pipelineType,
|
||||||
},
|
},
|
||||||
connector,
|
connector,
|
||||||
);
|
);
|
||||||
@@ -617,21 +630,39 @@ export class PlatformApiController {
|
|||||||
@ApiOperation({ summary: 'Execute a pipeline' })
|
@ApiOperation({ summary: 'Execute a pipeline' })
|
||||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||||
async executePipeline(@Body() body: any, @User() user: RequestUser) {
|
async executePipeline(@Body() body: any, @User() user: RequestUser) {
|
||||||
return this.platformApiService.proxy('POST', '/pipeline/execute', user, body);
|
// Inject customer_id (actually customer_name) into body for Platform-API
|
||||||
|
// Note: Platform-API was created before customer_id existed, so it expects customer_name in the customer_id field
|
||||||
|
const enrichedBody = {
|
||||||
|
...body,
|
||||||
|
customer_id: user.customer_name,
|
||||||
|
};
|
||||||
|
return this.platformApiService.proxy('POST', '/pipeline/execute', user, enrichedBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('pipeline/pause')
|
@Post('pipeline/pause')
|
||||||
@ApiOperation({ summary: 'Pause a pipeline' })
|
@ApiOperation({ summary: 'Pause a pipeline' })
|
||||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||||
async pausePipeline(@Body() body: any, @User() user: RequestUser) {
|
async pausePipeline(@Body() body: any, @User() user: RequestUser) {
|
||||||
return this.platformApiService.proxy('POST', '/pipeline/pause', user, body);
|
// Inject customer_id (actually customer_name) into body for Platform-API
|
||||||
|
// Note: Platform-API was created before customer_id existed, so it expects customer_name in the customer_id field
|
||||||
|
const enrichedBody = {
|
||||||
|
...body,
|
||||||
|
customer_id: user.customer_name,
|
||||||
|
};
|
||||||
|
return this.platformApiService.proxy('POST', '/pipeline/pause', user, enrichedBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('pipeline/unpause')
|
@Post('pipeline/unpause')
|
||||||
@ApiOperation({ summary: 'Unpause a pipeline' })
|
@ApiOperation({ summary: 'Unpause a pipeline' })
|
||||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||||
async unpausePipeline(@Body() body: any, @User() user: RequestUser) {
|
async unpausePipeline(@Body() body: any, @User() user: RequestUser) {
|
||||||
return this.platformApiService.proxy('POST', '/pipeline/unpause', user, body);
|
// Inject customer_id (actually customer_name) into body for Platform-API
|
||||||
|
// Note: Platform-API was created before customer_id existed, so it expects customer_name in the customer_id field
|
||||||
|
const enrichedBody = {
|
||||||
|
...body,
|
||||||
|
customer_id: user.customer_name,
|
||||||
|
};
|
||||||
|
return this.platformApiService.proxy('POST', '/pipeline/unpause', user, enrichedBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Put('pipeline/:pipelineId/memory')
|
@Put('pipeline/:pipelineId/memory')
|
||||||
@@ -691,18 +722,6 @@ export class PlatformApiController {
|
|||||||
|
|
||||||
// ==================== PIPELINE RUN ROUTES ====================
|
// ==================== PIPELINE RUN ROUTES ====================
|
||||||
|
|
||||||
@Post('pipeline/pipeline_run')
|
|
||||||
@ApiOperation({ summary: 'Create a pipeline run' })
|
|
||||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
|
||||||
async createPipelineRun(@Body() body: any, @User() user: RequestUser) {
|
|
||||||
return this.platformApiService.proxy(
|
|
||||||
'POST',
|
|
||||||
'/pipeline/pipeline_run',
|
|
||||||
user,
|
|
||||||
body,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get('pipeline/:pipelineId/pipeline_run')
|
@Get('pipeline/:pipelineId/pipeline_run')
|
||||||
@ApiOperation({ summary: 'Get pipeline runs for a pipeline' })
|
@ApiOperation({ summary: 'Get pipeline runs for a pipeline' })
|
||||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
|
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
|
||||||
@@ -711,9 +730,10 @@ export class PlatformApiController {
|
|||||||
@User() user: RequestUser,
|
@User() user: RequestUser,
|
||||||
@Query() query: Record<string, string>,
|
@Query() query: Record<string, string>,
|
||||||
) {
|
) {
|
||||||
|
const normalizedId = this.normalizePipelineId(pipelineId);
|
||||||
return this.platformApiService.proxy(
|
return this.platformApiService.proxy(
|
||||||
'GET',
|
'GET',
|
||||||
`/pipeline/${pipelineId}/pipeline_run`,
|
`/pipeline/${normalizedId}/pipeline_run`,
|
||||||
user,
|
user,
|
||||||
undefined,
|
undefined,
|
||||||
query,
|
query,
|
||||||
@@ -728,9 +748,11 @@ export class PlatformApiController {
|
|||||||
@Param('runId') runId: string,
|
@Param('runId') runId: string,
|
||||||
@User() user: RequestUser,
|
@User() user: RequestUser,
|
||||||
) {
|
) {
|
||||||
|
const normalizedPipelineId = this.normalizePipelineId(pipelineId);
|
||||||
|
const normalizedRunId = this.normalizePipelineId(runId);
|
||||||
return this.platformApiService.proxy(
|
return this.platformApiService.proxy(
|
||||||
'GET',
|
'GET',
|
||||||
`/pipeline/${pipelineId}/pipeline_run/${runId}`,
|
`/pipeline/${normalizedPipelineId}/pipeline_run/${normalizedRunId}`,
|
||||||
user,
|
user,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -743,9 +765,10 @@ export class PlatformApiController {
|
|||||||
@User() user: RequestUser,
|
@User() user: RequestUser,
|
||||||
@Query() query: Record<string, string>,
|
@Query() query: Record<string, string>,
|
||||||
) {
|
) {
|
||||||
|
const normalizedRunId = this.normalizePipelineId(runId);
|
||||||
return this.platformApiService.proxy(
|
return this.platformApiService.proxy(
|
||||||
'GET',
|
'GET',
|
||||||
`/pipeline/pipeline_run/${runId}/logs`,
|
`/pipeline/pipeline_run/${normalizedRunId}/logs`,
|
||||||
user,
|
user,
|
||||||
undefined,
|
undefined,
|
||||||
query,
|
query,
|
||||||
|
|||||||
@@ -229,27 +229,33 @@ export class RolesService {
|
|||||||
const [roleTreated] = this.getRolesPermissionsName([role.role]);
|
const [roleTreated] = this.getRolesPermissionsName([role.role]);
|
||||||
return { role: roleTreated };
|
return { role: roleTreated };
|
||||||
}
|
}
|
||||||
|
|
||||||
getRolesPermissionsName(roles: GetRolesPermissionsName[]): RoleDto[] {
|
getRolesPermissionsName(roles: GetRolesPermissionsName[]): RoleDto[] {
|
||||||
const newRoles: RoleDto[] = [];
|
const newRoles: RoleDto[] = [];
|
||||||
for (const role of roles) {
|
for (const role of roles) {
|
||||||
const allPermissions = this.permissionsService.getAllPermissions(
|
const newRole: RoleDto = this.formatRole(role);
|
||||||
this.language,
|
|
||||||
);
|
|
||||||
const newPermissions = role.permissions.map((p) => {
|
|
||||||
const permission = allPermissions.find((per) => per.seqid === p.seqid);
|
|
||||||
return {
|
|
||||||
...p,
|
|
||||||
name: permission.name,
|
|
||||||
id: p.seqid,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
const newRole: RoleDto = {
|
|
||||||
...role,
|
|
||||||
permissions: newPermissions,
|
|
||||||
isPublic: role.isPublic,
|
|
||||||
};
|
|
||||||
newRoles.push(newRole);
|
newRoles.push(newRole);
|
||||||
}
|
}
|
||||||
return newRoles;
|
return newRoles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private formatRole(role: GetRolesPermissionsName): RoleDto {
|
||||||
|
const allPermissions = this.permissionsService.getAllPermissions(
|
||||||
|
this.language
|
||||||
|
);
|
||||||
|
const newPermissions = role.permissions.map((p) => {
|
||||||
|
const permission = allPermissions.find((per) => per.seqid === p.seqid);
|
||||||
|
return {
|
||||||
|
...p,
|
||||||
|
name: permission.name,
|
||||||
|
id: p.seqid,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...role,
|
||||||
|
permissions: newPermissions,
|
||||||
|
isPublic: role.isPublic,
|
||||||
|
};;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,12 @@ export class User {
|
|||||||
department?: string;
|
department?: string;
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
hierarchy?: string;
|
hierarchy?: string;
|
||||||
|
@ApiProperty()
|
||||||
|
bio?: string;
|
||||||
|
@ApiProperty()
|
||||||
|
companyName?: string;
|
||||||
|
@ApiProperty()
|
||||||
|
companySite?: string;
|
||||||
@ApiPropertyOptional()
|
@ApiPropertyOptional()
|
||||||
customer?: Customer;
|
customer?: Customer;
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@@ -109,6 +115,12 @@ export class UpdateUserReq {
|
|||||||
@ApiPropertyOptional()
|
@ApiPropertyOptional()
|
||||||
hierarchy?: string;
|
hierarchy?: string;
|
||||||
@ApiPropertyOptional()
|
@ApiPropertyOptional()
|
||||||
|
bio?: string;
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
companySite?: string;
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
companyName?: string;
|
||||||
|
@ApiPropertyOptional()
|
||||||
roleNames?: string[];
|
roleNames?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -266,7 +266,6 @@ export class UsersController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':id')
|
@Patch(':id')
|
||||||
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
|
|
||||||
@ApiOkResponse({ type: UpdateUserRes })
|
@ApiOkResponse({ type: UpdateUserRes })
|
||||||
async updateUser(
|
async updateUser(
|
||||||
@User() user: RequestUser,
|
@User() user: RequestUser,
|
||||||
@@ -274,6 +273,18 @@ export class UsersController {
|
|||||||
@Param('id') id: string,
|
@Param('id') id: string,
|
||||||
@Language() language: LanguageEnum,
|
@Language() language: LanguageEnum,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
const isSameUser = user.user_id === id;
|
||||||
|
const isSuperAdmin = user.permissions.includes(PERMISSIONS_GROUPS.USERS.permissions.ADMIN.seqid)
|
||||||
|
if (!isSameUser && !isSuperAdmin) {
|
||||||
|
throw new ErrorBuilder(ErrorCodes.AUTH.FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSameUser && !isSuperAdmin && body.roleNames) {
|
||||||
|
// Prevent users from updating their own roles
|
||||||
|
delete body.roleNames;
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.info('updateUser', { user });
|
this.logger.info('updateUser', { user });
|
||||||
this.userService.setLanguage(language);
|
this.userService.setLanguage(language);
|
||||||
return await this.userService.updateUser(body, id, user.customer_id);
|
return await this.userService.updateUser(body, id, user.customer_id);
|
||||||
|
|||||||
@@ -148,20 +148,23 @@ export class UsersService implements OnModuleInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async updateUser(req: UpdateUserReq, id: string, customerId: string) {
|
async updateUser(req: UpdateUserReq, id: string, customerId: string) {
|
||||||
const { department, hierarchy, jobTitle, name, roleNames, email } = req;
|
const { roleNames, ...updateUserDTO } = req;
|
||||||
if (roleNames) {
|
if (roleNames && roleNames.length > 0) {
|
||||||
await this.setRoles({ roleNames, userId: id }, customerId);
|
await this.setRoles({ roleNames, userId: id }, customerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = await lastValueFrom(
|
const { user } = await lastValueFrom(
|
||||||
this.usersClientService.UserUpdate({
|
this.usersClientService.UserUpdate({
|
||||||
name,
|
department: updateUserDTO.department,
|
||||||
|
email: updateUserDTO.email,
|
||||||
|
hierarchy: updateUserDTO.hierarchy,
|
||||||
|
jobTitle: updateUserDTO.jobTitle,
|
||||||
|
name: updateUserDTO.name,
|
||||||
|
bio: updateUserDTO.bio,
|
||||||
|
companyName: updateUserDTO.companyName,
|
||||||
|
companySite: updateUserDTO.companySite,
|
||||||
customerId,
|
customerId,
|
||||||
id,
|
id,
|
||||||
department,
|
|
||||||
hierarchy,
|
|
||||||
jobTitle,
|
|
||||||
email,
|
|
||||||
metabaseUserId: undefined,
|
metabaseUserId: undefined,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ export class ValidationPipe implements PipeTransform<any> {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
const object = plainToInstance(metatype, value);
|
const object = plainToInstance(metatype, value);
|
||||||
const errors = await validate(object);
|
const errors = await validate(object, {
|
||||||
|
forbidUnknownValues: false,
|
||||||
|
whitelist: true,
|
||||||
|
});
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
const errorMessages = errors.map((err) => err.constraints);
|
const errorMessages = errors.map((err) => err.constraints);
|
||||||
throw new BadRequestException(errorMessages);
|
throw new BadRequestException(errorMessages);
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
|||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { DYNAMODB_CONFIG } from './dynamodb.config';
|
import { DYNAMODB_CONFIG } from './dynamodb.config';
|
||||||
|
|
||||||
|
export interface ReferenceColumn {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface InputDocument {
|
export interface InputDocument {
|
||||||
id: string;
|
id: string;
|
||||||
client_id: string;
|
client_id: string;
|
||||||
@@ -24,7 +29,7 @@ export interface InputDocument {
|
|||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
columns?: string[];
|
columns?: string[];
|
||||||
reference_column?: string;
|
reference_column?: ReferenceColumn;
|
||||||
}>;
|
}>;
|
||||||
credentials?: Record<string, any>;
|
credentials?: Record<string, any>;
|
||||||
}
|
}
|
||||||
@@ -62,7 +67,7 @@ export class DynamoDBService {
|
|||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
columns?: string[];
|
columns?: string[];
|
||||||
reference_column?: string;
|
reference_column?: ReferenceColumn;
|
||||||
}>;
|
}>;
|
||||||
},
|
},
|
||||||
): Promise<InputDocument> {
|
): Promise<InputDocument> {
|
||||||
@@ -157,7 +162,7 @@ export class DynamoDBService {
|
|||||||
changes: {
|
changes: {
|
||||||
type?: string;
|
type?: string;
|
||||||
columns?: string[];
|
columns?: string[];
|
||||||
reference_column?: string | null;
|
reference_column?: ReferenceColumn | null;
|
||||||
},
|
},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const dynamoTableName = DYNAMODB_CONFIG.inputsTable();
|
const dynamoTableName = DYNAMODB_CONFIG.inputsTable();
|
||||||
|
|||||||
Reference in New Issue
Block a user