diff --git a/src/app/api/comments/[id]/route.ts b/src/app/api/comments/[id]/route.ts index b412856..4a1c418 100644 --- a/src/app/api/comments/[id]/route.ts +++ b/src/app/api/comments/[id]/route.ts @@ -5,6 +5,7 @@ import { removeComment, } from "@/services/commentService"; import { CommentWithoutDates } from "@/types/CommentWithoutDates"; +import { commentBodySchema } from "@/validators/api/commentSchema"; import { NextRequest, NextResponse } from "next/server"; /** @@ -39,9 +40,9 @@ export async function PUT( try { const id: number = Number(params.id); const body = await request.json(); - const comment: CommentWithoutDates = body.comment; + const commentParsed = commentBodySchema.parse(body); - console.log("COMMENT : " + comment); + const comment: CommentWithoutDates = commentParsed.comment; const result = await registerOrModifyComment(id, comment); return NextResponse.json({ data: result }, { status: 200 }); diff --git a/src/app/api/events/[id]/route.ts b/src/app/api/events/[id]/route.ts index cfa051e..0f900b0 100644 --- a/src/app/api/events/[id]/route.ts +++ b/src/app/api/events/[id]/route.ts @@ -1,10 +1,12 @@ +import { afficherTypesDesAttributs } from "@/app/utils/afficherTypesDesAttributs"; import { handleException } from "@/app/utils/errorHandlerUtils"; import { getEventByIdWithUserEvents, registerOrModifyEvent, removeEvent, } from "@/services/eventService"; -import { Event } from "@prisma/client"; +import { eventWithoutId } from "@/types/event"; +import { eventBodySchema } from "@/validators/api/eventSchema"; import { NextRequest, NextResponse } from "next/server"; /** @@ -38,8 +40,13 @@ export async function PUT( ) { try { const id: number = Number(params.id); - const body = await request.json(); - const event: Event = body.event; + let body = await request.json(); + let bodytarget: object; + afficherTypesDesAttributs(body.event, EventWithoutId); + + const eventParsed = eventBodySchema.parse(body); + + const event: eventWithoutId = eventParsed.event; const result = await registerOrModifyEvent(id, event); return NextResponse.json({ data: result }, { status: 200 }); diff --git a/src/app/api/events/route.ts b/src/app/api/events/route.ts index ba6500b..f2274a3 100644 --- a/src/app/api/events/route.ts +++ b/src/app/api/events/route.ts @@ -1,5 +1,7 @@ import { handleException } from "@/app/utils/errorHandlerUtils"; import { getAllEvents, registerOrModifyEvent } from "@/services/eventService"; +import { eventWithoutId } from "@/types/event"; +import { eventBodySchema } from "@/validators/api/eventSchema"; import { Event } from "@prisma/client"; import { NextRequest, NextResponse } from "next/server"; @@ -24,8 +26,11 @@ export async function GET() { export async function POST(request: NextRequest) { try { const body = await request.json(); - const event: Event = body.event; + body.event.startAt = new Date(body.event.startAt); + body.event.endAt = new Date(body.event.endAt); + const eventParsed = eventBodySchema.parse(body); + const event: eventWithoutId = eventParsed.event; const result = await registerOrModifyEvent(null, event); return NextResponse.json({ data: result }, { status: 200 }); } catch (error: any) { diff --git a/src/app/utils/afficherTypesDesAttributs.ts b/src/app/utils/afficherTypesDesAttributs.ts new file mode 100644 index 0000000..b5cbc69 --- /dev/null +++ b/src/app/utils/afficherTypesDesAttributs.ts @@ -0,0 +1,35 @@ +// Utilitaire pour obtenir les types des attributs de T +type TypeDesAttributs = { + [K in keyof T]: T[K]; +}; + +// Fonction pour afficher les types des attributs de T +export function afficherTypesDesAttributs( + body: T, + ctor: new () => T +) { + console.log("AFFICHER TYPES DES ATTRIBUTS"); + + // Instancier un nouvel objet de type T + const bodyTypeTarget = new ctor(); + + // Obtenir les clés de l'objet (y compris les symboles) + const keys = [ + ...Object.keys(bodyTypeTarget), + ...Object.getOwnPropertySymbols(bodyTypeTarget), + ] as (keyof T)[]; + + // Créer un objet pour stocker les types des attributs + const types: Record = {}; + + // Parcourir les clés et obtenir les types + keys.forEach((key) => { + const keyAsString = String(key); // Convertir la clé en chaîne de caractères + const valeur = body[key as keyof T]; + types[keyAsString] = typeof valeur; + console.log(`Clé: ${keyAsString}, Type: ${typeof valeur}`); + }); + + // Retourner les types des attributs + return types; +} diff --git a/src/repositories/eventRepository.ts b/src/repositories/eventRepository.ts index 28c55dc..b1b3392 100644 --- a/src/repositories/eventRepository.ts +++ b/src/repositories/eventRepository.ts @@ -1,5 +1,5 @@ import prisma from "@/lib/prisma"; -import { eventWithUserEvents } from "@/types/eventWithUserEvents"; +import { eventWithUserEvents, eventWithoutId } from "@/types/event"; import { Event } from "@prisma/client"; /** @@ -7,7 +7,7 @@ import { Event } from "@prisma/client"; * @returns Event * @description Creates a new event with the provided data. */ -export const createEvent = async (data: Event): Promise => { +export const createEvent = async (data: eventWithoutId): Promise => { return await prisma.event.create({ data, }); @@ -45,7 +45,7 @@ export const readEvents = async (): Promise => { */ export const updateEvent = async ( id: number, - data: Event + data: eventWithoutId ): Promise => { return await prisma.event.update({ where: { id }, diff --git a/src/services/eventService.ts b/src/services/eventService.ts index 8884bb1..65f4e29 100644 --- a/src/services/eventService.ts +++ b/src/services/eventService.ts @@ -11,12 +11,13 @@ import { deleteEvent, } from "../repositories/eventRepository"; import { Event, UserEvent } from "@prisma/client"; -import { eventWithUserEvents } from "@/types/eventWithUserEvents"; import { createUserEvent, deleteUserEvent, readUserEventByUserIdAndEventId, } from "@/repositories/userEventRepository"; +import { eventWithUserEvents, eventWithoutId } from "@/types/event"; +import { UserEventWithoutId } from "@/types/userEventWithoutId"; /** * @params id: number @@ -58,7 +59,7 @@ export const getAllEvents = async (): Promise => { */ export const registerOrModifyEvent = async ( id: number | null, - event: Event + event: eventWithoutId ): Promise => { // Check arguments if (id !== null && !Number.isFinite(id)) { diff --git a/src/types/event.ts b/src/types/event.ts new file mode 100644 index 0000000..4d68dbb --- /dev/null +++ b/src/types/event.ts @@ -0,0 +1,19 @@ +import { Prisma } from "@prisma/client"; + +export type eventWithUserEvents = Prisma.EventGetPayload<{ + include: { userEvents: true }; +}>; + +export type eventWithoutId = { + authorId: number; + journeyId: number; + title: string; + image: string; + numberPlayerMin: number; + numberPlayerMax: number; + description: string; + startAt: Date; + endAt: Date; + isPrivate?: boolean; + accessCode?: string; +}; diff --git a/src/types/eventWithUserEvents.ts b/src/types/eventWithUserEvents.ts deleted file mode 100644 index 5512d69..0000000 --- a/src/types/eventWithUserEvents.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Prisma } from "@prisma/client"; - -export type eventWithUserEvents = Prisma.EventGetPayload<{ - include: { userEvents: true }; -}>; diff --git a/src/types/journeyWithComments.ts b/src/types/journey.ts similarity index 60% rename from src/types/journeyWithComments.ts rename to src/types/journey.ts index 914cf1f..849f4c7 100644 --- a/src/types/journeyWithComments.ts +++ b/src/types/journey.ts @@ -3,3 +3,7 @@ import { Prisma } from "@prisma/client"; export type journeyWithComments = Prisma.JourneyGetPayload<{ include: { comments: true }; }>; + +export type journeyWithSteps = Prisma.JourneyGetPayload<{ + include: { steps: true }; +}>; diff --git a/src/types/journeyWithSteps.ts b/src/types/journeyWithSteps.ts deleted file mode 100644 index 4e57e85..0000000 --- a/src/types/journeyWithSteps.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Prisma } from "@prisma/client"; - -export type journeyWithSteps = Prisma.JourneyGetPayload<{ - include: { steps: true }; -}>; diff --git a/src/validators/api/eventSchema.ts b/src/validators/api/eventSchema.ts index 58b412f..e481c8f 100644 --- a/src/validators/api/eventSchema.ts +++ b/src/validators/api/eventSchema.ts @@ -1,18 +1,38 @@ import { z } from "zod"; -// Event schema -export const eventSchema = z.object({ - authorId: z.number().int(), - journeyId: z.number().int(), - title: z.string(), - image: z.string().url(), - numberPlayerMin: z.number().int(), - numberPlayerMax: z.number().int(), - description: z.string(), - isPrivate: z.boolean().optional(), - accessCode: z.string().nullable().optional(), - startAt: z.string().datetime(), // Using z.string() for ISO date strings - endAt: z.string().datetime(), +// Event schema de base avec des messages d'erreur personnalisés +const baseEventSchema = z.object({ + authorId: z.number({ required_error: "Ce champ est requis" }).int(), + journeyId: z.number({ required_error: "Ce champ est requis" }).int(), + title: z + .string({ required_error: "Ce champ est requis" }) + .max(255, { message: "Veuillez renseigner moins de 255 caractères" }), + image: z + .string({ required_error: "Ce champ est requis" }) + .url({ message: "Veuillez fournir une URL valide" }), + numberPlayerMin: z + .number({ required_error: "Ce champ est requis" }) + .int({ message: "Veuillez fournir un nombre entier" }), + numberPlayerMax: z + .number({ required_error: "Ce champ est requis" }) + .int({ message: "Veuillez fournir un nombre entier" }), + description: z + .string({ required_error: "Ce champ est requis" }) + .max(500, { message: "Veuillez renseigner moins de 500 caractères" }), + isPrivate: z.boolean({ required_error: "Ce champ est requis" }), + accessCode: z.string().optional(), + startAt: z.date({ required_error: "Ce champ est requis" }), + endAt: z.date({ required_error: "Ce champ est requis" }), +}); + +export const eventSchema = baseEventSchema.superRefine((data, ctx) => { + if (data.isPrivate && (!data.accessCode || data.accessCode.trim() === "")) { + ctx.addIssue({ + code: "custom", + message: "accessCode is required when isPrivate is true", + path: ["accessCode"], + }); + } }); // Combined schema for the body