59773bd797
Add createAccount, updateAccount, deleteAccount functions with validation, error handling, and logging. Implements Task 3 from the CalDAV multi-account spec. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
161 lines
4.2 KiB
JavaScript
161 lines
4.2 KiB
JavaScript
/**
|
|
* Modul: Generic CalDAV Sync
|
|
* Zweck: Multi-Account CalDAV synchronization with calendar selection
|
|
* Abhängigkeiten: tsdav, server/db.js, server/services/ics-parser.js
|
|
*/
|
|
|
|
import { createLogger } from '../logger.js';
|
|
const log = createLogger('CalDAV');
|
|
|
|
import * as db from '../db.js';
|
|
|
|
// Reused functions from apple-calendar.js
|
|
import {
|
|
parseICS,
|
|
formatICSDate,
|
|
tzLocalToUTC,
|
|
applyDuration
|
|
} from './ics-parser.js';
|
|
|
|
// --------------------------------------------------------
|
|
// Helper Functions
|
|
// --------------------------------------------------------
|
|
|
|
function normalizeCalColor(c) {
|
|
if (!c) return null;
|
|
if (/^#[0-9a-fA-F]{8}$/.test(c)) return c.slice(0, 7); // strip alpha
|
|
if (/^#[0-9a-fA-F]{6}$/.test(c)) return c;
|
|
return null;
|
|
}
|
|
|
|
function upsertExternalCalendar(source, externalId, name, color) {
|
|
const row = db.get().prepare(`
|
|
INSERT INTO external_calendars (source, external_id, name, color)
|
|
VALUES (?, ?, ?, ?)
|
|
ON CONFLICT(source, external_id) DO UPDATE SET
|
|
name = excluded.name,
|
|
color = excluded.color
|
|
RETURNING id
|
|
`).get(source, externalId, name, color);
|
|
return row.id;
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Credentials Helpers
|
|
// --------------------------------------------------------
|
|
|
|
function getAccountById(accountId) {
|
|
return db.get().prepare('SELECT * FROM caldav_accounts WHERE id = ?').get(accountId);
|
|
}
|
|
|
|
function getAllAccounts() {
|
|
return db.get().prepare('SELECT * FROM caldav_accounts').all();
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Account CRUD Operations
|
|
// --------------------------------------------------------
|
|
|
|
/**
|
|
* Create a new CalDAV account
|
|
* @param {string} label - User-friendly label
|
|
* @param {string} url - CalDAV server URL
|
|
* @param {string} username - Account username
|
|
* @param {string} password - Account password
|
|
* @returns {number} Account ID
|
|
*/
|
|
function createAccount(label, url, username, password) {
|
|
if (!label || !url || !username || !password) {
|
|
throw new Error('All fields required: label, url, username, password');
|
|
}
|
|
|
|
const result = db.get().prepare(`
|
|
INSERT INTO caldav_accounts (label, url, username, password)
|
|
VALUES (?, ?, ?, ?)
|
|
`).run(label, url, username, password);
|
|
|
|
log.info('CalDAV account created', { id: result.lastInsertRowid, label });
|
|
return result.lastInsertRowid;
|
|
}
|
|
|
|
/**
|
|
* Update an existing CalDAV account
|
|
* @param {number} accountId - Account ID
|
|
* @param {object} updates - Fields to update
|
|
* @returns {void}
|
|
*/
|
|
function updateAccount(accountId, updates) {
|
|
const account = getAccountById(accountId);
|
|
if (!account) {
|
|
throw new Error(`CalDAV account not found: ${accountId}`);
|
|
}
|
|
|
|
const { label, url, username, password } = updates;
|
|
const fields = [];
|
|
const values = [];
|
|
|
|
if (label !== undefined) {
|
|
fields.push('label = ?');
|
|
values.push(label);
|
|
}
|
|
if (url !== undefined) {
|
|
fields.push('url = ?');
|
|
values.push(url);
|
|
}
|
|
if (username !== undefined) {
|
|
fields.push('username = ?');
|
|
values.push(username);
|
|
}
|
|
if (password !== undefined) {
|
|
fields.push('password = ?');
|
|
values.push(password);
|
|
}
|
|
|
|
if (fields.length === 0) {
|
|
throw new Error('No fields to update');
|
|
}
|
|
|
|
values.push(accountId);
|
|
|
|
db.get().prepare(`
|
|
UPDATE caldav_accounts
|
|
SET ${fields.join(', ')}
|
|
WHERE id = ?
|
|
`).run(...values);
|
|
|
|
log.info('CalDAV account updated', { id: accountId, fields: Object.keys(updates) });
|
|
}
|
|
|
|
/**
|
|
* Delete a CalDAV account and all associated data
|
|
* @param {number} accountId - Account ID
|
|
* @returns {void}
|
|
*/
|
|
function deleteAccount(accountId) {
|
|
const account = getAccountById(accountId);
|
|
if (!account) {
|
|
throw new Error(`CalDAV account not found: ${accountId}`);
|
|
}
|
|
|
|
// Foreign key constraints will cascade delete:
|
|
// - caldav_selected_calendars
|
|
// - external_calendars (via source)
|
|
// - calendar_events (via external_calendar_id)
|
|
|
|
db.get().prepare('DELETE FROM caldav_accounts WHERE id = ?').run(accountId);
|
|
|
|
log.info('CalDAV account deleted', { id: accountId, label: account.label });
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Exports
|
|
// --------------------------------------------------------
|
|
|
|
export {
|
|
createAccount,
|
|
updateAccount,
|
|
deleteAccount,
|
|
getAccountById,
|
|
getAllAccounts
|
|
};
|