Exporting ICS calendar using endpoint

Hello,

In our company, we have an internal system where employees request (and get approved) their vacation. Internal system provides data about approved vacations across teams.

Requirement

Export all vacations into a single calendar, that can be subscribed by my cell phone

Solution

Integray provides more solutions. You can use for example ICS Writer Connector to produce ICS content, but i chose easier way (although it required some Javascript coding)

  1. Create Task with following steps
    1. Load vacation data from internal system
    2. Transform data into ICS format
  2. Bind such task to Integray Endpoint using GET method
  3. Copy endpoint URL and subscribe to it in any calendar application

Task

First step of this task pretty much depends on our internal system’s ability to provide data and it’s detail is out of scope of this solution

As a second step I used Node.js processor to transform vacations into ICS format and produce Endpoint File Output output schema.

// loaded from previous step
const loaded = inputData[0].ContentJSON;
/*
loaded data is returned from internal system and contains array of vacations in following schema
[
   {
      "start": "2023-11-01T14:27:23.130Z", // vacation start date
      "end": "2023-11-01T14:27:23.130Z", // vacation end date
      "title": "Libor Zoubek", // employee name
   }
]
*/

/**
* format date to ICS date
*/
function formatDateToICal(date) {
  date = new Date(date);
  const year = date.getUTCFullYear();
  const month = String(date.getUTCMonth() + 1).padStart(2, '0'); // Months are zero-based
  const day = String(date.getUTCDate()).padStart(2, '0');
  const hours = String(date.getUTCHours()).padStart(2, '0');
  const minutes = String(date.getUTCMinutes()).padStart(2, '0');
  const seconds = String(date.getUTCSeconds()).padStart(2, '0');

  return `${year}${month}${day}T${hours}${minutes}${seconds}Z`;
}

// transform vacations into ICS events
const events = loaded.map((e) => {
  const now = formatDateToICal(new Date());
  // each event must have some uniqueID, as our system does not expose it
  // it should be sufficient to calculate hash from `start`,`end` and `title`
  const hash = crypto.createHash('sha256');
  hash.update(`${e.start}${e.end}${e.title}`);
  return `BEGIN:VEVENT
DTSTART:${formatDateToICal(e.start)}
DTEND:${formatDateToICal(e.end)}
DTSTAMP:${now}
UID:${hash.digest('hex')}
CREATED:${now}
LAST-MODIFIED:${now}
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:${e.title} - Vacation
TRANSP:OPAQUE
END:VEVENT
  `;
})

// create ICS text content
const ics = `
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:Integray team
X-WR-TIMEZONE:Europe/Prague
X-WR-CALDESC:Integray team vacation
BEGIN:VTIMEZONE
TZID:Europe/Prague
X-LIC-LOCATION:Europe/Prague
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:CEST
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:CET
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
${events.join('\n')}
END:VCALENDAR
`;
// return as `Endpoint File Output` schema
return [{ Name: 'calendar.ics', Data: Buffer.from(ics).toString('base64') }]

Endpoint

Endpoint binding is easy to do, the only important thing is to select Endpoint File Output output schema

Voila … I am subscribed to vacations of all team members :heart_eyes:

1 Like