'use strict'; const config = require('../config/config'); const { Setting, SETTINGS_KEY } = require('../components/settings/settingModel'); const { NOTIFICATION_ACTION_DEFS, mergeNotificationSettings, toPublicNotificationSettings, normalizeStoredActionEntry, findActionDef } = require('../components/settings/notificationActions'); const { isEnvChannelEnabled, isDbChannelEnabled, CHANNELS } = require('./messagingChannels'); const { getDbMessagingFlags, invalidateMessagingCache } = require('../components/settings/messagingFlags'); let settingsCache = null; let settingsCacheAt = 0; const CACHE_TTL_MS = 10000; const readStoredMap = (doc) => { const stored = doc?.notificationSettings || {}; if (stored instanceof Map) { return Object.fromEntries(stored.entries()); } return { ...stored }; }; const getMergedSettingsMap = (doc) => mergeNotificationSettings(readStoredMap(doc)); const loadNotificationSettingsDoc = async () => { const now = Date.now(); if (settingsCache && (now - settingsCacheAt) < CACHE_TTL_MS) { return settingsCache; } const doc = await Setting.findOne({ key: SETTINGS_KEY }) .select('notificationSettings smsEnabled emailEnabled botEnabled') .lean(); settingsCache = { map: getMergedSettingsMap(doc), dbMessaging: { smsEnabled: doc?.smsEnabled, emailEnabled: doc?.emailEnabled, botEnabled: doc?.botEnabled } }; settingsCacheAt = now; return settingsCache; }; const invalidateNotificationSettingsCache = () => { settingsCache = null; settingsCacheAt = 0; invalidateMessagingCache(); }; const isGlobalChannelEnabled = async (channel) => { if (!CHANNELS.includes(channel)) return false; if (!isEnvChannelEnabled(channel, config)) return false; const db = await getDbMessagingFlags(); return isDbChannelEnabled(channel, db); }; const isActionChannelEnabled = async (actionKey, channel) => { if (!CHANNELS.includes(channel)) return false; if (!(await isGlobalChannelEnabled(channel))) return false; const cached = await loadNotificationSettingsDoc(); const def = findActionDef(actionKey); if (!def) return true; const entry = normalizeStoredActionEntry(cached.map[actionKey], def); return entry[channel] === true; }; const getActionChannelFlags = async (actionKey) => { const result = { sms: false, email: false, bot: false }; await Promise.all( CHANNELS.map(async (channel) => { result[channel] = await isActionChannelEnabled(actionKey, channel); }) ); return result; }; const getPublicNotificationSettings = async (doc = null) => { const resolved = doc || await Setting.findOne({ key: SETTINGS_KEY }).lean(); return toPublicNotificationSettings(getMergedSettingsMap(resolved)); }; module.exports = { getMergedSettingsMap, isActionChannelEnabled, getActionChannelFlags, getPublicNotificationSettings, invalidateNotificationSettingsCache, readStoredMap };