help-fem
Version:
A Browserify/Node.js client module for the Help.com team's FEM.
1,569 lines (1,519 loc) • 47.7 kB
JavaScript
;(function() {
'use strict';
// ## Required Modules
// ### underscore.js
// Underscore.js is used for utility, mainly to allow the client to be extended
// *a la* Backbone / Ampersand style.
var _ = require('underscore');
// ### uuid
// UUID is used to generate the v4 UUIDs for the socket messages.
var uuid = require('uuid');
// ### femio-client
// The main driver for this client module, the femio-client provides an easy
// interface for talking to a FEMIO server.
var io = require('femio-client');
var clientLog = require('debug')('help-fem:client');
var serverLog = require('debug')('help-fem:server');
// ## HelpFem
// `HelpFem` is really just a synonym for `module.exports`.
var HelpFem = {};
function defaultHandler(type, error, response) {
if (error) {
throw error;
}
console.log('Successful ' + type + ': ' + JSON.stringify(response));
}
// ## HelpFem.Client
// ### HelpFem.Client.constructor
// The constructor for `HelpFem.Client` takes an object of options for flexibility.
// The current supported options are:
// 1. `uri` :: `String` - The URI for the FEM (or really any websocket server).
// Defaults to either `localhost:8080` or reads the `FEM` environment variable.
// 2. `organizationId` || `namespace` :: `String` - The namespace you would like to
// connect to in your FEMIO server. The option is aliased to `organizationId`
// because Help.com namespaces are organization IDs.
// 3. `user` :: `Boolean` - Whether or not the client is a user or a customer.
// Defaults to `false`.
HelpFem.Client = function(options) {
// Test to see if we are in the browser or running as a backend microservice.
this.inBrowser = typeof window !== 'undefined';
// Set the `uri`. If it's set in `options`, use that value. Otherwise, defer to
// localhost if in the browser, or the FEM environment variable otherwise.
this.uri = typeof options.uri === 'string' ?
options.uri
: (this.inBrowser ? 'http://127.0.0.1:8080' : process.env.FEM);
// Set the `organizationId` and `namespace`.
var org = options.organizationId || options.namespace;
if (org === 'start') {
org = undefined;
}
this.organizationId = this.namespace = org;
// Set the `role` of the client, defaulting to `'customer'`.
this.role = options.user ? 'user' : 'customer';
// Ensure that any objects with methods have access to the client object.
// This will allow us to call functions with the desired context.
this.chat.parent = this;
this.session.parent = this;
// Application Context
this.context = options.context;
// Information to be stored about this specific client.
this.info = {};
/* istanbul ignore next */
if (this.inBrowser) {
var transports = window.WebSocket && window.WebSocket.CLOSING === 2
? ['websocket', 'polling']
: ['polling'];
} else {
var transports = options.transports || ['websocket', 'polling'];
}
// Connect to the FEMIO server and store the socket information.
this.socket = io(this.uri, {
transports: transports,
orgId: this.organizationId,
clientId: options.clientId || undefined
});
this.socket.on('error', function(err) {
console.error('socket err', err);
});
// Reply callback map for this client.
this.replyCallbacks = {};
// #### Extending Events
// Extending events is done exactly like in Ampersand or Backbone, except with
// added functionality to have types within an event. The event callback passes
// an error as the first argument followed by the JSON response object.
//
// ```js
// {
// events: {
// 'event with no sub types': 'regularCallback'
// 'server eventGroup event': {
// 'type one': 'typeOneCallback',
// 'type two': 'typeTwoCallback'
// },
// regularCallback: function(error, response) {
// console.log('# Raw response: ' + JSON.stringify(response));
// },
// typeOneCallback: function(error, response) {
// console.log('# Raw response: ' + JSON.stringify(response));
// }
// }
// }
// ```
//
// In order to be able to extend the events without completely overriding all
// the default actions, we need to split up socket events from our internal
// event types.
var events = {};
var eventsWithTypes = {};
// Run through the `events` property and dive into events that have sub types.
// This overwrites any default callbacks with explicitly declared ones.
var self = this;
_.each(self.events, function(event, index) {
if (typeof self._events[index] === 'object') {
eventsWithTypes[index] = {};
_.extend(eventsWithTypes[index], self._events[index], event);
}
});
// Create a full list of all events, deferring any default callbacks with
// explicitly declared ones.
_.extend(events, self._events, self.events, eventsWithTypes);
// `generateCallback` is a helper function to properly generate a callback
// that works with femio-client.
function generateCallback(event) {
var getRegisteredCallback;
// ##### Basic Top Level Events
// If the event does not handle any subtypes, just register the callback.
if (typeof events[event] === 'string') {
getRegisteredCallback = function() {
return self[events[event]];
};
// ##### Events with Subtypes
// If the event does involve subtypes, register a callback that handles
// those subtypes.
} else {
getRegisteredCallback = function(meta) {
if (_.has(events[event], meta.type)) {
return self[events[event][meta.type]];
}
};
}
return function callback() {
var args = Array.prototype.slice.call(arguments);
var response = args[0];
var meta = _.has(response, 'meta') ? response.meta : {};
self.log(event, response);
var next = [getRegisteredCallback(meta)];
if (_.has(self.replyCallbacks, meta.replyTo)) {
next.push(self.replyCallbacks[meta.replyTo]);
delete self.replyCallbacks[meta.replyTo];
}
// If no callbacks are registered, warn about an unhandled event.
if (next.length === 1 && next[0] === undefined) {
args.splice(2, 0, event);
// Use an overriding unhandled event if specified.
var unhandled = typeof self.unhandled === 'function' ? self.unhandled : self._unhandled;
next.push(unhandled);
}
// Prepend the error to the arguments list.
var error = _.has(meta, 'result') && meta.result !== 'SUCCESS' ? new Error(meta.reason) : null;
args.unshift(error);
// Call the callbacks with a client context and the arguments.
_.invoke(_.filter(next), 'apply', self, args);
};
}
// Register all the femio-client callbacks.
for (var event in events) {
self.socket.on(event, generateCallback(event));
}
// Call initialize function if not turned off
if (options.init !== false) {
this.initialize.apply(this, arguments);
}
};
// ### HelpFem.Client.prototype
_.extend(HelpFem.Client.prototype, {
// Logger
log: function log(event, payload) {
var meta = _.result(payload, 'meta', {});
if (event.indexOf('server') > -1) {
serverLog('%s: %o', meta.type, payload);
} else {
clientLog('%s: %o', meta.type, payload);
}
},
// Default events.
_events: {
'connect': '_connect',
'disconnect': '_disconnect',
'server session event': {
'start': '_sessionStart',
'end': '_sessionEnd',
'login': '_sessionLogin',
'logout': '_sessionLogout'
},
'server chat event': {
'start': '_chatStart',
'join': '_chatJoin',
'leave': '_chatLeave'
}
},
// ### Default Callbacks
// Default `unhandled` callback.
_unhandled: function(error, response, event) {
console.warn('Unhandled Event', {
event: event,
command: response.meta.type,
error: error,
response: response
});
},
// Default `connect` callback.
_connect: function() {
console.log('Connected to FEM.');
},
_disconnect: function() {
console.log('Disconnected from FEM.');
},
// Default `server session event start` callback.
_sessionStart: _.partial(defaultHandler, 'session start'),
// Default `server session event end` callback.
_sessionEnd: _.partial(defaultHandler, 'session end'),
// Default `server session event login` callback.
_sessionLogin: function(error, response) {
defaultHandler('session login', error, response);
// Update with new Client ID.
this.info.clientId = response.data.clientId;
},
// Default `server session event logout` callback.
_sessionLogout: _.partial(defaultHandler, 'session logout'),
// Default `server chat event start` callback.
_chatStart: _.partial(defaultHandler, 'chat start'),
// Default `server chat event join` callback.
_chatJoin: _.partial(defaultHandler, 'chat join'),
// Default `server chat event leave` callback.
_chatLeave: _.partial(defaultHandler, 'chat leave'),
// ### Built-In Actions
// #### Initialization
initialize: function() {
return this;
},
// #### Session
session: {
resetState: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'reset client state'},
data,
callback
);
},
// Request metadata cache.
getCacheMetadata: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'get cache metadata'},
data,
callback
);
},
// Start a session.
start: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'start'},
data,
callback
);
},
// End a session.
end: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'end'},
data,
callback
);
},
// Login to a session.
login: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'login'},
data,
callback
);
},
// Logout of a session.
logout: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'logout'},
data,
callback
);
},
//send request for reset password token
resetPassword: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'reset password'},
data,
callback
);
},
updatePassword: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'update password'},
data,
callback
);
},
// Actual password reset request
updateCurrentUser: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/user', method: 'PUT'},
data,
callback
);
},
initializeState: function(data) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'initialize state'},
data
);
},
customerSonarPing: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'customer sonar ping'},
data,
callback
);
},
userSonarPing: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'user sonar ping'},
data,
callback
);
},
doormanAssignChat: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'doorman assign chat'},
data,
callback
);
},
doormanMonitorChat: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'doorman monitor chat'},
data,
callback
);
},
// Send a chat status update.
chatStatus: function(data) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'chat status'},
data
);
},
// Set rep availability.
updateAvailability: function(availability, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'update availability'},
{availability: availability},
callback
);
},
suggestion: function(data) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'suggestion'},
data
);
},
postchat: function(data) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'postchat'},
data
);
},
getSurvey: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'postchat'},
{uri: '/survey', method: 'GET'},
data,
callback
);
},
postChatResponse: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'postchat'},
{uri: '/response', method: 'GET'},
data,
callback
);
},
getPostChatQuestion: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'postchat'},
{uri: '/question', method: 'GET'},
data,
callback
);
},
updatePostChatQuestion: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'postchat'},
{uri: '/question', method: 'PUT'},
data,
callback
);
},
createPostChatQuestion: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'postchat'},
{uri: '/question', method: 'POST'},
data,
callback
);
},
deletePostChatQuestion: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'postchat'},
{uri: '/question', method: 'DELETE'},
data,
callback
);
},
createPostChatQuestionOption: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'postchat'},
{uri: '/option', method: 'POST'},
data,
callback
);
},
updatePostChatQuestionOption: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'postchat'},
{uri: '/option', method: 'PUT'},
data,
callback
);
},
deletePostChatQuestionOption: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'postchat'},
{uri: '/option', method: 'DELETE'},
data,
callback
);
},
getOrganizationSettings: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'get organization settings'},
data,
callback
);
},
updateOrganizationSettings: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'update organization settings'},
data,
callback
);
},
deleteOrganizationSettings: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'delete organization settings'},
data,
callback
);
},
getOrganizationChatSettings: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'get organization chat settings'},
data,
callback
);
},
updateUser: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/users', method: 'PUT'},
data,
callback
);
},
createUser: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/users', method: 'POST'},
data,
callback
);
},
deleteUser: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/user', method: 'DELETE'},
data,
callback
);
},
getDepartments: function (data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/departments', method: 'GET'},
data,
callback
);
},
updateAnalyticsSession: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'update analytics'},
data,
callback
);
},
getAnalyticsSession: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'get analytics session'},
data,
callback
);
},
sendOfflineMessage: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'sendOfflineMessage'},
{uri: '/sendEmail', method: 'POST'},
data,
callback
);
},
getHistory: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'chatHistory'},
{uri: '/listChats', method: 'GET'},
data,
callback
);
},
getEventsForChat: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'chatHistory'},
{uri: '/eventsForChat', method: 'GET'},
data,
callback
);
},
getReportRollup: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingEvents', method: 'GET'},
data,
callback
);
},
getReportRaw: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingEventsRaw', method: 'GET'},
data,
callback
);
},
getNps: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingPostChat'},
{uri: '/nps', method: 'GET'},
data,
callback
);
},
getReportResponseLag: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingResponseLag', method: 'GET'},
data,
callback
);
},
getReportWordCounts: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingWordCounts', method: 'GET'},
data,
callback
);
},
getReportStarted: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingStarted', method: 'GET'},
data,
callback
);
},
getReportStartedByDayOfWeek: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingStartedByDayOfWeek', method: 'GET'},
data,
callback
);
},
getReportCompleted: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingCompleted', method: 'GET'},
data,
callback
);
},
getReportOfflineMessages: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingOfflineMessages', method: 'GET'},
data,
callback
);
},
getReportBusiestUsers: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingBusiestUsers', method: 'GET'},
data,
callback
);
},
getReportBusiestGroups: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingBusiestGroups', method: 'GET'},
data,
callback
);
},
getReportBusiestDepartments: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingBusiestDepartments', method: 'GET'},
data,
callback
);
},
getReportCompletedDOW: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingCompletedDOW', method: 'GET'},
data,
callback
);
},
getReportUnanswered: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingUnanswered', method: 'GET'},
data,
callback
);
},
getReportAbandoned: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingAbandoned', method: 'GET'},
data,
callback
);
},
getReportTotalChatTime: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingTotalChatTime', method: 'GET'},
data,
callback
);
},
getReportFirstResponse: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingFirstResponse', method: 'GET'},
data,
callback
);
},
getReportQueueTime: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingQueueTime', method: 'GET'},
data,
callback
);
},
getReportNpsResponseCounts: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingNpsResponseCounts', method: 'GET'},
data,
callback
);
},
getReportNpsHistorical: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingNpsHistorical', method: 'GET'},
data,
callback
);
},
getReportNpsByUser: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingNpsByUser', method: 'GET'},
data,
callback
);
},
getReportNpsByGroup: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingNpsByGroup', method: 'GET'},
data,
callback
);
},
getReportNpsByDepartment: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'reportingEvents'},
{uri: '/reportingNpsByDepartment', method: 'GET'},
data,
callback
);
},
getUsers: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/users', method: 'GET'},
data,
callback
);
},
getGroups: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/groups', method: 'GET'},
data,
callback
);
},
getGroupUsers: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/groupusers', method: 'GET'},
data,
callback
);
},
createGroupUserTie: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/groupusers', method: 'POST'},
data,
callback
);
},
deleteGroupUserTie: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/groupusers', method: 'DELETE'},
data,
callback
);
},
getDepartmentGroups: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/departmentgroups', method: 'GET'},
data,
callback
);
},
createDepartmentGroupTie: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/departmentgroups', method: 'POST'},
data,
callback
);
},
deleteDepartmentGroupTie: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/departmentgroups', method: 'DELETE'},
data,
callback
);
},
createDepartment: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/departments', method: 'POST'},
data,
callback
);
},
updateDepartment: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/departments', method: 'PUT'},
data,
callback
);
},
createGroup: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/groups', method: 'POST'},
data,
callback
);
},
updateGroup: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'organizationManager'},
{uri: '/groups', method: 'PUT'},
data,
callback
);
},
chatStartRep: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'chat start rep'},
data,
callback
);
},
chatInvitationSend: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'chat invitation send'},
data,
callback
);
},
chatInvitationAccept: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'chat invitation accept'},
data,
callback
);
},
chatInvitationReject: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'chat invitation reject'},
data,
callback
);
},
getChatNotes: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'noteManager'},
{uri: '/note', method: 'GET'},
data,
callback
);
},
postChatNotes: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'noteManager'},
{uri: '/note', method: 'POST'},
data,
callback
);
},
postChatTag: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'tagManager'},
{uri: '/chats', method: 'POST'},
data,
callback
);
},
removeChatTag: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'tagManager'},
{uri: '/chats', method: 'DELETE'},
data,
callback
);
},
getTagsForChat: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'tagManager'},
{uri: '/tagsForChat', method: 'GET'},
data,
callback
);
},
getTagReport: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'tagManager'},
{uri: '/report', method: 'GET'},
data,
callback
);
},
getOrganizationChatTags: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'tagManager'},
{uri: '/tags', method: 'GET'},
data,
callback
);
},
postOrganizationChatTag: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'tagManager'},
{uri: '/tags', method: 'POST'},
data,
callback
);
},
removeOrganizationChatTag: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'tagManager'},
{uri: '/tags', method: 'DELETE'},
data,
callback
);
},
getBannedIps: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'banned'},
{uri: '/banned', method: 'GET'},
data,
callback
);
},
postBannedIp: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'banned'},
{uri: '/banned', method: 'POST'},
data,
callback
);
},
removeBannedIp: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'banned'},
{uri: '/banned', method: 'DELETE'},
data,
callback
);
},
emailCustomerTranscript: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'email customer transcript'},
data,
callback
);
},
setCredentialsSalesforceApi: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'salesforceGet'},
{uri: '/credentials', method: 'POST'},
data,
callback
);
},
getCredentialsSalesforceApi: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'salesforceGet'},
{uri: '/credentials', method: 'GET'},
data,
callback
);
},
getSalesforceMetaData: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'salesforceGet'},
{uri: '/salesforceMetaData', method: 'GET'},
data,
callback
);
},
getSalesforcePicklist: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'salesforceGet'},
{uri: '/picklist', method: 'GET'},
data,
callback
);
},
setSalesforcePicklist: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'salesforceGet'},
{uri: '/picklist', method: 'POST'},
data,
callback
);
},
getSalesforceData: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'salesforceGet'},
{uri: '/salesforce', method: 'GET'},
data,
callback
);
},
getSalesforceAuthRequestURL: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'salesforcePush'},
{uri: '/requestURL', method: 'GET'},
data,
callback
);
},
getSalesforceConnectedApp: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'salesforcePush'},
{uri: '/connectedApp', method: 'GET'},
data,
callback
);
},
getSalesforceHasAccessToken: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'salesforcePush'},
{uri: '/hasAccessToken', method: 'GET'},
data,
callback
);
},
refreshSalesforceToken: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'salesforcePush'},
{uri: '/refreshToken', method: 'POST'},
data,
callback
);
},
createSalesforceObject: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'salesforcePush'},
{uri: '/createObject', method: 'POST'},
data,
callback
);
},
contactSupport: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'contact support'},
data,
callback
);
},
addOrganizationChatResponse: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'add organization chat response'},
data,
callback
);
},
updateOrganizationChatResponse: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'update organization chat response'},
data,
callback
);
},
getOrganizationChatResponses: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'get organization chat responses'},
data,
callback
);
},
deleteOrganizationChatResponse: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'delete organization chat response'},
data,
callback
);
},
addUserChatResponse: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'add user chat response'},
data,
callback
);
},
updateUserChatResponse: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'update user chat response'},
data,
callback
);
},
getUserChatResponses: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'get user chat responses'},
data,
callback
);
},
deleteUserChatResponse: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'delete user chat response'},
data,
callback
);
},
getAllChatResponses: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'get all chat responses'},
data,
callback
);
},
postChatResponseToRoom: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'post chat response room'},
data,
callback
);
},
zendeskGetAuthUrl: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'zendesk get auth url'},
data,
callback
);
},
zendeskGetTickets: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'zendesk get tickets'},
data,
callback
);
},
zendeskCreateTicket: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'zendesk create ticket'},
data,
callback
);
},
fireTrigger: function(data) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'proactive chat fire trigger'},
data
);
},
fireTriggers: function(data) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'proactive chat fire triggers'},
data
);
},
getProactiveGreetings: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'proactive chat get greetings'},
data,
callback
);
},
upsertProactiveGreeting: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'proactive chat upsert greeting'},
data,
callback
);
},
deleteProactiveGreeting: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'proactive chat delete greeting'},
data,
callback
);
},
// Request to transfer chat.
requestTransfer: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'transfer request'},
data,
callback
);
},
// Respond to transfer chat.
respondToTransfer: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'transfer response'},
data,
callback
);
},
getVisitors: function(data, callback) {
this.parent._doHyperJSONEmit(
this.parent._emitSessionEvent,
{type: 'list visitors'},
{},
data,
callback
);
},
forceUserLogout: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'force logout user'},
data,
callback
);
},
getMissionControlVersion: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'mission control get version'},
data,
callback
);
},
dumpState: function(callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'dumpState'},
{},
callback
);
},
chatAndAvailabilityDetails: function(callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'chat-and-availability-details'},
{},
callback
);
},
renameCustomer: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'rename-customer'},
data,
callback
);
}
},
// #### Chat
chat: {
// Start a chat.
start: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitChatEvent,
{type: 'start'},
data,
callback
);
},
// End a chat.
end: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitChatEvent,
{type: 'end'},
data,
callback
);
},
// Join a chat room.
join: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitChatEvent,
{type: 'join'},
data,
callback
);
},
// Leave a chat.
leave: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'leave'},
data,
callback
);
},
// Send a chat message.
message: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitChatEvent,
{type: 'message'},
data,
callback
);
},
// Request the latest chat cache.
cache: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitChatEvent,
{type: 'cache'},
data,
callback
);
},
// Request message cache.
getCacheMessages: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitChatEvent,
{type: 'get cache messages'},
data,
callback
);
},
// Request metadata cache.
getCacheMetadata: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitChatEvent,
{type: 'get cache metadata'},
data,
callback
);
},
requestRepAvailability: function(data, callback) {
this.parent._doSimpleEmit(
this.parent._emitSessionEvent,
{type: 'get rep availability'},
data,
callback
);
}
},
// #### Generic Emit
// This method can be called to send any kind of message through femio-client without
// having to directly invoke the socket object.
emit: function(type, payload) {
this.log(type, payload);
this.socket.send(type, payload);
},
// #### Generate Meta
// This method generates a meta for your payload. You can pass any properties and it
// will automatically take care of the `id` property for you. It will also
// add any information in stored in the client's `info` property.
// Properties passed into the function take precedent.
generateMeta: function(properties) {
return _.extend({id: uuid.v4()}, this.info, properties);
},
_doSimpleEmit: function(emitter, metaProperties, data, callback) {
if (typeof data === 'function' && typeof callback === 'undefined') {
callback = data;
data = {};
}
var _data = _.extend({}, data, this.info);
emitter.call(this, metaProperties, _data, callback);
},
_doHyperJSONEmit: function(emitter, metaProperties, hyperJSON, data, callback) {
if (typeof data === 'function' && typeof callback === 'undefined') {
callback = data;
data = {};
}
var _data = _.extend({}, hyperJSON, {body: data}, this.info);
emitter.call(this, metaProperties, _data, callback);
},
_emitChatEvent: function(metaProperties, data, callback) {
return this._emitEvent('client chat event', metaProperties, data, callback);
},
_emitSessionEvent: function(metaProperties, data, callback) {
return this._emitEvent('client session event', metaProperties, data, callback);
},
_emitEvent: function(event, metaProperties, data, callback) {
var payload = {meta: this.generateMeta(metaProperties), data: data};
this.emit(event, payload);
if (typeof callback === 'function') {
this.replyCallbacks[payload.meta.id] = callback;
}
}
});
// ### HelpFem.Client.extend
// Modeled after Ampersand and Backbone's `extend` functionality, this method creates
// a new `HelpFem.Client` with any additional prototypical or private methods and
// properties.
HelpFem.Client.extend = function(prototypes, privates) {
var parent = this;
var child;
if (typeof prototypes === 'object' && prototypes.hasOwnProperty('constructor')) {
child = prototypes.constructor;
} else {
child = function() {
return parent.apply(this, arguments);
};
}
_.extend(child, parent, privates);
var Surrogate = function() {
this.constructor = child;
};
Surrogate.prototype = parent.prototype;
child.prototype = new Surrogate();
if (typeof prototypes === 'object') {
_.extend(child.prototype, parent.prototype, prototypes);
}
return child;
};
// Export the module.
module.exports = HelpFem;
})();