Name

sn_cd.cd_DownloadICS

Description

API to download an ICS file

Script

gs.include("sn_ex_emp_fd.eef_VTimezone");

var cd_DownloadICS = Class.create();

cd_DownloadICS.prototype = {
  initialize: function(request, response, processor) {
  	this.processor = processor;
  	this.request = request;
  	this.response = response;
  	this.type = this.request.getParameter("sysparm_type");
  	this.spInstanceId = this.request.getParameter("sysparm_sp_instance_id");
  	this.dateLogic =  new sn_cd.cd_IcsDateLogic();
  	if (this.type === "holiday") {
  		this.year = this.request.getParameter("sysparm_year");
  		this.calendar = this.request.getParameter("sysparm_calendar");
  	} else {
  		this.sys_id = this.request.getParameter("sysparm_sys_id");
  		if (this.sys_id === "null")
  			this.sys_id = null;
  	}
  	this.icsString = '';
  	this.events = [];
  },

  process: function() {
  	this.response.setContentType("text/calendar; charset=UTF-8");
  	if (this.type === "holiday") {
  		this._downloadHolidayICS(this.year, this.calendar);
  		this.response.setHeader("Content-Disposition", "inline; filename=Holidays_" + this.year + ".ics");
  		this.processor.writeOutput(this.icsString);
  	} else if (this.sys_id == null) {
  		this._downloadEventICS();
  		this.response.setHeader("Content-Disposition", "inline; filename=All_Upcoming_Events.ics");
  		this.processor.writeOutput(this.icsString);
  	} else {
  		this._downloadEventICS(this.sys_id);
  		if (this.events.length > 0) {
  			var eventName = this.events[0].name.replace(/ /g, '_') + ".ics";
  			eventName = eventName.replace(/,/, '_');
  			this.response.setHeader("Content-Disposition", "inline; filename=" + eventName);
  			this.processor.writeOutput(this.icsString);
  		}
  	}
  },
  
  /**
  * build holiday calendar events
  * @param year String
  * @param calendarId String sys_id of a calendar
  **/
  _downloadHolidayICS: function(year, calendarId) {
  	var calendars = cd_ContentDelivery.getPortalContentByScheduleId(calendarId);
  	if (!calendars.length)
  		return;

  	var firstCalendar = calendars[0];
  	var grCalendar = new GlideRecord("cmn_schedule");

  	if (!grCalendar.get(firstCalendar.schedule)) 
  		return;

  	var start = new GlideDateTime();
  	var end = new GlideDateTime();
  	
  	end.setMonthLocalTime(12);
  	end.setDayOfMonthLocalTime(31); // end of this year

  	if (year !== new GlideDateTime().getYearUTC().toString()) {
  		start.addYearsLocalTime(1);
  		start.setMonthLocalTime(1);
  		start.setDayOfMonthLocalTime(1); // Jan 1st next year
  		end.addYearsLocalTime(1); // end of next year
  	}
  	this._buildHolidayCalendarEvents(grCalendar, start, end);
  },

  _buildHolidayCalendarEvents: function(schedule, start, end) {
  	var timeSpans;
  	var i;
  	var dateTime;
  	var calStartEventTime;
  	var calEndEventTime;
  	var gdtEndTime;

  	var timeSpan = new GlideRecord('cmn_schedule_span');
  	timeSpan.addQuery('schedule', schedule.sys_id);
  	timeSpan.query();
  	while (timeSpan.next()) {
  		var spanTZ;
  
  		// if the time zone is not floating, use span from the associated schedule
  		// if the time zone is floating, use the session's time zone
  		if (timeSpan.schedule && timeSpan.schedule.time_zone)
  			spanTZ = timeSpan.schedule.time_zone;
  		else  
  			spanTZ = gs.getSession().getTimeZoneName();
  		var scheduleSpan = new GlideScheduleTimeSpan(timeSpan, spanTZ);
  		timeSpans = scheduleSpan.getSpans(new GlideScheduleDateTime(start), new GlideScheduleDateTime(end));
  		
  		for (i = 0; i < timeSpans.length; i += 1) {
  			dateTime = timeSpans[i].getStart().getGlideDateTime();
  			calStartEventTime = sn_ex_emp_fd.eef_VTimezone.generateDateTime(dateTime);
  			gdtEndTime = new GlideDateTime(dateTime);
  			gdtEndTime.addDaysLocalTime(1);
  			calEndEventTime = sn_ex_emp_fd.eef_VTimezone.generateDateTime(gdtEndTime);
  			this.events.push({
  				name: scheduleSpan.getName(),
  				calStartTime: calStartEventTime,
  				calEndTime: calEndEventTime
  			});
  		}
  	}

  	var tzString = sn_ex_emp_fd.eef_VTimezone.generateVTimezone(calStartEventTime, calEndEventTime);
  	this.icsString = "BEGIN:VCALENDAR\n" +
  		"VERSION:2.0\n" +
  		"CALSCALE:GREGORIAN\n";
  	this.icsString += tzString;
  	this._createEventDownload();
  	this.icsString += "END:VCALENDAR";
  },

  _downloadEventICS: function(eventContentId) {
  	var contentArray;
  	var startDateTime;
  	var calStartTime;
  	var calEndTime;
  	var endDateTime;
  	var title;
  	var i;
  	var cleanEventText;
  	var cleanEventTextRich;
  	var regex;

  	if (eventContentId)
  		contentArray = cd_ContentDelivery.getPortalContentById(eventContentId);
  	else
  		contentArray = cd_ContentDelivery.getContentForWidgetInstance(this.spInstanceId);

  	regex = /(<([^>]+)>)/ig;

  	for (i = 0; i < contentArray.length; i += 1) {

  		startDateTime = new GlideDateTime(contentArray[i].event_start);
  		calStartTime = sn_ex_emp_fd.eef_VTimezone.generateDateTime(startDateTime);
  		endDateTime = new GlideDateTime(contentArray[i].event_end);
  		calEndTime = sn_ex_emp_fd.eef_VTimezone.generateDateTime(endDateTime);
  		title = contentArray[i].title;

  		// if there is rich text, use that as event details
  		if (contentArray[i].rich_text) {
  			cleanEventText = contentArray[i].rich_text.replace(regex, "\\n");
  			cleanEventText = cleanEventText.replace(/&nbsp;/g, '');
  			cleanEventText = cleanEventText.replace(/(?:\r\n|\r|\n)/g, '');
  			
  			cleanEventTextRich = contentArray[i].rich_text.replace(/&nbsp;/g, '');
  			cleanEventTextRich = cleanEventTextRich.replace(/(?:\r\n|\r|\n)/g, '');
  		}

  		this.events.push({
  			calStartTime: calStartTime,
  			calEndTime: calEndTime,
  			name: title,
  			sysID: contentArray[i].sys_id,
  			event_details: cleanEventText,
  			event_details_rich: cleanEventTextRich
  		});
  	}

  	var tzString = sn_ex_emp_fd.eef_VTimezone.generateVTimezone(calStartTime, calEndTime);
  	this.icsString = "BEGIN:VCALENDAR\r\n" +
              "PRODID:-//Service-now.com//Outlook 11.0 MIMEDIR//EN\r\n" +
              "VERSION:2.0\r\n" +
              "CALSCALE:GREGORIAN\r\n";
  	this.icsString += tzString;
  	this._createEventDownload();
  	this.icsString += "END:VCALENDAR";
  },

  _createEventDownload: function() {
  	var event;
  	var i;
  	
  	var nowDateTime = new GlideDateTime();
  	var dateTimeStamp = sn_ex_emp_fd.eef_VTimezone.generateDateTime(nowDateTime);
  	var MAX_LENGTH = 70;

  	for (i = 0; i < this.events.length; i += 1) {
  		var event_details = this.events[i].event_details ? this._wordWrap("DESCRIPTION:" + this.events[i].event_details, MAX_LENGTH) : "DESCRIPTION:";
  		var event_details_rich = this.events[i].event_details_rich ? this._wordWrap("X-ALT-DESC;FMTTYPE=text/html:" + this.events[i].event_details_rich, MAX_LENGTH) + "\r\n" : "";
  		if (event_details_rich) event_details = this._wordWrap("DESCRIPTION:" + this.events[i].event_details_rich, MAX_LENGTH);
  		event = 
  			"BEGIN:VEVENT\r\n" +
  			"SUMMARY:" + this.events[i].name + "\n" +
  			"DTSTART:" + this.events[i].calStartTime + "\r\n" +
  			"DTEND:" + this.events[i].calEndTime + "\r\n" +
  			"DTSTAMP:" + dateTimeStamp + "\r\n" +
  			"UID:" + this.events[i].sysID + "\r\n" +
  			event_details + "\r\n" +
  			event_details_rich +
  			"STATUS:CONFIRMED\n" +
  			"SEQUENCE:3\n" +
  			"BEGIN:VALARM\n" +
  			"TRIGGER:-PT10M\n" +
  			"DESCRIPTION:Pickup Reminder\n" +
  			"ACTION:DISPLAY\n" +
  			"END:VALARM\n" +
  			"END:VEVENT\n";

  		this.icsString += event;
  	}
  },

  _wordWrap: function(text, wrap) {
  	var str = text;
  	for (var i = 0; i + wrap < str.length; i += wrap)
  		str = str.substring(0, i + wrap).concat("\r\n\t", str.substring(i + wrap, str.length));
  	return str;
  },

  type: 'cd_DownloadICS'
};

Sys ID

40ead7443b230300d901655593efc4fa

Offical Documentation

Official Docs: