1
0
mirror of synced 2024-11-21 20:16:03 +03:00

Initial bot api client

This commit is contained in:
Akolzin Dmitry 2019-02-06 14:54:15 +03:00
parent 137632cff3
commit 772a6f1284
6 changed files with 934 additions and 0 deletions

63
.gitignore vendored Normal file
View File

@ -0,0 +1,63 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
.idea
package-lock.json

6
.travis.yml Normal file
View File

@ -0,0 +1,6 @@
language: node_js
node_js:
- "11"
- "10"
- "8"
script: npm test

View File

@ -1,2 +1,53 @@
# retailCRM Message Gateway Bot API JS client
This is js retailCRM bot API client. [API documentation](https://139810.selcdn.ru/download/doc/mg-bot-api/bot.v1.html)
# Installation
```
npm install --save mg-bot-api-client-js
```
In your file
```
var RetailcrmBotApiClient = require('retailcrm-bot-api-client');
```
# Usage
#### Get users
```javascript
var api = new RetailcrmBotApiClient({
host: 'https://api.example.com',
token: 'your bot token',
apiVersion: 'v1' // optional
});
api.getUsers()
.then(function (users) {
console.log(users);
})
.catch(function (e) {
console.log(e);
});
```
#### Send message
```javascript
var api = new RetailcrmBotApiClient({
host: 'https://api.example.com',
token: 'your bot token',
apiVersion: 'v1' // optional
});
var message = {
chat_id: 1,
content: 'Text message',
scope: 'public',
type: 'text'
}
api.sendMessage(message)
.then(function (result) {
console.log(result);
})
.catch(function (e) {
console.log(e);
});
```

404
index.js Normal file
View File

@ -0,0 +1,404 @@
'use strict';
var https = require('https');
var querystring = require('querystring');
var url = require('url');
var lastApiVersion = 'v1';
module.exports = RetailcrmBotApiClient;
/**
* @param {Object} options
* @throws {Error}
* @constructor
*/
function RetailcrmBotApiClient(options) {
if (!options.host) {
throw new Error('Url is required');
}
if (options.host.indexOf('https') !== 0) {
throw new Error('HTTPS required');
}
if (!(options.token)) {
throw new Error('Token is required');
}
this._setDefaultOptions(options)
}
/**
* @param {Object} options
* @private
*/
RetailcrmBotApiClient.prototype._setDefaultOptions = function (options) {
if (!options.apiVersion) {
this.apiVersion = lastApiVersion;
} else {
this.apiVersion = options.apiVersion;
}
this.host = url.parse(options.host).host;
this.token = options.token;
};
/**
* Get request path
* @param {string} endpoint
* @returns {string}
* @private
*/
RetailcrmBotApiClient.prototype._getPath = function (endpoint) {
return '/api/bot/' + this.apiVersion + endpoint;
};
/**
* Make request
* @param {string} endpoint
* @param {string} method
* @param {Object} data
* @returns {Promise}
* @throws {Error}
* @private
*/
RetailcrmBotApiClient.prototype._request = function (endpoint, method, data) {
var path= this._getPath(endpoint);
var response = '';
if (method === 'GET' && data.length > 0) {
path += '?' + querystring.stringify(data);
}
var options = {
host: this.host,
method: method,
path: path,
headers: {
'x-bot-token': this.token
}
};
return new Promise(function(resolve, reject) {
var request = https.request(options, function (res) {
res.on('data', function (chunk) {
response += chunk;
});
res.on('end', function () {
try {
var result = JSON.parse(response);
if (res.statusCode < 400) {
resolve(result);
} else {
reject(new Error(result.errors.join(',')));
}
} catch (e) {
reject(e);
}
});
res.on('error', function (e) {
reject(e);
})
});
if (['POST', 'PUT', 'PATCH'].includes(method)) {
request.write(JSON.stringify(data));
}
request.end();
request.on('error', function(e) {
reject(e);
});
});
};
/**
* Method GET
* @param {string} endpoint
* @param {Object} params
* @returns {Promise}
* @private
*/
RetailcrmBotApiClient.prototype._get = function (endpoint, params) {
if (params === undefined) {
params = {};
}
return this._request(endpoint, 'GET', params);
};
/**
* Method POST
* @param {string} endpoint
* @param {Object} data
* @returns {Promise}
* @throws {Error}
* @private
*/
RetailcrmBotApiClient.prototype._post = function (endpoint, data) {
if (!data) {
throw new Error('Body is not be empty');
}
return this._request(endpoint, 'POST', data);
};
/**
* Method PATCH
* @param {string} endpoint
* @param {Object} data
* @returns {Promise}
* @throws {Error}
* @private
*/
RetailcrmBotApiClient.prototype._patch = function (endpoint, data) {
if (!data) {
throw new Error('Body is not be empty');
}
return this._request(endpoint, 'PATCH', data);
};
/**
* Method PUT
* @param {string} endpoint
* @param {Object} data
* @returns {Promise}
* @throws {Error}
* @private
*/
RetailcrmBotApiClient.prototype._put = function (endpoint, data) {
if (!data) {
throw new Error('Body is not be empty');
}
return this._request(endpoint, 'PUT', data);
};
/**
* Method DELETE
* @param {string} endpoint
* @returns {Promise}
* @private
*/
RetailcrmBotApiClient.prototype._delete = function (endpoint) {
return this._request(endpoint, 'DELETE', {});
};
/**
* Set API version
* @param {string} api_version
*/
RetailcrmBotApiClient.prototype.setApiVersion = function (api_version) {
this.apiVersion = api_version;
};
/**
* Get bot token
* @returns {*|string}
*/
RetailcrmBotApiClient.prototype.getToken = function () {
return this.token;
};
/**
* Get bots
* @param {string} params
* @returns {Promise}
*/
RetailcrmBotApiClient.prototype.getBots = function (params) {
return this._get('/bots', params);
};
/**
* Get channels
* @param {string} params
* @returns {Promise}
*/
RetailcrmBotApiClient.prototype.getChannels = function (params) {
return this._get('/channels', params);
};
/**
* Get chats
* @param {string} params
* @returns {Promise}
*/
RetailcrmBotApiClient.prototype.getChats = function (params) {
return this._get('/chats', params);
};
/**
* Get customers
* @param {string} params
* @returns {Promise}
*/
RetailcrmBotApiClient.prototype.getCustomers = function (params) {
return this._get('/customers', params);
};
/**
* Get dialogs
* @param {string} params
* @returns {Promise}
*/
RetailcrmBotApiClient.prototype.getDialogs = function (params) {
return this._get('/dialogs', params);
};
/**
* Get members
* @param {string} params
* @returns {Promise}
*/
RetailcrmBotApiClient.prototype.getMembers = function (params) {
return this._get('/members', params);
};
/**
* Assign dialog
* @param {Number} dialog_id
* @param {Object} dialog
* @returns {Promise}
*/
RetailcrmBotApiClient.prototype.assignDialog = function (dialog_id, dialog) {
return this._patch('/dialogs/'+ dialog_id + '/assign', dialog);
};
/**
* Close dialog
* @param {Number} dialog_id
* @returns {Promise}
* @throws {Error}
*/
RetailcrmBotApiClient.prototype.closeDialog = function (dialog_id) {
if (!dialog_id) {
throw new Error('dialog_id is required');
}
return this._delete('/dialogs/'+ dialog_id + '/close');
};
/**
* Send message
* @param {Object} data
* @returns {Promise}
*/
RetailcrmBotApiClient.prototype.sendMessage = function (data) {
return this._post('/messages', data);
};
/**
* Get messages
* @param {Object} params
* @returns {Promise}
*/
RetailcrmBotApiClient.prototype.getMessages = function (params) {
return this._get('/messages', params);
};
/**
* Delete message
* @param {Number} message_id
* @returns {Promise}
* @throws {Error}
*/
RetailcrmBotApiClient.prototype.deleteMessage = function (message_id) {
if (!message_id) {
throw new Error('message_id is required');
}
return this._delete('/messages/' + message_id);
};
/**
* Edit message
* @param {Number} message_id
* @param {Object} message
* @returns {Promise}
*/
RetailcrmBotApiClient.prototype.editMessage = function (message_id, message) {
return this._patch('/messages/' + message_id, message);
};
/**
* Get bot commands
* @param {Object} params
* @returns {Promise}
*/
RetailcrmBotApiClient.prototype.getCommands = function (params) {
return this._get('/my/commands', params);
};
/**
* Edit bot command
* @param {string} command_name
* @param {Object} data
* @returns {Promise}
* @throws {Error}
*/
RetailcrmBotApiClient.prototype.editCommand = function (command_name, data) {
if (!command_name) {
throw new Error('Parameter command name is required');
}
return this._put('/my/commands/' + command_name, data);
};
/**
* Delete bot command
* @param {string} command_name
* @returns {Promise}
* @throws {Error}
*/
RetailcrmBotApiClient.prototype.deleteCommand = function (command_name) {
if (!command_name) {
throw new Error('command_name is required');
}
return this._delete('/my/commands/' + command_name);
};
/**
* Bot information update
* @param {Object} data
* @returns {Promise}
*/
RetailcrmBotApiClient.prototype.info = function (data) {
return this._patch('/my/info', data);
};
/**
* Get users
* @param {Object} params
* @returns {Promise}
*/
RetailcrmBotApiClient.prototype.getUsers = function (params) {
return this._get('/users', params);
};
/**
* Get websocket url
* @param {array<string>} events
* @returns {string}
* @throws {Error}
*/
RetailcrmBotApiClient.prototype.getWebsocketUrl = function (events) {
if (!events) {
throw new Error('Events is required');
}
var url = 'wss://' + this.host + '/api/bot/' + this.apiVersion + '/ws?events=';
events.forEach(function (event) {
url += event + ',';
});
url = url.slice(0, -1);
return url;
};

26
package.json Normal file
View File

@ -0,0 +1,26 @@
{
"name": "mg-bot-api-client-js",
"description": "JS client for retailCRM Bot API",
"tags": ["API", "retailCRM", "Bot", "Chat"],
"version": "1.0.0",
"scripts": {
"test": " ./node_modules/.bin/_mocha test.js"
},
"author": "retailCRM",
"license": "MIT",
"main": "index.js",
"bugs": {
"url": "https://github.com/retailcrm/mg-bot-api-client-js/issues"
},
"dependencies": {},
"devDependencies": {
"chai": "^4.2.0",
"mocha": "^5.2.0",
"nock": "^10.0.6"
},
"homepage": "https://github.com/retailcrm/mg-bot-api-client-js#readme",
"repository": {
"type": "git",
"url": "git@github.com:retailcrm/mg-bot-api-client-js.git"
}
}

384
test.js Normal file
View File

@ -0,0 +1,384 @@
var nock = require('nock');
var chai = require('chai');
var RetailcrmBotApiClient = require('./index');
describe('#Constructor', function () {
it('Empty url', function () {
chai.expect(function() {
new RetailcrmBotApiClient({token: 'test_token'});
}).to.throw('Url is required');
});
it('Incorrect url', function () {
chai.expect(function() {
new RetailcrmBotApiClient({
host: 'http://test.retailcrm.ru',
token: 'test_token'
});
}).to.throw('HTTPS required');
});
it('Empty token', function () {
chai.expect(function() {
new RetailcrmBotApiClient({host: 'https://test.retailcrm.ru',});
}).to.throw('Token is required');
});
it('Set the default options', function () {
var api = new RetailcrmBotApiClient({
host: 'https://test.retailcrm.ru',
token: 'xxxxxxxxxxxxxxxxxxxxxxxx'
});
chai.expect(api.apiVersion).to.equal('v1');
chai.expect(api.token).to.equal('xxxxxxxxxxxxxxxxxxxxxxxx');
chai.expect(api.getToken()).to.equal('xxxxxxxxxxxxxxxxxxxxxxxx');
chai.expect(api.host).to.equal('test.retailcrm.ru');
});
});
describe('#Requests', function() {
beforeEach(function() {
nock.cleanAll();
});
var retailcrm = new RetailcrmBotApiClient({
host: 'https://test.retailcrm.ru',
token: 'test_token'
});
it('Get bots list', function() {
nock('https://test.retailcrm.ru/api/bot/v1').get('/bots').reply(200, [{
id: 1,
isActive: true
}]);
retailcrm.getBots().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.not.empty;
});
});
it('Get empty bots list', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/bots').reply(200, []);
retailcrm.getBots().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.empty;
});
});
it('Get channels list', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/channels').reply(200, [{
id: 1
}]);
retailcrm.getChannels().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.not.empty;
});
});
it('Get empty channels list', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/channels').reply(200, []);
retailcrm.getChannels().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.empty;
});
});
it('Get chats list', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/chats').reply(200, [{
author_id: 1,
id: 1
}]);
retailcrm.getChats().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.not.empty;
});
});
it('Get empty chats list', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/chats').reply(200, []);
retailcrm.getChats().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.empty;
});
});
it('Get customers list', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/customers').reply(200, [{
external_id: 1,
channel_id: 1,
id: 1
}]);
retailcrm.getCustomers().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.not.empty;
});
});
it('Get empty customers list', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/customers').reply(200, []);
retailcrm.getCustomers().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.empty;
});
});
it('Get dialogs list', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/dialogs').reply(200, [{
begin_message_id: 1,
id: 1
}]);
retailcrm.getDialogs().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.not.empty;
});
});
it('Get empty dialogs list', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/dialogs').reply(200, []);
retailcrm.getDialogs().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.empty;
});
});
it('Get members list', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/members').reply(200, [{
id: 1
}]);
retailcrm.getMembers().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.not.empty;
});
});
it('Get empty members list', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/members').reply(200, []);
retailcrm.getMembers().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.empty;
});
});
it('Assign dialog', function () {
nock('https://test.retailcrm.ru/api/bot/v1').patch('/dialogs/1/assign').reply(200, {
is_reassign: true,
responsible: {
id: 1
}
});
retailcrm.assignDialog(1, {
manager_id: 1
}).then(function (value) {
chai.expect(value).to.be.an('object');
});
});
it('Assign dialog incorrect', function () {
chai.expect(retailcrm.assignDialog.bind(retailcrm)).to.throw('Body is not be empty');
});
it('Close dialog', function () {
nock('https://test.retailcrm.ru/api/bot/v1').delete('/dialogs/1/close').reply(200, {});
retailcrm.closeDialog(1).then(function (value) {
chai.expect(value).to.be.empty;
});
});
it('Close dialog incorrect', function () {
chai.expect(retailcrm.closeDialog.bind(retailcrm)).to.throw('dialog_id is required');
});
it('Send message', function () {
nock('https://test.retailcrm.ru/api/bot/v1').post('/messages', {
chat_id: 1,
scope: 'public',
type: 'text',
content: 'test message'
}).reply(200, {
message_id: 1
});
retailcrm.sendMessage({
chat_id: 1,
scope: 'public',
type: 'text',
content: 'test message'
}).then(function (value) {
chai.expect(value).to.be.an('object');
chai.expect(value).to.be.not.empty;
});
});
it('Send message incorrect', function () {
chai.expect(retailcrm.sendMessage.bind(retailcrm)).to.throw('Body is not be empty');
});
it('Get messages', function() {
nock('https://test.retailcrm.ru/api/bot/v1').get('/messages').reply(200, [{
id: 1,
chat_id: 1,
from: {
id: 1
}
}]);
retailcrm.getMessages().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.not.empty;
});
});
it('Get empty messages', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/messages').reply(200, []);
retailcrm.getMessages().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.empty;
});
});
it('Delete message', function () {
nock('https://test.retailcrm.ru/api/bot/v1').delete('/messages/1').reply(200, {});
retailcrm.deleteMessage(1).then(function (value) {
chai.expect(value).to.be.empty;
});
});
it('Delete message incorrect', function () {
chai.expect(retailcrm.deleteMessage.bind(retailcrm)).to.throw('message_id is required');
});
it('Edit message', function () {
nock('https://test.retailcrm.ru/api/bot/v1').patch('/messages/1', {
content: 'test message'
}).reply(200, {});
retailcrm.editMessage(1, {
content: 'test message'
}).then(function (value) {
chai.expect(value).to.be.empty;
});
});
it('Edit message incorrect', function () {
chai.expect(retailcrm.editMessage.bind(retailcrm)).to.throw('Body is not be empty');
});
it('Get commands', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/my/commands').reply(200, [{
id: 1,
name: 'Command name'
}]);
retailcrm.getCommands().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.not.empty;
});
});
it('Get empty commands', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/my/commands').reply(200, []);
retailcrm.getCommands().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.empty;
});
});
it('Edit command', function () {
nock('https://test.retailcrm.ru/api/bot/v1').put('/my/commands/command', {
description: 'Desc',
name: 'name'
}).reply(200, {});
retailcrm.editCommand('command', {
description: 'Desc',
name: 'name'
}).then(function (value) {
chai.expect(value).to.be.empty;
});
});
it('Edit command incorrect', function () {
chai.expect(retailcrm.editCommand.bind(retailcrm, 'command')).to.throw('Body is not be empty');
chai.expect(retailcrm.editCommand.bind(retailcrm)).to.throw('Parameter command name is required');
});
it('Delete command', function () {
nock('https://test.retailcrm.ru/api/bot/v1').delete('/my/commands/command').reply(200, {});
retailcrm.deleteCommand('command').then(function (value) {
chai.expect(value).to.be.empty;
});
});
it('Delete command incorrect', function () {
chai.expect(retailcrm.deleteCommand.bind(retailcrm)).to.throw('command_name is required');
});
it('Update bot info', function () {
nock('https://test.retailcrm.ru/api/bot/v1').patch('/my/info', {
avatar_url: 'http://test.ru/avatar.png',
name: 'Bot'
}).reply(200, {});
retailcrm.info({
avatar_url: 'http://test.ru/avatar.png',
name: 'Bot'
}).then(function (value) {
chai.expect(value).to.be.empty;
});
});
it('Update bot info incorrect', function () {
chai.expect(retailcrm.info.bind(retailcrm)).to.throw('Body is not be empty');
});
it('Get users', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/users').reply(200, [{
id: 1,
name: 'Username'
}]);
retailcrm.getUsers().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.not.empty;
});
});
it('Get empty users', function () {
nock('https://test.retailcrm.ru/api/bot/v1').get('/users').reply(200, []);
retailcrm.getUsers().then(function (value) {
chai.expect(value).to.be.an('array');
chai.expect(value).to.be.empty;
});
});
it('Get websocket url', function () {
var url = retailcrm.getWebsocketUrl(['message_new', 'message_updated']);
var expected = 'wss://test.retailcrm.ru/api/bot/v1/ws?events=message_new,message_updated';
chai.assert.equal(url, expected);
});
it('Get websocket url incorrect', function () {
chai.expect(retailcrm.getWebsocketUrl.bind(retailcrm)).to.throw('Events is required');
});
});