Calendar import

This commit is contained in:
yflory 2021-04-15 17:45:38 +02:00
parent 8a7f5556c4
commit 6ced731600
4 changed files with 125 additions and 6 deletions

View file

@ -99,13 +99,12 @@ define([
'TRIGGER:'+str,
'END:VALARM'
]);
// XXX ACTION:EMAIL
// XXX ATTENDEE:mailto:xxx@xxx.xxx
// XXX SUMMARY:Alarm notification
});
}
// XXX add hidden data (from imports)
if (Array.isArray(data.cp_hidden)) {
Array.prototype.push.apply(ICS, data.cp_hidden);
}
ICS.push('END:VEVENT');
});
@ -115,6 +114,86 @@ define([
return new Blob([ ICS.join('\n') ], { type: 'text/calendar;charset=utf-8' });
};
module.import = function (content, id, cb) {
require(['/lib/ical.min.js'], function () {
var ICAL = window.ICAL;
var res = {};
try {
var jcalData = ICAL.parse(content);
var vcalendar = new ICAL.Component(jcalData);
} catch (e) {
return void cb(e);
}
var method = vcalendar.getFirstPropertyValue('method');
if (method !== "PUBLISH") { return void cb('NOT_SUPPORTED'); }
var events = vcalendar.getAllSubcomponents('vevent');
events.forEach(function (ev) {
var uid = ev.getFirstPropertyValue('uid');
if (!uid) { return; }
// Get start and end time
var isAllDay = false;
var start = ev.getFirstPropertyValue('dtstart');
var end = ev.getFirstPropertyValue('dtend');
if (start.isDate && end.isDate) {
isAllDay = true;
start = String(start);
end.adjust(-1); // Substract one day
end = String(end);
} else {
start = +start.toJSDate();
end = +end.toJSDate();
}
// Store other properties
var used = ['dtstart', 'dtend', 'uid', 'summary', 'location', 'dtstamp'];
var hidden = [];
ev.getAllProperties().forEach(function (p) {
if (used.indexOf(p.name) !== -1) { return; }
// This is an unused property
hidden.push(p.toICALString());
});
// Get reminders
var reminders = [];
ev.getAllSubcomponents('valarm').forEach(function (al) {
var action = al.getFirstPropertyValue('action');
if (action !== 'DISPLAY') {
// XXX email: maybe keep a notification in CryptPad?
hidden.push(al.toString());
return;
}
var trigger = al.getFirstPropertyValue('trigger');
var minutes = -trigger.toSeconds() / 60;
if (reminders.indexOf(minutes) === -1) { reminders.push(minutes); }
});
// Create event
res[uid] = {
calendarId: id,
id: uid,
category: 'time',
title: ev.getFirstPropertyValue('summary'),
location: ev.getFirstPropertyValue('location'),
isAllDay: isAllDay,
start: start,
end: end,
reminders: reminders,
cp_hidden: hidden
};
if (!hidden.length) { delete res[uid].cp_hidden; }
if (!reminders.length) { delete res[uid].reminders; }
});
cb(null, res);
});
};
return module;
});

View file

@ -107,6 +107,12 @@ Messages.calendar_allDay = "All day";
cb(null, obj);
});
};
var importICSCalendar = function (data, cb) {
APP.module.execCommand('IMPORT_ICS', data, function (obj) {
if (obj && obj.error) { return void cb(obj.error); }
cb(null, obj);
});
};
var newEvent = function (data, cb) {
APP.module.execCommand('CREATE_EVENT', data, function (obj) {
if (obj && obj.error) { return void cb(obj.error); }
@ -466,7 +472,21 @@ Messages.calendar_allDay = "All day";
},
content: h('span', Messages.importButton),
action: function (e) {
e.stopPropagation();
UIElements.importContent('text/calendar', function (res) {
Export.import(res, id, function (err, json) {
if (err) { return void UI.warn(Messages.importError); }
importICSCalendar({
id: id,
json: json
}, function (err) {
if (err) { return void UI.warn(Messages.error); }
UI.log(Messages.saved);
});
});
}, {
accept: ['.ics']
})();
return true;
}
});

View file

@ -127,7 +127,7 @@ define([
dcAlert = undefined;
};
var importContent = function (type, f, cfg) {
var importContent = UIElements.importContent = function (type, f, cfg) {
return function () {
var $files = $('<input>', {type:"file"});
if (cfg && cfg.accept) {

View file

@ -434,6 +434,22 @@ ctx.calendars[channel] = {
});
};
var importICSCalendar = function (ctx, data, cId, cb) {
var id = data.id;
var c = ctx.calendars[id];
if (!c || !c.proxy) { return void cb({error: "ENOENT"}); }
var json = data.json;
c.proxy.content = c.proxy.content || {};
Object.keys(json).forEach(function (uid) {
c.proxy.content[uid] = json[uid];
});
Realtime.whenRealtimeSyncs(c.lm.realtime, function () {
sendUpdate(ctx, c);
cb();
});
};
var openCalendar = function (ctx, data, cId, cb) {
var secret = Hash.getSecrets('calendar', data.hash, data.password);
var hash = Hash.getEditHashFromKeys(secret);
@ -785,6 +801,10 @@ ctx.calendars[channel] = {
if (ctx.store.offline) { return void cb({error: 'OFFLINE'}); }
return void importCalendar(ctx, data, clientId, cb);
}
if (cmd === 'IMPORT_ICS') {
if (ctx.store.offline) { return void cb({error: 'OFFLINE'}); }
return void importICSCalendar(ctx, data, clientId, cb);
}
if (cmd === 'ADD') {
if (ctx.store.offline) { return void cb({error: 'OFFLINE'}); }
return void addCalendar(ctx, data, clientId, cb);