diff --git a/prisma/migrations/20250310203903_add_ratings_column/migration.sql b/prisma/migrations/20250310203903_add_ratings_column/migration.sql new file mode 100644 index 0000000..a314948 --- /dev/null +++ b/prisma/migrations/20250310203903_add_ratings_column/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "users" ADD COLUMN "ratings" JSONB NOT NULL DEFAULT '{}'; diff --git a/prisma/migrations/20250310204055_change_ratings_default_to_array/migration.sql b/prisma/migrations/20250310204055_change_ratings_default_to_array/migration.sql new file mode 100644 index 0000000..a0593c0 --- /dev/null +++ b/prisma/migrations/20250310204055_change_ratings_default_to_array/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "users" ALTER COLUMN "ratings" SET DEFAULT '[]'; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 8c66897..caa1495 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -74,5 +74,6 @@ model users { created_at DateTime @db.Timestamptz(0) last_logged_in DateTime? @db.Timestamptz(0) permissions String[] + ratings Json @default("[]") profile Json -} +} \ No newline at end of file diff --git a/server/routes/users/[id]/ratings.ts b/server/routes/users/[id]/ratings.ts new file mode 100644 index 0000000..d4682e0 --- /dev/null +++ b/server/routes/users/[id]/ratings.ts @@ -0,0 +1,112 @@ +import { useAuth } from '~/utils/auth'; +import { z } from 'zod'; + +const userRatingsSchema = z.object({ + tmdb_id: z.number(), + type: z.enum(['movie', 'tv']), + rating: z.number() +}); + +export default defineEventHandler(async (event) => { + const userId = event.context.params?.id; + + const authHeader = getRequestHeader(event, 'authorization'); + if (!authHeader || !authHeader.startsWith('Bearer ')) { + throw createError({ + statusCode: 401, + message: 'Unauthorized' + }); + } + + const token = authHeader.split(' ')[1]; + const auth = useAuth(); + + const payload = auth.verifySessionToken(token); + if (!payload) { + throw createError({ + statusCode: 401, + message: 'Invalid token' + }); + } + + const session = await auth.getSessionAndBump(payload.sid); + if (!session) { + throw createError({ + statusCode: 401, + message: 'Session not found or expired' + }); + } + + if (session.user !== userId) { + throw createError({ + statusCode: 403, + message: 'Permission denied' + }); + } + + if (event.method === 'GET'){ + const ratings = await prisma.users.findMany({ + select: { + ratings: true + }, + where: { + id: userId + }}); + + return { + userId, + ratings: ratings[0].ratings + } + } else if (event.method === 'POST'){ + const body = await readBody(event); + const validatedBody = userRatingsSchema.parse(body); + + const user = await prisma.users.findUnique({ + where: { + id: userId + }, + select: { + ratings: true + } + }); + + const userRatings = user?.ratings || []; + const currentRatings = Array.isArray(userRatings) ? userRatings : []; + + const existingRatingIndex = currentRatings.findIndex( + (r: any) => r.tmdb_id === validatedBody.tmdb_id && r.type === validatedBody.type + ); + + let updatedRatings; + if (existingRatingIndex >= 0) { + updatedRatings = [...currentRatings]; + updatedRatings[existingRatingIndex] = validatedBody; + } else { + updatedRatings = [...currentRatings, validatedBody]; + } + + await prisma.users.update({ + where: { + id: userId + }, + data: { + ratings: updatedRatings + } + }); + + return { + userId, + rating: { + tmdb_id: validatedBody.tmdb_id, + type: validatedBody.type, + rating: validatedBody.rating + } + }; + } + + // This should only execute if the method is neither GET nor POST + throw createError({ + statusCode: 405, + message: 'Method not allowed' + }); +}) \ No newline at end of file