import CalendarEvent from '../models/community/calendar_event.js'; import User from '../models/community/user.js'; import { Op } from 'sequelize'; class CalendarService { /** * Get all calendar events for a user * @param {string} hashedUserId - The user's hashed ID * @param {object} options - Optional filters (startDate, endDate) */ async getEvents(hashedUserId, options = {}) { const user = await User.findOne({ where: { hashedId: hashedUserId } }); if (!user) { throw new Error('User not found'); } const where = { userId: user.id }; // Filter by date range if provided if (options.startDate || options.endDate) { where[Op.or] = []; if (options.startDate && options.endDate) { // Events that overlap with the requested range where[Op.or].push({ startDate: { [Op.between]: [options.startDate, options.endDate] } }); where[Op.or].push({ endDate: { [Op.between]: [options.startDate, options.endDate] } }); where[Op.or].push({ [Op.and]: [ { startDate: { [Op.lte]: options.startDate } }, { endDate: { [Op.gte]: options.endDate } } ] }); } else if (options.startDate) { where[Op.or].push({ startDate: { [Op.gte]: options.startDate } }); where[Op.or].push({ endDate: { [Op.gte]: options.startDate } }); } else if (options.endDate) { where[Op.or].push({ startDate: { [Op.lte]: options.endDate } }); } } const events = await CalendarEvent.findAll({ where, order: [['startDate', 'ASC'], ['startTime', 'ASC']] }); return events.map(e => this.formatEvent(e)); } /** * Get a single event by ID */ async getEvent(hashedUserId, eventId) { const user = await User.findOne({ where: { hashedId: hashedUserId } }); if (!user) { throw new Error('User not found'); } const event = await CalendarEvent.findOne({ where: { id: eventId, userId: user.id } }); if (!event) { throw new Error('Event not found'); } return this.formatEvent(event); } /** * Create a new calendar event */ async createEvent(hashedUserId, eventData) { const user = await User.findOne({ where: { hashedId: hashedUserId } }); if (!user) { throw new Error('User not found'); } const event = await CalendarEvent.create({ userId: user.id, title: eventData.title, description: eventData.description || null, categoryId: eventData.categoryId || 'personal', startDate: eventData.startDate, endDate: eventData.endDate || eventData.startDate, startTime: eventData.allDay ? null : eventData.startTime, endTime: eventData.allDay ? null : eventData.endTime, allDay: eventData.allDay || false }); return this.formatEvent(event); } /** * Update an existing calendar event */ async updateEvent(hashedUserId, eventId, eventData) { const user = await User.findOne({ where: { hashedId: hashedUserId } }); if (!user) { throw new Error('User not found'); } const event = await CalendarEvent.findOne({ where: { id: eventId, userId: user.id } }); if (!event) { throw new Error('Event not found'); } await event.update({ title: eventData.title, description: eventData.description || null, categoryId: eventData.categoryId || 'personal', startDate: eventData.startDate, endDate: eventData.endDate || eventData.startDate, startTime: eventData.allDay ? null : eventData.startTime, endTime: eventData.allDay ? null : eventData.endTime, allDay: eventData.allDay || false }); return this.formatEvent(event); } /** * Delete a calendar event */ async deleteEvent(hashedUserId, eventId) { const user = await User.findOne({ where: { hashedId: hashedUserId } }); if (!user) { throw new Error('User not found'); } const event = await CalendarEvent.findOne({ where: { id: eventId, userId: user.id } }); if (!event) { throw new Error('Event not found'); } await event.destroy(); return { success: true }; } /** * Format event for API response */ formatEvent(event) { return { id: event.id, title: event.title, description: event.description, categoryId: event.categoryId, startDate: event.startDate, endDate: event.endDate, startTime: event.startTime ? event.startTime.substring(0, 5) : null, // HH:MM format endTime: event.endTime ? event.endTime.substring(0, 5) : null, allDay: event.allDay, createdAt: event.createdAt, updatedAt: event.updatedAt }; } } export default new CalendarService();