botpress
Version:
The world's first CMS for bots. Easily create, manage and extend chatbots.
286 lines (240 loc) • 9.19 kB
JavaScript
;
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _nanoid = require('nanoid');
var _nanoid2 = _interopRequireDefault(_nanoid);
var _helpers = require('./database/helpers');
var _helpers2 = _interopRequireDefault(_helpers);
var _util = require('./util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
const getOriginatingModule = () => {
const origPrepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = (_, stack) => stack;
const err = new Error();
const stack = err.stack;
Error.prepareStackTrace = origPrepareStackTrace;
stack.shift();
return stack[1].getFileName();
};
const notifications = ({ knex, modules, logger, events }) => {
const toDatabase = (knex, notification) => ({
id: notification.id,
message: notification.message,
level: notification.level,
module_id: notification.moduleId,
module_icon: notification.icon,
module_name: notification.name,
redirect_url: notification.url,
created_on: (0, _helpers2.default)(knex).date.now(),
read: (0, _helpers2.default)(knex).bool.false(),
archived: (0, _helpers2.default)(knex).bool.false()
});
const fromDatabase = (knex, row) => ({
id: row.id,
message: row.message,
level: row.level,
moduleId: row.module_id,
icon: row.module_icon,
name: row.module_name,
url: row.redirect_url,
date: new Date(row.created_on),
sound: false,
read: (0, _helpers2.default)(knex).bool.parse(row.read)
});
// TODO: a bunch of functions below doesn't use `await`, should they actually be `async`?
/**
* Marks a single notification as read (but doesn't archive it)
* @param {string} notificationId The id of the notification to mark as read
* @return {Promise}
*/
const markAsRead = (() => {
var _ref = _asyncToGenerator(function* (notificationId) {
return knex('notifications').where({ id: notificationId }).update({ read: (0, _helpers2.default)(knex).bool.true() }).then();
});
return function markAsRead(_x) {
return _ref.apply(this, arguments);
};
})();
/**
* Marks all notifications as read (but doesn't archive them)
* @return {Promise}
*/
const markAllAsRead = (() => {
var _ref2 = _asyncToGenerator(function* () {
return knex('notifications').update({ read: (0, _helpers2.default)(knex).bool.true() }).then();
});
return function markAllAsRead() {
return _ref2.apply(this, arguments);
};
})();
/**
* Get the top 100 (unseen) notifications
* @return {Promise<Array<Notification>>} The list of all unseen notifications
*/
const getInbox = (() => {
var _ref3 = _asyncToGenerator(function* () {
return knex('notifications').where({ archived: (0, _helpers2.default)(knex).bool.false() }).orderBy('created_on', 'DESC').limit(100).then(function (rows) {
return rows.map(function (row) {
return fromDatabase(knex, row);
});
});
});
return function getInbox() {
return _ref3.apply(this, arguments);
};
})();
/**
* Returns all archived notifications
* @return {Promise<Array<Notification>>} The list of all archived notifications
*/
const getArchived = (() => {
var _ref4 = _asyncToGenerator(function* () {
return knex('notifications').where({ archived: (0, _helpers2.default)(knex).bool.true() }).orderBy('created_on', 'DESC').limit(100).then(function (rows) {
return rows.map(function (row) {
return fromDatabase(knex, row);
});
});
});
return function getArchived() {
return _ref4.apply(this, arguments);
};
})();
/**
* Archives a single notification
* @param {string} notificationId The id of the notification to archive
* @return {Promise}
*/
const archive = (() => {
var _ref5 = _asyncToGenerator(function* (notificationId) {
return knex('notifications').where({ id: notificationId }).update({ archived: (0, _helpers2.default)(knex).bool.true() }).then();
});
return function archive(_x2) {
return _ref5.apply(this, arguments);
};
})();
/**
* Archives all notifications
* @return {Promise}
*/
const archiveAll = (() => {
var _ref6 = _asyncToGenerator(function* () {
return knex('notifications').update({ archived: (0, _helpers2.default)(knex).bool.true() }).then();
});
return function archiveAll() {
return _ref6.apply(this, arguments);
};
})();
// Internal use only
// Binds events to actions
const _bindEvents = () => {
events.on('notifications.getAll', _asyncToGenerator(function* () {
events.emit('notifications.all', (yield getInbox()));
}));
events.on('notifications.read', (() => {
var _ref8 = _asyncToGenerator(function* (id) {
yield markAsRead(id);
events.emit('notifications.all', (yield getInbox()));
});
return function (_x3) {
return _ref8.apply(this, arguments);
};
})());
events.on('notifications.allRead', _asyncToGenerator(function* () {
yield markAllAsRead();
events.emit('notifications.all', (yield getInbox()));
}));
events.on('notifications.trashAll', _asyncToGenerator(function* () {
yield archiveAll();
events.emit('notifications.all', (yield getInbox()));
}));
};
/**
* Create and append a new Notification in the Hub. Emits a `notifications.new` event.
* @param {string} options.message (required) The body message of the notification
* @param {string} options.redirectUrl (optional) The URL the users will be redirected to
* when clicking on the notification
* @param {string} options.level (optional) The level (info, success, error, warning). Defaults to `info`.
* @param {bool} options.enableSound (optional) Whether the notification will trigger a buzzing sound
* if a user is currently logged on the dashboard. (defaults to `false`)
* @return {Promise}
*/
const create = (() => {
var _ref11 = _asyncToGenerator(function* ({ message, redirectUrl, level, enableSound }) {
if (!message || typeof message !== 'string') {
throw new Error("'message' is mandatory and should be a string");
}
if (!level || typeof level !== 'string' || !_lodash2.default.includes(['info', 'error', 'success'], level.toLowerCase())) {
level = 'info';
} else {
level = level.toLowerCase();
}
const callingFile = getOriginatingModule();
const callingModuleRoot = callingFile && (0, _util.resolveModuleRootPath)(callingFile);
const module = _lodash2.default.find(modules, function (mod) {
return mod.root === callingModuleRoot;
});
let options = {
moduleId: 'botpress',
icon: 'view_module',
name: 'botpress',
url: _lodash2.default.isString(redirectUrl) ? redirectUrl : '/'
};
if (module) {
// because the bot itself can send notifications
options = {
moduleId: module.name,
icon: module.settings.menuIcon,
name: module.settings.menuText,
url: redirectUrl
};
if (!redirectUrl || typeof url !== 'string') {
options.url = `/modules/${module.name}`;
}
}
const notification = {
id: (0, _nanoid2.default)(),
message: message,
level: level,
moduleId: options.moduleId,
icon: options.icon,
name: options.name,
url: options.url,
date: new Date(),
sound: enableSound || false,
read: false
};
yield knex('notifications').insert(toDatabase(knex, notification)).then();
if (logger) {
const logMessage = `[notification::${notification.moduleId}] ${notification.message}`;
const loggerLevel = logger[level] || logger.info;
loggerLevel(logMessage);
}
if (events) {
events.emit('notifications.new', notification);
}
});
return function create(_x4) {
return _ref11.apply(this, arguments);
};
})();
return {
// ----> Start of legacy API (DEPRECATED as of Botpress 1.1)
load: getInbox,
send: ({ message, url, level, sound }) => {
return create({ message, redirectUrl: url, level, enableSound: sound });
},
// End of legacy API <---
markAsRead,
markAllAsRead,
archiveAll,
archive,
getInbox,
getArchived,
create,
// internal API
_bindEvents
};
};
module.exports = notifications;
//# sourceMappingURL=notifications.js.map