wingbot 3.29.0 → 3.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +17 -22
- package/plugins/ai.wingbot.goBack/plugin.js +1 -1
- package/plugins/ai.wingbot.goToLastBreadcrumb/plugin.js +1 -1
- package/plugins/ai.wingbot.jumpBack/plugin.js +1 -1
- package/plugins/ai.wingbot.jumpTo/plugin.js +1 -1
- package/plugins/ai.wingbot.stopResponding/plugin.js +3 -1
- package/src/Ai.js +59 -19
- package/src/AiMatching.js +11 -5
- package/src/BotApp.js +20 -10
- package/src/ConversationTester.js +2 -3
- package/src/OrchestratorClient.js +3 -5
- package/src/Processor.js +2 -2
- package/src/Request.js +29 -9
- package/src/graphApi/schema.gql +1 -0
- package/src/notifications/Notifications.js +31 -3
- package/src/notifications/api/notificationsApiFactory.js +51 -8
- package/src/resolvers/media.js +4 -2
- package/src/resolvers/utils.js +6 -3
- package/src/tools/MemoryBotConfigStorage.js +1 -1
- package/src/utils/customCondition.js +2 -2
- package/src/utils/getUpdate.js +4 -2
- package/src/utils/quickReplies.js +12 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wingbot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.30.0",
|
|
4
4
|
"description": "Enterprise Messaging Bot Conversation Engine",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -36,33 +36,28 @@
|
|
|
36
36
|
},
|
|
37
37
|
"homepage": "https://github.com/wingbot.ai/wingbot#readme",
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"cpy-cli": "^
|
|
40
|
-
"eslint": "^
|
|
41
|
-
"eslint-config-airbnb": "^
|
|
42
|
-
"eslint-
|
|
43
|
-
"eslint-plugin-
|
|
44
|
-
"eslint-plugin-
|
|
45
|
-
"eslint-plugin-
|
|
46
|
-
"eslint-plugin-
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"graphql-tools": "^7.0.5",
|
|
51
|
-
"jsdoc-to-markdown": "^6.0.1",
|
|
52
|
-
"mocha": "^8.2.1",
|
|
53
|
-
"move-cli": "^1.2.1",
|
|
39
|
+
"cpy-cli": "^4.1.0",
|
|
40
|
+
"eslint": "^8.11.0",
|
|
41
|
+
"eslint-config-airbnb": "^19.0.4",
|
|
42
|
+
"eslint-plugin-import": "^2.25.4",
|
|
43
|
+
"eslint-plugin-jsdoc": "^38.0.4",
|
|
44
|
+
"eslint-plugin-jsx-a11y": "^6.5.1",
|
|
45
|
+
"eslint-plugin-mocha": "^10.0.3",
|
|
46
|
+
"eslint-plugin-react": "^7.29.4",
|
|
47
|
+
"graphql-markdown": "^6.0.0",
|
|
48
|
+
"jsdoc-to-markdown": "^7.1.1",
|
|
49
|
+
"mocha": "^9.2.2",
|
|
54
50
|
"nyc": "^15.1.0",
|
|
55
51
|
"rimraf": "^3.0.2",
|
|
56
|
-
"sinon": "^
|
|
52
|
+
"sinon": "^13.0.1",
|
|
57
53
|
"tsd-jsdoc": "^2.5.0"
|
|
58
54
|
},
|
|
59
55
|
"dependencies": {
|
|
60
|
-
"graphql": "^15.
|
|
61
|
-
"graphql-mongodb-projection": "^1.1.1",
|
|
56
|
+
"graphql": "^15.8.0",
|
|
62
57
|
"jsonwebtoken": "^8.5.1",
|
|
63
|
-
"node-fetch": "^2.6.
|
|
58
|
+
"node-fetch": "^2.6.7",
|
|
64
59
|
"path-to-regexp": "^6.2.0",
|
|
65
|
-
"uuid": "^8.3.
|
|
60
|
+
"uuid": "^8.3.2",
|
|
66
61
|
"webalize": "^0.1.0"
|
|
67
62
|
},
|
|
68
63
|
"optionalDependencies": {
|
|
@@ -71,4 +66,4 @@
|
|
|
71
66
|
"request": "^2.88.0",
|
|
72
67
|
"request-promise-native": "^1.0.7"
|
|
73
68
|
}
|
|
74
|
-
}
|
|
69
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @param {import('../../src/Responder')} res
|
|
4
4
|
* @param {Function} postback
|
|
5
5
|
*/
|
|
6
|
-
module.exports = (req, res, postback)
|
|
6
|
+
module.exports = function (req, res, postback) {
|
|
7
7
|
if (req.state.beforeLastInteraction
|
|
8
8
|
&& !req.state.beforeLastInteraction.match(/\/\*$/)
|
|
9
9
|
&& req.state.beforeLastInteraction !== res.currentAction()) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @param {import('../../src/Responder')} res
|
|
4
4
|
* @param {Function} postback
|
|
5
5
|
*/
|
|
6
|
-
module.exports = (req, res, postback)
|
|
6
|
+
module.exports = function (req, res, postback) {
|
|
7
7
|
let { breadcrumbs = [] } = req.state;
|
|
8
8
|
let shift = req.state.breadcrumbAction === req.state._lastAction
|
|
9
9
|
? 2
|
package/src/Ai.js
CHANGED
|
@@ -64,6 +64,20 @@ class Ai {
|
|
|
64
64
|
*/
|
|
65
65
|
this.threshold = 0.3;
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Upper limit for NLP resolving of STT alternatives
|
|
69
|
+
*
|
|
70
|
+
* @type {number}
|
|
71
|
+
*/
|
|
72
|
+
this.sttMaxAlternatives = 3;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Minimal score to consider text as recognized well
|
|
76
|
+
*
|
|
77
|
+
* @type {number}
|
|
78
|
+
*/
|
|
79
|
+
this.sttScoreThreshold = 0;
|
|
80
|
+
|
|
67
81
|
/**
|
|
68
82
|
* The logger (console by default)
|
|
69
83
|
*
|
|
@@ -581,35 +595,61 @@ class Ai {
|
|
|
581
595
|
}
|
|
582
596
|
}
|
|
583
597
|
|
|
598
|
+
const texts = req.textAlternatives()
|
|
599
|
+
.filter((alt) => alt.score >= this.sttScoreThreshold)
|
|
600
|
+
.slice(0, this.sttMaxAlternatives);
|
|
601
|
+
|
|
602
|
+
const altMax = Math.max(0, ...texts.map((t) => t.score));
|
|
603
|
+
const altKoef = (1 - this.confidence);
|
|
604
|
+
|
|
584
605
|
const results = await Promise.all(
|
|
585
|
-
|
|
586
|
-
.
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
606
|
+
texts.map(({ text, score }) => model
|
|
607
|
+
.resolve(this.textFilter(text), req)
|
|
608
|
+
.then((res) => ({
|
|
609
|
+
...res,
|
|
610
|
+
intents: res.intents
|
|
611
|
+
.map((i) => ({
|
|
612
|
+
...i,
|
|
613
|
+
score: i.score - (altKoef * (altMax - score))
|
|
614
|
+
}))
|
|
615
|
+
.sort(({ score: a }, { score: z }) => z - a)
|
|
616
|
+
})))
|
|
592
617
|
);
|
|
593
618
|
|
|
594
619
|
results.sort(({
|
|
595
|
-
intents:
|
|
620
|
+
intents: [aIntent = { score: 0 }]
|
|
596
621
|
}, {
|
|
597
|
-
intents:
|
|
598
|
-
}) =>
|
|
599
|
-
const [{ score: aScore = 0 } = {}] = aIntents;
|
|
600
|
-
const [{ score: zScore = 0 } = {}] = zIntents;
|
|
622
|
+
intents: [zIntent = { score: 0 }]
|
|
623
|
+
}) => zIntent.score - aIntent.score);
|
|
601
624
|
|
|
602
|
-
|
|
603
|
-
const z = zAlt * zScore;
|
|
625
|
+
const [winner = { intents: [], entities: [] }, ...others] = results;
|
|
604
626
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
627
|
+
if (others.length === 0) {
|
|
628
|
+
return winner;
|
|
629
|
+
}
|
|
608
630
|
|
|
609
|
-
|
|
631
|
+
const { intents } = winner;
|
|
632
|
+
|
|
633
|
+
const known = new Set(intents.map((i) => i.intent));
|
|
634
|
+
|
|
635
|
+
others.forEach((other) => {
|
|
636
|
+
intents.push(
|
|
637
|
+
...other.intents.filter(({ score, intent }) => {
|
|
638
|
+
if (score >= this.confidence || known.has(intent)) {
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
known.add(intent);
|
|
642
|
+
return true;
|
|
643
|
+
})
|
|
644
|
+
);
|
|
610
645
|
});
|
|
611
646
|
|
|
612
|
-
|
|
647
|
+
intents.sort(({ score: a }, { score: z }) => z - a);
|
|
648
|
+
|
|
649
|
+
return {
|
|
650
|
+
...winner,
|
|
651
|
+
intents
|
|
652
|
+
};
|
|
613
653
|
}
|
|
614
654
|
|
|
615
655
|
/**
|
package/src/AiMatching.js
CHANGED
|
@@ -53,12 +53,16 @@ const COMPARE = {
|
|
|
53
53
|
* @param {Entity[]} [entities]
|
|
54
54
|
*/
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* @typedef {string|number|Function} Comparable
|
|
58
|
+
*/
|
|
59
|
+
|
|
56
60
|
/**
|
|
57
61
|
* @typedef {object} EntityExpression
|
|
58
62
|
* @prop {string} entity - the requested entity
|
|
59
63
|
* @prop {boolean} [optional] - the match is optional
|
|
60
64
|
* @prop {Compare} [op] - comparison operation
|
|
61
|
-
* @prop {
|
|
65
|
+
* @prop {Comparable[]} [compare] - value to compare
|
|
62
66
|
*/
|
|
63
67
|
|
|
64
68
|
/**
|
|
@@ -578,10 +582,12 @@ class AiMatching {
|
|
|
578
582
|
score: 1
|
|
579
583
|
};
|
|
580
584
|
|
|
581
|
-
matching = this
|
|
582
|
-
.
|
|
583
|
-
|
|
584
|
-
|
|
585
|
+
matching = this._entityIsMatching(
|
|
586
|
+
wanted.op,
|
|
587
|
+
wanted.compare,
|
|
588
|
+
requestEntity.value,
|
|
589
|
+
requestState
|
|
590
|
+
);
|
|
585
591
|
}
|
|
586
592
|
} else if (!entityExists) {
|
|
587
593
|
matching = this
|
package/src/BotApp.js
CHANGED
|
@@ -87,14 +87,12 @@ class BotApp {
|
|
|
87
87
|
this._senderLogger = chatLogStorage;
|
|
88
88
|
this._verify = promisify(jwt.verify);
|
|
89
89
|
|
|
90
|
-
this._processor = new Processor(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
);
|
|
90
|
+
this._processor = new Processor(bot, {
|
|
91
|
+
...processorOptions,
|
|
92
|
+
secret,
|
|
93
|
+
fetch: this._fetch,
|
|
94
|
+
apiUrl: gqlApiUrl
|
|
95
|
+
});
|
|
98
96
|
|
|
99
97
|
this._processor.plugin(BotApp.plugin());
|
|
100
98
|
this._preferSynchronousResponse = preferSynchronousResponse;
|
|
@@ -191,7 +189,13 @@ class BotApp {
|
|
|
191
189
|
}
|
|
192
190
|
|
|
193
191
|
async _processIncommingMessage (
|
|
194
|
-
message,
|
|
192
|
+
message,
|
|
193
|
+
senderId,
|
|
194
|
+
pageId,
|
|
195
|
+
appId,
|
|
196
|
+
secret,
|
|
197
|
+
sync = false,
|
|
198
|
+
headers = {}
|
|
195
199
|
) {
|
|
196
200
|
const { mid = null } = message;
|
|
197
201
|
|
|
@@ -386,7 +390,13 @@ class BotApp {
|
|
|
386
390
|
|
|
387
391
|
for (const message of messaging) {
|
|
388
392
|
const res = await this._processIncommingMessage(
|
|
389
|
-
message,
|
|
393
|
+
message,
|
|
394
|
+
senderId,
|
|
395
|
+
pageId,
|
|
396
|
+
appId,
|
|
397
|
+
secret,
|
|
398
|
+
sync,
|
|
399
|
+
headers
|
|
390
400
|
);
|
|
391
401
|
|
|
392
402
|
responses.push(res);
|
|
@@ -305,9 +305,8 @@ class ConversationTester {
|
|
|
305
305
|
return testCases
|
|
306
306
|
// @ts-ignore
|
|
307
307
|
.reduce(
|
|
308
|
-
(map, testCase) => map
|
|
309
|
-
testCase.list, [...(map.get(testCase.list) || []), testCase]
|
|
310
|
-
),
|
|
308
|
+
(map, testCase) => map
|
|
309
|
+
.set(testCase.list, [...(map.get(testCase.list) || []), testCase]),
|
|
311
310
|
new Map()
|
|
312
311
|
);
|
|
313
312
|
}
|
|
@@ -77,11 +77,9 @@ class OrchestratorClient {
|
|
|
77
77
|
*/
|
|
78
78
|
async addConversationTokenToUrl (url, expirationInSeconds, tokenName = 'wbchtoken') {
|
|
79
79
|
const { conversationToken } = await this.getConversationToken(expirationInSeconds);
|
|
80
|
-
return withParams(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
);
|
|
80
|
+
return withParams(url, {
|
|
81
|
+
query: { [tokenName]: conversationToken }
|
|
82
|
+
});
|
|
85
83
|
}
|
|
86
84
|
|
|
87
85
|
/**
|
package/src/Processor.js
CHANGED
|
@@ -100,7 +100,7 @@ const { mergeState } = require('./utils/stateVariables');
|
|
|
100
100
|
* @prop {string|null} [meta.targetAction]
|
|
101
101
|
*/
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
function NAME_FROM_STATE (state) {
|
|
104
104
|
if (state.user && state.user.firstName) {
|
|
105
105
|
return `${state.user.firstName} ${state.user.lastName}`;
|
|
106
106
|
}
|
|
@@ -108,7 +108,7 @@ const NAME_FROM_STATE = (state) => {
|
|
|
108
108
|
return `${state.user.name}`;
|
|
109
109
|
}
|
|
110
110
|
return null;
|
|
111
|
-
}
|
|
111
|
+
}
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
114
|
* Messaging event processor
|
package/src/Request.js
CHANGED
|
@@ -742,18 +742,36 @@ class Request {
|
|
|
742
742
|
if (!this.message || typeof this.message.text !== 'string') {
|
|
743
743
|
return [];
|
|
744
744
|
}
|
|
745
|
-
const { text, alternatives = [] } = this.message;
|
|
745
|
+
const { text: messageText, alternatives = [] } = this.message;
|
|
746
|
+
|
|
747
|
+
const unique = new Set();
|
|
748
|
+
let max = 0;
|
|
749
|
+
|
|
750
|
+
const sorted = alternatives
|
|
751
|
+
.slice()
|
|
752
|
+
.map(({ text, score = 1 }) => ({ text, score }))
|
|
753
|
+
.sort(({ score: a }, { score: z }) => z - a)
|
|
754
|
+
.filter((a) => {
|
|
755
|
+
const norm = tokenize(a.text);
|
|
756
|
+
if (unique.has(norm) || !a.text) {
|
|
757
|
+
return false;
|
|
758
|
+
}
|
|
759
|
+
max = Math.max(max, a.score);
|
|
760
|
+
unique.add(norm);
|
|
761
|
+
return true;
|
|
762
|
+
});
|
|
746
763
|
|
|
747
|
-
|
|
748
|
-
|
|
764
|
+
const normalized = tokenize(messageText);
|
|
765
|
+
|
|
766
|
+
if (unique.has(normalized)) {
|
|
767
|
+
return sorted;
|
|
749
768
|
}
|
|
750
769
|
|
|
770
|
+
max = max ? Math.min(1, max + 0.1) : 1;
|
|
771
|
+
|
|
751
772
|
return [
|
|
752
|
-
{
|
|
753
|
-
|
|
754
|
-
score: 1
|
|
755
|
-
},
|
|
756
|
-
...alternatives
|
|
773
|
+
{ text: messageText, score: max },
|
|
774
|
+
...sorted
|
|
757
775
|
];
|
|
758
776
|
}
|
|
759
777
|
|
|
@@ -1268,7 +1286,9 @@ class Request {
|
|
|
1268
1286
|
if (this._quickReplyActions === null) {
|
|
1269
1287
|
if (this.state._expectedKeywords) {
|
|
1270
1288
|
this._quickReplyActions = quickReplyAction(
|
|
1271
|
-
this.state._expectedKeywords,
|
|
1289
|
+
this.state._expectedKeywords,
|
|
1290
|
+
this,
|
|
1291
|
+
Ai.ai
|
|
1272
1292
|
);
|
|
1273
1293
|
} else {
|
|
1274
1294
|
this._quickReplyActions = [];
|
package/src/graphApi/schema.gql
CHANGED
|
@@ -103,6 +103,28 @@ const DEFAULT_CAMPAIGN_DATA = {
|
|
|
103
103
|
* @prop {number} slideRound
|
|
104
104
|
*/
|
|
105
105
|
|
|
106
|
+
/**
|
|
107
|
+
* @typedef {object} Subscription
|
|
108
|
+
* @prop {string} senderId
|
|
109
|
+
* @prop {string} pageId
|
|
110
|
+
* @prop {string} [meta]
|
|
111
|
+
*/
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @callback PreprocessSubscriptions
|
|
115
|
+
* @param {Subscription[]} subscriptions
|
|
116
|
+
* @param {string} pageId
|
|
117
|
+
* @returns {Promise<Subscription[]>|Subscription[]}
|
|
118
|
+
*/
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @callback PreprocessSubscribers
|
|
122
|
+
* @param {string[]} senderIds
|
|
123
|
+
* @param {string} pageId
|
|
124
|
+
* @param {string} tag
|
|
125
|
+
* @returns {Promise<string[]>|string[]} list of senderIds
|
|
126
|
+
*/
|
|
127
|
+
|
|
106
128
|
/**
|
|
107
129
|
* Experimental notifications service
|
|
108
130
|
*
|
|
@@ -121,7 +143,8 @@ class Notifications extends EventEmitter {
|
|
|
121
143
|
* @param {console} [options.log] - logger
|
|
122
144
|
* @param {number} [options.default24Clearance] - use this clearance to ensure delivery in 24h
|
|
123
145
|
* @param {string} [options.allAudienceTag] - tag to mark all users
|
|
124
|
-
* @param {
|
|
146
|
+
* @param {PreprocessSubscribers} [options.preprocessSubscribers] - preprocess senderIds import
|
|
147
|
+
* @param {PreprocessSubscriptions} [options.preprocessSubscriptions]
|
|
125
148
|
*/
|
|
126
149
|
constructor (notificationStorage = new NotificationsStorage(), options = {}) {
|
|
127
150
|
super();
|
|
@@ -138,6 +161,7 @@ class Notifications extends EventEmitter {
|
|
|
138
161
|
this._lts = new Map();
|
|
139
162
|
|
|
140
163
|
this._preprocessSubscribers = options.preprocessSubscribers;
|
|
164
|
+
this._preprocessSubscriptions = options.preprocessSubscriptions;
|
|
141
165
|
}
|
|
142
166
|
|
|
143
167
|
/**
|
|
@@ -150,7 +174,8 @@ class Notifications extends EventEmitter {
|
|
|
150
174
|
*/
|
|
151
175
|
api (acl = null) {
|
|
152
176
|
const options = {
|
|
153
|
-
preprocessSubscribers: this._preprocessSubscribers
|
|
177
|
+
preprocessSubscribers: this._preprocessSubscribers,
|
|
178
|
+
preprocessSubscriptions: this._preprocessSubscriptions
|
|
154
179
|
};
|
|
155
180
|
return api(this._storage, this, acl, options);
|
|
156
181
|
}
|
|
@@ -344,7 +369,10 @@ class Notifications extends EventEmitter {
|
|
|
344
369
|
|
|
345
370
|
await Promise.all(tasks
|
|
346
371
|
.map((task) => this._messageDeliveryByMid(
|
|
347
|
-
task.campaignId,
|
|
372
|
+
task.campaignId,
|
|
373
|
+
eventType,
|
|
374
|
+
senderId,
|
|
375
|
+
pageId
|
|
348
376
|
)));
|
|
349
377
|
|
|
350
378
|
return {
|
|
@@ -3,9 +3,41 @@
|
|
|
3
3
|
*/
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
|
-
const { infoToProjection } = require('graphql-mongodb-projection');
|
|
7
6
|
const apiAuthorizer = require('../../graphApi/apiAuthorizer');
|
|
8
7
|
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @param {*} info
|
|
11
|
+
* @returns {object}
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
function getFields (info) {
|
|
15
|
+
if (info.fieldNodes) {
|
|
16
|
+
const fieldNodes = info.fieldNodes.filter((k) => k.kind === 'Field');
|
|
17
|
+
|
|
18
|
+
if (fieldNodes.length !== 1) {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return getFields(fieldNodes[0]);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const nodes = info.selectionSet ? info.selectionSet.selections : info.fieldNodes;
|
|
26
|
+
|
|
27
|
+
if (!info.selectionSet) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return nodes.reduce((o, fieldInfo) => {
|
|
32
|
+
if (fieldInfo.kind !== 'Field' || !fieldInfo.name || !fieldInfo.name.value) {
|
|
33
|
+
return o;
|
|
34
|
+
}
|
|
35
|
+
return Object.assign(o, {
|
|
36
|
+
[fieldInfo.name.value]: getFields(fieldInfo)
|
|
37
|
+
});
|
|
38
|
+
}, {});
|
|
39
|
+
}
|
|
40
|
+
|
|
9
41
|
function notificationsApiFactory (storage, notifications, acl, options = {}) {
|
|
10
42
|
return {
|
|
11
43
|
async campaigns (args, ctx) {
|
|
@@ -87,9 +119,8 @@ function notificationsApiFactory (storage, notifications, acl, options = {}) {
|
|
|
87
119
|
};
|
|
88
120
|
}
|
|
89
121
|
|
|
90
|
-
const data = await storage
|
|
91
|
-
campaignId, sentWithoutReaction, pageId
|
|
92
|
-
);
|
|
122
|
+
const data = await storage
|
|
123
|
+
.getUnsuccessfulSubscribersByCampaign(campaignId, sentWithoutReaction, pageId);
|
|
93
124
|
|
|
94
125
|
return {
|
|
95
126
|
data,
|
|
@@ -115,7 +146,7 @@ function notificationsApiFactory (storage, notifications, acl, options = {}) {
|
|
|
115
146
|
return null;
|
|
116
147
|
}
|
|
117
148
|
|
|
118
|
-
const fields =
|
|
149
|
+
const fields = getFields(info);
|
|
119
150
|
|
|
120
151
|
const {
|
|
121
152
|
include,
|
|
@@ -132,7 +163,15 @@ function notificationsApiFactory (storage, notifications, acl, options = {}) {
|
|
|
132
163
|
}
|
|
133
164
|
|
|
134
165
|
if (fields.data) {
|
|
135
|
-
const res = storage
|
|
166
|
+
const res = await storage
|
|
167
|
+
.getSubscribtions(include, exclude, limit, pageId, lastKey);
|
|
168
|
+
|
|
169
|
+
if (fields.data.meta && typeof options.preprocessSubscriptions === 'function') {
|
|
170
|
+
res.data = await Promise.resolve(
|
|
171
|
+
options.preprocessSubscriptions(res.data, pageId)
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
136
175
|
return Object.assign(res, { count });
|
|
137
176
|
}
|
|
138
177
|
|
|
@@ -159,8 +198,12 @@ function notificationsApiFactory (storage, notifications, acl, options = {}) {
|
|
|
159
198
|
);
|
|
160
199
|
}
|
|
161
200
|
|
|
162
|
-
|
|
163
|
-
|
|
201
|
+
// make it little bit faster
|
|
202
|
+
while (senderIds.length > 0) {
|
|
203
|
+
await Promise.all(
|
|
204
|
+
senderIds.splice(0, 5)
|
|
205
|
+
.map((senderId) => storage.subscribe(`${senderId}`, pageId, tag))
|
|
206
|
+
);
|
|
164
207
|
}
|
|
165
208
|
|
|
166
209
|
return true;
|
package/src/resolvers/media.js
CHANGED
|
@@ -7,9 +7,11 @@ const Router = require('../Router');
|
|
|
7
7
|
const getCondition = require('../utils/getCondition');
|
|
8
8
|
const { stateData, cachedTranslatedCompilator } = require('./utils');
|
|
9
9
|
|
|
10
|
-
function media (
|
|
10
|
+
function media (
|
|
11
|
+
params,
|
|
11
12
|
// @ts-ignore
|
|
12
|
-
{ isLastIndex } = {}
|
|
13
|
+
{ isLastIndex } = {}
|
|
14
|
+
) {
|
|
13
15
|
const { type, url } = params;
|
|
14
16
|
|
|
15
17
|
const urlString = url || '';
|
package/src/resolvers/utils.js
CHANGED
|
@@ -202,18 +202,21 @@ function getText (text, state) {
|
|
|
202
202
|
return renderer(state);
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
// eslint-disable-next-line no-unused-vars
|
|
206
|
+
const DEFAULT_LINK_TRANSLATOR = (senderId, defaultText, urlText, isExtUrl, reqState) => urlText;
|
|
207
|
+
|
|
205
208
|
function processButtons (
|
|
206
209
|
buttons,
|
|
207
210
|
state,
|
|
208
211
|
elem,
|
|
209
212
|
linksMap,
|
|
210
213
|
senderId,
|
|
211
|
-
|
|
212
|
-
linksTranslator = (sndr, defaultText, urlText, isExtUrl, reqState) => urlText,
|
|
214
|
+
linksTranslator,
|
|
213
215
|
allowForbiddenSnippetWords,
|
|
214
216
|
req,
|
|
215
217
|
res
|
|
216
218
|
) {
|
|
219
|
+
const translateLinks = linksTranslator || DEFAULT_LINK_TRANSLATOR;
|
|
217
220
|
|
|
218
221
|
buttons.forEach(({
|
|
219
222
|
title: btnTitle,
|
|
@@ -251,7 +254,7 @@ function processButtons (
|
|
|
251
254
|
case TYPE_URL_WITH_EXT: {
|
|
252
255
|
const hasExtention = type === TYPE_URL_WITH_EXT;
|
|
253
256
|
let urlText = getText(url, state);
|
|
254
|
-
urlText =
|
|
257
|
+
urlText = translateLinks(senderId, defaultText, urlText, isExtUrl, state);
|
|
255
258
|
elem.urlButton(btnTitleText, urlText, hasExtention, webviewHeight);
|
|
256
259
|
break;
|
|
257
260
|
}
|
|
@@ -22,7 +22,7 @@ class MemoryBotConfigStorage {
|
|
|
22
22
|
* @param {Function|string[]} [acl] - acl configuration
|
|
23
23
|
* @returns {{updateBot:Function}}
|
|
24
24
|
*/
|
|
25
|
-
api (onUpdate = () => Promise.resolve(), acl) {
|
|
25
|
+
api (onUpdate = () => Promise.resolve(), acl = []) {
|
|
26
26
|
const storage = this;
|
|
27
27
|
return {
|
|
28
28
|
async updateBot (args, ctx) {
|
|
@@ -42,7 +42,7 @@ const isSimpleWord = (string) => {
|
|
|
42
42
|
const isStringNumber = (string) => {
|
|
43
43
|
if (typeof string !== 'string') return false;
|
|
44
44
|
if (string.length === 0) return false;
|
|
45
|
-
return
|
|
45
|
+
return !!/^([0-9]*[, ]{0,1})*[., ]{0,1}[0-9]*$/
|
|
46
46
|
.test((string).replace(/\s+/g, ''));
|
|
47
47
|
};
|
|
48
48
|
|
|
@@ -55,7 +55,7 @@ const stringToNumber = (string) => {
|
|
|
55
55
|
if (typeof string !== 'string') return string;
|
|
56
56
|
if (!isStringNumber(string)) throw new Error('String not a number');
|
|
57
57
|
let trimmed;
|
|
58
|
-
if (
|
|
58
|
+
if (/^[^,.]+,[^,.]+$/.test(string)) {
|
|
59
59
|
trimmed = string.replace(',', '.');
|
|
60
60
|
} else {
|
|
61
61
|
trimmed = string.replace(/(\s|,)+/g, '').replace(',', '.');
|
package/src/utils/getUpdate.js
CHANGED
|
@@ -88,8 +88,10 @@ function toArray (previousValue) {
|
|
|
88
88
|
const ENTITY_HBS_REGEXP = /^\s*\{\{\[?@([^@[\]{}\s]+)(\])?\}\}\s*$/;
|
|
89
89
|
const VARIABLE_HBS_REGEXP = /^\s*\{\{\[?([^@[\]{}\s]+)\]?\}\}\s*$/;
|
|
90
90
|
|
|
91
|
-
function getSetState (setState
|
|
92
|
-
|
|
91
|
+
function getSetState (setState, req, res = null, useState = null) {
|
|
92
|
+
if (!setState) {
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
93
95
|
const keys = Object.keys(setState)
|
|
94
96
|
.filter((k) => k !== '_');
|
|
95
97
|
|
|
@@ -32,7 +32,12 @@ const { checkSetState } = require('./stateVariables');
|
|
|
32
32
|
* @returns {ExpectedKeyword}
|
|
33
33
|
*/
|
|
34
34
|
function makeExpectedKeyword (
|
|
35
|
-
action,
|
|
35
|
+
action,
|
|
36
|
+
title,
|
|
37
|
+
matcher = null,
|
|
38
|
+
payloadData = {},
|
|
39
|
+
setState = null,
|
|
40
|
+
aiTitle = null
|
|
36
41
|
) {
|
|
37
42
|
let match = null;
|
|
38
43
|
|
|
@@ -226,7 +231,12 @@ function makeQuickReplies (replies, path = '', translate = (w) => w, quickReplyC
|
|
|
226
231
|
const translatedTitle = translate(title);
|
|
227
232
|
const translatedAiTitle = typeof aiTitle === 'string' ? translate(aiTitle) : aiTitle;
|
|
228
233
|
const expect = makeExpectedKeyword(
|
|
229
|
-
absoluteAction,
|
|
234
|
+
absoluteAction,
|
|
235
|
+
translatedTitle,
|
|
236
|
+
match,
|
|
237
|
+
data,
|
|
238
|
+
setState,
|
|
239
|
+
translatedAiTitle
|
|
230
240
|
);
|
|
231
241
|
expectedKeywords.push(expect);
|
|
232
242
|
|