| import { z } from "zod"; |
| import { eq, and, avg } from "drizzle-orm"; |
| import { router, protectedProcedure, publicProcedure } from "../index"; |
| import { db } from "@pram/db"; |
| import { questionRating, question, packageRating, testPackage } from "@pram/db"; |
| import { checkRateLimit } from "../lib/rate-limit"; |
|
|
| export const ratingRouter = router({ |
| getQuestionRating: publicProcedure |
| .input(z.object({ questionId: z.string().uuid() })) |
| .query(async ({ ctx, input }) => { |
| const userId = ctx.session?.user.id; |
|
|
| const [avgResult] = await db |
| .select({ avgScore: avg(questionRating.score) }) |
| .from(questionRating) |
| .where(eq(questionRating.questionId, input.questionId)); |
|
|
| const avgRating = avgResult?.avgScore ? Math.round(Number(avgResult.avgScore)) : null; |
|
|
| let myRating: number | null = null; |
| if (userId) { |
| const [row] = await db |
| .select({ score: questionRating.score }) |
| .from(questionRating) |
| .where( |
| and( |
| eq(questionRating.questionId, input.questionId), |
| eq(questionRating.userId, userId), |
| ), |
| ) |
| .limit(1); |
| myRating = row?.score ?? null; |
| } |
|
|
| return { avgRating, myRating }; |
| }), |
|
|
| rateQuestion: protectedProcedure |
| .input( |
| z.object({ |
| questionId: z.string().uuid(), |
| score: z.number().min(1).max(5), |
| }), |
| ) |
| .mutation(async ({ ctx, input }) => { |
| await checkRateLimit({ key: `rate:${ctx.session.user.id}`, limit: 10, windowMs: 10_000 }); |
|
|
| const existing = await db |
| .select() |
| .from(questionRating) |
| .where( |
| and( |
| eq(questionRating.questionId, input.questionId), |
| eq(questionRating.userId, ctx.session.user.id), |
| ), |
| ) |
| .limit(1); |
|
|
| const existingRating = existing[0]; |
| if (existingRating) { |
| await db |
| .update(questionRating) |
| .set({ score: input.score }) |
| .where(eq(questionRating.id, existingRating.id)); |
| } else { |
| await db.insert(questionRating).values({ |
| userId: ctx.session.user.id, |
| questionId: input.questionId, |
| score: input.score, |
| }); |
| } |
|
|
| const [avgResult] = await db |
| .select({ avgScore: avg(questionRating.score) }) |
| .from(questionRating) |
| .where(eq(questionRating.questionId, input.questionId)); |
|
|
| await db |
| .update(question) |
| .set({ avgRating: avgResult?.avgScore ? Math.round(Number(avgResult.avgScore)) : null }) |
| .where(eq(question.id, input.questionId)); |
|
|
| return { success: true }; |
| }), |
|
|
| getPackageRating: publicProcedure |
| .input(z.object({ packageId: z.string().uuid() })) |
| .query(async ({ ctx, input }) => { |
| const userId = ctx.session?.user.id; |
|
|
| const [avgResult] = await db |
| .select({ avgScore: avg(packageRating.score) }) |
| .from(packageRating) |
| .where(eq(packageRating.packageId, input.packageId)); |
|
|
| const avgRating = avgResult?.avgScore ? Math.round(Number(avgResult.avgScore)) : null; |
|
|
| let myRating: number | null = null; |
| if (userId) { |
| const [row] = await db |
| .select({ score: packageRating.score }) |
| .from(packageRating) |
| .where( |
| and( |
| eq(packageRating.packageId, input.packageId), |
| eq(packageRating.userId, userId), |
| ), |
| ) |
| .limit(1); |
| myRating = row?.score ?? null; |
| } |
|
|
| return { avgRating, myRating }; |
| }), |
|
|
| ratePackage: protectedProcedure |
| .input( |
| z.object({ |
| packageId: z.string().uuid(), |
| score: z.number().min(1).max(5), |
| }), |
| ) |
| .mutation(async ({ ctx, input }) => { |
| await checkRateLimit({ key: `rate:${ctx.session.user.id}`, limit: 10, windowMs: 10_000 }); |
|
|
| const existing = await db |
| .select() |
| .from(packageRating) |
| .where( |
| and( |
| eq(packageRating.packageId, input.packageId), |
| eq(packageRating.userId, ctx.session.user.id), |
| ), |
| ) |
| .limit(1); |
|
|
| const existingRating = existing[0]; |
| if (existingRating) { |
| await db |
| .update(packageRating) |
| .set({ score: input.score }) |
| .where(eq(packageRating.id, existingRating.id)); |
| } else { |
| await db.insert(packageRating).values({ |
| userId: ctx.session.user.id, |
| packageId: input.packageId, |
| score: input.score, |
| }); |
| } |
|
|
| const [avgResult] = await db |
| .select({ avgScore: avg(packageRating.score) }) |
| .from(packageRating) |
| .where(eq(packageRating.packageId, input.packageId)); |
|
|
| await db |
| .update(testPackage) |
| .set({ avgRating: avgResult?.avgScore ? Math.round(Number(avgResult.avgScore)) : null }) |
| .where(eq(testPackage.id, input.packageId)); |
|
|
| return { success: true }; |
| }), |
| }); |
|
|