Files
Paperless-Contracts/src/runtimeSettings.ts
2025-10-11 19:34:54 +02:00

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();
}