module.exports.endpoint = function(req, res) {
var unirest = require('unirest');
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
var cookieJar = unirest.jar();
// First, we set up the information we need for the API.
// NOTE: to test staging, change API_BASE to 'api.yadkrow.com'
const API_BASE = 'api.workday.com';
const TALK_API_BASE = `https://${API_BASE}/tlkw/rest/`;
// TODO: updated tenant alias, client ID and secret from octopaas
const TENANT_ALIAS = 'devsuvgms31';
const CLIENT_ID = 'ODNhZmVmMTAtOTU5Yi00ZmMyLTgwYmEtOTg0NTcxNTA2MDQ0';
const CLIENT_SECRET = 'exft8x3stl5vbtvvrfmug4t446652xbxqq847qpk6178d9zs598kjn1g3z35kdh4rnmkwjir47hgrvtz212fnstrzgaeocunfqc';
// Pull the tenant out of the command line arguments
const args = process.argv.slice(2);
const tenant = args[0];
// Wire up the webhook callback through Express.js
// This sets up a listener that will respond any time a POST request is made to /conversations/[id]
app.post('/conversations/:conversationId', async function(req, res) {
console.log('Got a POST request for conversation ' + req.params.conversationId);
console.dir(req.body);
try {
const jwt = await getAuthJwt(TENANT_ALIAS, CLIENT_ID, CLIENT_SECRET);
const response = await postMessage(jwt, req.params.conversationId, nextMessageForConversation(req.params.conversationId));
res.send(null);
} catch (e) {
res.status(500).send('Error sending chat message: ' + e);
}
});
app.listen(3000, function() {
console.log('Worktalk bot listening on port 3000!');
});
// API related methods:
// this method authenticates with the api. It uses the client ID and secret to obtain
// a jwt token that can be used with the talk API
async function getAuthJwt(tenantAlias, clientId, clientSecret) {
// Construct the credentials needed to authenticate with the API.
const base64Auth = new Buffer(`${clientId}:${clientSecret}`).toString('base64');
const headers = {
Authorization: `Basic ${base64Auth}`,
'Content-Type': 'application/x-www-form-urlencoded'
};
return new Promise((resolve, reject) => {
unirest
.post(`https://auth.${API_BASE}/v1/token`)
.headers(headers)
.send(`tenant_alias=${tenantAlias}`)
.send(`grant_type=client_credentials`)
.end(function(response) {
if (response.statusCode == 200 && response.body.hasOwnProperty('access_token')) {
resolve(response.body.access_token);
} else {
reject('Unable to validate JWT: ' + JSON.stringify(response.statusCode) + ' ' + JSON.stringify(response.body));
}
});
});
}
// This method posts a message to the Talk server. It takes a conversationId and a message (reply) body,
// and uses the credentials we set up above in 'headers' to POST the message
function postMessage(jwt, conversationId, replyBody) {
// Construct the credentials needed to interact with the API.
// These are passed as HTTP headers.
const headers = {
Authorization: `Bearer ${jwt}`,
'Content-Type': 'application/json'
};
const postPath = `${TALK_API_BASE}conversations/${tenant}/${conversationId}/chatMessages`;
const postBody = {
text: replyBody
};
console.log('Posting message to:', postPath);
return new Promise((resolve, reject) => {
unirest
.post(postPath)
.jar(cookieJar)
.headers(headers)
.send(postBody)
.end(function(response) {
if (response.clientError || response.serverError) {
console.log('Could not create Bot response! ' + JSON.stringify(response.raw_body));
reject(
'Error posting messages, clientError: ' + JSON.stringify(response.clientError) + ' ServerError:' + JSON.stringify(response.raw_body)
);
} else {
console.log('Chat message successfully posted to conversation');
resolve();
}
});
});
}
// Message related methods:
// Set up a Map to store which message index we need to send next in a given conversation.
var conversationMessageIndexes = new Map();
// Try to Load the conversation messages from the 'messages.json' file. If the file can't be
// found, use a default value
var conversationMessages = ['static', 'data', 'from', 'code'];
try {
conversationMessages = require('./messages.json');
} catch (e) {
console.log('Unable to read messages.json, using default values');
}
// This method takes a conversationId and returns the next message for that conversation.
// It checks what message we're at in the conversation, then pulls the correct message out of conversationMessages and returns it.
function nextMessageForConversation(conversationId) {
let currentIndex = conversationMessageIndexes.get(conversationId) || 0;
const currentMessage = conversationMessages[currentIndex];
currentIndex = (currentIndex + 1) % conversationMessages.length;
conversationMessageIndexes.set(conversationId, currentIndex);
return currentMessage;
}
}