@zoomus/chatbot
Advanced tools
Comparing version 0.3.16 to 1.0.0
@@ -1,81 +0,3 @@ | ||
## 0.0.6 | ||
## 1.0.0 | ||
* feature:COMMAND:integrate help command with lib | ||
* feature:CLIENT:client add command Event,and get IM account type,and specific command name | ||
## 0.1.0 | ||
* feature:CLIENT:abandon command api(exit,no longer maintained),add commands api,and replace options to hint | ||
* feature:CLIENT:no version api(no longer maintained) | ||
* feature:MESSAGE:listen commands(no command,command exit,no longer maintained),parse command arguments to data,origin data to payload | ||
* rich readme | ||
## 0.1.2 | ||
* feature:CLIENT:add parse method | ||
## 0.1.3 | ||
* change readme.md | ||
## 0.1.5 | ||
* feature:handle add promise method,you can use handle(opt).then((data)=>{}).catch((e)=>{}),old handle(opt,callback)//also can be used | ||
* feature:add checkCommands,triggerHelp,configurate({help:true,errorHelp:false}), | ||
* feature:add default error trigger help | ||
## 0.1.6 | ||
* feature:add debug,add request method | ||
## 0.1.8 | ||
* feature: add actions event,more help command style | ||
## 0.1.9 | ||
* feature: add messages event which scope > commands,and messages||commands only runs one at a time | ||
## 0.1.10 | ||
* feature: readme change | ||
## 0.1.11 | ||
* feature: callback error hint in handle callback add type&&errorMessage | ||
## 0.1.12 | ||
* change readme | ||
## 0.1.15 | ||
* fix lambda stack exit early before event commit | ||
## 0.1.16 | ||
* fit to lambda async step | ||
## 0.1.17 | ||
* pre for actions | ||
## 0.2.1 | ||
* add settings for sendMessage | ||
## 0.2.2 | ||
* add field_edit action type | ||
## 0.2.3 | ||
* prototype connect fix | ||
## 0.2.4 | ||
* support retry | ||
## 0.2.5 | ||
* sendmessage can use content,add expires_date in setTokens | ||
## 0.2.6 | ||
* change readme | ||
## 0.2.7 | ||
* case sensitive | ||
## 0.2.7 | ||
* case sensitive | ||
## 0.2.9 | ||
* let sendmessage tranform any paras,and also support body,header single send. | ||
## 0.3.10 | ||
* change readme | ||
use log,change the readme |
{ | ||
"name": "@zoomus/chatbot", | ||
"version": "0.3.16", | ||
"version": "1.0.0", | ||
"description": "Zoom Node.js Chatbot Library", | ||
@@ -16,6 +16,6 @@ "keywords": [ | ||
"scripts": { | ||
"eslint-fix": "eslint src/** --fix", | ||
"start": "node -r source-map-support/register ./@env/start.js", | ||
"build": "node ./@env/build.js", | ||
"test-dev": "NODE_ENV=dev mocha ./tests/index.*.js", | ||
"test-prod": "NODE_ENV=prod mocha ./tests/index.*.js", | ||
"test": "jest --config ./jest.config.js", | ||
"example1": "cd example && node -r source-map-support/register ./message.js", | ||
@@ -36,4 +36,7 @@ "example2": "cd example && node -r source-map-support/register ./oauthMessage.js", | ||
"devDependencies": { | ||
"@babel/core": "^7.3.3", | ||
"@babel/core": "^7.8.4", | ||
"@babel/preset-env": "^7.8.4", | ||
"babel-jest": "^25.1.0", | ||
"babel-plugin-add-module-exports": "^1.0.0", | ||
"babel-plugin-rewire": "^1.2.0", | ||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", | ||
@@ -53,11 +56,14 @@ "body-parser": "^1.18.3", | ||
"gulp-sourcemaps": "^2.6.4", | ||
"jest": "^25.1.0", | ||
"mocha": "^5.2.0", | ||
"rewire": "^4.0.1", | ||
"source-map-support": "^0.5.10" | ||
}, | ||
"dependencies": { | ||
"abort-controller": "^3.0.0", | ||
"node-fetch": "^2.6.0", | ||
"date-fns": "^1.30.1", | ||
"debug": "^4.1.1", | ||
"delay": "^4.2.0", | ||
"request": "^2.88.0" | ||
"delay": "^4.2.0" | ||
} | ||
} |
@@ -23,2 +23,6 @@ "use strict"; | ||
var _log = require("../services/log"); | ||
var _log2 = _interopRequireDefault(_log); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -164,3 +168,3 @@ | ||
this.config = { | ||
help: true, | ||
help: false, | ||
errorHelp: false | ||
@@ -362,2 +366,11 @@ }; | ||
if (out.status === false) { | ||
_log2.default.run({ | ||
type: 'error_notice', | ||
message: { | ||
error: out.errorMessage | ||
} | ||
}); | ||
} | ||
return out; | ||
@@ -364,0 +377,0 @@ } |
@@ -21,6 +21,6 @@ "use strict"; | ||
if (str.indexOf(kw) !== -1) { | ||
return 'group'; | ||
return 'channel'; | ||
} | ||
return 'one'; | ||
return 'bot'; | ||
}, | ||
@@ -27,0 +27,0 @@ |
@@ -15,6 +15,2 @@ "use strict"; | ||
var _branch = require("./branch"); | ||
var _branch2 = _interopRequireDefault(_branch); | ||
var _Event = require("./Event"); | ||
@@ -40,3 +36,2 @@ | ||
request: _request2.default, | ||
branch: _branch2.default, | ||
Event: _Event2.default, | ||
@@ -43,0 +38,0 @@ Store: _store2.default, |
@@ -7,10 +7,6 @@ "use strict"; | ||
var _request = require("request"); | ||
var _nodeFetch = require("node-fetch"); | ||
var _request2 = _interopRequireDefault(_request); | ||
var _nodeFetch2 = _interopRequireDefault(_nodeFetch); | ||
var _querystring = require("querystring"); | ||
var _querystring2 = _interopRequireDefault(_querystring); | ||
var _debug = require("./debug"); | ||
@@ -24,9 +20,32 @@ | ||
var _abortController = require("abort-controller"); | ||
var _abortController2 = _interopRequireDefault(_abortController); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
// import querystring from 'querystring'; | ||
let errorHandle = (logDataOption, errorInfo, reject) => { | ||
_log2.default.run({ | ||
type: 'http', | ||
message: { | ||
request: logDataOption, | ||
response: null, | ||
error: errorInfo | ||
} | ||
}); | ||
_log2.default.run({ | ||
type: 'error_notice', | ||
message: { | ||
error: errorInfo | ||
} | ||
}); | ||
reject(Object.assign({}, errorInfo)); | ||
}; | ||
let requestWrap = opt => { | ||
let { | ||
body, | ||
formData, | ||
form, | ||
method = 'get', | ||
@@ -36,79 +55,98 @@ url, | ||
query = {}, | ||
cookie, | ||
timeout | ||
} = opt; | ||
return new Promise((resolve, reject) => { | ||
let type, data; | ||
if (typeof body === 'object') { | ||
type = 'body', data = body; | ||
} else if (typeof formData === 'object') { | ||
type = 'formData', data = formData; | ||
} else if (typeof form === 'object') { | ||
type = 'form', data = form; | ||
body = JSON.stringify(body); | ||
} | ||
let dataOption = { | ||
qs: query, | ||
method, | ||
headers, | ||
url, | ||
method | ||
body | ||
}; | ||
let timeoutResult = null; | ||
if (type) { | ||
dataOption[type] = data; | ||
if (typeof timeout === 'number') { | ||
const controller = new _abortController2.default(); | ||
timeoutResult = setTimeout(() => { | ||
controller.abort(); | ||
}, timeout); | ||
} | ||
if (type === 'body') { | ||
dataOption.json = true; | ||
if (typeof query === 'object') { | ||
let urlObject = new URL(url); | ||
Object.keys(query).forEach(name => { | ||
urlObject.searchParams.set(name, query[name]); | ||
}); | ||
url = urlObject.href; | ||
} | ||
if (typeof cookie === 'object') { | ||
let j = _request2.default.jar(); | ||
let logDataOption = Object.assign({ | ||
url | ||
}, dataOption); | ||
(0, _debug2.default)('http')(logDataOption); | ||
let nodefeatchResult = (0, _nodeFetch2.default)(url, dataOption).then(res => { | ||
let status = res.status; | ||
res.text().then(responseBody => { | ||
let responseText = responseBody; | ||
let cookieRequest = _request2.default.cookie(_querystring2.default.stringify(cookie)); | ||
if (typeof responseBody === 'string') { | ||
try { | ||
responseBody = JSON.parse(responseBody); | ||
} catch (e) { | ||
errorHandle(logDataOption, { | ||
type: 'parseError', | ||
status, | ||
message: responseText | ||
}, reject); | ||
return; | ||
} | ||
} | ||
j.setCookie(cookieRequest, url); | ||
dataOption.jar = j; | ||
} | ||
if (status >= 200 && status < 300) { | ||
//success | ||
_log2.default.run({ | ||
type: 'http', | ||
message: { | ||
request: logDataOption, | ||
response: { | ||
status, | ||
body: responseBody | ||
}, | ||
error: null | ||
} | ||
}); | ||
(0, _debug2.default)('http')(dataOption); | ||
if (typeof timeout === 'number') { | ||
dataOption.timeout = timeout; | ||
} | ||
(0, _request2.default)(dataOption, function (error, response) { | ||
_log2.default.run({ | ||
type: 'http', | ||
message: { | ||
request: dataOption, | ||
response, | ||
error | ||
resolve({ | ||
status, | ||
body: responseBody | ||
}); | ||
} else { | ||
//success but status fail | ||
errorHandle(logDataOption, { | ||
status: status, | ||
message: responseBody | ||
}, reject); | ||
return; | ||
} | ||
}).catch(e => { | ||
//promise all error | ||
errorHandle(logDataOption, { | ||
type: 'parseError', | ||
status, | ||
message: e | ||
}, reject); | ||
return; | ||
}); | ||
}).catch(e => { | ||
//request error | ||
errorHandle(logDataOption, e, reject); | ||
}); | ||
if (error) { | ||
reject(error); | ||
} else { | ||
let code = response.statusCode; | ||
let oldBody = response.body; | ||
let newBody; | ||
try { | ||
newBody = JSON.parse(oldBody); | ||
} catch (e) { | ||
newBody = oldBody; | ||
} | ||
if (code >= 300) { | ||
reject(newBody); | ||
} else { | ||
response.body = newBody; | ||
resolve(response); | ||
} // response.body=newBody; | ||
// resolve(response); | ||
} | ||
}); | ||
if (timeoutResult !== null) { | ||
nodefeatchResult.finally(() => { | ||
clearTimeout(timeoutResult); | ||
}); | ||
} | ||
}); | ||
@@ -115,0 +153,0 @@ }; |
424
README.md
@@ -5,4 +5,2 @@ # Zoom Node.js Chatbot Library | ||
To get started follow the [instructions](#installation) and [examples](#examples) below, or checkout the [sample app](#sample-app). | ||
## Installation | ||
@@ -12,21 +10,16 @@ | ||
`$ npm install @zoomus/chatbot --save` | ||
## Setup | ||
Import [@zoomus/chatbot](https://www.npmjs.com/package/@zoomus/chatbot) into your app. | ||
```js | ||
const { oauth2, client } = require('@zoomus/chatbot'); | ||
``` | ||
$ npm install @zoomus/chatbot --save | ||
const { oauth2, client, setting, log } = require('@zoomus/chatbot'); | ||
``` | ||
## Log | ||
```js | ||
const {log} = require('@zoomus/chatbot'); | ||
log(function(info){ | ||
let {type,message}=info; | ||
if(type==='http'){ | ||
let {request,error,response}=message; | ||
const { oauth2, client, setting, log } = require('@zoomus/chatbot'); | ||
//we have two type log of info,one is {type:'http',{error,request,response}},another is {type:'error_notice',message:{error}} this error include http error/webhook data error. | ||
log(function(info) { | ||
let { type, message } = info; | ||
if (type === 'http') { | ||
let { request, error, response } = message; //response:{status,body},request:{body,url,headers,method} | ||
//handle log info; | ||
@@ -37,44 +30,62 @@ } | ||
### SendMessage Chatbot Message | ||
## Authentication | ||
```js | ||
const { oauth2, client, setting, log } = require('@zoomus/chatbot'); | ||
const oauth2Client = oauth2('{{ CLIENT_ID }}', '{{ CLIENT_SECRET }}'); | ||
let chatbot = client( | ||
'{{ CLIENT_ID }}', | ||
'{{ VERIFICATION_TOKEN }}', | ||
'{{ BOT_JID }}' | ||
).defaultAuth(oauth2Client.connect()); | ||
let zoomApp = chatbot.create({ auth: oauth2Client.connect() }); | ||
await zoomApp.sendMessage({ | ||
to_jid: 'to_jid: can get from webhook response or GET /users/{userID}', | ||
account_id: | ||
'account_id: can get from webhook response or from JWT parsed access_token or GET /users/{userID}', | ||
content: { | ||
head: { | ||
text: 'Hello World' | ||
} | ||
} | ||
}); | ||
``` | ||
There are two options for authenticating your Chatbot. | ||
### Get ZOOM IM channel message | ||
1. The [Chatbot Credentials Flow](#chatbot-credentials-flow) for just [sending Chatbot messages](#sending-chatbot-messages). | ||
Or | ||
2. The [OAuth2 Credentials Flow](#oauth2-credentials-flow) for [sending Chatbot messages](#sending-chatbot-messages) AND [calling the Zoom APIs](#calling-the-zoom-apis). | ||
> NOTE: The OAuth2 Credentials Flow flow requires a database. | ||
### Chatbot Credentials Flow | ||
```js | ||
const oauth2Client = oauth2('{{ CLIENT_ID }}', '{{ CLIENT_SECRET }}'); | ||
const { oauth2, client, setting, log } = require('@zoomus/chatbot'); | ||
let chatbot = client('{{ CLIENT_ID }}', '{{ VERIFICATION_TOKEN }}', '{{ BOT_JID }}') | ||
.commands([{ command: '{{ SLASH_COMMAND }}', hint: '<command parameter>', description: 'This is what my chatbot does' }]) | ||
.configurate({ help: true, errorHelp: false }) | ||
.defaultAuth(oauth2Client.connect()); | ||
app.post('/webhook',async function(req,res){ | ||
try{ | ||
let data = await chatbot.handle({ body, headers }); | ||
let { event, command?,type, payload } = data;//if this is slash from zoom im,just like /help,command will be help | ||
// we have type 'channel'|'bot', channel express this message from IM channel,bot express this message from the bot which you installed | ||
//payload details please see zoom https://marketplace.zoom.us/docs/guides/chatbots/customizing-messages/message-with-dropdown | ||
//we have slash event = 'bot_notification'; | ||
// we have action event = 'interactive_message_select'|'interactive_message_actions'|'interactive_message_editable'|'interactive_message_fields_editable' | ||
} | ||
catch(e){ | ||
// | ||
} | ||
}); | ||
app.get('/authorize', async (req, res) => { | ||
res.send('Thanks for installing!') | ||
}) | ||
let app = chatbot.create({ auth: oauth2Client.connect() }) | ||
``` | ||
See below for an example of [sending a message after receiving a users slash command.](#sending-a-message-after-receiving-a-users-slash-command) | ||
### OAuth2 Credentials Flow(prepare for request zoom openapi) | ||
### OAuth2 Credentials Flow | ||
```js | ||
const oauth2Client = oauth2('{{ CLIENT_ID }}', '{{ CLIENT_SECRET }}', '{{ REDIRECT_URI }}'); | ||
const { oauth2, client, setting, log } = require('@zoomus/chatbot'); | ||
const oauth2Client = oauth2( | ||
'{{ CLIENT_ID }}', | ||
'{{ CLIENT_SECRET }}', | ||
'{{ REDIRECT_URI }}' | ||
); | ||
let chatbot = client( | ||
'{{ CLIENT_ID }}', | ||
'{{ VERIFICATION_TOKEN }}', | ||
'{{ BOT_JID }}' | ||
).defaultAuth(oauth2Client.connect()); | ||
let chatbot = client('{{ CLIENT_ID }}', '{{ VERIFICATION_TOKEN }}', '{{ BOT_JID }}') | ||
.commands([{ command: '{{ SLASH_COMMAND }}', hint: '<command parameter>', description: 'This is what my chatbot does' }]) | ||
.configurate({ help: true, errorHelp: false }) | ||
.defaultAuth(oauth2Client.connect()); | ||
let middleZoomAuth = async (req, res, next) => { | ||
@@ -84,60 +95,57 @@ let { code } = req.query; | ||
let connection = await oauth2Client.connectByCode(code); | ||
let zoomApp = chatbot.create({ auth:connection }); | ||
let zoomApp = chatbot.create({ auth: connection }); //this is the first store tokens,zoomApp have already inject tokens by connection.you can use zoomApp to request zoom openapi | ||
res.locals.zoomApp = zoomApp; | ||
next(); | ||
} catch (error) { | ||
console.log(error); | ||
res.send(error); | ||
} | ||
catch(error) { | ||
console.log(error) | ||
res.send(error) | ||
} | ||
}; | ||
app.get('/authorize', middleZoomAuth, async (req, res) => { | ||
res.send('Thanks for installing!') | ||
res.send('Thanks for installing!'); | ||
let { zoomApp } = res.locals; | ||
let tokens = zoomApp.auth.getTokens(); | ||
// save tokens to db | ||
db.set('access_token') | ||
db.set('refresh_token') | ||
db.set('expires_in') | ||
// db.set('access_token'); | ||
// db.set('refresh_token'); | ||
// db.set('expires_in'); | ||
}); | ||
``` | ||
#### Setting Tokens | ||
#### Request Zoom Open Api and Refreshing the Access Token(must do oauth2 first) | ||
Get your access_token, refresh_token, and expires_in timestamp from your database and pass them into the `auth.setTokens()` function to allow `zoomApp` to make authenticated requests. | ||
If the access_token is expired, this function will request a new access_token, so you can update the tokens in your `zoomApp` instance and database. | ||
```js | ||
zoomApp.auth.setTokens({ | ||
// get tokens from database | ||
access_token: db.get('access_token'), | ||
refresh_token: db.get('refresh_token'), | ||
expires_in: db.get('expires_in') | ||
//see OAuth2 Credentials Flow for zoomApp | ||
let zoomApp = chatbot.create({ auth:connection });//zoomApp.auth is same with connection variable | ||
zoomApp.auth.setTokens({//get tokens from database and set into zoomApp | ||
access_token: item.get('zoom_access_token'), | ||
refresh_token: item.get('zoom_refresh_token'), | ||
expires_date: item.get('zoom_access_token_expire_time') | ||
}); | ||
zoomApp.auth.callbackRefreshTokens((tokens) => {// when request v2/users/me fail by accesstoken expired,this function will be called,you can save new access_token in database. and then will auto call request /v2/users/me again | ||
try { | ||
await databaseModels.zoom.update({ | ||
access_token:tokens.access_token | ||
refresh_token:tokens.refresh_token, | ||
expires_date: moment().add( tokens.expires_in, 'seconds' ).format | ||
}); | ||
} catch (e) { | ||
console.log(e); | ||
} | ||
}); | ||
//you can also catch the request error,and refresh access_token by your self. | ||
// await zoomApp.auth.requestTokensByRefresh(refreshToken); for refresh new access_token | ||
await zoomApp.request({url:'/v2/users/me', method:'get'}); | ||
``` | ||
#### Refreshing the Access Token | ||
### case sensitive in zoom IM message,default false | ||
If the access_token is expired, this function will request a new access_token, so you can update the tokens in your `zoomApp` instance and database. | ||
```js | ||
zoomApp.auth.callbackRefreshTokens((tokens) => { | ||
zoomApp.auth.setTokens({ | ||
access_token: tokens.access_token, | ||
refresh_token: tokens.refresh_token, | ||
expires_in: tokens.expires_in | ||
}); | ||
// save new tokens to db | ||
db.set('access_token') | ||
db.set('refresh_token') | ||
db.set('expires_in') | ||
}); | ||
setting.caseSensitive(false); //in zoom IM ,type help is same with Help | ||
``` | ||
See below for an example of [calling the Zoom API and sending a message after receiving a users slash command.](#calling-the-zoom-api-and-sending-a-message-after-receiving-a-users-slash-command) | ||
## Slash Commands and User Actions | ||
@@ -149,256 +157,6 @@ | ||
### Receiving Slash Commands and User Actions | ||
## Need Support? | ||
This express post route will receive all user commands and actions, and handle them by passing the request data to the event handler. Based on if the event is a command or action, the respective event listener function will be called. | ||
```js | ||
app.post('/webhook', async (req, res) => { | ||
let { body, headers } = req | ||
try { | ||
await chatbot.handle({ body, headers }) | ||
res.status(200) | ||
res.send() | ||
} catch (error) { | ||
console.log(error) | ||
res.send(error) | ||
} | ||
}) | ||
``` | ||
### Handling Slash Commands | ||
When the user types a slash command the `chatbot.on('commands')` function will be called. | ||
```js | ||
chatbot.on('commands', async (event) => { | ||
console.log(event) | ||
// app logic here | ||
}) | ||
``` | ||
### Handling User Actions | ||
When the user interacts with the [Editable Text](https://marketplace.zoom.us/docs/guides/chatbots/customizing-messages/message-with-editable-text), [Form Field](https://marketplace.zoom.us/docs/guides/chatbots/customizing-messages/message-with-form-field), [Dropdown](https://marketplace.zoom.us/docs/guides/chatbots/customizing-messages/message-with-dropdown), or [Buttons](https://marketplace.zoom.us/docs/guides/chatbots/customizing-messages/message-with-buttons) message types, the `chatbot.on('actions')` function will be called. | ||
```js | ||
chatbot.on('actions', async (event) => { | ||
console.log(event) | ||
// app logic here | ||
}) | ||
``` | ||
## Sending Chatbot Messages | ||
To send a Chatbot message, first create an auth connection. Then, call the `zoomApp.sendMessage()` function, passing in a [Chatbot message object](https://marketplace.zoom.us/docs/guides/chatbots/customizing-messages#base-json-structure). | ||
```js | ||
let zoomApp = chatbot.create({ auth: oauth2Client.connect() }); | ||
zoomApp.sendMessage({ | ||
to_jid: 'to_jid: can get from webhook response or GET /users/{userID}', | ||
account_id: 'account_id: can get from webhook response or from JWT parsed access_token or GET /users/{userID}', | ||
content: { | ||
head: { | ||
text: 'Hello World' | ||
} | ||
} | ||
}).then((data) => { | ||
console.log(data) | ||
}).catch((error) => { | ||
console.log(error) | ||
}) | ||
``` | ||
## Calling the Zoom APIs | ||
To call the Zoom API's, first create an auth connection. Then, call the `zoomApp.request()` function, passing in a respective url, method, and body from one of our [API endpoints](https://marketplace.zoom.us/docs/api-reference/introduction). | ||
```js | ||
let zoomApp = chatbot.create({ auth: oauth2Client.connect() }); | ||
zoomApp.auth.setTokens({ | ||
access_token: 'get from database', | ||
refresh_token: 'get from database', | ||
expires_in: 'get from database' | ||
}); | ||
zoomApp.auth.callbackRefreshTokens((tokens) => { | ||
zoomApp.auth.setTokens({ | ||
access_token: tokens.access_token, | ||
refresh_token: tokens.refresh_token, | ||
expires_in: tokens.expires_in | ||
}); | ||
// save new tokens to db | ||
db.set('access_token') | ||
db.set('refresh_token') | ||
db.set('expires_in') | ||
}); | ||
zoomApp.request({ | ||
url:'/v2/users/me', | ||
method:'get', | ||
}).then((data) => { | ||
console.log(data) | ||
}).catch((error) => { | ||
console.log(error) | ||
}) | ||
``` | ||
> NOTE: To call the Zoom API's you must authenticate your Chatbot via the [OAuth2 Credentials Flow](#oauth2-credentials-flow). | ||
## Examples | ||
### Sending a message after receiving a users slash command. | ||
In Zoom Chat type `/slashcommand Hello World`. You will see a message that reads `You said Hello World`. | ||
```js | ||
app.post('/webhook', async (req, res) => { | ||
let { body, headers } = req | ||
try { | ||
await chatbot.handle({ body, headers }) | ||
res.status(200) | ||
res.send() | ||
} catch (error) { | ||
console.log(error) | ||
res.send(error) | ||
} | ||
}) | ||
chatbot.on('commands', async (event) => { | ||
console.log(event) | ||
let zoomApp = chatbot.create({ auth: oauth2Client.connect() }); | ||
zoomApp.sendMessage({ | ||
to_jid: event.payload.toJid, | ||
account_id: event.payload.accountId, | ||
content: { | ||
head: { | ||
text: 'You said ' + event.message | ||
} | ||
} | ||
}).then((data) => { | ||
console.log(data) | ||
}).catch((error) => { | ||
console.log(error) | ||
}) | ||
}) | ||
``` | ||
### Calling the Zoom API and sending a message after receiving a users slash command. | ||
In Zoom Chat type `/slashcommand email`. You will see a message that contains information about the user on your account whose email you entered. | ||
```js | ||
app.post('/webhook', async (req, res) => { | ||
let { body, headers } = req | ||
try { | ||
await chatbot.handle({ body, headers }) | ||
res.status(200) | ||
res.send() | ||
} catch (error) { | ||
console.log(error) | ||
res.send(error) | ||
} | ||
}) | ||
chatbot.on('commands', async (event) => { | ||
console.log(event) | ||
let zoomApp = chatbot.create({ auth: oauth2Client.connect() }); | ||
zoomApp.auth.setTokens({ | ||
access_token: 'get from database', | ||
refresh_token: 'get from database', | ||
expires_in: 'get from databse' | ||
}); | ||
zoomApp.auth.callbackRefreshTokens((tokens) => { | ||
zoomApp.auth.setTokens({ | ||
access_token: tokens.access_token, | ||
refresh_token: tokens.refresh_token, | ||
expires_in: tokens.expires_in | ||
}); | ||
// save new tokens to db | ||
db.set('access_token') | ||
db.set('refresh_token') | ||
db.set('expires_in') | ||
}); | ||
zoomApp.request({ | ||
url: '/v2/users/' + event.command, | ||
method: 'get', | ||
}).then((data) => { | ||
console.log(data) | ||
zoomApp.sendMessage({ | ||
to_jid: event.payload.toJid, | ||
account_id: event.payload.accountId, | ||
content: { | ||
head: { | ||
text: 'Hi ' + data.first_name | ||
}, | ||
body: [ | ||
{ | ||
type: 'section', | ||
sections: [ | ||
{ | ||
type: 'message', | ||
text: 'Your Role: ' + data.role_name | ||
} | ||
], | ||
footer_icon: data.pic_url, | ||
footer: data.phone_number | ||
} | ||
] | ||
} | ||
}).then((data) => { | ||
console.log(data) | ||
}).catch((error) => { | ||
console.log(error) | ||
}) | ||
}).catch((error) => { | ||
console.log(error) | ||
zoomApp.sendMessage({ | ||
to_jid: event.payload.toJid, | ||
account_id: event.payload.accountId, | ||
content: { | ||
head: { | ||
text: 'Error: ' + error.message | ||
} | ||
} | ||
}).then((data) => { | ||
console.log(data) | ||
}).catch((error) => { | ||
console.log(error) | ||
}) | ||
}) | ||
}) | ||
``` | ||
## Sample App | ||
Checkout our [Vote Chatbot Sample App](https://github.com/zoom/vote-chatbot) built using this NPM package. | ||
![Vote Chatbot for Zoom](https://s3.amazonaws.com/user-content.stoplight.io/19808/1567798340584) | ||
## Debug | ||
To print out the HTTP request log, require the `setting` object and pass in `true`. | ||
```js | ||
let { setting } = require('@zoomus/chatbot'); | ||
setting.debug(true); | ||
``` | ||
## Need Support? | ||
The first place to look for help is on our [Developer Forum](https://devforum.zoom.us/), where Zoom Marketplace Developers can ask questions for public answers. | ||
If you can’t find the answer in the Developer Forum or your request requires sensitive information to be relayed, please email us at developersupport@zoom.us. |
@@ -5,2 +5,3 @@ import utils from '../utils/index'; | ||
import configSet from '../services/config'; | ||
import serviceLog from '../services/log'; | ||
@@ -122,3 +123,3 @@ let createInfo = { | ||
this.name = name; | ||
this.config = { help: true, errorHelp: false }; | ||
this.config = { help: false, errorHelp: false }; | ||
this.v = ''; | ||
@@ -265,2 +266,8 @@ } | ||
}); | ||
if(out.status===false){ | ||
serviceLog.run({ | ||
type: 'error_notice', | ||
message: {error:out.errorMessage} | ||
}); | ||
} | ||
return out; | ||
@@ -267,0 +274,0 @@ } |
@@ -8,5 +8,5 @@ // import store from './store'; | ||
if (str.indexOf(kw) !== -1) { | ||
return 'group'; | ||
return 'channel'; | ||
} | ||
return 'one'; | ||
return 'bot'; | ||
}, | ||
@@ -13,0 +13,0 @@ getConfigCmd(cmd) { |
import tool from './tool'; | ||
import request from './request'; | ||
import branch from './branch'; | ||
import Event from './Event'; | ||
@@ -10,5 +9,5 @@ import Store from './store'; | ||
let out = { request, branch, Event,Store,debug,loop}; | ||
let out = { request, Event,Store,debug,loop}; | ||
out = Object.assign(out,tool); | ||
export default out; |
@@ -1,11 +0,28 @@ | ||
import request from 'request'; | ||
import querystring from 'querystring'; | ||
import nodefetch from 'node-fetch'; | ||
// import querystring from 'querystring'; | ||
import debug from './debug'; | ||
import serviceLog from '../services/log'; | ||
import AbortController from 'abort-controller'; | ||
let errorHandle=(logDataOption,errorInfo,reject)=>{ | ||
serviceLog.run({ | ||
type: 'http', | ||
message: { | ||
request: logDataOption, | ||
response: null, | ||
error:errorInfo | ||
} | ||
}); | ||
serviceLog.run({ | ||
type: 'error_notice', | ||
message: { | ||
error:errorInfo | ||
} | ||
}); | ||
reject(Object.assign({},errorInfo)); | ||
}; | ||
let requestWrap = opt => { | ||
let { | ||
body, | ||
formData, | ||
form, | ||
method = 'get', | ||
@@ -15,66 +32,93 @@ url, | ||
query = {}, | ||
cookie, | ||
timeout | ||
} = opt; | ||
return new Promise((resolve, reject) => { | ||
return new Promise((resolve, reject) => { | ||
let type, data; | ||
if (typeof body === 'object') { | ||
(type = 'body'), (data = body); | ||
} else if (typeof formData === 'object') { | ||
(type = 'formData'), (data = formData); | ||
} else if (typeof form === 'object') { | ||
(type = 'form'), (data = form); | ||
if(typeof body==='object'){ | ||
body=JSON.stringify(body); | ||
} | ||
let dataOption = { qs: query, headers, url, method }; | ||
if (type) { | ||
dataOption[type] = data; | ||
} | ||
if (type === 'body') { | ||
dataOption.json = true; | ||
let dataOption={ | ||
method, | ||
headers, | ||
body | ||
}; | ||
let timeoutResult=null; | ||
if(typeof timeout==='number'){ | ||
const controller = new AbortController(); | ||
timeoutResult=setTimeout( | ||
() => { controller.abort(); }, | ||
timeout, | ||
); | ||
} | ||
if (typeof cookie === 'object') { | ||
let j = request.jar(); | ||
let cookieRequest = request.cookie(querystring.stringify(cookie)); | ||
j.setCookie(cookieRequest, url); | ||
dataOption.jar = j; | ||
} | ||
debug('http')(dataOption); | ||
if (typeof timeout === 'number') { | ||
dataOption.timeout = timeout; | ||
if(typeof query==='object'){ | ||
let urlObject=new URL(url); | ||
Object.keys(query).forEach((name)=>{ | ||
urlObject.searchParams.set(name,query[name]); | ||
}); | ||
url=urlObject.href; | ||
} | ||
request(dataOption, function(error, response) { | ||
serviceLog.run({ | ||
type: 'http', | ||
message: { | ||
request: dataOption, | ||
response, | ||
error | ||
} | ||
}); | ||
if (error) { | ||
reject(error); | ||
} else { | ||
let code = response.statusCode; | ||
let oldBody = response.body; | ||
let newBody; | ||
try { | ||
newBody = JSON.parse(oldBody); | ||
} catch (e) { | ||
newBody = oldBody; | ||
let logDataOption=Object.assign({url},dataOption); | ||
debug('http')(logDataOption); | ||
let nodefeatchResult=nodefetch(url,dataOption) | ||
.then((res)=>{ | ||
let status=res.status; | ||
res.text().then((responseBody)=>{ | ||
let responseText=responseBody; | ||
if(typeof responseBody==='string'){ | ||
try{ | ||
responseBody=JSON.parse(responseBody); | ||
} | ||
catch(e){ | ||
errorHandle(logDataOption,{ | ||
type:'parseError', | ||
status, | ||
message:responseText | ||
},reject); | ||
return; | ||
} | ||
} | ||
if (code >= 300) { | ||
reject(newBody); | ||
} else { | ||
response.body = newBody; | ||
resolve(response); | ||
if (status >= 200 && status < 300){//success | ||
serviceLog.run({ | ||
type: 'http', | ||
message: { | ||
request: logDataOption, | ||
response: { | ||
status, | ||
body:responseBody | ||
}, | ||
error:null | ||
} | ||
}); | ||
resolve({status,body:responseBody}); | ||
} else {//success but status fail | ||
errorHandle(logDataOption,{ | ||
status:status, | ||
message:responseBody | ||
},reject); | ||
return; | ||
} | ||
// response.body=newBody; | ||
// resolve(response); | ||
} | ||
}) | ||
.catch((e)=>{//promise all error | ||
errorHandle(logDataOption,{ | ||
type:'parseError', | ||
status, | ||
message:e | ||
},reject); | ||
return; | ||
}); | ||
}) | ||
.catch((e)=>{//request error | ||
errorHandle(logDataOption,e,reject); | ||
}); | ||
if(timeoutResult!==null){ | ||
nodefeatchResult.finally(()=>{ | ||
clearTimeout(timeoutResult); | ||
}); | ||
} | ||
}); | ||
@@ -81,0 +125,0 @@ }; |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
62
4925
0
151960
5
23
158
+ Addedabort-controller@^3.0.0
+ Addednode-fetch@^2.6.0
+ Addedabort-controller@3.0.0(transitive)
+ Addedevent-target-shim@5.0.1(transitive)
+ Addednode-fetch@2.7.0(transitive)
+ Addedtr46@0.0.3(transitive)
+ Addedwebidl-conversions@3.0.1(transitive)
+ Addedwhatwg-url@5.0.0(transitive)
- Removedrequest@^2.88.0
- Removedajv@6.12.6(transitive)
- Removedasn1@0.2.6(transitive)
- Removedassert-plus@1.0.0(transitive)
- Removedasynckit@0.4.0(transitive)
- Removedaws-sign2@0.7.0(transitive)
- Removedaws4@1.13.2(transitive)
- Removedbcrypt-pbkdf@1.0.2(transitive)
- Removedcaseless@0.12.0(transitive)
- Removedcombined-stream@1.0.8(transitive)
- Removedcore-util-is@1.0.2(transitive)
- Removeddashdash@1.14.1(transitive)
- Removeddelayed-stream@1.0.0(transitive)
- Removedecc-jsbn@0.1.2(transitive)
- Removedextend@3.0.2(transitive)
- Removedextsprintf@1.3.0(transitive)
- Removedfast-deep-equal@3.1.3(transitive)
- Removedfast-json-stable-stringify@2.1.0(transitive)
- Removedforever-agent@0.6.1(transitive)
- Removedform-data@2.3.3(transitive)
- Removedgetpass@0.1.7(transitive)
- Removedhar-schema@2.0.0(transitive)
- Removedhar-validator@5.1.5(transitive)
- Removedhttp-signature@1.2.0(transitive)
- Removedis-typedarray@1.0.0(transitive)
- Removedisstream@0.1.2(transitive)
- Removedjsbn@0.1.1(transitive)
- Removedjson-schema@0.4.0(transitive)
- Removedjson-schema-traverse@0.4.1(transitive)
- Removedjson-stringify-safe@5.0.1(transitive)
- Removedjsprim@1.4.2(transitive)
- Removedmime-db@1.52.0(transitive)
- Removedmime-types@2.1.35(transitive)
- Removedoauth-sign@0.9.0(transitive)
- Removedperformance-now@2.1.0(transitive)
- Removedpsl@1.15.0(transitive)
- Removedpunycode@2.3.1(transitive)
- Removedqs@6.5.3(transitive)
- Removedrequest@2.88.2(transitive)
- Removedsafe-buffer@5.2.1(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsshpk@1.18.0(transitive)
- Removedtough-cookie@2.5.0(transitive)
- Removedtunnel-agent@0.6.0(transitive)
- Removedtweetnacl@0.14.5(transitive)
- Removeduri-js@4.4.1(transitive)
- Removeduuid@3.4.0(transitive)
- Removedverror@1.10.0(transitive)