Функция валидации списка E-mail адресов в общие объекты моделей валидации, перенос функции отправки E-mail в utils.js (соответственно перенос схем валидации), включение валидации списка E-mail адресов в схеме Service

This commit is contained in:
Mikhail Chechnev 2018-12-10 15:59:32 +03:00
parent 1233efb6f5
commit d6beebabc5
6 changed files with 205 additions and 88 deletions

View File

@ -10,10 +10,9 @@
const _ = require("lodash"); //Работа с массивами и коллекциями
const rqp = require("request-promise"); //Работа с HTTP/HTTPS запросами
const EventEmitter = require("events"); //Обработчик пользовательских событий
const nodemailer = require("nodemailer"); //Отправка E-Mail сообщений
const { ServerError } = require("./server_errors"); //Типовая ошибка
const { SERR_SERVICE_UNAVAILABLE, SERR_MAIL_FAILED, SERR_OBJECT_BAD_INTERFACE } = require("./constants"); //Общесистемные константы
const { makeErrorText, validateObject } = require("./utils"); //Вспомогательные функции
const { SERR_SERVICE_UNAVAILABLE, SERR_OBJECT_BAD_INTERFACE } = require("./constants"); //Общесистемные константы
const { makeErrorText, validateObject, sendMail } = require("./utils"); //Вспомогательные функции
const prmsServiceAvailableControllerSchema = require("../models/prms_service_available_controller"); //Схемы валидации параметров функций класса
const objServiceSchema = require("../models/obj_service"); //Схемы валидации сервисов
@ -79,56 +78,6 @@ class ServiceAvailableController extends EventEmitter {
//Оповестим подписчиков об останове
this.emit(SEVT_SERVICE_AVAILABLE_CONTROLLER_STOPPED);
}
//Отправка E-Mail уведомления о недоступности сервиса
sendUnAvailableMail(prms) {
return new Promise((resolve, reject) => {
//Проверяем структуру переданного объекта для старта
let sCheckResult = validateObject(
prms,
prmsServiceAvailableControllerSchema.sendUnAvailableMail,
"Параметры функции отправки E-Mail уведомления о недоступности удалённого сервиса"
);
//Если структура объекта в норме
if (!sCheckResult) {
//Параметры подключения к SMTP-серверу
let transporter = nodemailer.createTransport({
host: this.mail.sHost,
port: this.mail.nPort,
secure: this.mail.nPort == 465,
auth: {
user: this.mail.sUser,
pass: this.mail.sPass
}
});
//Параметры отправляемого сообщения
let mailOptions = {
from: this.mail.sFrom,
to: prms.sTo,
subject: prms.sSubject,
text: prms.sMessage
};
//Отправляем сообщение
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
reject(new ServerError(SERR_MAIL_FAILED, `${error.code}: ${error.response}`));
} else {
if (info.rejected && Array.isArray(info.rejected) && info.rejected.length > 0) {
reject(
new ServerError(
SERR_MAIL_FAILED,
`Сообщение не доствлено адресатам: ${info.rejected.join(", ")}`
)
);
} else {
resolve(info);
}
}
});
} else {
reject(new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult));
}
});
}
//Перезапуск опроса списка сервисов
async restartDetectingLoop() {
//Включаем опрос сервисов только если установлен флаг работы
@ -197,7 +146,8 @@ class ServiceAvailableController extends EventEmitter {
}`;
await this.logger.error(sMessage, { nServiceId: this.services[i].nId });
try {
await this.sendUnAvailableMail({
await sendMail({
mail: this.mail,
sTo: this.services[i].sUnavlblNtfMail,
sSubject,
sMessage

View File

@ -9,13 +9,17 @@
const _ = require("lodash"); //Работа с массивами и объектами
const Schema = require("validate"); //Схемы валидации
const nodemailer = require("nodemailer"); //Отправка E-Mail сообщений
const {
SERR_UNEXPECTED,
SMODULES_PATH_MODULES,
SERR_OBJECT_BAD_INTERFACE,
SERR_MODULES_NO_MODULE_SPECIFIED,
SERR_MODULES_BAD_INTERFACE
SERR_MODULES_BAD_INTERFACE,
SERR_MAIL_FAILED
} = require("./constants"); //Глобавльные константы системы
const { ServerError } = require("./server_errors"); //Ошибка сервера
const prmsUtilsSchema = require("../models/prms_utils"); //Схемы валидации параметров функций
//------------
// Тело модуля
@ -25,12 +29,17 @@ const { ServerError } = require("./server_errors"); //Ошибка сервер
const validateObject = (obj, schema, sObjName) => {
//Объявим результат
let sRes = "";
//Если пришла верная схема
if (schema instanceof Schema) {
//И есть что проверять
if (obj) {
//Сделаем это
const objTmp = _.cloneDeep(obj);
const errors = schema.validate(objTmp, { strip: false });
//Если есть ошибки
if (errors && Array.isArray(errors)) {
if (errors.length > 0) {
//Сформируем из них сообщение об ошибке валидации
let a = errors.map(e => {
return e.message;
});
@ -41,12 +50,15 @@ const validateObject = (obj, schema, sObjName) => {
_.uniq(a).join("; ");
}
} else {
//Валидатор вернул не то, что мы ожидали
sRes = "Неожиданный ответ валидатора";
}
} else {
//Нам не передали объект на проверку
sRes = "Объект" + (sObjName ? " '" + sObjName + "' " : " ") + "не указан";
}
} else {
//Пришла не схема валидации а непонятно что
sRes = "Ошибочный формат схемы валидации";
}
//Вернем результат
@ -55,50 +67,70 @@ const validateObject = (obj, schema, sObjName) => {
//Формирование полного пути к подключаемому модулю
const makeModuleFullPath = sModuleName => {
//Если имя модуля передано
if (sModuleName) {
//Объединим его с шаблоном пути до библиотеки модулей
return SMODULES_PATH_MODULES + "/" + sModuleName;
} else {
//Нет имени модуля - нет полного пути
return "";
}
};
//Формирование текста ошибки
const makeErrorText = e => {
//Сообщение об ошибке по умолчанию
let sErr = `${SERR_UNEXPECTED}: ${e.message}`;
//Если это наше внутреннее сообщение, с кодом, то сделаем ошибку более информативной
if (e instanceof ServerError) sErr = `${e.sCode}: ${e.sMessage}`;
//Вернем ответ
return sErr;
};
//Считывание наименования модуля-обработчика сервера приложений (ожидаемый формат - <МОДУЛЬ>/<ФУНКЦИЯ>)
const getAppSrvModuleName = sAppSrv => {
//Если есть что разбирать
if (sAppSrv) {
//И если это строка
if (sAppSrv instanceof String || typeof sAppSrv === "string") {
//Проверим наличие разделителя между именем модуля и функции
if (sAppSrv.indexOf("/") === -1) {
//Нет разделителя - нечего вернуть
return null;
} else {
//Вернём всё, что левее разделителя
return sAppSrv.substring(0, sAppSrv.indexOf("/"));
}
} else {
//Пришла не строка
return null;
}
} else {
//Ничего не пришло
return null;
}
};
//Считывание наименования функции модуля-обработчика сервера приложений (ожидаемый формат - <МОДУЛЬ>/<ФУНКЦИЯ>)
const getAppSrvFunctionName = sAppSrv => {
//Если есть что разбирать
if (sAppSrv) {
//И если это строка
if (sAppSrv instanceof String || typeof sAppSrv === "string") {
//Проверим наличие разделителя между именем модуля и функции
if (sAppSrv.indexOf("/") === -1) {
//Нет разделителя - нечего вернуть
return null;
} else {
//Вернём всё, что правее разделителя
return sAppSrv.substring(sAppSrv.indexOf("/") + 1, sAppSrv.length);
}
} else {
//Пришла не строка
return null;
}
} else {
//Ничего не пришло
return null;
}
};
@ -139,6 +171,57 @@ const getAppSrvFunction = sAppSrv => {
}
};
//Отправка E-Mail уведомления
const sendMail = prms => {
return new Promise((resolve, reject) => {
//Проверяем структуру переданного объекта для старта
let sCheckResult = validateObject(
prms,
prmsUtilsSchema.sendMail,
"Параметры функции отправки E-Mail уведомления"
);
//Если структура объекта в норме
if (!sCheckResult) {
//Параметры подключения к SMTP-серверу
let transporter = nodemailer.createTransport({
host: prms.mail.sHost,
port: prms.mail.nPort,
secure: prms.mail.nPort == 465,
auth: {
user: prms.mail.sUser,
pass: prms.mail.sPass
}
});
//Параметры отправляемого сообщения
let mailOptions = {
from: prms.mail.sFrom,
to: prms.sTo,
subject: prms.sSubject,
text: prms.sMessage
};
//Отправляем сообщение
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
reject(new ServerError(SERR_MAIL_FAILED, `${error.code}: ${error.response}`));
} else {
if (info.rejected && Array.isArray(info.rejected) && info.rejected.length > 0) {
reject(
new ServerError(
SERR_MAIL_FAILED,
`Сообщение не доствлено адресатам: ${info.rejected.join(", ")}`
)
);
} else {
resolve(info);
}
}
});
} else {
reject(new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult));
}
});
};
//-----------------
// Интерфейс модуля
//-----------------
@ -149,3 +232,4 @@ exports.makeErrorText = makeErrorText;
exports.getAppSrvModuleName = getAppSrvModuleName;
exports.getAppSrvFunctionName = getAppSrvFunctionName;
exports.getAppSrvFunction = getAppSrvFunction;
exports.sendMail = sendMail;

34
models/common.js Normal file
View File

@ -0,0 +1,34 @@
/*
Сервис интеграции ПП Парус 8 с WEB API
Модели данных: общие функции валидации, константы, модели
*/
//------------
// Тело модуля
//------------
//Валидация списка адресов E-Mail
const validateMailList = sMailList => {
//Если есть что валидировать
if (sMailList) {
//Объявим разделитель списка адресов
let sSpr = ",";
//Регулярное выражение для контроля адреса E-Mail
let sMailRegExp = /^(([A-Za-z0-9_-]+\.)*[A-Za-z0-9_-]+@[a-z0-9_-]+(\.[a-z0-9_-]+)*\.[a-z]+)/;
//Развалим строку с разделителями на массив адресов
let addrs = sMailList.split(sSpr);
//Обходим массив адресов
for (i = 0; i < addrs.length; i++) {
//Проверяем адрес на соответствие регулярному выражению
if (!sMailRegExp.test(addrs[i])) return false;
}
}
//Если мы здесь - валидация прошла успешно
return true;
};
//-----------------
// Интерфейс модуля
//-----------------
exports.validateMailList = validateMailList;

View File

@ -9,6 +9,7 @@
const Schema = require("validate"); //Схемы валидации
const { defServiceFunctions } = require("./obj_service_functions"); //Схема валидации списка функций сервиса
const { validateMailList } = require("./common"); //Общие объекты валидации моделей данных
//----------
// Константы
@ -26,6 +27,15 @@ const NUNAVLBL_NTF_SIGN_YES = 1; //Оповещать о простое
const SUNAVLBL_NTF_SIGN_NO = "UNAVLBL_NTF_NO"; //Не оповещать о простое (строковый код)
const SUNAVLBL_NTF_SIGN_YES = "UNAVLBL_NTF_YES"; //Оповещать о простое (строковый код)
//-------------
// Тело модуля
//-------------
//Валидация списка адресов E-Mail для оповещения о простое внешнего сервиса
const validateUnavlblNtfMail = val => {
return validateMailList(val);
};
//------------------
// Интерфейс модуля
//------------------
@ -151,10 +161,13 @@ exports.Service = new Schema({
sUnavlblNtfMail: {
type: String,
required: false,
use: { validateUnavlblNtfMail },
message: {
type:
"Список адресов E-Mail для оповещения о простое внешнего сервиса (sUnavlblNtfMail) имеет некорректный тип данных (ожидалось - String)",
required: "Не указан список адресов E-Mail для оповещения о простое внешнего сервиса (sUnavlblNtfMail)"
required: "Не указан список адресов E-Mail для оповещения о простое внешнего сервиса (sUnavlblNtfMail)",
validateUnavlblNtfMail:
"Неверный формат списка адресов E-Mail для оповещения о простое внешнего сервиса (sUnavlblNtfMail), для указания нескольких адресов следует использовать запятую в качестве разделителя (без пробелов)"
}
},
//Список функций сервиса

View File

@ -38,38 +38,6 @@ exports.ServiceAvailableController = new Schema({
}
});
//Схема валидации параметров функции отправки E-Mail уведомления о недоступности сервиса
exports.sendUnAvailableMail = new Schema({
//Список адресов E-Mail для отправки уведомления
sTo: {
type: String,
required: true,
message: {
type: path =>
`Список адресов E-Mail для отправки уведомления (${path}) имеет некорректный тип данных (ожидалось - String)`,
required: path => `Не указан cписок адресов E-Mail для отправки уведомления (${path})`
}
},
//Заголовок сообщения
sSubject: {
type: String,
required: true,
message: {
type: path => `Заголовок сообщения (${path}) имеет некорректный тип данных (ожидалось - String)`,
required: path => `Не указан заголовок сообщения (${path})`
}
},
//Текст уведомления
sMessage: {
type: String,
required: true,
message: {
type: path => `Текст уведомления (${path}) имеет некорректный тип данных (ожидалось - String)`,
required: path => `Не указан текст уведомления (${path})`
}
}
});
//Схема валидации параметров функции запуска контроллера
exports.startController = new Schema({
//Список обслуживаемых сервисов

68
models/prms_utils.js Normal file
View File

@ -0,0 +1,68 @@
/*
Сервис интеграции ПП Парус 8 с WEB API
Модели данных: описатели параметров вспомогательных функций (модуль utils.js)
*/
//----------------------
// Подключение библиотек
//----------------------
const Schema = require("validate"); //Схемы валидации
const { mail } = require("./obj_config"); //Схемы валидации конфигурации сервера приложений
const { validateMailList } = require("./common"); //Общие объекты валидации моделей данных
//-------------
// Тело модуля
//-------------
//Валидация списка адресов E-Mail для отправки уведомления
const validateTo = val => {
return validateMailList(val);
};
//------------------
// Интерфейс модуля
//------------------
//Схема валидации параметров функции отправки E-Mail
exports.sendMail = new Schema({
//Параметры отправки E-Mail уведомлений
mail: {
schema: mail,
required: true,
message: {
required: path => `Не указаны параметры отправки E-Mail уведомлений (${path})`
}
},
//Список адресов E-Mail для отправки уведомления
sTo: {
type: String,
required: true,
use: { validateTo },
message: {
type: path =>
`Список адресов E-Mail для отправки уведомления (${path}) имеет некорректный тип данных (ожидалось - String)`,
required: path => `Не указан cписок адресов E-Mail для отправки уведомления (${path})`,
validateTo: path =>
`Неверный формат списка адресов E-Mail для отправки уведомления (${path}), для указания нескольких адресов следует использовать запятую в качестве разделителя (без пробелов)`
}
},
//Заголовок сообщения
sSubject: {
type: String,
required: true,
message: {
type: path => `Заголовок сообщения (${path}) имеет некорректный тип данных (ожидалось - String)`,
required: path => `Не указан заголовок сообщения (${path})`
}
},
//Текст уведомления
sMessage: {
type: String,
required: true,
message: {
type: path => `Текст уведомления (${path}) имеет некорректный тип данных (ожидалось - String)`,
required: path => `Не указан текст уведомления (${path})`
}
}
});