Files
Pickup-Config/services/adminConfig.js
2026-01-29 17:00:24 +01:00

195 lines
6.3 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const CONFIG_DIR = path.join(__dirname, '..', 'config');
const SETTINGS_FILE = path.join(CONFIG_DIR, 'admin-settings.json');
const DEFAULT_SETTINGS = {
scheduleCron: '*/10 7-22 * * *',
randomDelayMinSeconds: 10,
randomDelayMaxSeconds: 120,
initialDelayMinSeconds: 5,
initialDelayMaxSeconds: 30,
storeWatchCron: '*/30 * * * *',
storeWatchInitialDelayMinSeconds: 10,
storeWatchInitialDelayMaxSeconds: 60,
storeWatchRequestDelayMs: 1000,
storeWatchStatusCacheMaxAgeMinutes: 120,
storePickupCheckDelayMs: 400,
ignoredSlots: [
{
storeId: '51450',
slotName: 'TVS',
info: ''
}
],
notifications: {
ntfy: {
enabled: false,
serverUrl: 'https://ntfy.sh',
topicPrefix: '',
username: '',
password: ''
},
telegram: {
enabled: false,
botToken: '',
chatId: ''
}
}
};
function ensureDir() {
if (!fs.existsSync(CONFIG_DIR)) {
fs.mkdirSync(CONFIG_DIR, { recursive: true });
}
}
function sanitizeNumber(value, fallback) {
const num = Number(value);
if (Number.isFinite(num) && num >= 0) {
return num;
}
return fallback;
}
function sanitizeIgnoredSlots(slots = []) {
if (!Array.isArray(slots)) {
return DEFAULT_SETTINGS.ignoredSlots;
}
return slots
.map((slot) => {
const slotName = slot?.slotName ?? slot?.description;
return {
storeId: slot?.storeId ? String(slot.storeId) : '',
slotName: slotName ? String(slotName) : '',
info: slot?.info ? String(slot.info) : ''
};
})
.filter((slot) => slot.storeId && slot.slotName);
}
function sanitizeString(value) {
if (typeof value === 'string') {
return value.trim();
}
if (value === null || value === undefined) {
return '';
}
return String(value).trim();
}
function sanitizeNotifications(input = {}) {
const defaults = DEFAULT_SETTINGS.notifications;
return {
ntfy: {
enabled: !!(input?.ntfy?.enabled),
serverUrl: sanitizeString(input?.ntfy?.serverUrl || defaults.ntfy.serverUrl),
topicPrefix: sanitizeString(input?.ntfy?.topicPrefix || defaults.ntfy.topicPrefix),
username: sanitizeString(input?.ntfy?.username || defaults.ntfy.username),
password: sanitizeString(input?.ntfy?.password || defaults.ntfy.password)
},
telegram: {
enabled: !!(input?.telegram?.enabled),
botToken: sanitizeString(input?.telegram?.botToken || defaults.telegram.botToken),
chatId: sanitizeString(input?.telegram?.chatId || defaults.telegram.chatId)
}
};
}
function readSettings() {
ensureDir();
if (!fs.existsSync(SETTINGS_FILE)) {
fs.writeFileSync(SETTINGS_FILE, JSON.stringify(DEFAULT_SETTINGS, null, 2));
return { ...DEFAULT_SETTINGS };
}
try {
const raw = fs.readFileSync(SETTINGS_FILE, 'utf8');
const parsed = JSON.parse(raw);
return {
scheduleCron: parsed.scheduleCron || DEFAULT_SETTINGS.scheduleCron,
randomDelayMinSeconds: sanitizeNumber(parsed.randomDelayMinSeconds, DEFAULT_SETTINGS.randomDelayMinSeconds),
randomDelayMaxSeconds: sanitizeNumber(parsed.randomDelayMaxSeconds, DEFAULT_SETTINGS.randomDelayMaxSeconds),
initialDelayMinSeconds: sanitizeNumber(parsed.initialDelayMinSeconds, DEFAULT_SETTINGS.initialDelayMinSeconds),
initialDelayMaxSeconds: sanitizeNumber(parsed.initialDelayMaxSeconds, DEFAULT_SETTINGS.initialDelayMaxSeconds),
storeWatchCron: parsed.storeWatchCron || DEFAULT_SETTINGS.storeWatchCron,
storeWatchInitialDelayMinSeconds: sanitizeNumber(
parsed.storeWatchInitialDelayMinSeconds,
DEFAULT_SETTINGS.storeWatchInitialDelayMinSeconds
),
storeWatchInitialDelayMaxSeconds: sanitizeNumber(
parsed.storeWatchInitialDelayMaxSeconds,
DEFAULT_SETTINGS.storeWatchInitialDelayMaxSeconds
),
storeWatchRequestDelayMs: sanitizeNumber(
parsed.storeWatchRequestDelayMs,
DEFAULT_SETTINGS.storeWatchRequestDelayMs
),
storeWatchStatusCacheMaxAgeMinutes: sanitizeNumber(
parsed.storeWatchStatusCacheMaxAgeMinutes,
DEFAULT_SETTINGS.storeWatchStatusCacheMaxAgeMinutes
),
storePickupCheckDelayMs: sanitizeNumber(
parsed.storePickupCheckDelayMs,
DEFAULT_SETTINGS.storePickupCheckDelayMs
),
ignoredSlots: sanitizeIgnoredSlots(parsed.ignoredSlots),
notifications: sanitizeNotifications(parsed.notifications)
};
} catch (error) {
console.error('Konnte Admin-Einstellungen nicht lesen:', error.message);
return { ...DEFAULT_SETTINGS };
}
}
function writeSettings(patch = {}) {
const current = readSettings();
const next = {
scheduleCron: patch.scheduleCron || current.scheduleCron,
randomDelayMinSeconds: sanitizeNumber(patch.randomDelayMinSeconds, current.randomDelayMinSeconds),
randomDelayMaxSeconds: sanitizeNumber(patch.randomDelayMaxSeconds, current.randomDelayMaxSeconds),
initialDelayMinSeconds: sanitizeNumber(patch.initialDelayMinSeconds, current.initialDelayMinSeconds),
initialDelayMaxSeconds: sanitizeNumber(patch.initialDelayMaxSeconds, current.initialDelayMaxSeconds),
storeWatchCron: patch.storeWatchCron || current.storeWatchCron,
storeWatchInitialDelayMinSeconds: sanitizeNumber(
patch.storeWatchInitialDelayMinSeconds,
current.storeWatchInitialDelayMinSeconds
),
storeWatchInitialDelayMaxSeconds: sanitizeNumber(
patch.storeWatchInitialDelayMaxSeconds,
current.storeWatchInitialDelayMaxSeconds
),
storeWatchRequestDelayMs: sanitizeNumber(
patch.storeWatchRequestDelayMs,
current.storeWatchRequestDelayMs
),
storeWatchStatusCacheMaxAgeMinutes: sanitizeNumber(
patch.storeWatchStatusCacheMaxAgeMinutes,
current.storeWatchStatusCacheMaxAgeMinutes
),
storePickupCheckDelayMs: sanitizeNumber(
patch.storePickupCheckDelayMs,
current.storePickupCheckDelayMs
),
ignoredSlots:
patch.ignoredSlots !== undefined
? sanitizeIgnoredSlots(patch.ignoredSlots)
: current.ignoredSlots,
notifications:
patch.notifications !== undefined
? sanitizeNotifications(patch.notifications)
: current.notifications
};
ensureDir();
fs.writeFileSync(SETTINGS_FILE, JSON.stringify(next, null, 2));
return next;
}
module.exports = {
DEFAULT_SETTINGS,
readSettings,
writeSettings
};