mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-26 22:44:35 +10:00
feat(resume): ✨ implement resume locking feature
This commit is contained in:
@@ -16,16 +16,8 @@ import {
|
||||
import { ApiTags } from "@nestjs/swagger";
|
||||
import { User as UserEntity } from "@prisma/client";
|
||||
import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library";
|
||||
import {
|
||||
CreateResumeDto,
|
||||
ImportResumeDto,
|
||||
ResumeDto,
|
||||
StatisticsDto,
|
||||
UpdateResumeDto,
|
||||
UrlDto,
|
||||
} from "@reactive-resume/dto";
|
||||
import { CreateResumeDto, ImportResumeDto, ResumeDto, UpdateResumeDto } from "@reactive-resume/dto";
|
||||
import { resumeDataSchema } from "@reactive-resume/schema";
|
||||
import { ZodSerializerDto } from "nestjs-zod";
|
||||
import { zodToJsonSchema } from "zod-to-json-schema";
|
||||
|
||||
import { User } from "@/server/user/decorators/user.decorator";
|
||||
@@ -91,7 +83,6 @@ export class ResumeController {
|
||||
|
||||
@Get(":id/statistics")
|
||||
@UseGuards(TwoFactorGuard)
|
||||
@ZodSerializerDto(StatisticsDto)
|
||||
findOneStatistics(@User("id") userId: string, @Param("id") id: string) {
|
||||
return this.resumeService.findOneStatistics(userId, id);
|
||||
}
|
||||
@@ -111,15 +102,20 @@ export class ResumeController {
|
||||
return this.resumeService.update(user.id, id, updateResumeDto);
|
||||
}
|
||||
|
||||
@Patch(":id/lock")
|
||||
@UseGuards(TwoFactorGuard)
|
||||
lock(@User() user: UserEntity, @Param("id") id: string, @Body("set") set: boolean = true) {
|
||||
return this.resumeService.lock(user.id, id, set);
|
||||
}
|
||||
|
||||
@Delete(":id")
|
||||
@UseGuards(TwoFactorGuard)
|
||||
remove(@User() user: UserEntity, @Param("id") id: string) {
|
||||
return this.resumeService.remove(user.id, id);
|
||||
async remove(@User() user: UserEntity, @Param("id") id: string) {
|
||||
await this.resumeService.remove(user.id, id);
|
||||
}
|
||||
|
||||
@Get("/print/:id")
|
||||
@UseGuards(OptionalGuard, ResumeGuard)
|
||||
@ZodSerializerDto(UrlDto)
|
||||
async printResume(@Resume() resume: ResumeDto) {
|
||||
try {
|
||||
const url = await this.resumeService.printResume(resume);
|
||||
@@ -133,7 +129,6 @@ export class ResumeController {
|
||||
|
||||
@Get("/print/:id/preview")
|
||||
@UseGuards(TwoFactorGuard, ResumeGuard)
|
||||
@ZodSerializerDto(UrlDto)
|
||||
async printPreview(@Resume() resume: ResumeDto) {
|
||||
try {
|
||||
const url = await this.resumeService.printPreview(resume);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CACHE_MANAGER } from "@nestjs/cache-manager";
|
||||
import { Inject, Injectable, Logger } from "@nestjs/common";
|
||||
import { BadRequestException, Inject, Injectable, Logger } from "@nestjs/common";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { CreateResumeDto, ImportResumeDto, ResumeDto, UpdateResumeDto } from "@reactive-resume/dto";
|
||||
import { defaultResumeData, ResumeData } from "@reactive-resume/schema";
|
||||
@@ -13,6 +13,7 @@ import { PrismaService } from "nestjs-prisma";
|
||||
|
||||
import { PrinterService } from "@/server/printer/printer.service";
|
||||
|
||||
import { ErrorMessage } from "../constants/error-message";
|
||||
import { StorageService } from "../storage/storage.service";
|
||||
import { UtilsService } from "../utils/utils.service";
|
||||
|
||||
@@ -129,22 +130,44 @@ export class ResumeService {
|
||||
}
|
||||
|
||||
async update(userId: string, id: string, updateResumeDto: UpdateResumeDto) {
|
||||
await Promise.all([
|
||||
this.cache.set(`user:${userId}:resume:${id}`, updateResumeDto),
|
||||
this.cache.del(`user:${userId}:resumes`),
|
||||
this.cache.del(`user:${userId}:storage:resumes:${id}`),
|
||||
this.cache.del(`user:${userId}:storage:previews:${id}`),
|
||||
]);
|
||||
try {
|
||||
const resume = await this.prisma.resume.update({
|
||||
data: {
|
||||
title: updateResumeDto.title,
|
||||
slug: updateResumeDto.slug,
|
||||
visibility: updateResumeDto.visibility,
|
||||
data: updateResumeDto.data as unknown as Prisma.JsonObject,
|
||||
},
|
||||
where: { userId_id: { userId, id }, locked: false },
|
||||
});
|
||||
|
||||
return this.prisma.resume.update({
|
||||
data: {
|
||||
title: updateResumeDto.title,
|
||||
slug: updateResumeDto.slug,
|
||||
visibility: updateResumeDto.visibility,
|
||||
data: updateResumeDto.data as unknown as Prisma.JsonObject,
|
||||
},
|
||||
await Promise.all([
|
||||
this.cache.set(`user:${userId}:resume:${id}`, resume),
|
||||
this.cache.del(`user:${userId}:resumes`),
|
||||
this.cache.del(`user:${userId}:storage:resumes:${id}`),
|
||||
this.cache.del(`user:${userId}:storage:previews:${id}`),
|
||||
]);
|
||||
|
||||
return resume;
|
||||
} catch (error) {
|
||||
if (error.code === "P2025") {
|
||||
throw new BadRequestException(ErrorMessage.ResumeLocked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async lock(userId: string, id: string, set: boolean) {
|
||||
const resume = await this.prisma.resume.update({
|
||||
data: { locked: set },
|
||||
where: { userId_id: { userId, id } },
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
this.cache.set(`user:${userId}:resume:${id}`, resume),
|
||||
this.cache.del(`user:${userId}:resumes`),
|
||||
]);
|
||||
|
||||
return resume;
|
||||
}
|
||||
|
||||
async remove(userId: string, id: string) {
|
||||
@@ -156,9 +179,10 @@ export class ResumeService {
|
||||
// Remove files in storage, and their cached keys
|
||||
this.storageService.deleteObject(userId, "resumes", id),
|
||||
this.storageService.deleteObject(userId, "previews", id),
|
||||
]);
|
||||
|
||||
return this.prisma.resume.delete({ where: { userId_id: { userId, id } } });
|
||||
// Remove resume from database
|
||||
this.prisma.resume.delete({ where: { userId_id: { userId, id } } }),
|
||||
]);
|
||||
}
|
||||
|
||||
async printResume(resume: ResumeDto) {
|
||||
|
||||
Reference in New Issue
Block a user