Download packages/api/src/routers/feedback.ts from Atmint/cpns: direct link, hf CLI and curl.
- Browser
- Download file 3.16 kB
-
https://huggingface.co/spaces/Atmint/cpns/resolve/main/packages/api/src/routers/feedback.ts
- Command line
-
hf download hf://spaces/Atmint/cpns/packages/api/src/routers/feedback.ts
-
curl -L -o feedback.ts https://huggingface.co/spaces/Atmint/cpns/resolve/main/packages/api/src/routers/feedback.ts
3.16 kB
| import { z } from "zod"; | |
| import { eq, and, sql } from "drizzle-orm"; | |
| import { router, protectedProcedure, publicProcedure } from "../index"; | |
| import { db } from "@pram/db"; | |
| import { questionFeedback } from "@pram/db"; | |
| import { checkRateLimit } from "../lib/rate-limit"; | |
| export const feedbackRouter = router({ | |
| getQuestionFeedback: publicProcedure | |
| .input(z.object({ questionId: z.string().uuid() })) | |
| .query(async ({ ctx, input }) => { | |
| const userId = ctx.session?.user.id; | |
| const [counts] = await db | |
| .select({ | |
| up: sql<number>`count(case when ${questionFeedback.type} = 'up' then 1 end)::int`, | |
| down: sql<number>`count(case when ${questionFeedback.type} = 'down' then 1 end)::int`, | |
| }) | |
| .from(questionFeedback) | |
| .where(eq(questionFeedback.questionId, input.questionId)); | |
| let myFeedback: "up" | "down" | null = null; | |
| if (userId) { | |
| const [row] = await db | |
| .select({ type: questionFeedback.type }) | |
| .from(questionFeedback) | |
| .where( | |
| and( | |
| eq(questionFeedback.questionId, input.questionId), | |
| eq(questionFeedback.userId, userId), | |
| ), | |
| ) | |
| .limit(1); | |
| myFeedback = (row?.type as "up" | "down") ?? null; | |
| } | |
| return { up: counts?.up ?? 0, down: counts?.down ?? 0, myFeedback }; | |
| }), | |
| voteQuestion: protectedProcedure | |
| .input( | |
| z.object({ | |
| questionId: z.string().uuid(), | |
| type: z.enum(["up", "down"]), | |
| note: z.string().optional(), | |
| }), | |
| ) | |
| .mutation(async ({ ctx, input }) => { | |
| await checkRateLimit({ key: `vote:${ctx.session.user.id}`, limit: 10, windowMs: 10_000 }); | |
| const existing = await db | |
| .select() | |
| .from(questionFeedback) | |
| .where( | |
| and( | |
| eq(questionFeedback.questionId, input.questionId), | |
| eq(questionFeedback.userId, ctx.session.user.id), | |
| ), | |
| ) | |
| .limit(1); | |
| const existingFeedback = existing[0]; | |
| if (existingFeedback) { | |
| if (existingFeedback.type === input.type) { | |
| // Toggle off if same type clicked again | |
| await db | |
| .delete(questionFeedback) | |
| .where(eq(questionFeedback.id, existingFeedback.id)); | |
| } else { | |
| await db | |
| .update(questionFeedback) | |
| .set({ type: input.type, note: input.note ?? null }) | |
| .where(eq(questionFeedback.id, existingFeedback.id)); | |
| } | |
| } else { | |
| await db.insert(questionFeedback).values({ | |
| userId: ctx.session.user.id, | |
| questionId: input.questionId, | |
| type: input.type, | |
| note: input.note ?? null, | |
| }); | |
| } | |
| const [counts] = await db | |
| .select({ | |
| up: sql<number>`count(case when ${questionFeedback.type} = 'up' then 1 end)::int`, | |
| down: sql<number>`count(case when ${questionFeedback.type} = 'down' then 1 end)::int`, | |
| }) | |
| .from(questionFeedback) | |
| .where(eq(questionFeedback.questionId, input.questionId)); | |
| return { up: counts?.up ?? 0, down: counts?.down ?? 0 }; | |
| }), | |
| }); | |