Refactor event handling and user management: Replace direct database calls with service layer methods for events, user profiles, and preferences, enhancing code organization and maintainability. Update API routes to utilize new services for event registration, feedback, and user statistics, ensuring a consistent approach across the application.
This commit is contained in:
278
services/events/event.service.ts
Normal file
278
services/events/event.service.ts
Normal file
@@ -0,0 +1,278 @@
|
||||
import { prisma } from "../database";
|
||||
import type {
|
||||
Event,
|
||||
EventType,
|
||||
Prisma,
|
||||
} from "@/prisma/generated/prisma/client";
|
||||
import { ValidationError, NotFoundError } from "../errors";
|
||||
import { calculateEventStatus } from "@/lib/eventStatus";
|
||||
|
||||
export interface CreateEventInput {
|
||||
date: Date;
|
||||
name: string;
|
||||
description: string;
|
||||
type: EventType;
|
||||
room?: string | null;
|
||||
time?: string | null;
|
||||
maxPlaces?: number | null;
|
||||
}
|
||||
|
||||
export interface UpdateEventInput {
|
||||
date?: Date;
|
||||
name?: string;
|
||||
description?: string;
|
||||
type?: EventType;
|
||||
room?: string | null;
|
||||
time?: string | null;
|
||||
maxPlaces?: number | null;
|
||||
}
|
||||
|
||||
export interface EventWithRegistrationsCount extends Event {
|
||||
registrationsCount: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Service de gestion des événements
|
||||
*/
|
||||
export class EventService {
|
||||
/**
|
||||
* Récupère tous les événements
|
||||
*/
|
||||
async getAllEvents(options?: {
|
||||
orderBy?: Prisma.EventOrderByWithRelationInput;
|
||||
take?: number;
|
||||
}): Promise<Event[]> {
|
||||
return prisma.event.findMany({
|
||||
orderBy: options?.orderBy || { date: "asc" },
|
||||
...(options?.take && { take: options.take }),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère un événement par son ID
|
||||
*/
|
||||
async getEventById(id: string): Promise<Event | null> {
|
||||
return prisma.event.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les événements à venir
|
||||
*/
|
||||
async getUpcomingEvents(limit: number = 3): Promise<Event[]> {
|
||||
const now = new Date();
|
||||
return prisma.event.findMany({
|
||||
where: {
|
||||
date: {
|
||||
gte: now,
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
date: "asc",
|
||||
},
|
||||
take: limit,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un nouvel événement
|
||||
*/
|
||||
async createEvent(data: CreateEventInput): Promise<Event> {
|
||||
return prisma.event.create({
|
||||
data: {
|
||||
date: data.date,
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
type: data.type,
|
||||
room: data.room || null,
|
||||
time: data.time || null,
|
||||
maxPlaces: data.maxPlaces ? parseInt(String(data.maxPlaces)) : null,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour un événement
|
||||
*/
|
||||
async updateEvent(id: string, data: UpdateEventInput): Promise<Event> {
|
||||
const updateData: Prisma.EventUpdateInput = {};
|
||||
|
||||
if (data.date !== undefined) {
|
||||
updateData.date = data.date;
|
||||
}
|
||||
if (data.name !== undefined) {
|
||||
updateData.name = data.name;
|
||||
}
|
||||
if (data.description !== undefined) {
|
||||
updateData.description = data.description;
|
||||
}
|
||||
if (data.type !== undefined) {
|
||||
updateData.type = data.type;
|
||||
}
|
||||
if (data.room !== undefined) {
|
||||
updateData.room = data.room || null;
|
||||
}
|
||||
if (data.time !== undefined) {
|
||||
updateData.time = data.time || null;
|
||||
}
|
||||
if (data.maxPlaces !== undefined) {
|
||||
updateData.maxPlaces = data.maxPlaces
|
||||
? parseInt(String(data.maxPlaces))
|
||||
: null;
|
||||
}
|
||||
|
||||
return prisma.event.update({
|
||||
where: { id },
|
||||
data: updateData,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime un événement
|
||||
*/
|
||||
async deleteEvent(id: string): Promise<void> {
|
||||
await prisma.event.delete({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les événements avec le nombre d'inscriptions (pour admin)
|
||||
*/
|
||||
async getEventsWithRegistrationsCount(): Promise<
|
||||
EventWithRegistrationsCount[]
|
||||
> {
|
||||
const events = await prisma.event.findMany({
|
||||
orderBy: {
|
||||
date: "desc",
|
||||
},
|
||||
include: {
|
||||
_count: {
|
||||
select: {
|
||||
registrations: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return events.map((event) => ({
|
||||
...event,
|
||||
registrationsCount: event._count.registrations,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les événements avec leur statut calculé (pour admin)
|
||||
*/
|
||||
async getEventsWithStatus(): Promise<
|
||||
Array<
|
||||
EventWithRegistrationsCount & { status: "UPCOMING" | "LIVE" | "PAST" }
|
||||
>
|
||||
> {
|
||||
const events = await this.getEventsWithRegistrationsCount();
|
||||
return events.map((event) => ({
|
||||
...event,
|
||||
status: calculateEventStatus(event.date),
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Valide et crée un événement avec toutes les règles métier
|
||||
*/
|
||||
async validateAndCreateEvent(data: {
|
||||
date: string | Date;
|
||||
name: string;
|
||||
description: string;
|
||||
type: string;
|
||||
room?: string | null;
|
||||
time?: string | null;
|
||||
maxPlaces?: string | number | null;
|
||||
}): Promise<Event> {
|
||||
// Validation des champs requis
|
||||
if (!data.date || !data.name || !data.description || !data.type) {
|
||||
throw new ValidationError("Tous les champs sont requis");
|
||||
}
|
||||
|
||||
// Convertir et valider la date
|
||||
const eventDate =
|
||||
typeof data.date === "string" ? new Date(data.date) : data.date;
|
||||
if (isNaN(eventDate.getTime())) {
|
||||
throw new ValidationError("Format de date invalide", "date");
|
||||
}
|
||||
|
||||
// Valider le type d'événement
|
||||
if (!Object.values(EventType).includes(data.type as EventType)) {
|
||||
throw new ValidationError("Type d'événement invalide", "type");
|
||||
}
|
||||
|
||||
// Créer l'événement
|
||||
return this.createEvent({
|
||||
date: eventDate,
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
type: data.type as EventType,
|
||||
room: data.room || null,
|
||||
time: data.time || null,
|
||||
maxPlaces: data.maxPlaces ? parseInt(String(data.maxPlaces)) : null,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Valide et met à jour un événement avec toutes les règles métier
|
||||
*/
|
||||
async validateAndUpdateEvent(
|
||||
id: string,
|
||||
data: {
|
||||
date?: string | Date;
|
||||
name?: string;
|
||||
description?: string;
|
||||
type?: string;
|
||||
room?: string | null;
|
||||
time?: string | null;
|
||||
maxPlaces?: string | number | null;
|
||||
}
|
||||
): Promise<Event> {
|
||||
// Vérifier que l'événement existe
|
||||
const existingEvent = await this.getEventById(id);
|
||||
if (!existingEvent) {
|
||||
throw new NotFoundError("Événement");
|
||||
}
|
||||
|
||||
const updateData: UpdateEventInput = {};
|
||||
|
||||
// Valider et convertir la date si fournie
|
||||
if (data.date !== undefined) {
|
||||
const eventDate =
|
||||
typeof data.date === "string" ? new Date(data.date) : data.date;
|
||||
if (isNaN(eventDate.getTime())) {
|
||||
throw new ValidationError("Format de date invalide", "date");
|
||||
}
|
||||
updateData.date = eventDate;
|
||||
}
|
||||
|
||||
// Valider le type si fourni
|
||||
if (data.type !== undefined) {
|
||||
if (!Object.values(EventType).includes(data.type as EventType)) {
|
||||
throw new ValidationError("Type d'événement invalide", "type");
|
||||
}
|
||||
updateData.type = data.type as EventType;
|
||||
}
|
||||
|
||||
// Autres champs
|
||||
if (data.name !== undefined) updateData.name = data.name;
|
||||
if (data.description !== undefined)
|
||||
updateData.description = data.description;
|
||||
if (data.room !== undefined) updateData.room = data.room || null;
|
||||
if (data.time !== undefined) updateData.time = data.time || null;
|
||||
if (data.maxPlaces !== undefined) {
|
||||
updateData.maxPlaces = data.maxPlaces
|
||||
? parseInt(String(data.maxPlaces))
|
||||
: null;
|
||||
}
|
||||
|
||||
return this.updateEvent(id, updateData);
|
||||
}
|
||||
}
|
||||
|
||||
export const eventService = new EventService();
|
||||
Reference in New Issue
Block a user