Compare commits

...
8 changed files with 196 additions and 39 deletions
+1
View File
@@ -9,6 +9,7 @@ maestro:
cookie_secret: "ff7bc13823edb2ae50d248e5780bddc9d4b31c36" cookie_secret: "ff7bc13823edb2ae50d248e5780bddc9d4b31c36"
redis_database: "1" redis_database: "1"
platform_api_url: https://xs2hkhq07k.execute-api.us-east-1.amazonaws.com platform_api_url: https://xs2hkhq07k.execute-api.us-east-1.amazonaws.com
storage_explorer_api_url: "http://storage-explorer-{customer}.data-apps.svc.cluster.local:8000/api"
hostname: maestro.stg.dadosfera.ai hostname: maestro.stg.dadosfera.ai
+1 -1
View File
@@ -47,7 +47,7 @@ maestro:
open_customer_id: f239718a-a271-4ef9-ae7e-02a2f0f3aa6e open_customer_id: f239718a-a271-4ef9-ae7e-02a2f0f3aa6e
open_group_id: 401573bb-334f-44b2-b30e-88d4cea31ae9 open_group_id: 401573bb-334f-44b2-b30e-88d4cea31ae9
platform_api_url: https://oz8v2zid1e.execute-api.us-east-1.amazonaws.com platform_api_url: https://oz8v2zid1e.execute-api.us-east-1.amazonaws.com
storage_explorer_api_url: "https://storage-explorer-{customer_id}.prd.dadosfera.ai/api" storage_explorer_api_url: "https://storage-explorer-{customer}.dadosfera.ai/api"
dedicated_proxy: "" dedicated_proxy: ""
restricted_ip: "" restricted_ip: ""
redis_host: "aaapzppmlyamkocqwstpo7zvopczyyiyuy6xzm2g6c5k4mq3a66be4a-0.redis.sa-saopaulo-1.oci.oraclecloud.com" redis_host: "aaapzppmlyamkocqwstpo7zvopczyyiyuy6xzm2g6c5k4mq3a66be4a-0.redis.sa-saopaulo-1.oci.oraclecloud.com"
+94 -30
View File
@@ -7275,6 +7275,100 @@
] ]
} }
}, },
"/platform/pipelines/catalog/tables": {
"get": {
"operationId": "PlatformApiController_getAvailableTables",
"summary": "Get all tables available",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"Platform API"
],
"security": [
{
"access-token": []
}
]
}
},
"/platform/pipelines/catalog/schemas": {
"get": {
"operationId": "PlatformApiController_getAvailableSchemas",
"summary": "Get all schemas available",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"Platform API"
],
"security": [
{
"access-token": []
}
]
}
},
"/platform/pipelines/catalog/tables/validate": {
"post": {
"operationId": "PlatformApiController_validateTableAndSchema",
"summary": "Validate tables and schemas",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
},
"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",
@@ -8440,36 +8534,6 @@
] ]
} }
}, },
"/storage-explorer/storage/link-to-table": {
"post": {
"operationId": "StorageExplorerController_linkFileToTable",
"summary": "Link an existing file in storage to a table",
"parameters": [],
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"Storage Explorer"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
]
}
},
"/storage-explorer/storage/metadata": { "/storage-explorer/storage/metadata": {
"get": { "get": {
"operationId": "StorageExplorerController_getFileMetadata", "operationId": "StorageExplorerController_getFileMetadata",
+1 -1
View File
@@ -502,7 +502,7 @@ export class AuthController {
const accessToken = req.cookies['ddf-auth']; const accessToken = req.cookies['ddf-auth'];
const refreshToken = req.cookies['ddf-refresh-auth']; const refreshToken = req.cookies['ddf-refresh-auth'];
const userId = req.cookies['ddf-user-id']; const userId = req.cookies['ddf-user-id'];
const resourceHost = req.headers["host"] const resourceHost = req.headers["x-original-url"] as string || "" ;
const hasUserSession = Boolean(accessToken) && Boolean(userId); const hasUserSession = Boolean(accessToken) && Boolean(userId);
this.logger.info('Has User Session: ' + hasUserSession); this.logger.info('Has User Session: ' + hasUserSession);
@@ -26,6 +26,14 @@ 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';
type ValidateTablesDTO = {
tables: Array<{
table_schema: string,
table_name: string
}>
}
@ApiTags('Platform API') @ApiTags('Platform API')
@Controller('platform') @Controller('platform')
export class PlatformApiController { export class PlatformApiController {
@@ -720,6 +728,57 @@ export class PlatformApiController {
); );
} }
// ==================== Catalog ROUTES ====================
@Get('pipelines/catalog/tables')
@ApiOperation({ summary: 'Get all tables available' })
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
async getAvailableTables(
@User() user: RequestUser,
@Query() query: Record<string, string>,
) {
return this.platformApiService.proxy(
'GET',
'/catalog/tables',
user,
undefined,
query,
);
}
@Get('pipelines/catalog/schemas')
@ApiOperation({ summary: 'Get all schemas available' })
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
async getAvailableSchemas(
@User() user: RequestUser,
@Query() query: Record<string, string>,
) {
return this.platformApiService.proxy(
'GET',
'/catalog/schemas',
user,
undefined,
query,
);
}
@Post('pipelines/catalog/tables/validate')
@ApiOperation({ summary: 'Validate tables and schemas' })
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
async validateTableAndSchema(
@User() user: RequestUser,
@Query() query: Record<string, string>,
@Body() validateTablesDto: ValidateTablesDTO[]
) {
return this.platformApiService.proxy(
'POST',
'/catalog/tables/validate',
user,
validateTablesDto,
query,
);
}
// ==================== PIPELINE RUN ROUTES ==================== // ==================== PIPELINE RUN ROUTES ====================
@Get('pipeline/:pipelineId/pipeline_run') @Get('pipeline/:pipelineId/pipeline_run')
@@ -1,13 +1,13 @@
export const STORAGE_EXPLORER_CONFIG = { export const STORAGE_EXPLORER_CONFIG = {
getUrl: (customerId: string): string => { getUrl: (customerName: string): string => {
const urlTemplate = process.env.STORAGE_EXPLORER_API_URL; const urlTemplate = process.env.STORAGE_EXPLORER_API_URL;
if (!urlTemplate) { if (!urlTemplate) {
throw new Error('STORAGE_EXPLORER_API_URL environment variable is not set'); throw new Error('STORAGE_EXPLORER_API_URL environment variable is not set');
} }
// Replace {customer_id} placeholder with actual customer ID // Replace {customer_id} placeholder with actual customer ID
// For local: http://172.17.0.1:8000/api (no placeholder) // For local: http://172.17.0.1:8000/api (no placeholder)
// For prod: https://storage-explorer-{customer_id}.stg.dadosfera.ai/api // For prod: https://storage-explorer-{customer_id}.dadosfera.ai/api
return urlTemplate.replace('{customer_id}', customerId); return urlTemplate.replace('{customer}', customerName);
}, },
timeout: parseInt(process.env.STORAGE_EXPLORER_TIMEOUT || '30000', 10), timeout: parseInt(process.env.STORAGE_EXPLORER_TIMEOUT || '30000', 10),
}; };
@@ -3,13 +3,13 @@ import {
Get, Get,
Post, Post,
Put, Put,
Delete,
Param, Param,
Body, Body,
Query, Query,
Inject, Inject,
UseInterceptors, UseInterceptors,
UploadedFiles, UploadedFiles,
Headers,
} from '@nestjs/common'; } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiConsumes } from '@nestjs/swagger'; import { ApiTags, ApiOperation, ApiConsumes } from '@nestjs/swagger';
import { FilesInterceptor } from '@nestjs/platform-express'; import { FilesInterceptor } from '@nestjs/platform-express';
@@ -47,11 +47,13 @@ export class StorageExplorerController {
async validateTableName( async validateTableName(
@Body() body: any, @Body() body: any,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'POST', 'POST',
'/tables/validate-name', '/tables/validate-name',
user, user,
body, body,
); );
} }
@@ -62,11 +64,13 @@ export class StorageExplorerController {
async createTable( async createTable(
@Body() body: any, @Body() body: any,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'POST', 'POST',
'/tables/', '/tables/',
user, user,
body, body,
); );
} }
@@ -77,11 +81,13 @@ export class StorageExplorerController {
async listTables( async listTables(
@Query('page') page: number, @Query('page') page: number,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'GET', 'GET',
'/tables/', '/tables/',
user, user,
undefined, undefined,
{ page }, { page },
); );
@@ -93,6 +99,7 @@ export class StorageExplorerController {
async getTable( async getTable(
@Param('tableId') tableId: string, @Param('tableId') tableId: string,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'GET', 'GET',
@@ -108,11 +115,13 @@ export class StorageExplorerController {
@Param('tableId') tableId: string, @Param('tableId') tableId: string,
@Param('datasetId') datasetId: string, @Param('datasetId') datasetId: string,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'POST', 'POST',
`/tables/${tableId}/datasets/${datasetId}`, `/tables/${tableId}/datasets/${datasetId}`,
user, user,
); );
} }
@@ -122,11 +131,13 @@ export class StorageExplorerController {
async getTableDatasets( async getTableDatasets(
@Param('tableId') tableId: string, @Param('tableId') tableId: string,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'GET', 'GET',
`/tables/${tableId}/datasets`, `/tables/${tableId}/datasets`,
user, user,
); );
} }
@@ -136,11 +147,13 @@ export class StorageExplorerController {
async getTableSchema( async getTableSchema(
@Param('tableId') tableId: string, @Param('tableId') tableId: string,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'GET', 'GET',
`/tables/${tableId}/schema`, `/tables/${tableId}/schema`,
user, user,
); );
} }
@@ -156,6 +169,7 @@ export class StorageExplorerController {
'POST', 'POST',
`/tables/${tableId}/validate-compatibility/${datasetId}`, `/tables/${tableId}/validate-compatibility/${datasetId}`,
user, user,
); );
} }
@@ -170,11 +184,13 @@ export class StorageExplorerController {
@Param('datasetId') datasetId: string, @Param('datasetId') datasetId: string,
@Query('limit') limit: number, @Query('limit') limit: number,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'GET', 'GET',
`/datasets/${datasetId}/preview`, `/datasets/${datasetId}/preview`,
user, user,
undefined, undefined,
{ limit }, { limit },
); );
@@ -187,11 +203,13 @@ export class StorageExplorerController {
@Param('datasetId') datasetId: string, @Param('datasetId') datasetId: string,
@Query('force_refresh') forceRefresh: boolean, @Query('force_refresh') forceRefresh: boolean,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'GET', 'GET',
`/datasets/${datasetId}/schema`, `/datasets/${datasetId}/schema`,
user, user,
undefined, undefined,
{ force_refresh: forceRefresh }, { force_refresh: forceRefresh },
); );
@@ -203,11 +221,13 @@ export class StorageExplorerController {
async listDatasetsByUpload( async listDatasetsByUpload(
@Param('uploadId') uploadId: string, @Param('uploadId') uploadId: string,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'GET', 'GET',
`/datasets/upload/${uploadId}`, `/datasets/upload/${uploadId}`,
user, user,
); );
} }
@@ -218,11 +238,13 @@ export class StorageExplorerController {
@Param('datasetId') datasetId: string, @Param('datasetId') datasetId: string,
@Body() body: any, @Body() body: any,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'PUT', 'PUT',
`/datasets/${datasetId}/refresh-schema`, `/datasets/${datasetId}/refresh-schema`,
user, user,
body, body,
); );
} }
@@ -239,11 +261,13 @@ export class StorageExplorerController {
@Query('limit') limit: number, @Query('limit') limit: number,
@Query('folder_path') folderPath: string, @Query('folder_path') folderPath: string,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'GET', 'GET',
'/storage/uploads/history', '/storage/uploads/history',
user, user,
undefined, undefined,
{ page, limit, folder_path: folderPath }, { page, limit, folder_path: folderPath },
); );
@@ -255,11 +279,13 @@ export class StorageExplorerController {
async browseStorage( async browseStorage(
@Query('path') path: string, @Query('path') path: string,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'GET', 'GET',
'/storage/browse', '/storage/browse',
user, user,
undefined, undefined,
{ path }, { path },
); );
@@ -274,6 +300,7 @@ export class StorageExplorerController {
@UploadedFiles() files: Array<Express.Multer.File>, @UploadedFiles() files: Array<Express.Multer.File>,
@Body('folder_path') folderPath: string, @Body('folder_path') folderPath: string,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
// Create FormData to forward files to storage-explorer API // Create FormData to forward files to storage-explorer API
const formData = new FormData(); const formData = new FormData();
@@ -297,6 +324,7 @@ export class StorageExplorerController {
'POST', 'POST',
'/storage/upload/batch', '/storage/upload/batch',
user, user,
formData, formData,
); );
} }
@@ -307,11 +335,13 @@ export class StorageExplorerController {
async createFolder( async createFolder(
@Body() body: any, @Body() body: any,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'POST', 'POST',
'/storage/folder/create', '/storage/folder/create',
user, user,
body, body,
); );
} }
@@ -322,11 +352,13 @@ export class StorageExplorerController {
async downloadFile( async downloadFile(
@Query('file_path') filePath: string, @Query('file_path') filePath: string,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'GET', 'GET',
'/storage/download', '/storage/download',
user, user,
undefined, undefined,
{ file_path: filePath }, { file_path: filePath },
); );
@@ -338,6 +370,7 @@ export class StorageExplorerController {
async getFileMetadata( async getFileMetadata(
@Query('file_path') filePath: string, @Query('file_path') filePath: string,
@User() user: RequestUser, @User() user: RequestUser,
) { ) {
return this.storageExplorerService.proxy( return this.storageExplorerService.proxy(
'GET', 'GET',
@@ -20,7 +20,7 @@ export class StorageExplorerService {
path: string, path: string,
user: RequestUser, user: RequestUser,
body?: any, body?: any,
query?: Record<string, any>, query?: Record<string, any>
): Promise<any> { ): Promise<any> {
// Validate customer_id is present for multi-tenant isolation // Validate customer_id is present for multi-tenant isolation
if (!user.customer_id) { if (!user.customer_id) {
@@ -28,7 +28,7 @@ export class StorageExplorerService {
} }
// Get customer-specific storage-explorer URL // Get customer-specific storage-explorer URL
const baseUrl = STORAGE_EXPLORER_CONFIG.getUrl(user.customer_id); const baseUrl = STORAGE_EXPLORER_CONFIG.getUrl(user.customer_name);
const url = new URL(`${baseUrl}${path}`); const url = new URL(`${baseUrl}${path}`);
// Add query params // Add query params
@@ -113,7 +113,7 @@ export class StorageExplorerService {
} }
// Get customer-specific storage-explorer URL // Get customer-specific storage-explorer URL
const baseUrl = STORAGE_EXPLORER_CONFIG.getUrl(user.customer_id); const baseUrl = STORAGE_EXPLORER_CONFIG.getUrl(user.customer_name);
const url = new URL(`${baseUrl}${path}`); const url = new URL(`${baseUrl}${path}`);
// Add query params // Add query params