diff --git a/DATABASE-CHANGES.md b/DATABASE-CHANGES.md new file mode 100644 index 00000000..7c6374f4 --- /dev/null +++ b/DATABASE-CHANGES.md @@ -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 + +``` \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7b25a35c..e04b67c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index aa981e4a..133e1ff5 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/packages/core.gbapp/dialogs/SwitchBot.ts b/packages/core.gbapp/dialogs/SwitchBot.ts index bfb0e40b..27185ff4 100644 --- a/packages/core.gbapp/dialogs/SwitchBot.ts +++ b/packages/core.gbapp/dialogs/SwitchBot.ts @@ -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(); diff --git a/packages/core.gbapp/services/GBConversationalService.ts b/packages/core.gbapp/services/GBConversationalService.ts index e879993b..452cff8f 100644 --- a/packages/core.gbapp/services/GBConversationalService.ts +++ b/packages/core.gbapp/services/GBConversationalService.ts @@ -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 { diff --git a/packages/core.gbapp/services/GBCoreService.ts b/packages/core.gbapp/services/GBCoreService.ts index e6b22cc4..67fdae47 100644 --- a/packages/core.gbapp/services/GBCoreService.ts +++ b/packages/core.gbapp/services/GBCoreService.ts @@ -233,7 +233,7 @@ export class GBCoreService implements IGBCoreService { /** * Loads just one Bot instance. */ - public async loadInstance(botId: string): Promise { + public async loadInstanceByBotId(botId: string): Promise { const options = { where: {} }; options.where = { botId: botId }; diff --git a/packages/core.gbapp/services/GBDeployer.ts b/packages/core.gbapp/services/GBDeployer.ts index 7294b3bf..d0a1bdfc 100644 --- a/packages/core.gbapp/services/GBDeployer.ts +++ b/packages/core.gbapp/services/GBDeployer.ts @@ -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; diff --git a/packages/core.gbapp/services/GBImporterService.ts b/packages/core.gbapp/services/GBImporterService.ts index 204db1df..9dbcb18e 100644 --- a/packages/core.gbapp/services/GBImporterService.ts +++ b/packages/core.gbapp/services/GBImporterService.ts @@ -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}.`); diff --git a/packages/core.gbapp/services/GBMinService.ts b/packages/core.gbapp/services/GBMinService.ts index d5bbeb8f..01a0f43c 100644 --- a/packages/core.gbapp/services/GBMinService.ts +++ b/packages/core.gbapp/services/GBMinService.ts @@ -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(); diff --git a/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts b/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts index c469d512..4a4f1d6e 100644 --- a/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts +++ b/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts @@ -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 }); } diff --git a/packages/customer-satisfaction.gbapp/strings.ts b/packages/customer-satisfaction.gbapp/strings.ts index 123496ab..89414bbd 100644 --- a/packages/customer-satisfaction.gbapp/strings.ts +++ b/packages/customer-satisfaction.gbapp/strings.ts @@ -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.` + } }; diff --git a/packages/kb.gbapp/services/KBService.ts b/packages/kb.gbapp/services/KBService.ts index c82df06f..9751e122 100644 --- a/packages/kb.gbapp/services/KBService.ts +++ b/packages/kb.gbapp/services/KBService.ts @@ -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); diff --git a/packages/security.gblib/models/index.ts b/packages/security.gblib/models/index.ts index 45e0e012..f9324d78 100644 --- a/packages/security.gblib/models/index.ts +++ b/packages/security.gblib/models/index.ts @@ -68,9 +68,6 @@ export class GuaribasUser extends Model { @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 { @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 diff --git a/packages/security.gblib/services/SecService.ts b/packages/security.gblib/services/SecService.ts index 39839357..5a64963e 100644 --- a/packages/security.gblib/services/SecService.ts +++ b/packages/security.gblib/services/SecService.ts @@ -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 { 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 { + + + 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 { + 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 { + 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 { + + 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 { return await GuaribasUser.findOne({ where: { - phone: phone + userSystemId: systemId } }); } + public async getUserFromAgentSystemId( + systemId: string + ): Promise { + return await GuaribasUser.findOne({ + where: { + agentSystemId: systemId, + + } + }); + } } diff --git a/packages/whatsapp.gblib/services/WhatsappDirectLine.ts b/packages/whatsapp.gblib/services/WhatsappDirectLine.ts index 652a04cc..526cfa8c 100644 --- a/packages/whatsapp.gblib/services/WhatsappDirectLine.ts +++ b/packages/whatsapp.gblib/services/WhatsappDirectLine.ts @@ -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); } diff --git a/packages/whatsapp.gblib/strings.ts b/packages/whatsapp.gblib/strings.ts new file mode 100644 index 00000000..45b9ed19 --- /dev/null +++ b/packages/whatsapp.gblib/strings.ts @@ -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.` + } +};