import { Response } from "express"; import { CalendarEvent, RecurringDeleteMode } from "@calchat/shared"; import { EventService } from "../services"; import { createLogger } from "../logging"; import { AuthenticatedRequest } from "./AuthMiddleware"; import { CaldavService } from "../services/CaldavService"; const log = createLogger("EventController"); export class EventController { constructor( private eventService: EventService, private caldavService: CaldavService, ) {} private async pushToCaldav(userId: string, event: CalendarEvent) { if (await this.caldavService.getConfig(userId)) { try { await this.caldavService.pushEvent(userId, event); } catch (error) { log.error({ err: error, userId }, "Error pushing event to CalDAV"); } } } private async deleteFromCaldav(userId: string, event: CalendarEvent) { if (event.caldavUUID && (await this.caldavService.getConfig(userId))) { try { await this.caldavService.deleteEvent(userId, event.caldavUUID); } catch (error) { log.error({ err: error, userId }, "Error deleting event from CalDAV"); } } } async create(req: AuthenticatedRequest, res: Response): Promise { try { const userId = req.user!.userId; const event = await this.eventService.create(userId, req.body); await this.pushToCaldav(userId, event); res.status(201).json(event); } catch (error) { log.error( { err: error, userId: req.user?.userId }, "Error creating event", ); res.status(500).json({ error: "Failed to create event" }); } } async getById(req: AuthenticatedRequest, res: Response): Promise { try { const event = await this.eventService.getById( req.params.id, req.user!.userId, ); if (!event) { res.status(404).json({ error: "Event not found" }); return; } res.json(event); } catch (error) { log.error({ err: error, eventId: req.params.id }, "Error getting event"); res.status(500).json({ error: "Failed to get event" }); } } async getAll(req: AuthenticatedRequest, res: Response): Promise { try { const events = await this.eventService.getAll(req.user!.userId); res.json(events); } catch (error) { log.error( { err: error, userId: req.user?.userId }, "Error getting events", ); res.status(500).json({ error: "Failed to get events" }); } } async getByDateRange( req: AuthenticatedRequest, res: Response, ): Promise { try { const { start, end } = req.query; if (!start || !end) { res.status(400).json({ error: "start and end query params required" }); return; } const startDate = new Date(start as string); const endDate = new Date(end as string); if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) { res.status(400).json({ error: "Invalid date format" }); return; } const events = await this.eventService.getByDateRange( req.user!.userId, startDate, endDate, ); res.json(events); } catch (error) { log.error( { err: error, start: req.query.start, end: req.query.end }, "Error getting events by range", ); res.status(500).json({ error: "Failed to get events" }); } } async update(req: AuthenticatedRequest, res: Response): Promise { try { const userId = req.user!.userId; const event = await this.eventService.update( req.params.id, userId, req.body, ); if (!event) { res.status(404).json({ error: "Event not found" }); return; } await this.pushToCaldav(userId, event); res.json(event); } catch (error) { log.error({ err: error, eventId: req.params.id }, "Error updating event"); res.status(500).json({ error: "Failed to update event" }); } } async delete(req: AuthenticatedRequest, res: Response): Promise { try { const userId = req.user!.userId; const { mode, occurrenceDate } = req.query as { mode?: RecurringDeleteMode; occurrenceDate?: string; }; // Fetch event before deletion to get caldavUUID for sync const event = await this.eventService.getById(req.params.id, userId); if (!event) { res.status(404).json({ error: "Event not found" }); return; } // If mode is specified, use deleteRecurring if (mode) { const result = await this.eventService.deleteRecurring( req.params.id, userId, mode, occurrenceDate, ); // Event was updated (single/future mode) - push update to CalDAV if (result) { await this.pushToCaldav(userId, result); res.json(result); return; } // Event was fully deleted (all mode, or future from first occurrence) await this.deleteFromCaldav(userId, event); res.status(204).send(); return; } // Default behavior: delete completely await this.eventService.delete(req.params.id, userId); await this.deleteFromCaldav(userId, event); res.status(204).send(); } catch (error) { log.error({ err: error, eventId: req.params.id }, "Error deleting event"); res.status(500).json({ error: "Failed to delete event" }); } } }