Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix event time with timezone #1231

Merged
merged 4 commits into from Sep 10, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions server/services/caldav/index.js
Expand Up @@ -11,12 +11,16 @@ module.exports = function CalDAVService(gladys, serviceId) {
const duration = require('dayjs/plugin/duration');
const advancedFormat = require('dayjs/plugin/advancedFormat');
const isBetween = require('dayjs/plugin/isBetween');
const utc = require('dayjs/plugin/utc');
const timezone = require('dayjs/plugin/timezone');
const xmlDom = require('xmldom');

dayjs.extend(objectSupport);
dayjs.extend(duration);
dayjs.extend(advancedFormat);
dayjs.extend(isBetween);
dayjs.extend(utc);
dayjs.extend(timezone);

const calDavHandler = new CalDAVHandler(gladys, serviceId, ical, dav, dayjs, xmlDom);

Expand Down
32 changes: 21 additions & 11 deletions server/services/caldav/lib/calendar/calendar.formaters.js
Expand Up @@ -8,15 +8,18 @@
* formatRecurringEvents(event, gladysCalendar)
*/
function formatRecurringEvents(event, gladysCalendar) {
let startDate = this.dayjs(event.start);
const { tz } = event.start;
let startDate = this.dayjs.tz(this.dayjs(event.start).format('YYYY-MM-DDTHH:mm:ss'), tz);
let endDate;

if (event.end) {
endDate = this.dayjs(event.end);
endDate = this.dayjs.tz(this.dayjs(event.end).format('YYYY-MM-DDTHH:mm:ss'), tz);
} else if (event.duration) {
endDate = this.dayjs(event.start).add(this.dayjs.duration(event.duration));
endDate = this.dayjs
.tz(this.dayjs(event.start).format('YYYY-MM-DDTHH:mm:ss'), tz)
.add(this.dayjs.duration(event.duration));
} else {
endDate = this.dayjs(event.start).add(1, 'days');
endDate = this.dayjs.tz(this.dayjs(event.start).format('YYYY-MM-DDTHH:mm:ss'), tz).add(1, 'days');
}

// Calculate the duration of the event for use with recurring events.
Expand Down Expand Up @@ -49,8 +52,7 @@ function formatRecurringEvents(event, gladysCalendar) {
let curEvent = event;
let showRecurrence = true;
let curDuration = duration;

startDate = this.dayjs(date);
startDate = this.dayjs.tz(this.dayjs(date).format('YYYY-MM-DDTHH:mm:ss'), tz);

// Use just the date of the recurrence to look up overrides and exceptions (i.e. chop off time information)
const dateLookupKey = date.toISOString().substring(0, 10);
Expand All @@ -60,7 +62,7 @@ function formatRecurringEvents(event, gladysCalendar) {
// We found an override, so for this recurrence, use a potentially different title,
// start date, and duration.
curEvent = curEvent.recurrences[dateLookupKey];
startDate = this.dayjs(curEvent.start);
startDate = this.dayjs.tz(this.dayjs(curEvent.start).format('YYYY-MM-DDTHH:mm:ss'), tz);
curDuration = parseInt(this.dayjs(curEvent.end).format('x'), 10) - parseInt(startDate.format('x'), 10);
if (curEvent.status === 'CANCELLED') {
showRecurrence = false;
Expand All @@ -75,6 +77,10 @@ function formatRecurringEvents(event, gladysCalendar) {
// Set the the title and the end date from either the regular event or the recurrence override.
const recurrenceTitle = curEvent.summary;
endDate = this.dayjs(parseInt(startDate.format('x'), 10) + curDuration, 'x');
endDate = this.dayjs.tz(
this.dayjs(parseInt(startDate.format('x'), 10) + curDuration, 'x').format('YYYY-MM-DDTHH:mm:ss'),
tz,
);

// If this recurrence ends before the start of the date range, or starts after the end of the date range,
// don't process it.
Expand All @@ -101,8 +107,8 @@ function formatRecurringEvents(event, gladysCalendar) {
endDate = endDate.set({ hour: 0, minute: 0, second: 0, millisecond: 0 });
}

newEvent.start = startDate.toISOString();
newEvent.end = endDate.toISOString();
newEvent.start = startDate.format();
newEvent.end = endDate.format();

return newEvent;
}
Expand Down Expand Up @@ -138,11 +144,15 @@ function formatEvents(caldavEvents, gladysCalendar) {
};

if (caldavEvent.start) {
newEvent.start = caldavEvent.start.toISOString();
newEvent.start = this.dayjs
.tz(this.dayjs(caldavEvent.start).format('YYYY-MM-DDTHH:mm:ss'), caldavEvent.start.tz)
.format();
}

if (caldavEvent.end) {
newEvent.end = caldavEvent.end.toISOString();
newEvent.end = this.dayjs
.tz(this.dayjs(caldavEvent.end).format('YYYY-MM-DDTHH:mm:ss'), caldavEvent.end.tz)
.format();
}

if (
Expand Down
52 changes: 28 additions & 24 deletions server/test/services/caldav/lib/calendar/formaters.test.js
Expand Up @@ -29,6 +29,10 @@ dayjsUTCOverride.duration = function duration(number) {
return dayjs.duration(number);
};

dayjsUTCOverride.tz = function tz(date, timezoneValue) {
return dayjs.utc(date);
};

describe('CalDAV formaters', () => {
let caldavCalendars;
let expectedCalendars;
Expand Down Expand Up @@ -129,8 +133,8 @@ describe('CalDAV formaters', () => {
selector: 'e52c11e3-af8a-48c7-9f54-de7aba373c46',
name: 'Event 1',
location: 'Paris',
start: '2019-02-25T10:00:00.000Z',
end: '2019-02-25T12:00:00.000Z',
start: '2019-02-25T10:00:00+00:00',
end: '2019-02-25T12:00:00+00:00',
calendar_id: '1fe8f557-2685-4b6b-8f05-238184f6b701',
url: 'https://caldav.host/home/event1.ics',
},
Expand All @@ -139,8 +143,8 @@ describe('CalDAV formaters', () => {
selector: '71c01038-2231-4dee-a230-6820fdb1136e',
name: 'Event 2',
location: 'Toulouse',
start: '2019-04-01T00:00:00.000Z',
end: '2019-04-02T00:00:00.000Z',
start: '2019-04-01T00:00:00+00:00',
end: '2019-04-02T00:00:00+00:00',
full_day: true,
calendar_id: '1fe8f557-2685-4b6b-8f05-238184f6b701',
url: 'https://caldav.host/home/event2.ics',
Expand All @@ -152,8 +156,8 @@ describe('CalDAV formaters', () => {
location: 'Paris',
calendar_id: '1fe8f557-2685-4b6b-8f05-238184f6b701',
full_day: true,
start: '2019-09-27T00:00:00.000Z',
end: '2019-09-28T00:00:00.000Z',
start: '2019-09-27T00:00:00+00:00',
end: '2019-09-28T00:00:00+00:00',
url: 'https://caldav.host.com/home/recur-event2',
},
{
Expand All @@ -163,19 +167,19 @@ describe('CalDAV formaters', () => {
location: 'Paris',
calendar_id: '1fe8f557-2685-4b6b-8f05-238184f6b701',
full_day: true,
start: '2020-09-27T00:00:00.000Z',
end: '2020-09-28T00:00:00.000Z',
start: '2020-09-27T00:00:00+00:00',
end: '2020-09-28T00:00:00+00:00',
url: 'https://caldav.host.com/home/recur-event2',
},
{
calendar_id: '1fe8f557-2685-4b6b-8f05-238184f6b701',
end: '2021-09-28T00:00:00.000Z',
external_id: '29f76a08-5439-4e04-bc1f-a67c32b47c802021-09-27-00-00',
full_day: true,
location: 'Paris',
name: 'Anniversaire Pepper',
selector: '29f76a08-5439-4e04-bc1f-a67c32b47c802021-09-27-00-00',
start: '2021-09-27T00:00:00.000Z',
start: '2021-09-27T00:00:00+00:00',
end: '2021-09-28T00:00:00+00:00',
url: 'https://caldav.host.com/home/recur-event2',
},
];
Expand Down Expand Up @@ -280,8 +284,8 @@ describe('CalDAV formaters', () => {
name: 'Cours de tennis',
location: 'Stade Roland-Garros',
calendar_id: '1fe8f557-2685-4b6b-8f05-238184f6b701',
start: '2019-06-01T09:00:00.000Z',
end: '2019-06-01T12:00:00.000Z',
start: '2019-06-01T09:00:00+00:00',
end: '2019-06-01T12:00:00+00:00',
url: 'https://caldav.host.com/home/recur-event1',
},
null,
Expand All @@ -295,8 +299,8 @@ describe('CalDAV formaters', () => {
location: 'Paris',
calendar_id: '1fe8f557-2685-4b6b-8f05-238184f6b701',
full_day: true,
start: '2019-09-27T00:00:00.000Z',
end: '2019-09-28T00:00:00.000Z',
start: '2019-09-27T00:00:00+00:00',
end: '2019-09-28T00:00:00+00:00',
url: 'https://caldav.host.com/home/recur-event2',
},
{
Expand All @@ -306,8 +310,8 @@ describe('CalDAV formaters', () => {
location: 'Paris',
calendar_id: '1fe8f557-2685-4b6b-8f05-238184f6b701',
full_day: true,
start: '2020-09-27T00:00:00.000Z',
end: '2020-09-28T00:00:00.000Z',
start: '2020-09-27T00:00:00+00:00',
end: '2020-09-28T00:00:00+00:00',
url: 'https://caldav.host.com/home/recur-event2',
},
null,
Expand All @@ -319,8 +323,8 @@ describe('CalDAV formaters', () => {
name: 'Réunion Avengers',
location: 'Tour Stark',
calendar_id: '1fe8f557-2685-4b6b-8f05-238184f6b701',
start: '2019-06-10T09:00:00.000Z',
end: '2019-06-10T10:00:00.000Z',
start: '2019-06-10T09:00:00+00:00',
end: '2019-06-10T10:00:00+00:00',
url: 'https://caldav.host.com/home/recur-event3',
},
null,
Expand All @@ -330,8 +334,8 @@ describe('CalDAV formaters', () => {
name: 'Réunion Avengers, nouvel arrivant',
location: 'Tour Stark',
calendar_id: '1fe8f557-2685-4b6b-8f05-238184f6b701',
start: '2019-06-24T09:00:00.000Z',
end: '2019-06-24T10:00:00.000Z',
start: '2019-06-24T09:00:00+00:00',
end: '2019-06-24T10:00:00+00:00',
url: 'https://caldav.host.com/home/recur-event3',
},
],
Expand All @@ -342,8 +346,8 @@ describe('CalDAV formaters', () => {
name: 'Gouter',
location: 'Jardin',
calendar_id: '1fe8f557-2685-4b6b-8f05-238184f6b701',
start: '2019-06-20T16:00:00.000Z',
end: '2019-06-20T17:30:00.000Z',
start: '2019-06-20T16:00:00+00:00',
end: '2019-06-20T17:30:00+00:00',
url: 'https://caldav.host.com/home/recur-event4',
},
{
Expand All @@ -352,8 +356,8 @@ describe('CalDAV formaters', () => {
name: 'Gouter',
location: 'Jardin',
calendar_id: '1fe8f557-2685-4b6b-8f05-238184f6b701',
start: '2019-06-21T16:00:00.000Z',
end: '2019-06-21T17:30:00.000Z',
start: '2019-06-21T16:00:00+00:00',
end: '2019-06-21T17:30:00+00:00',
url: 'https://caldav.host.com/home/recur-event4',
},
],
Expand Down