Reputation: 1309
Capture each event sent through a webhook and turn it into a Slack post. Events include new blog posts, questions, discussions, wiki page, etc. (qualified as contents
) and comments (qualified as comments
) posted in an online community. Sometimes multiple events are sent in the webhook at once.
This simple JavaScript Azure Function is intended to
contents
from those qualified as comments
content
and/or comment
object (both have their own URL endpoint)contents
and comments
return a similar but different hierarchy of keys)content
or comment
) and send to SlackThe following code worked fine for a single webhook event until I attempted to add the for
loop to accommodate multiple webhook events sent in one array.
{
"events": [{
"TypeId": "9999-999e",
"DateOccurred": "2018-12-15T20:39:42.2487557Z",
"EventData": {
"ActorUserId": 1234,
"ContentId": "5678-999c",
"ContentTypeId": "9012-999d",
"WikiPageId": 3456,
"WikiId": 1
}
},
{
"TypeId": "1111-111f",
"DateOccurred": "2018-12-15T22:55:37.7846546Z",
"EventData": {
"ActorUserId": 2345,
"ContentId": "2222-222b",
"ContentTypeId": "3333-333a",
"ForumReplyId": 4567,
"ForumThreadId": 8901,
"ForumId": 2
}
},
{
"TypeId": "9012-888f",
"DateOccurred": "2018-12-15T22:44:57.7091846Z",
"EventData": {
"ActorUserId": 9876,
"CommentId": "8900-123a"
}
}
]
}
The slightly different structure in hierarchies is accurate.
(for contents)
{
"Content": {
"CreatedByUser": {
"ProfileUrl": "https://<company>.telligenthosting.net/members/<user>",
"Username": "<user>"
},
"HtmlName": "Title",
"HtmlDescription": "Text",
"Url": "https://<company>.telligenthosting.net/<link>"
}
}
(for comments)
{
"Comment": {
"Content": {
"CreatedByUser": {
"ProfileUrl": "https://<company>.telligenthosting.net/members/<user>",
"Username": "<user>"
},
"HtmlName": "Title",
"HtmlDescription": "Text",
"Url": "https://<company>.telligenthosting.net/<link>"
}
}
}
module.exports = function (context, data) {
var json = data.body;
var request = require('request');
// Parse the webhook event JSON body
var unparsed = JSON.stringify(json.events);
var parsed = JSON.parse(unparsed);
console.log(parsed) // RESULTS ARE AS EXPECTED (the JSON nested beneath `events`, beginning and ending with `[]`)
for (var i = 0; i < parsed.length; i++) {
// Parse out Id of webhook event (for all content types but comments)
// This Id retrieves details about the content
var ContentId, ContentTypeId;
if (parsed[i].EventData.hasOwnProperty('ContentId')) {
var ContentId = parsed[i].EventData.ContentId;
var ContentTypeId = parsed[i].EventData.ContentTypeId;
console.log(ContentTypeId); // RESULTS ARE NOT AS EXPECTED: Prints the same Id twice
var options = {
url: "https://<company>.telligenthosting.net/api.ashx/v2/genericcontent/" + ContentId + "/" + ContentTypeId + ".json",
headers: {
"Rest-User-Token": "<token>",
"Content-Type": "application/json"
}
};
};
// Parse out Id of a webhook event (for comments only)
// This Id retrieves details about a comment
var CommentId;
if (parsed[i].EventData.hasOwnProperty('CommentId')) {
var CommentId = parsed[i].EventData.CommentId;
var options = {
url: "https://<company>.telligenthosting.net/api.ashx/v2/comments/" + CommentId + ".json",
headers: {
"Rest-User-Token": "<token>",
"Content-Type": "application/json"
}
};
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
//For all content types but comments
var username, profileUrl, subject, url, text;
if (info.hasOwnProperty('Content')) {
username = info.Content.CreatedByUser.Username;
profileUrl = info.Content.CreatedByUser.ProfileUrl;
subject = info.Content.HtmlName;
url = info.Content.Url;
text = info.Content.HtmlDescription;
};
//For comments
if (info.hasOwnProperty('Comment')) {
username = info.Comment.User.DisplayName;
profileUrl = info.Comment.User.ProfileUrl;
subject = info.Comment.Content.HtmlName;
url = info.Comment.Url;
text = info.Comment.Body;
};
};
//Send to Slack
function sendToSlack(theUsername, theIconEmoji) {
var theUsername = "Bot";
var theIconEmoji = ":bot:";
var payload = {
attachments: [{
author_name: username,
author_link: profileUrl,
title: subject,
title_link: url,
text: text
}]
};
if (theUsername !== undefined) {
payload.username = theUsername;
}
if (theIconEmoji !== undefined) {
payload.icon_emoji = theIconEmoji;
}
var theRequest = {
url: urlWebHook,
method: "POST",
json: payload
};
request(theRequest, function (error, response, body) {});
}
var urlWebHook = "https://hooks.slack.com/services/<Id>";
sendToSlack();
};
};
request(options, callback);
};
As commented out in the code above, it appears that the loop is not going through each event but rather through the first event multiple times.
Much of what I read indicates for (var i = 0; i < json.length; i++) {
is the proper approach but no matter what I try the Azure Function throws a 500 Internal Service Error
and eventually times out. No information is provided in the debug console even though detailed logging is turned on.
Thank you for any advice or education.
Upvotes: 0
Views: 318
Reputation: 186
EventData
is not defined because you're not constructing your object properly.
Here's how you might do it:
var json = require("./test.json");
var unparsedEvents = json.events;
for (let event of unparsedEvents) {
var ContentId = event.EventData.ContentId;
var ContentTypeId = event.EventData.ContentTypeId;
var CommentId = event.EventData.CommentId;
var options = new Object();
console.log("ContentId:", ContentId);
console.log("ContentTypeId:", ContentTypeId);
console.log("CommentId:", CommentId);
if (CommentId) {
options.url = "https://<company>.telligenthosting.net/api.ashx/v2/comments/" + CommentId + ".json";
options.headers = {
"Rest-User-Token": "<token>",
"Content-Type": "application/json",
};
} else {
options.url = "https://<company>.telligenthosting.net/api.ashx/v2/genericcontent/" + ContentId + "/" + ContentTypeId + ".json";
options.headers = {
"Rest-User-Token": "<token>",
"Content-Type": "application/json",
};
}
console.log("options:", options);
console.log();
}
Upvotes: 1
Reputation: 11
I believe you need to change parsed[0] to parsed[i]. Currently you are looping through the array but only accessing the first element, which is why you see the first event multiple times.
Upvotes: 1