wingbot
Version:
Enterprise Messaging Bot Conversation Engine
223 lines (188 loc) • 5.91 kB
JavaScript
/**
* @author David Menger
*/
;
const apiAuthorizer = require('./apiAuthorizer');
const { apiTextOutputFilter, mapObject, defaultMapperFactory } = require('../utils/deepMapTools');
/** @typedef {import('../utils/deepMapTools').Mapper} Mapper */
/** @typedef {import('../notifications/Notifications')} Notifications */
/**
* @typedef {object} ConversationsAPI
* @typedef {Function} conversations
* @typedef {Function} conversation
*/
/**
* @typedef {object} StateStorage
* @prop {Function} getStates
* @prop {Function} getState
*/
/**
* @typedef {object} ChatLogStorage
* @prop {Function} getInteractions
*/
/**
* Function for filtration of string output
*
* @callback TextFilter
* @param {string} value
* @param {string} key
* @returns {any}
*/
/**
* Create a conversations API
* for retrieving conversations and it's history
*
* @param {StateStorage} stateStorage
* @param {ChatLogStorage} chatLogStorage
* @param {Notifications} notifications
* @param {string[]|Function} [acl] - limit api to array of groups or use auth function
* @param {object} options
* @param {TextFilter} [options.stateTextFilter] - optional funcion for filtering data in states
* @param {Mapper} [options.mapper] - mapper for state values
* @returns {ConversationsAPI}
* @example
* const { GraphApi, conversationsApi } = require('wingbot');
* const BOT_UPDATE_GROUPS = ['botEditor', 'botAdmin', 'botUser'];
*
* function stateTextFilter (value, key) {
* if (key === 'credentials.password') {
* return '****';
* }
* return value;
* }
*
* const api = new GraphApi([
* conversationsApi(
* stateStorage, chatLogStorage, notifications, BOT_UPDATE_GROUPS,
* { stateTextFilter }
* )
* ], {
* token: 'my-secret-token'
* });
*/
function conversationsApi (
stateStorage,
chatLogStorage = null,
notifications = null,
acl = null,
options = {}
) {
async function history (args) {
if (!chatLogStorage || typeof chatLogStorage.getInteractions !== 'function') {
return null;
}
const { limit, startTimestamp, endTimestamp } = args;
const { pageId, senderId } = this;
const data = await chatLogStorage
.getInteractions(senderId, pageId, limit, endTimestamp, startTimestamp);
return data;
}
async function subscriptions () {
const { pageId, senderId } = this;
if (!notifications) {
return null;
}
if (typeof notifications.getSubscriptions === 'function') {
return notifications.getSubscriptions(senderId, pageId);
}
if (typeof notifications.getSubscribtions === 'function') {
const sups = await notifications.getSubscribtions(senderId, pageId);
return sups.map((s) => ({
tag: s,
meta: {}
}));
}
return null;
}
async function subscribtions () {
if (!notifications || typeof notifications.getSubscribtions !== 'function') {
return null;
}
const { pageId, senderId } = this;
return notifications.getSubscribtions(senderId, pageId);
}
let mapState;
if (options.stateTextFilter) {
mapState = (d) => ({
...d,
state: apiTextOutputFilter(d.state, options.stateTextFilter),
lastInteraction: d.lastInteraction || (new Date(0)),
history,
subscribtions,
subscriptions
});
} else if (options.mapper) {
mapState = (d) => ({
...mapObject(d, defaultMapperFactory(options.mapper)),
lastInteraction: d.lastInteraction || (new Date(0)),
history,
subscribtions,
subscriptions
});
} else {
mapState = (d) => ({
...d,
lastInteraction: d.lastInteraction || (new Date(0)),
history,
subscribtions,
subscriptions
});
}
return {
async conversations (args, ctx) {
if (!apiAuthorizer(args, ctx, acl)) {
return null;
}
if (typeof stateStorage.getStates !== 'function') {
return null;
}
const {
limit,
lastKey,
condition
} = args;
await ctx.audit('conversations', args);
const { data, lastKey: nextKey } = await stateStorage
.getStates(condition || {}, limit, lastKey);
return {
data: data.map(mapState),
lastKey: nextKey
};
},
async conversation (args, ctx) {
if (!apiAuthorizer(args, ctx, acl)) {
return null;
}
if (typeof stateStorage.getState !== 'function') {
return null;
}
const {
pageId,
senderId
} = args;
await ctx.audit('conversation', args);
const state = await stateStorage.getState(senderId, pageId);
if (!state) {
return null;
}
return mapState(state);
},
async flaggedInteractions (args, ctx) {
if (!apiAuthorizer(args, ctx, acl)) {
return null;
}
if (!chatLogStorage || typeof chatLogStorage.getInteractions !== 'function') {
return null;
}
const {
limit,
startTimestamp,
flag = null
} = args;
const data = await chatLogStorage
.getInteractions(flag, null, limit, null, startTimestamp);
return data;
}
};
}
module.exports = conversationsApi;