mirror of
https://github.com/dadosfera/maestro.git
synced 2026-09-17 20:14:48 +00:00
FEAT: add Platform API proxy with Elasticsearch and DynamoDB sync
- Add Platform API module to proxy requests to Platform API service - Add Elasticsearch service for pipeline catalog sync (CRUD operations) - Add DynamoDB service for storing pipeline tables/inputs configuration - Sync pipeline creation/update/delete to Elasticsearch index - Extract tables from jobs with connector-specific mappings: - JDBC: table_name, load_type, column_include_list, incremental_column_name - Singer: replication_method -> full_load/incremental - S3: same as Singer - Map connector types to DynamoDB types (jdbc->database, singer->application, s3->file) - Validate connector type is provided in job input - Normalize pipeline IDs for Platform API (replace - with _), keep UUIDs for ES 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
e789076ed4
commit
df674dd441
@@ -0,0 +1,663 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Patch,
|
||||
Delete,
|
||||
Param,
|
||||
Body,
|
||||
Query,
|
||||
Inject,
|
||||
BadRequestException,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
||||
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
|
||||
import {
|
||||
Authenticated,
|
||||
RequireAllPermissions,
|
||||
} 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 { ElasticsearchService } from '../../services/elasticsearch';
|
||||
import { DynamoDBService } from '../../services/dynamodb';
|
||||
|
||||
@ApiTags('Platform API')
|
||||
@Controller('platform')
|
||||
export class PlatformApiController {
|
||||
private logger: any;
|
||||
|
||||
constructor(
|
||||
private readonly platformApiService: PlatformApiService,
|
||||
private readonly elasticsearchService: ElasticsearchService,
|
||||
private readonly dynamoDBService: DynamoDBService,
|
||||
@Inject(DadosferaLogger) dadosferaLogger: DadosferaLogger,
|
||||
) {
|
||||
this.logger = dadosferaLogger.logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize pipeline ID to match Platform-API format.
|
||||
* Platform-API replaces '-' with '_' in pipeline IDs.
|
||||
*/
|
||||
private normalizePipelineId(id: string): string {
|
||||
return id?.replace(/-/g, '_') || '';
|
||||
}
|
||||
|
||||
private readonly VALID_CONNECTORS = ['jdbc', 'singer', 's3'];
|
||||
|
||||
/**
|
||||
* Validate that connector is provided and is a valid type.
|
||||
*/
|
||||
private validateConnector(connector: string | undefined): void {
|
||||
if (!connector || !this.VALID_CONNECTORS.includes(connector)) {
|
||||
throw new BadRequestException(
|
||||
`connector is required in job input and must be one of: ${this.VALID_CONNECTORS.join(', ')}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map connector type to DynamoDB type.
|
||||
* jdbc -> 'database', singer -> 'application', s3 -> 'file'
|
||||
*/
|
||||
private mapConnectorToDynamoType(connector: string): string {
|
||||
switch (connector) {
|
||||
case 'jdbc':
|
||||
return 'database';
|
||||
case 'singer':
|
||||
return 'application';
|
||||
case 's3':
|
||||
return 'file';
|
||||
default:
|
||||
return connector;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract and transform tables from jobs for DynamoDB input.
|
||||
* Maps connector-specific fields to a common table format.
|
||||
*
|
||||
* - JDBC: load_type, table_name, column_include_list (columns), incremental_column_name (reference_column)
|
||||
* - Singer: type maps replication_method (FULL_TABLE -> full_load, INCREMENTAL -> incremental), no columns
|
||||
* - S3: same mapping as Singer, no columns
|
||||
*/
|
||||
private extractTablesFromJobs(jobs: any[], connector: string): Array<{
|
||||
name: string;
|
||||
type: string;
|
||||
columns?: string[];
|
||||
reference_column?: { name: string; type: string };
|
||||
}> {
|
||||
if (!jobs || jobs.length === 0) return [];
|
||||
|
||||
const tables: Array<{
|
||||
name: string;
|
||||
type: string;
|
||||
columns?: string[];
|
||||
reference_column?: { name: string; type: string };
|
||||
}> = [];
|
||||
|
||||
for (const job of jobs) {
|
||||
const input = job.input;
|
||||
if (!input) continue;
|
||||
|
||||
if (connector === 'jdbc') {
|
||||
// JDBC: table_name, load_type, column_include_list, incremental_column_name
|
||||
const table: {
|
||||
name: string;
|
||||
type: string;
|
||||
columns?: string[];
|
||||
reference_column?: { name: string; type: string };
|
||||
} = {
|
||||
name: input.table_name || '',
|
||||
type: input.load_type || 'full_load',
|
||||
};
|
||||
if (input.column_include_list && input.column_include_list.length > 0) {
|
||||
table.columns = input.column_include_list;
|
||||
}
|
||||
if (input.incremental_column_name) {
|
||||
table.reference_column = {
|
||||
name: input.incremental_column_name,
|
||||
type: input.incremental_column_type || 'timestamp',
|
||||
};
|
||||
}
|
||||
tables.push(table);
|
||||
} else if (connector === 'singer' || connector === 's3') {
|
||||
// Singer/S3: replication_method -> type mapping, no columns
|
||||
let type = 'full_load';
|
||||
if (input.replication_method === 'INCREMENTAL') {
|
||||
type = 'incremental';
|
||||
} else if (input.replication_method === 'FULL_TABLE') {
|
||||
type = 'full_load';
|
||||
}
|
||||
|
||||
tables.push({
|
||||
name: input.table_name || '',
|
||||
type,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build properties object for Elasticsearch based on connector type.
|
||||
* Different connectors have different property structures.
|
||||
*
|
||||
* Note: In pi-factory flow, properties come pre-built from frontend.
|
||||
* In Maestro proxy flow, we reconstruct from job input fields.
|
||||
*/
|
||||
private buildPipelineProperties(jobInput: any): Record<string, any> {
|
||||
if (!jobInput) return {};
|
||||
|
||||
const connector = jobInput.connector;
|
||||
const properties: Record<string, any> = {};
|
||||
|
||||
// Determine credentials_type
|
||||
if (jobInput.auth_parameters?.credentials_type) {
|
||||
properties.credentials_type = jobInput.auth_parameters.credentials_type;
|
||||
} else {
|
||||
// Default based on connector type
|
||||
// S3 connector typically uses iam_user, others use basic_auth
|
||||
properties.credentials_type = connector === 's3' ? 'iam_user' : 'basic_auth';
|
||||
}
|
||||
|
||||
if (connector === 'jdbc') {
|
||||
// JDBC connectors: schema comes from table_schema
|
||||
if (jobInput.table_schema) {
|
||||
properties.schema = jobInput.table_schema;
|
||||
}
|
||||
} else if (connector === 'singer') {
|
||||
// Singer connectors: merge config fields (dates, selected_competitions, etc.)
|
||||
if (jobInput.config) {
|
||||
Object.assign(properties, jobInput.config);
|
||||
}
|
||||
} else if (connector === 's3') {
|
||||
// S3 connector
|
||||
if (jobInput.engine) properties.engine = jobInput.engine;
|
||||
if (jobInput.source_bucket) properties.source_bucket = jobInput.source_bucket;
|
||||
if (jobInput.source_prefix) properties.source_prefix = jobInput.source_prefix;
|
||||
if (jobInput.file_format_params) properties.file_format_params = jobInput.file_format_params;
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
// ==================== PIPELINE ROUTES ====================
|
||||
|
||||
@Post('pipeline')
|
||||
@ApiOperation({ summary: 'Create a new pipeline' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.CREATE)
|
||||
async createPipeline(@Body() body: any, @User() user: RequestUser) {
|
||||
// Validate that pipeline has jobs
|
||||
if (!body.jobs || body.jobs.length === 0) {
|
||||
throw new BadRequestException('Pipeline must have at least one job');
|
||||
}
|
||||
|
||||
// Validate connector before proceeding
|
||||
const firstJob = body.jobs[0]?.input;
|
||||
this.validateConnector(firstJob?.connector);
|
||||
|
||||
// Inject customer_id (actually customer_name) and normalized ID 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,
|
||||
id: this.normalizePipelineId(body.id),
|
||||
customer_id: user.customer_name,
|
||||
};
|
||||
|
||||
const result = await this.platformApiService.proxy('POST', '/pipeline', user, enrichedBody);
|
||||
|
||||
// Sync to Elasticsearch and DynamoDB
|
||||
try {
|
||||
const plugin = firstJob?.plugin;
|
||||
const connectorType = firstJob?.connector;
|
||||
const connectionId = firstJob?.auth_parameters?.config_id;
|
||||
|
||||
// Build properties based on connector type
|
||||
const properties = this.buildPipelineProperties(firstJob);
|
||||
|
||||
const connector = plugin
|
||||
? await this.elasticsearchService.getConnectorByPlugin(plugin)
|
||||
: null;
|
||||
|
||||
// Extract tables from jobs and create DynamoDB input
|
||||
const tables = this.extractTablesFromJobs(body.jobs, connectorType);
|
||||
let inputId: string | undefined;
|
||||
|
||||
if (tables.length > 0) {
|
||||
const inputDoc = await this.dynamoDBService.createInput(
|
||||
user.customer_id,
|
||||
user.user_id,
|
||||
{
|
||||
name: body.name,
|
||||
description: body.description,
|
||||
plugin: plugin || '',
|
||||
type: this.mapConnectorToDynamoType(connectorType),
|
||||
tables,
|
||||
},
|
||||
);
|
||||
inputId = inputDoc.id;
|
||||
this.logger.info('Created DynamoDB input for tables config', {
|
||||
inputId,
|
||||
pipelineId: body.id,
|
||||
tablesCount: tables.length,
|
||||
});
|
||||
}
|
||||
|
||||
this.logger.info('Syncing pipeline to Elasticsearch', {
|
||||
customerName: user.customer_name,
|
||||
pipelineId: body.id,
|
||||
plugin,
|
||||
connector: connectorType,
|
||||
properties,
|
||||
inputId,
|
||||
});
|
||||
|
||||
// Keep original UUID format for Elasticsearch (not normalized)
|
||||
await this.elasticsearchService.createPipeline(
|
||||
user.customer_name,
|
||||
body.id,
|
||||
{
|
||||
name: body.name,
|
||||
description: body.description,
|
||||
user_id: user.user_id,
|
||||
username: user.username,
|
||||
customer_id: user.customer_id,
|
||||
plugin,
|
||||
connection_id: connectionId,
|
||||
cron: body.cron,
|
||||
tables: inputId,
|
||||
properties,
|
||||
},
|
||||
connector,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to sync pipeline creation to Elasticsearch/DynamoDB', {
|
||||
pipelineId: body.id,
|
||||
customerName: user.customer_name,
|
||||
error: error.message,
|
||||
errorName: error.name,
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Get('pipelines')
|
||||
@ApiOperation({ summary: 'List all pipelines for customer' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
|
||||
async getPipelines(
|
||||
@User() user: RequestUser,
|
||||
@Query() query: Record<string, string>,
|
||||
) {
|
||||
return this.platformApiService.proxy(
|
||||
'GET',
|
||||
'/pipelines',
|
||||
user,
|
||||
undefined,
|
||||
query,
|
||||
);
|
||||
}
|
||||
|
||||
@Get('pipeline/:pipelineId')
|
||||
@ApiOperation({ summary: 'Get pipeline by ID' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
|
||||
async getPipeline(
|
||||
@Param('pipelineId') pipelineId: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
const normalizedId = this.normalizePipelineId(pipelineId);
|
||||
return this.platformApiService.proxy('GET', `/pipeline/${normalizedId}`, user);
|
||||
}
|
||||
|
||||
@Patch('pipeline/:pipelineId')
|
||||
@ApiOperation({ summary: 'Update pipeline by ID' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||
async updatePipeline(
|
||||
@Param('pipelineId') pipelineId: string,
|
||||
@Body() body: any,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
const normalizedId = this.normalizePipelineId(pipelineId);
|
||||
const result = await this.platformApiService.proxy(
|
||||
'PATCH',
|
||||
`/pipeline/${normalizedId}`,
|
||||
user,
|
||||
body,
|
||||
);
|
||||
|
||||
// Sync to Elasticsearch (use original UUID, not normalized)
|
||||
try {
|
||||
await this.elasticsearchService.updatePipeline(
|
||||
user.customer_name,
|
||||
pipelineId,
|
||||
{
|
||||
name: body.name,
|
||||
description: body.description,
|
||||
cron: body.cron,
|
||||
status: body.status,
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to sync pipeline update to Elasticsearch', {
|
||||
pipelineId,
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Delete('pipeline/:pipelineId')
|
||||
@ApiOperation({ summary: 'Delete pipeline by ID' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE)
|
||||
async deletePipeline(
|
||||
@Param('pipelineId') pipelineId: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
const normalizedId = this.normalizePipelineId(pipelineId);
|
||||
const result = await this.platformApiService.proxy(
|
||||
'DELETE',
|
||||
`/pipeline/${normalizedId}`,
|
||||
user,
|
||||
);
|
||||
|
||||
// Sync to Elasticsearch (use original UUID, not normalized)
|
||||
try {
|
||||
await this.elasticsearchService.deletePipeline(
|
||||
user.customer_name,
|
||||
pipelineId,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to sync pipeline deletion to Elasticsearch', {
|
||||
pipelineId,
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Post('pipeline/execute')
|
||||
@ApiOperation({ summary: 'Execute a pipeline' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||
async executePipeline(@Body() body: any, @User() user: RequestUser) {
|
||||
return this.platformApiService.proxy('POST', '/pipeline/execute', user, body);
|
||||
}
|
||||
|
||||
@Post('pipeline/pause')
|
||||
@ApiOperation({ summary: 'Pause a pipeline' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||
async pausePipeline(@Body() body: any, @User() user: RequestUser) {
|
||||
return this.platformApiService.proxy('POST', '/pipeline/pause', user, body);
|
||||
}
|
||||
|
||||
@Post('pipeline/unpause')
|
||||
@ApiOperation({ summary: 'Unpause a pipeline' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||
async unpausePipeline(@Body() body: any, @User() user: RequestUser) {
|
||||
return this.platformApiService.proxy('POST', '/pipeline/unpause', user, body);
|
||||
}
|
||||
|
||||
@Put('pipeline/:pipelineId/memory')
|
||||
@ApiOperation({ summary: 'Update pipeline memory configuration' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||
async updatePipelineMemory(
|
||||
@Param('pipelineId') pipelineId: string,
|
||||
@Body() body: any,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.platformApiService.proxy(
|
||||
'PUT',
|
||||
`/pipeline/${pipelineId}/memory`,
|
||||
user,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== PIPELINE METADATA ROUTES ====================
|
||||
|
||||
@Put('pipeline/:pipelineId/metadata')
|
||||
@ApiOperation({ summary: 'Update pipeline metadata' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||
async updatePipelineMetadata(
|
||||
@Param('pipelineId') pipelineId: string,
|
||||
@Body() body: any,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.platformApiService.proxy(
|
||||
'PUT',
|
||||
`/pipeline/${pipelineId}/metadata`,
|
||||
user,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
@Get('pipelines/metadata')
|
||||
@ApiOperation({ summary: 'Get all pipelines metadata' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
|
||||
async getPipelinesMetadata(
|
||||
@User() user: RequestUser,
|
||||
@Query() query: Record<string, string>,
|
||||
) {
|
||||
return this.platformApiService.proxy(
|
||||
'GET',
|
||||
'/pipelines/metadata',
|
||||
user,
|
||||
undefined,
|
||||
query,
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== 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')
|
||||
@ApiOperation({ summary: 'Get pipeline runs for a pipeline' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
|
||||
async getPipelineRuns(
|
||||
@Param('pipelineId') pipelineId: string,
|
||||
@User() user: RequestUser,
|
||||
@Query() query: Record<string, string>,
|
||||
) {
|
||||
return this.platformApiService.proxy(
|
||||
'GET',
|
||||
`/pipeline/${pipelineId}/pipeline_run`,
|
||||
user,
|
||||
undefined,
|
||||
query,
|
||||
);
|
||||
}
|
||||
|
||||
@Get('pipeline/:pipelineId/pipeline_run/:runId')
|
||||
@ApiOperation({ summary: 'Get specific pipeline run' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
|
||||
async getPipelineRun(
|
||||
@Param('pipelineId') pipelineId: string,
|
||||
@Param('runId') runId: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.platformApiService.proxy(
|
||||
'GET',
|
||||
`/pipeline/${pipelineId}/pipeline_run/${runId}`,
|
||||
user,
|
||||
);
|
||||
}
|
||||
|
||||
@Get('pipeline/pipeline_run/:runId/logs')
|
||||
@ApiOperation({ summary: 'Get pipeline run logs' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
|
||||
async getPipelineRunLogs(
|
||||
@Param('runId') runId: string,
|
||||
@User() user: RequestUser,
|
||||
@Query() query: Record<string, string>,
|
||||
) {
|
||||
return this.platformApiService.proxy(
|
||||
'GET',
|
||||
`/pipeline/pipeline_run/${runId}/logs`,
|
||||
user,
|
||||
undefined,
|
||||
query,
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== JOBS - COLUMN EDITING ROUTES ====================
|
||||
|
||||
@Put('jobs/:jobId/input')
|
||||
@ApiOperation({ summary: 'Update job input columns' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||
async updateJobInput(
|
||||
@Param('jobId') jobId: string,
|
||||
@Body() body: any,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.platformApiService.proxy(
|
||||
'PUT',
|
||||
`/jobs/${jobId}/input`,
|
||||
user,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
@Patch('jobs/:jobId/input')
|
||||
@ApiOperation({ summary: 'Partial update job input columns' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||
async patchJobInput(
|
||||
@Param('jobId') jobId: string,
|
||||
@Body() body: any,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.platformApiService.proxy(
|
||||
'PATCH',
|
||||
`/jobs/${jobId}/input`,
|
||||
user,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
@Put('jobs/:jobId/memory')
|
||||
@ApiOperation({ summary: 'Update job memory configuration' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||
async updateJobMemory(
|
||||
@Param('jobId') jobId: string,
|
||||
@Body() body: any,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.platformApiService.proxy(
|
||||
'PUT',
|
||||
`/jobs/${jobId}/memory`,
|
||||
user,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
@Post('jobs/:jobId/reset-state')
|
||||
@ApiOperation({ summary: 'Reset job state' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||
async resetJobState(
|
||||
@Param('jobId') jobId: string,
|
||||
@Body() body: any,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.platformApiService.proxy(
|
||||
'POST',
|
||||
`/jobs/${jobId}/reset-state`,
|
||||
user,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== JOBS - JDBC SYNC MODE ROUTES ====================
|
||||
|
||||
@Get('jobs/jdbc/:jobId')
|
||||
@ApiOperation({ summary: 'Get JDBC job details' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
|
||||
async getJdbcJob(@Param('jobId') jobId: string, @User() user: RequestUser) {
|
||||
return this.platformApiService.proxy('GET', `/jobs/jdbc/${jobId}`, user);
|
||||
}
|
||||
|
||||
@Put('jobs/jdbc/:jobId/sync-mode')
|
||||
@ApiOperation({ summary: 'Update JDBC job sync mode' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||
async updateJdbcSyncMode(
|
||||
@Param('jobId') jobId: string,
|
||||
@Body() body: any,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.platformApiService.proxy(
|
||||
'PUT',
|
||||
`/jobs/jdbc/${jobId}/sync-mode`,
|
||||
user,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
@Get('jobs/jdbc/configs/allowed_datatypes')
|
||||
@ApiOperation({ summary: 'Get allowed datatypes for JDBC' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
|
||||
async getJdbcAllowedDatatypes(@User() user: RequestUser) {
|
||||
return this.platformApiService.proxy(
|
||||
'GET',
|
||||
'/jobs/jdbc/configs/allowed_datatypes',
|
||||
user,
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== JOBS - SINGER REPLICATION ROUTES ====================
|
||||
|
||||
@Get('jobs/singer/:jobId')
|
||||
@ApiOperation({ summary: 'Get Singer job details' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
|
||||
async getSingerJob(@Param('jobId') jobId: string, @User() user: RequestUser) {
|
||||
return this.platformApiService.proxy('GET', `/jobs/singer/${jobId}`, user);
|
||||
}
|
||||
|
||||
@Put('jobs/singer/:jobId/sync-mode')
|
||||
@ApiOperation({ summary: 'Update Singer job sync mode' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE)
|
||||
async updateSingerSyncMode(
|
||||
@Param('jobId') jobId: string,
|
||||
@Body() body: any,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.platformApiService.proxy(
|
||||
'PUT',
|
||||
`/jobs/singer/${jobId}/sync-mode`,
|
||||
user,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== JOBS - S3 ROUTES ====================
|
||||
|
||||
@Get('jobs/s3/:jobId')
|
||||
@ApiOperation({ summary: 'Get S3 job details' })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.GET)
|
||||
async getS3Job(@Param('jobId') jobId: string, @User() user: RequestUser) {
|
||||
return this.platformApiService.proxy('GET', `/jobs/s3/${jobId}`, user);
|
||||
}
|
||||
|
||||
// ==================== HEALTH ROUTE ====================
|
||||
|
||||
@Get('health')
|
||||
@ApiOperation({ summary: 'Platform API health check' })
|
||||
@Authenticated()
|
||||
async healthCheck(@User() user: RequestUser) {
|
||||
return this.platformApiService.proxy('GET', '/health', user);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user