Files
bigcapital/packages/server/src/services/Settings/SmsNotificationsSettings.ts

194 lines
5.5 KiB
TypeScript

import { Service, Inject } from 'typedi';
import { isUndefined, omit, keyBy } from 'lodash';
import {
ISmsNotificationDefined,
ISmsNotificationMeta,
IEditSmsNotificationDTO,
ISmsNotificationAllowedVariable,
} from '@/interfaces';
import TenancyService from '@/services/Tenancy/TenancyService';
import SMSNotificationsConfig from 'config/smsNotifications';
import { ServiceError } from '@/exceptions';
const ERRORS = {
SMS_NOTIFICATION_KEY_NOT_FOUND: 'SMS_NOTIFICATION_KEY_NOT_FOUND',
UNSUPPORTED_SMS_MESSAGE_VARIABLES: 'UNSUPPORTED_SMS_MESSAGE_VARIABLES',
};
@Service()
export default class SmsNotificationsSettingsService {
@Inject()
private tenancy: TenancyService;
/**
* Retrieve sms notification meta from the given notification key.
* @param {string} notificationKey - Notification key.
* @returns {ISmsNotificationMeta}
*/
public getSmsNotificationMeta = (
tenantId: number,
notificationKey: string
): ISmsNotificationMeta => {
const notificationsByKey = keyBy(SMSNotificationsConfig, 'key');
const notification = notificationsByKey[notificationKey];
// Validates sms notification exists.
this.validateSmsNotificationExists(notification);
return this.transformSmsNotifConfigToMeta(tenantId, notification);
};
/**
* Transformes the sms notification config to notificatin meta.
* @param {Settings} settings
* @param {ISmsNotificationDefined} smsNotification
* @returns {ISmsNotificationMeta}
*/
private transformSmsNotifConfigToMeta = (
tenantId: number,
smsNotification: ISmsNotificationDefined
): ISmsNotificationMeta => {
const settings = this.tenancy.settings(tenantId);
const i18n = this.tenancy.i18n(tenantId);
const group = 'sms-notification';
const defaultSmsMessage = i18n.__(smsNotification.defaultSmsMessage);
return {
...omit(smsNotification, [
'defaultSmsMessage',
'defaultIsNotificationEnabled',
]),
notificationLabel: i18n.__(smsNotification.notificationLabel),
notificationDescription: i18n.__(smsNotification.notificationDescription),
moduleFormatted: i18n.__(smsNotification.moduleFormatted),
allowedVariables: smsNotification.allowedVariables.map(
(notification) => ({
...notification,
description: i18n.__(notification.description),
})
),
defaultSmsMessage,
smsMessage: settings.get(
{
key: `sms-message.${smsNotification.key}`,
group,
},
defaultSmsMessage
),
isNotificationEnabled: settings.get(
{
key: `sms-notification-enable.${smsNotification.key}`,
group,
},
smsNotification.defaultIsNotificationEnabled
),
};
};
/**
* Retrieve the sms notifications list.
* @param {number} tenantId
*/
public smsNotificationsList = (
tenantId: number
): Promise<ISmsNotificationMeta[]> => {
return SMSNotificationsConfig.map((notification) => {
return this.transformSmsNotifConfigToMeta(tenantId, notification);
});
};
/**
* Edits/Mutates the sms notification message text.
* @param {number} tenantId - Tenant id.
* @param {IEditSmsNotificationDTO} editSmsNotificationDTO - Edit SMS notification DTO.
*/
public editSmsNotificationMessage = (
tenantId: number,
editDTO: IEditSmsNotificationDTO
): ISmsNotificationMeta => {
const settings = this.tenancy.settings(tenantId);
const notification = this.getSmsNotificationMeta(
tenantId,
editDTO.notificationKey
);
const group = 'sms-notification';
if (editDTO.messageText) {
this.validateSmsMessageVariables(
editDTO.messageText,
notification.allowedVariables
);
settings.set({
key: `sms-message.${editDTO.notificationKey}`,
value: editDTO.messageText,
group,
});
}
if (!isUndefined(editDTO.isNotificationEnabled)) {
settings.set({
key: `sms-notification-enable.${editDTO.notificationKey}`,
value: editDTO.isNotificationEnabled,
group,
});
}
return notification;
};
/**
* Vaidates the sms notification key existance.
* @param {string} notificationKey
*/
private validateSmsNotificationExists = (
notificationDefined: ISmsNotificationDefined | null
): void => {
if (!notificationDefined) {
throw new ServiceError(ERRORS.SMS_NOTIFICATION_KEY_NOT_FOUND);
}
};
/**
* Retrieve unspported message arguments.
* @param {string} smsMessage - SMS message.
* @param {string[]} args -
* @returns {string[]}
*/
private getUnsupportedMessageArgs = (
smsMessage: string,
args: string[]
): string[] => {
const matchedVariables = smsMessage.match(/\{(.*?)\}/g).map((matched) => {
return matched.replace('{', '').replace('}', '');
});
const invalidVariables = matchedVariables.filter(
(variable) => args.indexOf(variable) === -1
);
return invalidVariables;
};
/**
* Validates the sms message variables.
* @param {string} smsMessage
* @param {string[]} args
*/
private validateSmsMessageVariables(
smsMessage: string,
allowedVariables: ISmsNotificationAllowedVariable[]
) {
const allowedVariablesKeys = allowedVariables.map(
(allowed) => allowed.variable
);
const unsupportedArgs = this.getUnsupportedMessageArgs(
smsMessage,
allowedVariablesKeys
);
if (unsupportedArgs.length > 0) {
throw new ServiceError(ERRORS.UNSUPPORTED_SMS_MESSAGE_VARIABLES, null, {
unsupportedArgs,
});
}
}
}