131 lines
3.7 KiB
JavaScript
131 lines
3.7 KiB
JavaScript
'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
|
||
};
|