Merge branch 'feature/cardav-contacts'
# Conflicts: # package-lock.json
This commit is contained in:
+128
-1
@@ -1074,6 +1074,112 @@ const MIGRATIONS = [
|
||||
db.exec(`CREATE UNIQUE INDEX idx_calendar_sub_extid ON calendar_events (subscription_id, external_calendar_id)`);
|
||||
},
|
||||
},
|
||||
{
|
||||
version: 30,
|
||||
description: 'CardDAV multi-account contacts sync',
|
||||
up: `
|
||||
-- ========================================
|
||||
-- CardDAV Accounts
|
||||
-- ========================================
|
||||
CREATE TABLE carddav_accounts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
carddav_url TEXT NOT NULL,
|
||||
username TEXT NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
||||
last_sync TEXT,
|
||||
UNIQUE(carddav_url, username)
|
||||
);
|
||||
|
||||
-- ========================================
|
||||
-- CardDAV Addressbook Selection
|
||||
-- ========================================
|
||||
CREATE TABLE carddav_addressbook_selection (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
account_id INTEGER NOT NULL,
|
||||
addressbook_url TEXT NOT NULL,
|
||||
addressbook_name TEXT NOT NULL,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
||||
UNIQUE(account_id, addressbook_url),
|
||||
FOREIGN KEY(account_id) REFERENCES carddav_accounts(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_carddav_addressbook_account
|
||||
ON carddav_addressbook_selection(account_id, enabled);
|
||||
|
||||
-- ========================================
|
||||
-- Extend Contacts Table for CardDAV
|
||||
-- ========================================
|
||||
ALTER TABLE contacts ADD COLUMN organization TEXT;
|
||||
ALTER TABLE contacts ADD COLUMN job_title TEXT;
|
||||
ALTER TABLE contacts ADD COLUMN birthday TEXT;
|
||||
ALTER TABLE contacts ADD COLUMN website TEXT;
|
||||
ALTER TABLE contacts ADD COLUMN photo TEXT;
|
||||
ALTER TABLE contacts ADD COLUMN nickname TEXT;
|
||||
ALTER TABLE contacts ADD COLUMN carddav_account_id INTEGER
|
||||
REFERENCES carddav_accounts(id) ON DELETE SET NULL;
|
||||
ALTER TABLE contacts ADD COLUMN carddav_uid TEXT;
|
||||
ALTER TABLE contacts ADD COLUMN carddav_addressbook_url TEXT;
|
||||
|
||||
CREATE INDEX idx_contacts_carddav_uid ON contacts(carddav_uid);
|
||||
CREATE INDEX idx_contacts_email ON contacts(email);
|
||||
|
||||
-- UNIQUE constraint for CardDAV UIDs (prevents duplicates per account+addressbook)
|
||||
CREATE UNIQUE INDEX idx_contacts_carddav_uid_unique
|
||||
ON contacts(carddav_account_id, carddav_addressbook_url, carddav_uid)
|
||||
WHERE carddav_uid IS NOT NULL;
|
||||
|
||||
-- ========================================
|
||||
-- Contact Phones (Multiple per Contact)
|
||||
-- ========================================
|
||||
CREATE TABLE contact_phones (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
contact_id INTEGER NOT NULL,
|
||||
label TEXT,
|
||||
value TEXT NOT NULL,
|
||||
is_primary INTEGER NOT NULL DEFAULT 0,
|
||||
FOREIGN KEY(contact_id) REFERENCES contacts(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_contact_phones_contact ON contact_phones(contact_id);
|
||||
CREATE INDEX idx_contact_phones_value ON contact_phones(value);
|
||||
|
||||
-- ========================================
|
||||
-- Contact Emails (Multiple per Contact)
|
||||
-- ========================================
|
||||
CREATE TABLE contact_emails (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
contact_id INTEGER NOT NULL,
|
||||
label TEXT,
|
||||
value TEXT NOT NULL,
|
||||
is_primary INTEGER NOT NULL DEFAULT 0,
|
||||
FOREIGN KEY(contact_id) REFERENCES contacts(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_contact_emails_contact ON contact_emails(contact_id);
|
||||
CREATE INDEX idx_contact_emails_value ON contact_emails(value);
|
||||
|
||||
-- ========================================
|
||||
-- Contact Addresses (Multiple per Contact)
|
||||
-- ========================================
|
||||
CREATE TABLE contact_addresses (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
contact_id INTEGER NOT NULL,
|
||||
label TEXT,
|
||||
street TEXT,
|
||||
city TEXT,
|
||||
state TEXT,
|
||||
postal_code TEXT,
|
||||
country TEXT,
|
||||
is_primary INTEGER NOT NULL DEFAULT 0,
|
||||
FOREIGN KEY(contact_id) REFERENCES contacts(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_contact_addresses_contact ON contact_addresses(contact_id);
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -1247,6 +1353,27 @@ function transaction(fn) {
|
||||
return get().transaction(fn)();
|
||||
}
|
||||
|
||||
let _originalDb = null;
|
||||
|
||||
/**
|
||||
* ONLY FOR TESTING: Override the internal db instance
|
||||
* @param {import('better-sqlite3').Database} testDb
|
||||
*/
|
||||
function _setTestDatabase(testDb) {
|
||||
if (!_originalDb) _originalDb = db;
|
||||
db = testDb;
|
||||
}
|
||||
|
||||
/**
|
||||
* ONLY FOR TESTING: Restore the original db instance
|
||||
*/
|
||||
function _resetTestDatabase() {
|
||||
if (_originalDb) {
|
||||
db = _originalDb;
|
||||
_originalDb = null;
|
||||
}
|
||||
}
|
||||
|
||||
init(); // auto-initialise when module is first imported
|
||||
|
||||
export { init, get, transaction, currentVersion, getPath, backupToFile, restoreFromFile };
|
||||
export { init, get, transaction, currentVersion, getPath, backupToFile, restoreFromFile, MIGRATIONS, _setTestDatabase, _resetTestDatabase };
|
||||
|
||||
Reference in New Issue
Block a user