import * as dotenv from 'dotenv'; import {Guid} from 'guid-typescript'; import {Event} from './event.interface'; import {NachklangCalendarDB} from '../Calendar.db'; dotenv.config(); /** * Returns all events for the given calendar * @param calendarId The calendar Id */ export const getAllEvents = async (calendarId: number): Promise => { let conn = await NachklangCalendarDB.getConnection(); let eventRows: Event[] = []; try { const calendarQuery = 'SELECT calendar_id, includes_calendars FROM calendars WHERE calendar_id = ?'; const calendarRes = await conn.query(calendarQuery, calendarId); let calendarsToFetch: number[] = [calendarId]; for(let row of calendarRes) { let includes: number[] = JSON.parse(row.includes_calendars); calendarsToFetch = [...calendarsToFetch, ...includes]; } const eventsQuery = ` SELECT e.calendar_id, e.uuid, e.created_date, e.created_by_id, u.full_name as created_by_name, u2.full_name as last_modified_by_name, v.* FROM events e INNER JOIN ( SELECT event_id, MAX(event_version_id) AS latest_version FROM event_versions GROUP BY event_id ) latest_versions ON e.event_id = latest_versions.event_id INNER JOIN event_versions v ON v.event_id = latest_versions.event_id AND v.event_version_id = latest_versions.latest_version LEFT OUTER JOIN users u ON u.user_id = e.created_by_id LEFT OUTER JOIN users u2 ON u2.user_id = v.version_created_by_id WHERE e.calendar_id IN (?) AND v.status = 'PUBLIC' ORDER BY e.event_id`; const eventsRes = await conn.query(eventsQuery, [calendarsToFetch]); for (let row of eventsRes) { eventRows.push({ eventId: row.event_id, calendarId: row.calendar_id, uuid: row.uuid, name: row.name, description: row.description, startDateTime: row.start_datetime, endDateTime: row.end_datetime, createdDate: row.created_date, lastModifiedDate: row.version_created_at, location: row.location, createdBy: row.created_by_name, createdById: row.created_by_id, lastModifiedBy: row.last_modified_by_name, lastModifiedById: row.version_created_by_id, url: row.url, wholeDay: row.whole_day, repeatFrequency: row.repeat_frequency }); } return eventRows; } catch (err) { throw err; } finally { // Return connection await conn.end(); } }; /** * Returns all events for the given calendar for the admin UI (therefore includes admin relevant information and * ignores the calendar includes * @param calendarId */ export const getAllEventsAdmin = async (calendarId: number): Promise => { let conn = await NachklangCalendarDB.getConnection(); let eventRows: Event[] = []; try { const eventsQuery = ` SELECT e.calendar_id, e.uuid, e.created_date, e.created_by_id, u.full_name as created_by_name, u2.full_name as last_modified_by_name, v.* FROM events e INNER JOIN ( SELECT event_id, MAX(event_version_id) AS latest_version FROM event_versions GROUP BY event_id ) latest_versions ON e.event_id = latest_versions.event_id INNER JOIN event_versions v ON v.event_id = latest_versions.event_id AND v.event_version_id = latest_versions.latest_version LEFT OUTER JOIN users u ON u.user_id = e.created_by_id LEFT OUTER JOIN users u2 ON u2.user_id = v.version_created_by_id WHERE e.calendar_id = ? ORDER BY e.event_id`; const eventsRes = await conn.query(eventsQuery, calendarId); for (let row of eventsRes) { eventRows.push({ eventId: row.event_id, calendarId: row.calendar_id, uuid: row.uuid, name: row.name, description: row.description, startDateTime: row.start_datetime, endDateTime: row.end_datetime, createdDate: row.created_date, lastModifiedDate: row.version_created_at, location: row.location, createdBy: row.created_by_name, createdById: row.created_by_id, lastModifiedBy: row.last_modified_by_name, lastModifiedById: row.version_created_by_id, url: row.url, wholeDay: row.whole_day, repeatFrequency: row.repeat_frequency, status: row.status }); } return eventRows; } catch (err) { throw err; } finally { // Return connection await conn.end(); } }; /** * Create the given event in the database * @param event The event to create */ export const createEvent = async (event: Event): Promise => { let conn = await NachklangCalendarDB.getConnection(); try { let eventUUID = Guid.create().toString(); const eventsQuery = 'INSERT INTO events (calendar_id, uuid, created_by_id) VALUES (?,?,?) RETURNING event_id'; const eventsRes = await conn.execute(eventsQuery, [event.calendarId, eventUUID, event.createdById]); const versionQuery = 'INSERT INTO event_versions (event_id, name, description, start_datetime, end_datetime, whole_day, repeat_frequency, location, url, status, version_created_by_id) VALUES (?,?,?,?,?,?,?,?,?,?,?);' const versionRes = await conn.execute(versionQuery, [eventsRes[0].event_id, event.name, event.description, event.startDateTime, event.endDateTime, event.wholeDay, event.repeatFrequency, event.location, event.url, event.status, event.createdById]); await conn.commit(); return eventsRes[0].event_id; } catch (err) { await conn.rollback(); throw err; } finally { // Return connection await conn.commit(); await conn.end(); } }; /** * Update the given event in the database * @param event The event to update */ export const updateEvent = async (event: Event): Promise => { let conn = await NachklangCalendarDB.getConnection(); try { const versionQuery = 'INSERT INTO event_versions (event_id, name, description, start_datetime, end_datetime, whole_day, repeat_frequency, location, url, status, version_created_by_id) VALUES (?,?,?,?,?,?,?,?,?,?,?);' const versionRes = await conn.execute(versionQuery, [event.eventId, event.name, event.description, event.startDateTime, event.endDateTime, event.wholeDay, event.repeatFrequency, event.location, event.url, event.status, event.createdById]); await conn.commit(); return versionRes.affectedRows; } catch (err) { await conn.rollback(); throw err; } finally { // Return connection await conn.commit(); await conn.end(); } }; /** * Deletes the given event from the database * @param event The event to delete */ export const deleteEvent = async (event: Event): Promise => { let conn = await NachklangCalendarDB.getConnection(); try { const versionQuery = 'INSERT INTO event_versions (event_id, status, version_created_by_id) VALUES (?,?,?);' const versionRes = await conn.execute(versionQuery, [event.eventId, 'DELETED', event.createdById]); await conn.commit(); return versionRes.affectedRows === 1; } catch (err) { await conn.rollback(); throw err; } finally { // Return connection await conn.commit(); await conn.end(); } }; /** * Moves an event to the specified calendar * @param event The event to move. Has to have the target calendar set already. */ export const moveEvent = async (event: Event): Promise => { let conn = await NachklangCalendarDB.getConnection(); try { const eventQuery = 'UPDATE events SET calendar_id = ? WHERE event_id = ?'; const eventRes = await conn.execute(eventQuery, [event.calendarId, event.eventId]); await conn.commit(); return eventRes.affectedRows === 1; } catch (err) { await conn.rollback(); throw err; } finally { // Return connection await conn.commit(); await conn.end(); } } /** * Returns the next upcoming event for the given calendar * @param calendarId The calendar Id */ export const getNextUpcomingEvent = async (calendarId: number): Promise => { let conn = await NachklangCalendarDB.getConnection(); try { const calendarQuery = 'SELECT calendar_id, includes_calendars FROM calendars WHERE calendar_id = ?'; const calendarRes = await conn.query(calendarQuery, calendarId); let calendarsToFetch: number[] = [calendarId]; for(let row of calendarRes) { let includes: number[] = JSON.parse(row.includes_calendars); calendarsToFetch = [...calendarsToFetch, ...includes]; } const now = new Date(); const eventsQuery = ` SELECT e.calendar_id, e.uuid, e.created_date, e.created_by_id, u.full_name as created_by_name, u2.full_name as last_modified_by_name, v.* FROM events e INNER JOIN ( SELECT event_id, MAX(event_version_id) AS latest_version FROM event_versions GROUP BY event_id ) latest_versions ON e.event_id = latest_versions.event_id INNER JOIN event_versions v ON v.event_id = latest_versions.event_id AND v.event_version_id = latest_versions.latest_version LEFT OUTER JOIN users u ON u.user_id = e.created_by_id LEFT OUTER JOIN users u2 ON u2.user_id = v.version_created_by_id WHERE e.calendar_id IN (?) AND v.status = 'PUBLIC' AND v.start_datetime > ? ORDER BY v.start_datetime ASC LIMIT 1`; const eventsRes = await conn.query(eventsQuery, [calendarsToFetch, now]); if (eventsRes.length === 0) { return null; } const row = eventsRes[0]; return { eventId: row.event_id, calendarId: row.calendar_id, uuid: row.uuid, name: row.name, description: row.description, startDateTime: row.start_datetime, endDateTime: row.end_datetime, createdDate: row.created_date, lastModifiedDate: row.version_created_at, location: row.location, createdBy: row.created_by_name, createdById: row.created_by_id, lastModifiedBy: row.last_modified_by_name, lastModifiedById: row.version_created_by_id, url: row.url, wholeDay: row.whole_day, repeatFrequency: row.repeat_frequency } as Event; } catch (err) { throw err; } finally { // Return connection await conn.end(); } }