mirror of
https://github.com/abort-retry-ignore/joplock.git
synced 2026-05-23 04:28:34 +00:00
188 lines
6 KiB
JavaScript
188 lines
6 KiB
JavaScript
const validThemes = ['matrix','matrix-blue','matrix-purple','matrix-amber','matrix-orange','dark-grey','dark-red','dark','light','oled-dark','solarized-light','solarized-dark','nord','dracula','aritim-dark'];
|
|
|
|
const validDateFormats = [
|
|
'YYYY-MM-DD',
|
|
'MM/DD/YYYY',
|
|
'DD/MM/YYYY',
|
|
'MMM DD, YYYY',
|
|
'DD MMM YYYY',
|
|
'YYYY.MM.DD',
|
|
];
|
|
|
|
const validDatetimeFormats = [
|
|
'YYYY-MM-DD HH:mm',
|
|
'MM/DD/YYYY HH:mm',
|
|
'DD/MM/YYYY HH:mm',
|
|
'MMM DD, YYYY HH:mm',
|
|
'DD MMM YYYY HH:mm',
|
|
'YYYY.MM.DD HH:mm',
|
|
'YYYY-MM-DD HH:mm:ss',
|
|
'MM/DD/YYYY hh:mm A',
|
|
'DD/MM/YYYY hh:mm A',
|
|
];
|
|
|
|
const defaultSettings = Object.freeze({
|
|
noteFontSize: 15,
|
|
mobileNoteFontSize: 17,
|
|
codeFontSize: 12,
|
|
noteMonospace: false,
|
|
noteOpenMode: 'preview',
|
|
resumeLastNote: true,
|
|
lastNoteId: '',
|
|
lastNoteFolderId: '',
|
|
dateFormat: 'YYYY-MM-DD',
|
|
datetimeFormat: 'YYYY-MM-DD HH:mm',
|
|
autoLogout: false,
|
|
autoLogoutMinutes: 15,
|
|
theme: 'matrix',
|
|
liveSearch: false,
|
|
confirmTrash: true,
|
|
encryptionAutoLockMinutes: 5,
|
|
uiMode: 'auto',
|
|
});
|
|
|
|
const validUiModes = ['auto', 'mobile', 'desktop'];
|
|
|
|
const nowMs = () => Date.now();
|
|
|
|
const normalizeInteger = (value, fallback, min, max) => {
|
|
const numeric = Number.parseInt(`${value}`, 10);
|
|
if (Number.isNaN(numeric)) return fallback;
|
|
return Math.max(min, Math.min(max, numeric));
|
|
};
|
|
|
|
const normalizeSettings = settings => ({
|
|
noteFontSize: normalizeInteger(settings.noteFontSize, defaultSettings.noteFontSize, 12, 24),
|
|
mobileNoteFontSize: normalizeInteger(settings.mobileNoteFontSize, normalizeInteger(settings.noteFontSize, defaultSettings.noteFontSize, 12, 24) + 2, 12, 28),
|
|
codeFontSize: normalizeInteger(settings.codeFontSize, defaultSettings.codeFontSize, 10, 22),
|
|
noteMonospace: !!Number(settings.noteMonospace) || settings.noteMonospace === true || settings.noteMonospace === '1',
|
|
noteOpenMode: settings.noteOpenMode === 'markdown' ? 'markdown' : defaultSettings.noteOpenMode,
|
|
resumeLastNote: !!Number(settings.resumeLastNote) || settings.resumeLastNote === true || settings.resumeLastNote === '1',
|
|
lastNoteId: `${settings.lastNoteId || ''}`,
|
|
lastNoteFolderId: `${settings.lastNoteFolderId || ''}`,
|
|
dateFormat: validDateFormats.includes(settings.dateFormat) ? settings.dateFormat : defaultSettings.dateFormat,
|
|
datetimeFormat: validDatetimeFormats.includes(settings.datetimeFormat) ? settings.datetimeFormat : defaultSettings.datetimeFormat,
|
|
autoLogout: !!Number(settings.autoLogout) || settings.autoLogout === true || settings.autoLogout === '1',
|
|
autoLogoutMinutes: normalizeInteger(settings.autoLogoutMinutes, defaultSettings.autoLogoutMinutes, 1, 480),
|
|
theme: validThemes.includes(settings.theme) ? settings.theme : defaultSettings.theme,
|
|
liveSearch: !!Number(settings.liveSearch) || settings.liveSearch === true || settings.liveSearch === '1',
|
|
confirmTrash: settings.confirmTrash !== false && settings.confirmTrash !== '0' && settings.confirmTrash !== 0,
|
|
encryptionAutoLockMinutes: normalizeInteger(settings.encryptionAutoLockMinutes, defaultSettings.encryptionAutoLockMinutes, 0, 480),
|
|
uiMode: validUiModes.includes(settings.uiMode) ? settings.uiMode : defaultSettings.uiMode,
|
|
});
|
|
|
|
const createSettingsService = database => {
|
|
let _tableAvailable = null;
|
|
|
|
const ensureTable = async () => {
|
|
if (_tableAvailable !== null) return;
|
|
try {
|
|
await database.query(`
|
|
CREATE TABLE IF NOT EXISTS joplock_settings (
|
|
user_id VARCHAR(32) PRIMARY KEY,
|
|
settings JSONB NOT NULL DEFAULT '{}',
|
|
updated_time BIGINT NOT NULL,
|
|
totp_seed VARCHAR(64)
|
|
)
|
|
`);
|
|
// Add totp_seed column if missing (migration for existing tables)
|
|
await database.query(`
|
|
ALTER TABLE joplock_settings ADD COLUMN IF NOT EXISTS totp_seed VARCHAR(64)
|
|
`).catch(() => {});
|
|
_tableAvailable = true;
|
|
} catch {
|
|
_tableAvailable = false;
|
|
}
|
|
};
|
|
|
|
return {
|
|
async settingsByUserId(userId) {
|
|
await ensureTable();
|
|
if (!_tableAvailable) return { ...defaultSettings };
|
|
try {
|
|
const result = await database.query(
|
|
'SELECT settings FROM joplock_settings WHERE user_id = $1 LIMIT 1',
|
|
[userId],
|
|
);
|
|
const row = result.rows[0];
|
|
if (!row) return { ...defaultSettings };
|
|
const json = typeof row.settings === 'string' ? JSON.parse(row.settings) : (row.settings || {});
|
|
return normalizeSettings({ ...defaultSettings, ...json });
|
|
} catch {
|
|
return { ...defaultSettings };
|
|
}
|
|
},
|
|
|
|
async saveSettings(userId, settings) {
|
|
await ensureTable();
|
|
const normalized = normalizeSettings(settings);
|
|
if (!_tableAvailable) return normalized;
|
|
const timestamp = nowMs();
|
|
await database.query(`
|
|
INSERT INTO joplock_settings (user_id, settings, updated_time)
|
|
VALUES ($1, $2, $3)
|
|
ON CONFLICT (user_id) DO UPDATE SET
|
|
settings = EXCLUDED.settings,
|
|
updated_time = EXCLUDED.updated_time
|
|
`, [userId, JSON.stringify(normalized), timestamp]);
|
|
return normalized;
|
|
},
|
|
|
|
async getTotpSeed(userId) {
|
|
await ensureTable();
|
|
if (!_tableAvailable) return null;
|
|
try {
|
|
const result = await database.query(
|
|
'SELECT totp_seed FROM joplock_settings WHERE user_id = $1 LIMIT 1',
|
|
[userId],
|
|
);
|
|
return result.rows[0]?.totp_seed || null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
},
|
|
|
|
async setTotpSeed(userId, seed) {
|
|
await ensureTable();
|
|
if (!_tableAvailable) return false;
|
|
const timestamp = nowMs();
|
|
try {
|
|
await database.query(`
|
|
INSERT INTO joplock_settings (user_id, settings, updated_time, totp_seed)
|
|
VALUES ($1, '{}', $2, $3)
|
|
ON CONFLICT (user_id) DO UPDATE SET
|
|
totp_seed = EXCLUDED.totp_seed,
|
|
updated_time = EXCLUDED.updated_time
|
|
`, [userId, timestamp, seed]);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
async clearTotpSeed(userId) {
|
|
await ensureTable();
|
|
if (!_tableAvailable) return false;
|
|
const timestamp = nowMs();
|
|
try {
|
|
await database.query(
|
|
'UPDATE joplock_settings SET totp_seed = NULL, updated_time = $2 WHERE user_id = $1',
|
|
[userId, timestamp],
|
|
);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
},
|
|
};
|
|
};
|
|
|
|
module.exports = {
|
|
createSettingsService,
|
|
defaultSettings,
|
|
normalizeSettings,
|
|
validDateFormats,
|
|
validDatetimeFormats,
|
|
validThemes,
|
|
validUiModes,
|
|
};
|