import { Injectable, NotFoundException } from '@nestjs/common'; import { PrismaService } from '../../prisma/prisma.service'; import { AuditService } from '../audit/audit.service'; import { AuditAction } from '../audit/audit.types'; @Injectable() export class EventsService { constructor( private readonly prisma: PrismaService, private readonly audit: AuditService, ) {} async list(tenantId: string, includeUnpublished = false) { return this.prisma.event.findMany({ where: { tenantId, ...(includeUnpublished ? {} : { isPublished: true }), }, orderBy: { startsAt: 'asc' }, include: { _count: { select: { rsvps: true } } }, }); } async create(tenantId: string, adminId: string, dto: { title: string; description?: string; location?: string; startsAt: string; endsAt?: string; isPublished?: boolean; }) { const event = await this.prisma.event.create({ data: { tenantId, title: dto.title, description: dto.description ?? null, location: dto.location ?? null, startsAt: new Date(dto.startsAt), endsAt: dto.endsAt ? new Date(dto.endsAt) : null, createdBy: adminId, isPublished: dto.isPublished ?? false, }, }); await this.audit.log({ tenantId, actorId: adminId, action: AuditAction.EVENT_CREATED, resourceType: 'Event', resourceId: event.id, payload: { title: event.title, isPublished: event.isPublished }, }); return event; } async update(tenantId: string, adminId: string, eventId: string, dto: { title?: string; description?: string; location?: string; startsAt?: string; endsAt?: string; isPublished?: boolean; }) { const event = await this.prisma.event.findFirst({ where: { id: eventId, tenantId } }); if (!event) throw new NotFoundException('Event not found'); return this.prisma.event.update({ where: { id: eventId }, data: { ...(dto.title !== undefined && { title: dto.title }), ...(dto.description !== undefined && { description: dto.description }), ...(dto.location !== undefined && { location: dto.location }), ...(dto.startsAt !== undefined && { startsAt: new Date(dto.startsAt) }), ...(dto.endsAt !== undefined && { endsAt: new Date(dto.endsAt) }), ...(dto.isPublished !== undefined && { isPublished: dto.isPublished }), }, }); } async remove(tenantId: string, adminId: string, eventId: string) { const event = await this.prisma.event.findFirst({ where: { id: eventId, tenantId } }); if (!event) throw new NotFoundException('Event not found'); await this.prisma.event.delete({ where: { id: eventId } }); await this.audit.log({ tenantId, actorId: adminId, action: AuditAction.EVENT_DELETED, resourceType: 'Event', resourceId: eventId, payload: { deleted: true }, }); return { ok: true }; } async getRsvps(tenantId: string, eventId: string) { const event = await this.prisma.event.findFirst({ where: { id: eventId, tenantId } }); if (!event) throw new NotFoundException('Event not found'); return this.prisma.eventRsvp.findMany({ where: { eventId }, include: { user: { select: { id: true, displayName: true, jid: true } } }, orderBy: { createdAt: 'asc' }, }); } }