[resumes][feat] Add API to submit & query for resume reviews (#313)

* [resumes][feat] Add route to submit resume reviews

* [resumes][feat] Add router to query for comments

* [resumes][refactor] Change limit of upvotes query

* [resumes][chore] revert changes

* [resumes][chore] remove comment

* [resumes][chore] Use ResumesSection enum instead of hard-coded string

* [resumes][refactor] Add check for user session in comments

* [resumes][fix] fix linting issues

Co-authored-by: Terence Ho <>
This commit is contained in:
Terence
2022-10-07 14:19:37 +08:00
committed by GitHub
parent 641a565e5c
commit 0933cce7b5
9 changed files with 209 additions and 25 deletions

View File

@ -3,6 +3,8 @@ import superjson from 'superjson';
import { createRouter } from './context';
import { protectedExampleRouter } from './protected-example-router';
import { resumesResumeUserRouter } from './resumes-resume-user-router';
import { resumeReviewsRouter } from './resumes-reviews-router';
import { resumesReviewsUserRouter } from './resumes-reviews-user-router';
import { todosRouter } from './todos';
import { todosUserRouter } from './todos-user-router';
@ -14,7 +16,9 @@ export const appRouter = createRouter()
.merge('auth.', protectedExampleRouter)
.merge('todos.', todosRouter)
.merge('todos.user.', todosUserRouter)
.merge('resumes.resume.user.', resumesResumeUserRouter);
.merge('resumes.resume.user.', resumesResumeUserRouter)
.merge('resumes.reviews.', resumeReviewsRouter)
.merge('resumes.reviews.user.', resumesReviewsUserRouter);
// Export type definition of API
export type AppRouter = typeof appRouter;

View File

@ -0,0 +1,44 @@
import { z } from 'zod';
import { createRouter } from './context';
export const resumeReviewsRouter = createRouter().query('list', {
input: z.object({
resumeId: z.string(),
}),
async resolve({ ctx, input }) {
const userId = ctx.session?.user?.id;
const { resumeId } = input;
// For this resume, we retrieve every comment's information, along with:
// The user's name and image to render
// Number of votes, and whether the user (if-any) has voted
return await ctx.prisma.resumesComment.findMany({
include: {
_count: {
select: {
votes: true,
},
},
user: {
select: {
image: true,
name: true,
},
},
votes: {
take: 1,
where: {
userId,
},
},
},
orderBy: {
createdAt: 'desc',
},
where: {
resumeId,
},
});
},
});

View File

@ -0,0 +1,54 @@
import { z } from 'zod';
import { ResumesSection } from '@prisma/client';
import { createProtectedRouter } from './context';
type IResumeCommentInput = Readonly<{
description: string;
resumeId: string;
section: ResumesSection;
userId: string;
}>;
export const resumesReviewsUserRouter = createProtectedRouter().mutation(
'create',
{
input: z.object({
education: z.string(),
experience: z.string(),
general: z.string(),
projects: z.string(),
resumeId: z.string(),
skills: z.string(),
}),
async resolve({ ctx, input }) {
const userId = ctx.session?.user.id;
const { resumeId, education, experience, general, projects, skills } =
input;
// For each section, convert them into ResumesComment model if provided
const comments: Array<IResumeCommentInput> = [
{ description: education, section: ResumesSection.EDUCATION },
{ description: experience, section: ResumesSection.EXPERIENCE },
{ description: general, section: ResumesSection.GENERAL },
{ description: projects, section: ResumesSection.PROJECTS },
{ description: skills, section: ResumesSection.SKILLS },
]
.filter(({ description }) => {
return description.trim().length > 0;
})
.map(({ description, section }) => {
return {
description,
resumeId,
section,
userId,
};
});
return await ctx.prisma.resumesComment.createMany({
data: comments,
});
},
},
);