because I got bored of customising my CV for every job
at main 86 lines 2.7 kB view raw
1import type { User } from "@cv/auth"; 2import { PrismaService } from "@cv/system"; 3import { Injectable } from "@nestjs/common"; 4import { EventEmitter2 } from "@nestjs/event-emitter"; 5import type { DataImportSource } from "./data-import-source.interface"; 6import { UserFileCreatedEvent } from "./events/user-file-created.event"; 7import { UserFile } from "./user-file.entity"; 8import { UserFileMapper } from "./user-file.mapper"; 9 10@Injectable() 11export class ImportService { 12 constructor( 13 private readonly prisma: PrismaService, 14 private readonly userFileMapper: UserFileMapper, 15 private readonly eventEmitter: EventEmitter2, 16 ) {} 17 18 /** 19 * Find an existing completed UserFile with the same fingerprint for this user. 20 */ 21 async findDuplicateForUser( 22 userId: string, 23 fingerprint: string, 24 ): Promise<UserFile | null> { 25 const record = await this.prisma.userFile.findFirst({ 26 where: { 27 fingerprint, 28 profile: { userId }, 29 status: "completed", 30 }, 31 orderBy: { createdAt: "desc" }, 32 }); 33 return this.userFileMapper.toDomain(record); 34 } 35 36 /** 37 * Create a UserFile and emit an event for async processing. 38 */ 39 async createImport( 40 user: User, 41 profileId: string, 42 source: DataImportSource, 43 file: { fileName: string; mimeType: string; sizeBytes: number; fingerprint?: string }, 44 params: Record<string, unknown>, 45 ): Promise<UserFile> { 46 const record = await this.prisma.userFile.create({ 47 data: { 48 profile: { connect: { id: profileId } }, 49 fingerprint: file.fingerprint ?? null, 50 fileName: file.fileName, 51 mimeType: file.mimeType, 52 sizeBytes: file.sizeBytes, 53 source: source.name, 54 status: "pending", 55 statusMessage: "Queued for processing", 56 }, 57 }); 58 59 this.eventEmitter.emit( 60 UserFileCreatedEvent.event, 61 new UserFileCreatedEvent(record.id, user, source, params), 62 ); 63 64 return this.userFileMapper.toDomain(record) as UserFile; 65 } 66 67 /** 68 * Delete a UserFile and its cascading ImportJobs. 69 */ 70 async deleteUserFile(id: string): Promise<void> { 71 await this.prisma.userFile.delete({ where: { id } }); 72 } 73 74 async findUserFileById(id: string): Promise<UserFile | null> { 75 const record = await this.prisma.userFile.findUnique({ where: { id } }); 76 return this.userFileMapper.toDomain(record); 77 } 78 79 async findUserFilesForUser(userId: string): Promise<UserFile[]> { 80 const records = await this.prisma.userFile.findMany({ 81 where: { profile: { userId } }, 82 orderBy: { createdAt: "desc" }, 83 }); 84 return this.userFileMapper.mapToDomain(records); 85 } 86}