diff --git a/.gitignore b/.gitignore index a58f6f6..3bd4f75 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,8 @@ node_modules # Private environments .env -ToDo.private \ No newline at end of file +ToDo.private + +# Test version of sample +example1.js + diff --git a/README.md b/README.md index 487d689..cd3bb87 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,15 @@ -# webex-flint +# webex-node-bot-framework ### Webex Teams Bot Framework for Node JS -This project is inspired by, and provides an alternate implementation of, the awesome [node-flint](https://github.com/flint-bot/flint/) framework by [Nick Marus](https://github.com/nmarus). The flint framework makes it easy to quickly develop a Webex Teams bot, abstractig away some of the complexity of Webex For Developers interfaces, such as registering for events and calling REST APIs. A bot developer can use the flint framework to spark their imagination and focus primarily on how the bot will interact with users in Webex Teams. +**Warning** - *This project is still in its initial development, so use at your own risk. For details on areas that may still require attention before the poejcet is fully complete please see the* [To Do List](./docs/ToDo.MD) -The primary change in this implementation is that it is based on the [webex-jssdk](https://webex.github.io/webex-js-sdk) which continues to be supported as new features and functionality are added to Webex. - -For developers who are familiar with flint, or who wish to port existing bots built on node-flint to the webex-flint framework, this implementation is backwards compatible. Please see [Differences from original flint framework](./docs/migrate-from-node-flint.md) - -**See [CHANGELOG.md](/CHANGELOG.md) for details on changes to versions of Flint.** - -## Differences from the original flint framework - -For developers who are familiar with flint, there are also other difference to be aware of. This version of flint was designed with two themes in mind: -* Mimimize Webex API Calls. The original flint could be quite slow as it attempted to provide bot developers rich details about the space, membership, message and message author. This version eliminates some of that data in the interests of efficiency, (but provides convenience methods to get it when required) -* Leverage native Webex data types. The original flint would copy details from the webex objects such as message and person into various flint objects. This version simply attaches the native Webex objects. This increases flint's efficiency and makes it future proof as new attributes are added to the webex DTO - -For developer's who are porting existing flint based bots to this framework the following tables provide an overview of the changes to the key objects: - -### Bot Framework for Node JS - -## News - -**10/25/19 Support for Adaptive Cards:** - -* Cisco recently introduced support for [Adaptive Cards](https://developer.webex.com/docs/api/guides/cards/) in the Webex Teams. Bots can send cards, using the new `attachment` attribute of the message object. Cards are useful as an alternative to text messages and files in order to display or collect complex bits of information. Cards can be sent by passing an object to the bot.say() method that includes a valid attachment. To process user input to cards, apps must implement a `flint.on('attachmentaction', ..)` function. For more details see the [adaptive-card-example](./adaptive-card-example.md) - -**6/21/19 Deploying behind a firewall:** - -* Cisco has recently introduced support in the Webex Javascript SDK which allows applications to register to receive the message, membership, and room events via a socket instead of via wehbhoks. This allows applications to be deployed behind firewalls and removes the requirement that webex bots and integrations must expose a public IP address to receive events. To take advantage of this in your flint applications simply remove the `webhookUrl` field from the configuration object passed to the flint constructor. If this field is not set, flint will register to listen for these events instead of creating webhooks. - -**6/21/18 IMPORTANT:** +This project is inspired by, and provides an alternate implementation of, the awesome [node-flint](https://github.com/flint-bot/flint/) framework by [Nick Marus](https://github.com/nmarus). The framework makes it easy to quickly develop a Webex Teams bot, abstractig away some of the complexity of Webex For Developers interfaces, such as registering for events and calling REST APIs. A bot developer can use the framework to spark their imagination and focus primarily on how the bot will interact with users in Webex Teams. -* On August 31st, 2018 all bots with the sparkbot.io domain name will be - renamed with a webex.bot domain. Today in flint, the code compares the bot's - email with the trigger email to filter out messages from itself. If this code - is running on August 31st the bot will start responding to its own messages. - Please update to Flint v4.7.x as soon as possible to avoid interruption. - -**3/19/18 IMPORTANT:** +The primary change in this implementation is that it is based on the [webex-jssdk](https://webex.github.io/webex-js-sdk) which continues to be supported as new features and functionality are added to Webex. -* Note that Flint v4 is still using the node-sparky library version 3.x. - However the repo for node-sparky is now on version 4 which has some major - differences. This misalignment between Flint and Sparky version - will be fixed with the release of Flint v5. In the - short term if you are accessing the spark object directly from Flint via - `flint.spark` be sure to use the documentation for [node-sparky 3.x](https://github.com/flint-bot/sparky/tree/v3). +For developers who are familiar with flint, or who wish to port existing bots built on node-flint to the webex-node-bot-framework, this implementation is NOT backwards compatible. Please see [Differences from original flint framework](./docs/migrate-from-node-flint.md) -**See [CHANGELOG.md](/CHANGELOG.md) for details on changes to versions of Flint.** ## Contents @@ -71,60 +33,90 @@ For developer's who are porting existing flint based bots to this framework the ```bash mkdir myproj cd myproj -git clone https://github.com/nmarus/flint -npm install ./flint +git clone https://github.com/jpjpjp/webex-node-bot-framework +npm install ./webex-node-bot-framework ``` #### Via NPM ```bash mkdir myproj cd myproj -npm install node-flint +npm install webex-node-bot-framework ``` #### Example Template Using Express ```js -var Flint = require('node-flint'); -var webhook = require('node-flint/webhook'); +var Framework = require('webex-node-bot-framework'); +var webhook = require('webex-node-bot-framework/webhook'); + var express = require('express'); var bodyParser = require('body-parser'); var app = express(); app.use(bodyParser.json()); -// flint options +// framework options var config = { - webhookUrl: 'http://myserver.com/flint', + webhookUrl: 'http://myserver.com/framework', token: 'Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u', port: 80 }; -// init flint -var flint = new Flint(config); -flint.start(); +// init framework +var framework = new Framework(config); +framework.start(); +// An initialized event means your webhooks are all registered and the +// framework has created a bot object for all the spaces your bot is in +framework.on("initialized", function () { + framework.debug("Framework initialized successfully! [Press CTRL-C to quit]"); +}); + +// A spawn event is generated when the framework finds a space with your bot in it +framework.on('spawn', function (bot) { + if (!framework.initialized) { + // don't say anything here or your bot's spaces will get + // spammed every time your server is restarted + framework.debug(`While starting up framework found our bot in a space called: ${bot.room.title}`); + } else { + // After initialization, a spawn event means your bot got added to + // a new space. Say hello, and tell users what you do! + bot.say('Hi there, you can say hello to me. Don\'t forget you need to mention me in a group space!'); + } +}); + +var responded = false; // say hello -flint.hears('/hello', function(bot, trigger) { - bot.say('Hello %s!', trigger.personDisplayName); +framework.hears('hello', function(bot, trigger) { + bot.say('Hello %s!', trigger.person.displayName); + responded = true; +}); + +// Its a good practice to handle unexpected input +framework.hears(/.*/gim, function(bot, trigger) { + if (!responded) { + bot.say('Sorry, I don\'t know how to respond to "%s"', trigger.message.text); + } + responded = false; }); // define express path for incoming webhooks -app.post('/flint', webhook(flint)); +app.post('/framework', webhook(framework)); // start express server var server = app.listen(config.port, function () { - flint.debug('Flint listening on port %s', config.port); + framework.debug('Framework listening on port %s', config.port); }); // gracefully shutdown (ctrl-c) process.on('SIGINT', function() { - flint.debug('stoppping...'); + framework.debug('stoppping...'); server.close(); - flint.stop().then(function() { + framework.stop().then(function() { process.exit(); }); }); ``` -[**Restify Example**](https://github.com/nmarus/flint/blob/master/docs/example2.md) +[**Restify Example**](https://github.com/nmarus/framework/blob/master/docs/example2.md) ## Overview Most of Flint's functionality is based around the flint.hears function. This @@ -234,13 +226,13 @@ symbol and the word. With bot accounts, this behaves a bit differently. * If defining a flint.hears() using regex, the trigger.args array is the entire message. -# Flint Reference +# Framework Reference ## Classes
-
Flint
+
Framework
Bot
@@ -264,16 +256,16 @@ symbol and the word. With bot accounts, this behaves a bit differently.
"log"
-

Flint log event.

+

Framework log event.

"stop"
-

Flint stop event.

+

Framework stop event.

"start"
-

Flint start event.

+

Framework start event.

"initialized"
-

Flint initialized event.

+

Framework initialized event.

"roomLocked"

Room Locked event.

@@ -281,8 +273,8 @@ symbol and the word. With bot accounts, this behaves a bit differently.
"roomUnocked"

Room Unocked event.

-
"personEnters"
-

Person Enter Room event.

+
"userEnters"
+

User Enter Room event.

"botAddedAsModerator"

Bot Added as Room Moderator.

@@ -316,66 +308,66 @@ symbol and the word. With bot accounts, this behaves a bit differently.
- + -## Flint +## Framework **Kind**: global class **Properties** | Name | Type | Description | | --- | --- | --- | -| id | string | Flint UUID | -| active | boolean | Flint active state | -| initialized | boolean | Flint fully initialized | -| isBotAccount | boolean | Is Flint attached to Webex using a bot account? | -| isUserAccount | boolean | Is Flint attached to Webex using a user account? | -| person | object | Flint person object | -| email | string | Flint email | -| webex | object | The Webex JSSDK instance used by flint | - - -* [Flint](#Flint) - * [new Flint(options)](#new_Flint_new) - * [.options](#Flint+options) : object - * [.setWebexToken(token)](#Flint+setWebexToken) ⇒ Promise.<String> - * [.stop()](#Flint+stop) ⇒ Promise.<Boolean> - * [.start()](#Flint+start) ⇒ Promise.<Boolean> - * [.restart()](#Flint+restart) ⇒ Promise.<Boolean> - * [.getMessage(messageId)](#Flint+getMessage) ⇒ [Promise.<Message>](#Message) - * [.getFiles(messageId)](#Flint+getFiles) ⇒ Promise.<Array> - * [.getAttachmentAction(attachmentActionId)](#Flint+getAttachmentAction) ⇒ Promise.<AttachmentAction> - * [.hears(phrase, action, [helpText], [preference])](#Flint+hears) ⇒ String - * [.clearHears(id)](#Flint+clearHears) ⇒ null - * [.showHelp([header], [footer])](#Flint+showHelp) ⇒ String - * [.setAuthorizer(Action)](#Flint+setAuthorizer) ⇒ Boolean - * [.clearAuthorizer()](#Flint+clearAuthorizer) ⇒ null - * [.storageDriver(Driver)](#Flint+storageDriver) ⇒ null - * [.use(path)](#Flint+use) ⇒ Boolean - - - -### new Flint(options) -Creates an instance of Flint. +| id | string | Framework UUID | +| active | boolean | Framework active state | +| initialized | boolean | Framework fully initialized | +| isBotAccount | boolean | Is Framework attached to Webex using a bot account? | +| isUserAccount | boolean | Is Framework attached to Webex using a user account? | +| person | object | Framework person object | +| email | string | Framework email | +| webex | object | The Webex JSSDK instance used by Framework | + + +* [Framework](#Framework) + * [new Framework(options)](#new_Framework_new) + * [.options](#Framework+options) : object + * [.setWebexToken(token)](#Framework+setWebexToken) ⇒ Promise.<String> + * [.stop()](#Framework+stop) ⇒ Promise.<Boolean> + * [.start()](#Framework+start) ⇒ Promise.<Boolean> + * [.restart()](#Framework+restart) ⇒ Promise.<Boolean> + * [.getMessage(messageId)](#Framework+getMessage) ⇒ [Promise.<Message>](#Message) + * [.getFiles(messageId)](#Framework+getFiles) ⇒ Promise.<Array> + * [.getAttachmentAction(attachmentActionId)](#Framework+getAttachmentAction) ⇒ Promise.<AttachmentAction> + * [.hears(phrase, action, [helpText], [preference])](#Framework+hears) ⇒ String + * [.clearHears(id)](#Framework+clearHears) ⇒ null + * [.showHelp([header], [footer])](#Framework+showHelp) ⇒ String + * [.setAuthorizer(Action)](#Framework+setAuthorizer) ⇒ Boolean + * [.clearAuthorizer()](#Framework+clearAuthorizer) ⇒ null + * [.storageDriver(Driver)](#Framework+storageDriver) ⇒ null + * [.use(path)](#Framework+use) ⇒ Boolean + + + +### new Framework(options) +Creates an instance of the Framework. | Param | Type | Description | | --- | --- | --- | -| options | Object | Configuration object containing Flint settings. | +| options | Object | Configuration object containing Framework settings. | **Example** ```js var options = { - webhookUrl: 'http://myserver.com/flint', + webhookUrl: 'http://myserver.com/framework', token: 'Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u' }; -var flint = new Flint(options); +var framework = new Framework(options); ``` - + -### flint.options : object +### framework.options : object Options Object -**Kind**: instance namespace of [Flint](#Flint) +**Kind**: instance namespace of [Framework](#Framework) **Properties** | Name | Type | Default | Description | @@ -393,97 +385,97 @@ Options Object | [requestTimeout] | number | 20000 | Timeout for an individual request recieving a response. | | [queueSize] | number | 10000 | Size of the buffer that holds outbound requests. | | [requeueSize] | number | 10000 | Size of the buffer that holds outbound re-queue requests. | -| [id] | string | "random" | The id this instance of flint uses. | +| [id] | string | "random" | The id this instance of Framework uses. | | [webhookRequestJSONLocation] | string | "body" | The property under the Request to find the JSON contents. | | [removeWebhooksOnStart] | Boolean | true | If you wish to have the bot remove all account webhooks when starting. | - + -### flint.setWebexToken(token) ⇒ Promise.<String> +### framework.setWebexToken(token) ⇒ Promise.<String> Tests, and then sets a new Webex Token. -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) | Param | Type | Description | | --- | --- | --- | -| token | String | New Webex Token for Flint to use. | +| token | String | New Webex Token for Framework to use. | **Example** ```js -flint.setWebexToken('Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u') +framework.setWebexToken('Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u') .then(function(token) { console.log('token updated to: ' + token); }); ``` - + -### flint.stop() ⇒ Promise.<Boolean> -Stop Flint. +### framework.stop() ⇒ Promise.<Boolean> +Stop Framework. -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) **Example** ```js -flint.stop(); +framework.stop(); ``` - + -### flint.start() ⇒ Promise.<Boolean> -Start Flint. +### framework.start() ⇒ Promise.<Boolean> +Start Framework. -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) **Example** ```js -flint.start(); +framework.start(); ``` - + -### flint.restart() ⇒ Promise.<Boolean> -Restart Flint. +### framework.restart() ⇒ Promise.<Boolean> +Restart Framework. -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) **Example** ```js -flint.restart(); +framework.restart(); ``` - + -### flint.getMessage(messageId) ⇒ [Promise.<Message>](#Message) +### framework.getMessage(messageId) ⇒ [Promise.<Message>](#Message) Get Message Object by ID -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) | Param | Type | Description | | --- | --- | --- | | messageId | String | Message ID from Webex API. | - + -### flint.getFiles(messageId) ⇒ Promise.<Array> +### framework.getFiles(messageId) ⇒ Promise.<Array> Get Files from Message Object by ID -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) | Param | Type | Description | | --- | --- | --- | | messageId | String | Message ID from Webex API. | - + -### flint.getAttachmentAction(attachmentActionId) ⇒ Promise.<AttachmentAction> +### framework.getAttachmentAction(attachmentActionId) ⇒ Promise.<AttachmentAction> Get Attachement Action by ID -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) | Param | Type | Description | | --- | --- | --- | | attachmentActionId | String | attachmentActionID from Webex API. | - + -### flint.hears(phrase, action, [helpText], [preference]) ⇒ String +### framework.hears(phrase, action, [helpText], [preference]) ⇒ String Add action to be performed when bot hears a phrase. -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) | Param | Type | Default | Description | | --- | --- | --- | --- | @@ -495,23 +487,23 @@ Add action to be performed when bot hears a phrase. **Example** ```js // using a string to match first word and defines help text -flint.hears('/say', function(bot, trigger, id) { +framework.hears('/say', function(bot, trigger, id) { bot.say(trigger.args.slice(1, trigger.arges.length - 1)); }, '/say - Responds with a greeting'); ``` **Example** ```js // using regex to match across entire message -flint.hears(/(^| )beer( |.|$)/i, function(bot, trigger, id) { +framework.hears(/(^| )beer( |.|$)/i, function(bot, trigger, id) { bot.say('Enjoy a beer, %s! 🍻', trigger.personDisplayName); }); ``` - + -### flint.clearHears(id) ⇒ null -Remove a "flint.hears()" entry. +### framework.clearHears(id) ⇒ null +Remove a "framework.hears()" entry. -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) | Param | Type | Description | | --- | --- | --- | @@ -520,35 +512,35 @@ Remove a "flint.hears()" entry. **Example** ```js // using a string to match first word and defines help text -var hearsHello = flint.hears('/flint', function(bot, trigger, id) { +var hearsHello = framework.hears('/framework', function(bot, trigger, id) { bot.say('Hello %s!', trigger.personDisplayName); }); -flint.clearHears(hearsHello); +framework.clearHears(hearsHello); ``` - + -### flint.showHelp([header], [footer]) ⇒ String -Display help for registered Flint Commands. +### framework.showHelp([header], [footer]) ⇒ String +Display help for registered Framework Commands. -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) | Param | Type | Default | Description | | --- | --- | --- | --- | | [header] | String | Usage: | String to use in header before displaying help message. | -| [footer] | String | Powered by Flint - https://github.com/nmarus/flint | String to use in footer before displaying help message. | +| [footer] | String | Powered by Webex Node Bot Framework - https://github.com/jpjpjp/webex-node-bot-framework | String to use in footer before displaying help message. | **Example** ```js -flint.hears('/help', function(bot, trigger, id) { - bot.say(flint.showHelp()); +framework.hears('/help', function(bot, trigger, id) { + bot.say(framework.showHelp()); }); ``` - + -### flint.setAuthorizer(Action) ⇒ Boolean +### framework.setAuthorizer(Action) ⇒ Boolean Attaches authorizer function. -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) | Param | Type | Description | | --- | --- | --- | @@ -567,24 +559,24 @@ function myAuthorizer(bot, trigger, id) { return false; } } -flint.setAuthorizer(myAuthorizer); +framework.setAuthorizer(myAuthorizer); ``` - + -### flint.clearAuthorizer() ⇒ null +### framework.clearAuthorizer() ⇒ null Removes authorizer function. -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) **Example** ```js -flint.clearAuthorizer(); +framework.clearAuthorizer(); ``` - + -### flint.storageDriver(Driver) ⇒ null +### framework.storageDriver(Driver) ⇒ null Defines storage backend. -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) | Param | Type | Description | | --- | --- | --- | @@ -593,14 +585,14 @@ Defines storage backend. **Example** ```js // define memory store (default if not specified) -flint.storageDriver(new MemStore()); +framework.storageDriver(new MemStore()); ``` - + -### flint.use(path) ⇒ Boolean +### framework.use(path) ⇒ Boolean Load a Plugin from a external file. -**Kind**: instance method of [Flint](#Flint) +**Kind**: instance method of [Framework](#Framework) | Param | Type | Description | | --- | --- | --- | @@ -608,19 +600,19 @@ Load a Plugin from a external file. **Example** ```js -flint.use('events.js'); +framework.use('events.js'); ``` **Example** ```js // events.js -module.exports = function(flint) { - flint.on('spawn', function(bot) { +module.exports = function(framework) { + framework.on('spawn', function(bot) { console.log('new bot spawned in room: %s', bot.myroom.title); }); - flint.on('despawn', function(bot) { + framework.on('despawn', function(bot) { console.log('bot despawned in room: %s', bot.myroom.title); }); - flint.on('messageCreated', function(message, bot) { + framework.on('messageCreated', function(message, bot) { console.log('"%s" said "%s" in room "%s"', message.personEmail, message.text, bot.myroom.title); }); }; @@ -648,12 +640,12 @@ module.exports = function(flint) { * [Bot](#Bot) - * [new Bot(flint)](#new_Bot_new) + * [new Bot(framework, options, webex)](#new_Bot_new) * [.exit()](#Bot+exit) ⇒ Promise.<Boolean> * [.add(email(s), [moderator])](#Bot+add) ⇒ Promise.<Array> * [.remove(email(s))](#Bot+remove) ⇒ Promise.<Array> * [.getModerators()](#Bot+getModerators) ⇒ Promise.<Array> - * [.newRoom(name, emails)](#Bot+newRoom) ⇒ [Promise.<Bot>](#Bot) + * [.newRoom(name, emails, isTeam)](#Bot+newRoom) ⇒ [Promise.<Bot>](#Bot) * [.newTeamRoom(name, emails)](#Bot+newTeamRoom) ⇒ [Promise.<Bot>](#Bot) * [.moderateRoom()](#Bot+moderateRoom) ⇒ [Promise.<Bot>](#Bot) * [.unmoderateRoom()](#Bot+unmoderateRoom) ⇒ [Promise.<Bot>](#Bot) @@ -662,6 +654,7 @@ module.exports = function(flint) { * [.implode()](#Bot+implode) ⇒ Promise.<Boolean> * [.say([format], message)](#Bot+say) ⇒ [Promise.<Message>](#Message) * [.dm(email, [format], message)](#Bot+dm) ⇒ [Promise.<Message>](#Message) + * [.sendCard(cardJson, fallbackText)](#Bot+sendCard) ⇒ [Promise.<Message>](#Message) * [.uploadStream(filename, stream)](#Bot+uploadStream) ⇒ [Promise.<Message>](#Message) * [.messageStreamRoom(roomId, message)](#Bot+messageStreamRoom) ⇒ [Promise.<Message>](#Message) * [.upload(filepath)](#Bot+upload) ⇒ [Promise.<Message>](#Message) @@ -674,13 +667,15 @@ module.exports = function(flint) { -### new Bot(flint) -Creates a Bot instance that is then attached to a Spark Room. +### new Bot(framework, options, webex) +Creates a Bot instance that is then attached to a Webex Team Room. | Param | Type | Description | | --- | --- | --- | -| flint | Object | The flint object this Bot spawns under. | +| framework | Object | The framework object this Bot spawns under. | +| options | Object | The options of the framework object this Bot spawns under. | +| webex | Object | The webex sdk of the framework object this Bot spawns under. | @@ -761,7 +756,7 @@ bot.getModerators() ``` -### bot.newRoom(name, emails) ⇒ [Promise.<Bot>](#Bot) +### bot.newRoom(name, emails, isTeam) ⇒ [Promise.<Bot>](#Bot) Create new room with people by email **Kind**: instance method of [Bot](#Bot) @@ -770,12 +765,17 @@ Create new room with people by email | --- | --- | --- | | name | String | Name of room. | | emails | Array | Emails of people to add to room. | +| isTeam | Boolean | - Create a team room (if bot is already in a team space) | ### bot.newTeamRoom(name, emails) ⇒ [Promise.<Bot>](#Bot) Create new Team Room +This can also be done by passing an optional boolean +isTeam param to the newRoom() function, but this function +is also kept for compatibility with node-flint + **Kind**: instance method of [Bot](#Bot) | Param | Type | Description | @@ -786,7 +786,10 @@ Create new Team Room ### bot.moderateRoom() ⇒ [Promise.<Bot>](#Bot) -Enable Room Moderation.Enable. +Enable Room Moderation. + +This function will not work when framework was created +using a bot token, it requires an authorized user token **Kind**: instance method of [Bot](#Bot) **Example** @@ -801,6 +804,9 @@ bot.moderateRoom() ### bot.unmoderateRoom() ⇒ [Promise.<Bot>](#Bot) Disable Room Moderation. +This function will not work when framework was created +using a bot token, it requires an authorized user token + **Kind**: instance method of [Bot](#Bot) **Example** ```js @@ -814,6 +820,9 @@ bot.unmoderateRoom() ### bot.moderatorSet(email(s)) ⇒ [Promise.<Bot>](#Bot) Assign Moderator in Room +This function will not work when framework was created +using a bot token, it requires an authorized user token + **Kind**: instance method of [Bot](#Bot) | Param | Type | Description | @@ -832,6 +841,9 @@ bot.moderatorSet('john@test.com') ### bot.moderatorClear(email(s)) ⇒ [Promise.<Bot>](#Bot) Unassign Moderator in Room +This function will not work when framework was created +using a bot token, it requires an authorized user token + **Kind**: instance method of [Bot](#Bot) | Param | Type | Description | @@ -853,7 +865,7 @@ Remove a room and all memberships. **Kind**: instance method of [Bot](#Bot) **Example** ```js -flint.hears('/implode', function(bot, trigger) { +framework.hears('/implode', function(bot, trigger) { bot.implode(); }); ``` @@ -872,43 +884,57 @@ Send text with optional file to room. **Example** ```js // Simple example -flint.hears('/hello', function(bot, trigger) { +framework.hears('/hello', function(bot, trigger) { bot.say('hello'); }); ``` **Example** ```js // Simple example to send message and file -flint.hears('/file', function(bot, trigger) { +framework.hears('/file', function(bot, trigger) { bot.say({text: 'Here is your file!', file: 'http://myurl/file.doc'}); }); ``` **Example** ```js // Markdown Method 1 - Define markdown as default -flint.messageFormat = 'markdown'; -flint.hears('/hello', function(bot, trigger) { +framework.messageFormat = 'markdown'; +framework.hears('/hello', function(bot, trigger) { bot.say('**hello**, How are you today?'); }); ``` **Example** ```js // Markdown Method 2 - Define message format as part of argument string -flint.hears('/hello', function(bot, trigger) { +framework.hears('/hello', function(bot, trigger) { bot.say('markdown', '**hello**, How are you today?'); }); ``` **Example** ```js // Mardown Method 3 - Use an object (use this method of bot.say() when needing to send a file in the same message as markdown text. -flint.hears('/hello', function(bot, trigger) { - bot.say({markdown: '*Hello <@personEmail:' + trigger.personEmail + '|' + trigger.personDisplayName + '>*'}); +framework.hears('/hello', function(bot, trigger) { + bot.say(); }); ``` +**Example** +```js +// Send an Webex card by providing a fully formed message object. +framework.hears('/card please', function(bot, trigger) { + bot.say({ + // Fallback text for clients that don't render cards is required + markdown: "If you see this message your client cannot render buttons and cards.", + attachments: [{ + "contentType": "application/vnd.microsoft.card.adaptive", + "content": myCardsSchema + }] + }); +``` ### bot.dm(email, [format], message) ⇒ [Promise.<Message>](#Message) -Send text with optional file in a direct message. This sends a message to a 1:1 room with the user (creates 1:1, if one does not already exist) +Send text with optional file in a direct message. +This sends a message to a 1:1 room with the user (creates 1:1, if one does not already exist) **Kind**: instance method of [Bot](#Bot) @@ -921,39 +947,99 @@ Send text with optional file in a direct message. This sends a message to a 1:1 **Example** ```js // Simple example -flint.hears('/dm', function(bot, trigger) { +framework.hears('/dm', function(bot, trigger) { bot.dm('someone@domain.com', 'hello'); }); ``` **Example** ```js // Simple example to send message and file -flint.hears('/dm', function(bot, trigger) { +framework.hears('/dm', function(bot, trigger) { bot.dm('someone@domain.com', {text: 'Here is your file!', file: 'http://myurl/file.doc'}); }); ``` **Example** ```js // Markdown Method 1 - Define markdown as default -flint.messageFormat = 'markdown'; -flint.hears('/dm', function(bot, trigger) { +framework.messageFormat = 'markdown'; +framework.hears('/dm', function(bot, trigger) { bot.dm('someone@domain.com', '**hello**, How are you today?'); }); ``` **Example** ```js // Markdown Method 2 - Define message format as part of argument string -flint.hears('/dm', function(bot, trigger) { +framework.hears('/dm', function(bot, trigger) { bot.dm('someone@domain.com', 'markdown', '**hello**, How are you today?'); }); ``` **Example** ```js // Mardown Method 3 - Use an object (use this method of bot.dm() when needing to send a file in the same message as markdown text. -flint.hears('/dm', function(bot, trigger) { +framework.hears('/dm', function(bot, trigger) { bot.dm('someone@domain.com', {markdown: '*Hello <@personEmail:' + trigger.personEmail + '|' + trigger.personDisplayName + '>*'}); }); ``` + + +### bot.sendCard(cardJson, fallbackText) ⇒ [Promise.<Message>](#Message) +Send a Webex Teams Card to room. + +**Kind**: instance method of [Bot](#Bot) + +| Param | Type | Description | +| --- | --- | --- | +| cardJson | Object | The card JSON to render. This can come from the Webex Buttons and Cards Designer. | +| fallbackText | String | Message to be displayed on client's that can't render cards. | + +**Example** +```js +// Simple example +framework.hears('card please', function(bot, trigger) { + bot.SendCard( + { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.0", + "body": [ + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "width": 2, + "items": [ + { + "type": "TextBlock", + "text": "Card Sample", + "weight": "Bolder", + "size": "Medium" + }, + { + "type": "TextBlock", + "text": "What is your name?", + "wrap": true + }, + { + "type": "Input.Text", + "id": "myName", + "placeholder": "John Doe" + } + ] + } + ] + } + ], + "actions": [ + { + "type": "Action.Submit", + "title": "Submit" + } + ] + }, + "This is the fallback text if the client can't render this card"); + }); +``` ### bot.uploadStream(filename, stream) ⇒ [Promise.<Message>](#Message) @@ -968,7 +1054,7 @@ Upload a file to a room using a Readable Stream **Example** ```js -flint.hears('/file', function(bot, trigger) { +framework.hears('/file', function(bot, trigger) { // define filename used when uploading to room var filename = 'test.png'; @@ -988,7 +1074,7 @@ Streams message to a room. | Param | Type | Description | | --- | --- | --- | -| roomId | String | Spark Room ID | +| roomId | String | Webex Teams Room ID | | message | Object | Message Object | **Example** @@ -1019,7 +1105,7 @@ Upload a file to room. **Example** ```js -flint.hears('/file', function(bot, trigger) { +framework.hears('/file', function(bot, trigger) { bot.upload('test.png'); }); ``` @@ -1057,11 +1143,14 @@ bot.roomRename('My Renamed Room') ### bot.getMessages(count) ⇒ Promise.<Array> Get messages from room. Returned data has newest message at bottom. +This function will not work when framework was created +using a bot token, it requires an authorized user token + **Kind**: instance method of [Bot](#Bot) -| Param | Type | -| --- | --- | -| count | Integer | +| Param | Type | Description | +| --- | --- | --- | +| count | Integer | - count of messages to return (max 10) | **Example** ```js @@ -1174,7 +1263,7 @@ Trigger Object ## "log" -Flint log event. +Framework log event. **Kind**: event emitted **Properties** @@ -1186,38 +1275,38 @@ Flint log event. ## "stop" -Flint stop event. +Framework stop event. **Kind**: event emitted **Properties** | Name | Type | Description | | --- | --- | --- | -| id | string | Flint UUID | +| id | string | Framework UUID | ## "start" -Flint start event. +Framework start event. **Kind**: event emitted **Properties** | Name | Type | Description | | --- | --- | --- | -| id | string | Flint UUID | +| id | string | Framework UUID | ## "initialized" -Flint initialized event. +Framework initialized event. **Kind**: event emitted **Properties** | Name | Type | Description | | --- | --- | --- | -| id | string | Flint UUID | +| id | string | Framework UUID | @@ -1230,7 +1319,7 @@ Room Locked event. | Name | Type | Description | | --- | --- | --- | | bot | object | Bot Object | -| id | string | Flint UUID | +| id | string | Framework UUID | @@ -1243,12 +1332,12 @@ Room Unocked event. | Name | Type | Description | | --- | --- | --- | | bot | object | Bot Object | -| id | string | Flint UUID | +| id | string | Framework UUID | - + -## "personEnters" -Person Enter Room event. +## "userEnters" +User Enter Room event. **Kind**: event emitted **Properties** @@ -1256,8 +1345,8 @@ Person Enter Room event. | Name | Type | Description | | --- | --- | --- | | bot | object | Bot Object | -| person | object | Person Object | -| id | string | Flint UUID | +| membership | object | Membership Object | +| id | string | Framework UUID | @@ -1270,7 +1359,7 @@ Bot Added as Room Moderator. | Name | Type | Description | | --- | --- | --- | | bot | object | Bot Object | -| id | string | Flint UUID | +| id | string | Framework UUID | @@ -1283,7 +1372,7 @@ Bot Removed as Room Moderator. | Name | Type | Description | | --- | --- | --- | | bot | object | Bot Object | -| id | string | Flint UUID | +| id | string | Framework UUID | @@ -1297,7 +1386,7 @@ Person Added as Moderator. | --- | --- | --- | | bot | object | Bot Object | | person | object | Person Object | -| id | string | Flint UUID | +| id | string | Framework UUID | @@ -1311,7 +1400,7 @@ Person Removed as Moderator. | --- | --- | --- | | bot | object | Bot Object | | person | object | Person Object | -| id | string | Flint UUID | +| id | string | Framework UUID | @@ -1324,8 +1413,8 @@ Person Exits Room. | Name | Type | Description | | --- | --- | --- | | bot | object | Bot Object | -| person | object | Person Object | -| id | string | Flint UUID | +| membership | object | Membership Object | +| id | string | Framework UUID | @@ -1339,7 +1428,7 @@ Bot Mentioned. | --- | --- | --- | | bot | object | Bot Object | | trigger | object | Trigger Object | -| id | string | Flint UUID | +| id | string | Framework UUID | @@ -1353,7 +1442,7 @@ Message Recieved. | --- | --- | --- | | bot | object | Bot Object | | trigger | object | Trigger Object | -| id | string | Flint UUID | +| id | string | Framework UUID | @@ -1367,7 +1456,7 @@ File Recieved. | --- | --- | --- | | bot | object | Bot Object | | trigger | trigger | Trigger Object | -| id | string | Flint UUID | +| id | string | Framework UUID | @@ -1380,7 +1469,7 @@ Bot Spawned. | Name | Type | Description | | --- | --- | --- | | bot | object | Bot Object | -| id | string | Flint UUID | +| id | string | Framework UUID | @@ -1393,7 +1482,7 @@ Bot Despawned. | Name | Type | Description | | --- | --- | --- | | bot | object | Bot Object | -| id | string | Flint UUID | +| id | string | Framework UUID | ## License diff --git a/docs/adaptive-card-example.md b/docs/adaptive-card-example.md index 9adbff3..3d5c61b 100644 --- a/docs/adaptive-card-example.md +++ b/docs/adaptive-card-example.md @@ -1,31 +1,31 @@ #### Adaptive Card Template Using Express ```js -var Flint = require('node-flint'); -var webhook = require('node-flint/webhook'); +var Framework = require('webex-node-bot-framework'); +var webhook = require('webex-node-bot-framework/webhook'); var express = require('express'); var bodyParser = require('body-parser'); var app = express(); app.use(bodyParser.json()); -// flint options +// framework options var config = { - webhookUrl: 'http://myserver.com/flint', + webhookUrl: 'http://myserver.com/framework', token: 'Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u', port: 80 }; -// init flint -var flint = new Flint(config); -flint.start(); +// init framework +var framework = new Framework(config); +framework.start(); -flint.on("initialized", async function () { - flint.debug("Flint initialized successfully! [Press CTRL-C to quit]"); +framework.on("initialized", async function () { + framework.debug("Framework initialized successfully! [Press CTRL-C to quit]"); }); // send an example card in response to any input -flint.hears(/.*/, function(bot) { +framework.hears(/.*/, function(bot) { bot.say({ // Fallback text for clients that don't render cards markdown: "[Tell us about yourself](https://www.example.com/form/book-vacation). We just need a few more details to get you booked for the trip of a lifetime!", @@ -34,23 +34,23 @@ flint.hears(/.*/, function(bot) { }); // Process a submitted card -flint.on('attachmentAction', function (bot, attachmentAction) { - bot.say(`Got an attachmentAction:\n${JSON.stringify(attachmentAction, null, 2)}`); +framework.on('attachmentAction', function (bot, trigger) { + bot.say(`Got an attachmentAction:\n${JSON.stringify(trigger.attachmentAction, null, 2)}`); }); // define express path for incoming webhooks -app.post('/', webhook(flint)); +app.post('/', webhook(framework)); // start express server var server = app.listen(config.port, function () { - flint.debug('Flint listening on port %s', config.port); + framework.debug('Framework listening on port %s', config.port); }); // gracefully shutdown (ctrl-c) process.on('SIGINT', function() { - flint.debug('stoppping...'); + framework.debug('stoppping...'); server.close(); - flint.stop().then(function() { + framework.stop().then(function() { process.exit(); }); }); diff --git a/docs/build.sh b/docs/build.sh index 304574a..738404d 100755 --- a/docs/build.sh +++ b/docs/build.sh @@ -11,8 +11,8 @@ cat overview.md >> ${README} ${DOCTOC} --github --notitle --maxlevel 4 ${README} -echo -e "\n# Flint Reference\n\n" >> ${README} +echo -e "\n# Framework Reference\n\n" >> ${README} -${JSDOC} ../lib/flint.js ../lib/bot.js >> ${README} +${JSDOC} ../lib/framework.js ../lib/bot.js >> ${README} cat license.md >> ${README} diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..cd2170d --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,56 @@ +## Contributing + +#### Build + +## Rebuilding Docs + +The `build.sh` script in this folder generates the README.md for the project. +This build script requires that you have installed the dev dependencies of this project. + +To build the docs: +```bash +npm i --only=dev +npm run build +``` +(note: the dependencies only need to be installed once) + +#### Test + +Before submitting a pull request, please validate that all tests work and are augmented as necessary, to test your new functionality. It is reccomended that you familiarize yourself with the tests BEFORE beginning any feature related work. + +The tests require the following environment variables which will be read in from a .env file if one is available. +| Variable| Value | Purpose | +| --------------- | -------------- | ------------------------------ | +|BOT_API_TOKEN | Token of a bot created on [Webex For Developers](https://developer.webex.com/my-apps/new/bot)| Identity of bot to test framework with. There is no need to have any actual bot code associated with this token, in fact its probably better if there isnt.| +|USER_API_TOKEN | Token of a user that the test bot will interact with. This can be grabbed from [Webex For Developers](https://developer.webex.com/docs/api/getting-started/accounts-and-authentication)| This user will create rooms with the bot, (and vice versa) and exchange messages with it. Rooms will be deleted at the end of the test.| +|HOSTED_FILE | URL for a file to upload in some of the message tests.| Any file suppported by Webex Teams will do, perhaps the one here: https://www.webex.com/content/dam/wbx/us/images/hp/hp_56565/Teams_Iconx2.png| +|DEBUG | framework| Optionally set DEBUG=framework for extended debug output during the test run.| + +When the environment is set, run the tests: +```bash +npm i --only=dev +npm run test +``` +(note: the dependencies only need to be installed once) + +The test suite includes direct message tests. These will run ONLY if an existing one-one space exists between the test bot and test user. To run these tests, manually create this 1-1 space. + +It is also possible to run the tests by instantiating the framework with an authorized user token (as an integration would do). At this time the framework is not optimized for use as an integration, however the tests are provided as a convenience. These tests are similar but the user does not at-mention the bot. + +To run the user tests set the following environment variables: +| Variable| Value | Purpose | +| --------------- | -------------- | ------------------------------ | +|AUTHORIZED_FLINT_USER_API_TOKEN | Token of a user. This can be extracted from the developer portal or obtained by via an OAuth flow with an integration.| Identity of a non bot user to test framework with. There is no need to have any actual integration code associated with this token, in fact its probably better if there isnt.| +|USER_API_TOKEN | Token of a user that the test bot will interact with. This can be grabbed from [Webex For Developers](https://developer.webex.com/docs/api/getting-started/accounts-and-authentication)| This user will create rooms with the bot, (and vice versa) and exchange messages with it. Rooms will be deleted at the end of the test. **Make sure this is a different user from the AUTHORIZED_FLINT_USER**| +|HOSTED_FILE | URL for a file to upload in some of the message tests.| Any file suppported by Webex Teams will do, perhaps the one here: https://www.webex.com/content/dam/wbx/us/images/hp/hp_56565/Teams_Iconx2.png| + +When the environment is set, run the tests: +```bash +npm i --only=dev +npm run test-as-user +``` + + +# Support this Project + +Find this project useful? Help suppport the continued development by submitting issues, feature requests, or code. diff --git a/docs/example1.md b/docs/example1.md index 144b99f..3ea6a0f 100644 --- a/docs/example1.md +++ b/docs/example1.md @@ -1,44 +1,74 @@ #### Example Template Using Express ```js -var Flint = require('node-flint'); -var webhook = require('node-flint/webhook'); +var Framework = require('webex-node-bot-framework'); +var webhook = require('webex-node-bot-framework/webhook'); + var express = require('express'); var bodyParser = require('body-parser'); var app = express(); app.use(bodyParser.json()); -// flint options +// framework options var config = { - webhookUrl: 'http://myserver.com/flint', + webhookUrl: 'http://myserver.com/framework', token: 'Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u', port: 80 }; -// init flint -var flint = new Flint(config); -flint.start(); +// init framework +var framework = new Framework(config); +framework.start(); + +// An initialized event means your webhooks are all registered and the +// framework has created a bot object for all the spaces your bot is in +framework.on("initialized", function () { + framework.debug("Framework initialized successfully! [Press CTRL-C to quit]"); +}); +// A spawn event is generated when the framework finds a space with your bot in it +framework.on('spawn', function (bot) { + if (!framework.initialized) { + // don't say anything here or your bot's spaces will get + // spammed every time your server is restarted + framework.debug(`While starting up framework found our bot in a space called: ${bot.room.title}`); + } else { + // After initialization, a spawn event means your bot got added to + // a new space. Say hello, and tell users what you do! + bot.say('Hi there, you can say hello to me. Don\'t forget you need to mention me in a group space!'); + } +}); + +var responded = false; // say hello -flint.hears('/hello', function(bot, trigger) { - bot.say('Hello %s!', trigger.personDisplayName); +framework.hears('hello', function(bot, trigger) { + bot.say('Hello %s!', trigger.person.displayName); + responded = true; +}); + +// Its a good practice to handle unexpected input +framework.hears(/.*/gim, function(bot, trigger) { + if (!responded) { + bot.say('Sorry, I don\'t know how to respond to "%s"', trigger.message.text); + } + responded = false; }); // define express path for incoming webhooks -app.post('/flint', webhook(flint)); +app.post('/framework', webhook(framework)); // start express server var server = app.listen(config.port, function () { - flint.debug('Flint listening on port %s', config.port); + framework.debug('Framework listening on port %s', config.port); }); // gracefully shutdown (ctrl-c) process.on('SIGINT', function() { - flint.debug('stoppping...'); + framework.debug('stoppping...'); server.close(); - flint.stop().then(function() { + framework.stop().then(function() { process.exit(); }); }); ``` -[**Restify Example**](https://github.com/nmarus/flint/blob/master/docs/example2.md) +[**Restify Example**](https://github.com/nmarus/framework/blob/master/docs/example2.md) diff --git a/docs/example2.md b/docs/example2.md index 1a91b7f..9593380 100644 --- a/docs/example2.md +++ b/docs/example2.md @@ -1,40 +1,40 @@ ## Example #2 Using Restify ```js -var Flint = require('node-flint'); -var webhook = require('node-flint/webhook'); +var Framework = require('webex-node-bot-framework'); +var webhook = require('webex-node-bot-framework/webhook'); var Restify = require('restify'); var server = Restify.createServer(); server.use(Restify.bodyParser()); -// flint options +// framework options var config = { - webhookUrl: 'http://myserver.com/flint', + webhookUrl: 'http://myserver.com/framework', token: 'Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u', port: 80 }; -// init flint -var flint = new Flint(config); -flint.start(); +// init framework +var framework = new Framework(config); +framework.start(); // say hello -flint.hears('/hello', function(bot, trigger) { - bot.say('Hello %s!', trigger.personDisplayName); +framework.hears('/hello', function(bot, trigger) { + bot.say('Hello %s!', trigger.person.displayName); }); // define restify path for incoming webhooks -server.post('/flint', webhook(flint)); +server.post('/framework', webhook(framework)); // start restify server server.listen(config.port, function () { - flint.debug('Flint listening on port %s', config.port); + framework.debug('Framework listening on port %s', config.port); }); // gracefully shutdown (ctrl-c) process.on('SIGINT', function() { - flint.debug('stoppping...'); + framework.debug('stoppping...'); server.close(); - flint.stop().then(function() { + framework.stop().then(function() { process.exit(); }); }); diff --git a/docs/example3.md b/docs/example3.md index 4ccfad4..47dd09c 100644 --- a/docs/example3.md +++ b/docs/example3.md @@ -1,24 +1,24 @@ ## Example #3 Using Socket2me (experimental and under development) -An inbound, internet reachable port, is required for the Spark API to notify -Flint of webhook events. This is not always easy or possible. +An inbound, internet reachable port, is required for the Webex API to notify +Framework of webhook events. This is not always easy or possible. -Flint utilize a remote socket client through a +Framework utilize a remote socket client through a [socket2me](https://github.com/nmarus/socket2me) server in the event you want to stand up a bot where forwarding a port is not possible. -The remote socket2me server allows you to run Flint behind a NAT without adding +The remote socket2me server allows you to run Framework behind a NAT without adding a port forward configuration to your firewall. To make use of a socket2me server, you can either stand up your own socket2me server or make use of a public/shared socket2me server. A single socket2me server can support many clients/bots simultaneously. ```js -var Flint = require('node-flint'); -var webhook = require('node-flint/webhook'); +var Framework = require('webex-node-bot-framework'); +var webhook = require('webex-node-bot-framework/webhook'); var Socket2meClient = require('socket2me-client'); var server = new Socket2meClient('https://socket.bothub.io'); -// flint options +// framework options var config = { token: 'Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u' }; @@ -27,16 +27,16 @@ var config = { server.on('connected', function(webhookUrl) { config.webhookUrl = webhookUrl; - var flint = new Flint(config); - flint.start(); + var framework = new Framework(config); + framework.start(); // say hello - flint.hears('/hello', function(bot, trigger) { - bot.say('Hello %s!', trigger.personDisplayName); + framework.hears('/hello', function(bot, trigger) { + bot.say('Hello %s!', trigger.person.displayName); }); server.requestHandler(function(request, respond) { - webhook(flint)(request); + webhook(framework)(request); respond(200, 'OK'); }); }); diff --git a/docs/header.md b/docs/header.md index 35380bf..94cebbb 100644 --- a/docs/header.md +++ b/docs/header.md @@ -1,53 +1,15 @@ -# webex-flint +# webex-node-bot-framework ### Webex Teams Bot Framework for Node JS -This project is inspired by, and provides an alternate implementation of, the awesome [node-flint](https://github.com/flint-bot/flint/) framework by [Nick Marus](https://github.com/nmarus). The flint framework makes it easy to quickly develop a Webex Teams bot, abstractig away some of the complexity of Webex For Developers interfaces, such as registering for events and calling REST APIs. A bot developer can use the flint framework to spark their imagination and focus primarily on how the bot will interact with users in Webex Teams. +**Warning** - *This project is still in its initial development, so use at your own risk. For details on areas that may still require attention before the poejcet is fully complete please see the* [To Do List](./docs/ToDo.MD) -The primary change in this implementation is that it is based on the [webex-jssdk](https://webex.github.io/webex-js-sdk) which continues to be supported as new features and functionality are added to Webex. - -For developers who are familiar with flint, or who wish to port existing bots built on node-flint to the webex-flint framework, this implementation is NOT backwards compatible. Please see [Differences from original flint framework](./docs/migrate-from-node-flint.md) - -**See [CHANGELOG.md](/CHANGELOG.md) for details on changes to versions of Flint.** - -## Differences from the original flint framework - -For developers who are familiar with flint, there are also other difference to be aware of. This version of flint was designed with two themes in mind: -* Mimimize Webex API Calls. The original flint could be quite slow as it attempted to provide bot developers rich details about the space, membership, message and message author. This version eliminates some of that data in the interests of efficiency, (but provides convenience methods to get it when required) -* Leverage native Webex data types. The original flint would copy details from the webex objects such as message and person into various flint objects. This version simply attaches the native Webex objects. This increases flint's efficiency and makes it future proof as new attributes are added to the webex DTO - -For developer's who are porting existing flint based bots to this framework the following tables provide an overview of the changes to the key objects: - -### Bot Framework for Node JS - -## News +This project is inspired by, and provides an alternate implementation of, the awesome [node-flint](https://github.com/flint-bot/flint/) framework by [Nick Marus](https://github.com/nmarus). The framework makes it easy to quickly develop a Webex Teams bot, abstractig away some of the complexity of Webex For Developers interfaces, such as registering for events and calling REST APIs. A bot developer can use the framework to spark their imagination and focus primarily on how the bot will interact with users in Webex Teams. -**10/25/19 Support for Adaptive Cards:** - -* Cisco recently introduced support for [Adaptive Cards](https://developer.webex.com/docs/api/guides/cards/) in the Webex Teams. Bots can send cards, using the new `attachment` attribute of the message object. Cards are useful as an alternative to text messages and files in order to display or collect complex bits of information. Cards can be sent by passing an object to the bot.say() method that includes a valid attachment. To process user input to cards, apps must implement a `flint.on('attachmentaction', ..)` function. For more details see the [adaptive-card-example](./adaptive-card-example.md) - -**6/21/19 Deploying behind a firewall:** - -* Cisco has recently introduced support in the Webex Javascript SDK which allows applications to register to receive the message, membership, and room events via a socket instead of via wehbhoks. This allows applications to be deployed behind firewalls and removes the requirement that webex bots and integrations must expose a public IP address to receive events. To take advantage of this in your flint applications simply remove the `webhookUrl` field from the configuration object passed to the flint constructor. If this field is not set, flint will register to listen for these events instead of creating webhooks. - -**6/21/18 IMPORTANT:** - -* On August 31st, 2018 all bots with the sparkbot.io domain name will be - renamed with a webex.bot domain. Today in flint, the code compares the bot's - email with the trigger email to filter out messages from itself. If this code - is running on August 31st the bot will start responding to its own messages. - Please update to Flint v4.7.x as soon as possible to avoid interruption. - -**3/19/18 IMPORTANT:** +The primary change in this implementation is that it is based on the [webex-jssdk](https://webex.github.io/webex-js-sdk) which continues to be supported as new features and functionality are added to Webex. -* Note that Flint v4 is still using the node-sparky library version 3.x. - However the repo for node-sparky is now on version 4 which has some major - differences. This misalignment between Flint and Sparky version - will be fixed with the release of Flint v5. In the - short term if you are accessing the spark object directly from Flint via - `flint.spark` be sure to use the documentation for [node-sparky 3.x](https://github.com/flint-bot/sparky/tree/v3). +For developers who are familiar with flint, or who wish to port existing bots built on node-flint to the webex-node-bot-framework, this implementation is NOT backwards compatible. Please see [Differences from original flint framework](./docs/migrate-from-node-flint.md) -**See [CHANGELOG.md](/CHANGELOG.md) for details on changes to versions of Flint.** ## Contents diff --git a/docs/installation.md b/docs/installation.md index 61adf37..4e6faff 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -4,13 +4,13 @@ ```bash mkdir myproj cd myproj -git clone https://github.com/nmarus/flint -npm install ./flint +git clone https://github.com/jpjpjp/webex-node-bot-framework +npm install ./webex-node-bot-framework ``` #### Via NPM ```bash mkdir myproj cd myproj -npm install node-flint +npm install webex-node-bot-framework ``` diff --git a/docs/migrate-from-node-flint.md b/docs/migrate-from-node-flint.md index 1132f33..c44e974 100644 --- a/docs/migrate-from-node-flint.md +++ b/docs/migrate-from-node-flint.md @@ -1,27 +1,59 @@ # Differences from the original flint framework -The primary reason for creating the webex-flint framework was to create a framework based on the [webex-jssdk](https://webex.github.io/webex-js-sdk) which continues to be supported as new features and functionality are added to Webex. This version of flint was designed with two themes in mind: +The primary reason for creating the webex-node-bot-framework was to create a framework based on the [webex-jssdk](https://webex.github.io/webex-js-sdk) which continues to be supported as new features and functionality are added to Webex. This version of the proejct was designed with two themes in mind: * Mimimize Webex API Calls. The original flint could be quite slow as it attempted to provide bot developers rich details about the space, membership, message and message author. This version eliminates some of that data in the interests of efficiency, (but provides convenience methods to enable bot developers to get this information if it is required) -* Leverage native Webex data types. The original flint would copy details from the webex objects such as message and person into various flint objects. This version simply attaches the native Webex objects. This increases flint's efficiency and makes it future proof as new attributes are added to the various webex DTOs +* Leverage native Webex data types. The original flint would copy details from the webex objects such as message and person into various flint objects. This version simply attaches the native Webex objects. This increases the framework's efficiency and makes it future proof as new attributes are added to the various webex DTOs + +It's also worth noting that the `flint` object from node-flint has been renamed simply to `framework`. For developers porting to from node-flint, it may be simpler to modify code that looks like this: + +```javascript +var Flint = require('node-flint'); +var webhook = require('node-flint/webhook'); +// flint options +var config = { + webhookUrl: 'http://myserver.com/framework', + token: 'Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u', + port: 80 +}; +var flint = new Flint(config); +``` + +To look something like this: + +```javascript +var Framework = require('webex-node-bot-framework'); +var webhook = require('webex-node-bot-framework/webhook'); +// framework options +var config = { + webhookUrl: 'http://myserver.com/framework', + token: 'Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u', + port: 80 +}; +var flint = new Framework(config); +``` +Naming the new Framework object `flint`, allows existing `flint.hears()` and `flint.on()` functions to behave as the currently do. + +With that said, please review the other changes outlined in this document to determine if any flint handler function logic needs to be updated. + ## Core Object Changes For developer's who are porting existing flint based bots to this framework the following tables provide an overview of the changes to the key objects (note that all dates are strings, not moment objects as they were in node-flint): -## Flint +## Framework (Formerly Flint) **Kind**: global class **Properties** -| Orig Flint Name | New Flint Name | Description | Reason For Change | +| Orig Flint Name | New Framework Name | Description | Reason For Change | | --------------- | -------------- | ------------------------------ | ------------------------------------ | -| id | id | Flint UUID | | -| active | active | Flint active state | | -| intialized | initialized | Flint fully initialized | | -| isBotAccount | isBotAccount | Is Flint using a bot account? | | -| isUserAccount | isUserAccount | Is Flint using a user account? | | -| person | person | Flint person object | Now is unchanged webex person object | -| email | email | Flint email | No longer set to all lower case | -| spark | webex | Flint SDK | now based on webex jsssdk | +| id | id | Framework UUID | | +| active | active | Framework active state | | +| intialized | initialized | Framework fully initialized | | +| isBotAccount | isBotAccount | Is Framework using a bot account? | | +| isUserAccount | isUserAccount | Is Framework using a user account? | | +| person | person | Framework person object | Now is unchanged webex person object | +| email | email | Framework email | No longer set to all lower case | +| spark | webex | Framework SDK | now based on webex jsssdk | ## Bot **Kind**: global class @@ -30,9 +62,10 @@ For developer's who are porting existing flint based bots to this framework the | Orig Bot Name | New Bot Name | Description | Reason For Change | | ------------- | ------------ | -------------------------------------------- | -------------------------------------------------------------| | id | id | Bot UUID | | +| flint | framework | Framework object | Name change | | active | active | Bot active state | | -| person | -- | Bot Person Object | Availabile in flint object | -| email | -- | Bot email | Availabile in flint object | +| person | -- | Bot Person Object | Availabile as bot.framework.person | +| email | -- | Bot email | Availabile as bot.framework.person.emails[0] | | team | -- | Bot team object | available via bot.getTeam() convenience function TODO | | room | room | Bot room object | Now is standard webex room object | | membership | membership | Bot membership object | Standard Webex Teams membership object for bot | @@ -82,7 +115,7 @@ Trigger Object | personMembership | -- | Person Membership object for person | use bot.getTriggerMembership() | ## Event changes -Node-flint generated a set of `person` events based on membership changes. For each membership, the framework would fetch the person object associated with that memebership pass it to the event handler. Since many bots don't even register these handers this seems expensive. Information like the personEmail and personDisplayName are also already included in the membership DTO. Finally, bots that truly wish to get the person object can always query it directly via the `flint.getPerson(membership.personId)` function. +Node-flint generated a set of `person` events based on membership changes. For each membership, the framework would fetch the person object associated with that memebership pass it to the event handler. Since many bots don't even register these handers this seems expensive. Information like the personEmail and personDisplayName are also already included in the membership DTO. Finally, bots that truly wish to get the person object can always query it directly via the `framework.getPerson(membership.personId)` function. Our framework instead generates a set of related `member` named events and passes the membership associated with the change to event handler. This makes the framework snappier and the events seem more aptly named (since the membership change may be associated with another bot as well as a person). @@ -92,31 +125,28 @@ Witht this in mind the following node-flint events are now renamed as follows: * `personAddedAsModerator` -> `memberAddedAsModerator` * `personRemovedAsModerator` -> `memberRemovedAsModerator` -The payload passed to the event handlers will be a bot, the membership object, and the bot or flint id. Therefore an app that implemented something like: +The payload passed to the event handlers will be a bot, the *membership object* (not a person object), and the bot or framework id. Therefore an app that implemented something like: ```javascript -flint.on('personEnters', function (bot, person) { - bot.sy(`Welcome ${person.displayName}!`); +framework.on('personEnters', function (bot, person) { + bot.say(`Welcome ${person.displayName}!`); }); ``` Would need to be modified to handle the `memberAdded` event with a memebership object instead, ie: ```javascript -flint.on('memberAdded', function (bot, membership) { - bot.sy(`Welcome ${membership.personDisplayName}!`); +framework.on('memberAdded', function (bot, membership) { + bot.say(`Welcome ${membership.personDisplayName}!`); }); ``` -For every message node-flint generates a set of messages which may include +For every message node-flint generates a set of events which may include * `messageCreated` * `mentioned` * `message` * `files` -Our new framework will ONLY generate the `messageCreated` event in instances when the message was sent by the bot. In almost all cases bots and applications don't want to respond to their own messages, however those that choose to do so should build the logic for processing them in a `flint.on("messageCreated", message, flintId)` handler since the other events are no longer sent. If any other space member posts a message the `message` event will always fire and the `mentioned` event will fire if the message mentioned the bot, and a `files` event will fire if the message includes file attachments. +Our new framework will ONLY generate the `messageCreated` event in instances when the message was sent by the bot. In almost all cases bots and applications don't want to respond to their own messages, however those that choose to do so should build the logic for processing them in a `flint.on("messageCreated", message, flintId)` handler since the other events are no longer sent. If any other space member posts a message, the `message` event will always fire and the `mentioned` event will fire if the message mentioned the bot, and a `files` event will fire if the message includes file attachments. -* bot.memberships -* trigger -* Messages from the bot are ignored earlier in the process. Even if the bot mentions itself in a message this message will be ignored. diff --git a/docs/todo.md b/docs/todo.md new file mode 100644 index 0000000..c407d65 --- /dev/null +++ b/docs/todo.md @@ -0,0 +1,55 @@ +# Webex-node-bot-framework TO-DO + +While this project is inspired by the awesome [node-flint](https://github.com/flint-bot/flint/) framework by [Nick Marus](https://github.com/nmarus), there are aspects of that project that have not been tested yet. + +Contributions to make this fully formed are welcome please see the [Contribution Guide](./contributing.md) + +## Basic functionality +The initial goal of the project was to support the basic framework initiation and support the .hears() and basic bot funtionality. This work is primarily complete but the following functions need more testing and validation + +- [ ] Add tests for the Teams functions +- [ ] Remove code that prevents bots from making moderator status changes +- [ ] Add tests for moderator functions using integration token +- [ ] Add tests for bot.getMessages using integration token +- [x] Add tests for bot.dm (only if test bot and user already have a 1-1 space) +- [ ] Add tests for bot.uploadStream, bot.messageStreamRoom, bot.upload +- [ ] Add tests for bot.censor +- [ ] Add tests for bot.roomRename +- [ ] Expand tests for bot.newRoom to exercise an array of users to be added, and with the moderator flag on +- [ ] Add convenience functions promised in the migration readme + +## Documentation + +- [ ] Ensure all the samples work +- [ ] Update the core readme to discuss how the framework starts up +- [ ] Update the core readme to discuss websockets vs. webhooks + +## Modifications to the framework + +- [x] Rename from flint to framework +- [ ] Get rid fo flint pass through functions that are natively supported by the webex sdk +- [x] Update contribution doc to explain how to run tests +- [ ] Build a webex-node-integration-framework around this framework that demonstrates OAuth token management and creates a unique framework instance for each authorized user + +## New functions +A goal of this project was to extend the framework to support new functionality that becomes avaialble on Webex + +- [x] Add bot.sayCard() +- [ ] Add bot.reply + +## Storage +node-flint provides a storage system to allow developers to store and retrieve data associated with individual bot/space combinations. This framework has not modified that code, but has also not tested it to see if it has broken. + +- [ ] Add storage tests +- [ ] Add mongo storage + +## Migrating from node-flint +- [x] Add a chart in the readme that shows the difference in the bot and trigger structures +- [ ] figure out how to format dates with 3 msecs + +## Improving the tests + +- [ ] Add a ability to create a bot and user on the fly for the tests +- [ ] Refactor the tests so the framework.isBotAccount variable is used to determine if mentions are needed in the user messages +- [x] Break out the tests so they aren't in one monolithic file but don't create a new framework each time +- [ ] Track and report the number of times each flint event was tested, to catch gaps in event validation diff --git a/index.js b/index.js index e01170a..7d11991 100644 --- a/index.js +++ b/index.js @@ -1 +1 @@ -module.exports = require('./lib/flint'); +module.exports = require('./lib/framework'); diff --git a/lib/bot.js b/lib/bot.js index 6847fb0..3d472a3 100644 --- a/lib/bot.js +++ b/lib/bot.js @@ -40,9 +40,9 @@ function htmlFormat(str) { * Creates a Bot instance that is then attached to a Webex Team Room. * * @constructor - * @param {Object} flint - The flint object this Bot spawns under. - * @param {Object} options - The options of the flint object this Bot spawns under. - * @param {Object} webex - The webex sdk of the flint object this Bot spawns under. + * @param {Object} framework - The framework object this Bot spawns under. + * @param {Object} options - The options of the framework object this Bot spawns under. + * @param {Object} webex - The webex sdk of the framework object this Bot spawns under. * @property {string} id - Bot UUID * @property {boolean} active - Bot active state * @property {object} person - Bot's Webex Person Object @@ -56,20 +56,20 @@ function htmlFormat(str) { * @property {string} isDirectTo - Recipient Email if bot is in 1:1/Direct Room * @property {date} lastActivity - Last bot activity */ -function Bot(flint) { +function Bot(framework) { EventEmitter.call(this); this.id = u.genUUID64(); - this.flint = flint; - this.options = flint.options; - this.webex = flint.webex; + this.framework = framework; + this.options = framework.options; + this.webex = framework.webex; this.debug = function (message) { message = util.format.apply(null, Array.prototype.slice.call(arguments)); - if (typeof flint.debugger === 'function') { - flint.debugger(message, this.id); + if (typeof framework.debugger === 'function') { + framework.debugger(message, this.id); } else { _debug(message); } @@ -77,16 +77,16 @@ function Bot(flint) { // Does anything bad happen if we never audit? //randomize distribution of when audit event should take place for this bot instance... - //this.auditTrigger = Math.floor((Math.random() * this.flint.auditDelay)) + 1; + //this.auditTrigger = Math.floor((Math.random() * this.framework.auditDelay)) + 1; - this.batchDelay = this.flint.batchDelay; + this.batchDelay = this.framework.batchDelay; this.active = false; this.room = {}; this.team = {}; - this.person = this.flint.person; + this.person = this.framework.person; this.membership = {}; this.memberships = []; - this.email = this.flint.email; + this.email = this.framework.email; this.isLocked = false; this.isModerator = false; this.isGroup = false; @@ -165,7 +165,7 @@ Bot.prototype.exit = function () { return when(false); } else { - return this.flint.webex.memberships.remove(this.membership) + return this.framework.webex.memberships.remove(this.membership) .then(() => { return when(true); }) @@ -205,13 +205,13 @@ Bot.prototype.add = function (email, asModerator) { // function to add membership by email address to this room var add = (e, m) => { if (validator.isEmail(e)) { - return this.flint.webex.memberships.create({ + return this.framework.webex.memberships.create({ roomId: this.room.id, personEmail: e, isModerator: m }) .then(membership => { - this.flint.debug('Added "%s" to room "%s"', + this.framework.debug('Added "%s" to room "%s"', (membership.personDisplayName) ? membership.personDisplayName : membership.personEmail, this.room.title); return when(e); @@ -304,11 +304,11 @@ Bot.prototype.remove = function (email) { // remove membership by email address from this room var remove = e => { // if (validator.isEmail(e) && _.includes(_.map(this.memberships, 'personEmail'), e)) { - // return this.flint.webex.memberships.list({ roomId: this.room.id, personEmail: e }) - return this.flint.webex.memberships.list({ roomId: this.room.id, personEmail: email }) + // return this.framework.webex.memberships.list({ roomId: this.room.id, personEmail: e }) + return this.framework.webex.memberships.list({ roomId: this.room.id, personEmail: email }) .then((memberships) => { let membership = memberships.items[0]; - return this.flint.webex.memberships.remove(membership); + return this.framework.webex.memberships.remove(membership); }) .then(() => { this.debug('Removed "%s" from room "%s"', e, this.room.title); @@ -453,7 +453,7 @@ Bot.prototype.newRoom = function (name, emails, isTeam) { // add room var newRoom = { title: name }; if (teamId) { newRoom.team = teamId; } - return this.flint.webex.rooms.create(newRoom) + return this.framework.webex.rooms.create(newRoom) // create room .then(room => { @@ -463,7 +463,7 @@ Bot.prototype.newRoom = function (name, emails, isTeam) { // find bot function var bot = () => { // get bot for new room - return _.find(this.flint.bots, bot => { + return _.find(this.framework.bots, bot => { return (bot.room.id === room.id); }); }; @@ -485,7 +485,7 @@ Bot.prototype.newRoom = function (name, emails, isTeam) { return poll(bot, 100, isReady) .then(bot => { if (!bot) { - return when.reject(new Error('Flint timed out when creating a new room')); + return when.reject(new Error('Framework timed out when creating a new room')); } else { newRoomBot = bot; newRoom = room; @@ -513,7 +513,7 @@ Bot.prototype.newRoom = function (name, emails, isTeam) { .catch(err => { if (newRoom && newRoom.id) { - this.flint.webex.rooms.remove(newRoom) + this.framework.webex.rooms.remove(newRoom) .catch(() => {/* ignore remove room errors */ }); } @@ -544,7 +544,7 @@ Bot.prototype.newTeamRoom = function (name, emails) { /** * Enable Room Moderation. * - * This function will not work when flint was created + * This function will not work when framework was created * using a bot token, it requires an authorized user token * * @function @@ -557,8 +557,8 @@ Bot.prototype.newTeamRoom = function (name, emails) { * }); */ Bot.prototype.moderateRoom = function () { - // validate flint is not a bot account - if (this.flint.isBotAccount) { + // validate framework is not a bot account + if (this.framework.isBotAccount) { return when.reject(new Error('Bot accounts can not change moderation status in rooms')); } @@ -575,7 +575,7 @@ Bot.prototype.moderateRoom = function () { var membership = this.membership; if (!membership.isModerator) { membership.isModerator = true; - return this.flint.webex.memberships.update(membership) + return this.framework.webex.memberships.update(membership) .then(() => when(this)); } else { return when(this); @@ -587,7 +587,7 @@ Bot.prototype.moderateRoom = function () { /** * Disable Room Moderation. * - * This function will not work when flint was created + * This function will not work when framework was created * using a bot token, it requires an authorized user token * * @function @@ -601,8 +601,8 @@ Bot.prototype.moderateRoom = function () { */ Bot.prototype.unmoderateRoom = function () { - // validate flint is not a bot account - if (this.flint.isBotAccount) { + // validate framework is not a bot account + if (this.framework.isBotAccount) { return when.reject(new Error('Bot accounts can not change moderator status in rooms')); } @@ -615,7 +615,7 @@ Bot.prototype.unmoderateRoom = function () { } else if (this.isLocked && !this.isModerator) { - return when.reject(new Error('Flint is not a moderator in this room')); + return when.reject(new Error('Bot is not a moderator in this room')); } else { @@ -641,7 +641,7 @@ Bot.prototype.unmoderateRoom = function () { /** * Assign Moderator in Room * - * This function will not work when flint was created + * This function will not work when framework was created * using a bot token, it requires an authorized user token * * @function @@ -662,7 +662,7 @@ Bot.prototype.moderatorSet = function (email) { .then(membership => { if (!membership.isModerator) { membership.isModerator = true; - return this.flint.webex.memberships.update(membership) + return this.framework.webex.memberships.update(membership) .then(() => when(this)); } else { return when(this); @@ -671,7 +671,7 @@ Bot.prototype.moderatorSet = function (email) { }; // validate bot is not a bot account - if (this.flint.isBotAccount) { + if (this.framework.isBotAccount) { return when.reject(new Error('Bot accounts can not change moderator status in rooms')); } @@ -684,7 +684,7 @@ Bot.prototype.moderatorSet = function (email) { } else if (this.isLocked && !this.isModerator) { - return when.reject(new Error('Flint is not moderator in this room')); + return when.reject(new Error('Bot is not moderator in this room')); } else { @@ -713,7 +713,7 @@ Bot.prototype.moderatorSet = function (email) { /** * Unassign Moderator in Room * - * This function will not work when flint was created + * This function will not work when framework was created * using a bot token, it requires an authorized user token * * @function @@ -734,7 +734,7 @@ Bot.prototype.moderatorClear = function (email) { .then(membership => { if (membership.isModerator) { membership.isModerator = false; - return this.flint.webex.memberships.update(membership) + return this.framework.webex.memberships.update(membership) .then(() => when(this)); } else { return when(this); @@ -743,7 +743,7 @@ Bot.prototype.moderatorClear = function (email) { }; // validate bot is not a bot account - if (this.flint.isBotAccount) { + if (this.framework.isBotAccount) { return when.reject(new Error('Bot accounts can not change moderator status in rooms')); } @@ -756,7 +756,7 @@ Bot.prototype.moderatorClear = function (email) { } else if (this.isLocked && !this.isModerator) { - return when.reject(new Error('Flint is not a moderator in this room')); + return when.reject(new Error('Bot is not a moderator in this room')); } else { @@ -789,7 +789,7 @@ Bot.prototype.moderatorClear = function (email) { * @returns {Promise.} * * @example - * flint.hears('/implode', function(bot, trigger) { + * framework.hears('/implode', function(bot, trigger) { * bot.implode(); * }); */ @@ -802,10 +802,10 @@ Bot.prototype.implode = function () { // validate bot is moderator if room is locked if (this.isLocked && !this.isModerator) { - return when.reject(new Error('Flint is not moderator in this room')); + return when.reject(new Error('Bot is not moderator in this room')); } - return this.flint.webex.rooms.remove(this.room) + return this.framework.webex.rooms.remove(this.room) .then(() => when(true)) .catch(() => when(false)); }; @@ -820,38 +820,38 @@ Bot.prototype.implode = function () { * * @example * // Simple example - * flint.hears('/hello', function(bot, trigger) { + * framework.hears('/hello', function(bot, trigger) { * bot.say('hello'); * }); * * @example * // Simple example to send message and file - * flint.hears('/file', function(bot, trigger) { + * framework.hears('/file', function(bot, trigger) { * bot.say({text: 'Here is your file!', file: 'http://myurl/file.doc'}); * }); * * @example * // Markdown Method 1 - Define markdown as default - * flint.messageFormat = 'markdown'; - * flint.hears('/hello', function(bot, trigger) { + * framework.messageFormat = 'markdown'; + * framework.hears('/hello', function(bot, trigger) { * bot.say('**hello**, How are you today?'); * }); * * @example * // Markdown Method 2 - Define message format as part of argument string - * flint.hears('/hello', function(bot, trigger) { + * framework.hears('/hello', function(bot, trigger) { * bot.say('markdown', '**hello**, How are you today?'); * }); * * @example * // Mardown Method 3 - Use an object (use this method of bot.say() when needing to send a file in the same message as markdown text. - * flint.hears('/hello', function(bot, trigger) { + * framework.hears('/hello', function(bot, trigger) { * bot.say(); * }); * * @example * // Send an Webex card by providing a fully formed message object. - * flint.hears('/card please', function(bot, trigger) { + * framework.hears('/card please', function(bot, trigger) { * bot.say({ * // Fallback text for clients that don't render cards is required * markdown: "If you see this message your client cannot render buttons and cards.", @@ -864,7 +864,7 @@ Bot.prototype.implode = function () { Bot.prototype.say = function (format, message) { // set default format type - format = this.flint.messageFormat; + format = this.framework.messageFormat; // parse function args var args = Array.prototype.slice.call(arguments); @@ -883,7 +883,7 @@ Bot.prototype.say = function (format, message) { if (typeof args[0] === 'object') { let message = args[0]; message.roomId = this.room.id; - return this.flint.webex.messages.create(message); + return this.framework.webex.messages.create(message); } // if message is string @@ -903,7 +903,7 @@ Bot.prototype.say = function (format, message) { // send constructed message object to room messageObj.roomId = this.room.id; - return this.flint.webex.messages.create(messageObj); + return this.framework.webex.messages.create(messageObj); } else { @@ -924,33 +924,33 @@ Bot.prototype.say = function (format, message) { * * @example * // Simple example - * flint.hears('/dm', function(bot, trigger) { + * framework.hears('/dm', function(bot, trigger) { * bot.dm('someone@domain.com', 'hello'); * }); * * @example * // Simple example to send message and file - * flint.hears('/dm', function(bot, trigger) { + * framework.hears('/dm', function(bot, trigger) { * bot.dm('someone@domain.com', {text: 'Here is your file!', file: 'http://myurl/file.doc'}); * }); * * @example * // Markdown Method 1 - Define markdown as default - * flint.messageFormat = 'markdown'; - * flint.hears('/dm', function(bot, trigger) { + * framework.messageFormat = 'markdown'; + * framework.hears('/dm', function(bot, trigger) { * bot.dm('someone@domain.com', '**hello**, How are you today?'); * }); * * @example * // Markdown Method 2 - Define message format as part of argument string - * flint.hears('/dm', function(bot, trigger) { + * framework.hears('/dm', function(bot, trigger) { * bot.dm('someone@domain.com', 'markdown', '**hello**, How are you today?'); * }); * * @example * // Mardown Method 3 - Use an object (use this method of bot.dm() when needing to send a file in the same message as markdown text. - * flint.hears('/dm', function(bot, trigger) { - * bot.dm('someone@domain.com', {markdown: '*Hello <@personEmail:' + trigger.personEmail + '|' + trigger.personDisplayName + '>*'}); + * framework.hears('/dm', function(bot, trigger) { + * bot.dm('someone@domain.com', {markdown: '*Hello <@personEmail:' + trigger.personEmail + '|' + trigger.person.displayName + '>*'}); * }); */ Bot.prototype.dm = function (email, format, message) { @@ -959,13 +959,13 @@ Bot.prototype.dm = function (email, format, message) { message = args.length > 0 ? args.pop() : false; email = args.length > 0 ? args.shift() : false; - format = args.length > 0 && _.includes(['markdown', 'html', 'text'], format) ? args.shift() : this.flint.messageFormat || 'text'; + format = args.length > 0 && _.includes(['markdown', 'html', 'text'], format) ? args.shift() : this.framework.messageFormat || 'text'; if (email && validator.isEmail(email) && (typeof message === 'string' || typeof message === 'object')) { if (typeof message === 'object') { message.toPersonEmail = email; - return this.flint.webex.messages.create(message); + return this.framework.webex.messages.create(message); } if (typeof message === 'string') { @@ -979,7 +979,7 @@ Bot.prototype.dm = function (email, format, message) { msgObj[format] = message; msgObj.toPersonEmail = email; - return this.flint.webex.messages.create(msgObj); + return this.framework.webex.messages.create(msgObj); } } @@ -998,7 +998,7 @@ Bot.prototype.dm = function (email, format, message) { * * @example * // Simple example - * flint.hears('card please', function(bot, trigger) { + * framework.hears('card please', function(bot, trigger) { * bot.SendCard( * { * "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", @@ -1054,7 +1054,7 @@ Bot.prototype.sendCard = function (cardJson, fallbackText) { } // use the default format type for the fallback text - var format = this.flint.messageFormat; + var format = this.framework.messageFormat; // construct message object with attachments var messageObj = {}; @@ -1066,7 +1066,7 @@ Bot.prototype.sendCard = function (cardJson, fallbackText) { // send constructed message object to room messageObj.roomId = this.room.id; - return this.flint.webex.messages.create(messageObj); + return this.framework.webex.messages.create(messageObj); }; @@ -1080,7 +1080,7 @@ Bot.prototype.sendCard = function (cardJson, fallbackText) { * @returns {Promise.} * * @example - * flint.hears('/file', function(bot, trigger) { + * framework.hears('/file', function(bot, trigger) { * * // define filename used when uploading to room * var filename = 'test.png'; @@ -1129,7 +1129,7 @@ Bot.prototype.messageStreamRoom = function (roomId, message) { var requestOptions = { method: 'post', url: this.apiUrl + 'messages', - headers: { 'Authorization': 'Bearer ' + this.flint.options.token }, + headers: { 'Authorization': 'Bearer ' + this.framework.options.token }, formData: { 'roomId': roomId } }; @@ -1201,7 +1201,7 @@ Bot.prototype.messageStreamRoom = function (roomId, message) { * @returns {Promise.} * * @example - * flint.hears('/file', function(bot, trigger) { + * framework.hears('/file', function(bot, trigger) { * bot.upload('test.png'); * }); */ @@ -1223,12 +1223,12 @@ Bot.prototype.upload = function (filepath) { * @returns {Promise.} */ Bot.prototype.censor = function (messageId) { - return this.flint.webex.messages.get(messageId) + return this.framework.webex.messages.get(messageId) .then(message => { // if bot can delete a message... - if ((this.isLocked && this.isModerator && !this.flint.isBotAccount) || message.personId === this.person.id) { - return this.flint.webex.messages.remove(messageId); + if ((this.isLocked && this.isModerator && !this.framework.isBotAccount) || message.personId === this.person.id) { + return this.framework.webex.messages.remove(messageId); } else { return when.reject(new Error('Can not remove this message')); @@ -1254,13 +1254,13 @@ Bot.prototype.roomRename = function (title) { return when.reject(new Error('Can not set title of 1:1 room')); } else if (this.isLocked && !this.isModerator) { - return when.reject(new Error('Flint is not moderator in this room')); + return when.reject(new Error('Bot is not moderator in this room')); } else { if (this.room.title != title) { let room = this.room; room.title = title; - return this.flint.webex.rooms.update(room) + return this.framework.webex.rooms.update(room) .then((r) => { this.room = r; return when(this); @@ -1274,7 +1274,7 @@ Bot.prototype.roomRename = function (title) { /** * Get messages from room. Returned data has newest message at bottom. * - * This function will not work when flint was created + * This function will not work when framework was created * using a bot token, it requires an authorized user token * * @function @@ -1292,12 +1292,12 @@ Bot.prototype.roomRename = function (title) { * }); */ Bot.prototype.getMessages = function (count) { - if (this.flint.isBotAccount) { + if (this.framework.isBotAccount) { return when.reject(new Error('Bot accounts can not read room messages')); } else { count = typeof count !== 'number' && parseInt(count, 10) ? parseInt(count, 10) : count; - return this.flint.webex.messages.list({ roomId: this.room.id, max: count }) - .then(messages => when.map(_.reverse(messages), message => this.flint.parseMessage(message))); + return this.framework.webex.messages.list({ roomId: this.room.id, max: count }) + .then(messages => when.map(_.reverse(messages), message => this.framework.parseMessage(message))); } }; diff --git a/lib/flint.js b/lib/framework.js similarity index 87% rename from lib/flint.js rename to lib/framework.js index 6036d87..d779a9e 100644 --- a/lib/flint.js +++ b/lib/framework.js @@ -5,7 +5,7 @@ EventEmitter.prototype._maxListeners = 0; var sequence = require('when/sequence'); var moment = require('moment'); var Webex = require('webex'); -var _debug = require('debug')('flint'); +var _debug = require('debug')('framework'); var util = require('util'); var when = require('when'); var path = require('path'); @@ -17,27 +17,27 @@ var Bot = require('./bot'); var u = require('./utils'); /** - * Creates an instance of Flint. - * - * @constructor Flint - * @param {Object} options - Configuration object containing Flint settings. - * @property {string} id - Flint UUID - * @property {boolean} active - Flint active state - * @property {boolean} initialized - Flint fully initialized - * @property {boolean} isBotAccount - Is Flint attached to Webex using a bot account? - * @property {boolean} isUserAccount - Is Flint attached to Webex using a user account? - * @property {object} person - Flint person object - * @property {string} email - Flint email - * @property {object} webex - The Webex JSSDK instance used by flint + * Creates an instance of the Framework. + * + * @constructor Framework + * @param {Object} options - Configuration object containing Framework settings. + * @property {string} id - Framework UUID + * @property {boolean} active - Framework active state + * @property {boolean} initialized - Framework fully initialized + * @property {boolean} isBotAccount - Is Framework attached to Webex using a bot account? + * @property {boolean} isUserAccount - Is Framework attached to Webex using a user account? + * @property {object} person - Framework person object + * @property {string} email - Framework email + * @property {object} webex - The Webex JSSDK instance used by Framework * * @example * var options = { - * webhookUrl: 'http://myserver.com/flint', + * webhookUrl: 'http://myserver.com/framework', * token: 'Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u' * }; - * var flint = new Flint(options); + * var framework = new Framework(options); */ -function Flint(options) { +function Framework(options) { EventEmitter.call(this); this.id = options.id || u.genUUID64(); @@ -45,7 +45,7 @@ function Flint(options) { /** * Options Object * - * @memberof Flint + * @memberof Framework * @instance * @namespace options * @property {string} token - Webex Token. @@ -61,7 +61,7 @@ function Flint(options) { * @property {number} [requestTimeout=20000] - Timeout for an individual request recieving a response. * @property {number} [queueSize=10000] - Size of the buffer that holds outbound requests. * @property {number} [requeueSize=10000] - Size of the buffer that holds outbound re-queue requests. - * @property {string} [id=random] - The id this instance of flint uses. + * @property {string} [id=random] - The id this instance of Framework uses. * @property {string} [webhookRequestJSONLocation=body] - The property under the Request to find the JSON contents. * @property {Boolean} [removeWebhooksOnStart=true] - If you wish to have the bot remove all account webhooks when starting. */ @@ -79,7 +79,7 @@ function Flint(options) { // note: this is typically 'request.body' but depending on express/restify configuration, it may be 'request.params' this.options.webhookRequestJSONLocation = this.options.webhookRequestJSONLocation || 'body'; - // define if flint remove all webhooks attached to token on start (if not defined, defaults to true) + // define if Framework remove all webhooks attached to token on start (if not defined, defaults to true) this.options.removeWebhooksOnStart = typeof this.options.removeWebhooksOnStart === 'boolean' ? this.options.removeWebhooksOnStart : true; // define default messageFormat used with bot.say (if not defined, defaults to 'text') @@ -112,18 +112,18 @@ function Flint(options) { this.initialize(); }); } -util.inherits(Flint, EventEmitter); +util.inherits(Framework, EventEmitter); /** * Internal logger function. * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} message - Message to log * @returns {string} Formatted message */ -Flint.prototype.log = function (message) { +Framework.prototype.log = function (message) { if (this.log.length > this.logMax) { this.log = this.log.slice(this.log.length - this.logMax); } @@ -131,7 +131,7 @@ Flint.prototype.log = function (message) { this.logs.push(message); /** - * Flint log event. + * Framework log event. * * @event log * @property {string} message - Log Message @@ -144,12 +144,12 @@ Flint.prototype.log = function (message) { * Internal debug function. * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} message - Message to debug * @returns {null} */ -Flint.prototype.debug = function (message) { +Framework.prototype.debug = function (message) { message = util.format.apply(null, Array.prototype.slice.call(arguments)); if (typeof this.debugger === 'function') { @@ -163,17 +163,17 @@ Flint.prototype.debug = function (message) { * Tests, and then sets a new Webex Token. * * @function - * @memberof Flint - * @param {String} token - New Webex Token for Flint to use. + * @memberof Framework + * @param {String} token - New Webex Token for Framework to use. * @returns {Promise.} * * @example - * flint.setWebexToken('Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u') + * framework.setWebexToken('Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u') * .then(function(token) { * console.log('token updated to: ' + token); * }); */ -Flint.prototype.setWebexToken = function (token) { +Framework.prototype.setWebexToken = function (token) { return this.testWebexToken(token) .then(token => { this.options.token = token; @@ -188,13 +188,13 @@ Flint.prototype.setWebexToken = function (token) { * Test a new Webex Token. * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} token - Test if Token is valid by attempting a simple Webex API Call. * @returns {Promise.} * * @example - * flint.testWebexToken('Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u') + * framework.testWebexToken('Tm90aGluZyB0byBzZWUgaGVyZS4uLiBNb3ZlIGFsb25nLi4u') * .then(function() { * console.log('token valid'); * }) @@ -202,7 +202,7 @@ Flint.prototype.setWebexToken = function (token) { * console.log(err.message); * }); */ -Flint.prototype.testWebexToken = function (token) { +Framework.prototype.testWebexToken = function (token) { var testOptions = _.clone(this.options); testOptions.token = token; var testWebex = new Webex(testOptions); @@ -218,16 +218,16 @@ Flint.prototype.testWebexToken = function (token) { }; /** - * Stop Flint. + * Stop Framework. * * @function - * @memberof Flint + * @memberof Framework * @returns {Promise.} * * @example - * flint.stop(); + * framework.stop(); */ -Flint.prototype.stop = function () { +Framework.prototype.stop = function () { // if not stopped... if (this.active) { @@ -250,10 +250,10 @@ Flint.prototype.stop = function () { this.active = false; this.initialized = false; /** - * Flint stop event. + * Framework stop event. * * @event stop - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('stop', this.id); @@ -266,16 +266,16 @@ Flint.prototype.stop = function () { }; /** - * Start Flint. + * Start Framework. * * @function - * @memberof Flint + * @memberof Framework * @returns {Promise.} * * @example - * flint.start(); + * framework.start(); */ -Flint.prototype.start = function () { +Framework.prototype.start = function () { // if not started... if (!this.active) { @@ -383,10 +383,10 @@ Flint.prototype.start = function () { // start .then(() => { /** - * Flint start event. + * Framework start event. * * @event start - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('start', this.id); this.active = true; @@ -412,17 +412,17 @@ Flint.prototype.start = function () { }; /** - * Initialize Flint. + * Initialize Framework. * * @function - * @memberof Flint + * @memberof Framework * @private * @returns {Promise.} * * @example - * flint.initialize(); + * framework.initialize(); */ -Flint.prototype.initialize = function () { +Framework.prototype.initialize = function () { // spawn bots in existing rooms at startup return this.webex.memberships.list() .then(memberships => { @@ -443,10 +443,10 @@ Flint.prototype.initialize = function () { .then(() => { /** - * Flint initialized event. + * Framework initialized event. * * @event initialized - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('initialized', this.id); this.initialized = true; @@ -456,16 +456,16 @@ Flint.prototype.initialize = function () { }; /** - * Restart Flint. + * Restart Framework. * * @function - * @memberof Flint + * @memberof Framework * @returns {Promise.} * * @example - * flint.restart(); + * framework.restart(); */ -Flint.prototype.restart = function () { +Framework.prototype.restart = function () { return this.stop() .then(stopped => { if (stopped) { @@ -480,16 +480,16 @@ Flint.prototype.restart = function () { * Audit bot objects to verify they are in sync with the Webex API. * * @function - * @memberof Flint + * @memberof Framework * @private * @returns {Promise.} * * @example - * flint.auditBots(); + * framework.auditBots(); */ // TODO this seems expensive, do we need to do it -Flint.prototype.auditBots = function () { - // only run if Flint has initialized +Framework.prototype.auditBots = function () { + // only run if Framework has initialized if (!this.initialized) { return when(true); } @@ -502,7 +502,7 @@ Flint.prototype.auditBots = function () { this.auditCounter = 0; } - // update flint.person + // update framework.person if (this.auditCounter === 0) { this.getPerson(this.person.id) .then(person => { @@ -593,12 +593,12 @@ Flint.prototype.auditBots = function () { * Take a native webex message object and add additional info about the sender to it * * @function - * @memberof Flint + * @memberof Framework * @private * @param {Object} message - Message Object * @returns {Promise.} */ -Flint.prototype.parseMessage = function (message) { +Framework.prototype.parseMessage = function (message) { /** * Message Object @@ -662,12 +662,12 @@ Flint.prototype.parseMessage = function (message) { * Parse a File from Message. * * @function - * @memberof Flint + * @memberof Framework * @private * @param {Object} message - Previously parsed Message Object * @returns {Promise.} */ -Flint.prototype.parseFile = function (message) { +Framework.prototype.parseFile = function (message) { /** * File Object @@ -688,7 +688,7 @@ Flint.prototype.parseFile = function (message) { */ //TODO figure out how/if Webex SDK handles this - when.reject(new Error('flint.ParseFile not yet supported')); + when.reject(new Error('framework.ParseFile not yet supported')); // // parse message files // if (message.files && message.files instanceof Array) { @@ -719,13 +719,13 @@ Flint.prototype.parseFile = function (message) { * Creates Trigger Object from a message or attachmentAction * * @function - * @memberof Flint + * @memberof Framework * @private * @param {Object} message - Enhanced message object (with additional sender info) // * @param {Webhook} messageData - Webhook object from message created webhook * @returns {Promise.} */ -Flint.prototype.getTrigger = function (type, triggerObject) { +Framework.prototype.getTrigger = function (type, triggerObject) { /** * Trigger Object @@ -779,13 +779,13 @@ Flint.prototype.getTrigger = function (type, triggerObject) { // * Creates Trigger Object from an attachmentAction. // * // * @function -// * @memberof Flint +// * @memberof Framework // * @private // * @param {Object} attachmentAction - Enhanced message object (with additional sender info) // * @returns {Promise.} // */ -// Flint.prototype.getTrigger = function (attachmentAction) { -// //Flint.prototype.getTrigger = function (messageId) { +// Framework.prototype.getTrigger = function (attachmentAction) { +// //Framework.prototype.getTrigger = function (messageId) { // /** // * Trigger Object @@ -912,11 +912,11 @@ Flint.prototype.getTrigger = function (type, triggerObject) { * Get Rooms * * @function - * @memberof Flint + * @memberof Framework * @private * @returns {Promise.} */ -Flint.prototype.getRooms = function () { +Framework.prototype.getRooms = function () { return this.webex.rooms.list() .then(rooms => when(rooms.items)); // Not convinced this is necessary @@ -934,12 +934,12 @@ Flint.prototype.getRooms = function () { * Get Room Object By ID * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} roomId - Room ID from Webex API. * @returns {Promise.} */ -Flint.prototype.getRoom = function (roomId) { +Framework.prototype.getRoom = function (roomId) { return this.webex.rooms.get(roomId) .then(room => when(room)); // Not convinced this is necessary @@ -956,11 +956,11 @@ Flint.prototype.getRoom = function (roomId) { * Get Teams * * @function - * @memberof Flint + * @memberof Framework * @private * @returns {Promise.} */ -Flint.prototype.getTeams = function () { +Framework.prototype.getTeams = function () { return this.webex.teams.list() .then(teams => when(teams.items)); // Not convinced this is necessary @@ -976,12 +976,12 @@ Flint.prototype.getTeams = function () { * Get Team Object By ID * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} teamId - Team ID from Webex API. * @returns {Promise.} */ -Flint.prototype.getTeam = function (teamId) { +Framework.prototype.getTeam = function (teamId) { return this.webex.teams.get(teamId) .then(team => when(team)); // Not convinced this is necessary @@ -995,12 +995,12 @@ Flint.prototype.getTeam = function (teamId) { * Get Team Rooms * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} teamId - Room ID from webex API * @returns {Promise.} */ -Flint.prototype.getTeamRooms = function (teamId) { +Framework.prototype.getTeamRooms = function (teamId) { return this.webex.rooms.list({ teamId: teamId }) .then(rooms => when(rooms.items)); // Not convinced this is necessary @@ -1017,12 +1017,12 @@ Flint.prototype.getTeamRooms = function (teamId) { * Get Person Object By Id * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} personId- PersonId of Webex Account * @returns {Promise.} */ -Flint.prototype.getPerson = function (personId) { +Framework.prototype.getPerson = function (personId) { return this.webex.people.get(personId); // .then(person => { // // Why is this neeeded? @@ -1043,12 +1043,12 @@ Flint.prototype.getPerson = function (personId) { * Get Person Object By Email * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} personEmail - Person Email of Webex Account * @returns {Promise.} */ -Flint.prototype.getPersonByEmail = function (personEmail) { +Framework.prototype.getPersonByEmail = function (personEmail) { return this.webex.people.list({ email: personEmail }) .then(people => { let personList = people.items; @@ -1078,12 +1078,12 @@ Flint.prototype.getPersonByEmail = function (personEmail) { * Get Person Email * * @function - * @memberof Flint + * @memberof Framework * @private * @param {Ojbect} person- Webex Person Object * @returns {string} */ -Flint.prototype.getPersonEmail = function (person) { +Framework.prototype.getPersonEmail = function (person) { if (person.emails.length >= 1) { return person.emails[0]; } else { @@ -1095,12 +1095,12 @@ Flint.prototype.getPersonEmail = function (person) { * Get Person Username * * @function - * @memberof Flint + * @memberof Framework * @private * @param {Ojbect} person- Webex Person Object * @returns {string} */ -Flint.prototype.getPersonUsername = function (person) { +Framework.prototype.getPersonUsername = function (person) { if (person.emails.length >= 1) { return _.split((person.emails[0]), '@', 2)[0]; } else { @@ -1112,12 +1112,12 @@ Flint.prototype.getPersonUsername = function (person) { * Get Person Domain * * @function - * @memberof Flint + * @memberof Framework * @private * @param {Ojbect} person- Webex Person Object * @returns {string} */ -Flint.prototype.getPersonDomain = function (person) { +Framework.prototype.getPersonDomain = function (person) { if (person.emails.length >= 1) { return _.split(person.emails[0], '@', 2)[1]; } else { @@ -1130,11 +1130,11 @@ Flint.prototype.getPersonDomain = function (person) { * Get Message Object by ID * * @function - * @memberof Flint + * @memberof Framework * @param {String} messageId - Message ID from Webex API. * @returns {Promise.} */ -Flint.prototype.getMessage = function (messageId) { +Framework.prototype.getMessage = function (messageId) { return this.webex.messages.get(messageId); // .then(message => this.parseMessage(message)); }; @@ -1143,13 +1143,13 @@ Flint.prototype.getMessage = function (messageId) { * Get Files from Message Object by ID * * @function - * @memberof Flint + * @memberof Framework * @param {String} messageId - Message ID from Webex API. * @returns {Promise.} */ -Flint.prototype.getFiles = function (messageId) { +Framework.prototype.getFiles = function (messageId) { //TODO figure out how/if Webex SDK handles this - when.reject(new Error('flint.getFiles not yet supported')); + when.reject(new Error('framework.getFiles not yet supported')); // return this.webex.messageGet(messageId) // .then(message => this.parseMessage(message)) @@ -1167,12 +1167,12 @@ Flint.prototype.getFiles = function (messageId) { * Get Membership Object by ID * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} membershipId - Membership ID from Webex API. * @returns {Promise.} */ -Flint.prototype.getMembership = function (membershipId) { +Framework.prototype.getMembership = function (membershipId) { return this.webex.memberships.get(membershipId) .then(membership => when(membership)); // Not convinced this is necessary @@ -1189,13 +1189,13 @@ Flint.prototype.getMembership = function (membershipId) { * Get Memberships by Room ID * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} [roomId] - Room ID from Webex API. * @returns {Promise.} * Promise fulfilled with Array of updated Membership objects. */ -Flint.prototype.getMemberships = function (roomId) { +Framework.prototype.getMemberships = function (roomId) { if (!roomId) { return this.webex.memberships.list() .then(memberships => { @@ -1231,12 +1231,12 @@ Flint.prototype.getMemberships = function (roomId) { * Get Team Membership Object by ID * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} teamMembershipId - Team Membership ID from Webex API. * @returns {Promise.} */ -Flint.prototype.getTeamMembership = function (teamMembershipId) { +Framework.prototype.getTeamMembership = function (teamMembershipId) { return this.webex.teamMembership.get(teamMembershipId) .then(memberships => when(memberships)); @@ -1254,12 +1254,12 @@ Flint.prototype.getTeamMembership = function (teamMembershipId) { * Get Memberships by Team ID * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} teamId - Team ID from Webex API. * @returns {Promise.} */ -Flint.prototype.getTeamMemberships = function (teamId) { +Framework.prototype.getTeamMemberships = function (teamId) { if (teamId) { return this.webex.teamMemberships.list({ teamId: teamId }) .then(memberships => { @@ -1283,12 +1283,12 @@ Flint.prototype.getTeamMemberships = function (teamId) { * Get Webhook Object by ID * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} webhookId - Webhook ID from Webex API. * @returns {Promise.} */ -Flint.prototype.getWebhook = function (webhookId) { +Framework.prototype.getWebhook = function (webhookId) { return this.webex.webhooks.get(webhookId) .then(webhook => { webhook.created = moment(webhook.created).utc().format(); @@ -1306,11 +1306,11 @@ Flint.prototype.getWebhook = function (webhookId) { * Get Webhooks * * @function - * @memberof Flint + * @memberof Framework * @private * @returns {Promise.} */ -Flint.prototype.getWebhooks = function () { +Framework.prototype.getWebhooks = function () { return this.webex.webhooks.list() .then(webhooks => { _.forEach(webhooks.items, webhook => { @@ -1329,11 +1329,11 @@ Flint.prototype.getWebhooks = function () { * Get Attachement Action by ID * * @function - * @memberof Flint + * @memberof Framework * @param {String} attachmentActionId - attachmentActionID from Webex API. * @returns {Promise.} */ -Flint.prototype.getAttachmentAction = function (attachmentActionId) { +Framework.prototype.getAttachmentAction = function (attachmentActionId) { return this.webex.attachmentActions.get(attachmentActionId); }; @@ -1342,11 +1342,11 @@ Flint.prototype.getAttachmentAction = function (attachmentActionId) { * Process a Room create event. * * @function - * @memberof Flint + * @memberof Framework * @private * @returns {Promise} */ -Flint.prototype.onRoomCreated = function (room) { +Framework.prototype.onRoomCreated = function (room) { var bot = _.find(this.bots, bot => bot.room.id === room.id); if (bot) { bot.room = room; @@ -1359,11 +1359,11 @@ Flint.prototype.onRoomCreated = function (room) { * Process a Room update event. * * @function - * @memberof Flint + * @memberof Framework * @private * @returns {Promise} */ -Flint.prototype.onRoomUpdated = function (room) { +Framework.prototype.onRoomUpdated = function (room) { var bot = _.find(this.bots, bot => bot.room.id === room.id); if (bot) bot.lastActivity = moment().utc().format(); @@ -1381,7 +1381,7 @@ Flint.prototype.onRoomUpdated = function (room) { * * @event roomLocked * @property {object} bot - Bot Object - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('roomLocked', bot, this.id); bot.emit('roomLocked', bot, bot.id); @@ -1393,7 +1393,7 @@ Flint.prototype.onRoomUpdated = function (room) { * * @event roomUnocked * @property {object} bot - Bot Object - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('roomUnlocked', bot, this.id); bot.emit('roomUnlocked', bot, bot.id); @@ -1412,12 +1412,12 @@ Flint.prototype.onRoomUpdated = function (room) { * Process a new Membership event. * * @function - * @memberof Flint + * @memberof Framework * @private * @param {Object} membership - Webex Team Membership Object * @returns {Promise} */ -Flint.prototype.onMembershipCreated = function (membership) { +Framework.prototype.onMembershipCreated = function (membership) { var bot = _.find(this.bots, bot => bot.room.id === membership.roomId); if (bot) bot.lastActivity = moment().utc().format(); @@ -1443,7 +1443,7 @@ Flint.prototype.onMembershipCreated = function (membership) { * @event userEnters * @property {object} bot - Bot Object * @property {object} membership - Membership Object - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('memberEnters', bot, membership, this.id); bot.emit('memberEnters', bot, membership, bot.id); @@ -1461,12 +1461,12 @@ Flint.prototype.onMembershipCreated = function (membership) { * Process a updated Membership event. * * @function - * @memberof Flint + * @memberof Framework * @private * @param {Object} membership - Webex Membership Object * @returns {Promise} */ -Flint.prototype.onMembershipUpdated = function (membership) { +Framework.prototype.onMembershipUpdated = function (membership) { var bot = _.find(this.bots, bot => bot.room.id === membership.roomId); if (bot) bot.lastActivity = moment().utc().format(); @@ -1483,7 +1483,7 @@ Flint.prototype.onMembershipUpdated = function (membership) { * * @event botAddedAsModerator * @property {object} bot - Bot Object - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('botAddedAsModerator', bot, this.id); bot.emit('botAddedAsModerator', bot, bot.id); @@ -1493,7 +1493,7 @@ Flint.prototype.onMembershipUpdated = function (membership) { * * @event botRemovedAsModerator * @property {object} bot - Bot Object - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('botRemovedAsModerator', bot, this.id); bot.emit('botRemovedAsModerator', bot, bot.id); @@ -1528,7 +1528,7 @@ Flint.prototype.onMembershipUpdated = function (membership) { * @event personAddedAsModerator * @property {object} bot - Bot Object * @property {object} person - Person Object - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('memberAddedAsModerator', bot, membership, this.id); bot.emit('memberAddedAsModerator', bot, membership, bot.id); @@ -1539,7 +1539,7 @@ Flint.prototype.onMembershipUpdated = function (membership) { * @event personRemovedAsModerator * @property {object} bot - Bot Object * @property {object} person - Person Object - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('memberRemovedAsModerator', bot, membership, this.id); bot.emit('memberRemovedAsModerator', bot, membership, bot.id); @@ -1552,13 +1552,13 @@ Flint.prototype.onMembershipUpdated = function (membership) { * Process a deleted Membership event. * * @function - * @memberof Flint + * @memberof Framework * @private * * @param {Object} membership - Webex Membership Object * @returns {Promise} */ -Flint.prototype.onMembershipDeleted = function (membership) { +Framework.prototype.onMembershipDeleted = function (membership) { var bot = _.find(this.bots, bot => bot.room.id === membership.roomId); // if bot membership deleted in monitored room @@ -1584,7 +1584,7 @@ Flint.prototype.onMembershipDeleted = function (membership) { * @event personExits * @property {object} bot - Bot Object * @property {object} membership - Membership Object - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('memberExits', bot, membership, this.id); bot.emit('memberExits', bot, membership, bot.id); @@ -1603,12 +1603,12 @@ Flint.prototype.onMembershipDeleted = function (membership) { * Process a new Message event. * * @function - * @memberof Flint + * @memberof Framework * @private * @param {Object} tembership - Webex Team Membership Object * @returns {Promise} */ -Flint.prototype.onMessageCreated = function (message) { +Framework.prototype.onMessageCreated = function (message) { var bot = _.find(this.bots, bot => bot.room.id === message.roomId); if (bot) bot.lastActivity = moment().utc().format(); @@ -1685,7 +1685,7 @@ Flint.prototype.onMessageCreated = function (message) { * @event mentioned * @property {object} bot - Bot Object * @property {object} trigger - Trigger Object - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('mentioned', bot, trigger, this.id); bot.emit('mentioned', bot, trigger, bot.id); @@ -1700,7 +1700,7 @@ Flint.prototype.onMessageCreated = function (message) { * @event message * @property {object} bot - Bot Object * @property {object} trigger - Trigger Object - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('message', bot, trigger, this.id); bot.emit('message', bot, trigger, bot.id); @@ -1716,7 +1716,7 @@ Flint.prototype.onMessageCreated = function (message) { * @event files * @property {object} bot - Bot Object * @property {trigger} trigger - Trigger Object - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('files', bot, trigger, this.id); bot.emit('files', bot, trigger, bot.id); @@ -1803,12 +1803,12 @@ Flint.prototype.onMessageCreated = function (message) { * Process a new attachment action event. * * @function - * @memberof Flint + * @memberof Framework * @private * @param {Object} attachmentAction - Webex attachentAction Object * @returns {Promise} */ -Flint.prototype.onAttachmentActions = function (attachmentAction) { +Framework.prototype.onAttachmentActions = function (attachmentAction) { var bot = _.find(this.bots, bot => bot.room.id === attachmentAction.roomId); if (bot) bot.lastActivity = moment().utc().format(); @@ -1828,12 +1828,12 @@ Flint.prototype.onAttachmentActions = function (attachmentAction) { * Spawns a bot in a Webex Teams Spae. * * @function - * @memberof Flint + * @memberof Framework * @private * @param {Object} Membership of bot in room * @returns {Promise.} */ -Flint.prototype.spawn = function (membership) { +Framework.prototype.spawn = function (membership) { // if active... if (!this.active) { @@ -1958,7 +1958,7 @@ Flint.prototype.spawn = function (membership) { * * @event spawn * @property {object} bot - Bot Object - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('spawn', newBot, this.id); @@ -1983,12 +1983,12 @@ Flint.prototype.spawn = function (membership) { * Despawns a bot in a Webex Teams Space. * * @function - * @memberof Flint + * @memberof Framework * @private * @param {String} Room ID - The ID for a Webex Teams Space. * @returns {Promise.} */ -Flint.prototype.despawn = function (roomId) { +Framework.prototype.despawn = function (roomId) { var bot = _.find(this.bots, bot => (bot.room.id === roomId)); if (bot) { @@ -2003,11 +2003,11 @@ Flint.prototype.despawn = function (roomId) { * * @event despawn * @property {object} bot - Bot Object - * @property {string} id - Flint UUID + * @property {string} id - Framework UUID */ this.emit('despawn', bot, this.id); - // remove bot from flint + // remove bot from framework this.bots = _.reject(this.bots, { 'id': bot.id }); return when(true); @@ -2021,7 +2021,7 @@ Flint.prototype.despawn = function (roomId) { * Add action to be performed when bot hears a phrase. * * @function - * @memberof Flint + * @memberof Framework * @param {Regex|String} phrase - The phrase as either a regex or string. If * regex, matches on entire message.If string, matches on first word. * @param {Function} action - The function to execute when phrase is matched. @@ -2039,17 +2039,17 @@ Flint.prototype.despawn = function (roomId) { * * @example * // using a string to match first word and defines help text - * flint.hears('/say', function(bot, trigger, id) { + * framework.hears('/say', function(bot, trigger, id) { * bot.say(trigger.args.slice(1, trigger.arges.length - 1)); * }, '/say - Responds with a greeting'); * * @example * // using regex to match across entire message - * flint.hears(/(^| )beer( |.|$)/i, function(bot, trigger, id) { - * bot.say('Enjoy a beer, %s! 🍻', trigger.personDisplayName); + * framework.hears(/(^| )beer( |.|$)/i, function(bot, trigger, id) { + * bot.say('Enjoy a beer, %s! 🍻', trigger.person.displayName); * }); */ -Flint.prototype.hears = function (phrase, action, helpText, preference) { +Framework.prototype.hears = function (phrase, action, helpText, preference) { var id = u.genUUID64(); // parse function args @@ -2071,45 +2071,45 @@ Flint.prototype.hears = function (phrase, action, helpText, preference) { } else { - throw new Error('Invalid flint.hears() syntax'); + throw new Error('Invalid framework.hears() syntax'); } }; /** - * Remove a "flint.hears()" entry. + * Remove a "framework.hears()" entry. * * @function - * @memberof Flint + * @memberof Framework * @param {String} id - The "hears" ID. * @returns {null} * * @example * // using a string to match first word and defines help text - * var hearsHello = flint.hears('/flint', function(bot, trigger, id) { - * bot.say('Hello %s!', trigger.personDisplayName); + * var hearsHello = framework.hears('/framework', function(bot, trigger, id) { + * bot.say('Hello %s!', trigger.person.displayName); * }); - * flint.clearHears(hearsHello); + * framework.clearHears(hearsHello); */ -Flint.prototype.clearHears = function (hearsId) { +Framework.prototype.clearHears = function (hearsId) { this.lexicon = _.reject(this.lexicon, lex => (lex.id === hearsId)); }; /** - * Display help for registered Flint Commands. + * Display help for registered Framework Commands. * * @function * @param {String} [header=Usage:] - String to use in header before displaying help message. - * @param {String} [footer=Powered by Flint - https://github.com/nmarus/flint] - String to use in footer before displaying help message. + * @param {String} [footer=Powered by Webex Node Bot Framework - https://github.com/jpjpjp/webex-node-bot-framework] - String to use in footer before displaying help message. * @returns {String} * * @example - * flint.hears('/help', function(bot, trigger, id) { - * bot.say(flint.showHelp()); + * framework.hears('/help', function(bot, trigger, id) { + * bot.say(framework.showHelp()); * }); */ -Flint.prototype.showHelp = function (header, footer) { +Framework.prototype.showHelp = function (header, footer) { header = header ? header : 'Usage:'; - footer = footer ? footer : 'Powered by Flint - https://github.com/nmarus/flint'; + footer = footer ? footer : 'Powered by Webex Node Bot Framework - https://github.com/jpjpjp/webex-node-bot-framework'; var helpText = ''; @@ -2128,7 +2128,7 @@ Flint.prototype.showHelp = function (header, footer) { * Attaches authorizer function. * * @function - * @memberof Flint + * @memberof Framework * @param {Function} Action - The function to execute when phrase is matched * to authenticate a user. The function is passed the bot, trigger, and id and * expects a return value of true or false. @@ -2146,9 +2146,9 @@ Flint.prototype.showHelp = function (header, footer) { * return false; * } * } - * flint.setAuthorizer(myAuthorizer); + * framework.setAuthorizer(myAuthorizer); */ -Flint.prototype.setAuthorizer = function (fn) { +Framework.prototype.setAuthorizer = function (fn) { if (typeof fn === 'function') { this.authorize = when.lift(fn); return true; @@ -2157,19 +2157,19 @@ Flint.prototype.setAuthorizer = function (fn) { return false; } }; -Flint.prototype.authorize = null; +Framework.prototype.authorize = null; /** * Removes authorizer function. * * @function - * @memberof Flint + * @memberof Framework * @returns {null} * * @example - * flint.clearAuthorizer(); + * framework.clearAuthorizer(); */ -Flint.prototype.clearAuthorizer = function () { +Framework.prototype.clearAuthorizer = function () { this.authorize = null; }; @@ -2177,15 +2177,15 @@ Flint.prototype.clearAuthorizer = function () { * Defines storage backend. * * @function - * @memberof Flint + * @memberof Framework * @param {Function} Driver - The storage driver. * @returns {null} * * @example * // define memory store (default if not specified) - * flint.storageDriver(new MemStore()); + * framework.storageDriver(new MemStore()); */ -Flint.prototype.storageDriver = function (driver) { +Framework.prototype.storageDriver = function (driver) { // validate storage module store() method if (typeof driver.store === 'function') { @@ -2226,7 +2226,7 @@ Flint.prototype.storageDriver = function (driver) { } }; - Flint.prototype.forgetByRoomId = function (roomId) { + Framework.prototype.forgetByRoomId = function (roomId) { return driver.forget.call(driver, roomId) .catch(err => { // ignore errors when called by forgetByRoomId @@ -2249,64 +2249,64 @@ Flint.prototype.storageDriver = function (driver) { * @param {String} roomId * @returns {Boolean} */ -Flint.prototype.forgetByRoomId = null; +Framework.prototype.forgetByRoomId = null; /** * Load a Plugin from a external file. * @function - * @memberof Flint + * @memberof Framework * @param {String} path - Load a plugin at given path. * @returns {Boolean} * * @example - * flint.use('events.js'); + * framework.use('events.js'); * * @example * // events.js - * module.exports = function(flint) { - * flint.on('spawn', function(bot) { + * module.exports = function(framework) { + * framework.on('spawn', function(bot) { * console.log('new bot spawned in room: %s', bot.myroom.title); * }); - * flint.on('despawn', function(bot) { + * framework.on('despawn', function(bot) { * console.log('bot despawned in room: %s', bot.myroom.title); * }); - * flint.on('messageCreated', function(message, bot) { + * framework.on('messageCreated', function(message, bot) { * console.log('"%s" said "%s" in room "%s"', message.personEmail, message.text, bot.myroom.title); * }); * }; */ -Flint.prototype.use = function (pluginPath) { +Framework.prototype.use = function (pluginPath) { if (path.parse(pluginPath).ext === '.js') { try { require(pluginPath)(this); - this.debug('Loading flint plugin at "%s"', pluginPath); + this.debug('Loading framework plugin at "%s"', pluginPath); return true; } catch (err) { - this.debug('Could not load flint plugin at "%s"', pluginPath); + this.debug('Could not load framework plugin at "%s"', pluginPath); return false; } } }; -module.exports = Flint; +module.exports = Framework; -function cleanupListeners(flint) { +function cleanupListeners(framework) { // Cleanup webhooks or websockets - if (flint.options.webhookUrl) { - return flint.getWebhooks() + if (framework.options.webhookUrl) { + return framework.getWebhooks() // get webhooks .then(webhooks => { // remove all webhooks on stop - if (!flint.options.removeWebhooksOnStart) { + if (!framework.options.removeWebhooksOnStart) { var webhooksToRemove = _.filter(webhooks, webhook => { - return (webhook.name == u.base64encode(flint.options.webhookUrl.split('/')[2] + ' ' + flint.email)); + return (webhook.name == u.base64encode(framework.options.webhookUrl.split('/')[2] + ' ' + framework.email)); }); if (webhooksToRemove instanceof Array && webhooksToRemove.length > 0) { - return when.map(webhooksToRemove, webhook => flint.webex.webhooks.remove(webhook)) + return when.map(webhooksToRemove, webhook => framework.webex.webhooks.remove(webhook)) .then(() => when(true)) .catch(() => when(true)); } else { @@ -2316,16 +2316,16 @@ function cleanupListeners(flint) { // else, only remove webhooks this app created else { - return when.map(webhooks, webhook => flint.webex.webhooks.remove(webhook)) + return when.map(webhooks, webhook => framework.webex.webhooks.remove(webhook)) .then(() => when(true)) .catch(() => when(true)); } }); } else { - return flint.websocket.cleanup() + return framework.websocket.cleanup() .then(() => { - delete flint.websocket; + delete framework.websocket; return when(true); }); } diff --git a/lib/logs.js b/lib/logs.js index 6f8e367..ea39223 100644 --- a/lib/logs.js +++ b/lib/logs.js @@ -1,83 +1,83 @@ var util = require('util'); var _ = require('lodash'); -module.exports = function(flint) { +module.exports = function(framework) { - flint.on('initialized', function(id) { - var msg = util.format('(Flint Initialized) %s rooms', flint.bots.length); - flint.log(msg); + framework.on('initialized', function(id) { + var msg = util.format('(Framework Initialized) %s rooms', framework.bots.length); + framework.log(msg); }); - flint.on('start', function(id) { - var msg = util.format('(Flint Started) "%s"', flint.email); - flint.log(msg); + framework.on('start', function(id) { + var msg = util.format('(Framework Started) "%s"', framework.email); + framework.log(msg); }); - flint.on('stop', function(id) { - var msg = util.format('(Flint Stopped) "%s"', flint.email); - flint.log(msg); + framework.on('stop', function(id) { + var msg = util.format('(Framework Stopped) "%s"', framework.email); + framework.log(msg); }); - flint.on('spawn', (bot, id) => { + framework.on('spawn', (bot, id) => { var msg = util.format('(Room Discovered) "%s"', bot.room.title); - flint.log(msg); + framework.log(msg); }); - flint.on('despawn', (bot, id) => { + framework.on('despawn', (bot, id) => { var msg = util.format('(Room Removed) "%s"', bot.room.title); - flint.log(msg); + framework.log(msg); }); - flint.on('message', (bot, trigger, id) => { - var msg = util.format('(Messsage Received) "%s" "%s" "%s"', bot.room.title, trigger.personEmail, trigger.text); - flint.log(msg); + framework.on('message', (bot, trigger, id) => { + var msg = util.format('(Messsage Received) "%s" "%s" "%s"', bot.room.title, trigger.person.emails[0], trigger.message.text); + framework.log(msg); }); - flint.on('files', (bot, trigger, id) => { - _.forEach(trigger.files, file => { - var msg = util.format('(File Uploaded) "%s" "%s" "%s"', bot.room.title, trigger.personEmail, file.name); - flint.log(msg); + framework.on('files', (bot, trigger, id) => { + _.forEach(trigger.message.files, file => { + var msg = util.format('(File Uploaded) "%s" "%s" "%s"', bot.room.title, trigger.person.emails[0], file.name); + framework.log(msg); }); }); - flint.on('roomLocked', (bot, id) => { + framework.on('roomLocked', (bot, id) => { var msg = util.format('(Room moderated) "%s"', bot.room.title); - flint.log(msg); + framework.log(msg); }); - flint.on('roomUnlocked', (bot, id) => { + framework.on('roomUnlocked', (bot, id) => { var msg = util.format('(Room unmoderated) "%s"', bot.room.title); - flint.log(msg); + framework.log(msg); }); - flint.on('botAddedAsModerator', (bot, id) => { + framework.on('botAddedAsModerator', (bot, id) => { var msg = util.format('(Added as Room Moderator) "%s" "%s"', bot.room.title, bot.email); - flint.log(msg); + framework.log(msg); }); - flint.on('botRemovedAsModerator', (bot, id) => { + framework.on('botRemovedAsModerator', (bot, id) => { var msg = util.format('(Removed as Room Moderator) "%s" "%s"', bot.room.title, bot.email); - flint.log(msg); + framework.log(msg); }); - flint.on('personAddedAsModerator', (bot, person, id) => { + framework.on('personAddedAsModerator', (bot, person, id) => { var msg = util.format('(Added as Room Moderator) "%s" "%s"', bot.room.title, person.email); - flint.log(msg); + framework.log(msg); }); - flint.on('personRemovedAsModerator', (bot, person, id) => { + framework.on('personRemovedAsModerator', (bot, person, id) => { var msg = util.format('(Removed as Room Moderator) "%s" "%s"', bot.room.title, person.email); - flint.log(msg); + framework.log(msg); }); - flint.on('personEnters', function(bot, person, id) { - var msg = util.format('(Room Entered) "%s" "%s"', bot.room.title, person.email); - flint.log(msg); + framework.on('memberEnters', function(bot, membership, id) { + var msg = util.format('(Room Entered) "%s" "%s"', bot.room.title, membership.personEmail); + framework.log(msg); }); - flint.on('personExits', function(bot, person, id) { - var msg = util.format('(Room Exited) "%s" "%s"', bot.room.title, person.email); - flint.log(msg); + framework.on('memberExits', function(bot, membership, id) { + var msg = util.format('(Room Exited) "%s" "%s"', bot.room.title, membership.personEmail); + framework.log(msg); }); }; diff --git a/lib/process-event.js b/lib/process-event.js index d0380bc..f61038d 100644 --- a/lib/process-event.js +++ b/lib/process-event.js @@ -7,12 +7,12 @@ var when = require('when'); * This can be called by either the webhook or websocket handler. * @function * @private - * @param {Object} flint - The flint object this function applies to. + * @param {Object} framework - The framework object this function applies to. * @param {Object} body - The body of the event being processed * @param {String} name - The name of the webhook, if a webhook is being processed */ -function processEvent(flint, body, name = '') { - if(!flint.active) { +function processEvent(framework, body, name = '') { + if(!framework.active) { return when(true); } @@ -23,19 +23,19 @@ function processEvent(flint, body, name = '') { var data = body.data; var roomId = body.filter ? body.filter.split('=')[1] : null; - // validate event is bound for this instance of flint - if(name !== flint.webhook.name || (typeof flint.webhook.roomId !== 'undefined' && flint.webhook.roomId !== roomId)) { + // validate event is bound for this instance of framework + if(name !== framework.webhook.name || (typeof framework.webhook.roomId !== 'undefined' && framework.webhook.roomId !== roomId)) { return when(true); } if(typeof resource !== 'string' || typeof event !== 'string') { - flint.debug('Can not determine webhook type'); + framework.debug('Can not determine webhook type'); return when(true); } // rooms if(resource === 'rooms') { - return flint.getRoom(data.id) + return framework.getRoom(data.id) .then(room => { // set room title for rooms with none set (api bug?) @@ -45,22 +45,22 @@ function processEvent(flint, body, name = '') { // room created if(event === 'created') { - flint.emit('roomCreated', room, flint.id); + framework.emit('roomCreated', room, framework.id); - return flint.onRoomCreated(room) + return framework.onRoomCreated(room) .catch(err => { - flint.debug(err.stack); + framework.debug(err.stack); return when(true); }); } // room updated if(event === 'updated') { - flint.emit('roomUpdated', room, flint.id); + framework.emit('roomUpdated', room, framework.id); - return flint.onRoomUpdated(room) + return framework.onRoomUpdated(room) .catch(err => { - flint.debug(err.stack); + framework.debug(err.stack); return when(true); }); } @@ -76,13 +76,13 @@ function processEvent(flint, body, name = '') { // membership created if(event === 'created') { - return flint.getMembership(data.id) + return framework.getMembership(data.id) .then(membership => { - flint.emit('membershipCreated', membership, flint.id); + framework.emit('membershipCreated', membership, framework.id); - return flint.onMembershipCreated(membership) + return framework.onMembershipCreated(membership) .catch(err => { - flint.debug(err.stack); + framework.debug(err.stack); return when(true); }); }) @@ -93,13 +93,13 @@ function processEvent(flint, body, name = '') { // membership updated if(event === 'updated') { - return flint.getMembership(data.id) + return framework.getMembership(data.id) .then(membership => { - flint.emit('membershipUpdated', membership, flint.id); + framework.emit('membershipUpdated', membership, framework.id); - return flint.onMembershipUpdated(membership) + return framework.onMembershipUpdated(membership) .catch(err => { - flint.debug(err.stack); + framework.debug(err.stack); return when(true); }); }) @@ -110,11 +110,11 @@ function processEvent(flint, body, name = '') { // membership deleted if(event === 'deleted') { - flint.emit('membershipDeleted', data, flint.id); + framework.emit('membershipDeleted', data, framework.id); - return flint.onMembershipDeleted(data) + return framework.onMembershipDeleted(data) .catch(err => { - flint.debug(err.stack); + framework.debug(err.stack); return when(true); }); } @@ -125,13 +125,13 @@ function processEvent(flint, body, name = '') { if(resource === 'messages') { // membership created if(event === 'created') { - return flint.getMessage(data.id) + return framework.getMessage(data.id) .then(message => { - flint.emit('messageCreated', message, flint.id); + framework.emit('messageCreated', message, framework.id); - return flint.onMessageCreated(message) + return framework.onMessageCreated(message) .catch(err => { - flint.debug(err.stack); + framework.debug(err.stack); return when(true); }); }) @@ -142,7 +142,7 @@ function processEvent(flint, body, name = '') { // message deleted if(event === 'deleted') { - flint.emit('messageDeleted', data, flint.id); + framework.emit('messageDeleted', data, framework.id); return when(true); } } @@ -151,12 +151,12 @@ function processEvent(flint, body, name = '') { if(resource === 'attachmentActions') { // action created if(event === 'created') { - return flint.getAttachmentAction(data.id) + return framework.getAttachmentAction(data.id) .then(attachmentAction => { // We'll emit an event later if we detect a related bot - return flint.onAttachmentActions(attachmentAction) + return framework.onAttachmentActions(attachmentAction) .catch(err => { - flint.debug(err.stack); + framework.debug(err.stack); return when(true); }); }) diff --git a/lib/validator.js b/lib/validator.js index 0ef801c..c921e9f 100644 --- a/lib/validator.js +++ b/lib/validator.js @@ -7,7 +7,7 @@ const _ = require('lodash'); const fsp = node.liftAll(fs); /** - * @description Flint Object Validation + * @description Framework Object Validation * * @name Validator * @namespace Validator @@ -15,25 +15,25 @@ const fsp = node.liftAll(fs); const Validator = {}; /** - * @description Validate an initialized flint object + * @description Validate an initialized framework object * * @function * @memberof Validator - * @param {object} flint A Flint object - * @returns {boolean} If flint object is valid + * @param {object} framework A Framework object + * @returns {boolean} If framework object is valid */ -Validator.isFlint = (flint) => { - const result = (typeof flint === 'object' - && (typeof flint.id === 'string') - && (typeof flint.active === 'boolean') - && (typeof flint.initialized === 'boolean') - && (typeof flint.isBotAccount === 'boolean') - && (typeof flint.isUserAccount === 'boolean') - && (typeof flint.options === 'object') - && (typeof flint.person === 'object') - && (typeof flint.email === 'string') - && (typeof flint.webex === 'object') - && (typeof flint.bots === 'object') +Validator.isFramework = (framework) => { + const result = (typeof framework === 'object' + && (typeof framework.id === 'string') + && (typeof framework.active === 'boolean') + && (typeof framework.initialized === 'boolean') + && (typeof framework.isBotAccount === 'boolean') + && (typeof framework.isUserAccount === 'boolean') + && (typeof framework.options === 'object') + && (typeof framework.person === 'object') + && (typeof framework.email === 'string') + && (typeof framework.webex === 'object') + && (typeof framework.bots === 'object') ); return result; }; @@ -50,7 +50,7 @@ Validator.isBot = (bot) => { const result = (typeof bot === 'object' && (typeof bot.id === 'string') && (typeof bot.email === 'string') - && (typeof bot.flint === 'object') + && (typeof bot.framework === 'object') && (typeof bot.isDirect === 'boolean') && (typeof bot.isGroup === 'boolean') && (typeof bot.isLocked === 'boolean') @@ -243,7 +243,7 @@ Validator.isFilePath = (path) => { * @function * @memberof Validator * @param {Object.} options Validate that object passed includes all - * valid options for flint constructor + * valid options for framework constructor * @returns {Boolean} result */ Validator.isOptions = options => (typeof options === 'object'); // TODO diff --git a/lib/webhook.js b/lib/webhook.js index 3db3247..a83629c 100644 --- a/lib/webhook.js +++ b/lib/webhook.js @@ -8,17 +8,17 @@ var processEvent = require('./process-event'); * Processes a inbound Webex API webhook. * @function * @private - * @param {Object} flint - The flint object this function applies to. + * @param {Object} framework - The framework object this function applies to. * @returns {Function} * Function that can be used for Express and Express-like webserver routes. * */ -function Webhook(flint) { +function Webhook(framework) { return function (req, res) { // emit webhook event (mostly here for debugging...) - flint.emit('webhook', req[flint.options.webhookRequestJSONLocation]); + framework.emit('webhook', req[framework.options.webhookRequestJSONLocation]); // if "res" is passed to function... if (typeof res !== 'undefined') { @@ -26,40 +26,40 @@ function Webhook(flint) { res.send('OK'); } - var body = req[flint.options.webhookRequestJSONLocation] || false; + var body = req[framework.options.webhookRequestJSONLocation] || false; if (!body) { return when(true); } - if (flint.options.webhookSecret) { + if (framework.options.webhookSecret) { // get webhook header to determine if security is enabled var sig = req.headers['x-spark-signature'] || false; if (!sig) { - flint.debug('missing expected signature in webhook callback, ignoring...'); + framework.debug('missing expected signature in webhook callback, ignoring...'); return when(true); } //validate signature - if (typeof flint.options.webhookSecret === 'string' && typeof sig === 'string') { - var hmac = crypto.createHmac('sha1', flint.options.webhookSecret); + if (typeof framework.options.webhookSecret === 'string' && typeof sig === 'string') { + var hmac = crypto.createHmac('sha1', framework.options.webhookSecret); var payload = JSON.stringify(body); hmac.update(payload); var digest = hmac.digest('hex'); if (sig !== digest) { // invalid signature, ignore processing webhook - flint.debug('invalid signature in webhook callback, ignoring...'); + framework.debug('invalid signature in webhook callback, ignoring...'); return when(true); } } } - // if (flint.options.webhookSecret && !(sig && flint.spark.webhookAuth(sig, body))) { + // if (framework.options.webhookSecret && !(sig && framework.spark.webhookAuth(sig, body))) { // // invalid signature, ignore processing webhook - // flint.debug('invalid signature in webhook callback, ignoring...'); + // framework.debug('invalid signature in webhook callback, ignoring...'); // return when(true); // } - return processEvent(flint, body); + return processEvent(framework, body); }; // end of return function... } diff --git a/lib/websocket.js b/lib/websocket.js index b1b96e0..6304d55 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -16,47 +16,37 @@ var processEvent = require('./process-event'); * * @function * @private - * @param {Object} flint - The flint object this function applies to. + * @param {Object} framework - The framework object this function applies to. * @param {Object} webhook - The webhook handler object for this instance * @returns {Object} * */ -function Websocket(flint, webhook) { - this.flint = flint; +function Websocket(framework, webhook) { + this.framework = framework; this.webhook = (webhook) ? webhook : {}; - // Todo make this more like the traditional flint "name" + // Todo make this more like the traditional framework "name" // B64 encoding of URL and bot name... this.name = 'webex sdk socket event'; - flint.webhook.name = this.name; + framework.webhook.name = this.name; } Websocket.prototype.init = function() { -// This is no longer needed since flint al ready has a webex instance -// this.flint.webex = Webex.init({ -// credentials: { -// access_token: this.flint.options.token -// } -// }); - -// if (!((this.flint.webex) && (this.flint.webex.canAuthorize))) { -// console.error('Unable to intiatize Webex SDK for events'); -// return when(false); -// } // register for message, membership and room events - let messagesPromise = this.flint.webex.messages.listen(); - let membershipsPromise = this.flint.webex.memberships.listen(); - let roomsPromise = this.flint.webex.rooms.listen(); + // TODO Add attachmentActions when webex sdk supports it + let messagesPromise = this.framework.webex.messages.listen(); + let membershipsPromise = this.framework.webex.memberships.listen(); + let roomsPromise = this.framework.webex.rooms.listen(); return Promise.all([messagesPromise, membershipsPromise, roomsPromise]) .then(() => { - this.flint.webex.messages.on('created', (event) => processEvent(this.flint, event, this.name)); - this.flint.webex.messages.on('deleted', (event) => processEvent(this.flint, event, this.name)); - this.flint.webex.memberships.on('created', (event) => processEvent(this.flint, event, this.name)); - this.flint.webex.memberships.on('deleted', (event) => processEvent(this.flint, event, this.name)); - this.flint.webex.memberships.on('updated', (event) => processEvent(this.flint, event, this.name)); - this.flint.webex.rooms.on('created', (event) => processEvent(this.flint, event, this.name)); - this.flint.webex.rooms.on('updated', (event) => processEvent(this.flint, event, this.name)); + this.framework.webex.messages.on('created', (event) => processEvent(this.framework, event, this.name)); + this.framework.webex.messages.on('deleted', (event) => processEvent(this.framework, event, this.name)); + this.framework.webex.memberships.on('created', (event) => processEvent(this.framework, event, this.name)); + this.framework.webex.memberships.on('deleted', (event) => processEvent(this.framework, event, this.name)); + this.framework.webex.memberships.on('updated', (event) => processEvent(this.framework, event, this.name)); + this.framework.webex.rooms.on('created', (event) => processEvent(this.framework, event, this.name)); + this.framework.webex.rooms.on('updated', (event) => processEvent(this.framework, event, this.name)); console.log('Listening for webex teams events...'); return when(true); }) @@ -68,17 +58,17 @@ Websocket.prototype.init = function() { Websocket.prototype.cleanup = function() { // register for message, membership and room events - this.flint.webex.messages.stopListening(); - this.flint.webex.memberships.stopListening(); - this.flint.webex.rooms.stopListening(); + this.framework.webex.messages.stopListening(); + this.framework.webex.memberships.stopListening(); + this.framework.webex.rooms.stopListening(); - this.flint.webex.messages.off('created'); - this.flint.webex.messages.off('deleted'); - this.flint.webex.memberships.off('created'); - this.flint.webex.memberships.off('deleted'); - this.flint.webex.memberships.off('updated'); - this.flint.webex.rooms.off('created'); - this.flint.webex.rooms.off('updated'); + this.framework.webex.messages.off('created'); + this.framework.webex.messages.off('deleted'); + this.framework.webex.memberships.off('created'); + this.framework.webex.memberships.off('deleted'); + this.framework.webex.memberships.off('updated'); + this.framework.webex.rooms.off('created'); + this.framework.webex.rooms.off('updated'); console.log('Stopped listening for webex teams events...'); return when(true); }; diff --git a/package-lock.json b/package-lock.json index 92ad86c..9cc63c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "webex-flint", + "name": "webex-node-bot-framework", "version": "0.1.0", "lockfileVersion": 1, "requires": true, diff --git a/package.json b/package.json index 4991cd5..dc06fca 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "webex-flint", + "name": "webex-node-bot-framework", "version": "0.1.0", - "description": "Bot Framework for Node JS", + "description": "Webex Teams Bot Framework for Node JS", "main": "index.js", "scripts": { "test": "node_modules/.bin/mocha test/bot-tests.js --exit", @@ -10,7 +10,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/flint-bot/flint.git" + "url": "git+https://github.com/jpjpjp/webex-node-bot-framework.git" }, "keywords": [ "bot", @@ -20,10 +20,10 @@ "cisco" ], "bugs": { - "url": "https://github.com/flint-bot/flint/issues" + "url": "https://github.com/jpjpjp/webex-node-bot-framework/issues" }, - "homepage": "https://github.com/flint-bot/flint#readme", - "author": "Nicholas Marus ", + "homepage": "https://github.com/jpjpjp/webex-node-bot-framework#readme", + "author": "JP Shipherd ", "license": "MIT", "dependencies": { "moment": "^2.24.0", diff --git a/storage/README.md b/storage/README.md index 1236e0f..0ce47d7 100644 --- a/storage/README.md +++ b/storage/README.md @@ -1,7 +1,7 @@ -# Flint Storage Modules +# Framework Storage Modules -This folder contains the storage modules that can optionally be used in Flint for the `bot.store()`, `bot.recall()` and `bot.forget()` methods. +This folder contains the storage modules that can optionally be used in Framework for the `bot.store()`, `bot.recall()` and `bot.forget()` methods. -If not specified, Flint will default to the "memory" module. +If not specified, Framework will default to the "memory" module. See the 'memory.js' module for an example, and 'template.js' as a starting point in defining your own Storage module. diff --git a/storage/redis_old.js b/storage/redis_old.js index 211ec27..461eca8 100644 --- a/storage/redis_old.js +++ b/storage/redis_old.js @@ -5,7 +5,7 @@ var when = require('when'); var _ = require('lodash'); function Storage(connectionUrl, name) { - name = typeof name === 'string' ? name : 'flint'; + name = typeof name === 'string' ? name : 'framework'; var redis = Redis.createClient({ url: connectionUrl }); var memStore = {}; diff --git a/templates/bothub-template/Procfile b/templates/bothub-template/Procfile index 64da828..747a66d 100644 --- a/templates/bothub-template/Procfile +++ b/templates/bothub-template/Procfile @@ -1 +1 @@ -web: DEBUG=flint,bot node app.js +web: DEBUG=framework,bot node app.js diff --git a/templates/bothub-template/app.js b/templates/bothub-template/app.js index eab10ac..68cec1d 100644 --- a/templates/bothub-template/app.js +++ b/templates/bothub-template/app.js @@ -1,46 +1,46 @@ "use strict"; -var Flint = require('node-flint'); -var webhook = require('node-flint/webhook'); +var Framework = require('webex-node-bot-framework'); +var webhook = require('webex-node-bot-framework/webhook'); var express = require('express'); var bodyParser = require('body-parser'); var path = require('path'); var config = require(path.join(__dirname, 'config.js')); -// var RedisStore = require('node-flint/storage/redis'); +// var RedisStore = require('webex-node-bot-framework/storage/redis'); var app = express(); app.use(bodyParser.json()); -// init flint -var flint = new Flint(config); +// init framework +var framework = new Framework(config); // use redis storage -// flint.storageDriver(new RedisStore(process.env.REDIS_URL)); +// framework.storageDriver(new RedisStore(process.env.REDIS_URL)); -//start flint, load plugin(s) -flint.start() +//start framework, load plugin(s) +framework.start() .then(() => { - flint.use(path.join(__dirname, 'flint.js')); + framework.use(path.join(__dirname, 'framework.js')); }) .then(() => { - flint.debug('Flint has started'); + framework.debug('Framework has started'); }); // define express path for incoming webhooks -app.post('/flint', webhook(flint)); +app.post('/framework', webhook(framework)); // start express server var server = app.listen(process.env.PORT, function () { - flint.debug('Flint listening on port %s', process.env.PORT); + framework.debug('Framework listening on port %s', process.env.PORT); }); // gracefully shutdown (ctrl-c) process.on('SIGINT', function() { - flint.debug('stoppping...'); + framework.debug('stoppping...'); server.close(); - flint.stop().then(function() { + framework.stop().then(function() { process.exit(); }); }); diff --git a/templates/bothub-template/config.js b/templates/bothub-template/config.js index bde41a2..1845c50 100644 --- a/templates/bothub-template/config.js +++ b/templates/bothub-template/config.js @@ -7,5 +7,5 @@ module.exports = { requeueMinTime: 500, removeWebhooksOnStart: true, webhookSecret: process.env.FLYNN_APP_ID, - webhookUrl: 'http://' + process.env.FLYNN_APP_NAME + '.engine.bothub.io/flint' + webhookUrl: 'http://' + process.env.FLYNN_APP_NAME + '.engine.bothub.io/framework' }; diff --git a/templates/bothub-template/flint.js b/templates/bothub-template/flint.js deleted file mode 100644 index 6c0b384..0000000 --- a/templates/bothub-template/flint.js +++ /dev/null @@ -1,7 +0,0 @@ -"use strict"; - -module.exports = function(flint) { - flint.hears('hello', function(bot, trigger) { - bot.say('Hello %s!', trigger.personDisplayName); - }); -}; diff --git a/templates/bothub-template/framework.js b/templates/bothub-template/framework.js new file mode 100644 index 0000000..4b16bac --- /dev/null +++ b/templates/bothub-template/framework.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = function(framework) { + framework.hears('hello', function(bot, trigger) { + bot.say('Hello %s!', trigger.person.displayName); + }); +}; diff --git a/templates/bothub-template/package.json b/templates/bothub-template/package.json index 44111a2..e3741c7 100644 --- a/templates/bothub-template/package.json +++ b/templates/bothub-template/package.json @@ -3,7 +3,7 @@ "dependencies": { "body-parser": "^1.15.2", "express": "^4.14.0", - "node-flint": "^4.2.0", + "webex-node-bot-framework": "^4.2.0", "socket2me-client": "^1.2.0" }, "engines": { diff --git a/templates/bothub-template/test.js b/templates/bothub-template/test.js index e37bd95..23376ba 100644 --- a/templates/bothub-template/test.js +++ b/templates/bothub-template/test.js @@ -1,37 +1,37 @@ "use strict"; -var Flint = require('node-flint'); -var webhook = require('node-flint/webhook'); +var Framework = require('webex-node-bot-framework'); +var webhook = require('webex-node-bot-framework/webhook'); var Socket2meClient = require('socket2me-client'); var path = require('path'); var server = new Socket2meClient('https://socket.bothub.io'); -// var RedisStore = require('node-flint/storage/redis'); +// var RedisStore = require('webex-node-bot-framework/storage/redis'); -// flint options +// framework options var config = require(path.join(__dirname, 'config.js')); // get a remote webhook from socket2me server server.on('connected', function(webhookUrl) { config.webhookUrl = webhookUrl; - var flint = new Flint(config); + var framework = new Framework(config); // use redis storage - // flint.storageDriver(new RedisStore('redis://127.0.0.1')); + // framework.storageDriver(new RedisStore('redis://127.0.0.1')); - //start flint, load plugin(s) - flint.start() + //start framework, load plugin(s) + framework.start() .then(() => { - flint.use(path.join(__dirname, 'flint.js')); + framework.use(path.join(__dirname, 'framework.js')); }) .then(() => { - flint.debug('Flint has started'); + framework.debug('Framework has started'); }); server.requestHandler(function(request, respond) { - webhook(flint)(request); + webhook(framework)(request); respond(200, 'OK'); }); }); diff --git a/test/as-bot/bot-created-room-tests.js b/test/as-bot/bot-created-room-tests.js index 1972e9e..2217700 100644 --- a/test/as-bot/bot-created-room-tests.js +++ b/test/as-bot/bot-created-room-tests.js @@ -1,6 +1,6 @@ // Variables an functions shared by all tests var common = require("../common/common"); -let flint = common.flint; +let framework = common.framework; let userWebex = common.userWebex; let Bot_Test_Space_Title = common.Bot_Test_Space_Title; let User_Test_Space_Title = common.User_Test_Space_Title; @@ -22,7 +22,7 @@ describe('User Created Room to create a Test Bot', () => { })); // Add our bot to the room and validate that it is spawned properly - before(() => common.addBotToSpace('Add Bot to Space', flint, userCreatedTestRoom, eventsData) + before(() => common.addBotToSpace('Add Bot to Space', framework, userCreatedTestRoom, eventsData) .then((b) => { userCreatedRoomBot = b; return validator.isBot(b); @@ -33,7 +33,7 @@ describe('User Created Room to create a Test Bot', () => { if ((!userCreatedRoomBot) || (!userCreatedTestRoom)) { return Promise.resolve(); } - return common.botLeaveRoom('Bot Leaves Space', flint, userCreatedRoomBot, userCreatedTestRoom, eventsData); + return common.botLeaveRoom('Bot Leaves Space', framework, userCreatedRoomBot, userCreatedTestRoom, eventsData); }); // User deletes room -- cleanup @@ -59,7 +59,7 @@ describe('User Created Room to create a Test Bot', () => { // Create a room as user to have test bot which will create other rooms before(() => { let testName = 'bot.newRoom() with user as member test'; - return common.botCreateRoom(testName, flint, userCreatedRoomBot, eventsData, common.userInfo.emails[0]) + return common.botCreateRoom(testName, framework, userCreatedRoomBot, eventsData, common.userInfo.emails[0]) .then((b) => { botCreatedRoomBot = b; return validator.isBot(b); @@ -72,13 +72,13 @@ describe('User Created Room to create a Test Bot', () => { return Promise.resolve(); } const membershipDeleted = new Promise((resolve) => { - common.flintMembershipDeletedHandler('delete room', flint, eventsData, resolve); + common.frameworkMembershipDeletedHandler('delete room', framework, eventsData, resolve); }); const stopped = new Promise((resolve) => { botCreatedRoomBot.stopHandler('delete room', resolve); }); const despawned = new Promise((resolve) => { - common.flintDespawnHandler('flint init', flint, eventsData, resolve); + common.frameworkDespawnHandler('framework init', framework, eventsData, resolve); }); @@ -91,10 +91,10 @@ describe('User Created Room to create a Test Bot', () => { // remove the hears handlers we set up for these tests after(() => { - flint.clearHears(hearsHi); - flint.clearHears(hearsFile); - flint.clearHears(hearsAnything); - flint.clearHears(hearsSomeStuff); + framework.clearHears(hearsHi); + framework.clearHears(hearsFile); + framework.clearHears(hearsAnything); + framework.clearHears(hearsSomeStuff); }); describe('#user.webex.message.create()', () => { @@ -119,7 +119,7 @@ describe('User Created Room to create a Test Bot', () => { let hearsInfo = { phrase: 'hi' }; - return common.userSendMessage(testName, flint, userWebex, bot, + return common.userSendMessage(testName, framework, userWebex, bot, eventsData, hearsInfo, `<@personId:${bot.person.id}> hi`) .then((m) => { hearsHi = hearsInfo.functionVar; @@ -133,21 +133,21 @@ describe('User Created Room to create a Test Bot', () => { phrase: /.*file.*/igm, }; // Wait for the `files` events (as well as the others) - flintFilesEvent = new Promise((resolve) => { - common.flintFilesHandler(testName, flint, eventsData, resolve); + frameworkFilesEvent = new Promise((resolve) => { + common.frameworkFilesHandler(testName, framework, eventsData, resolve); }); botFilesEvent = new Promise((resolve) => { bot.filesHandler(testName, eventsData, resolve); }); - return common.userSendMessage(testName, flint, userWebex, bot, + return common.userSendMessage(testName, framework, userWebex, bot, eventsData, hearsInfo, `<@personId:${bot.person.id}> Here is a file for ya`, process.env.HOSTED_FILE) .then((m) => { message = m; hearsFile = hearsInfo.functionVar; - return when.all([flintFilesEvent, botFilesEvent]); + return when.all([frameworkFilesEvent, botFilesEvent]); }); }); @@ -159,13 +159,13 @@ describe('User Created Room to create a Test Bot', () => { priority: 99 }; - return common.userSendMessage(testName, flint, userWebex, bot, + return common.userSendMessage(testName, framework, userWebex, bot, eventsData, hearsInfo, `<@personId:${bot.person.id}>Here is a whole mess of stuff for ya`) .then((m) => { hearsAnything = hearsInfo.functionVar; message = m; - return when.all([flintFilesEvent, botFilesEvent]); + return when.all([frameworkFilesEvent, botFilesEvent]); }); }); @@ -177,13 +177,13 @@ describe('User Created Room to create a Test Bot', () => { priority: 2 // lower number == higher priority }; - return common.userSendMessage(testName, flint, userWebex, bot, + return common.userSendMessage(testName, framework, userWebex, bot, eventsData, hearsInfo, `<@personId:${bot.person.id}>Here is a Some Stuff for ya`) .then((m) => { hearsSomeStuff = hearsInfo.functionVar; message = m; - return when.all([flintFilesEvent, botFilesEvent]); + return when.all([frameworkFilesEvent, botFilesEvent]); }); }); @@ -196,11 +196,11 @@ describe('User Created Room to create a Test Bot', () => { testName = 'Bot posts message to room'; message = {}; eventsData = { bot: botCreatedRoomBot }; - flint.messageFormat = 'markdown'; + framework.messageFormat = 'markdown'; // Wait for the events associated with a new message before completing test.. messageCreatedEvent = new Promise((resolve) => { - common.flintMessageCreatedEventHandler(testName, flint, eventsData, resolve); + common.frameworkMessageCreatedEventHandler(testName, framework, eventsData, resolve); }); }); @@ -219,9 +219,9 @@ describe('User Created Room to create a Test Bot', () => { } } if (trigger.phrase) { - message += `\nIt matched the flint.hears() phrase: ${trigger.phrase}`; + message += `\nIt matched the framework.hears() phrase: ${trigger.phrase}`; } - flint.debug(message); + framework.debug(message); } else { message = ''; } @@ -329,7 +329,7 @@ describe('User Created Room to create a Test Bot', () => { // Wait for the events associated with a new message before completing test.. messageCreatedEvent = new Promise((resolve) => { - common.flintMessageCreatedEventHandler(testName, flint, eventsData, resolve); + common.frameworkMessageCreatedEventHandler(testName, framework, eventsData, resolve); }); return botCreatedRoomBot.sendCard(cardJson, 'What is your name?') diff --git a/test/as-bot/user-created-room-tests.js b/test/as-bot/user-created-room-tests.js index ccc9d57..edbd34b 100644 --- a/test/as-bot/user-created-room-tests.js +++ b/test/as-bot/user-created-room-tests.js @@ -1,6 +1,6 @@ // Variables an functions shared by all tests var common = require("../common/common"); -let flint = common.flint; +let framework = common.framework; let userWebex = common.userWebex; let User_Test_Space_Title = common.User_Test_Space_Title; @@ -26,7 +26,7 @@ describe('User Created Rooms Tests', () => { })); // Add our bot to the room and validate that it is spawned properly - before(() => common.addBotToSpace('Add bot to user created room', flint, userCreatedTestRoom, eventsData) + before(() => common.addBotToSpace('Add bot to user created room', framework, userCreatedTestRoom, eventsData) .then((b) => { bot = b; return validator.isBot(b); @@ -34,10 +34,10 @@ describe('User Created Rooms Tests', () => { // remove the hears handlers we set up for these tests after(() => { - flint.clearHears(hearsHi); - flint.clearHears(hearsFile); - flint.clearHears(hearsAnything); - flint.clearHears(hearsSomeStuff); + framework.clearHears(hearsHi); + framework.clearHears(hearsFile); + framework.clearHears(hearsAnything); + framework.clearHears(hearsSomeStuff); }); // Bot leaves rooms @@ -45,7 +45,7 @@ describe('User Created Rooms Tests', () => { if ((!bot) || (!userCreatedTestRoom)) { return Promise.resolve(); } - return common.botLeaveRoom('Remove bot from user created room', flint, bot, userCreatedTestRoom, eventsData); + return common.botLeaveRoom('Remove bot from user created room', framework, bot, userCreatedTestRoom, eventsData); }); // User deletes room -- cleanup @@ -81,7 +81,7 @@ describe('User Created Rooms Tests', () => { let hearsInfo = { phrase: 'hi' }; - return common.userSendMessage(testName, flint, userWebex, bot, + return common.userSendMessage(testName, framework, userWebex, bot, eventsData, hearsInfo, `<@personId:${bot.person.id}> hi`) .then((m) => { hearsHi = hearsInfo.functionVar; @@ -95,21 +95,21 @@ describe('User Created Rooms Tests', () => { phrase: /.*file.*/igm, }; // Wait for the `files` events (as well as the others) - flintFilesEvent = new Promise((resolve) => { - common.flintFilesHandler(testName, flint, eventsData, resolve); + frameworkFilesEvent = new Promise((resolve) => { + common.frameworkFilesHandler(testName, framework, eventsData, resolve); }); botFilesEvent = new Promise((resolve) => { bot.filesHandler(testName, eventsData, resolve); }); - return common.userSendMessage(testName, flint, userWebex, bot, + return common.userSendMessage(testName, framework, userWebex, bot, eventsData, hearsInfo, `<@personId:${bot.person.id}> Here is a file for ya`, process.env.HOSTED_FILE) .then((m) => { message = m; hearsFile = hearsInfo.functionVar; - return when.all([flintFilesEvent, botFilesEvent]); + return when.all([frameworkFilesEvent, botFilesEvent]); }); }); @@ -121,13 +121,13 @@ describe('User Created Rooms Tests', () => { priority: 99 }; - return common.userSendMessage(testName, flint, userWebex, bot, + return common.userSendMessage(testName, framework, userWebex, bot, eventsData, hearsInfo, `<@personId:${bot.person.id}>Here is a whole mess of stuff for ya`) .then((m) => { hearsAnything = hearsInfo.functionVar; message = m; - return when.all([flintFilesEvent, botFilesEvent]); + return when.all([frameworkFilesEvent, botFilesEvent]); }); }); @@ -139,13 +139,13 @@ describe('User Created Rooms Tests', () => { priority: 2 // lower number == higher priority }; - return common.userSendMessage(testName, flint, userWebex, bot, + return common.userSendMessage(testName, framework, userWebex, bot, eventsData, hearsInfo, `<@personId:${bot.person.id}>Here is a Some Stuff for ya`) .then((m) => { hearsSomeStuff = hearsInfo.functionVar; message = m; - return when.all([flintFilesEvent, botFilesEvent]); + return when.all([frameworkFilesEvent, botFilesEvent]); }); }); @@ -158,11 +158,11 @@ describe('User Created Rooms Tests', () => { testName = 'Bot posts message to room'; message = {}; eventsData = { bot: bot }; - flint.messageFormat = 'markdown'; + framework.messageFormat = 'markdown'; // Wait for the events associated with a new message before completing test.. messageCreatedEvent = new Promise((resolve) => { - common.flintMessageCreatedEventHandler(testName, flint, eventsData, resolve); + common.frameworkMessageCreatedEventHandler(testName, framework, eventsData, resolve); }); }); @@ -181,9 +181,9 @@ describe('User Created Rooms Tests', () => { } } if (trigger.phrase) { - message += `\nIt matched the flint.hears() phrase: ${trigger.phrase}`; + message += `\nIt matched the framework.hears() phrase: ${trigger.phrase}`; } - flint.debug(message); + framework.debug(message); } else { message = ''; } @@ -291,17 +291,17 @@ describe('User Created Rooms Tests', () => { testName = 'Bot posts message to room'; message = {}; eventsData = { bot: bot }; - flint.messageFormat = 'markdown'; + framework.messageFormat = 'markdown'; // Wait for the events associated with a new message before completing test.. messageCreatedEvent = new Promise((resolve) => { - common.flintMessageCreatedEventHandler(testName, flint, eventsData, resolve); + common.frameworkMessageCreatedEventHandler(testName, framework, eventsData, resolve); }); }); it('sends a file attachment', () => { testName = 'sends a file attachment'; - flint.messageFormat = 'text'; + framework.messageFormat = 'text'; messageText = 'Here is your file!'; return bot.say({ text: messageText, file: process.env.HOSTED_FILE }) .then((m) => { @@ -325,10 +325,10 @@ describe('User Created Rooms Tests', () => { }); }); - it('sends a flint.format=text message', () => { - testName = 'sends a flint.format=text message'; - flint.messageFormat = 'text'; - messageText = 'This message is plain text, inferred from flint\'s messageFormat'; + it('sends a framework.format=text message', () => { + testName = 'sends a framework.format=text message'; + framework.messageFormat = 'text'; + messageText = 'This message is plain text, inferred from framework\'s messageFormat'; return bot.say(messageText) .then((m) => { message = m; @@ -349,10 +349,10 @@ describe('User Created Rooms Tests', () => { }); }); - it('sends a flint.format=markdown message', () => { - testName = 'sends a flint.format=markdown message'; - flint.messageFormat = 'markdown'; - messageText = 'This message is **markdown** text, inferred from flint\'s messageFormat'; + it('sends a framework.format=markdown message', () => { + testName = 'sends a framework.format=markdown message'; + framework.messageFormat = 'markdown'; + messageText = 'This message is **markdown** text, inferred from framework\'s messageFormat'; return bot.say(messageText) .then((m) => { message = m; @@ -375,7 +375,7 @@ describe('User Created Rooms Tests', () => { it('sends an explicitly formatted text message', () => { testName = 'sends an explicitly formatted text message'; - flint.messageFormat = 'markdown'; + framework.messageFormat = 'markdown'; messageText = 'This message is plain text, explicitly set in the bot.say() call'; return bot.say('text', messageText) .then((m) => { @@ -398,8 +398,8 @@ describe('User Created Rooms Tests', () => { }); it('sends an explicitly formatted markdown message', () => { - testName = 'sends a flint.format=markdown message'; - flint.messageFormat = 'text'; + testName = 'sends a framework.format=markdown message'; + framework.messageFormat = 'text'; messageText = 'This message is **markdown**, explicitly set in the bot.say() call'; return bot.say('markdown', messageText) .then((m) => { @@ -412,7 +412,7 @@ describe('User Created Rooms Tests', () => { }) .then(() => { // Set this back to our default - flint.messageFormat = 'markdown'; + framework.messageFormat = 'markdown'; assert(validator.objIsEqual(message, eventsData.message), 'message returned by API did not match the one from the messageCreated event'); return when(true); diff --git a/test/as-user/bot-direct-message-tests.js b/test/as-user/bot-direct-message-tests.js index 35634f2..f7a55b1 100644 --- a/test/as-user/bot-direct-message-tests.js +++ b/test/as-user/bot-direct-message-tests.js @@ -1,6 +1,6 @@ // Variables an functions shared by all tests var common = require("../common/common"); -let flint = common.flint; +let framework = common.framework; let userWebex = common.userWebex; let assert = common.assert; @@ -14,7 +14,7 @@ describe('Bot interacts with user in 1-1 space', () => { let message; let eventsData = {}; let trigger = {}; - let messageCreatedEvent, flintMessageEvent, botMessageEvent; + let messageCreatedEvent, frameworkMessageEvent, botMessageEvent; // Setup the promises for the events that come from user input that mentions a bot beforeEach(() => { message = {}; @@ -26,10 +26,10 @@ describe('Bot interacts with user in 1-1 space', () => { eventsData = { bot: common.botForUser1on1Space }; common.createBotEventHandlers(common.botForUser1on1Space); messageCreatedEvent = new Promise((resolve) => { - common.flintMessageCreatedEventHandler(testName, flint, eventsData, resolve); + common.frameworkMessageCreatedEventHandler(testName, framework, eventsData, resolve); }); - flintMessageEvent = new Promise((resolve) => { - common.flintMessageHandler(testName, flint, eventsData, resolve); + frameworkMessageEvent = new Promise((resolve) => { + common.frameworkMessageHandler(testName, framework, eventsData, resolve); }); botMessageEvent = new Promise((resolve) => { common.botForUser1on1Space.messageHandler(testName, eventsData, resolve); @@ -46,13 +46,13 @@ describe('Bot interacts with user in 1-1 space', () => { } // Wait for the hears event associated with the input text const heard = new Promise((resolve) => { - flint.hears(/^DM: hi.*/igm, (b, t) => { + framework.hears(/^DM: hi.*/igm, (b, t) => { assert((b.id === common.botForUser1on1Space.id), 'bot returned in fint.hears("hi") is not the one expected'); assert(validator.objIsEqual(t, eventsData.trigger), - 'trigger returned in flint.hears(/^hi.*/) was not as expected'); + 'trigger returned in framework.hears(/^hi.*/) was not as expected'); trigger = t; - flint.debug('Bot heard message that user posted'); + framework.debug('Bot heard message that user posted'); resolve(true); }); }); @@ -67,7 +67,7 @@ describe('Bot interacts with user in 1-1 space', () => { assert(validator.isMessage(message), 'create message did not return a valid message'); // Wait for all the event handlers and the heard handler to fire - return when.all([messageCreatedEvent, flintMessageEvent, botMessageEvent, heard]); + return when.all([messageCreatedEvent, frameworkMessageEvent, botMessageEvent, heard]); }) .catch((e) => { console.error(`${testName} failed: ${e.message}`); diff --git a/test/as-user/user-created-room-tests.js b/test/as-user/user-created-room-tests.js index f5f3259..b1a62bd 100644 --- a/test/as-user/user-created-room-tests.js +++ b/test/as-user/user-created-room-tests.js @@ -1,6 +1,6 @@ // Variables an functions shared by all tests var common = require("../common/common"); -let flint = common.flint; +let framework = common.framework; let userWebex = common.userWebex; let User_Test_Space_Title = common.User_Test_Space_Title; @@ -24,7 +24,7 @@ describe('User Created Rooms Tests', () => { })); // Add our bot to the room and validate that it is spawned properly - before(() => common.addBotToSpace('Add bot to user created room', flint, userCreatedTestRoom, eventsData) + before(() => common.addBotToSpace('Add bot to user created room', framework, userCreatedTestRoom, eventsData) .then((b) => { bot = b; return validator.isBot(b); @@ -32,10 +32,10 @@ describe('User Created Rooms Tests', () => { // remove the hears handlers we set up for these tests after(() => { - flint.clearHears(hearsHi); - flint.clearHears(hearsFile); - flint.clearHears(hearsAnything); - flint.clearHears(hearsSomeStuff); + framework.clearHears(hearsHi); + framework.clearHears(hearsFile); + framework.clearHears(hearsAnything); + framework.clearHears(hearsSomeStuff); }); // Bot leaves rooms @@ -43,7 +43,7 @@ describe('User Created Rooms Tests', () => { if ((!bot) || (!userCreatedTestRoom)) { return Promise.resolve(); } - return common.botLeaveRoom('Remove bot from user created room', flint, bot, userCreatedTestRoom, eventsData); + return common.botLeaveRoom('Remove bot from user created room', framework, bot, userCreatedTestRoom, eventsData); }); // User deletes room -- cleanup @@ -58,7 +58,7 @@ describe('User Created Rooms Tests', () => { }); }); - // When running flint with a user token there is no need for the sending user to at-mention the app + // When running framework with a user token there is no need for the sending user to at-mention the app describe('#user.webex.message.create()', () => { // Setup the promises for the events that come from user input that mentions a bot beforeEach(() => { @@ -80,7 +80,7 @@ describe('User Created Rooms Tests', () => { let hearsInfo = { phrase: 'hi' }; - return common.userSendMessage(testName, flint, userWebex, bot, + return common.userSendMessage(testName, framework, userWebex, bot, eventsData, hearsInfo, `hi`) .then((m) => { hearsHi = hearsInfo.functionVar; @@ -94,21 +94,21 @@ describe('User Created Rooms Tests', () => { phrase: /.*file.*/igm, }; // Wait for the `files` events (as well as the others) - flintFilesEvent = new Promise((resolve) => { - common.flintFilesHandler(testName, flint, eventsData, resolve); + frameworkFilesEvent = new Promise((resolve) => { + common.frameworkFilesHandler(testName, framework, eventsData, resolve); }); botFilesEvent = new Promise((resolve) => { bot.filesHandler(testName, eventsData, resolve); }); - return common.userSendMessage(testName, flint, userWebex, bot, + return common.userSendMessage(testName, framework, userWebex, bot, eventsData, hearsInfo, `Here is a file for ya`, process.env.HOSTED_FILE) .then((m) => { message = m; hearsFile = hearsInfo.functionVar; - return when.all([flintFilesEvent, botFilesEvent]); + return when.all([frameworkFilesEvent, botFilesEvent]); }); }); @@ -120,13 +120,13 @@ describe('User Created Rooms Tests', () => { priority: 99 }; - return common.userSendMessage(testName, flint, userWebex, bot, + return common.userSendMessage(testName, framework, userWebex, bot, eventsData, hearsInfo, `Here is a whole mess of stuff for ya`) .then((m) => { hearsAnything = hearsInfo.functionVar; message = m; - return when.all([flintFilesEvent, botFilesEvent]); + return when.all([frameworkFilesEvent, botFilesEvent]); }); }); @@ -138,13 +138,13 @@ describe('User Created Rooms Tests', () => { priority: 2 // lower number == higher priority }; - return common.userSendMessage(testName, flint, userWebex, bot, + return common.userSendMessage(testName, framework, userWebex, bot, eventsData, hearsInfo, `Here is a Some Stuff for ya`) .then((m) => { hearsSomeStuff = hearsInfo.functionVar; message = m; - return when.all([flintFilesEvent, botFilesEvent]); + return when.all([frameworkFilesEvent, botFilesEvent]); }); }); @@ -157,11 +157,11 @@ describe('User Created Rooms Tests', () => { testName = 'Bot posts message to room'; message = {}; eventsData = { bot: bot }; - flint.messageFormat = 'markdown'; + framework.messageFormat = 'markdown'; // Wait for the events associated with a new message before completing test.. messageCreatedEvent = new Promise((resolve) => { - common.flintMessageCreatedEventHandler(testName, flint, eventsData, resolve); + common.frameworkMessageCreatedEventHandler(testName, framework, eventsData, resolve); }); }); @@ -180,9 +180,9 @@ describe('User Created Rooms Tests', () => { } } if (trigger.phrase) { - message += `\nIt matched the flint.hears() phrase: ${trigger.phrase}`; + message += `\nIt matched the framework.hears() phrase: ${trigger.phrase}`; } - flint.debug(message); + framework.debug(message); } else { message = ''; } @@ -290,17 +290,17 @@ describe('User Created Rooms Tests', () => { testName = 'Bot posts message to room'; message = {}; eventsData = { bot: bot }; - flint.messageFormat = 'markdown'; + framework.messageFormat = 'markdown'; // Wait for the events associated with a new message before completing test.. messageCreatedEvent = new Promise((resolve) => { - common.flintMessageCreatedEventHandler(testName, flint, eventsData, resolve); + common.frameworkMessageCreatedEventHandler(testName, framework, eventsData, resolve); }); }); it('sends a file attachment', () => { testName = 'sends a file attachment'; - flint.messageFormat = 'text'; + framework.messageFormat = 'text'; messageText = 'Here is your file!'; return bot.say({ text: messageText, file: process.env.HOSTED_FILE }) .then((m) => { @@ -324,10 +324,10 @@ describe('User Created Rooms Tests', () => { }); }); - it('sends a flint.format=text message', () => { - testName = 'sends a flint.format=text message'; - flint.messageFormat = 'text'; - messageText = 'This message is plain text, inferred from flint\'s messageFormat'; + it('sends a framework.format=text message', () => { + testName = 'sends a framework.format=text message'; + framework.messageFormat = 'text'; + messageText = 'This message is plain text, inferred from framework\'s messageFormat'; return bot.say(messageText) .then((m) => { message = m; @@ -348,10 +348,10 @@ describe('User Created Rooms Tests', () => { }); }); - it('sends a flint.format=markdown message', () => { - testName = 'sends a flint.format=markdown message'; - flint.messageFormat = 'markdown'; - messageText = 'This message is **markdown** text, inferred from flint\'s messageFormat'; + it('sends a framework.format=markdown message', () => { + testName = 'sends a framework.format=markdown message'; + framework.messageFormat = 'markdown'; + messageText = 'This message is **markdown** text, inferred from framework\'s messageFormat'; return bot.say(messageText) .then((m) => { message = m; @@ -374,7 +374,7 @@ describe('User Created Rooms Tests', () => { it('sends an explicitly formatted text message', () => { testName = 'sends an explicitly formatted text message'; - flint.messageFormat = 'markdown'; + framework.messageFormat = 'markdown'; messageText = 'This message is plain text, explicitly set in the bot.say() call'; return bot.say('text', messageText) .then((m) => { @@ -397,8 +397,8 @@ describe('User Created Rooms Tests', () => { }); it('sends an explicitly formatted markdown message', () => { - testName = 'sends a flint.format=markdown message'; - flint.messageFormat = 'text'; + testName = 'sends a framework.format=markdown message'; + framework.messageFormat = 'text'; messageText = 'This message is **markdown**, explicitly set in the bot.say() call'; return bot.say('markdown', messageText) .then((m) => { @@ -411,7 +411,7 @@ describe('User Created Rooms Tests', () => { }) .then(() => { // Set this back to our default - flint.messageFormat = 'markdown'; + framework.messageFormat = 'markdown'; assert(validator.objIsEqual(message, eventsData.message), 'message returned by API did not match the one from the messageCreated event'); return when(true); diff --git a/test/bot-tests.js b/test/bot-tests.js index 5f3e979..8c5b256 100644 --- a/test/bot-tests.js +++ b/test/bot-tests.js @@ -1,20 +1,20 @@ /* bot-tests.js * - * A set of tests to validate flint functionality - * when flint is created using a bot token + * A set of tests to validate framework functionality + * when framework is created using a bot token */ -const Flint = require('../lib/flint'); +const Framework = require('../lib/framework'); const Webex = require('webex'); console.log('Starting bot-tests...'); -// Initialize the flint and user objects once for all the tests -let flint, userWebex; +// Initialize the framework and user objects once for all the tests +let framework, userWebex; require('dotenv').config(); if ((typeof process.env.BOT_API_TOKEN === 'string') && (typeof process.env.USER_API_TOKEN === 'string') && (typeof process.env.HOSTED_FILE === 'string')) { - flint = new Flint({ token: process.env.BOT_API_TOKEN }); + framework = new Framework({ token: process.env.BOT_API_TOKEN }); userWebex = new Webex({ credentials: process.env.USER_API_TOKEN }); } else { console.error('Missing required evnvironment variables:\n' + @@ -28,20 +28,20 @@ if ((typeof process.env.BOT_API_TOKEN === 'string') && // Load the common module which includes functions and variables // shared by multiple tests var common = require("./common/common"); -common.setFlint(flint); +common.setFramework(framework); common.setUser(userWebex); -// Start up an instance of flint that we will use across multiple tests -describe('#flint', () => { - // Validate that flint starts and that we have a valid user - before(() => common.initFlint('flint init', flint, userWebex)); +// Start up an instance of framework that we will use across multiple tests +describe('#framework', () => { + // Validate that framework starts and that we have a valid user + before(() => common.initFramework('framework init', framework, userWebex)); - //Stop flint to shut down the event listeners - after(() => common.stopFlint('shutdown flint', flint)); + //Stop framework to shut down the event listeners + after(() => common.stopFramework('shutdown framework', framework)); - // Run some basic validation against the flint methods + // Run some basic validation against the framework methods // Could probably get rid of these if they are used internally by the other tests - require('./common/flint-functions.js'); + require('./common/framework-functions.js'); // Test bot interactions in a user created test space require('./as-bot/user-created-room-tests.js'); @@ -59,8 +59,8 @@ describe('#flint', () => { // gracefully shutdown (ctrl-c) process.on('SIGINT', function () { - flint.debug('stoppping...'); - flint.stop().then(function () { + framework.debug('stoppping...'); + framework.stop().then(function () { process.exit(); }); }); diff --git a/test/common/bot-direct-message-tests.js b/test/common/bot-direct-message-tests.js index 35634f2..f7a55b1 100644 --- a/test/common/bot-direct-message-tests.js +++ b/test/common/bot-direct-message-tests.js @@ -1,6 +1,6 @@ // Variables an functions shared by all tests var common = require("../common/common"); -let flint = common.flint; +let framework = common.framework; let userWebex = common.userWebex; let assert = common.assert; @@ -14,7 +14,7 @@ describe('Bot interacts with user in 1-1 space', () => { let message; let eventsData = {}; let trigger = {}; - let messageCreatedEvent, flintMessageEvent, botMessageEvent; + let messageCreatedEvent, frameworkMessageEvent, botMessageEvent; // Setup the promises for the events that come from user input that mentions a bot beforeEach(() => { message = {}; @@ -26,10 +26,10 @@ describe('Bot interacts with user in 1-1 space', () => { eventsData = { bot: common.botForUser1on1Space }; common.createBotEventHandlers(common.botForUser1on1Space); messageCreatedEvent = new Promise((resolve) => { - common.flintMessageCreatedEventHandler(testName, flint, eventsData, resolve); + common.frameworkMessageCreatedEventHandler(testName, framework, eventsData, resolve); }); - flintMessageEvent = new Promise((resolve) => { - common.flintMessageHandler(testName, flint, eventsData, resolve); + frameworkMessageEvent = new Promise((resolve) => { + common.frameworkMessageHandler(testName, framework, eventsData, resolve); }); botMessageEvent = new Promise((resolve) => { common.botForUser1on1Space.messageHandler(testName, eventsData, resolve); @@ -46,13 +46,13 @@ describe('Bot interacts with user in 1-1 space', () => { } // Wait for the hears event associated with the input text const heard = new Promise((resolve) => { - flint.hears(/^DM: hi.*/igm, (b, t) => { + framework.hears(/^DM: hi.*/igm, (b, t) => { assert((b.id === common.botForUser1on1Space.id), 'bot returned in fint.hears("hi") is not the one expected'); assert(validator.objIsEqual(t, eventsData.trigger), - 'trigger returned in flint.hears(/^hi.*/) was not as expected'); + 'trigger returned in framework.hears(/^hi.*/) was not as expected'); trigger = t; - flint.debug('Bot heard message that user posted'); + framework.debug('Bot heard message that user posted'); resolve(true); }); }); @@ -67,7 +67,7 @@ describe('Bot interacts with user in 1-1 space', () => { assert(validator.isMessage(message), 'create message did not return a valid message'); // Wait for all the event handlers and the heard handler to fire - return when.all([messageCreatedEvent, flintMessageEvent, botMessageEvent, heard]); + return when.all([messageCreatedEvent, frameworkMessageEvent, botMessageEvent, heard]); }) .catch((e) => { console.error(`${testName} failed: ${e.message}`); diff --git a/test/common/bot-membership-tests.js b/test/common/bot-membership-tests.js index 17e1129..98e5804 100644 --- a/test/common/bot-membership-tests.js +++ b/test/common/bot-membership-tests.js @@ -1,6 +1,6 @@ // Variables an functions shared by all tests var common = require("../common/common"); -let flint = common.flint; +let framework = common.framework; let userWebex = common.userWebex; let Bot_Test_Space_Title = common.Bot_Test_Space_Title; let User_Test_Space_Title = common.User_Test_Space_Title; @@ -22,7 +22,7 @@ describe('User Created Room to create a Test Bot', () => { })); // Add our bot to the room and validate that it is spawned properly - before(() => common.addBotToSpace('Add Bot to Space', flint, userCreatedTestRoom, eventsData) + before(() => common.addBotToSpace('Add Bot to Space', framework, userCreatedTestRoom, eventsData) .then((b) => { userCreatedRoomBot = b; return validator.isBot(b); @@ -33,7 +33,7 @@ describe('User Created Room to create a Test Bot', () => { if ((!userCreatedRoomBot) || (!userCreatedTestRoom)) { return Promise.resolve(); } - return common.botLeaveRoom('Bot Leaves Space', flint, userCreatedRoomBot, userCreatedTestRoom, eventsData); + return common.botLeaveRoom('Bot Leaves Space', framework, userCreatedRoomBot, userCreatedTestRoom, eventsData); }); // User deletes room -- cleanup @@ -56,7 +56,7 @@ describe('User Created Room to create a Test Bot', () => { // Create a room as user to have test bot which will create other rooms before(() => { let testName = 'empty bot.newRoom() test'; - return common.botCreateRoom(testName, flint, userCreatedRoomBot, eventsData) + return common.botCreateRoom(testName, framework, userCreatedRoomBot, eventsData) .then((b) => { botCreatedRoomBot = b; botCreatedTestRoom, b.room; @@ -70,13 +70,13 @@ describe('User Created Room to create a Test Bot', () => { return Promise.resolve(); } const membershipDeleted = new Promise((resolve) => { - common.flintMembershipDeletedHandler('flint init', flint, eventsData, resolve); + common.frameworkMembershipDeletedHandler('framework init', framework, eventsData, resolve); }); const stopped = new Promise((resolve) => { - botCreatedRoomBot.stopHandler('flint init', resolve); + botCreatedRoomBot.stopHandler('framework init', resolve); }); const despawned = new Promise((resolve) => { - common.flintDespawnHandler('flint init', flint, eventsData, resolve); + common.frameworkDespawnHandler('framework init', framework, eventsData, resolve); }); @@ -100,10 +100,10 @@ describe('User Created Room to create a Test Bot', () => { testName = 'adds a user to the room'; // Wait for the events associated with a new membership before completing test.. membershipCreatedEvent = new Promise((resolve) => { - common.flintMembershipCreatedHandler(testName, flint, eventsData, resolve); + common.frameworkMembershipCreatedHandler(testName, framework, eventsData, resolve); }); - flintMemberEntersEvent = new Promise((resolve) => { - common.flintMemberEntersHandler(testName, flint, eventsData, resolve); + frameworkMemberEntersEvent = new Promise((resolve) => { + common.frameworkMemberEntersHandler(testName, framework, eventsData, resolve); }); botMemberEntersEvent = new Promise((resolve) => { botCreatedRoomBot.memberEntersHandler(testName, eventsData, resolve); @@ -115,7 +115,7 @@ describe('User Created Room to create a Test Bot', () => { assert((emails[0] === common.userInfo.emails[0]), 'bot.add did not return the expected email'); // Wait for all the event handlers to fire - return when.all([membershipCreatedEvent, flintMemberEntersEvent, botMemberEntersEvent]); + return when.all([membershipCreatedEvent, frameworkMemberEntersEvent, botMemberEntersEvent]); }) .catch((e) => { console.error(`${testName} failed: ${e.message}`); @@ -128,10 +128,10 @@ describe('User Created Room to create a Test Bot', () => { // testName = 'makes user a moderator'; // // Wait for the events associated with a new membership before completing test.. // membershipUpdateEvent = new Promise((resolve) => { - // flintMembershipUpdatedHandler(testName, flint, eventsData, resolve); + // frameworkMembershipUpdatedHandler(testName, framework, eventsData, resolve); // }); - // flintMemberAddedAsModerator = new Promise((resolve) => { - // flintMemberAddedAsModeratorHandler(testName, flint, eventsData, resolve); + // frameworkMemberAddedAsModerator = new Promise((resolve) => { + // frameworkMemberAddedAsModeratorHandler(testName, framework, eventsData, resolve); // }); // botMemberAddedAsModerator = new Promise((resolve) => { // botCreatedRoomBot.memberAddedAsModerator(testName, eventsData, resolve); @@ -143,7 +143,7 @@ describe('User Created Room to create a Test Bot', () => { // assert((emails[0] === user.emails[0]), // 'bot.add did not return the expected email'); // // Wait for all the event handlers to fire - // return when.all([membershipUpdateEvent, flintMemberAddedAsModerator, botMemberAddedAsModerator]); + // return when.all([membershipUpdateEvent, frameworkMemberAddedAsModerator, botMemberAddedAsModerator]); // }) // // .then(() => { // // // triggers.push(eventsData.trigger); @@ -161,10 +161,10 @@ describe('User Created Room to create a Test Bot', () => { testName = 'removes a user from the room'; // Wait for the events associated with a new membership before completing test.. membershipDeletedEvent = new Promise((resolve) => { - common.flintMembershipDeletedHandler(testName, flint, eventsData, resolve); + common.frameworkMembershipDeletedHandler(testName, framework, eventsData, resolve); }); - flintMemberExitsEvent = new Promise((resolve) => { - common.flintMemberExitsHandler(testName, flint, eventsData, resolve); + frameworkMemberExitsEvent = new Promise((resolve) => { + common.frameworkMemberExitsHandler(testName, framework, eventsData, resolve); }); botMemberExitsEvent = new Promise((resolve) => { botCreatedRoomBot.memberExitsHandler(testName, eventsData, resolve); @@ -176,7 +176,7 @@ describe('User Created Room to create a Test Bot', () => { assert((emails[0] === common.userInfo.emails[0]), 'bot.remove did not return the expected email'); // Wait for all the event handlers to fire - return when.all([membershipDeletedEvent, flintMemberExitsEvent, botMemberExitsEvent]); + return when.all([membershipDeletedEvent, frameworkMemberExitsEvent, botMemberExitsEvent]); }) .catch((e) => { console.error(`${testName} failed: ${e.message}`); diff --git a/test/common/common.js b/test/common/common.js index 69ea4db..c514d52 100644 --- a/test/common/common.js +++ b/test/common/common.js @@ -3,43 +3,43 @@ const when = require('when'); const validator = require('../../lib/validator'); var _ = require('lodash'); -const User_Test_Space_Title = 'Flint User Created Test Room'; -const Bot_Test_Space_Title = 'Flint Bot Created Test Room'; +const User_Test_Space_Title = 'Framework User Created Test Room'; +const Bot_Test_Space_Title = 'Framework Bot Created Test Room'; module.exports = { - // Parent test will init the flint and SDK objects - setFlint: function (f) { - this.flint = f; + // Parent test will init the framework and SDK objects + setFramework: function (f) { + this.framework = f; }, setUser: function (w) { this.userWebex = w; }, // Common Tasks used by tests - initFlint: function (testName, flint, userWebex) { - // Wait for flint to generate events that indicate it started succesfully + initFramework: function (testName, framework, userWebex) { + // Wait for framework to generate events that indicate it started succesfully const started = new Promise((resolve) => { - this.flintStartHandler(testName, flint, resolve); + this.frameworkStartHandler(testName, framework, resolve); }); const initialized = new Promise((resolve) => { - this.flintInitializedHandler(testName, flint, resolve); + this.frameworkInitializedHandler(testName, framework, resolve); }); - flint.start() + framework.start() .catch(() => { - console.error('Flint initialization failed, abandon all tests!'); + console.error('Framework initialization failed, abandon all tests!'); process.exit(-1); }); - // While we wait for flint, lets validate the user + // While we wait for framework, lets validate the user let userInfoIsReady = userWebex.people.get('me'); - // Now wait until flint is initialized + // Now wait until framework is initialized return when.all([started, initialized]) .then(() => { - assert(validator.isFlint(flint), - 'Flint did not initialize succesfully'); - flint.debug(`${flint.email} is in ${flint.bots.length} at the start of the tests.`); + assert(validator.isFramework(framework), + 'Framework did not initialize succesfully'); + framework.debug(`${framework.email} is in ${framework.bots.length} at the start of the tests.`); if (process.env.CLEANUP_USER_ROOMS) { asUserCeanupFromPreviousTests(userWebex); } @@ -50,7 +50,7 @@ module.exports = { this.userInfo = person; assert(validator.isPerson(person), 'getPerson did not return a valid person'); - this.botForUser1on1Space = cleanupFromPreviousTests(flint, this.userInfo); + this.botForUser1on1Space = cleanupFromPreviousTests(framework, this.userInfo); return when(true); }) .catch((e) => { @@ -59,52 +59,52 @@ module.exports = { }); }, - stopFlint: function (testName, flint) { - if (flint) { + stopFramework: function (testName, framework) { + if (framework) { const stopped = new Promise((resolve) => { - this.flintStopHandler(testName, flint, resolve); + this.frameworkStopHandler(testName, framework, resolve); }); - return flint.stop() + return framework.stop() .then(() => when(stopped)) - .catch((e) => console.error(`Failled during flint.stop(): ${e.message}`)); + .catch((e) => console.error(`Failled during framework.stop(): ${e.message}`)); } }, - addBotToSpace: function (testName, flint, userCreatedTestRoom, eventsData) { + addBotToSpace: function (testName, framework, userCreatedTestRoom, eventsData) { let membership; // Wait for the events associated with a new membership before completing test.. const membershipEvent = new Promise((resolve) => { - this.flintMembershipCreatedHandler(testName, flint, eventsData, resolve); + this.frameworkMembershipCreatedHandler(testName, framework, eventsData, resolve); }); const spawned = new Promise((resolve) => { - this.flintSpawnedHandler(testName, flint, eventsData, resolve); + this.frameworkSpawnedHandler(testName, framework, eventsData, resolve); }); // Add the bot to our user created space return this.userWebex.memberships.create({ roomId: userCreatedTestRoom.id, - personId: flint.person.id + personId: framework.person.id }) .then((m) => { membership = m; return assert(validator.isMembership(membership), 'create memebership did not return a valid membership'); }) - // Wait for flint's membershipCreated event + // Wait for framework's membershipCreated event .then(() => when(membershipEvent) .then(() => { assert((eventsData.membership.id === membership.id), - 'Membership from flint event does not match the one returned by API'); + 'Membership from framework event does not match the one returned by API'); return when(spawned); }) - // Wait for flint's spawned event + // Wait for framework's spawned event .then(() => { userCreatedRoomBot = eventsData.bot; this.createBotEventHandlers(userCreatedRoomBot); - assert(_.find(flint.bots, bot => bot.room.id === userCreatedRoomBot.room.id), - 'After spawn new bot is not in flint\'s bot array'); + assert(_.find(framework.bots, bot => bot.room.id === userCreatedRoomBot.room.id), + 'After spawn new bot is not in framework\'s bot array'); return userCreatedRoomBot; }) .catch((e) => { @@ -117,15 +117,15 @@ module.exports = { // }); }, - botLeaveRoom: function (testName, flint, bot, roomToLeave, eventsData) { + botLeaveRoom: function (testName, framework, bot, roomToLeave, eventsData) { const membershipDeleted = new Promise((resolve) => { - this.flintMembershipDeletedHandler(testName, flint, eventsData, resolve); + this.frameworkMembershipDeletedHandler(testName, framework, eventsData, resolve); }); const stopped = new Promise((resolve) => { bot.stopHandler(testName, resolve); }); const despawned = new Promise((resolve) => { - this.flintDespawnHandler(testName, flint, eventsData, resolve); + this.frameworkDespawnHandler(testName, framework, eventsData, resolve); }); @@ -136,16 +136,16 @@ module.exports = { }); }, - botCreateRoom: function (testName, flint, bot, eventsData, members) { + botCreateRoom: function (testName, framework, bot, eventsData, members) { // Wait for the events associated with a new membership before completing test.. const roomCreated = new Promise((resolve) => { - this.flintRoomCreatedHandler(testName, flint, eventsData, resolve); + this.frameworkRoomCreatedHandler(testName, framework, eventsData, resolve); }); const membershipCreatedEvent = new Promise((resolve) => { - this.flintMembershipCreatedHandler(testName, flint, eventsData, resolve); + this.frameworkMembershipCreatedHandler(testName, framework, eventsData, resolve); }); const spawned = new Promise((resolve) => { - this.flintSpawnedHandler(testName, flint, eventsData, resolve); + this.frameworkSpawnedHandler(testName, framework, eventsData, resolve); }); return bot.newRoom(Bot_Test_Space_Title, members) @@ -158,25 +158,25 @@ module.exports = { this.createBotEventHandlers(b); return when(roomCreated); }) - // Wait for flint's membershipCreated event + // Wait for framework's membershipCreated event .then(() => { assert((eventsData.room.id == botCreatedRoomBot.room.id), - 'Room from flint roomCreated event does not match ' + + 'Room from framework roomCreated event does not match ' + 'the one in the bot returned by newRoom()'); return when(membershipCreatedEvent); }) .then(() => { assert((eventsData.membership.id === botCreatedRoomBot.membership.id), - 'Membership from flint membershipCreated event does not match ' + + 'Membership from framework membershipCreated event does not match ' + 'the one in the bot returned by newRoom()'); return when(spawned); }) - // Wait for flint's spawned event + // Wait for framework's spawned event .then(() => { assert((eventsData.bot.id == botCreatedRoomBot.id), - 'Bot from flint spawned event does not match the one returned by newRoom()'); - assert(_.find(flint.bots, bot => bot.room.id === botCreatedRoomBot.room.id), - 'After spawn new bot is not in flint\'s bot array'); + 'Bot from framework spawned event does not match the one returned by newRoom()'); + assert(_.find(framework.bots, bot => bot.room.id === botCreatedRoomBot.room.id), + 'After spawn new bot is not in framework\'s bot array'); return when(botCreatedRoomBot); }) .catch((e) => { @@ -185,18 +185,18 @@ module.exports = { }); }, - userSendMessage: function (testName, flint, userWebex, bot, eventsData, hearsInfo, markdown, files) { + userSendMessage: function (testName, framework, userWebex, bot, eventsData, hearsInfo, markdown, files) { // Check the markdown to see if there is an at-mention in the message let isMention = (_.toLower(markdown).indexOf('<@PersonId') > -1); const heard = new Promise((resolve) => { // if (!hearsInfo.priority) { - hearsInfo.functionVar = flint.hears(hearsInfo.phrase, (b, t) => { + hearsInfo.functionVar = framework.hears(hearsInfo.phrase, (b, t) => { assert((b.id === bot.id), 'bot returned in fint.hears("hi") is not the one expected'); assert(validator.objIsEqual(t, eventsData.trigger), - 'trigger returned in flint.hears("hi") was not as expected'); - flint.debug('Bot heard message "hi" that user posted'); + 'trigger returned in framework.hears("hi") was not as expected'); + framework.debug('Bot heard message "hi" that user posted'); resolve(true); }), hearsInfo.helpString, hearsInfo.priority; // }; @@ -204,18 +204,18 @@ module.exports = { // Wait for the events associated with a new message before completing test.. messageCreatedEvent = new Promise((resolve) => { - this.flintMessageCreatedEventHandler(testName, flint, eventsData, resolve); + this.frameworkMessageCreatedEventHandler(testName, framework, eventsData, resolve); }); if (isMention) { - flintMentionedEvent = new Promise((resolve) => { - this.flintMentionedHandler(testName, flint, eventsData, resolve); + frameworkMentionedEvent = new Promise((resolve) => { + this.frameworkMentionedHandler(testName, framework, eventsData, resolve); }); botMentionedEvent = new Promise((resolve) => { bot.mentionedHandler(testName, eventsData, resolve); }); } - flintMessageEvent = new Promise((resolve) => { - this.flintMessageHandler(testName, flint, eventsData, resolve); + frameworkMessageEvent = new Promise((resolve) => { + this.frameworkMessageHandler(testName, framework, eventsData, resolve); }); botMessageEvent = new Promise((resolve) => { bot.messageHandler(testName, eventsData, resolve); @@ -235,10 +235,10 @@ module.exports = { `Test:${testName} create message did not return a valid message`); // Wait for all the event handlers and the heard handler to fire if (isMention) { - return when.all([messageCreatedEvent, flintMentionedEvent, botMentionedEvent, flintMessageEvent, botMessageEvent, heard]); + return when.all([messageCreatedEvent, frameworkMentionedEvent, botMentionedEvent, frameworkMessageEvent, botMessageEvent, heard]); } else { // Don;t wait for the mentioned events.... - return when.all([messageCreatedEvent, flintMessageEvent, botMessageEvent, heard]); + return when.all([messageCreatedEvent, frameworkMessageEvent, botMessageEvent, heard]); } }) .then(() => when(message)) @@ -250,197 +250,197 @@ module.exports = { - // Flint Event Handlers + // Framework Event Handlers - flintStartHandler: function (testName, flint, promiseResolveFunction) { - this.flint.once('start', (id) => { - flint.debug(`Flint start event occurred in test ${testName}`); - promiseResolveFunction(assert(id === flint.id)); + frameworkStartHandler: function (testName, framework, promiseResolveFunction) { + this.framework.once('start', (id) => { + framework.debug(`Framework start event occurred in test ${testName}`); + promiseResolveFunction(assert(id === framework.id)); }); }, - flintInitializedHandler: function (testName, flint, promiseResolveFunction) { - this.flint.once('initialized', (id) => { - flint.debug(`Flint initiatlized event occurred in test:${testName}`); - promiseResolveFunction(assert(id === flint.id)); + frameworkInitializedHandler: function (testName, framework, promiseResolveFunction) { + this.framework.once('initialized', (id) => { + framework.debug(`Framework initiatlized event occurred in test:${testName}`); + promiseResolveFunction(assert(id === framework.id)); }); }, - flintSpawnedHandler: function (testName, flint, eventsData, promiseResolveFunction) { - this.flint.once('spawn', (bot) => { - flint.debug(`Flint spawned event occurred in test ${testName}`); + frameworkSpawnedHandler: function (testName, framework, eventsData, promiseResolveFunction) { + this.framework.once('spawn', (bot) => { + framework.debug(`Framework spawned event occurred in test ${testName}`); eventsData.bot = bot; promiseResolveFunction(assert(validator.isBot(bot), 'spawned event did not include a valid bot')); }); }, - flintRoomCreatedHandler: function (testName, flint, eventsData, promiseResolveFunction) { - this.flint.once('roomCreated', (room, id) => { - flint.debug(`Flint roomCreated event occurred in test ${testName}`); + frameworkRoomCreatedHandler: function (testName, framework, eventsData, promiseResolveFunction) { + this.framework.once('roomCreated', (room, id) => { + framework.debug(`Framework roomCreated event occurred in test ${testName}`); eventsData.room = room; - assert((id === flint.id), - 'id returned in flint.on("roomCreated") is not the one expected'); + assert((id === framework.id), + 'id returned in framework.on("roomCreated") is not the one expected'); promiseResolveFunction(assert(validator.isRoom(room), 'roomCreated event did not include a valid message')); }); }, - flintMembershipCreatedHandler: function (testName, flint, eventsData, promiseResolveFunction) { - this.flint.once('membershipCreated', (membership, id) => { - flint.debug(`Flint membershipCreated event occurred in test ${testName}`); + frameworkMembershipCreatedHandler: function (testName, framework, eventsData, promiseResolveFunction) { + this.framework.once('membershipCreated', (membership, id) => { + framework.debug(`Framework membershipCreated event occurred in test ${testName}`); eventsData.membership = membership; assert(validator.isMembership(membership), 'membershipCreated event did not include a valid membership'); - promiseResolveFunction(assert(id === flint.id)); + promiseResolveFunction(assert(id === framework.id)); }); }, - flintMembershipUpdatedHandler: function (testName, flint, eventsData, promiseResolveFunction) { - this.flint.once('membershipUpdated', (membership, id) => { - flint.debug(`Flint membershipUpdated event occurred in test ${testName}`); + frameworkMembershipUpdatedHandler: function (testName, framework, eventsData, promiseResolveFunction) { + this.framework.once('membershipUpdated', (membership, id) => { + framework.debug(`Framework membershipUpdated event occurred in test ${testName}`); eventsData.membership = membership; assert(validator.isMembership(membership), 'membershipUpdated event did not include a valid membership'); - promiseResolveFunction(assert(id === flint.id)); + promiseResolveFunction(assert(id === framework.id)); }); }, - flintMessageCreatedEventHandler: function (testName, flint, eventsData, promiseResolveFunction) { - this.flint.once('messageCreated', (message, id) => { - flint.debug(`Flint messageCreated event occurred in test ${testName}`); + frameworkMessageCreatedEventHandler: function (testName, framework, eventsData, promiseResolveFunction) { + this.framework.once('messageCreated', (message, id) => { + framework.debug(`Framework messageCreated event occurred in test ${testName}`); eventsData.message = message; - assert((id === flint.id), - 'id returned in flint.on("messageCreated") is not the one expected'); + assert((id === framework.id), + 'id returned in framework.on("messageCreated") is not the one expected'); promiseResolveFunction(assert(validator.isMessage(message), 'memssageCreated event did not include a valid message')); }); }, - flintMentionedHandler: function (testName, flint, eventsData, promiseResolveFunction) { - this.flint.once('mentioned', (bot, trigger, id) => { - flint.debug(`Flint mentioned event occurred in test ${testName}`); + frameworkMentionedHandler: function (testName, framework, eventsData, promiseResolveFunction) { + this.framework.once('mentioned', (bot, trigger, id) => { + framework.debug(`Framework mentioned event occurred in test ${testName}`); assert(validator.isBot(bot), 'mentioned event did not include a valid bot'); assert((bot.id === eventsData.bot.id), - 'bot returned in flint.on("mentioned") is not the one expected'); + 'bot returned in framework.on("mentioned") is not the one expected'); assert(validator.isTrigger(trigger), 'mentioned event did not include a valid trigger'); eventsData.trigger = trigger; - assert((id === flint.id), - 'id returned in flint.on("mentioned") is not the one expected'); + assert((id === framework.id), + 'id returned in framework.on("mentioned") is not the one expected'); promiseResolveFunction(true); }); }, - flintMessageHandler: function (testName, flint, eventsData, promiseResolveFunction) { - this.flint.once('message', (bot, trigger, id) => { - flint.debug(`Flint message event occurred in test ${testName}`); + frameworkMessageHandler: function (testName, framework, eventsData, promiseResolveFunction) { + this.framework.once('message', (bot, trigger, id) => { + framework.debug(`Framework message event occurred in test ${testName}`); assert(validator.isBot(bot), 'message event did not include a valid bot'); assert((bot.id === eventsData.bot.id), - 'bot returned in flint.on("message") is not the one expected'); + 'bot returned in framework.on("message") is not the one expected'); assert(validator.isTrigger(trigger), 'message event did not include a valid trigger'); eventsData.trigger = trigger; - assert((id === flint.id), - 'id returned in flint.on("message") is not the one expected'); + assert((id === framework.id), + 'id returned in framework.on("message") is not the one expected'); promiseResolveFunction(true); }); }, - flintFilesHandler: function (testName, flint, eventsData, promiseResolveFunction) { - this.flint.once('files', (bot, trigger, id) => { - flint.debug(`Flint files event occurred in test ${testName}`); + frameworkFilesHandler: function (testName, framework, eventsData, promiseResolveFunction) { + this.framework.once('files', (bot, trigger, id) => { + framework.debug(`Framework files event occurred in test ${testName}`); assert(validator.isBot(bot), 'files event did not include a valid bot'); assert((bot.id === eventsData.bot.id), - 'bot returned in flint.on("files") is not the one expected'); + 'bot returned in framework.on("files") is not the one expected'); assert(validator.isTrigger(trigger), 'files event did not include a valid trigger'); eventsData.trigger = trigger; - assert((id === flint.id), - 'id returned in flint.on("files") is not the one expected'); + assert((id === framework.id), + 'id returned in framework.on("files") is not the one expected'); promiseResolveFunction(true); }); }, - flintMemberEntersHandler: function (testName, flint, eventsData, promiseResolveFunction) { - this.flint.once('memberEnters', (bot, membership, id) => { - flint.debug(`Flint memberEnters event occurred in test ${testName}`); + frameworkMemberEntersHandler: function (testName, framework, eventsData, promiseResolveFunction) { + this.framework.once('memberEnters', (bot, membership, id) => { + framework.debug(`Framework memberEnters event occurred in test ${testName}`); assert(validator.isBot(bot), 'bot in memberEnters event did not include a valid bot'); assert((bot.id === eventsData.bot.id), - 'bot returned in flint.on("memberEnters") is not the one expected'); + 'bot returned in framework.on("memberEnters") is not the one expected'); // TODO validate membership - assert((id === flint.id), - 'id returned in flint.on("memberEnters") is not the one expected'); + assert((id === framework.id), + 'id returned in framework.on("memberEnters") is not the one expected'); promiseResolveFunction(true); }); }, - flintMemberAddedAsModeratorHandler: function (testName, flint, eventsData, promiseResolveFunction) { - this.flint.once('memberAddedAsModerator', (bot, membership, id) => { - flint.debug(`Flint memberAddedAsModerator event occurred in test ${testName}`); + frameworkMemberAddedAsModeratorHandler: function (testName, framework, eventsData, promiseResolveFunction) { + this.framework.once('memberAddedAsModerator', (bot, membership, id) => { + framework.debug(`Framework memberAddedAsModerator event occurred in test ${testName}`); assert(validator.isBot(bot), 'bot in memberAddedAsModerator event did not include a valid bot'); assert((bot.id === eventsData.bot.id), - 'bot returned in flint.on("memberAddedAsModerator") is not the one expected'); + 'bot returned in framework.on("memberAddedAsModerator") is not the one expected'); assert((membership.id === eventsData.membership.id), - 'membership returned in flint.on("memberAddedAsModerator") is not the one expected'); + 'membership returned in framework.on("memberAddedAsModerator") is not the one expected'); assert(validator.isMembership(membership), - 'membership returned in flint.on("memberAddedAsModerator") is not valid'); - assert((id === flint.id), - 'id returned in flint.on("personEmemberAddedAsModeratornters") is not the one expected'); + 'membership returned in framework.on("memberAddedAsModerator") is not valid'); + assert((id === framework.id), + 'id returned in framework.on("personEmemberAddedAsModeratornters") is not the one expected'); promiseResolveFunction(true); }); }, - flintMemberExitsHandler: function (testName, flint, eventsData, promiseResolveFunction) { - this.flint.once('memberExits', (bot, membership, id) => { - flint.debug(`Flint memberExits event occurred in test ${testName}`); + frameworkMemberExitsHandler: function (testName, framework, eventsData, promiseResolveFunction) { + this.framework.once('memberExits', (bot, membership, id) => { + framework.debug(`Framework memberExits event occurred in test ${testName}`); assert(validator.isBot(bot), 'bot in memberExits event did not include a valid bot'); assert((bot.id === eventsData.bot.id), - 'bot returned in flint.on("memberExits") is not the one expected'); + 'bot returned in framework.on("memberExits") is not the one expected'); assert((membership.id === eventsData.membership.id), - 'membership returned in flint.on("memberExits") is not the one expected'); + 'membership returned in framework.on("memberExits") is not the one expected'); assert(validator.isMembership(membership), - 'membership returned in flint.on("memberExits") is not valid'); - assert((id === flint.id), - 'id returned in flint.on("memberExits") is not the one expected'); + 'membership returned in framework.on("memberExits") is not valid'); + assert((id === framework.id), + 'id returned in framework.on("memberExits") is not the one expected'); promiseResolveFunction(true); }); }, - flintMembershipDeletedHandler: function (testName, flint, eventsData, promiseResolveFunction) { - this.flint.once('membershipDeleted', (membership, id) => { - flint.debug(`Flint membershipDeleted event occurred in test ${testName}`); - assert(id === flint.id); + frameworkMembershipDeletedHandler: function (testName, framework, eventsData, promiseResolveFunction) { + this.framework.once('membershipDeleted', (membership, id) => { + framework.debug(`Framework membershipDeleted event occurred in test ${testName}`); + assert(id === framework.id); assert(validator.isMembership(membership), - 'membership returned in flint.on("membershipDeleted") is not valid'); + 'membership returned in framework.on("membershipDeleted") is not valid'); eventsData.membership = membership; promiseResolveFunction(assert(validator.isMembership(membership), 'membershipDeleted event did not include a valid membership')); }); }, - flintDespawnHandler: function (testName, flint, eventsData, promiseResolveFunction) { - this.flint.once('despawn', (bot, id) => { - flint.debug(`Flint despawn event occurred in test ${testName}`); + frameworkDespawnHandler: function (testName, framework, eventsData, promiseResolveFunction) { + this.framework.once('despawn', (bot, id) => { + framework.debug(`Framework despawn event occurred in test ${testName}`); assert(eventsData.bot.id === bot.id); eventsData.leftRoomId = bot.room.id; - assert((id === flint.id), - 'id returned in flint.on("despawn") is not the one expected'); + assert((id === framework.id), + 'id returned in framework.on("despawn") is not the one expected'); promiseResolveFunction(assert(validator.isBot(bot), 'despawn event did not include a valid bot')); }); }, - flintStopHandler: function (testName, flint, promiseResolveFunction) { - this.flint.once('stop', (id) => { - flint.debug(`Flint stop event occurred in test ${testName}`); - promiseResolveFunction(assert(id === flint.id)); + frameworkStopHandler: function (testName, framework, promiseResolveFunction) { + this.framework.once('stop', (id) => { + framework.debug(`Framework stop event occurred in test ${testName}`); + promiseResolveFunction(assert(id === framework.id)); }); }, @@ -448,7 +448,7 @@ module.exports = { createBotEventHandlers: function (activeBot) { activeBot.mentionedHandler = function (testName, eventsData, promiseResolveFunction) { activeBot.once('mentioned', (bot, trigger, id) => { - this.flint.debug(`Bot mentioned event occurred in test ${testName}`); + this.framework.debug(`Bot mentioned event occurred in test ${testName}`); assert(validator.isBot(bot), 'mentioned event did not include a valid bot'); assert((bot.id === activeBot.id), @@ -456,14 +456,14 @@ module.exports = { assert(validator.isTrigger(trigger), 'mentioned event did not include a valid trigger'); assert((id === activeBot.id), - 'id returned in flint.on("mentioned") is not the one expected'); + 'id returned in framework.on("mentioned") is not the one expected'); promiseResolveFunction(true); }); }, activeBot.messageHandler = function (testName, eventsData, promiseResolveFunction) { activeBot.once('message', (bot, trigger, id) => { - this.flint.debug(`Bot message event occurred in test ${testName}`); + this.framework.debug(`Bot message event occurred in test ${testName}`); assert(validator.isBot(bot), 'message event did not include a valid bot'); assert((bot.id === activeBot.id), @@ -471,14 +471,14 @@ module.exports = { assert(validator.isTrigger(trigger), 'message event did not include a valid trigger'); assert((id === activeBot.id), - 'id returned in flint.on("message") is not the one expected'); + 'id returned in framework.on("message") is not the one expected'); promiseResolveFunction(true); }); }; activeBot.filesHandler = function (testName, eventsData, promiseResolveFunction) { activeBot.once('files', (bot, trigger, id) => { - this.flint.debug(`Bot files event occurred in test ${testName}`); + this.framework.debug(`Bot files event occurred in test ${testName}`); assert(validator.isBot(bot), 'files event did not include a valid bot'); assert((bot.id === activeBot.id), @@ -486,59 +486,59 @@ module.exports = { assert(validator.isTrigger(trigger), 'files event did not include a valid trigger'); assert((id === activeBot.id), - 'id returned in flint.on("files") is not the one expected'); + 'id returned in framework.on("files") is not the one expected'); promiseResolveFunction(true); }); }; activeBot.memberEntersHandler = function (testName, eventsData, promiseResolveFunction) { activeBot.once('memberEnters', (bot, membership) => { - this.flint.debug(`Bot memberEnters event occurred in test ${testName}`); + this.framework.debug(`Bot memberEnters event occurred in test ${testName}`); assert(validator.isBot(bot), 'bot memberEnters event did not include a valid bot'); assert((bot.id === activeBot.id), 'bot returned in bot.on("memberEnters") is not the one expected'); assert((membership.id === eventsData.membership.id), - 'membership returned in flint.on("memberEnters") is not the one expected'); + 'membership returned in framework.on("memberEnters") is not the one expected'); assert(validator.isMembership(membership), - 'membership returned in flint.on("memberEnters") is not valid'); + 'membership returned in framework.on("memberEnters") is not valid'); promiseResolveFunction(true); }); }; activeBot.memberAddedAsModerator = function (testName, eventsData, promiseResolveFunction) { activeBot.once('memberAddedAsModerator', (bot, membership) => { - this.flint.debug(`Bot memberAddedAsModerator event occurred in test ${testName}`); + this.framework.debug(`Bot memberAddedAsModerator event occurred in test ${testName}`); assert(validator.isBot(bot), 'bot memberAddedAsModerator event did not include a valid bot'); assert((bot.id === activeBot.id), 'bot returned in bot.on("memberAddedAsModerator") is not the one expected'); assert((membership.id === eventsData.membership.id), - 'membership returned in flint.on("memberAddedAsModerator") is not the one expected'); + 'membership returned in framework.on("memberAddedAsModerator") is not the one expected'); assert(validator.isMembership(membership), - 'membership returned in flint.on("memberAddedAsModerator") is not valid'); + 'membership returned in framework.on("memberAddedAsModerator") is not valid'); promiseResolveFunction(true); }); }; activeBot.memberExitsHandler = function (testName, eventsData, promiseResolveFunction) { activeBot.once('memberExits', (bot, membership) => { - this.flint.debug(`Bot memberExits event occurred in test ${testName}`); + this.framework.debug(`Bot memberExits event occurred in test ${testName}`); assert(validator.isBot(bot), 'bot memberExits event did not include a valid bot'); assert((bot.id === activeBot.id), 'bot returned in bot.on("memberExits") is not the one expected'); assert((membership.id === eventsData.membership.id), - 'membership returned in flint.on("memberExits") is not the one expected'); + 'membership returned in framework.on("memberExits") is not the one expected'); assert(validator.isMembership(membership), - 'membership returned in flint.on("memberExits") is not valid'); + 'membership returned in framework.on("memberExits") is not valid'); promiseResolveFunction(true); }); }; activeBot.stopHandler = function (testName, promiseResolveFunction) { activeBot.once('stop', (bot) => { - this.flint.debug(`Bot stop event occurred in test ${testName}`); + this.framework.debug(`Bot stop event occurred in test ${testName}`); assert(validator.isBot(bot), 'bot event did not include a valid bot'); assert((bot.id === activeBot.id), @@ -548,12 +548,12 @@ module.exports = { }; }, - // Additional flint events to-do + // Additional framework events to-do // attachmentAction // files (and for bot) // Common variables - // flint: this.flint, + // framework: this.framework, // userWebex: this.userWebex, User_Test_Space_Title: User_Test_Space_Title, Bot_Test_Space_Title: Bot_Test_Space_Title, @@ -571,18 +571,18 @@ module.exports = { // Delete spaces leftover from previous test runs // Aslo Check if the test bot already has a 1-1 space with the test user -function cleanupFromPreviousTests(flint, user) { +function cleanupFromPreviousTests(framework, user) { botForUser1on1Space = null; - for (let bot of flint.bots) { + for (let bot of framework.bots) { assert(validator.isBot(bot), - 'bot in flint.bots did not validate preoprly!'); + 'bot in framework.bots did not validate preoprly!'); if ((bot.room.title === User_Test_Space_Title) || (bot.room.title === Bot_Test_Space_Title)) { - flint.debug('Removing room left over from previous test...'); - flint.webex.rooms.remove(bot.room); + framework.debug('Removing room left over from previous test...'); + framework.webex.rooms.remove(bot.room); } else if (bot.room.type == 'direct') { if (bot.isDirectTo == user.emails[0]) { - flint.debug(`Found existing direct space with ${bot.room.title}. Will run direct message tests.`); + framework.debug(`Found existing direct space with ${bot.room.title}. Will run direct message tests.`); botForUser1on1Space = bot; } } @@ -596,7 +596,7 @@ function asUserCeanupFromPreviousTests(userWebex) { for (let room of rooms.items) { if ((room.title === User_Test_Space_Title) || (room.title === Bot_Test_Space_Title)) { - flint.debug('As user, removing room left over from previous test...'); + framework.debug('As user, removing room left over from previous test...'); userWebex.rooms.remove(room); } } diff --git a/test/common/framework-functions.js b/test/common/framework-functions.js new file mode 100644 index 0000000..9e7421e --- /dev/null +++ b/test/common/framework-functions.js @@ -0,0 +1,25 @@ +// Variables an functions shared by all tests +var common = require("./common"); +let framework = common.framework; +let assert = common.assert; +let validator = common.validator; +let when = common.when; + + +describe('#Framework API Checks', () => { + it('framework.getPerson("me") returns info about my bot', () => framework.getPerson('me') + .then((person) => { + let bot = person; + return when(validator.objIsEqual(bot, framework.person), + 'bot.getPerson(\'me\') does not match framework.person'); + })); + + it('returns an array of spaces', () => framework.getRooms() + .then((rooms) => { + let roomList = rooms; + // We have a bot for each existing room + assert(roomList.length === framework.bots.length); + return when(assert(validator.isRooms(rooms), + 'getRooms did not return a list of rooms')); + })); +}); \ No newline at end of file diff --git a/test/integration-tests.js b/test/integration-tests.js index 27d4468..8044480 100644 --- a/test/integration-tests.js +++ b/test/integration-tests.js @@ -1,27 +1,27 @@ /* integration-tests.js * - * A set of tests to validate flint functionality - * when flint is created using an authorized user token + * A set of tests to validate framework functionality + * when framework is created using an authorized user token */ -const Flint = require('../lib/flint'); +const Framework = require('../lib/framework'); const Webex = require('webex'); console.log('Starting integration-tests...'); -// Initialize the flint and user objects once for all the tests -// TODO support another Env variable for emails of users to add to a space in order to test flint batch APIs -let flint, userWebex; +// Initialize the framework and user objects once for all the tests +// TODO support another Env variable for emails of users to add to a space in order to test framework batch APIs +let framework, userWebex; // Read in environment variables require('dotenv').config(); environmentEvaluated = true; if ((typeof process.env.AUTHORIZED_FLINT_USER_API_TOKEN === 'string') && (typeof process.env.USER_API_TOKEN === 'string') && (typeof process.env.HOSTED_FILE === 'string')) { - flint = new Flint({ token: process.env.AUTHORIZED_FLINT_USER_API_TOKEN }); + framework = new Framework({ token: process.env.AUTHORIZED_FLINT_USER_API_TOKEN }); userWebex = new Webex({ credentials: process.env.USER_API_TOKEN }); } else { console.error('Missing required evnvironment variables:\n' + - '- AUTHORIZED_FLINT_USER_API_TOKEN -- token associatd with a user who authorized a flint based integrationt\n' + + '- AUTHORIZED_FLINT_USER_API_TOKEN -- token associatd with a user who authorized a framework based integrationt\n' + '- USER_API_TOKEN -- token associated with an existing user that integration will interact with\n' + '- HOSTED_FILE -- url to a file that can be attached to test messages\n' + 'The tests will create a new space with the bot and the user'); @@ -32,16 +32,16 @@ if ((typeof process.env.AUTHORIZED_FLINT_USER_API_TOKEN === 'string') && // Load the common module which includes functions and variables // shared by multiple tests var common = require("./common/common"); -common.setFlint(flint); +common.setFramework(framework); common.setUser(userWebex); -// Start up an instance of flint that we will use across multiple tests -describe('#flint', () => { - // Validate that flint starts and that we have a valid user - before(() => common.initFlint('flint init', flint, userWebex)); +// Start up an instance of framework that we will use across multiple tests +describe('#framework', () => { + // Validate that framework starts and that we have a valid user + before(() => common.initFramework('framework init', framework, userWebex)); - //Stop flint to shut down the event listeners - after(() => common.stopFlint('shutdown flint', flint)); + //Stop framework to shut down the event listeners + after(() => common.stopFramework('shutdown framework', framework)); // Test app interactions in a user created test space require('./as-user/user-created-room-tests.js'); @@ -59,8 +59,8 @@ describe('#flint', () => { // gracefully shutdown (ctrl-c) process.on('SIGINT', function () { - flint.debug('stoppping...'); - flint.stop().then(function () { + framework.debug('stoppping...'); + framework.stop().then(function () { process.exit(); }); });