Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added a property addedBy to a bot #25

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions docs/example4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
## Example #4 Using PubNub
An inbound, internet reachable port, is required for the Webex Teams API to notify
Flint of webhook events. This is not always easy or possible.

The standard way to handle firewall tunneling is via a tool like ngrok or a web server in the DMZ.
Here we use a different approach. We are using a PubNub server as a way to transmit the webhook event to
the flint application, which uses a PubNub client to receive the event. PubNub uses whatever mechanism is best suited to reach the PubHub nodes.

There is a PubNub function you need to deploy at PubNub. It's in the file pubnub-function.js.
Check their tutorial here:
https://www.pubnub.com/tutorials/pubnub-functions/
Configure the function to run 'On Request'

Once you configured your PubNub function (block) you should copy the URL and configure it as WebhookRecipientURL
in your environment. You also need to configure the PubnubSubscribeKey in your environment so the client
can subscribe to the channel. As channel name we used webex since flint registers for webhooks with
resource:all event: all ( we also publish to webex.${resource} and webex.${resource}.${event} so you can use
PubNubs channel wildcards if you want. See here https://www.pubnub.com/developers/tech/key-concepts/stream-controller/wildcard-subscribe/)

When PubNub receives the event it will invoke the function that then sends the event along the channel.
Flint spawns a bot for every space/room and will cross check based on the roomId to which bot the message
belongs.

If you want a different additional bot configured, you must use a different WebhookRecipientURL and
PubnubSubscribeKey Key.

You should check the temaplates folder for a working example.
```js
"use strict";

var Flint = require('node-flint');
var webhook = require('node-flint/webhook');
var path = require('path');
var PubNub = require('pubnub');
var config = require(path.join(__dirname, 'config.js'));
var when = require('when');


// instantiate thje pubnub object
var pubnub = new PubNub ({
subscribeKey : config.pubnubSubscribeKey
})

// pubnub status listener
// we use it here for the initialization and then remove ourselves
let statusListener = {
status: (s) => {
if (s.category === "PNConnectedCategory") {
// res is from the closure
this.res("fullfilled my init promise for pubnub");
}
}
}




let messageListener = {
message: (m) => {
webhook(flint)(m.message);
}
}



function checkInit() {
return new Promise( (res,rej) => {
statusListener.__proto__.res = res;
const initTimeSecs = 5;
// give 3 second init time
setTimeout(() => {
rej("resolved")
}, initTimeSecs * 1000)

pubnub.addListener(statusListener);
})
}

// init flint
var flint = new Flint(config);

checkInit()
.then( (a) => { pubnub.removeListener(statusListener) })
.then( () => { flint.start() } )
.then( () => { flint.use(path.join(__dirname, 'flint.js')) })
.then( () => { flint.debug('Flint has started') })
.then( () => { pubnub.addListener(messageListener) })
.catch( (e) => { console.log("could not init pubnub or flint") })


// flint registers webhooks for resurce: all event: all
// so here we listen to the all all pubnub channel
pubnub.subscribe({
channels: ["webex"]
})


// gracefully shutdown (ctrl-c)
process.on('SIGINT', function() {
flint.debug('stoppping...');
flint.stop().then(function() {
process.exit();
});
});
```
11 changes: 6 additions & 5 deletions lib/bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -857,13 +857,10 @@ Bot.prototype.say = function(format, message) {
format = _.toLower(args.shift());
}

// if message is object (raw)
if(typeof args[0] === 'object') {
return this.spark.messageSendRoom(this.room.id, args[0]);
}


// if message is string
else if(typeof args[0] === 'string') {
else if(typeof args[0] === 'string' || Array.isArray(args[0])) {
// apply string formatters to remaining arguments
message = util.format.apply(null, args);

Expand All @@ -879,6 +876,10 @@ Bot.prototype.say = function(format, message) {

// send constructed message object to room
return this.spark.messageSendRoom(this.room.id, messageObj);
}
// if message is object (raw)
else if(typeof args[0] === 'object') {
return this.spark.messageSendRoom(this.room.id, args[0]);
}

else {
Expand Down
23 changes: 19 additions & 4 deletions lib/flint.js
Original file line number Diff line number Diff line change
Expand Up @@ -1213,8 +1213,9 @@ Flint.prototype.onMembershipCreated = function(membership) {

// if bot membership added to un-monitored room...
if(!bot && this.initialized && membership.personEmail === this.person.email) {
// spawn bot
return this.spawn(membership.roomId);
// spawn bot - we added the actorId which is the person who added us to the room ( or undefined ) to the bot as
// property
return this.spawn(membership.roomId, membership.actorId);
}

// else if other membership added to monitored room...
Expand Down Expand Up @@ -1502,7 +1503,6 @@ Flint.prototype.onMessageCreated = function(message) {

// emit message event
if(trigger.text) {

/**
* Message Recieved.
*
Expand Down Expand Up @@ -1637,7 +1637,7 @@ Flint.prototype.onAttachmentActions = function(attachmentAction) {
* @param {String} Room ID - The ID for a Spark Room.
* @returns {Promise.<Boolean>}
*/
Flint.prototype.spawn = function(roomId) {
Flint.prototype.spawn = function(roomId, actorId) {

// if active...
if(!this.active) {
Expand Down Expand Up @@ -1722,6 +1722,21 @@ Flint.prototype.spawn = function(roomId) {

return when(memberships);
})
.then( () => {
if (undefined !== actorId && actorId) {
return this.spark.personGet(actorId)
} else {
return when(false)
}
}
)
.then( (p) => {
if (p !== false) {
newBot.addedBy = p.emails[0]
}
return when(true)
}
)

// register and start bot
.then(() => {
Expand Down
4 changes: 3 additions & 1 deletion lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

var uuid = require('uuid');
var base64 = require('js-base64').Base64;

var Utils = {};

Expand All @@ -12,7 +13,8 @@ var Utils = {};
* @returns {String} Base64 encoded string.
*/
Utils.base64encode = function(string) {
return new Buffer(string).toString('base64');
// deprecated return new Buffer(string).toString('base64');
return base64.encode(string);
};

/**
Expand Down
143 changes: 143 additions & 0 deletions lib/webhook.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,151 @@ function Webhook(flint) {
return when(true);
}

<<<<<<< HEAD
return processEvent(flint, body);

=======
if(!flint.active) {
return when(true);
}

// get webhook content
var id = body.id;
var name = body.name;
var resource = body.resource;
var event = body.event;
var data = body.data;
var roomId = body.filter ? body.filter.split('=')[1] : null;
// actorId is part of the webhook enevelope
var actorId = body.actorId;

// validate webbhook is bound for this instance of flint
if(name !== flint.webhook.name || (typeof flint.webhook.roomId !== 'undefined' && flint.webhook.roomId !== roomId)) {
return when(true);
}

if(typeof resource !== 'string' || typeof event !== 'string') {
flint.debug('Can not determine webhook type');
return when(true);
}

// rooms
if(resource === 'rooms') {
return flint.getRoom(data.id)
.then(room => {

// set room title for rooms with none set (api bug?)
if(room.title == '') {
room.title = 'Default title';
}

// room created
if(event === 'created') {
flint.emit('roomCreated', room, flint.id);

return flint.onRoomCreated(room)
.catch(err => {
flint.debug(err.stack);
return when(true);
});
}

// room updated
if(event === 'updated') {
flint.emit('roomUpdated', room, flint.id);

return flint.onRoomUpdated(room)
.catch(err => {
flint.debug(err.stack);
return when(true);
});
}

})
.catch(() => {
return when(true);
});
}

// memberships
if(resource === 'memberships') {

// membership created
if(event === 'created') {
return flint.getMembership(data.id)
.then(membership => {
// /we augment the membership with the actorID so we can DM the person and ask them into a private room
membership.actorId = actorId;
flint.emit('membershipCreated', membership, flint.id);

return flint.onMembershipCreated(membership)
.catch(err => {
flint.debug(err.stack);
return when(true);
});
})
.catch(() => {
return when(true);
});
}

// membership updated
if(event === 'updated') {
return flint.getMembership(data.id)
.then(membership => {
membership.actorId = actorId;
flint.emit('membershipUpdated', membership, flint.id);

return flint.onMembershipUpdated(membership)
.catch(err => {
flint.debug(err.stack);
return when(true);
});
})
.catch(() => {
return when(true);
});
}

// membership deleted
if(event === 'deleted') {
flint.emit('membershipDeleted', data, flint.id);

return flint.onMembershipDeleted(data)
.catch(err => {
flint.debug(err.stack);
return when(true);
});
}

}

// messages
if(resource === 'messages') {
// membership created
if(event === 'created') {
return flint.getMessage(data.id)
.then(message => {
flint.emit('messageCreated', message, flint.id);

return flint.onMessageCreated(message)
.catch(err => {
flint.debug(err.stack);
return when(true);
});
})
.catch(() => {
return when(true);
});
}

// message deleted
if(event === 'deleted') {
flint.emit('messageDeleted', data, flint.id);
return when(true);
}
}
>>>>>>> added a property addedBy to a bot to store the email of the person who added the bot. this may be useful if we want to DM the person who added the bot, for example for bots that are disallowed in the group rooms. The bot can act immediately without needing to be addressed first
}; // end of return function...
}

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
},
"devDependencies": {
"doctoc": "^1.3.0",
"express": "^4.16.4",
"js-base64": "^2.4.9",
"jsdoc-to-markdown": "^3.0.0"
}
}
1 change: 1 addition & 0 deletions templates/pubnub-template/Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: DEBUG=flint,bot node main.js
2 changes: 2 additions & 0 deletions templates/pubnub-template/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#pubnub-template

12 changes: 12 additions & 0 deletions templates/pubnub-template/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
token: process.env.TOKEN,
maxPageItems: 100,
maxConcurrent: 5,
minTime: 50,
requeueCodes: [ 429, 500, 501, 502, 503 ],
requeueMinTime: 500,
removeWebhooksOnStart: true,
webhookSecret: process.env.FLYNN_APP_ID,
pubnubSubscribeKey: process.env.PubnubSubscribeKey,
webhookUrl: process.env.WebhookRecipientURL
};
7 changes: 7 additions & 0 deletions templates/pubnub-template/flint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"use strict";

module.exports = function(flint) {
flint.hears('hello', function(bot, trigger) {
bot.say('Hello %s!', trigger.personDisplayName);
});
};
Loading