const clouds = { KLUB_RESEAU: 'klub-reseau', ELEVES_ENS: 'eleves-ens' } const calendars = { '5WrcagPPARQ3BD87': { cloud: clouds.KLUB_RESEAU, name: 'Club réseau', color: null }, TFEAKjAgNFQZpNjo: { cloud: clouds.KLUB_RESEAU, name: 'hackENS', color: null }, LLWm8qK9iC5YGrrR: { cloud: clouds.ELEVES_ENS, name: 'Délégation Générale', short_name: 'DG', color: null }, w442JdS5AaQ6czrP: { cloud: clouds.ELEVES_ENS, name: "Écriv'ENS", color: null, } } const calendarsByName = Object.fromEntries( Object.entries(calendars).map(([id, {name}]) => ([name, id])) ); export const calendarTree = { 'Clubs COF': { 'Club réseau': {}, hackENS: {}, "Écriv'ENS": {} }, COF: { BDA: { Philharmonie: {} }, AG: {} }, BDS: {}, 'Délégation Générale': {} } const calendarIds = Object.keys(calendars) function mkCalendarUrl(id, { cloud }, extra={}) { return `/cal/${cloud}/${id}/?` + new URLSearchParams({ ...extra, export: true, expand: true, accept: 'jcal' }); } function fetchCalendar(id, cal, extra={}) { return fetch(mkCalendarUrl(id, cal, extra), { credentials: 'omit' }) .then(resp => resp.json()) .catch(err => console.error(err)) } class Calendar { constructor(id, calendar) { const metadata = calendars[id] this.name = metadata.name this.short_name = metadata.short_name this.color = metadata.color || calendar[1][4][3] this.events = calendar[2] .filter(item => item[0] === 'vevent') .map(item => this._parse_vevent(item[1])) } _parse_vevent(vevent) { const event = {} vevent.forEach(elt => { event[elt[0]] = elt[3] }) return event } } function fcEventFromjCalEvent(cal) { return function (evt) { const start = new Date(evt.dtstart) const end = new Date(evt.dtend) const fcEvent = { title: `${cal.short_name ?? cal.name} : ${evt.summary}`, start: evt.dtstart, end: evt.dtend, color: cal.color, duration: end - start // in ms } fcEvent.calendar = cal.name fcEvent.short_name = evt.summary if (evt.description) { fcEvent.description = evt.description } if (evt.location) { fcEvent.location = evt.location } if (evt.rrule) { const { freq, byday, interval } = evt.rrule fcEvent.rrule = { freq, byweekday: byday, dtstart: evt.dtstart } if (interval) { fcEvent.rrule.interval = interval } } return fcEvent } } function mkEventsFromCalendar(id, cal) { return fetchCalendar(id, cal).then(calendar => { if (calendar[0] !== 'vcalendar') return const cal = new Calendar(id, calendar) return cal.events.map(fcEventFromjCalEvent(cal)) }) } export function mkSource(name) { const calendarId = calendarsByName[name]; if (!calendarId) return null; const calendar = calendars[calendarId]; return { id: name, ...(calendar?.meta || {}), success: calendarData => { if (calendarData[0] !== 'vcalendar') return; const cal = new Calendar(calendarId, calendarData); return cal.events.map(fcEventFromjCalEvent(cal)); }, failure: error => { console.error(`Fatal error during event source fetching of '${name}': ${error}`); }, events: (info, successCallback, failureCallback) => { const { start, end } = info; fetchCalendar(calendarId, calendar, { start: start.valueOf() / 1000, end: end.valueOf() / 1000 }) .then(successCallback, failureCallback); } } }