Skip to content

Commit

Permalink
wip : zod integration in event comment journey step
Browse files Browse the repository at this point in the history
  • Loading branch information
demanguillaume committed May 24, 2024
1 parent c083dce commit 6e9fbdd
Show file tree
Hide file tree
Showing 11 changed files with 116 additions and 34 deletions.
5 changes: 3 additions & 2 deletions src/app/api/comments/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

/**
Expand Down Expand Up @@ -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 });
Expand Down
13 changes: 10 additions & 3 deletions src/app/api/events/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -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";

/**
Expand Down Expand Up @@ -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<eventWithoutId>(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 });
Expand Down
7 changes: 6 additions & 1 deletion src/app/api/events/route.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand All @@ -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) {
Expand Down
35 changes: 35 additions & 0 deletions src/app/utils/afficherTypesDesAttributs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Utilitaire pour obtenir les types des attributs de T
type TypeDesAttributs<T> = {
[K in keyof T]: T[K];
};

// Fonction pour afficher les types des attributs de T
export function afficherTypesDesAttributs<T extends object>(
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<string, string> = {};

// 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;
}
6 changes: 3 additions & 3 deletions src/repositories/eventRepository.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import prisma from "@/lib/prisma";
import { eventWithUserEvents } from "@/types/eventWithUserEvents";
import { eventWithUserEvents, eventWithoutId } from "@/types/event";
import { Event } from "@prisma/client";

/**
* @params data: Event
* @returns Event
* @description Creates a new event with the provided data.
*/
export const createEvent = async (data: Event): Promise<Event> => {
export const createEvent = async (data: eventWithoutId): Promise<Event> => {
return await prisma.event.create({
data,
});
Expand Down Expand Up @@ -45,7 +45,7 @@ export const readEvents = async (): Promise<Event[] | null> => {
*/
export const updateEvent = async (
id: number,
data: Event
data: eventWithoutId
): Promise<Event | null> => {
return await prisma.event.update({
where: { id },
Expand Down
5 changes: 3 additions & 2 deletions src/services/eventService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -58,7 +59,7 @@ export const getAllEvents = async (): Promise<Event[] | null> => {
*/
export const registerOrModifyEvent = async (
id: number | null,
event: Event
event: eventWithoutId
): Promise<Event | null> => {
// Check arguments
if (id !== null && !Number.isFinite(id)) {
Expand Down
19 changes: 19 additions & 0 deletions src/types/event.ts
Original file line number Diff line number Diff line change
@@ -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;
};
5 changes: 0 additions & 5 deletions src/types/eventWithUserEvents.ts

This file was deleted.

4 changes: 4 additions & 0 deletions src/types/journeyWithComments.ts → src/types/journey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
}>;
5 changes: 0 additions & 5 deletions src/types/journeyWithSteps.ts

This file was deleted.

46 changes: 33 additions & 13 deletions src/validators/api/eventSchema.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down

0 comments on commit 6e9fbdd

Please sign in to comment.