Workaround mozilla-comm/ical.js/issues/186, support events with times like "2019-11-12T::"

This commit is contained in:
Ben Gotow 2019-10-23 00:56:51 -05:00
parent 5847e82cef
commit b7017f10de
3 changed files with 44 additions and 25 deletions

View file

@ -69,25 +69,23 @@ export class EventHeader extends React.Component<EventHeaderProps, EventHeaderSt
fs.readFile(AttachmentStore.pathForFile(file), async (err, data) => {
if (err || !this._mounted) return;
const icsData = ICAL.parse(data.toString());
const icsRoot = new ICAL.Component(icsData);
const icsEvent = new ICAL.Event(icsRoot.getFirstSubcomponent('vevent'));
const { event, root } = CalendarUtils.parseICSString(data.toString());
this.setState({
icsEvent: icsEvent,
icsMethod: (icsRoot.getFirstPropertyValue('method') || 'request').toLowerCase(),
icsEvent: event,
icsMethod: (root.getFirstPropertyValue('method') || 'request').toLowerCase(),
icsOriginalData: data.toString(),
});
this._subscription = Rx.Observable.fromQuery(
DatabaseStore.findBy<Event>(Event, {
icsuid: icsEvent.uid,
icsuid: event.uid,
accountId: message.accountId,
})
).subscribe(calEvent => {
if (!this._mounted || !calEvent) return;
this.setState({
icsEvent: CalendarUtils.eventFromICSString(calEvent.ics),
icsEvent: CalendarUtils.parseICSString(calEvent.ics).event,
});
});
});

View file

@ -1,6 +1,10 @@
import ICAL from 'ical.js';
import { AccountStore } from 'mailspring-exports';
type ICALComponent = typeof import('ical.js').Component;
type ICALEvent = typeof import('ical.js').Event;
let ICAL: typeof import('ical.js') = null;
export type ICSParticipantStatus =
| 'NEEDS-ACTION'
| 'ACCEPTED'
@ -14,13 +18,38 @@ export interface ICSParticipant {
email: string | null;
role: 'CHAIR' | 'REQ-PARTICIPANT' | 'OPT-PARTICIPANT' | 'NON-PARTICIPANT';
status: ICSParticipantStatus;
component: ICAL.Component;
component: ICALComponent;
}
export function eventFromICSString(ics: string) {
function fixJCalDatesWithoutTimes(jCal) {
jCal[1].forEach(property => {
if (
property[0] === 'dtstart' ||
property[0] === 'dtend' ||
property[0] === 'exdate' ||
property[0] === 'rdate'
) {
if (!property[1].value && property[2] === 'date-time' && /T::$/.test(property[3])) {
property[2] = 'date';
property[3] = property[3].replace(/T::$/, '');
}
}
});
jCal[2].forEach(fixJCalDatesWithoutTimes);
}
export function parseICSString(ics: string) {
if (!ICAL) {
ICAL = require('ical.js');
}
const jcalData = ICAL.parse(ics);
const comp = new ICAL.Component(jcalData);
return new ICAL.Event(comp.name === 'vevent' ? comp : comp.getFirstSubcomponent('vevent'));
// workaround https://github.com/mozilla-comm/ical.js/issues/186
fixJCalDatesWithoutTimes(jcalData);
const root = new ICAL.Component(jcalData);
const event = new ICAL.Event(root.name === 'vevent' ? root : root.getFirstSubcomponent('vevent'));
return { root, event };
}
export function emailFromParticipantURI(uri: string) {
@ -33,7 +62,7 @@ export function emailFromParticipantURI(uri: string) {
return null;
}
export function cleanParticipants(icsEvent: ICAL.Event): ICSParticipant[] {
export function cleanParticipants(icsEvent: ICALEvent): ICSParticipant[] {
return icsEvent.attendees.map(a => ({
component: a,
status: a.getParameter('partstat'),
@ -46,7 +75,7 @@ export function cleanParticipants(icsEvent: ICAL.Event): ICSParticipant[] {
}
export function selfParticipant(
icsEvent: ICAL.Event,
icsEvent: ICALEvent,
accountId: string
): ICSParticipant | undefined {
const me = cleanParticipants(icsEvent).find(a => {

View file

@ -11,8 +11,6 @@ import {
Actions,
} from 'mailspring-exports';
let ICAL: typeof import('ical.js') = null;
export class EventRSVPTask extends Task {
ics: string;
icsRSVPStatus: ICSParticipantStatus;
@ -57,18 +55,12 @@ export class EventRSVPTask extends Task {
icsOriginalData: string;
icsRSVPStatus: ICSParticipantStatus;
}) {
if (!ICAL) {
ICAL = require('ical.js');
}
const jcalData = ICAL.parse(icsOriginalData);
const comp = new ICAL.Component(jcalData);
const event = new ICAL.Event(comp.getFirstSubcomponent('vevent'));
const { event, root } = CalendarUtils.parseICSString(icsOriginalData);
const me = CalendarUtils.selfParticipant(event, accountId);
me.component.setParameter('partstat', icsRSVPStatus);
comp.updatePropertyWithValue('method', 'REPLY');
root.updatePropertyWithValue('method', 'REPLY');
const icsReplyData = comp.toString();
const icsReplyData = root.toString();
return new EventRSVPTask({
to,