wingbot-mongodb 2.16.3 → 2.19.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/.mocharc.js +14 -0
- package/.nyc_output/8e3ceac5-95c5-4bf9-a069-da51cccc2525.json +1 -0
- package/.nyc_output/processinfo/8e3ceac5-95c5-4bf9-a069-da51cccc2525.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -1
- package/README.md +58 -50
- package/package.json +21 -20
- package/src/AuditLogStorage.js +364 -0
- package/src/BaseStorage.js +73 -30
- package/src/BotConfigStorage.js +18 -7
- package/src/BotTokenStorage.js +3 -3
- package/src/ChatLogStorage.js +65 -34
- package/src/NotificationsStorage.js +37 -37
- package/src/StateStorage.js +36 -138
- package/src/main.js +3 -1
- package/.nyc_output/5a4dc5e6-8e98-4d63-a4fc-e2fe688626a9.json +0 -1
- package/.nyc_output/ccf7d45a-e479-43d4-862d-f3f229049ae1.json +0 -1
- package/.nyc_output/processinfo/5a4dc5e6-8e98-4d63-a4fc-e2fe688626a9.json +0 -1
- package/.nyc_output/processinfo/ccf7d45a-e479-43d4-862d-f3f229049ae1.json +0 -1
package/src/ChatLogStorage.js
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
|
-
const mongodb = require('mongodb'); // eslint-disable-line no-unused-vars
|
|
7
6
|
const BaseStorage = require('./BaseStorage');
|
|
8
7
|
|
|
9
8
|
const PAGE_SENDER_TIMESTAMP = 'pageId_1_senderId_1_timestamp_-1';
|
|
10
9
|
const TIMESTAMP = 'timestamp_1';
|
|
11
10
|
|
|
11
|
+
/** @typedef {import('mongodb/lib/db')} Db */
|
|
12
|
+
|
|
12
13
|
/**
|
|
13
14
|
* Storage for conversation logs
|
|
14
15
|
*
|
|
@@ -18,12 +19,13 @@ class ChatLogStorage extends BaseStorage {
|
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
*
|
|
21
|
-
* @param {
|
|
22
|
+
* @param {Db|{():Promise<Db>}} mongoDb
|
|
22
23
|
* @param {string} collectionName
|
|
23
24
|
* @param {{error:Function,log:Function}} [log] - console like logger
|
|
24
|
-
* @param {boolean} isCosmo
|
|
25
|
+
* @param {boolean} [isCosmo]
|
|
26
|
+
* @param {string|Promise<string>} [secret]
|
|
25
27
|
*/
|
|
26
|
-
constructor (mongoDb, collectionName = 'chatlogs', log = console, isCosmo = false) {
|
|
28
|
+
constructor (mongoDb, collectionName = 'chatlogs', log = console, isCosmo = false, secret = null) {
|
|
27
29
|
super(mongoDb, collectionName, log, isCosmo);
|
|
28
30
|
|
|
29
31
|
this.addIndex({
|
|
@@ -43,6 +45,7 @@ class ChatLogStorage extends BaseStorage {
|
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
this.muteErrors = true;
|
|
48
|
+
this._secret = secret;
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
/**
|
|
@@ -54,6 +57,7 @@ class ChatLogStorage extends BaseStorage {
|
|
|
54
57
|
* @param {number} [limit]
|
|
55
58
|
* @param {number} [endAt] - iterate backwards to history
|
|
56
59
|
* @param {number} [startAt] - iterate forward to last interaction
|
|
60
|
+
* @returns {Promise<object[]>}
|
|
57
61
|
*/
|
|
58
62
|
async getInteractions (senderId, pageId, limit = 10, endAt = null, startAt = null) {
|
|
59
63
|
const c = await this._getCollection();
|
|
@@ -80,44 +84,79 @@ class ChatLogStorage extends BaseStorage {
|
|
|
80
84
|
const res = await c.find(q)
|
|
81
85
|
.limit(limit)
|
|
82
86
|
.sort({ timestamp: orderBackwards ? 1 : -1 })
|
|
83
|
-
.project({ _id: 0
|
|
87
|
+
.project({ _id: 0 })
|
|
84
88
|
.toArray();
|
|
85
89
|
|
|
86
90
|
if (!orderBackwards) {
|
|
87
91
|
res.reverse();
|
|
88
92
|
}
|
|
89
93
|
|
|
90
|
-
|
|
94
|
+
if (!this._secret) {
|
|
95
|
+
return res.map((r) => Object.assign(r, { ok: null }));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const secret = await Promise.resolve(this._secret);
|
|
99
|
+
|
|
100
|
+
return res.map((r) => {
|
|
101
|
+
const {
|
|
102
|
+
sign,
|
|
103
|
+
...log
|
|
104
|
+
} = r;
|
|
105
|
+
const objToSign = this._objectToSign(log);
|
|
106
|
+
const compare = this._signWithSecret(objToSign, secret);
|
|
107
|
+
const ok = compare === sign;
|
|
108
|
+
if (!ok) {
|
|
109
|
+
this._log.error(`ChatLog: found wrong signature at pageId: "${r.pageId}", senderId: "${r.senderId}", at: ${r.timestamp}`, r);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return Object.assign(log, { ok });
|
|
113
|
+
});
|
|
91
114
|
}
|
|
92
115
|
|
|
93
116
|
/**
|
|
94
117
|
* Log single event
|
|
95
118
|
*
|
|
96
119
|
* @param {string} senderId
|
|
97
|
-
* @param {
|
|
98
|
-
* @param {
|
|
99
|
-
* @param {
|
|
120
|
+
* @param {object[]} responses - list of sent responses
|
|
121
|
+
* @param {object} request - event request
|
|
122
|
+
* @param {object} [metadata] - request metadata
|
|
100
123
|
* @returns {Promise}
|
|
101
124
|
*/
|
|
102
125
|
log (senderId, responses = [], request = {}, metadata = {}) {
|
|
103
126
|
const log = {
|
|
104
127
|
senderId,
|
|
105
|
-
time: new Date(request.timestamp || Date.now()),
|
|
106
128
|
request,
|
|
107
|
-
responses
|
|
129
|
+
responses,
|
|
130
|
+
...metadata
|
|
108
131
|
};
|
|
109
132
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return this._getCollection()
|
|
113
|
-
.then(c => c.insertOne(log))
|
|
114
|
-
.catch((err) => {
|
|
115
|
-
this._log.error('Failed to store chat log', err, log);
|
|
133
|
+
return this._storeLog(log);
|
|
134
|
+
}
|
|
116
135
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
136
|
+
async _storeLog (event) {
|
|
137
|
+
let log = event;
|
|
138
|
+
if (!event.timestamp) {
|
|
139
|
+
Object.assign(event, {
|
|
140
|
+
timestamp: event.request.timestamp || Date.now()
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
if (typeof event.pageId === 'undefined') {
|
|
144
|
+
Object.assign(event, {
|
|
145
|
+
pageId: null
|
|
120
146
|
});
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
const c = await this._getCollection();
|
|
150
|
+
log = await this._sign(log);
|
|
151
|
+
// @ts-ignore
|
|
152
|
+
await c.insertOne(log);
|
|
153
|
+
} catch (e) {
|
|
154
|
+
this._log.error('Failed to store chat log', e, log);
|
|
155
|
+
|
|
156
|
+
if (!this.muteErrors) {
|
|
157
|
+
throw e;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
121
160
|
}
|
|
122
161
|
|
|
123
162
|
/**
|
|
@@ -127,31 +166,23 @@ class ChatLogStorage extends BaseStorage {
|
|
|
127
166
|
* @name ChatLog#error
|
|
128
167
|
* @param {any} err - error
|
|
129
168
|
* @param {string} senderId
|
|
130
|
-
* @param {
|
|
131
|
-
* @param {
|
|
132
|
-
* @param {
|
|
169
|
+
* @param {object[]} [responses] - list of sent responses
|
|
170
|
+
* @param {object} [request] - event request
|
|
171
|
+
* @param {object} [metadata] - request metadata
|
|
133
172
|
* @returns {Promise}
|
|
134
173
|
*/
|
|
135
174
|
error (err, senderId, responses = [], request = {}, metadata = {}) {
|
|
136
175
|
const log = {
|
|
137
176
|
senderId,
|
|
138
|
-
time: new Date(request.timestamp || Date.now()),
|
|
139
177
|
request,
|
|
140
178
|
responses,
|
|
141
|
-
err: `${err}
|
|
179
|
+
err: `${err}`,
|
|
180
|
+
...metadata
|
|
142
181
|
};
|
|
143
182
|
|
|
144
183
|
Object.assign(log, metadata);
|
|
145
184
|
|
|
146
|
-
return this.
|
|
147
|
-
.then(c => c.insertOne(log))
|
|
148
|
-
.catch((storeError) => {
|
|
149
|
-
this._log.error('Failed to store chat log', storeError, log);
|
|
150
|
-
|
|
151
|
-
if (!this.muteErrors) {
|
|
152
|
-
throw storeError;
|
|
153
|
-
}
|
|
154
|
-
});
|
|
185
|
+
return this._storeLog(log);
|
|
155
186
|
}
|
|
156
187
|
|
|
157
188
|
}
|
|
@@ -21,7 +21,7 @@ const { ObjectID } = mongodb;
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* @typedef Campaign {
|
|
24
|
+
* @typedef Campaign {object}
|
|
25
25
|
* @prop {string} id
|
|
26
26
|
* @prop {string} name
|
|
27
27
|
*
|
|
@@ -45,7 +45,7 @@ const { ObjectID } = mongodb;
|
|
|
45
45
|
* Interaction
|
|
46
46
|
*
|
|
47
47
|
* @prop {string} action
|
|
48
|
-
* @prop {
|
|
48
|
+
* @prop {object} [data]
|
|
49
49
|
*
|
|
50
50
|
* Setup
|
|
51
51
|
*
|
|
@@ -72,7 +72,6 @@ const { ObjectID } = mongodb;
|
|
|
72
72
|
* @prop {number} [leaved] - time the event was not sent because user left
|
|
73
73
|
*/
|
|
74
74
|
|
|
75
|
-
|
|
76
75
|
const MAX_TS = 9999999999999;
|
|
77
76
|
const COSMO_LIMIT = 999;
|
|
78
77
|
|
|
@@ -114,7 +113,7 @@ class NotificationsStorage {
|
|
|
114
113
|
const collections = await db.collections();
|
|
115
114
|
|
|
116
115
|
collection = collections
|
|
117
|
-
.find(c => c.collectionName === name);
|
|
116
|
+
.find((c) => c.collectionName === name);
|
|
118
117
|
|
|
119
118
|
if (!collection) {
|
|
120
119
|
try {
|
|
@@ -223,7 +222,7 @@ class NotificationsStorage {
|
|
|
223
222
|
}
|
|
224
223
|
|
|
225
224
|
await Promise.all(existing
|
|
226
|
-
.filter(e => !['_id_', '_id'].includes(e.name) && !indexes.some(i => e.name === i.options.name))
|
|
225
|
+
.filter((e) => !['_id_', '_id'].includes(e.name) && !indexes.some((i) => e.name === i.options.name))
|
|
227
226
|
.map((e) => {
|
|
228
227
|
// eslint-disable-next-line no-console
|
|
229
228
|
this._log.log(`dropping index ${e.name}`);
|
|
@@ -235,8 +234,8 @@ class NotificationsStorage {
|
|
|
235
234
|
}));
|
|
236
235
|
|
|
237
236
|
await Promise.all(indexes
|
|
238
|
-
.filter(i => !existing.some(e => e.name === i.options.name))
|
|
239
|
-
.map(i => collection
|
|
237
|
+
.filter((i) => !existing.some((e) => e.name === i.options.name))
|
|
238
|
+
.map((i) => collection
|
|
240
239
|
.createIndex(i.index, i.options)
|
|
241
240
|
// @ts-ignore
|
|
242
241
|
.catch((e) => {
|
|
@@ -251,7 +250,7 @@ class NotificationsStorage {
|
|
|
251
250
|
|
|
252
251
|
/**
|
|
253
252
|
*
|
|
254
|
-
* @param {
|
|
253
|
+
* @param {object} tasks
|
|
255
254
|
* @returns {Promise<Task[]>}
|
|
256
255
|
*/
|
|
257
256
|
async pushTasks (tasks) {
|
|
@@ -267,7 +266,7 @@ class NotificationsStorage {
|
|
|
267
266
|
campaignId, senderId, pageId, sent
|
|
268
267
|
} = task;
|
|
269
268
|
|
|
270
|
-
const $set =
|
|
269
|
+
const $set = { ...task };
|
|
271
270
|
|
|
272
271
|
const filter = {
|
|
273
272
|
campaignId, senderId, pageId, sent
|
|
@@ -338,7 +337,7 @@ class NotificationsStorage {
|
|
|
338
337
|
} else {
|
|
339
338
|
override = missingIds.get(i);
|
|
340
339
|
}
|
|
341
|
-
return
|
|
340
|
+
return { ...task, ...override };
|
|
342
341
|
});
|
|
343
342
|
}
|
|
344
343
|
|
|
@@ -382,7 +381,7 @@ class NotificationsStorage {
|
|
|
382
381
|
}
|
|
383
382
|
}, {
|
|
384
383
|
sort: { enqueue: 1 },
|
|
385
|
-
|
|
384
|
+
returnDocument: 'after'
|
|
386
385
|
});
|
|
387
386
|
if (found.value) {
|
|
388
387
|
pop.push(this._mapGenericObject(found.value));
|
|
@@ -464,7 +463,7 @@ class NotificationsStorage {
|
|
|
464
463
|
/**
|
|
465
464
|
*
|
|
466
465
|
* @param {string} taskId
|
|
467
|
-
* @param {
|
|
466
|
+
* @param {object} data
|
|
468
467
|
*/
|
|
469
468
|
async updateTask (taskId, data) {
|
|
470
469
|
const c = await this._getCollection(this.taksCollection);
|
|
@@ -476,7 +475,7 @@ class NotificationsStorage {
|
|
|
476
475
|
}, {
|
|
477
476
|
$set: data
|
|
478
477
|
}, {
|
|
479
|
-
|
|
478
|
+
returnDocument: 'after'
|
|
480
479
|
});
|
|
481
480
|
|
|
482
481
|
return this._mapGenericObject(res.value);
|
|
@@ -530,7 +529,7 @@ class NotificationsStorage {
|
|
|
530
529
|
.project({ campaignId: 1, _id: 0 })
|
|
531
530
|
.toArray();
|
|
532
531
|
|
|
533
|
-
return data.map(d => d.campaignId);
|
|
532
|
+
return data.map((d) => d.campaignId);
|
|
534
533
|
}
|
|
535
534
|
}
|
|
536
535
|
|
|
@@ -558,7 +557,7 @@ class NotificationsStorage {
|
|
|
558
557
|
}
|
|
559
558
|
|
|
560
559
|
const result = await Promise.all(
|
|
561
|
-
tasks.map(task => c.findOneAndUpdate({
|
|
560
|
+
tasks.map((task) => c.findOneAndUpdate({
|
|
562
561
|
_id: task._id,
|
|
563
562
|
[eventType]: null
|
|
564
563
|
}, {
|
|
@@ -566,19 +565,19 @@ class NotificationsStorage {
|
|
|
566
565
|
[eventType]: ts
|
|
567
566
|
}
|
|
568
567
|
}, {
|
|
569
|
-
|
|
568
|
+
returnDocument: 'after'
|
|
570
569
|
}))
|
|
571
570
|
);
|
|
572
571
|
|
|
573
572
|
return result
|
|
574
|
-
.map(res => (res.value ? this._mapGenericObject(res.value) : null))
|
|
575
|
-
.filter(r => r !== null);
|
|
573
|
+
.map((res) => (res.value ? this._mapGenericObject(res.value) : null))
|
|
574
|
+
.filter((r) => r !== null);
|
|
576
575
|
}
|
|
577
576
|
|
|
578
577
|
/**
|
|
579
578
|
*
|
|
580
|
-
* @param {
|
|
581
|
-
* @param {
|
|
579
|
+
* @param {object} campaign
|
|
580
|
+
* @param {object} [updateCampaign]
|
|
582
581
|
* @returns {Promise<Campaign>}
|
|
583
582
|
*/
|
|
584
583
|
async upsertCampaign (campaign, updateCampaign = null) {
|
|
@@ -586,7 +585,7 @@ class NotificationsStorage {
|
|
|
586
585
|
|
|
587
586
|
let ret;
|
|
588
587
|
if (campaign.id) {
|
|
589
|
-
const $setOnInsert =
|
|
588
|
+
const $setOnInsert = { ...campaign };
|
|
590
589
|
delete $setOnInsert.id;
|
|
591
590
|
const update = {};
|
|
592
591
|
if (Object.keys($setOnInsert).length !== 0) {
|
|
@@ -603,12 +602,12 @@ class NotificationsStorage {
|
|
|
603
602
|
id: campaign.id
|
|
604
603
|
}, update, {
|
|
605
604
|
upsert: true,
|
|
606
|
-
|
|
605
|
+
returnDocument: 'after'
|
|
607
606
|
});
|
|
608
607
|
ret = this._mapCampaign(res.value);
|
|
609
608
|
} else {
|
|
610
609
|
const id = new ObjectID();
|
|
611
|
-
ret =
|
|
610
|
+
ret = { id: id.toHexString(), _id: id, ...campaign };
|
|
612
611
|
if (updateCampaign) {
|
|
613
612
|
Object.assign(ret, updateCampaign);
|
|
614
613
|
}
|
|
@@ -635,7 +634,7 @@ class NotificationsStorage {
|
|
|
635
634
|
/**
|
|
636
635
|
*
|
|
637
636
|
* @param {string} campaignId
|
|
638
|
-
* @param {
|
|
637
|
+
* @param {object} increment
|
|
639
638
|
* @returns {Promise}
|
|
640
639
|
*/
|
|
641
640
|
async incrementCampaign (campaignId, increment = {}) {
|
|
@@ -651,7 +650,7 @@ class NotificationsStorage {
|
|
|
651
650
|
/**
|
|
652
651
|
*
|
|
653
652
|
* @param {string} campaignId
|
|
654
|
-
* @param {
|
|
653
|
+
* @param {object} data
|
|
655
654
|
* @returns {Promise<Campaign|null>}
|
|
656
655
|
*/
|
|
657
656
|
async updateCampaign (campaignId, data) {
|
|
@@ -662,7 +661,7 @@ class NotificationsStorage {
|
|
|
662
661
|
}, {
|
|
663
662
|
$set: data
|
|
664
663
|
}, {
|
|
665
|
-
|
|
664
|
+
returnDocument: 'after'
|
|
666
665
|
});
|
|
667
666
|
|
|
668
667
|
return this._mapCampaign(res.value);
|
|
@@ -682,7 +681,7 @@ class NotificationsStorage {
|
|
|
682
681
|
}, {
|
|
683
682
|
$set: { startAt: null }
|
|
684
683
|
}, {
|
|
685
|
-
|
|
684
|
+
returnDocument: 'before'
|
|
686
685
|
});
|
|
687
686
|
|
|
688
687
|
return this._mapCampaign(res.value);
|
|
@@ -717,16 +716,16 @@ class NotificationsStorage {
|
|
|
717
716
|
}
|
|
718
717
|
})
|
|
719
718
|
.limit(campaignIds.length)
|
|
720
|
-
.map(camp => this._mapCampaign(camp));
|
|
719
|
+
.map((camp) => this._mapCampaign(camp));
|
|
721
720
|
|
|
722
721
|
return cursor.toArray();
|
|
723
722
|
}
|
|
724
723
|
|
|
725
724
|
/**
|
|
726
725
|
*
|
|
727
|
-
* @param {
|
|
726
|
+
* @param {object} condition
|
|
728
727
|
* @param {number} [limit]
|
|
729
|
-
* @param {
|
|
728
|
+
* @param {object} [lastKey]
|
|
730
729
|
* @returns {Promise<{data:Campaign[],lastKey:string}>}
|
|
731
730
|
*/
|
|
732
731
|
async getCampaigns (condition, limit = null, lastKey = null) {
|
|
@@ -737,11 +736,12 @@ class NotificationsStorage {
|
|
|
737
736
|
if (lastKey !== null) {
|
|
738
737
|
const key = JSON.parse(Buffer.from(lastKey, 'base64').toString('utf8'));
|
|
739
738
|
|
|
740
|
-
useCondition =
|
|
739
|
+
useCondition = {
|
|
740
|
+
...useCondition,
|
|
741
741
|
_id: {
|
|
742
742
|
$lt: ObjectID.createFromHexString(key._id)
|
|
743
743
|
}
|
|
744
|
-
}
|
|
744
|
+
};
|
|
745
745
|
}
|
|
746
746
|
|
|
747
747
|
const cursor = c.find(useCondition)
|
|
@@ -764,7 +764,7 @@ class NotificationsStorage {
|
|
|
764
764
|
}
|
|
765
765
|
|
|
766
766
|
return {
|
|
767
|
-
data: data.map(camp => this._mapCampaign(camp)),
|
|
767
|
+
data: data.map((camp) => this._mapCampaign(camp)),
|
|
768
768
|
lastKey: nextLastKey
|
|
769
769
|
};
|
|
770
770
|
}
|
|
@@ -807,7 +807,7 @@ class NotificationsStorage {
|
|
|
807
807
|
}, {
|
|
808
808
|
$pull: { subs: tag }
|
|
809
809
|
}, {
|
|
810
|
-
|
|
810
|
+
returnDocument: 'after'
|
|
811
811
|
});
|
|
812
812
|
|
|
813
813
|
if (res.value) {
|
|
@@ -880,11 +880,12 @@ class NotificationsStorage {
|
|
|
880
880
|
if (lastKey !== null) {
|
|
881
881
|
const key = JSON.parse(Buffer.from(lastKey, 'base64').toString('utf8'));
|
|
882
882
|
|
|
883
|
-
condition =
|
|
883
|
+
condition = {
|
|
884
|
+
...condition,
|
|
884
885
|
_id: {
|
|
885
886
|
$gt: ObjectID.createFromHexString(key._id)
|
|
886
887
|
}
|
|
887
|
-
}
|
|
888
|
+
};
|
|
888
889
|
}
|
|
889
890
|
|
|
890
891
|
let data = [];
|
|
@@ -972,7 +973,6 @@ class NotificationsStorage {
|
|
|
972
973
|
|
|
973
974
|
const res = await c.aggregate(pipeline);
|
|
974
975
|
|
|
975
|
-
|
|
976
976
|
const arr = await res.toArray();
|
|
977
977
|
|
|
978
978
|
return arr.map(({ _id: tag, subscribtions }) => ({ tag, subscribtions }));
|