forked from Progyssey/Calmerge
Compare commits
No commits in common. "29208d8b4d8512ecfe38a0f3947ec7712284b21b" and "bed3e47f8e21b912fc3ad66d1a1b4bb371ff285b" have entirely different histories.
29208d8b4d
...
bed3e47f8e
10 changed files with 114 additions and 285 deletions
|
@ -1,7 +0,0 @@
|
||||||
export default {
|
|
||||||
transform: {
|
|
||||||
'^.+\\.jsx?$': 'babel-jest',
|
|
||||||
},
|
|
||||||
moduleFileExtensions: ['js', 'jsx'],
|
|
||||||
testEnvironment: 'node',
|
|
||||||
};
|
|
9
package-lock.json
generated
9
package-lock.json
generated
|
@ -17,11 +17,8 @@
|
||||||
"supertest": "^7.0.0"
|
"supertest": "^7.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.26.0",
|
|
||||||
"@babel/plugin-transform-modules-commonjs": "^7.25.9",
|
|
||||||
"@babel/preset-env": "^7.26.0",
|
"@babel/preset-env": "^7.26.0",
|
||||||
"@babel/register": "^7.25.9",
|
"@babel/register": "^7.25.9",
|
||||||
"babel-jest": "^29.7.0",
|
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"rewire": "^7.0.0"
|
"rewire": "^7.0.0"
|
||||||
}
|
}
|
||||||
|
@ -3184,9 +3181,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"path-key": "^3.1.0",
|
"path-key": "^3.1.0",
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "calendar-merger",
|
"name": "calendar-merger",
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node src/app.js",
|
"start": "node app.js",
|
||||||
"test": "jest ./test"
|
"test": "jest ./test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -15,15 +15,12 @@
|
||||||
},
|
},
|
||||||
"description": "calmerger",
|
"description": "calmerger",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"author": "Ryan",
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"author": "Ryan",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.26.0",
|
|
||||||
"@babel/plugin-transform-modules-commonjs": "^7.25.9",
|
|
||||||
"@babel/preset-env": "^7.26.0",
|
"@babel/preset-env": "^7.26.0",
|
||||||
"@babel/register": "^7.25.9",
|
"@babel/register": "^7.25.9",
|
||||||
"babel-jest": "^29.7.0",
|
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"rewire": "^7.0.0"
|
"rewire": "^7.0.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,128 +26,77 @@ export async function fetchCalendarData(calendar) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to check if TZID exists in the raw property string
|
|
||||||
function hasTZID(rawProperty) {
|
|
||||||
return rawProperty.includes('TZID=');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to process DTSTART/DTEND
|
|
||||||
function processDateTimeProperty(event, propertyName, newEvent) {
|
|
||||||
const rawProperty = event.getFirstProperty(propertyName)?.toICALString();
|
|
||||||
if (!rawProperty) return;
|
|
||||||
|
|
||||||
const dateTime = event.getFirstPropertyValue(propertyName);
|
|
||||||
const dateTimeString = dateTime.toString();
|
|
||||||
|
|
||||||
const property = new ICAL.Property(propertyName, newEvent);
|
|
||||||
property.setValue(dateTimeString);
|
|
||||||
|
|
||||||
if (hasTZID(rawProperty)) {
|
|
||||||
// If raw property includes TZID, add it
|
|
||||||
property.setParameter('TZID', dateTime.zone.tzid);
|
|
||||||
}
|
|
||||||
|
|
||||||
newEvent.addProperty(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a top-level VCALENDAR component
|
// Create a top-level VCALENDAR component
|
||||||
export function createCalendarComponent(name) {
|
export function createCalendarComponent(name) {
|
||||||
const calendarComponent = new ICAL.Component(['vcalendar', [], []]);
|
const calendarComponent = new ICAL.Component(['vcalendar', [], []]);
|
||||||
calendarComponent.updatePropertyWithValue('name', name);
|
calendarComponent.updatePropertyWithValue('name', name);
|
||||||
calendarComponent.updatePropertyWithValue('prodid', '-//CalMerge//Calendar Merger 1.0//EN');
|
|
||||||
calendarComponent.updatePropertyWithValue('version', '2.0');
|
calendarComponent.updatePropertyWithValue('version', '2.0');
|
||||||
calendarComponent.updatePropertyWithValue('calscale', 'GREGORIAN');
|
|
||||||
return calendarComponent;
|
return calendarComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add events to the calendar component
|
// Add events to the calendar component
|
||||||
export function addEventsToCalendar(calendarComponent, results, overrideFlag = false) {
|
export function addEventsToCalendar(calendarComponent, results) {
|
||||||
let defaultTimeZone = null; // To store the first found X-WR-TIMEZONE
|
|
||||||
|
|
||||||
results.forEach((result) => {
|
results.forEach((result) => {
|
||||||
try {
|
try {
|
||||||
const parsed = ICAL.parse(result.data);
|
const parsed = ICAL.parse(result.data);
|
||||||
const component = new ICAL.Component(parsed);
|
const component = new ICAL.Component(parsed);
|
||||||
|
|
||||||
// Extract METHOD from the parsed data (if available)
|
|
||||||
const method = component.getFirstPropertyValue('method');
|
|
||||||
if (method) {
|
|
||||||
console.log(`Extracted METHOD: ${method}`);
|
|
||||||
// Only add the METHOD property once
|
|
||||||
if (!calendarComponent.getFirstPropertyValue('method')) {
|
|
||||||
calendarComponent.updatePropertyWithValue('method', method.toUpperCase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Extract X-WR-TIMEZONE if available
|
|
||||||
const wrTimeZone = component.getFirstPropertyValue('x-wr-timezone');
|
|
||||||
if (wrTimeZone) {
|
|
||||||
console.log(`Extracted X-WR-TIMEZONE: ${wrTimeZone}`);
|
|
||||||
// Set it as the default if not already set
|
|
||||||
if (!defaultTimeZone) {
|
|
||||||
defaultTimeZone = wrTimeZone;
|
|
||||||
if (!calendarComponent.getFirstPropertyValue('x-wr-timezone')) {
|
|
||||||
calendarComponent.updatePropertyWithValue('x-wr-timezone', defaultTimeZone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract and add VTIMEZONE components
|
|
||||||
const timezones = component.getAllSubcomponents('vtimezone');
|
|
||||||
timezones.forEach((timezone) => {
|
|
||||||
const tzid = timezone.getFirstPropertyValue('tzid');
|
|
||||||
if (!calendarComponent.getFirstSubcomponent((comp) => comp.name === 'vtimezone' && comp.getFirstPropertyValue('tzid') === tzid)) {
|
|
||||||
calendarComponent.addSubcomponent(timezone);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Process VEVENT components
|
|
||||||
component.getAllSubcomponents('vevent').forEach((event) => {
|
component.getAllSubcomponents('vevent').forEach((event) => {
|
||||||
const vevent = new ICAL.Event(event);
|
const vevent = new ICAL.Event(event);
|
||||||
const newEvent = new ICAL.Component('vevent');
|
const newEvent = new ICAL.Component('vevent');
|
||||||
|
|
||||||
// 1. Add DTSTART
|
|
||||||
processDateTimeProperty(event, 'dtstart', newEvent);
|
|
||||||
|
|
||||||
// 2. Add DTEND
|
// Use ICAL.Time to handle dates correctly
|
||||||
processDateTimeProperty(event, 'dtend', newEvent);
|
const startDate = vevent.startDate;
|
||||||
|
const endDate = vevent.endDate;
|
||||||
|
|
||||||
// 3. Copy DTSTAMP
|
// Create new ICAL.Time objects for start and end dates
|
||||||
const dtstamp = event.getFirstPropertyValue('dtstamp');
|
const startTime = new ICAL.Time({
|
||||||
if (dtstamp) newEvent.updatePropertyWithValue('dtstamp', dtstamp);
|
year: startDate.year,
|
||||||
|
month: startDate.month,
|
||||||
|
day: startDate.day,
|
||||||
|
hour: startDate.isDate ? null : startDate.hour,
|
||||||
|
minute: startDate.isDate ? null : startDate.minute,
|
||||||
|
second: startDate.isDate ? null : startDate.second,
|
||||||
|
zone: startDate.zone
|
||||||
|
});
|
||||||
|
startTime.isDate = startDate.isDate;
|
||||||
|
|
||||||
// 4. Copy UID
|
const endTime = new ICAL.Time({
|
||||||
|
year: endDate.year,
|
||||||
|
month: endDate.month,
|
||||||
|
day: endDate.day,
|
||||||
|
hour: endDate.isDate ? null : endDate.hour,
|
||||||
|
minute: endDate.isDate ? null : endDate.minute,
|
||||||
|
second: endDate.isDate ? null : endDate.second,
|
||||||
|
zone: endDate.zone
|
||||||
|
});
|
||||||
|
endTime.isDate = endDate.isDate;
|
||||||
|
|
||||||
|
// Retain the existing DTSTAMP from vevent
|
||||||
|
const dtstampProperty = event.getFirstProperty('dtstamp');
|
||||||
|
const dtstamp = dtstampProperty ? dtstampProperty.getFirstValue() : null;
|
||||||
|
|
||||||
|
// Add properties to the new event
|
||||||
newEvent.updatePropertyWithValue('uid', vevent.uid);
|
newEvent.updatePropertyWithValue('uid', vevent.uid);
|
||||||
|
if (dtstamp) {
|
||||||
// 5. Add LOCATION (conditionally included)
|
newEvent.updatePropertyWithValue('dtstamp', dtstamp); // Retain the existing DTSTAMP
|
||||||
if (!overrideFlag && vevent.location) {
|
|
||||||
newEvent.updatePropertyWithValue('location', vevent.location);
|
|
||||||
} else if (overrideFlag && vevent.location) {
|
|
||||||
// Modify SUMMARY if override is set
|
|
||||||
const modifiedSummary = `${vevent.summary.trim()} (Location omitted)`;
|
|
||||||
newEvent.updatePropertyWithValue('summary', modifiedSummary);
|
|
||||||
} else {
|
} else {
|
||||||
newEvent.updatePropertyWithValue('summary', vevent.summary.trim());
|
console.warn('DTSTAMP not found in the original event.'); // Warn if DTSTAMP is missing
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Copy Recurrence Rules (RRULE) and Recurrence ID
|
|
||||||
const rrule = event.getFirstPropertyValue('rrule');
|
|
||||||
if (rrule) newEvent.updatePropertyWithValue('rrule', rrule);
|
|
||||||
|
|
||||||
const recurrenceId = event.getFirstPropertyValue('recurrence-id');
|
|
||||||
if (recurrenceId) newEvent.updatePropertyWithValue('recurrence-id', recurrenceId);
|
|
||||||
|
|
||||||
// 7. Copy SUMMARY
|
// Set the dtstart and dtend properties using ICAL.Time
|
||||||
newEvent.updatePropertyWithValue('summary', vevent.summary.trim());
|
newEvent.updatePropertyWithValue('dtstart', startTime);
|
||||||
|
newEvent.updatePropertyWithValue('dtend', endTime);
|
||||||
|
newEvent.updatePropertyWithValue('summary', vevent.summary.trim());
|
||||||
|
|
||||||
// 8. Add SEQUENCE (if available or default to 0)
|
|
||||||
const sequence = event.getFirstPropertyValue('sequence') || 0;
|
// Add the new event to the calendar component
|
||||||
newEvent.updatePropertyWithValue('sequence', sequence);
|
|
||||||
|
|
||||||
// Add the VEVENT to the calendar
|
|
||||||
calendarComponent.addSubcomponent(newEvent);
|
calendarComponent.addSubcomponent(newEvent);
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`Processed VEVENT components for calendar: ${result.name}`);
|
// Log the added events for debugging
|
||||||
} catch (error) {
|
console.log('Added events:', calendarComponent.toString());
|
||||||
|
} catch (error) {
|
||||||
console.error('Error processing calendar data:', error.message);
|
console.error('Error processing calendar data:', error.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -155,9 +104,8 @@ export function addEventsToCalendar(calendarComponent, results, overrideFlag = f
|
||||||
|
|
||||||
// Save calendar data to file
|
// Save calendar data to file
|
||||||
export function saveCalendarFile(filename, content) {
|
export function saveCalendarFile(filename, content) {
|
||||||
const normalizedContent = content.replace(/\r?\n/g, '\r\n').trimEnd(); // Normalize to CRLF
|
|
||||||
const filePath = path.join(MERGED_CALENDARS_DIR, filename);
|
const filePath = path.join(MERGED_CALENDARS_DIR, filename);
|
||||||
// console.log(`Saving calendar data to file: ${filePath}`);
|
console.log(`Saving calendar data to file: ${filePath}`);
|
||||||
fs.writeFileSync(filePath, normalizedContent);
|
fs.writeFileSync(filePath, content);
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
import { createRequire } from 'module';
|
const ICAL = require('./ical.js');
|
||||||
const require = createRequire(import.meta.url);
|
|
||||||
|
|
||||||
const ICAL = require('./ical.cjs');
|
|
||||||
(function() {
|
(function() {
|
||||||
function register(tzdata) { ICAL.TimezoneService.register(ICAL.Component.fromString("BEGIN:VTIMEZONE\r\n" + tzdata + "\r\nEND:VTIMEZONE")) };
|
function register(tzdata) { ICAL.TimezoneService.register(ICAL.Component.fromString("BEGIN:VTIMEZONE\r\n" + tzdata + "\r\nEND:VTIMEZONE")) };
|
||||||
ICAL.TimezoneService.IANA_TZDB_VERSION = "2024b";
|
ICAL.TimezoneService.IANA_TZDB_VERSION = "2024b";
|
||||||
|
|
|
@ -9,11 +9,9 @@ const EXPECTED_OUTPUTS_DIR = path.join(__dirname, 'expected_outputs');
|
||||||
|
|
||||||
let server;
|
let server;
|
||||||
process.chdir(__dirname)
|
process.chdir(__dirname)
|
||||||
// console.log(process.cwd());
|
console.log(process.cwd());
|
||||||
const app = require('../src/server').default;
|
const app = require('../src/server').default;
|
||||||
|
|
||||||
const normalizeLineEndings = (str) => str.replace(/\r\n/g, '\r\n').trimEnd(); // Normalize to CRLF
|
|
||||||
|
|
||||||
describe('Calendar Merging API', () => {
|
describe('Calendar Merging API', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
// Start the server
|
// Start the server
|
||||||
|
@ -53,27 +51,20 @@ describe('Calendar Merging API', () => {
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
// Check if the file was created in the test directory
|
// Check if the file was created in the test directory
|
||||||
const filePath = path.join(CALENDARS_DIR, 'nextcloud-minimal.ics');
|
const filePath = path.join(CALENDARS_DIR, 'nextcloud-minimal.ics');
|
||||||
// console.log('Checking if file exists at:', filePath);
|
console.log('Checking if file exists at:', filePath);
|
||||||
expect(fs.existsSync(filePath)).toBe(true);
|
expect(fs.existsSync(filePath)).toBe(true);
|
||||||
|
// Load expected output and compare
|
||||||
// Load expected output
|
|
||||||
const expectedOutput = fs.readFileSync(input, 'utf8');
|
const expectedOutput = fs.readFileSync(input, 'utf8');
|
||||||
const actualOutput = fs.readFileSync(filePath, 'utf8');
|
const actualOutput = fs.readFileSync(filePath, 'utf8');
|
||||||
|
expect(actualOutput).toBe(expectedOutput);
|
||||||
// Normalize line endings
|
|
||||||
const normalizedActual = normalizeLineEndings(actualOutput);
|
|
||||||
const normalizedExpected = normalizeLineEndings(expectedOutput);
|
|
||||||
|
|
||||||
//compare
|
|
||||||
expect(normalizedActual).toBe(normalizedExpected);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Preserve google calendar', async () => {
|
test('Preserve date-based calendar', async () => {
|
||||||
const input = getTestCalendarFilename('google-calendar-minimal.ics');
|
const input = getTestCalendarFilename('US_Holidays.ics');
|
||||||
const response = await request(server)
|
const response = await request(server)
|
||||||
.post('/merge')
|
.post('/merge')
|
||||||
.send({
|
.send({
|
||||||
linkGroupName: 'google-calendar-minimal',
|
linkGroupName: 'US Holidays',
|
||||||
calendars: [
|
calendars: [
|
||||||
{
|
{
|
||||||
url: input,
|
url: input,
|
||||||
|
@ -84,48 +75,15 @@ describe('Calendar Merging API', () => {
|
||||||
});
|
});
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
// Check if the file was created in the test directory
|
// Check if the file was created in the test directory
|
||||||
const filePath = path.join(CALENDARS_DIR, 'google-calendar-minimal.ics');
|
const filePath = path.join(CALENDARS_DIR, 'US_Holidays.ics');
|
||||||
// console.log('Checking if file exists at:', filePath);
|
console.log('Checking if file exists at:', filePath);
|
||||||
expect(fs.existsSync(filePath)).toBe(true);
|
expect(fs.existsSync(filePath)).toBe(true);
|
||||||
|
// Load expected output and compare
|
||||||
// Load expected output
|
|
||||||
const expectedOutput = fs.readFileSync(input, 'utf8');
|
const expectedOutput = fs.readFileSync(input, 'utf8');
|
||||||
const actualOutput = fs.readFileSync(filePath, 'utf8');
|
const actualOutput = fs.readFileSync(filePath, 'utf8');
|
||||||
|
expect(actualOutput).toBe(expectedOutput);
|
||||||
// Normalize line endings
|
|
||||||
const normalizedActual = normalizeLineEndings(actualOutput);
|
|
||||||
const normalizedExpected = normalizeLineEndings(expectedOutput);
|
|
||||||
|
|
||||||
//compare
|
|
||||||
expect(normalizedActual).toBe(normalizedExpected);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// test('Preserve date-based calendar', async () => {
|
|
||||||
// const input = getTestCalendarFilename('US_Holidays.ics');
|
|
||||||
// const response = await request(server)
|
|
||||||
// .post('/merge')
|
|
||||||
// .send({
|
|
||||||
// linkGroupName: 'US Holidays',
|
|
||||||
// calendars: [
|
|
||||||
// {
|
|
||||||
// url: input,
|
|
||||||
// prefix: '',
|
|
||||||
// override: false,
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// });
|
|
||||||
// expect(response.status).toBe(200);
|
|
||||||
// // Check if the file was created in the test directory
|
|
||||||
// const filePath = path.join(CALENDARS_DIR, 'US_Holidays.ics');
|
|
||||||
// console.log('Checking if file exists at:', filePath);
|
|
||||||
// expect(fs.existsSync(filePath)).toBe(true);
|
|
||||||
// // Load expected output and compare
|
|
||||||
// const expectedOutput = fs.readFileSync(input, 'utf8');
|
|
||||||
// const actualOutput = fs.readFileSync(filePath, 'utf8');
|
|
||||||
// expect(actualOutput).toBe(expectedOutput);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// test('Merge date-based calendar', async () => {
|
// test('Merge date-based calendar', async () => {
|
||||||
// const response = await request(server)
|
// const response = await request(server)
|
||||||
// .post('/merge')
|
// .post('/merge')
|
||||||
|
@ -158,61 +116,61 @@ describe('Calendar Merging API', () => {
|
||||||
// expect(actualOutput).toBe(expectedOutput);
|
// expect(actualOutput).toBe(expectedOutput);
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// test('Merge time-based calendar', async () => {
|
test('Merge time-based calendar', async () => {
|
||||||
// const input = getTestCalendarFilename('work_task_calendar.ics');
|
const input = getTestCalendarFilename('work_task_calendar.ics');
|
||||||
// const response = await request(server)
|
const response = await request(server)
|
||||||
// .post('/merge')
|
.post('/merge')
|
||||||
// .send({
|
.send({
|
||||||
// linkGroupName: 'Time Based Calendar',
|
linkGroupName: 'Time Based Calendar',
|
||||||
// calendars: [
|
calendars: [
|
||||||
// {
|
{
|
||||||
// url: input,
|
url: input,
|
||||||
// prefix: 'work_task',
|
prefix: 'work_task',
|
||||||
// override: false,
|
override: false,
|
||||||
// },
|
},
|
||||||
// ],
|
],
|
||||||
// });
|
});
|
||||||
|
|
||||||
// expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
// expect(response.body.url).toMatch(/calendar\/Time_Based_Calendar/);
|
expect(response.body.url).toMatch(/calendar\/Time_Based_Calendar/);
|
||||||
|
|
||||||
// // Check if the file was created in the test directory
|
// Check if the file was created in the test directory
|
||||||
// const filePath = path.join(CALENDARS_DIR, 'Time_Based_Calendar.ics');
|
const filePath = path.join(CALENDARS_DIR, 'Time_Based_Calendar.ics');
|
||||||
// expect(fs.existsSync(filePath)).toBe(true);
|
expect(fs.existsSync(filePath)).toBe(true);
|
||||||
|
|
||||||
// // Load expected output and compare
|
// Load expected output and compare
|
||||||
// const expectedOutput = fs.readFileSync(input, 'utf8');
|
const expectedOutput = fs.readFileSync(input, 'utf8');
|
||||||
// const actualOutput = fs.readFileSync(filePath, 'utf8');
|
const actualOutput = fs.readFileSync(filePath, 'utf8');
|
||||||
// expect(actualOutput).toBe(expectedOutput);
|
expect(actualOutput).toBe(expectedOutput);
|
||||||
// });
|
});
|
||||||
|
|
||||||
// test('EAT Event', async () => {
|
test('EAT Event', async () => {
|
||||||
// const input = getTestCalendarFilename('eat_time_zone_event.ics');
|
const input = getTestCalendarFilename('eat_time_zone_event.ics');
|
||||||
// const response = await request(server)
|
const response = await request(server)
|
||||||
// .post('/merge')
|
.post('/merge')
|
||||||
// .send({
|
.send({
|
||||||
// linkGroupName: 'EAT Event',
|
linkGroupName: 'EAT Event',
|
||||||
// calendars: [
|
calendars: [
|
||||||
// {
|
{
|
||||||
// url: input,
|
url: input,
|
||||||
// prefix: 'EAT Event',
|
prefix: 'EAT Event',
|
||||||
// override: false,
|
override: false,
|
||||||
// },
|
},
|
||||||
// ],
|
],
|
||||||
// });
|
});
|
||||||
|
|
||||||
// expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
// expect(response.body.url).toMatch(/calendar\/EAT_Event/);
|
expect(response.body.url).toMatch(/calendar\/EAT_Event/);
|
||||||
|
|
||||||
// // Check if the file was created in the test directory
|
// Check if the file was created in the test directory
|
||||||
// const filePath = path.join(CALENDARS_DIR, 'EAT_Event.ics');
|
const filePath = path.join(CALENDARS_DIR, 'EAT_Event.ics');
|
||||||
// expect(fs.existsSync(filePath)).toBe(true);
|
expect(fs.existsSync(filePath)).toBe(true);
|
||||||
|
|
||||||
// // Load expected output and compare
|
// Load expected output and compare
|
||||||
// const expectedOutput = fs.readFileSync(input, 'utf8');
|
const expectedOutput = fs.readFileSync(input, 'utf8');
|
||||||
// const actualOutput = fs.readFileSync(filePath, 'utf8');
|
const actualOutput = fs.readFileSync(filePath, 'utf8');
|
||||||
// expect(actualOutput).toBe(expectedOutput);
|
expect(actualOutput).toBe(expectedOutput);
|
||||||
// });
|
});
|
||||||
|
|
||||||
// test('Merge calendar without prefix', async () => {
|
// test('Merge calendar without prefix', async () => {
|
||||||
// const response = await request(server)
|
// const response = await request(server)
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
BEGIN:VCALENDAR
|
|
||||||
NAME:google-calendar-minimal
|
|
||||||
PRODID:-//CalMerge//Calendar Merger 1.0//EN
|
|
||||||
VERSION:2.0
|
|
||||||
CALSCALE:GREGORIAN
|
|
||||||
METHOD:PUBLISH
|
|
||||||
X-WR-TIMEZONE:Africa/Nairobi
|
|
||||||
BEGIN:VEVENT
|
|
||||||
DTSTART:20241003T190000Z
|
|
||||||
DTEND:20241003T200000Z
|
|
||||||
DTSTAMP:20241119T115316Z
|
|
||||||
UID:6tbrvsitniuu72li7kk15gou2b@google.com
|
|
||||||
SUMMARY:progodessey
|
|
||||||
SEQUENCE:0
|
|
||||||
END:VEVENT
|
|
||||||
END:VCALENDAR
|
|
|
@ -1,44 +0,0 @@
|
||||||
BEGIN:VCALENDAR
|
|
||||||
PRODID:-//Google Inc//Google Calendar 70.9054//EN
|
|
||||||
VERSION:2.0
|
|
||||||
CALSCALE:GREGORIAN
|
|
||||||
METHOD:PUBLISH
|
|
||||||
X-WR-CALNAME:work
|
|
||||||
X-WR-TIMEZONE:Africa/Nairobi
|
|
||||||
BEGIN:VEVENT
|
|
||||||
DTSTART:20240930T113000Z
|
|
||||||
DTEND:20240930T123000Z
|
|
||||||
DTSTAMP:20241119T115316Z
|
|
||||||
UID:0d0p2hp0l26ebuk2r0kb1q9kuo@google.com
|
|
||||||
CREATED:20240930T111532Z
|
|
||||||
LAST-MODIFIED:20240930T111532Z
|
|
||||||
SEQUENCE:0
|
|
||||||
STATUS:CONFIRMED
|
|
||||||
SUMMARY:other work
|
|
||||||
TRANSP:OPAQUE
|
|
||||||
END:VEVENT
|
|
||||||
BEGIN:VEVENT
|
|
||||||
DTSTART:20241003T190000Z
|
|
||||||
DTEND:20241003T200000Z
|
|
||||||
DTSTAMP:20241119T115316Z
|
|
||||||
UID:6tbrvsitniuu72li7kk15gou2b@google.com
|
|
||||||
CREATED:20241001T194455Z
|
|
||||||
LAST-MODIFIED:20241001T194455Z
|
|
||||||
SEQUENCE:0
|
|
||||||
STATUS:CONFIRMED
|
|
||||||
SUMMARY:progodessey
|
|
||||||
TRANSP:OPAQUE
|
|
||||||
END:VEVENT
|
|
||||||
BEGIN:VEVENT
|
|
||||||
DTSTART:20241009T173000Z
|
|
||||||
DTEND:20241009T183000Z
|
|
||||||
DTSTAMP:20241119T115316Z
|
|
||||||
UID:7l7n9nltrudluv65gfgll2q930@google.com
|
|
||||||
CREATED:20241010T123337Z
|
|
||||||
LAST-MODIFIED:20241010T123337Z
|
|
||||||
SEQUENCE:0
|
|
||||||
STATUS:CONFIRMED
|
|
||||||
SUMMARY:do
|
|
||||||
TRANSP:OPAQUE
|
|
||||||
END:VEVENT
|
|
||||||
END:VCALENDAR
|
|
|
@ -1,8 +1,7 @@
|
||||||
BEGIN:VCALENDAR
|
BEGIN:VCALENDAR
|
||||||
NAME:nextcloud-minimal
|
|
||||||
PRODID:-//CalMerge//Calendar Merger 1.0//EN
|
|
||||||
VERSION:2.0
|
VERSION:2.0
|
||||||
CALSCALE:GREGORIAN
|
CALSCALE:GREGORIAN
|
||||||
|
PRODID:-//SabreDAV//SabreDAV//EN
|
||||||
BEGIN:VTIMEZONE
|
BEGIN:VTIMEZONE
|
||||||
TZID:Europe/Berlin
|
TZID:Europe/Berlin
|
||||||
BEGIN:DAYLIGHT
|
BEGIN:DAYLIGHT
|
||||||
|
@ -21,13 +20,13 @@ RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
|
||||||
END:STANDARD
|
END:STANDARD
|
||||||
END:VTIMEZONE
|
END:VTIMEZONE
|
||||||
BEGIN:VEVENT
|
BEGIN:VEVENT
|
||||||
DTSTART;TZID=Europe/Berlin:20241120T211500
|
|
||||||
DTEND;TZID=Europe/Berlin:20241120T215000
|
DTEND;TZID=Europe/Berlin:20241120T215000
|
||||||
DTSTAMP:20241113T212909Z
|
DTSTAMP:20241113T212909Z
|
||||||
UID:5f4ad965-16a8-48eb-8233-78bf93a8b35e
|
DTSTART;TZID=Europe/Berlin:20241120T211500
|
||||||
LOCATION:FaceTime
|
LOCATION:FaceTime
|
||||||
RRULE:FREQ=WEEKLY;BYDAY=WE
|
RRULE:FREQ=WEEKLY;BYDAY=WE
|
||||||
SUMMARY:JR Weekly Check-In
|
|
||||||
SEQUENCE:0
|
SEQUENCE:0
|
||||||
|
SUMMARY:JR Weekly Check-In
|
||||||
|
UID:5f4ad965-16a8-48eb-8233-78bf93a8b35e
|
||||||
END:VEVENT
|
END:VEVENT
|
||||||
END:VCALENDAR
|
END:VCALENDAR
|
||||||
|
|
Loading…
Add table
Reference in a new issue