174 lines
5.0 KiB
TypeScript
174 lines
5.0 KiB
TypeScript
import {
|
|
Controller,
|
|
Post,
|
|
Body,
|
|
Headers,
|
|
UseGuards,
|
|
Get,
|
|
Param,
|
|
Query,
|
|
Res,
|
|
ParseIntPipe,
|
|
} from '@nestjs/common';
|
|
import { MigrationService } from './migration.service';
|
|
import { ImportCorrespondenceDto } from './dto/import-correspondence.dto';
|
|
import { EnqueueMigrationDto } from './dto/enqueue-migration.dto';
|
|
import { CommitBatchDto } from './dto/commit-batch.dto';
|
|
import { CreateMigrationErrorDto } from './dto/create-migration-error.dto';
|
|
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
|
|
import { CurrentUser } from '../../common/decorators/current-user.decorator';
|
|
import {
|
|
ApiTags,
|
|
ApiOperation,
|
|
ApiBearerAuth,
|
|
ApiHeader,
|
|
ApiQuery,
|
|
ApiParam,
|
|
} from '@nestjs/swagger';
|
|
import { MigrationQueueQueryDto } from './dto/migration-queue-query.dto';
|
|
import type { Response } from 'express';
|
|
|
|
@ApiTags('Migration')
|
|
@ApiBearerAuth()
|
|
@Controller('migration')
|
|
export class MigrationController {
|
|
constructor(private readonly migrationService: MigrationService) {}
|
|
|
|
@Post('import')
|
|
@UseGuards(JwtAuthGuard)
|
|
@ApiOperation({
|
|
summary: 'Import generic legacy correspondence record via n8n integration',
|
|
})
|
|
@ApiHeader({
|
|
name: 'Idempotency-Key',
|
|
description:
|
|
'Unique key per document and batch to prevent duplicate inserts',
|
|
required: true,
|
|
})
|
|
async importCorrespondence(
|
|
@Body() dto: ImportCorrespondenceDto,
|
|
@Headers('idempotency-key') idempotencyKey: string,
|
|
@CurrentUser() user: any
|
|
) {
|
|
const userId = user?.id || user?.userId || 5;
|
|
return this.migrationService.importCorrespondence(
|
|
dto,
|
|
idempotencyKey,
|
|
userId
|
|
);
|
|
}
|
|
|
|
@Post('commit_batch')
|
|
@UseGuards(JwtAuthGuard)
|
|
@ApiOperation({
|
|
summary: 'Batch approve and import migration review queue items',
|
|
})
|
|
@ApiHeader({
|
|
name: 'Idempotency-Key',
|
|
description:
|
|
'Unique key for the entire batch to prevent duplicate execution',
|
|
required: true,
|
|
})
|
|
async commitBatch(
|
|
@Body() dto: CommitBatchDto,
|
|
@Headers('idempotency-key') idempotencyKey: string,
|
|
@CurrentUser() user: any
|
|
) {
|
|
const userId = user?.id || user?.userId || 5;
|
|
return this.migrationService.commitBatch(dto, idempotencyKey, userId);
|
|
}
|
|
|
|
@Post('queue')
|
|
@UseGuards(JwtAuthGuard)
|
|
@ApiOperation({
|
|
summary: 'Enqueue a record into the staging migration review queue',
|
|
})
|
|
async enqueueRecord(@Body() dto: EnqueueMigrationDto) {
|
|
return this.migrationService.enqueueRecord(dto);
|
|
}
|
|
|
|
@Get('queue')
|
|
@UseGuards(JwtAuthGuard)
|
|
@ApiOperation({ summary: 'Get migration review queue' })
|
|
async getReviewQueue(@Query() query: MigrationQueueQueryDto) {
|
|
return this.migrationService.getReviewQueue(query);
|
|
}
|
|
|
|
@Get('queue/:id')
|
|
@UseGuards(JwtAuthGuard)
|
|
@ApiOperation({ summary: 'Get a specific queue item by ID' })
|
|
@ApiParam({ name: 'id', type: Number })
|
|
async getQueueItemById(@Param('id', ParseIntPipe) id: number) {
|
|
return this.migrationService.getQueueItemById(id);
|
|
}
|
|
|
|
@Post('errors')
|
|
@UseGuards(JwtAuthGuard)
|
|
@ApiOperation({ summary: 'Log a migration error from n8n workflow' })
|
|
async createError(@Body() dto: CreateMigrationErrorDto) {
|
|
return this.migrationService.createError(dto);
|
|
}
|
|
|
|
@Get('errors')
|
|
@UseGuards(JwtAuthGuard)
|
|
@ApiOperation({ summary: 'Get migration errors' })
|
|
@ApiQuery({ name: 'page', required: false, type: Number })
|
|
@ApiQuery({ name: 'limit', required: false, type: Number })
|
|
async getErrors(
|
|
@Query('page') page?: number,
|
|
@Query('limit') limit?: number
|
|
) {
|
|
return this.migrationService.getErrors(page, limit);
|
|
}
|
|
|
|
@Post('queue/:id/approve')
|
|
@UseGuards(JwtAuthGuard)
|
|
@ApiOperation({ summary: 'Approve and import a queued migration item' })
|
|
@ApiParam({ name: 'id', type: Number })
|
|
@ApiHeader({
|
|
name: 'Idempotency-Key',
|
|
description:
|
|
'Unique key per document and batch to prevent duplicate inserts',
|
|
required: true,
|
|
})
|
|
async approveQueueItem(
|
|
@Param('id', ParseIntPipe) id: number,
|
|
@Body() dto: ImportCorrespondenceDto,
|
|
@Headers('idempotency-key') idempotencyKey: string,
|
|
@CurrentUser() user: any
|
|
) {
|
|
const userId = user?.id || user?.userId || 5;
|
|
return this.migrationService.approveQueueItem(
|
|
id,
|
|
dto,
|
|
idempotencyKey,
|
|
userId
|
|
);
|
|
}
|
|
|
|
@Post('queue/:id/reject')
|
|
@UseGuards(JwtAuthGuard)
|
|
@ApiOperation({ summary: 'Reject a queued migration item' })
|
|
@ApiParam({ name: 'id', type: Number })
|
|
async rejectQueueItem(
|
|
@Param('id', ParseIntPipe) id: number,
|
|
@CurrentUser() user: any
|
|
) {
|
|
const userId = user?.id || user?.userId || 5;
|
|
return this.migrationService.rejectQueueItem(id, userId);
|
|
}
|
|
|
|
@Get('staging-file')
|
|
@UseGuards(JwtAuthGuard)
|
|
@ApiOperation({ summary: 'Stream a file from staging' })
|
|
@ApiQuery({ name: 'path', required: true, type: String })
|
|
async getStagingFile(@Query('path') filePath: string, @Res() res: Response) {
|
|
const stream = this.migrationService.getStagingFileStream(filePath);
|
|
res.set({
|
|
'Content-Type': 'application/pdf',
|
|
'Content-Disposition': 'inline; filename="document.pdf"',
|
|
});
|
|
stream.pipe(res);
|
|
}
|
|
}
|