162 lines
5.1 KiB
TypeScript
162 lines
5.1 KiB
TypeScript
import { config } from "./config.js";
|
|
import {
|
|
ensureSetting,
|
|
generateSecret,
|
|
listSettings,
|
|
removeSetting,
|
|
setSetting,
|
|
SettingKey,
|
|
StoredSettings
|
|
} from "./settingsStore.js";
|
|
|
|
export interface RuntimeSettings {
|
|
paperlessBaseUrl: string | null;
|
|
paperlessExternalUrl: string | null;
|
|
appExternalUrl: string | null;
|
|
appLocale: string;
|
|
paperlessToken: string | null;
|
|
schedulerIntervalMinutes: number;
|
|
alertDaysBefore: number;
|
|
mailServer: string | null;
|
|
mailPort: number | null;
|
|
mailUsername: string | null;
|
|
mailPassword: string | null;
|
|
mailUseTls: boolean;
|
|
mailFrom: string | null;
|
|
mailTo: string | null;
|
|
ntfyServerUrl: string | null;
|
|
ntfyTopic: string | null;
|
|
ntfyToken: string | null;
|
|
ntfyPriority: string | null;
|
|
authUsername: string | null;
|
|
authPassword: string | null;
|
|
icalSecret: string | null;
|
|
}
|
|
|
|
const numericKeys = new Set<SettingKey>(["schedulerIntervalMinutes", "alertDaysBefore", "mailPort"]);
|
|
const booleanKeys = new Set<SettingKey>(["mailUseTls"]);
|
|
|
|
function coerceNumber(value: unknown, fallback: number): number {
|
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
return value;
|
|
}
|
|
if (typeof value === "string" && value.trim() !== "") {
|
|
const parsed = Number(value);
|
|
if (!Number.isNaN(parsed)) {
|
|
return parsed;
|
|
}
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
function coerceBoolean(value: unknown, fallback: boolean): boolean {
|
|
if (typeof value === "boolean") {
|
|
return value;
|
|
}
|
|
if (typeof value === "string") {
|
|
return ["1", "true", "yes", "on"].includes(value.toLowerCase());
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
function coerceString(value: unknown, fallback: string | null): string | null {
|
|
if (typeof value === "string") {
|
|
const trimmed = value.trim();
|
|
return trimmed.length === 0 ? null : trimmed;
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
function normalizeLocale(value: unknown, fallback: string): string {
|
|
if (typeof value === "string") {
|
|
const lower = value.toLowerCase();
|
|
if (lower.startsWith("de")) {
|
|
return "de";
|
|
}
|
|
if (lower.startsWith("en")) {
|
|
return "en";
|
|
}
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
export function getRuntimeSettings(): RuntimeSettings {
|
|
const stored = listSettings();
|
|
|
|
const schedulerIntervalMinutes = coerceNumber(
|
|
stored.schedulerIntervalMinutes,
|
|
config.schedulerIntervalMinutes
|
|
);
|
|
const alertDaysBefore = coerceNumber(stored.alertDaysBefore, config.alertDaysBefore);
|
|
const mailPort = stored.mailPort !== undefined ? coerceNumber(stored.mailPort, config.mailPort) : config.mailPort;
|
|
|
|
return {
|
|
paperlessBaseUrl: coerceString(stored.paperlessBaseUrl, config.paperlessBaseUrl ?? null),
|
|
paperlessExternalUrl: coerceString(stored.paperlessExternalUrl, config.paperlessExternalUrl ?? null),
|
|
appExternalUrl: coerceString(stored.appExternalUrl, config.appExternalUrl ?? null),
|
|
appLocale: normalizeLocale(stored.appLocale, config.appLocale),
|
|
paperlessToken: coerceString(stored.paperlessToken, config.paperlessToken ?? null),
|
|
schedulerIntervalMinutes,
|
|
alertDaysBefore,
|
|
mailServer: coerceString(stored.mailServer, config.mailServer ?? null),
|
|
mailPort,
|
|
mailUsername: coerceString(stored.mailUsername, config.mailUsername ?? null),
|
|
mailPassword: coerceString(stored.mailPassword, config.mailPassword ?? null),
|
|
mailUseTls:
|
|
stored.mailUseTls !== undefined
|
|
? coerceBoolean(stored.mailUseTls, config.mailUseTls)
|
|
: config.mailUseTls,
|
|
mailFrom: coerceString(stored.mailFrom, config.mailFrom ?? null),
|
|
mailTo: coerceString(stored.mailTo, config.mailTo ?? null),
|
|
ntfyServerUrl: coerceString(stored.ntfyServerUrl, config.ntfyServerUrl ?? null),
|
|
ntfyTopic: coerceString(stored.ntfyTopic, config.ntfyTopic ?? null),
|
|
ntfyToken: coerceString(stored.ntfyToken, config.ntfyToken ?? null),
|
|
ntfyPriority: coerceString(stored.ntfyPriority, config.ntfyPriority ?? null),
|
|
authUsername: coerceString(stored.authUsername, config.authUsername ?? null),
|
|
authPassword: coerceString(stored.authPassword, config.authPassword ?? null),
|
|
icalSecret: coerceString(stored.icalSecret, config.icalSecret ?? null)
|
|
};
|
|
}
|
|
|
|
export function updateRuntimeSettings(update: Partial<RuntimeSettings>): RuntimeSettings {
|
|
const keys = Object.keys(update) as SettingKey[];
|
|
for (const key of keys) {
|
|
let value = update[key as keyof RuntimeSettings];
|
|
if (value === undefined || value === null || value === "") {
|
|
removeSetting(key);
|
|
continue;
|
|
}
|
|
|
|
if (key === "appLocale") {
|
|
value = normalizeLocale(value, config.appLocale);
|
|
}
|
|
|
|
if (numericKeys.has(key)) {
|
|
const numericValue = coerceNumber(value, 0);
|
|
setSetting(key, numericValue);
|
|
} else if (booleanKeys.has(key)) {
|
|
const boolValue = coerceBoolean(value, false);
|
|
setSetting(key, boolValue);
|
|
} else {
|
|
setSetting(key, value);
|
|
}
|
|
}
|
|
|
|
return getRuntimeSettings();
|
|
}
|
|
|
|
export function ensureIcalSecret(): string {
|
|
const value = ensureSetting("icalSecret", () => generateSecret(24));
|
|
return String(value);
|
|
}
|
|
|
|
export function regenerateIcalSecret(): string {
|
|
const secret = generateSecret(24);
|
|
setSetting("icalSecret", secret);
|
|
return secret;
|
|
}
|
|
|
|
export function getStoredSettings(): StoredSettings {
|
|
return listSettings();
|
|
}
|