new(whatsapp.gblib): Transfer to human implemented.

This commit is contained in:
Rodrigo Rodriguez 2020-05-02 21:28:13 -03:00
parent 08c5601581
commit 63dfc03c15
16 changed files with 295 additions and 304 deletions

20
DATABASE-CHANGES.md Normal file
View file

@ -0,0 +1,20 @@
# 1.7.6
``` SQL
ALTER TABLE dbo.GuaribasUser ADD
agentSystemId nvarchar(16) NULL,
agentMode nvarchar(16) NULL,
agentContacted datetime NULL
GO
ALTER TABLE [dbo].[GuaribasUser] DROP COLUMN [phone]
GO
ALTER TABLE [dbo].[GuaribasUser] DROP COLUMN [internalAddress]
GO
ALTER TABLE [dbo].[GuaribasUser] DROP COLUMN [currentBotId]
GO
```

256
package-lock.json generated
View file

@ -1131,15 +1131,6 @@
"parse-cache-control": "^1.0.1"
}
},
"@discordjs/opus": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@discordjs/opus/-/opus-0.1.0.tgz",
"integrity": "sha512-VWsrsgqSktxOEHx9SFcnOWJhYQOsyzaW3JVN73LDSzKrycEjtRIS+axlm4qeMGx60u6RH1SY15b3pl5G4+Y+gA==",
"requires": {
"node-addon-api": "^2.0.0",
"node-pre-gyp": "^0.14.0"
}
},
"@glimmer/interfaces": {
"version": "0.41.4",
"resolved": "https://registry.npmjs.org/@glimmer/interfaces/-/interfaces-0.41.4.tgz",
@ -2155,11 +2146,6 @@
"resolved": "https://registry.npmjs.org/any-shell-escape/-/any-shell-escape-0.1.1.tgz",
"integrity": "sha1-1Vq5ciRMcaml4asIefML8RCAaVk="
},
"aproba": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
},
"archiver": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/archiver/-/archiver-3.1.1.tgz",
@ -2231,15 +2217,6 @@
}
}
},
"are-we-there-yet": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"requires": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
}
},
"arg": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.2.tgz",
@ -3715,11 +3692,6 @@
"integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=",
"dev": true
},
"chownr": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
},
"chrono-node": {
"version": "1.3.11",
"resolved": "https://registry.npmjs.org/chrono-node/-/chrono-node-1.3.11.tgz",
@ -4085,7 +4057,8 @@
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true
},
"collapse-white-space": {
"version": "1.0.5",
@ -4396,11 +4369,6 @@
}
}
},
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
},
"content-disposition": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
@ -5020,7 +4988,8 @@
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true
},
"deep-is": {
"version": "0.1.3",
@ -5156,11 +5125,6 @@
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@ -5214,11 +5178,6 @@
"integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==",
"dev": true
},
"detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
},
"detect-newline": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
@ -6538,14 +6497,6 @@
}
}
},
"fs-minipass": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
"integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
"requires": {
"minipass": "^2.6.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -6591,54 +6542,6 @@
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
"dev": true
},
"gauge": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"requires": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.0",
"object-assign": "^4.1.0",
"signal-exit": "^3.0.0",
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wide-align": "^1.1.0"
},
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"requires": {
"number-is-nan": "^1.0.0"
}
},
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
}
}
}
},
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@ -7121,11 +7024,6 @@
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
"integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q="
},
"has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
},
"has-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
@ -7380,14 +7278,6 @@
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
"dev": true
},
"ignore-walk": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
"integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
"requires": {
"minimatch": "^3.0.4"
}
},
"immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
@ -9253,30 +9143,6 @@
"is-plain-obj": "^1.1.0"
}
},
"minipass": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
},
"dependencies": {
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
}
}
},
"minizlib": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
"integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
"requires": {
"minipass": "^2.9.0"
}
},
"mixin-deep": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
@ -9608,26 +9474,6 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
"needle": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.4.1.tgz",
"integrity": "sha512-x/gi6ijr4B7fwl6WYL9FwlCvRQKGlUNvnceho8wxkwXqN8jvVmmmATTmZPRRG7b/yC1eode26C2HO9jl78Du9g==",
"requires": {
"debug": "^3.2.6",
"iconv-lite": "^0.4.4",
"sax": "^1.2.4"
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"requires": {
"ms": "^2.1.1"
}
}
}
},
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
@ -9729,11 +9575,6 @@
"resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-1.0.4.tgz",
"integrity": "sha512-7cNtLKTAg0LrW3ViS2C7UfIzbL3rZd8L0++5MidbKqQVJ8yrH6+1VRSHl33P0ZjBTbOJd37d9EYekvHyKkB0QQ=="
},
"node-addon-api": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.0.tgz",
"integrity": "sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA=="
},
"node-emoji": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
@ -9772,33 +9613,6 @@
"request": "^2.66.0"
}
},
"node-pre-gyp": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz",
"integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==",
"requires": {
"detect-libc": "^1.0.2",
"mkdirp": "^0.5.1",
"needle": "^2.2.1",
"nopt": "^4.0.1",
"npm-packlist": "^1.1.6",
"npmlog": "^4.0.2",
"rc": "^1.2.7",
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"tar": "^4.4.2"
},
"dependencies": {
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"requires": {
"glob": "^7.1.3"
}
}
}
},
"node-releases": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.21.tgz",
@ -13545,29 +13359,6 @@
}
}
},
"npm-bundled": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz",
"integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
"requires": {
"npm-normalize-package-bin": "^1.0.1"
}
},
"npm-normalize-package-bin": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
"integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA=="
},
"npm-packlist": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz",
"integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==",
"requires": {
"ignore-walk": "^3.0.1",
"npm-bundled": "^1.0.1",
"npm-normalize-package-bin": "^1.0.1"
}
},
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
@ -13576,17 +13367,6 @@
"path-key": "^2.0.0"
}
},
"npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"requires": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
"gauge": "~2.7.3",
"set-blocking": "~2.0.0"
}
},
"nsp": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/nsp/-/nsp-3.2.1.tgz",
@ -13923,7 +13703,8 @@
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true
},
"oauth-sign": {
"version": "0.9.0",
@ -15727,6 +15508,7 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"dev": true,
"requires": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
@ -15737,7 +15519,8 @@
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
}
}
},
@ -17585,27 +17368,6 @@
}
}
},
"tar": {
"version": "4.4.13",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
"integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
"requires": {
"chownr": "^1.1.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.8.6",
"minizlib": "^1.2.1",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.3"
},
"dependencies": {
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
}
}
},
"tar-stream": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz",

View file

@ -87,7 +87,7 @@
"prism-media": "1.2.1",
"opn": "6.0.0",
"pragmatismo-io-framework": "1.0.20",
"public-ip": "4.0.0",
"public-ip": "4.0.0",
"readline": "1.3.0",
"reflect-metadata": "0.1.13",
"request-promise": "4.2.5",

View file

@ -63,7 +63,9 @@ export class SwitchBotDialog extends IGBDialog {
async step => {
let sec = new SecService();
let from = step.context.activity.from.id;
await sec.updateCurrentBotId(from, step.result);
const botId = step.result;
const instance = await min.core.loadInstanceByBotId(botId);
await sec.updateUserInstance(from, instance.instanceId);
await step.context.sendActivity(`Opa, vamos lá!`);
return await step.next();

View file

@ -51,6 +51,7 @@ const { join } = require('path')
const shell = require('any-shell-escape')
const { exec } = require('child_process')
const fs = require('fs')
const prism = require('prism-media')
const sdk = require("microsoft-cognitiveservices-speech-sdk");
export interface LanguagePickerSettings {

View file

@ -233,7 +233,7 @@ export class GBCoreService implements IGBCoreService {
/**
* Loads just one Bot instance.
*/
public async loadInstance(botId: string): Promise<IGBInstance> {
public async loadInstanceByBotId(botId: string): Promise<IGBInstance> {
const options = { where: {} };
options.where = { botId: botId };

View file

@ -213,7 +213,7 @@ export class GBDeployer implements IGBDeployer {
} else {
let botId = GBConfigService.get('BOT_ID');
let bootInstance = await this.core.loadInstance(botId);
let bootInstance = await this.core.loadInstanceByBotId(botId);
instance.searchHost = bootInstance.searchHost;
instance.searchIndex = bootInstance.searchIndex;

View file

@ -61,7 +61,7 @@ export class GBImporter {
if (botId === undefined) {
botId = GBConfigService.get('BOT_ID');
}
const instance = await this.core.loadInstance(botId);
const instance = await this.core.loadInstanceByBotId(botId);
if (instance != null && instance.botId === null) {
console.log(`Null BotId after load instance with botId: ${botId}.`);

View file

@ -134,6 +134,7 @@ export class GBMinService {
try {
const id = req.body.messages[0].chatId.split('@')[0];
const senderName = req.body.messages[0].senderName;
const text = req.body.messages[0].body;
if (req.body.messages[0].fromMe) {
res.end();
@ -142,30 +143,33 @@ export class GBMinService {
let activeMin;
if (process.env.WHATSAPP_WELCOME_DISABLED !== "true") {
const toSwitchMin = GBServer.globals.minInstances.filter(p => p.botId === text)[0];
const toSwitchMin = GBServer.globals.minInstances.filter(p => p.instance.botId === text)[0];
activeMin = toSwitchMin ? toSwitchMin : GBServer.globals.minBoot;
let sec = new SecService();
let user = await sec.getUserFromPhone(id);
const instance = await this.core.loadInstanceByBotId(activeMin.botId);
let user = await sec.getUserFromSystemId(id);
if (user === null) {
user = await sec.ensureUser(activeMin.instance.instanceId, id,
activeMin.botId, id, "", "whatsapp", id, id);
user = await sec.ensureUser(activeMin.instance.instanceId, id, senderName, "", "whatsapp", senderName);
await (activeMin as any).whatsAppDirectLine.sendToDevice(id, `Olá! Seja bem-vinda(o)!\nMe chamo ${activeMin.instance.title}. Como posso ajudar? Pode me falar que eu te ouço, me manda um aúdio.`);
res.end();
} else {
// User wants to switch bots.
if (toSwitchMin !== undefined) {
await sec.updateCurrentBotId(id, text);
const botId = text;
const instance = await this.core.loadInstanceByBotId(botId);
await sec.updateUserInstance(id, instance.instanceId);
await (activeMin as any).whatsAppDirectLine.resetConversationId(id);
await (activeMin as any).whatsAppDirectLine.sendToDevice(id, `Agora falando com ${activeMin.instance.title}...`);
res.end();
}
else {
activeMin = GBServer.globals.minInstances.filter(p => p.botId === user.currentBotId)[0];;
activeMin = GBServer.globals.minInstances.filter(p => p.instance.instanceId === user.instanceId)[0];;
if (activeMin === undefined) {
activeMin = GBServer.globals.minBoot;
await (activeMin as any).whatsAppDirectLine.sendToDevice(id, `O outro Bot que você estava falando(${user.currentBotId}), não está mais disponível. Agora você está falando comigo, ${activeMin.instance.title}...`);
await (activeMin as any).whatsAppDirectLine.sendToDevice(id, `O outro Bot que você estava falando(${user.instanceId}), não está mais disponível. Agora você está falando comigo, ${activeMin.instance.title}...`);
}
await (activeMin as any).whatsAppDirectLine.received(req, res);
}
@ -196,7 +200,7 @@ export class GBMinService {
const uiUrl = `/${botId}`;
removeRoute(GBServer.globals.server, uiUrl);
GBServer.globals.minInstances = GBServer.globals.minInstances.filter(p => p.botId !== botId);
GBServer.globals.minInstances = GBServer.globals.minInstances.filter(p => p.instance.botId !== botId);
}
public async mountBot(instance: IGBInstance) {
@ -294,7 +298,7 @@ export class GBMinService {
if (botId === '[default]' || botId === undefined) {
botId = GBConfigService.get('BOT_ID');
}
const instance = await this.core.loadInstance(botId);
const instance = await this.core.loadInstanceByBotId(botId);
if (instance !== null) {
const webchatTokenContainer = await this.getWebchatToken(instance);
const speechToken = instance.speechKey != null ? await this.getSTSToken(instance) : null;
@ -405,7 +409,7 @@ export class GBMinService {
min.adminService = this.adminService;
min.deployService = this.deployer;
min.kbService = new KBService(this.core.sequelize);
min.instance = await this.core.loadInstance(min.botId);
min.instance = await this.core.loadInstanceByBotId(min.botId);
min.cbMap = {};
min.scriptMap = {};
min.sandBoxMap = {};
@ -504,7 +508,7 @@ export class GBMinService {
const member = context.activity.membersAdded[0];
const persistedUser = await sec.ensureUser(instance.instanceId, member.id,
min.botId, member.id, "", "web", member.name, member.id);
member.name, "", "web", member.name);
const analytics = new AnalyticsService();

View file

@ -42,6 +42,7 @@ import { GBMinInstance, IGBDialog } from 'botlib';
import { AzureText } from 'pragmatismo-io-framework';
import { CSService } from '../services/CSService';
import { Messages } from '../strings';
import { SecService } from '../../security.gblib/services/SecService';
/**
* Dialog for feedback collecting.
@ -67,6 +68,42 @@ export class FeedbackDialog extends IGBDialog {
])
);
min.dialogs.add(
new WaterfallDialog('/t', [
async step => {
const locale = step.context.activity.locale;
let sec = new SecService();
let from = step.context.activity.from.id;
await step.context.sendActivity(Messages[locale].please_wait_transfering);
let agentSystemId = await sec.assignHumanAgent(from, min.instance.instanceId);
await min.whatsAppDirectLine.sendToDevice(agentSystemId,
Messages[locale].notify_agent(step.context.activity.from.name));
return await step.next();
}
])
);
min.dialogs.add(
new WaterfallDialog('/qt', [
async step => {
const locale = step.context.activity.locale;
let sec = new SecService();
let from = step.context.activity.from.id;
await sec.updateCurrentAgent(from, min.instance.instanceId, null);
await step.context.sendActivity(Messages[locale].notify_end_transfer(min.instance.botId));
return await step.next();
}
])
);
min.dialogs.add(
@ -111,7 +148,7 @@ export class FeedbackDialog extends IGBDialog {
await step.context.sendActivity(Messages[locale].glad_you_liked);
} else {
await step.context.sendActivity(Messages[locale].we_will_improve);
}
}
return await step.replaceDialog('/ask', { isReturning: true });
}

View file

@ -1,14 +1,17 @@
export const Messages = {
'en-US': {
about_suggestions: 'Suggestions are welcomed and improve my quality...',
about_suggestions: 'Suggestions are welcomed and improve my quality...',
what_about_service: 'What about my service?',
glad_you_liked: 'I\'m glad you liked. I\'m here for you.',
we_will_improve: 'Let\'s take note of that, thanks for sharing.',
glad_you_liked: 'I\'m glad you liked. I\'m here for you.',
we_will_improve: 'Let\'s take note of that, thanks for sharing.',
what_about_me: 'What about the service, please rate between 1 and 5.',
thanks: 'Thanks!',
im_sorry_lets_try: 'I\'m sorry. Let\'s try again...',
great_thanks: 'Great, thanks for sharing your thoughts.',
please_no_bad_words: 'Please, no bad words.'
please_no_bad_words: 'Please, no bad words.',
please_wait_transfering: 'Please, wait while I find an agent to answer you.',
notify_agent: (name) => `New call available for *${name}*, you can answer right here when you are finished, type /qt.`,
notify_end_transfer: (botName) => `Now talking to ${botName} again.`,
},
'pt-BR': {
about_suggestions: 'Sugestões melhoram muito minha qualidade...',
@ -19,6 +22,9 @@ export const Messages = {
thanks: 'Obrigado!',
im_sorry_lets_try: 'Desculpe-me, vamos tentar novamente.',
great_thanks: 'Ótimo, obrigado por contribuir com sua resposta.',
please_no_bad_words: 'Por favor, sem palavrões!'
please_no_bad_words: 'Por favor, sem palavrões!',
please_wait_transfering: 'Por favor, aguarde enquanto eu localizo alguém para te atender.',
notify_agent: (name) => `Existe um novo atendimento para *${name}*, por favor, responda aqui mesmo para a pessoa. Para finalizar, digite /qt.`
}
};

View file

@ -560,7 +560,7 @@ export class KBService implements IGBKBService {
GBLog.info(`[GBDeployer] Opening package: ${localPath}`);
const packageObject = JSON.parse(Fs.readFileSync(urlJoin(localPath, 'package.json'), 'utf8'));
const instance = await core.loadInstance(packageObject.botId);
const instance = await core.loadInstanceByBotId(packageObject.botId);
GBLog.info(`[GBDeployer] Importing: ${localPath}`);
const p = await deployer.deployPackageToStorage(instance.instanceId, packageName);
await this.importKbPackage(localPath, p, instance);

View file

@ -68,9 +68,6 @@ export class GuaribasUser extends Model<GuaribasUser> {
@Column public email: string;
@Column(DataType.STRING(512))
public internalAddress: string;
@ForeignKey(() => GuaribasInstance)
@Column
public instanceId: number;
@ -78,11 +75,15 @@ export class GuaribasUser extends Model<GuaribasUser> {
@BelongsTo(() => GuaribasInstance)
public instance: GuaribasInstance;
@Column(DataType.STRING(16))
agentSystemId: string
@Column(DataType.DATE)
@Column
phone: string
agentContacted: Date;
@Column
currentBotId: string
@Column(DataType.STRING(16))
agentMode: string;
@Column(DataType.TEXT)
@Column

View file

@ -6,6 +6,7 @@ import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from '../models';
import { ConversationReference } from 'botbuilder';
import { CollectionUtil } from 'pragmatismo-io-framework';
/**
* Security service layer.
*/
@ -37,17 +38,14 @@ export class SecService extends GBService {
public async ensureUser(
instanceId: number,
userSystemId: string,
currentBotId: string,
userName: string,
address: string,
channelName: string,
displayName: string,
phone: string
displayName: string
): Promise<GuaribasUser> {
let user = await GuaribasUser.findOne({
where: {
instanceId: instanceId,
userSystemId: userSystemId
}
});
@ -58,12 +56,9 @@ export class SecService extends GBService {
user.instanceId = instanceId;
user.userSystemId = userSystemId;
user.currentBotId = currentBotId;
user.userName = userName;
user.displayName = displayName;
user.internalAddress = address;
user.email = userName;
user.phone = phone;
user.defaultChannel = channelName;
return await user.save();
}
@ -89,29 +84,126 @@ export class SecService extends GBService {
await user.save();
}
public async updateCurrentBotId(
public async updateUserInstance(
userSystemId: string,
currentBotId: string
instanceId: number
): Promise<GuaribasUser> {
let user = await GuaribasUser.findOne({
where: {
userSystemId: userSystemId
}
});
user.currentBotId = currentBotId;
user.instanceId = instanceId;
return await user.save();
}
public async updateCurrentAgent(
userSystemId: string,
instanceId: number,
agentSystemId: string
): Promise<GuaribasUser> {
const user = await GuaribasUser.findOne({
where: {
userSystemId: userSystemId
}
});
if (agentSystemId === null) {
const agent = await GuaribasUser.findOne({
where: {
userSystemId: user.agentSystemId
}
});
if (agent !== null && agent !== undefined) {
agent.agentMode = "bot";
agent.agentSystemId = null;
await agent.save();
}
user.agentMode = "bot";
user.agentSystemId = null;
} else {
user.agentMode = "human";
user.agentSystemId = agentSystemId;
const agent = await GuaribasUser.findOne({
where: {
userSystemId: agentSystemId
}
});
agent.instanceId = user.instanceId;
agent.agentMode = "self";
agent.agentSystemId = null;
await agent.save();
}
await user.save();
return user;
}
public async getUserFromPhone(
phone: string
public async isAgentSystemId(systemId: string): Promise<Boolean> {
let user = await GuaribasUser.findOne({
where: {
userSystemId: systemId
}
});
if (user === null) {
throw `TRANSFER_TO phones must talk first to the bot before becoming an agent.`;
}
return (user.agentMode === "self");
}
public async assignHumanAgent(
userSystemId: string,
instanceId: number
): Promise<string> {
let agentSystemId;
const list = process.env.TRANSFER_TO.split(';');
await CollectionUtil.asyncForEach(list, async item => {
if (!await this.isAgentSystemId(item) && item !== undefined &&
agentSystemId === undefined && item !== userSystemId) { // TODO: Optimize loop.
agentSystemId = item;
}
});
await this.updateCurrentAgent(userSystemId, instanceId, agentSystemId);
return agentSystemId;
}
public async getUserFromSystemId(
systemId: string
): Promise<GuaribasUser> {
return await GuaribasUser.findOne({
where: {
phone: phone
userSystemId: systemId
}
});
}
public async getUserFromAgentSystemId(
systemId: string
): Promise<GuaribasUser> {
return await GuaribasUser.findOne({
where: {
agentSystemId: systemId,
}
});
}
}

View file

@ -34,11 +34,13 @@ import urlJoin = require('url-join');
const Swagger = require('swagger-client');
const rp = require('request-promise');
const fs = require('fs');
import { GBLog, GBService, GBMinInstance } from 'botlib';
import * as request from 'request-promise-native';
const fs = require('fs');
import { GBServer } from '../../../src/app';
import { GBConversationalService } from '../../core.gbapp/services/GBConversationalService';
import { SecService } from '../../security.gblib/services/SecService';
import { Messages } from '../strings';
/**
* Support for Whatsapp.
@ -53,7 +55,7 @@ export class WhatsappDirectLine extends GBService {
public whatsappServiceUrl: string;
public botId: string;
private directLineSecret: string;
private locale: string = 'pt-BR';
public conversationIds = {};
min: GBMinInstance;
@ -158,7 +160,7 @@ export class WhatsappDirectLine extends GBService {
text = await GBConversationalService.getTextFromAudioBuffer(
this.min.instance.speechKey,
this.min.instance.cloudLocation,
buf, 'pt-br'
buf, this.locale
);
}
@ -167,18 +169,75 @@ export class WhatsappDirectLine extends GBService {
let client = await this.directLineClient;
if (this.conversationIds[from] === undefined) {
GBLog.info(`GBWhatsapp: Starting new conversation on Bot.`);
const response = await client.Conversations.Conversations_StartConversation()
const generatedConversationId = response.obj.conversationId;
const id = req.body.messages[0].chatId.split('@')[0];
const senderName = req.body.messages[0].senderName;
let sec = new SecService();
this.conversationIds[from] = generatedConversationId;
const user = await sec.ensureUser(this.min.instance.instanceId, id,
senderName, "", "whatsapp", senderName);
this.pollMessages(client, generatedConversationId, from, fromName);
this.inputMessage(client, generatedConversationId, text, from, fromName);
} else {
this.inputMessage(client, conversationId, text, from, fromName);
if (user.agentMode === "self") {
let manualUser = await sec.getUserFromAgentSystemId(id);
const cmd = '/reply ';
if (text.startsWith(cmd)) {
let filename = text.substr(cmd.length);
let message = await this.min.kbService.getAnswerTextByMediaName(this.min.instance.instanceId, filename);
if (message === null) {
await this.sendToDevice(user.userSystemId, `File ${filename} not found in any .gbkb published. Check the name or publish again the associated .gbkb.`);
} else {
await this.min.conversationalService.sendMarkdownToMobile(this.min,null, user.userSystemId, message);
}
} else if (text === '/qt') {
// TODO: Transfers only in pt-br for now.
await this.sendToDevice(manualUser.userSystemId, Messages[this.locale].notify_end_transfer(this.min.instance.botId));
await this.sendToDevice(user.agentSystemId, Messages[this.locale].notify_end_transfer(this.min.instance.botId));
await sec.updateCurrentAgent(manualUser.userSystemId, this.min.instance.instanceId, null);
}
else {
GBLog.info(`HUMAN AGENT (${id}) TO USER ${manualUser.userSystemId}: ${text}`);
this.sendToDevice(manualUser.userSystemId, `${manualUser.userSystemId}: ${text}`);
}
}
else if (user.agentMode === "human") {
let agent = await sec.getUserFromSystemId(user.agentSystemId);
if (text === '/t') {
await this.sendToDevice(user.userSystemId, `Você já está sendo atendido por ${agent.userSystemId}.`);
}
else if (text === '/qt') {
// TODO: Transfers only in pt-br for now.
await this.sendToDevice(id, Messages[this.locale].notify_end_transfer(this.min.instance.botId));
await this.sendToDevice(user.agentSystemId, Messages[this.locale].notify_end_transfer(this.min.instance.botId));
await sec.updateCurrentAgent(id, this.min.instance.instanceId, null);
}
else {
GBLog.info(`USER (${id}) TO AGENT ${agent.userSystemId}: ${text}`);
this.sendToDevice(user.agentSystemId, `${id}: ${text}`);
}
}
else if (user.agentMode === "bot" || user.agentMode === null) {
if (this.conversationIds[from] === undefined) {
GBLog.info(`GBWhatsapp: Starting new conversation on Bot.`);
const response = await client.Conversations.Conversations_StartConversation()
const generatedConversationId = response.obj.conversationId;
this.conversationIds[from] = generatedConversationId;
this.pollMessages(client, generatedConversationId, from, fromName);
this.inputMessage(client, generatedConversationId, text, from, fromName);
} else {
this.inputMessage(client, conversationId, text, from, fromName);
}
}
else {
GBLog.warn(`Inconsistencty found: Invalid agentMode on User Table: ${user.agentMode}`);
}
res.end();
}
@ -320,17 +379,16 @@ export class WhatsappDirectLine extends GBService {
let url = await GBConversationalService.getAudioBufferFromText(
this.min.instance.speechKey,
this.min.instance.cloudLocation,
msg, 'pt-BR'
msg, this.locale
);
await this.sendFileToDevice(to, url, 'Audio', msg);
}
public async sendToDevice(to, msg) {
const cmd = '/audio ';
if (msg.startsWith (cmd)) {
if (msg.startsWith(cmd)) {
msg = msg.substr(cmd.length);
return await this.sendTextAsAudioToDevice(to, msg);
}

View file

@ -0,0 +1,8 @@
export const Messages = {
'en-US': {
notify_end_transfer: (botName) => `Now talking to ${botName} again.`
},
'pt-BR': {
notify_end_transfer: (botName) => `Falando com o bot ${botName} novamente.`
}
};