Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@coozzy/cal-dav

Package Overview
Dependencies
Maintainers
3
Versions
87
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@coozzy/cal-dav - npm Package Compare versions

Comparing version 2.4.5 to 2.4.6

20

dist/index.d.ts

@@ -5,13 +5,13 @@ import * as ICAL from 'ical.js';

import { Attendee, Alarm } from './lib/types';
import { EventWithExceptions } from 'ical.js';
import { EventFrequencyCalendarService } from '../types/calendar';
export interface CalDavClient {
getEventByUrl(eventUrl: string): Promise<ICAL.Event | undefined>;
getEventByUid(eventUid: string): Promise<ICAL.Event | undefined>;
getEventOccurrencesByUrl(eventUrl: string, startDate: Date, endDate: Date): Promise<ICAL.EventOccurrence[] | undefined>;
getEventsByEventUid(eventUid: string, startDate?: Date, endDate?: Date): Promise<ICAL.EventOccurrence[] | undefined>;
deleteEvent(eventUid: string): Promise<void>;
listAllEvents(): Promise<ICAL.Event[]>;
createEvent(eventUrl: string, id: string, title: string, description: string, location: string, startDate: ICAL.TimeJsonData, endDate: ICAL.TimeJsonData, attendees: Attendee[], categories: string[], organizerEmail: string, prodid: string, privateEvent: boolean, frequencyInterval?: string, endDateFrequency?: ICAL.TimeJsonData, countFrequency?: number, alarms?: Alarm[]): Promise<void>;
updateEvent(eventUrl: string, event: ICAL.Event, title: string, description: string, location: string, startDate: ICAL.TimeJsonData, endDate: ICAL.TimeJsonData, attendees: Attendee[], categories: string[], organizerEmail: string, prodid: string, privateEvent: boolean, exceptionEventId?: number, frequencyInterval?: string, endDateFrequency?: ICAL.TimeJsonData, countFrequency?: number, alarms?: Alarm[]): Promise<void>;
deleteOccurrenceEvent(eventUrl: string, event: ICAL.Event, exceptionEventId: number, prodid: string): Promise<void>;
listEventsInTimeRange(startDate: Date, endDate?: Date): Promise<ICAL.EventWithExceptions[]>;
updateEvent(eventUrl: string, event: ICAL.Event, title: string, description: string, location: string, startDate: ICAL.TimeJsonData, endDate: ICAL.TimeJsonData, attendees: Attendee[], categories: string[], organizerEmail: string, prodid: string, privateEvent: boolean, occurrenceEventId?: number, frequencyInterval?: string, endDateFrequency?: ICAL.TimeJsonData, countFrequency?: number, alarms?: Alarm[]): Promise<void>;
deleteOccurrenceEvent(eventUrl: string, event: ICAL.Event, occurrenceEventId: number, prodid: string): Promise<void>;
listEventsInTimeRange(startDate: Date, endDate?: Date): Promise<ICAL.EventOccurrence[]>;
multiGetEvents(eventUrls: string[]): Promise<ICAL.Event[]>;

@@ -25,11 +25,13 @@ createEventWithString(event: string, eventUid: string): Promise<void>;

getEventByUrl: (eventUrl: string) => Promise<ICAL.Event | undefined>;
getEventByUid: (eventUid: string) => Promise<ICAL.Event | undefined>;
getEventOccurrencesByUrl: (eventUrl: string, startDate: Date, endDate: Date) => Promise<ICAL.EventOccurrence[] | undefined>;
getEventsByEventUid: (eventUid: string, startDate?: Date, endDate?: Date) => Promise<ICAL.EventOccurrence[] | undefined>;
deleteEvent: (eventUrl: string) => Promise<void>;
listAllEvents: () => Promise<ICAL.Event[]>;
listEventsInTimeRange: (startDate: Date, endDate?: Date) => Promise<ICAL.EventWithExceptions[]>;
listEventsInTimeRange: (startDate: Date, endDate?: Date) => Promise<ICAL.EventOccurrence[]>;
multiGetEvents: (eventUrls: string[]) => Promise<ICAL.Event[]>;
createEvent: (eventUrl: string, id: string, title: string, description: string, location: string, startDate: ICAL.TimeJsonData, endDate: ICAL.TimeJsonData, attendees: Attendee[], categories: string[], organizerEmail: string, prodid: string, privateEvent: boolean, frequencyInterval?: EventFrequencyCalendarService, endDateFrequency?: ICAL.TimeJsonData, countFrequency?: number, alarms?: Alarm[]) => Promise<void>;
updateEvent: (eventUrl: string, event: ICAL.Event, title: string, description: string, location: string, startDate: ICAL.TimeJsonData, endDate: ICAL.TimeJsonData, attendees: Attendee[], categories: string[], organizerEmail: string, prodid: string, privateEvent: boolean, exceptionEventId: number | undefined, frequencyInterval?: EventFrequencyCalendarService, endDateFrequency?: ICAL.TimeJsonData, countFrequency?: number, alarms?: Alarm[]) => Promise<void>;
updateEvent: (eventUrl: string, event: ICAL.Event, title: string, description: string, location: string, startDate: ICAL.TimeJsonData, endDate: ICAL.TimeJsonData, attendees: Attendee[], categories: string[], organizerEmail: string, prodid: string, privateEvent: boolean, occurrenceEventId: number | undefined, frequencyInterval?: EventFrequencyCalendarService, endDateFrequency?: ICAL.TimeJsonData, countFrequency?: number, alarms?: Alarm[]) => Promise<void>;
private getDateWithoutTime;
updateEventProperties: (eventUrl: string, event: ICAL.Event, title: string, description: string, location: string, startDate: ICAL.TimeJsonData, endDate: ICAL.TimeJsonData, attendees: Attendee[], categories: string[], organizerEmail: string, prodid: string, privateEvent: boolean, frequencyInterval?: EventFrequencyCalendarService, endDateFrequency?: ICAL.TimeJsonData, countFrequency?: number, alarms?: Alarm[]) => string;
deleteOccurrenceEvent: (eventUrl: string, event: ICAL.Event, exceptionEventId: number, prodid: string) => Promise<void>;
deleteOccurrenceEvent: (eventUrl: string, event: ICAL.Event, occurrenceEventId: number, prodid: string) => Promise<void>;
createEventWithString: (event: string, eventUid: string) => Promise<void>;

@@ -36,0 +38,0 @@ static parseEvent: (eventData: string) => ICAL.Event;

@@ -37,19 +37,35 @@ "use strict";

};
this.getEventByUid = async eventUid => {
this.getEventOccurrencesByUrl = async (eventUrl, startDate, endDate) => {
try {
const response = await this.service.multiGetEvents([eventUrl]);
if (response.status === 207) {
_logger.default.info('CalDavClient.GetEventOccurrencesByUrl: Successfully got event and parsing all occurrences.');
return this.parseListOfEvents(response.data, 'getEventOccurrencesByUrl', startDate, endDate);
}
} catch (e) {
throw new Error(`CalDavClient.GetEventOccurrencesByUrl: ${e.message}. `);
}
};
this.getEventsByEventUid = async (eventUid, startDate, endDate) => {
try {
const response = await this.service.getEventByUid(eventUid);
if (response.status === 207) {
const parsedData = await this.parser.parseEvent(response.data);
const calData = ICAL.parse(parsedData.event);
const comp = new ICAL.Component(calData);
const vevent = comp.getFirstSubcomponent('vevent');
const event = new ICAL.Event(vevent);
const urlParts = parsedData.url.split('/');
event.component.addPropertyWithValue('url', urlParts[urlParts.length - 1]);
this.extendEventWithRecurrenceDetails(event);
_logger.default.info(`CalDavClient.GetEvent: Successfully got event ${event.uid}. `);
return event;
if (startDate && endDate) {
_logger.default.info('CalDavClient.getEventsByEventUid: Successfully got event and parsing all occurrences.');
return this.parseListOfEvents(response.data, 'getEventsByEventUid', startDate, endDate);
} else {
const parsedData = await this.parser.parseEvent(response.data);
const calData = ICAL.parse(parsedData.event);
const comp = new ICAL.Component(calData);
const vevent = comp.getFirstSubcomponent('vevent');
const event = new ICAL.Event(vevent);
const urlParts = parsedData.url.split('/');
event.component.addPropertyWithValue('url', urlParts[urlParts.length - 1]);
this.extendEventWithRecurrenceDetails(event);
_logger.default.info(`CalDavClient.getEventsByEventUid: Successfully got event ${event.uid}. `);
return [event];
}
}
} catch (e) {
throw new Error(`CalDavClient.GetEventByUid: ${e.message}. `);
throw new Error(`CalDavClient.getEventsByEventUid: ${e.message}. `);
}

@@ -178,3 +194,3 @@ };

};
this.updateEvent = async (eventUrl, event, title, description, location, startDate, endDate, attendees, categories, organizerEmail, prodid, privateEvent, exceptionEventId, frequencyInterval, endDateFrequency, countFrequency, alarms) => {
this.updateEvent = async (eventUrl, event, title, description, location, startDate, endDate, attendees, categories, organizerEmail, prodid, privateEvent, occurrenceEventId, frequencyInterval, endDateFrequency, countFrequency, alarms) => {
try {

@@ -193,3 +209,3 @@ _logger.default.debug(`Method updateEvent executed for eventUrl: ${eventUrl}`, {

privateEvent,
exceptionEventId,
occurrenceEventId,
frequencyInterval,

@@ -202,5 +218,9 @@ endDateFrequency,

let exceptionEventString = '';
if (exceptionEventId) {
if (occurrenceEventId) {
eventString = event.toString();
let exceptionEventIdIteration = 1;
const exDates = event.component.getAllProperties('exdate');
const exDatesValues = [];
for (const exDate of exDates) {
exDatesValues.push(new Date(exDate.getFirstValue().toString()).getTime());
}
let exceptions = {};

@@ -210,13 +230,82 @@ if (event.exceptions) {

}
for (const exception in exceptions) {
exceptionEventString += '\n';
if (exceptionEventIdIteration === exceptionEventId) {
_logger.default.debug(`Execute method updateEventProperties for exceptionEventId: ${exceptionEventId}`);
const exceptionEvent = new ICAL.Event(exceptions[exception.toString()].component);
exceptionEventString += this.updateEventProperties(eventUrl, exceptionEvent, title, description, location, startDate, endDate, attendees, categories, organizerEmail, prodid, privateEvent, undefined, undefined, undefined, alarms);
} else {
const exceptionEvent = new ICAL.Event(exceptions[exception.toString()].component);
exceptionEventString += exceptionEvent.toString();
let exceptionProcessed = 0;
let previousOccurrenceDate;
let occurrenceEventIdIteration = 0;
const iterator = event.iterator();
for (let next = iterator.next(); next; next = iterator.next()) {
if (exceptionProcessed === exceptions.length && occurrenceEventIdIteration > occurrenceEventId) {
break;
}
exceptionEventIdIteration += 1;
occurrenceEventIdIteration += 1;
if (exDatesValues.find(x => x === new Date(next.toString()).getTime())) {
if (occurrenceEventIdIteration === occurrenceEventId) {
throw new Error('CalDavClient.UpdateEvent: Deleted occurrence can\'t be updated.');
}
event.component.addPropertyWithValue('EXDATE', ICAL.Time.fromJSDate(new Date(next.toString()), true));
continue;
}
let currentOccurrenceDate;
let exceptionAdded = false;
for (const exception in exceptions) {
let exceptionString = exception.toString();
if (!exceptionString.includes('T') && next.toString().includes('T')) {
exceptionString += 'T00:00:00';
}
if (new Date(exceptionString).getTime() === new Date(next.toString()).getTime()) {
exceptionAdded = true;
exceptionProcessed += 1;
exceptionEventString += '\r\n';
if (occurrenceEventIdIteration === occurrenceEventId) {
_logger.default.debug(`Execute method updateEventProperties for occurrenceEventId: ${occurrenceEventId}`);
const exceptionEvent = new ICAL.Event(exceptions[exception.toString()].component);
currentOccurrenceDate = new ICAL.Time(startDate);
// const recurrenceId = new ICAL.Time(next.toJSON());
// icalEvent.component.addPropertyWithValue('RECURRENCE-ID', recurrenceId);
exceptionEventString += this.updateEventProperties(eventUrl, exceptionEvent, title, description, location, startDate, endDate, attendees, categories, organizerEmail, prodid, privateEvent, undefined, undefined, undefined, alarms, new ICAL.Time(next.toJSON()));
} else {
const exceptionEvent = new ICAL.Event(exceptions[exception.toString()].component);
currentOccurrenceDate = new ICAL.Time(exceptionEvent.startDate.toJSON());
exceptionEventString += exceptionEvent.toString();
}
break;
}
}
// process not deleted and not existing exception occurrence - create new exception
if (occurrenceEventIdIteration === occurrenceEventId && !exceptionAdded) {
const calDataOccurrence = ICAL.parse(`BEGIN:VCALENDAR\r\n${eventString}\r\nEND:VCALENDAR`);
const compOccurrence = new ICAL.Component(calDataOccurrence);
const veventOccurrence = compOccurrence.getFirstSubcomponent('vevent');
const icalEvent = new ICAL.Event(veventOccurrence);
exceptionEventString += '\r\n';
currentOccurrenceDate = new ICAL.Time(startDate);
exceptionEventString += this.updateEventProperties(eventUrl, icalEvent, title, description, location, startDate, endDate, attendees, categories, organizerEmail, prodid, privateEvent, undefined, undefined, undefined, alarms, new ICAL.Time(next.toJSON()));
}
if (!currentOccurrenceDate) {
currentOccurrenceDate = next;
}
if (occurrenceEventIdIteration === occurrenceEventId) {
if (previousOccurrenceDate && currentOccurrenceDate) {
const currentOccurrenceDateTime = this.getDateWithoutTime(currentOccurrenceDate.toJSDate()).getTime();
if (previousOccurrenceDate === currentOccurrenceDateTime) {
throw new Error('Two occurrences cannot occur on the same day.');
}
if (previousOccurrenceDate > currentOccurrenceDateTime) {
throw new Error('Cannot reschedule an occurrence of the recurring appointment if it skips over a later occurrence of the same appointment.');
}
}
} else if (occurrenceEventIdIteration === occurrenceEventId + 1) {
if (previousOccurrenceDate && currentOccurrenceDate) {
const currentOccurrenceDateTime = this.getDateWithoutTime(currentOccurrenceDate.toJSDate()).getTime();
if (previousOccurrenceDate === currentOccurrenceDateTime) {
throw new Error('Two occurrences cannot occur on the same day!');
}
if (previousOccurrenceDate > currentOccurrenceDateTime) {
throw new Error('Cannot reschedule an occurrence of the recurring appointment if it skips over a later occurrence of the same appointment!');
}
}
}
if (currentOccurrenceDate) {
previousOccurrenceDate = this.getDateWithoutTime(currentOccurrenceDate.toJSDate()).getTime();
}
}

@@ -232,3 +321,3 @@ } else {

};
this.updateEventProperties = (eventUrl, event, title, description, location, startDate, endDate, attendees, categories, organizerEmail, prodid, privateEvent, frequencyInterval, endDateFrequency, countFrequency, alarms) => {
this.updateEventProperties = (eventUrl, event, title, description, location, startDate, endDate, attendees, categories, organizerEmail, prodid, privateEvent, frequencyInterval, endDateFrequency, countFrequency, alarms, recurrenceId) => {
try {

@@ -252,2 +341,3 @@ _logger.default.debug(`Method updateEventProperties executed for eventUrl: ${eventUrl}`, {

});
const tempId = event.uid;
const originalSubcomponents = event.component.getAllSubcomponents();

@@ -271,6 +361,7 @@ const originalProperties = event.component.getAllProperties();

event.component = newEventComponent;
event.uid = tempId;
event.component.removeAllProperties('categories');
event.component.removeAllProperties('attendee');
event.component.removeAllProperties('class');
if (privateEvent) {
event.component.removeAllProperties('class');
event.component.addPropertyWithValue('CLASS', 'PRIVATE');

@@ -293,3 +384,10 @@ }

this.addFrequency(event, frequencyInterval, endDateFrequency, countFrequency);
} else {
event.component.removeAllProperties('rrule');
}
if (recurrenceId) {
recurrenceId.convertToZone(ICAL.Timezone.utcTimezone);
event.component.removeAllProperties('recurrence-id');
event.component.addPropertyWithValue('RECURRENCE-ID', recurrenceId.toICALString());
}
event.summary = title;

@@ -326,21 +424,68 @@ event.description = description;

};
this.deleteOccurrenceEvent = async (eventUrl, event, exceptionEventId, prodid) => {
this.deleteOccurrenceEvent = async (eventUrl, event, occurrenceEventId, prodid) => {
let eventString;
try {
let exceptions = {};
if (event.exceptions) {
exceptions = event.exceptions;
}
let exceptionEventString = '';
let exceptionEventIdIteration = 1;
for (const exception in exceptions) {
if (exceptionEventIdIteration === exceptionEventId) {
event.component.addPropertyWithValue('EXDATE', ICAL.Time.fromJSDate(new Date(exception.toString()), true));
} else {
const exceptionEvent = new ICAL.Event(exceptions[exception.toString()].component);
exceptionEventString += '\n';
exceptionEventString += exceptionEvent.toString();
let newExceptionAdded = false;
if (occurrenceEventId) {
const iterator = event.iterator();
let occurrenceEventIdIteration = 0;
const exDates = event.component.getAllProperties('exdate');
const exDatesValues = [];
for (const exDate of exDates) {
exDatesValues.push(new Date(exDate.getFirstValue().toString()).getTime());
}
exceptionEventIdIteration += 1;
let exceptions = {};
if (event.exceptions) {
exceptions = event.exceptions;
}
let exceptionProcessed = 0;
for (let next = iterator.next(); next; next = iterator.next()) {
if (exceptionProcessed === exceptions.length && occurrenceEventIdIteration > occurrenceEventId) {
break;
}
occurrenceEventIdIteration += 1;
if (exDatesValues.find(x => x === new Date(next.toString()).getTime())) {
if (occurrenceEventIdIteration === occurrenceEventId) {
throw new Error('CalDavClient.UpdateEvent: Occurrence has been already deleted!');
}
event.component.addPropertyWithValue('EXDATE', ICAL.Time.fromJSDate(new Date(next.toString()), true));
continue;
}
let exceptionAdded = false;
for (const exception in exceptions) {
let exceptionString = exception.toString();
if (!exceptionString.includes('T') && next.toString().includes('T')) {
exceptionString += 'T00:00:00';
}
if (new Date(exceptionString).getTime() === new Date(next.toString()).getTime()) {
exceptionAdded = true;
exceptionProcessed += 1;
exceptionEventString += '\r\n';
if (occurrenceEventIdIteration === occurrenceEventId) {
newExceptionAdded = true;
event.component.addPropertyWithValue('EXDATE', ICAL.Time.fromJSDate(new Date(exception.toString()), true));
} else {
const exceptionEvent = new ICAL.Event(exceptions[exception.toString()].component);
exceptionEventString += exceptionEvent.toString();
}
break;
}
}
// process not deleted and not existing exception occurrence - create new exception
if (occurrenceEventIdIteration === occurrenceEventId && !exceptionAdded) {
newExceptionAdded = true;
event.component.addPropertyWithValue('EXDATE', ICAL.Time.fromJSDate(new Date(next.toString()), true));
}
}
if (occurrenceEventIdIteration === 1) {
await this.deleteEvent(eventUrl);
return;
}
}
let eventString = event.toString();
if (!newExceptionAdded) {
throw new Error(`CalDavClient.UpdateEvent: There is no occurrenceEventId: ${occurrenceEventId}`);
}
eventString = event.toString();
eventString += exceptionEventString;

@@ -386,3 +531,3 @@ await this.service.createUpdateEvent(`BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:${prodid}\r\n` + eventString + '\r\nEND:VCALENDAR', eventUrl);

}
let exceptionEventId = 1;
let occurrenceEventId = 0;
const iterator = iCalEvent.iterator();

@@ -395,2 +540,3 @@ const calDataOccurrence = ICAL.parse(eventData.event);

}
occurrenceEventId += 1;
if (exDatesValues.find(x => x === new Date(next.toString()).getTime())) {

@@ -400,16 +546,22 @@ // occurrence deleted

}
let isException = false;
let exceptionAdded = false;
for (const exception in exceptions) {
if (new Date(exception.toString()).getTime() === new Date(next.toString()).getTime()) {
isException = true;
let exceptionString = exception.toString();
if (!exceptionString.includes('T') && next.toString().includes('T')) {
// exception is at midnight, we need to add time
exceptionString += 'T00:00:00';
}
if (new Date(exceptionString).getTime() === new Date(next.toString()).getTime()) {
exceptionAdded = true;
const event = new ICAL.Event(exceptions[exception.toString()].component);
if (this.eventIncludedInDates(event.startDate, event.endDate, startDateFilter, endDateFilter)) {
event.exceptionEventId = exceptionEventId;
exceptionEventId += 1;
event.occurrenceEventId = occurrenceEventId;
this.extendEventWithRecurrenceDetails(event);
events.push(event);
}
break;
}
}
if (!isException) {
if (!exceptionAdded) {
// process not deleted and not exception occurrence
const compOccurrence = new ICAL.Component(calDataOccurrence);

@@ -423,2 +575,3 @@ const veventOccurrence = compOccurrence.getFirstSubcomponent('vevent');

if (this.eventIncludedInDates(icalEvent.startDate, icalEvent.endDate, startDateFilter, endDateFilter)) {
icalEvent.occurrenceEventId = occurrenceEventId;
icalEvent.component.addPropertyWithValue('url', urlParts[urlParts.length - 1]);

@@ -439,2 +592,5 @@ this.extendEventWithRecurrenceDetails(icalEvent);

}
getDateWithoutTime(date) {
return new Date(date.toDateString());
}
extendEventWithRecurrenceDetails(iCalEvent) {

@@ -441,0 +597,0 @@ const rrule = iCalEvent.component.getFirstPropertyValue('rrule');

{
"name": "@coozzy/cal-dav",
"version": "2.4.5",
"version": "2.4.6",
"description": "Simple cal dav client.",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

@@ -6,3 +6,3 @@ import * as ICAL from 'ical.js';

import logger from '@coozzy/logger';
import {EventWithExceptions, FrequencyValues, TimeJsonData} from 'ical.js';
import {EventOccurrence, FrequencyValues, Time, TimeJsonData} from 'ical.js';
import {EventFrequencyCalendarService} from '../types/calendar';

@@ -14,4 +14,6 @@

getEventByUid(eventUid: string): Promise<ICAL.Event | undefined>;
getEventOccurrencesByUrl(eventUrl: string, startDate: Date, endDate: Date): Promise<ICAL.EventOccurrence[] | undefined>
getEventsByEventUid(eventUid: string, startDate?: Date, endDate?: Date): Promise<ICAL.EventOccurrence[] | undefined>;
deleteEvent(eventUid: string): Promise<void>;

@@ -50,3 +52,3 @@

privateEvent: boolean,
exceptionEventId?: number,
occurrenceEventId?: number,
frequencyInterval?: string,

@@ -59,6 +61,6 @@ endDateFrequency?: ICAL.TimeJsonData,

event: ICAL.Event,
exceptionEventId: number,
occurrenceEventId: number,
prodid: string): Promise<void>;
listEventsInTimeRange(startDate: Date, endDate?: Date): Promise<ICAL.EventWithExceptions[]>;
listEventsInTimeRange(startDate: Date, endDate?: Date): Promise<ICAL.EventOccurrence[]>;

@@ -99,20 +101,38 @@ multiGetEvents(eventUrls: string[]): Promise<ICAL.Event[]>;

getEventByUid = async(eventUid: string): Promise<ICAL.Event | undefined> => {
getEventOccurrencesByUrl = async(eventUrl: string, startDate: Date, endDate: Date): Promise<ICAL.EventOccurrence[] | undefined> => {
try{
const response = await this.service.multiGetEvents([eventUrl]);
if(response.status === 207) {
logger.info('CalDavClient.GetEventOccurrencesByUrl: Successfully got event and parsing all occurrences.');
return this.parseListOfEvents(response.data, 'getEventOccurrencesByUrl', startDate, endDate);
}
} catch(e) {
throw new Error(`CalDavClient.GetEventOccurrencesByUrl: ${e.message}. `);
}
};
getEventsByEventUid = async(eventUid: string, startDate?: Date, endDate?: Date): Promise<ICAL.EventOccurrence[] | undefined> => {
try{
const response = await this.service.getEventByUid(eventUid);
if(response.status === 207) {
const parsedData = await this.parser.parseEvent(response.data);
const calData = ICAL.parse(parsedData.event);
const comp = new ICAL.Component(calData);
const vevent = comp.getFirstSubcomponent('vevent');
if (startDate && endDate) {
logger.info('CalDavClient.getEventsByEventUid: Successfully got event and parsing all occurrences.');
return this.parseListOfEvents(response.data, 'getEventsByEventUid', startDate, endDate);
} else {
const parsedData = await this.parser.parseEvent(response.data);
const calData = ICAL.parse(parsedData.event);
const comp = new ICAL.Component(calData);
const vevent = comp.getFirstSubcomponent('vevent');
const event = new ICAL.Event(vevent);
const urlParts = parsedData.url.split('/');
event.component.addPropertyWithValue('url', urlParts[urlParts.length - 1]);
this.extendEventWithRecurrenceDetails(event);
logger.info(`CalDavClient.GetEvent: Successfully got event ${event.uid}. `);
return event;
const event = new ICAL.Event(vevent);
const urlParts = parsedData.url.split('/');
event.component.addPropertyWithValue('url', urlParts[urlParts.length - 1]);
this.extendEventWithRecurrenceDetails(event);
logger.info(`CalDavClient.getEventsByEventUid: Successfully got event ${event.uid}. `);
return [event];
}
}
} catch(e) {
throw new Error(`CalDavClient.GetEventByUid: ${e.message}. `);
throw new Error(`CalDavClient.getEventsByEventUid: ${e.message}. `);
}

@@ -147,3 +167,3 @@ };

listEventsInTimeRange = async(startDate: Date, endDate?: Date): Promise<ICAL.EventWithExceptions[]> => {
listEventsInTimeRange = async(startDate: Date, endDate?: Date): Promise<ICAL.EventOccurrence[]> => {
try{

@@ -261,3 +281,3 @@ const response = await this.service.listEventsInTimeRange(startDate, endDate);

updateEvent = async(eventUrl: string, event: ICAL.Event, title: string, description: string, location: string, startDate: ICAL.TimeJsonData, endDate: ICAL.TimeJsonData, attendees: Attendee[], categories: string[], organizerEmail: string, prodid: string, privateEvent: boolean, exceptionEventId: number | undefined, frequencyInterval?: EventFrequencyCalendarService, endDateFrequency?: ICAL.TimeJsonData, countFrequency?: number, alarms?: Alarm[]): Promise<void> => {
updateEvent = async(eventUrl: string, event: ICAL.Event, title: string, description: string, location: string, startDate: ICAL.TimeJsonData, endDate: ICAL.TimeJsonData, attendees: Attendee[], categories: string[], organizerEmail: string, prodid: string, privateEvent: boolean, occurrenceEventId: number | undefined, frequencyInterval?: EventFrequencyCalendarService, endDateFrequency?: ICAL.TimeJsonData, countFrequency?: number, alarms?: Alarm[]): Promise<void> => {
try{

@@ -277,3 +297,3 @@ logger.debug(`Method updateEvent executed for eventUrl: ${eventUrl}`,

privateEvent,
exceptionEventId,
occurrenceEventId,
frequencyInterval,

@@ -286,5 +306,11 @@ endDateFrequency,

let exceptionEventString = '';
if (exceptionEventId) {
if (occurrenceEventId) {
eventString = event.toString();
let exceptionEventIdIteration = 1;
const exDates = event.component.getAllProperties('exdate');
const exDatesValues: number[] = [];
for (const exDate of exDates) {
exDatesValues.push(new Date(exDate.getFirstValue().toString()).getTime());
}
let exceptions: any = {};

@@ -294,13 +320,89 @@ if (event.exceptions) {

}
for (const exception in exceptions) {
exceptionEventString += '\n';
if (exceptionEventIdIteration === exceptionEventId) {
logger.debug(`Execute method updateEventProperties for exceptionEventId: ${exceptionEventId}`);
const exceptionEvent: ICAL.Event = new ICAL.Event(exceptions[exception.toString()].component);
exceptionEventString += this.updateEventProperties(eventUrl, exceptionEvent, title, description, location, startDate, endDate, attendees, categories, organizerEmail, prodid, privateEvent, undefined, undefined, undefined, alarms);
} else {
const exceptionEvent: ICAL.Event = new ICAL.Event(exceptions[exception.toString()].component);
exceptionEventString += exceptionEvent.toString();
let exceptionProcessed = 0;
let previousOccurrenceDate: number | undefined;
let occurrenceEventIdIteration = 0;
const iterator = event.iterator();
for (let next = iterator.next(); next; next = iterator.next()) {
if (exceptionProcessed === exceptions.length && occurrenceEventIdIteration > occurrenceEventId) {
break;
}
exceptionEventIdIteration += 1;
occurrenceEventIdIteration += 1;
if (exDatesValues.find(x => x === new Date(next.toString()).getTime())) {
if (occurrenceEventIdIteration === occurrenceEventId) {
throw new Error('CalDavClient.UpdateEvent: Deleted occurrence can\'t be updated.');
}
event.component.addPropertyWithValue('EXDATE', ICAL.Time.fromJSDate(new Date(next.toString()), true));
continue;
}
let currentOccurrenceDate: ICAL.Time | undefined;
let exceptionAdded = false;
for (const exception in exceptions) {
let exceptionString = exception.toString();
if (!exceptionString.includes('T') && next.toString().includes('T')) {
exceptionString += 'T00:00:00';
}
if (new Date(exceptionString).getTime() === new Date(next.toString()).getTime()) {
exceptionAdded = true;
exceptionProcessed += 1;
exceptionEventString += '\r\n';
if (occurrenceEventIdIteration === occurrenceEventId) {
logger.debug(`Execute method updateEventProperties for occurrenceEventId: ${occurrenceEventId}`);
const exceptionEvent: ICAL.Event = new ICAL.Event(exceptions[exception.toString()].component);
currentOccurrenceDate = new ICAL.Time(startDate);
// const recurrenceId = new ICAL.Time(next.toJSON());
// icalEvent.component.addPropertyWithValue('RECURRENCE-ID', recurrenceId);
exceptionEventString += this.updateEventProperties(eventUrl, exceptionEvent, title, description, location, startDate, endDate, attendees, categories, organizerEmail, prodid, privateEvent, undefined, undefined, undefined, alarms, new ICAL.Time(next.toJSON()));
} else {
const exceptionEvent: ICAL.Event = new ICAL.Event(exceptions[exception.toString()].component);
currentOccurrenceDate = new ICAL.Time(exceptionEvent.startDate.toJSON());
exceptionEventString += exceptionEvent.toString();
}
break;
}
}
// process not deleted and not existing exception occurrence - create new exception
if (occurrenceEventIdIteration === occurrenceEventId && !exceptionAdded) {
const calDataOccurrence = ICAL.parse(`BEGIN:VCALENDAR\r\n${eventString}\r\nEND:VCALENDAR`);
const compOccurrence = new ICAL.Component(calDataOccurrence);
const veventOccurrence = compOccurrence.getFirstSubcomponent('vevent');
const icalEvent: ICAL.EventOccurrence = new ICAL.Event(veventOccurrence);
exceptionEventString += '\r\n';
currentOccurrenceDate = new ICAL.Time(startDate);
exceptionEventString += this.updateEventProperties(eventUrl, icalEvent, title, description, location, startDate, endDate, attendees, categories, organizerEmail, prodid, privateEvent, undefined, undefined, undefined, alarms, new ICAL.Time(next.toJSON()));
}
if (!currentOccurrenceDate) {
currentOccurrenceDate = next;
}
if (occurrenceEventIdIteration === occurrenceEventId) {
if (previousOccurrenceDate && currentOccurrenceDate) {
const currentOccurrenceDateTime = this.getDateWithoutTime(currentOccurrenceDate.toJSDate()).getTime();
if (previousOccurrenceDate === currentOccurrenceDateTime) {
throw new Error('Two occurrences cannot occur on the same day.');
}
if (previousOccurrenceDate > currentOccurrenceDateTime) {
throw new Error('Cannot reschedule an occurrence of the recurring appointment if it skips over a later occurrence of the same appointment.');
}
}
} else if (occurrenceEventIdIteration === (occurrenceEventId + 1)) {
if (previousOccurrenceDate && currentOccurrenceDate) {
const currentOccurrenceDateTime = this.getDateWithoutTime(currentOccurrenceDate.toJSDate()).getTime();
if (previousOccurrenceDate === currentOccurrenceDateTime) {
throw new Error('Two occurrences cannot occur on the same day!');
}
if (previousOccurrenceDate > currentOccurrenceDateTime) {
throw new Error('Cannot reschedule an occurrence of the recurring appointment if it skips over a later occurrence of the same appointment!');
}
}
}
if (currentOccurrenceDate) {
previousOccurrenceDate = this.getDateWithoutTime(currentOccurrenceDate.toJSDate()).getTime();
}
}

@@ -311,3 +413,2 @@ } else {

eventString += exceptionEventString;
await this.service.createUpdateEvent(`BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:${prodid}\r\n` + eventString + '\r\nEND:VCALENDAR', eventUrl);

@@ -319,3 +420,7 @@ } catch(e) {

updateEventProperties = (eventUrl: string, event: ICAL.Event, title: string, description: string, location: string, startDate: ICAL.TimeJsonData, endDate: ICAL.TimeJsonData, attendees: Attendee[], categories: string[], organizerEmail: string, prodid: string, privateEvent: boolean, frequencyInterval?: EventFrequencyCalendarService, endDateFrequency?: ICAL.TimeJsonData, countFrequency?: number, alarms?: Alarm[]): string => {
private getDateWithoutTime(date: Date) {
return new Date(date.toDateString());
}
updateEventProperties = (eventUrl: string, event: ICAL.Event, title: string, description: string, location: string, startDate: ICAL.TimeJsonData, endDate: ICAL.TimeJsonData, attendees: Attendee[], categories: string[], organizerEmail: string, prodid: string, privateEvent: boolean, frequencyInterval?: EventFrequencyCalendarService, endDateFrequency?: ICAL.TimeJsonData, countFrequency?: number, alarms?: Alarm[], recurrenceId?: Time): string => {
try{

@@ -341,2 +446,3 @@ logger.debug(`Method updateEventProperties executed for eventUrl: ${eventUrl}`,

const tempId = event.uid;
const originalSubcomponents = event.component.getAllSubcomponents();

@@ -361,8 +467,9 @@ const originalProperties = event.component.getAllProperties();

event.component = newEventComponent;
event.uid = tempId; // above line sometimes erasy uid from ocurrence event (when all occurrences are exceptions in recurrence event, then first and last lost uid)
event.component.removeAllProperties('categories');
event.component.removeAllProperties('attendee');
event.component.removeAllProperties('class');
if (privateEvent) {
event.component.removeAllProperties('class');
event.component.addPropertyWithValue('CLASS', 'PRIVATE');

@@ -387,4 +494,12 @@ }

this.addFrequency(event, frequencyInterval, endDateFrequency, countFrequency);
} else {
event.component.removeAllProperties('rrule');
}
if (recurrenceId) {
recurrenceId.convertToZone(ICAL.Timezone.utcTimezone);
event.component.removeAllProperties('recurrence-id');
event.component.addPropertyWithValue('RECURRENCE-ID', recurrenceId.toICALString());
}
event.summary = title;

@@ -396,2 +511,3 @@ event.description = description;

if (alarms?.length) {

@@ -427,21 +543,75 @@ for (const alarm of alarms) {

deleteOccurrenceEvent = async(eventUrl: string, event: ICAL.Event, exceptionEventId: number, prodid: string): Promise<void> => {
deleteOccurrenceEvent = async(eventUrl: string, event: ICAL.Event, occurrenceEventId: number, prodid: string): Promise<void> => {
let eventString;
try {
let exceptions: any = {};
if (event.exceptions) {
exceptions = event.exceptions;
}
let exceptionEventString = '';
let exceptionEventIdIteration = 1;
for (const exception in exceptions) {
if (exceptionEventIdIteration === exceptionEventId) {
event.component.addPropertyWithValue('EXDATE', ICAL.Time.fromJSDate(new Date(exception.toString()), true));
} else {
const exceptionEvent: ICAL.Event = new ICAL.Event(exceptions[exception.toString()].component);
exceptionEventString += '\n';
exceptionEventString += exceptionEvent.toString();
let newExceptionAdded = false;
if (occurrenceEventId) {
const iterator = event.iterator();
let occurrenceEventIdIteration = 0;
const exDates = event.component.getAllProperties('exdate');
const exDatesValues: number[] = [];
for (const exDate of exDates) {
exDatesValues.push(new Date(exDate.getFirstValue().toString()).getTime());
}
exceptionEventIdIteration += 1;
let exceptions: any = {};
if (event.exceptions) {
exceptions = event.exceptions;
}
let exceptionProcessed = 0;
for (let next = iterator.next(); next; next = iterator.next()) {
if (exceptionProcessed === exceptions.length && occurrenceEventIdIteration > occurrenceEventId) {
break;
}
occurrenceEventIdIteration += 1;
if (exDatesValues.find(x => x === new Date(next.toString()).getTime())) {
if (occurrenceEventIdIteration === occurrenceEventId) {
throw new Error('CalDavClient.UpdateEvent: Occurrence has been already deleted!');
}
event.component.addPropertyWithValue('EXDATE', ICAL.Time.fromJSDate(new Date(next.toString()), true));
continue;
}
let exceptionAdded = false;
for (const exception in exceptions) {
let exceptionString = exception.toString();
if (!exceptionString.includes('T') && next.toString().includes('T')) {
exceptionString += 'T00:00:00';
}
if (new Date(exceptionString).getTime() === new Date(next.toString()).getTime()) {
exceptionAdded = true;
exceptionProcessed += 1;
exceptionEventString += '\r\n';
if (occurrenceEventIdIteration === occurrenceEventId) {
newExceptionAdded = true;
event.component.addPropertyWithValue('EXDATE', ICAL.Time.fromJSDate(new Date(exception.toString()), true));
} else {
const exceptionEvent: ICAL.Event = new ICAL.Event(exceptions[exception.toString()].component);
exceptionEventString += exceptionEvent.toString();
}
break;
}
}
// process not deleted and not existing exception occurrence - create new exception
if (occurrenceEventIdIteration === occurrenceEventId && !exceptionAdded) {
newExceptionAdded = true;
event.component.addPropertyWithValue('EXDATE', ICAL.Time.fromJSDate(new Date(next.toString()), true));
}
}
if (occurrenceEventIdIteration === 1) {
await this.deleteEvent(eventUrl);
return;
}
}
let eventString = event.toString();
if (!newExceptionAdded) {
throw new Error(`CalDavClient.UpdateEvent: There is no occurrenceEventId: ${occurrenceEventId}`);
}
eventString = event.toString();
eventString += exceptionEventString;

@@ -473,3 +643,4 @@

private parseListOfEvents = async(responseData: string, method: string, startDateFilter?: Date, endDateFilter?: Date): Promise<ICAL.EventWithExceptions[]> => {
private parseListOfEvents = async(responseData: string, method: string, startDateFilter?: Date, endDateFilter?: Date): Promise<ICAL.EventOccurrence[]> => {
if (!endDateFilter) {

@@ -479,3 +650,3 @@ throw new Error('End date of filter is mandatory to avoid parsing infinite recurrence events!');

const eventsData = await this.parser.parseListOfEvents(responseData);
const events: ICAL.EventWithExceptions[] = [];
const events: ICAL.EventOccurrence[] = [];
if(eventsData.length){

@@ -487,3 +658,3 @@ for(const eventData of eventsData){

if (vevent) {
const iCalEvent: ICAL.EventWithExceptions = new ICAL.Event(vevent);
const iCalEvent: ICAL.EventOccurrence = new ICAL.Event(vevent);
const urlParts = eventData.url.split('/');

@@ -495,3 +666,3 @@ iCalEvent.component.addPropertyWithValue('url', urlParts[urlParts.length - 1]);

const exDates = iCalEvent.component.getAllProperties('exdate');
const exDatesValues: any[] = [];
const exDatesValues: number[] = [];
for (const exDate of exDates) {

@@ -505,3 +676,3 @@ exDatesValues.push(new Date(exDate.getFirstValue().toString()).getTime());

}
let exceptionEventId = 1;
let occurrenceEventId = 0;
const iterator = iCalEvent.iterator();

@@ -515,2 +686,3 @@

}
occurrenceEventId += 1;

@@ -522,22 +694,27 @@ if (exDatesValues.find(x => x === new Date(next.toString()).getTime())) {

let isException = false;
let exceptionAdded = false;
for (const exception in exceptions) {
if (new Date(exception.toString()).getTime() === new Date(next.toString()).getTime()) {
isException = true;
const event: ICAL.EventWithExceptions = new ICAL.Event(exceptions[exception.toString()].component);
let exceptionString = exception.toString();
if (!exceptionString.includes('T') && next.toString().includes('T')) {
// exception is at midnight, we need to add time
exceptionString += 'T00:00:00';
}
if (new Date(exceptionString).getTime() === new Date(next.toString()).getTime()) {
exceptionAdded = true;
const event: ICAL.EventOccurrence = new ICAL.Event(exceptions[exception.toString()].component);
if (this.eventIncludedInDates(event.startDate, event.endDate, startDateFilter, endDateFilter)) {
event.exceptionEventId = exceptionEventId;
exceptionEventId += 1;
event.occurrenceEventId = occurrenceEventId;
this.extendEventWithRecurrenceDetails(event);
events.push(event);
}
break;
}
}
if (!isException) {
if (!exceptionAdded) {
// process not deleted and not exception occurrence
const compOccurrence = new ICAL.Component(calDataOccurrence);
const veventOccurrence = compOccurrence.getFirstSubcomponent('vevent');
const icalEvent = new ICAL.Event(veventOccurrence);
const icalEvent: ICAL.EventOccurrence = new ICAL.Event(veventOccurrence);
const diffInMs = new Date(next.toString()).getTime() - new Date(iCalEvent.startDate.toString()).getTime();

@@ -548,2 +725,3 @@ const diffInDays = diffInMs / (1000 * 60 * 60 * 24);

if (this.eventIncludedInDates(icalEvent.startDate, icalEvent.endDate, startDateFilter, endDateFilter)) {
icalEvent.occurrenceEventId = occurrenceEventId;
icalEvent.component.addPropertyWithValue('url', urlParts[urlParts.length - 1]);

@@ -558,3 +736,2 @@ this.extendEventWithRecurrenceDetails(icalEvent);

}
logger.debug(`${method}: ${events.length} events successfully parsed.`);

@@ -564,3 +741,3 @@ return events;

private extendEventWithRecurrenceDetails(iCalEvent: EventWithExceptions): ICAL.EventWithExceptions {
private extendEventWithRecurrenceDetails(iCalEvent: EventOccurrence): ICAL.EventOccurrence {
const rrule = iCalEvent.component.getFirstPropertyValue('rrule');

@@ -659,3 +836,3 @@ if (rrule) {

private addFrequency(event: ICAL.Event, freq?: EventFrequencyCalendarService, endDate?: TimeJsonData, count?: number): ICAL.EventWithExceptions {
private addFrequency(event: ICAL.Event, freq?: EventFrequencyCalendarService, endDate?: TimeJsonData, count?: number): ICAL.EventOccurrence {
if (endDate && count) {

@@ -662,0 +839,0 @@ throw new Error('CalDavClient.addFrequency: It is allowed to use endDate or count, not both at the same time.');

@@ -36,4 +36,4 @@ /* eslint-disable @typescript-eslint/no-explicit-any */

class EventWithExceptions extends Event {
exceptionEventId?: number;
class EventOccurrence extends Event {
occurrenceEventId?: number;
frequency?: FrequencyValues;

@@ -40,0 +40,0 @@ endDateRecurrence?: Time;

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc