feat: verify-files
All checks were successful
Deploy API Server / build (push) Successful in 36s
Deploy API Server / deploy (push) Successful in 58s

This commit is contained in:
wangdl 2026-07-04 12:18:30 +08:00
parent 9d35c14bc2
commit c97b58fc5f

View File

@ -1,6 +1,7 @@
import { Controller, Get, Param, Delete, Query, UseGuards } from '@nestjs/common'; import { Controller, Get, Param, Delete, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
import { PrismaService } from '../../infrastructure/database/prisma.service'; import { PrismaService } from '../../infrastructure/database/prisma.service';
import { StorageService } from '../../infrastructure/storage/storage.service';
import { enrichWithNames } from '../../common/helpers/name-resolver'; import { enrichWithNames } from '../../common/helpers/name-resolver';
import { AdminAuthGuard } from '../../common/guards/admin-auth.guard'; import { AdminAuthGuard } from '../../common/guards/admin-auth.guard';
import { AdminRolesGuard } from '../../common/guards/admin-roles.guard'; import { AdminRolesGuard } from '../../common/guards/admin-roles.guard';
@ -10,7 +11,10 @@ import { AdminRolesGuard } from '../../common/guards/admin-roles.guard';
@UseGuards(AdminAuthGuard, AdminRolesGuard) @UseGuards(AdminAuthGuard, AdminRolesGuard)
@ApiBearerAuth() @ApiBearerAuth()
export class AdminKnowledgeController { export class AdminKnowledgeController {
constructor(private readonly prisma: PrismaService) {} constructor(
private readonly prisma: PrismaService,
private readonly storage: StorageService,
) {}
@Get() @Get()
@ApiOperation({ summary: '知识库列表(管理员,支持搜索)' }) @ApiOperation({ summary: '知识库列表(管理员,支持搜索)' })
@ -108,6 +112,31 @@ export class AdminKnowledgeController {
}); });
} }
// ── File verification ──
@Get('verify-files')
@ApiOperation({ summary: '校验所有 source 文件是否存在' })
async verifyFiles() {
const sources = await this.prisma.knowledgeSource.findMany({
where: { deletedAt: null, originalObjectKey: { not: null } },
select: { id: true, originalObjectKey: true, originalFilename: true },
});
const results = await Promise.all(
sources.map(async (s) => {
try {
const info = await this.storage.verifyUpload(s.originalObjectKey!);
return { sourceId: s.id, filename: s.originalFilename, objectKey: s.originalObjectKey, exists: !!info };
} catch {
return { sourceId: s.id, filename: s.originalFilename, objectKey: s.originalObjectKey, exists: false };
}
}),
);
const missing = results.filter(r => !r.exists);
return { total: results.length, missing: missing.length, missingFiles: missing };
}
// ── Candidates ── // ── Candidates ──
@Get('candidates') @Get('candidates')