mirror of
https://github.com/nfonteyne/octane-website.git
synced 2026-09-03 23:24:48 +02:00
update: work with webcal
This commit is contained in:
parent
5dce6eb89b
commit
fd81b74594
4 changed files with 40 additions and 3 deletions
12
src/lib/icsUrl.js
Normal file
12
src/lib/icsUrl.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Apple/iCloud (and some other providers) hand out webcal:// links — that
|
||||
// scheme is just a convention meaning "this is a calendar subscription, open
|
||||
// it with your calendar app" and isn't something fetch() can request, so
|
||||
// without this it fails with a confusing network error. webcal(s):// always
|
||||
// resolves to the same feed over plain http(s), so swap the scheme and fetch
|
||||
// that instead. Applied once, at add-time, so the stored URL is already the
|
||||
// fetchable form and every later sync just works.
|
||||
function normalizeIcsUrl(url) {
|
||||
return url.replace(/^webcals?:\/\//i, 'https://');
|
||||
}
|
||||
|
||||
module.exports = { normalizeIcsUrl };
|
||||
|
|
@ -3,6 +3,7 @@ const calendarRepo = require('../repositories/calendarRepo');
|
|||
const usersRepo = require('../repositories/usersRepo');
|
||||
const workflowState = require('../lib/calendarWorkflowState');
|
||||
const calendarSync = require('../services/calendarSync');
|
||||
const { normalizeIcsUrl } = require('../lib/icsUrl');
|
||||
const { requireAdmin } = require('../auth/middleware');
|
||||
const asyncHandler = require('../lib/asyncHandler');
|
||||
|
||||
|
|
@ -93,7 +94,7 @@ router.post(
|
|||
if (!icsUrl || !icsUrl.trim()) {
|
||||
return res.status(400).json({ error: 'ics_url_required' });
|
||||
}
|
||||
const trimmedUrl = icsUrl.trim();
|
||||
const trimmedUrl = normalizeIcsUrl(icsUrl.trim());
|
||||
try {
|
||||
await calendarSync.testFeed(trimmedUrl);
|
||||
} catch (err) {
|
||||
|
|
@ -148,7 +149,7 @@ router.post(
|
|||
if (!user) {
|
||||
return res.status(404).json({ error: 'user_not_found' });
|
||||
}
|
||||
const trimmedUrl = icsUrl.trim();
|
||||
const trimmedUrl = normalizeIcsUrl(icsUrl.trim());
|
||||
try {
|
||||
await calendarSync.testFeed(trimmedUrl);
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ const ical = require('node-ical');
|
|||
const calendarRepo = require('../repositories/calendarRepo');
|
||||
const { generateSlots, isBusyDuring, widenWindow } = require('../lib/calendarAvailability');
|
||||
const { parisWallClockToUTC } = require('../lib/calendarDates');
|
||||
const { normalizeIcsUrl } = require('../lib/icsUrl');
|
||||
|
||||
const RANGE_DAYS = 105; // slightly more than the 14 weeks generateSlots() covers
|
||||
const FETCH_TIMEOUT_MS = 15000;
|
||||
|
|
@ -13,7 +14,10 @@ async function fetchIcsCalendar(icsUrl) {
|
|||
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
||||
let text;
|
||||
try {
|
||||
const response = await fetch(icsUrl, { signal: controller.signal });
|
||||
// Defensive: normalize here too, not just at add-time in routes/calendar.js,
|
||||
// so a webcal:// URL stored before that fix (or inserted directly) doesn't
|
||||
// keep silently failing every sync.
|
||||
const response = await fetch(normalizeIcsUrl(icsUrl), { signal: controller.signal });
|
||||
if (!response.ok) throw new Error(`ICS fetch failed: ${response.status}`);
|
||||
text = await response.text();
|
||||
} finally {
|
||||
|
|
|
|||
20
test/icsUrl.test.js
Normal file
20
test/icsUrl.test.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
const { test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const { normalizeIcsUrl } = require('../src/lib/icsUrl');
|
||||
|
||||
test('normalizeIcsUrl: rewrites webcal:// to https://', () => {
|
||||
assert.equal(normalizeIcsUrl('webcal://p01-caldav.icloud.com/foo.ics'), 'https://p01-caldav.icloud.com/foo.ics');
|
||||
});
|
||||
|
||||
test('normalizeIcsUrl: rewrites webcals:// to https://', () => {
|
||||
assert.equal(normalizeIcsUrl('webcals://p01-caldav.icloud.com/foo.ics'), 'https://p01-caldav.icloud.com/foo.ics');
|
||||
});
|
||||
|
||||
test('normalizeIcsUrl: is case-insensitive on the scheme', () => {
|
||||
assert.equal(normalizeIcsUrl('WebCal://example.com/foo.ics'), 'https://example.com/foo.ics');
|
||||
});
|
||||
|
||||
test('normalizeIcsUrl: leaves http/https URLs untouched', () => {
|
||||
assert.equal(normalizeIcsUrl('https://example.com/foo.ics'), 'https://example.com/foo.ics');
|
||||
assert.equal(normalizeIcsUrl('http://example.com/foo.ics'), 'http://example.com/foo.ics');
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue