Files

131 lines
3.7 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
const config = require('../../config/config');
const logger = require('../../utils/logger');
const { Setting, SETTINGS_KEY } = require('./settingModel');
const {
isDbChannelEnabled,
isEnvChannelEnabled,
toPublicMessaging
} = require('../../utils/messagingChannels');
let cache = null;
let cacheAt = 0;
const CACHE_TTL_MS = 10000;
const normalizePhoneForBypass = (raw = '') => {
if (!raw) return '';
let digits = String(raw)
.replace(/[۰-۹]/g, (d) => '0123456789'['۰۱۲۳۴۵۶۷۸۹'.indexOf(d)])
.replace(/[٠-٩]/g, (d) => '0123456789'['٠١٢٣٤٥٦٧٨٩'.indexOf(d)])
.replace(/\D/g, '');
if (digits.startsWith('98') && digits.length >= 12) digits = `0${digits.slice(2)}`;
if (digits.length === 10 && digits.startsWith('9')) digits = `0${digits}`;
if (digits.length > 11 && digits.startsWith('09')) digits = digits.slice(0, 11);
return digits;
};
const readDbFlags = (doc) => ({
smsEnabled: doc?.smsEnabled,
emailEnabled: doc?.emailEnabled,
botEnabled: doc?.botEnabled,
smsBypassNumbers: Array.isArray(doc?.smsBypassNumbers)
? doc.smsBypassNumbers.map((item) => (item.toObject ? item.toObject() : item))
: []
});
const getDbMessagingFlags = async () => {
const now = Date.now();
if (cache && (now - cacheAt) < CACHE_TTL_MS) return cache;
const doc = await Setting.findOne({ key: SETTINGS_KEY })
.select('smsEnabled emailEnabled botEnabled smsBypassNumbers')
.lean();
cache = readDbFlags(doc);
cacheAt = now;
return cache;
};
const invalidateMessagingCache = () => {
cache = null;
cacheAt = 0;
};
const isSmsBypassNumber = async (phoneNumber) => {
if (!phoneNumber) return false;
const target = normalizePhoneForBypass(phoneNumber);
if (!target) return false;
try {
const db = await getDbMessagingFlags();
const bypassList = Array.isArray(db.smsBypassNumbers) ? db.smsBypassNumbers : [];
return bypassList.some((item) => item.isActive !== false && normalizePhoneForBypass(item.phoneNumber) === target);
} catch (err) {
logger.warn(`[Messaging] Failed to check bypass numbers: ${err.message}`);
return false;
}
};
const getMessagingChannelState = async (channel, recipientPhone = null) => {
const envEnabled = isEnvChannelEnabled(channel, config);
const bypass = channel === 'sms' && recipientPhone ? await isSmsBypassNumber(recipientPhone) : false;
if (bypass) {
logger.info(`[Messaging] Recipient ${recipientPhone} is in SMS bypass list. Channel bypass activated.`);
return {
enabled: true,
envEnabled,
dbEnabled: true,
bypass: true,
blockReason: null
};
}
if (!envEnabled) {
return {
enabled: false,
envEnabled: false,
dbEnabled: null,
bypass: false,
blockReason: 'env_disabled'
};
}
try {
const db = await getDbMessagingFlags();
const dbEnabled = isDbChannelEnabled(channel, db);
return {
enabled: dbEnabled,
envEnabled: true,
dbEnabled,
bypass: false,
blockReason: dbEnabled ? null : 'dashboard_disabled'
};
} catch (err) {
logger.warn(`[Messaging] Failed to read settings for ${channel}, using env only: ${err.message}`);
return {
enabled: true,
envEnabled: true,
dbEnabled: null,
bypass: false,
blockReason: null
};
}
};
const isMessagingChannelEnabled = async (channel, recipientPhone = null) => {
const state = await getMessagingChannelState(channel, recipientPhone);
return state.enabled;
};
const getPublicMessaging = (doc) => toPublicMessaging(readDbFlags(doc), config);
module.exports = {
getMessagingChannelState,
isMessagingChannelEnabled,
isSmsBypassNumber,
normalizePhoneForBypass,
invalidateMessagingCache,
getPublicMessaging,
getDbMessagingFlags
};