mirror of
https://github.com/SrIzan10/fireentity-movienights.git
synced 2026-06-06 00:56:52 +00:00
zod shit
This commit is contained in:
1
bun.lock
1
bun.lock
@@ -24,6 +24,7 @@
|
||||
"sonner": "^2.0.7",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tw-animate-css": "^1.3.7",
|
||||
"zod": "^4.0.17",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
"react-dom": "19.1.0",
|
||||
"sonner": "^2.0.7",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tw-animate-css": "^1.3.7"
|
||||
"tw-animate-css": "^1.3.7",
|
||||
"zod": "^4.0.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
|
||||
@@ -3,6 +3,7 @@ import { PrismaClient } from "@prisma/client";
|
||||
import { NextResponse } from "next/server";
|
||||
import { auth } from "../../../../auth/auth";
|
||||
import { headers } from "next/headers";
|
||||
import { idSchema, validateParams } from "@/lib/validation";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
@@ -17,9 +18,15 @@ export async function POST(
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
// Validate params
|
||||
const { data, error } = validateParams(await params, idSchema);
|
||||
if (error) {
|
||||
return NextResponse.json({ error }, { status: 400 });
|
||||
}
|
||||
|
||||
const movie = await prisma.movie.update({
|
||||
where: {
|
||||
id: (await params).id,
|
||||
id: data.id,
|
||||
},
|
||||
data: {
|
||||
approved: true,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { PrismaClient } from "@prisma/client";
|
||||
import { NextResponse } from "next/server";
|
||||
import { headers } from "next/headers";
|
||||
import { auth } from "../../auth/auth";
|
||||
import { scheduleMovieSchema, scheduleIdSchema, validateRequestData, validateSearchParams } from "@/lib/validation";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
@@ -14,7 +15,13 @@ export async function POST(req: Request) {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
const { movieId, date } = await req.json();
|
||||
// Validate request data
|
||||
const { data, error } = await validateRequestData(req, scheduleMovieSchema);
|
||||
if (error) {
|
||||
return NextResponse.json({ error }, { status: 400 });
|
||||
}
|
||||
|
||||
const { movieId, date } = data;
|
||||
|
||||
try {
|
||||
const schedule = await prisma.movieSchedule.create({
|
||||
@@ -60,12 +67,13 @@ export async function DELETE(req: Request) {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(req.url);
|
||||
const scheduleId = searchParams.get('id');
|
||||
|
||||
if (!scheduleId) {
|
||||
return NextResponse.json({ error: "Schedule ID required" }, { status: 400 });
|
||||
// Validate search params
|
||||
const { data, error } = validateSearchParams(req.url, scheduleIdSchema);
|
||||
if (error) {
|
||||
return NextResponse.json({ error }, { status: 400 });
|
||||
}
|
||||
|
||||
const { id: scheduleId } = data;
|
||||
|
||||
try {
|
||||
await prisma.movieSchedule.delete({
|
||||
|
||||
@@ -3,6 +3,7 @@ import { PrismaClient } from "@prisma/client";
|
||||
import { NextResponse } from "next/server";
|
||||
import { auth } from "../../../auth/auth";
|
||||
import { headers } from "next/headers";
|
||||
import { idSchema, validateParams } from "@/lib/validation";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
@@ -16,7 +17,13 @@ export async function POST(
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
const movieId = (await params).id;
|
||||
// Validate params
|
||||
const { data, error } = validateParams(await params, idSchema);
|
||||
if (error) {
|
||||
return NextResponse.json({ error }, { status: 400 });
|
||||
}
|
||||
|
||||
const movieId = data.id;
|
||||
const userId = session.user.id;
|
||||
|
||||
// Check if the user has already voted for this movie
|
||||
|
||||
@@ -3,16 +3,23 @@ import { PrismaClient } from "@prisma/client";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { headers } from "next/headers";
|
||||
import { auth } from "../auth/auth";
|
||||
import { movieSuggestionSchema, validateRequestData } from "@/lib/validation";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const { title, description, posterUrl, suggestedBy } = await req.json();
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
if (!session || !session.user?.id) {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
// Validate request data
|
||||
const { data, error } = await validateRequestData(req, movieSuggestionSchema);
|
||||
if (error) {
|
||||
return NextResponse.json({ error }, { status: 400 });
|
||||
}
|
||||
const { title, description, posterUrl, suggestedBy } = data as any;
|
||||
|
||||
// Check if there's already a pending request for this movie (not approved)
|
||||
const existingPendingMovies = await prisma.movie.findMany({
|
||||
where: {
|
||||
|
||||
@@ -2,24 +2,27 @@
|
||||
import auth from "@/lib/auth-config";
|
||||
import { headers } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
import { searchMovieSchema, validateSearchParams } from "@/lib/validation";
|
||||
|
||||
export async function GET(req: Request) {
|
||||
const { searchParams } = new URL(req.url);
|
||||
const query = searchParams.get("query");
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
|
||||
if (!session) {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
if (!query) {
|
||||
return NextResponse.json({ error: "Query is required" }, { status: 400 });
|
||||
// Validate search params
|
||||
const { data, error } = validateSearchParams(req.url, searchMovieSchema);
|
||||
if (error) {
|
||||
return NextResponse.json({ error }, { status: 400 });
|
||||
}
|
||||
|
||||
const { query } = data;
|
||||
|
||||
const res = await fetch(
|
||||
`https://api.themoviedb.org/3/search/movie?api_key=${process.env.TMDB_API_KEY}&query=${query}`
|
||||
);
|
||||
const data = await res.json();
|
||||
const apiData = await res.json();
|
||||
|
||||
return NextResponse.json(data.results);
|
||||
return NextResponse.json(apiData.results);
|
||||
}
|
||||
|
||||
80
src/lib/validation.ts
Normal file
80
src/lib/validation.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
// Movie suggestion schema
|
||||
export const movieSuggestionSchema = z.object({
|
||||
title: z.string().min(1, "Title is required").max(255, "Title must be less than 255 characters"),
|
||||
description: z.string().min(1, "Description is required").max(1000, "Description must be less than 1000 characters"),
|
||||
posterUrl: z.string().url("Invalid URL format"),
|
||||
suggestedBy: z.string().min(1, "Suggested by is required").max(100, "Suggested by must be less than 100 characters"),
|
||||
});
|
||||
|
||||
// Movie vote schema
|
||||
export const movieVoteSchema = z.object({
|
||||
movieId: z.string().min(1, "Movie ID is required"),
|
||||
});
|
||||
|
||||
// Schedule movie schema
|
||||
export const scheduleMovieSchema = z.object({
|
||||
movieId: z.string().min(1, "Movie ID is required"),
|
||||
date: z.string().datetime("Invalid date format"),
|
||||
});
|
||||
|
||||
// Search movie schema
|
||||
export const searchMovieSchema = z.object({
|
||||
query: z.string().min(1, "Query is required").max(100, "Query must be less than 100 characters"),
|
||||
});
|
||||
|
||||
// Schedule ID schema
|
||||
export const scheduleIdSchema = z.object({
|
||||
id: z.string().min(1, "Schedule ID is required"),
|
||||
});
|
||||
|
||||
// Generic ID schema
|
||||
export const idSchema = z.object({
|
||||
id: z.string().min(1, "ID is required"),
|
||||
});
|
||||
|
||||
// Utility function to validate request data
|
||||
export async function validateRequestData(request: Request, schema: z.ZodSchema) {
|
||||
try {
|
||||
const data = await request.json();
|
||||
return { data: schema.parse(data) as any, error: null };
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
const errorMessage = error.errors.map(err => err.message).join(", ");
|
||||
return { data: null, error: errorMessage };
|
||||
}
|
||||
return { data: null, error: "Invalid JSON" };
|
||||
}
|
||||
}
|
||||
|
||||
// Utility function to validate URL parameters
|
||||
export function validateParams(params: Record<string, string>, schema: z.ZodSchema) {
|
||||
try {
|
||||
return { data: schema.parse(params) as any, error: null };
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
const errorMessage = error.errors.map(err => err.message).join(", ");
|
||||
return { data: null, error: errorMessage };
|
||||
}
|
||||
return { data: null, error: "Invalid parameters" };
|
||||
}
|
||||
}
|
||||
|
||||
// Utility function to validate search parameters
|
||||
export function validateSearchParams(url: string, schema: z.ZodSchema) {
|
||||
try {
|
||||
const { searchParams } = new URL(url);
|
||||
const params: Record<string, string> = {};
|
||||
for (const [key, value] of searchParams.entries()) {
|
||||
params[key] = value;
|
||||
}
|
||||
return { data: schema.parse(params) as any, error: null };
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
const errorMessage = error.errors.map(err => err.message).join(", ");
|
||||
return { data: null, error: errorMessage };
|
||||
}
|
||||
return { data: null, error: "Invalid search parameters" };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user