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.
@@ -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 {mongodb.Db|{():Promise<mongodb.Db>}} mongoDb
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, time: 0 })
87
+ .project({ _id: 0 })
84
88
  .toArray();
85
89
 
86
90
  if (!orderBackwards) {
87
91
  res.reverse();
88
92
  }
89
93
 
90
- return res;
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 {Object[]} responses - list of sent responses
98
- * @param {Object} request - event request
99
- * @param {Object} [metadata] - request metadata
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
- Object.assign(log, metadata);
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
- if (!this.muteErrors) {
118
- throw err;
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 {Object[]} [responses] - list of sent responses
131
- * @param {Object} [request] - event request
132
- * @param {Object} [metadata] - request metadata
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._getCollection()
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 {Object}
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 {Object} [data]
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 {Object} tasks
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 = Object.assign({}, task);
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 Object.assign({}, task, override);
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
- returnOriginal: false
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 {Object} data
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
- returnOriginal: false
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
- returnOriginal: false
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 {Object} campaign
581
- * @param {Object} [updateCampaign]
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 = Object.assign({}, campaign);
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
- returnOriginal: false
605
+ returnDocument: 'after'
607
606
  });
608
607
  ret = this._mapCampaign(res.value);
609
608
  } else {
610
609
  const id = new ObjectID();
611
- ret = Object.assign({ id: id.toHexString(), _id: id }, campaign);
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 {Object} increment
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 {Object} data
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
- returnOriginal: false
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
- returnOriginal: true
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 {Object} condition
726
+ * @param {object} condition
728
727
  * @param {number} [limit]
729
- * @param {Object} [lastKey]
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 = Object.assign({}, 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
- returnOriginal: false
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 = Object.assign({}, 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 }));