Skip to content

Commit

Permalink
Fix issue with exceptions in recurrent events
Browse files Browse the repository at this point in the history
  • Loading branch information
lme committed Dec 28, 2018
1 parent c649b54 commit d5d289c
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 61 deletions.
15 changes: 14 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
},
"dependencies": {
"clone": "^2.1.1",
"ical-expander": "^2.0.0",
"moment": "^2.22.1",
"node-ical": "^0.5.4",
"relative-time-parser": "^1.0.9",
Expand Down
85 changes: 33 additions & 52 deletions src/CalendarActionBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,67 +28,45 @@ class CalendarActionBuilder {
allEvents = this._sortEventsByDate(allEvents);
allEvents = this._filterExpiredEvents(allEvents, now);

console.log(JSON.stringify(allEvents));

return allEvents;
}

_generateNonRecurringEvents(cal) {
const events = [];

for (const key in cal) {
if (cal.hasOwnProperty(key)) {
const event = cal[key];
if (event.type === 'VEVENT' && event.rrule === undefined) {
events.push({
date: moment(event.start).relativeTime(this._startOffset).toDate(),
expires: event.end,
state: true,
summary: event.summary
});
events.push({
date: event.end,
expires: event.end,
state: false,
summary: event.summary
});
}
}
}

const events = [].concat(cal.events.map(e => ({
date: moment(e.startDate.toJSDate()).relativeTime(this._startOffset).toDate(),
expires: e.endDate.toJSDate(),
state: true,
summary: e.summary
})),
cal.events.map(e => ({
date: e.endDate.toJSDate(),
expires: e.endDate.toJSDate(),
state: false,
summary: e.summary
}))
);

return events;
}

_generateRecurringEvents(cal, now) {
const events = [];

for (const key in cal) {
if (cal.hasOwnProperty(key)) {
const event = cal[key];
if (event.type === 'VEVENT' && event.rrule !== undefined) {
const duration = event.end - event.start;

const rstart = now.clone().subtract(2 * duration, 'milliseconds').toDate();
const rend = now.clone().add(7, 'days').toDate();

const expandedStartDates = event.rrule.between(rstart, rend, true);

for (const startDate of expandedStartDates) {
const endDate = new Date(startDate.valueOf() + duration);
events.push({
date: moment(startDate).relativeTime(this._startOffset).toDate(),
expires: endDate,
state: true,
summary: event.summary
});
events.push({
date: endDate,
expires: endDate,
state: false,
summary: event.summary
});
}
}
}
}

const events = [].concat(cal.occurrences.map(e => ({
date: moment(e.startDate.toJSDate()).relativeTime(this._startOffset).toDate(),
expires: e.endDate.toJSDate(),
state: true,
summary: e.summary
})),
cal.occurrences.map(e => ({
date: e.endDate.toJSDate(),
expires: e.endDate.toJSDate(),
state: false,
summary: e.summary
}))
);

return events;
}
Expand All @@ -99,6 +77,9 @@ class CalendarActionBuilder {
}

_filterExpiredEvents(events, now) {

console.log(now);

// Keep only events that expire right now or in the future
return events.filter(event => event.expires.valueOf() >= now);
}
Expand Down
73 changes: 65 additions & 8 deletions src/CalendarPoller.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
'use strict';

const EventEmitter = require('events').EventEmitter;

const ical = require('node-ical');
const IcalExpander = require('ical-expander');
const https = require('https');
const fs = require('fs');

class CalendarPoller extends EventEmitter {

Expand All @@ -12,7 +13,7 @@ class CalendarPoller extends EventEmitter {
this.log = log;
this.name = name;

this._url = url.replace('webcal://', 'http://');
this._url = url.replace('webcal://', 'https://');
this._interval = interval;
this._isStarted = false;
}
Expand All @@ -38,18 +39,53 @@ class CalendarPoller extends EventEmitter {
_loadCalendar() {
// TODO: Make use of HTTP cache control stuff
this.log(`Updating calendar ${this.name}`);
ical.fromURL(this._url, {}, (err, cal) => {

https.get(this._url, (resp) => {

resp.setEncoding('utf8');
let data = '';

// A chunk of data has been recieved.
resp.on('data', (chunk) => {
data += chunk;
});

// The whole response has been received. Print out the result.
resp.on('end', () => {
fs.writeFileSync('./data.ics', data);
this._refreshCalendar();
});

}).on("error", (err) => {

if (err) {
this.log(`Failed to load iCal calender: ${this.url} with error ${err}`);
this.emit('error', err);
}

if (cal) {
this.emit('data', cal);
}
});
}

_refreshCalendar() {

this._scheduleNextIteration();
const ics = fs.readFileSync('./data.ics', 'utf-8');
const icalExpander = new IcalExpander({
ics,
maxIterations: 1000
});

const duration = 7; // days
var now = new Date();
var next = new Date(now.getTime() + duration * 24 * 60 * 60 * 1000)

const cal = icalExpander.between(now, next);
this._printEvent(cal);

if (cal) {
this.emit('data', cal);
}

this._scheduleNextIteration();
}

_scheduleNextIteration() {
Expand All @@ -62,6 +98,27 @@ class CalendarPoller extends EventEmitter {
this._loadCalendar();
}, this._interval);
}

_printEvent(events) {

const mappedEvents = events.events.map(e => ({
startDate: e.startDate,
endDate: e.endDate,
summary: e.summary
}));

const mappedOccurrences = events.occurrences.map(o => ({
startDate: o.startDate,
endDate: o.endDate,
summary: o.item.summary
}));

const allEvents = [].concat(mappedEvents, mappedOccurrences);

console.log(allEvents.map(e => `${e.startDate.toJSDate().toISOString()} to ${e.endDate.toJSDate().toISOString()} - ${e.summary}`).join('\n'));


}
}

module.exports = CalendarPoller;

0 comments on commit d5d289c

Please sign in to comment.