-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 4f1d678
Showing
8 changed files
with
327 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
module.exports = api => { | ||
api.cache.never() | ||
|
||
const presets = [ | ||
[ '@babel/env', { modules: false } ], | ||
] | ||
const plugins = [ | ||
'@babel/plugin-proposal-class-properties', | ||
] | ||
|
||
if (process.env.NODE_ENV === 'testing') { | ||
plugins.push('istanbul') | ||
} | ||
|
||
return { presets, plugins, comments: false } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/node_modules/ | ||
package-lock.json | ||
dist/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package-lock=false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# amoCRM widget installer | ||
|
||
Сервисный класс, который упаковывает директорию в zip-архив и загружает в аккаунт amoCRM. Если в amoCRM виджет не сущестует, он будет создан, иначе будет обновлен. | ||
|
||
## Установка | ||
```bash | ||
$ npm install --save-dev @amopro/widget-installer | ||
``` | ||
|
||
## Использование | ||
```javascript | ||
const path = require('path'); | ||
const WIDGET_DIR = path.resolve('widget'); | ||
|
||
// ... | ||
// Здесь собирается виджет в папку "widget" | ||
// ... | ||
|
||
try { | ||
const WidgetInstaller = require('@amopro/widget-installer'); | ||
const wi = new WidgetInstaller( | ||
process.env.AMO_SUB_DOMAIN, | ||
process.env.AMO_LOGIN, | ||
process.env.AMO_PASSWORD, | ||
WIDGET_DIR | ||
); | ||
|
||
await wi.upload(); | ||
console.log('Widget uploaded!'); | ||
// после загрузки можно удалить архив | ||
const fse = require('fs-extra'); | ||
fse.removeSync(path.resolve('widget.zip')); | ||
} catch (e) { | ||
console.error('uploading error', e.toString()); | ||
throw e; | ||
} | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
{ | ||
"name": "@amopro/widget-installer", | ||
"version": "1.0.0", | ||
"description": "Automatic installation of a widget in amoCRM", | ||
"main": "dist/widget-installer.js", | ||
"scripts": { | ||
"build": "rollup --config rollup.config.js" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/max-kut/amocrm-widget-installer.git" | ||
}, | ||
"keywords": [ | ||
"amocrm", | ||
"widget" | ||
], | ||
"author": "Maksim Kutishchev", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/max-kut/amocrm-widget-installer/issues" | ||
}, | ||
"homepage": "https://github.com/max-kut/amocrm-widget-installer#readme", | ||
"dependencies": { | ||
"archiver": "^2.1.1", | ||
"content-type": "^1.0.4", | ||
"jsdom": "^16.4.0", | ||
"lodash": "^4.17.19", | ||
"request-promise": "^4.2.6" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.11.6", | ||
"@babel/plugin-proposal-class-properties": "^7.13.0", | ||
"@babel/preset-env": "^7.11.5", | ||
"@rollup/plugin-commonjs": "^11.1.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
export default { | ||
input: 'src/index.js', | ||
output: { | ||
file: 'dist/widget-installer.js', | ||
format: 'cjs', | ||
exports: 'default' | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const archiver = require('archiver'); | ||
const contentType = require('content-type'); | ||
const _get = require('lodash/get'); | ||
const request = require('request-promise'); | ||
const {JSDOM} = require("jsdom"); | ||
|
||
|
||
export default class WidgetInstaller { | ||
/** | ||
* @param {String} subDomain | ||
* @param {String} login | ||
* @param {String} password | ||
* @param {String} widgetDirectory | ||
* @param {String} redirectUri | ||
* @param {String} defaultLocale | ||
*/ | ||
constructor(subDomain, login, password, widgetDirectory, redirectUri = 'https://amocrm.ru/', defaultLocale = 'ru') { | ||
this.login = login; | ||
this.password = password; | ||
this.domain = subDomain; | ||
this.redirectUri = redirectUri; | ||
this.widgetDirectory = widgetDirectory; | ||
this.defaultLocale = defaultLocale; | ||
|
||
this.accessToken = null; | ||
this.refreshToken = null; | ||
|
||
this.widget_code = null; | ||
this.widget_uuid = null; | ||
|
||
this._request = request.defaults({ | ||
headers: { | ||
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:51.0) Gecko/20100101 Firefox/51.0', | ||
'X-Requested-With': 'XMLHttpRequest', | ||
'Referer': this._url('/settings/widgets/') | ||
}, | ||
jar: true, | ||
transform(body, response) { | ||
const ct = contentType.parse(response.headers['content-type']); | ||
if (ct.type === 'application/json' || ct.type === 'text/json') { | ||
try { | ||
return JSON.parse(body); | ||
} catch (e) { | ||
return body; | ||
} | ||
} | ||
|
||
return body; | ||
} | ||
}); | ||
} | ||
|
||
async upload() { | ||
await this._createAuthenticatedSession(); | ||
const widgetName = this._getManifestLocalizedValue('widget.name'); | ||
|
||
await this._findWidgetData(widgetName); | ||
|
||
if (this.widget_uuid === null) { | ||
const {uuid} = await this._request.post(this._url(`/v3/clients/`), { | ||
json: this._getWidgetData() | ||
}); | ||
await this.uploadWidget(uuid); | ||
} else { | ||
const {uuid} = await this._request.patch(this._url(`/v3/clients/${this.widget_uuid}`), { | ||
json: this._getWidgetData() | ||
}); | ||
await this.uploadWidget(uuid); | ||
} | ||
} | ||
|
||
_url(path) { | ||
return `https://${this.domain}.amocrm.ru/` + path.replace(/^\/*(.*)/, '$1') | ||
} | ||
|
||
/** | ||
* Create amocrm session | ||
* @private | ||
*/ | ||
async _createAuthenticatedSession() { | ||
let csrfToken; | ||
try { | ||
// this request has 401 response | ||
await this._request.get(this._url(`/`)); | ||
} catch (e) { | ||
const {response} = e; | ||
const dom = new JSDOM(response); | ||
csrfToken = dom.window.document.querySelector('input[name="csrf_token"]').value; | ||
} | ||
|
||
const res = await this._request.post(this._url(`/oauth2/authorize`), { | ||
headers: { | ||
Referer: this._url(`/`) | ||
}, | ||
json: { | ||
csrf_token: csrfToken, | ||
username: this.login, | ||
password: this.password, | ||
temporary_auth: 'N' | ||
} | ||
}); | ||
|
||
this.accessToken = res.access_token; | ||
this.refreshToken = res.refresh_token; | ||
} | ||
|
||
async _findWidgetData(name) { | ||
if (!name) { | ||
throw new Error('name is required') | ||
} | ||
|
||
const {widgets} = await this._request.get(this._url(`/ajax/settings/widgets/category/own_integrations/1/`)); | ||
|
||
for (const type of Object.keys(widgets.own_integrations)) { | ||
const integrations = widgets.own_integrations[type]; | ||
for (const code in integrations) if (integrations.hasOwnProperty(code)) { | ||
if (integrations[code].type === 'widget' && name === integrations[code].name) { | ||
this.widget_code = integrations[code].code; | ||
this.widget_uuid = integrations[code].client.uuid; | ||
return; | ||
} | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
_getWidgetData() { | ||
return { | ||
name: { | ||
en: this._getManifestLocalizedValue('widget.name', 'en') || "", | ||
es: this._getManifestLocalizedValue('widget.name', 'es') || "", | ||
pt: this._getManifestLocalizedValue('widget.name', 'pt') || "", | ||
ru: this._getManifestLocalizedValue('widget.name', 'ru') || "" | ||
}, | ||
description: { | ||
en: this._getManifestLocalizedValue('widget.description', 'en') || "", | ||
es: this._getManifestLocalizedValue('widget.description', 'es') || "", | ||
pt: this._getManifestLocalizedValue('widget.description', 'pt') || "", | ||
ru: this._getManifestLocalizedValue('widget.description', 'ru') || "" | ||
}, | ||
redirect_uri: this.redirectUri, | ||
scopes: ['crm', 'notifications'], | ||
uuid: this.widget_uuid | ||
}; | ||
} | ||
|
||
_getManifest() { | ||
if (typeof this._manifest === 'undefined') { | ||
const manifestPath = path.resolve(this.widgetDirectory, 'manifest.json'); | ||
this._manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); | ||
} | ||
return this._manifest; | ||
} | ||
|
||
/** | ||
* Получает локализованное значение из манифеста | ||
* @param {string} key - path in dot notation | ||
* @param {string} locale | ||
* @returns {*} | ||
* @private | ||
*/ | ||
_getManifestLocalizedValue(key, locale = null) { | ||
locale = locale || this.defaultLocale; | ||
if (typeof this._manifest_i18n === 'undefined' || typeof this._manifest_i18n[locale] === 'undefined') { | ||
this._manifest_i18n = this._manifest_i18n || {}; | ||
try { | ||
this._manifest_i18n[locale] = JSON.parse( | ||
fs.readFileSync(path.resolve(this.widgetDirectory, `i18n/${locale}.json`), 'utf8') | ||
) | ||
} catch (e) { | ||
return null; | ||
} | ||
} | ||
|
||
return _get(this._manifest_i18n[locale], key, _get(this._getManifest(), key)); | ||
} | ||
|
||
async uploadWidget(uuid) { | ||
const archivePath = await WidgetInstaller.zipArchive(this.widgetDirectory); | ||
|
||
const result = await this._request.post(this._url(`/ajax/widgets/${uuid}/widget/upload/?fileapi${Date.now()}`), { | ||
formData: { | ||
'widget': { | ||
value: fs.createReadStream(archivePath), | ||
options: { | ||
filename: 'widget.zip', | ||
contentType: 'application/x-zip-compressed' | ||
} | ||
}, | ||
'_widget': 'widget.zip', | ||
} | ||
}); | ||
|
||
return result; | ||
} | ||
|
||
static zipArchive(widgetFolder) { | ||
return new Promise((resolve, reject) => { | ||
const widgetPath = path.resolve('widget.zip'); | ||
const widgetFileStream = fs.createWriteStream(widgetPath); | ||
|
||
const archive = archiver('zip', { | ||
zlib: {level: 1} | ||
}); | ||
|
||
widgetFileStream.on('close', () => { | ||
resolve(widgetPath); | ||
}); | ||
|
||
archive.on('error', (err) => { | ||
reject(err); | ||
}); | ||
|
||
archive.pipe(widgetFileStream); | ||
archive.directory(path.resolve(widgetFolder), false); | ||
archive.finalize(); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import WidgetInstaller from './WidgetInstaller'; | ||
|
||
export default WidgetInstaller; |