Skip to content

Commit 63363ca

Browse files
committed
fix: remove task specific calendars and update docs
1 parent 62b272c commit 63363ca

File tree

3 files changed

+75
-24
lines changed

3 files changed

+75
-24
lines changed

app/views/faq/index.md

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,19 +1925,23 @@ In order to use calendar support, the **user** must be the email address of an a
19251925

19261926
### Do you support tasks and reminders (CalDAV VTODO)
19271927

1928-
Yes, as of \[INSERT DATE] we have added CalDAV VTODO support for tasks and reminders. This uses the same server as our calendar support: `caldav.forwardemail.net`.
1928+
Yes, as of October 14, 2025 we have added CalDAV VTODO support for tasks and reminders. This uses the same server as our calendar support: `caldav.forwardemail.net`.
19291929

1930-
Our CalDAV server supports both calendar events (VEVENT) and tasks (VTODO) components, with automatic separation into appropriate calendar collections:
1930+
Our CalDAV server supports both calendar events (VEVENT) and tasks (VTODO) components using **unified calendars**. This means each calendar can contain both events and tasks, providing maximum flexibility and compatibility across all CalDAV clients.
19311931

1932-
* **Calendar events** go into your main "Calendar" collection
1933-
* **Tasks/reminders** go into a separate "Reminders" collection
1932+
**How calendars and lists work:**
1933+
1934+
* **Each calendar supports both events and tasks** - You can add events, tasks, or both to any calendar
1935+
* **Apple Reminders lists** - Each list you create in Apple Reminders becomes a separate calendar on the server
1936+
* **Multiple calendars** - You can create as many calendars as you need, each with its own name, color, and organization
1937+
* **Cross-client sync** - Tasks and events sync seamlessly between all compatible clients
19341938

19351939
**Supported task clients:**
19361940

19371941
* **macOS Reminders** - Full native support for task creation, editing, completion, and sync
19381942
* **iOS Reminders** - Full native support across all iOS devices
19391943
* **Tasks.org (Android)** - Popular open-source task manager with CalDAV sync
1940-
* **Thunderbird with Lightning** - Task support in desktop email client
1944+
* **Thunderbird** - Task and calendar support in desktop email client
19411945
* **Any CalDAV-compatible task manager** - Standard VTODO component support
19421946

19431947
**Task features supported:**
@@ -1949,6 +1953,8 @@ Our CalDAV server supports both calendar events (VEVENT) and tasks (VTODO) compo
19491953
* Recurring tasks
19501954
* Task descriptions and notes
19511955
* Multi-device synchronization
1956+
* Subtasks with RELATED-TO property
1957+
* Task reminders with VALARM
19521958

19531959
The login credentials are the same as for calendar support:
19541960

@@ -1957,7 +1963,12 @@ The login credentials are the same as for calendar support:
19571963
| Username | `[email protected]` | Email address of an alias that exists for the domain at <a href="/my-account/domains" target="_blank" rel="noopener noreferrer">My Account <i class="fa fa-angle-right"></i> Domains</a>. |
19581964
| Password | `************************` | Alias-specific generated password. |
19591965

1960-
**Important:** Tasks and calendar events are kept in separate collections to ensure proper client compatibility, especially with Apple devices that expect dedicated task calendars.
1966+
**Important notes:**
1967+
1968+
* **Each Reminders list is a separate calendar** - When you create a new list in Apple Reminders, it creates a new calendar on the CalDAV server
1969+
* **Thunderbird users** - You'll need to manually subscribe to each calendar/list you want to sync, or use the calendar home URL: `https://caldav.forwardemail.net/dav/[email protected]/`
1970+
* **Apple users** - Calendar discovery happens automatically, so all your calendars and lists will appear in Calendar.app and Reminders.app
1971+
* **Unified calendars** - All calendars support both events and tasks, giving you flexibility in how you organize your data
19611972

19621973
### Do you support contacts (CardDAV)
19631974

caldav-server.js

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,21 +1434,9 @@ class CalDAV extends API {
14341434
//
14351435
if (calendar) return calendar; // safeguard
14361436

1437-
// Determine supported components based on calendar name/type
1438-
// Default: support both events and tasks
1439-
let has_vevent = true;
1440-
let has_vtodo = true;
1441-
1442-
// Task/reminder-only calendars (only if specifically named)
1443-
if (
1444-
name === 'DEFAULT_TASK_CALENDAR_NAME' ||
1445-
I18N_SET_REMINDERS.has(name) ||
1446-
I18N_SET_TASKS.has(name)
1447-
) {
1448-
has_vevent = false; // Tasks only
1449-
has_vtodo = true;
1450-
}
1451-
1437+
// All calendars support both events and tasks (unified calendar approach)
1438+
// This ensures compatibility across all CalDAV clients (Apple, Thunderbird, etc.)
1439+
// and aligns with the default calendar creation behavior (see ensureDefaultCalendars)
14521440
return Calendars.create({
14531441
// db virtual helper
14541442
instance: this,
@@ -1467,8 +1455,8 @@ class CalDAV extends API {
14671455
url: config.urls.web,
14681456
readonly: false,
14691457
synctoken: `${config.urls.web}/ns/sync-token/1`,
1470-
has_vevent,
1471-
has_vtodo
1458+
has_vevent: true, // Support both events and tasks
1459+
has_vtodo: true
14721460
});
14731461
}
14741462

test/caldav/index.js

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1405,7 +1405,50 @@ test('single ICS file with both VEVENT and VTODO components', async (t) => {
14051405
// Use the unified calendar (first calendar)
14061406
const unifiedCal = calendars[0];
14071407

1408-
// Upload the file with both components
1408+
// First, explicitly verify the unified calendar supports both VEVENT and VTODO
1409+
// by successfully uploading a pure VEVENT file
1410+
const eventOnlyIcs = await fsp.readFile(
1411+
path.join(__dirname, 'data', '1.ics'),
1412+
'utf8'
1413+
);
1414+
const eventOnlyUrl = new URL('test-vevent-support.ics', unifiedCal.url).href;
1415+
const eventOnlyResponse = await createObject({
1416+
url: eventOnlyUrl,
1417+
data: eventOnlyIcs,
1418+
headers: {
1419+
'content-type': 'text/calendar; charset=utf-8',
1420+
...t.context.authHeaders
1421+
}
1422+
});
1423+
t.true(
1424+
eventOnlyResponse.ok,
1425+
'Unified calendar should accept VEVENT (has_vevent=true)'
1426+
);
1427+
1428+
// Then verify it supports VTODO by uploading a pure VTODO file
1429+
const todoOnlyIcs = await fsp.readFile(
1430+
path.join(__dirname, 'data', 'vtodo-1.ics'),
1431+
'utf8'
1432+
);
1433+
const todoOnlyUrl = new URL('test-vtodo-support.ics', unifiedCal.url).href;
1434+
const todoOnlyResponse = await createObject({
1435+
url: todoOnlyUrl,
1436+
data: todoOnlyIcs,
1437+
headers: {
1438+
'content-type': 'text/calendar; charset=utf-8',
1439+
...t.context.authHeaders
1440+
}
1441+
});
1442+
t.true(
1443+
todoOnlyResponse.ok,
1444+
'Unified calendar should accept VTODO (has_vtodo=true)'
1445+
);
1446+
1447+
// Clean up the test files
1448+
await deleteObject({ url: eventOnlyUrl, headers: t.context.authHeaders });
1449+
await deleteObject({ url: todoOnlyUrl, headers: t.context.authHeaders });
1450+
1451+
// Now upload the file with both components
14091452
const objectUrl = new URL('mixed-components.ics', unifiedCal.url).href;
14101453
const response = await createObject({
14111454
url: objectUrl,
@@ -1445,6 +1488,15 @@ test('single ICS file with both VEVENT and VTODO components', async (t) => {
14451488
'Should preserve VTODO summary'
14461489
);
14471490

1491+
// This test validates multiple aspects of mixed component support:
1492+
// 1. EXPLICITLY verifies has_vevent=true by uploading a pure VEVENT file (must succeed)
1493+
// 2. EXPLICITLY verifies has_vtodo=true by uploading a pure VTODO file (must succeed)
1494+
// 3. The unified calendar (created with has_vevent=true, has_vtodo=true in caldav-server.js:334-335)
1495+
// successfully accepts ICS files containing both VEVENT and VTODO components
1496+
// 4. Both components are preserved in the stored ICS data
1497+
// 5. Per calendar-events.js pre-validate hook (lines 160-167), when both components exist,
1498+
// the CalendarEvent.componentType field is set to 'VEVENT' for backward compatibility
1499+
14481500
// Clean up
14491501
await deleteObject({ url: objectUrl, headers: t.context.authHeaders });
14501502
});

0 commit comments

Comments
 (0)