@tiledesk/tiledesk-server 2.10.86 → 2.10.88

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/CHANGELOG.md CHANGED
@@ -5,6 +5,21 @@
5
5
  🚀 IN PRODUCTION 🚀
6
6
  (https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
7
7
 
8
+ # 2.10.88
9
+ - Added: modified field in faq_kb model
10
+ - Added: chatbot template refactoring
11
+ - Added: clearing logic for chatbot
12
+ - Added: ttl when a chatbot is deleted
13
+ - Added: flow logs apis
14
+ - Added: webhooks apis
15
+ - Added: user_phone field in user model
16
+
17
+ # 2.10.87
18
+ - Updated voice-twilio-connector to 0.1.18
19
+
20
+ # 2.10.86
21
+ - Updated voice-twilio-connector to 0.1.16
22
+
8
23
  # 2.10.85
9
24
  - Updated: default system context for gpt-4.1 models
10
25
 
package/app.js CHANGED
@@ -202,6 +202,10 @@ let whatsappQueue = require('@tiledesk/tiledesk-whatsapp-jobworker');
202
202
  winston.info("whatsappQueue");
203
203
  jobsManager.listenWhatsappQueue(whatsappQueue);
204
204
 
205
+ let multiWorkerQueue = require('@tiledesk/tiledesk-multi-worker');
206
+ winston.info("multiWorkerQueue from App")
207
+ jobsManager.listenMultiWorker(multiWorkerQueue);
208
+
205
209
  var channelManager = require('./channels/channelManager');
206
210
  channelManager.listen();
207
211
 
package/errorCodes.js CHANGED
@@ -31,6 +31,12 @@ const errorCodes = {
31
31
  ERRORS: {
32
32
  DUPLICATE_SLUG: 12001
33
33
  }
34
+ },
35
+ WEBHOOK: {
36
+ BASE_CODE: 13000,
37
+ ERRORS: {
38
+ NO_PRELOADED_DEV_REQUEST: 13001
39
+ }
34
40
  }
35
41
  // Aggiungi altre route
36
42
  };
package/event/botEvent.js CHANGED
@@ -2,25 +2,24 @@ const EventEmitter = require('events');
2
2
  const messageEvent = require('../event/messageEvent');
3
3
  const Faq_kb = require('../models/faq_kb');
4
4
  var winston = require('../config/winston');
5
-
6
-
7
5
  const cacheUtil = require("../utils/cacheUtil");
8
6
  const cacheEnabler = require("../services/cacheEnabler");
7
+ var Faq = require("../models/faq");
8
+ const { Webhook } = require('../models/webhook');
9
9
 
10
10
  // class BotEvent extends EventEmitter {}
11
11
  class BotEvent extends EventEmitter {
12
+
12
13
  constructor() {
13
14
  super();
14
15
  this.queueEnabled = false;
15
16
  this.setMaxListeners(11);
16
- }
17
+ }
17
18
 
18
19
 
19
- listen() {
20
+ listen() {
20
21
  //TODO modify to async
21
22
  //messageEvent.on('message.received', function(message) {
22
-
23
-
24
23
  var messageCreateKey = 'message.create';
25
24
  if (messageEvent.queueEnabled) {
26
25
  messageCreateKey = 'message.create.queue';
@@ -28,7 +27,7 @@ class BotEvent extends EventEmitter {
28
27
 
29
28
  winston.info("Listening " + messageCreateKey + " event for Chatbot messages");
30
29
 
31
- messageEvent.on(messageCreateKey, function(message) {
30
+ messageEvent.on(messageCreateKey, function (message) {
32
31
 
33
32
  winston.debug("message", message);
34
33
 
@@ -49,7 +48,7 @@ class BotEvent extends EventEmitter {
49
48
  // }
50
49
 
51
50
  if (message.sender === "system") {
52
- if (message.text && (message.text=="\\start" || message.text=="/start") ) {
51
+ if (message.text && (message.text == "\\start" || message.text == "/start")) {
53
52
  winston.debug("it s a start message");
54
53
  } else {
55
54
  winston.debug("it s a message sent from system, exit");
@@ -58,28 +57,28 @@ class BotEvent extends EventEmitter {
58
57
  } else {
59
58
  winston.debug("it s a message sent from other let s go");
60
59
  }
61
-
62
- if (message.text && ( message.text.indexOf("\\agent") > -1 || message.text.indexOf("\\close") > -1)) { //not reply to a message containing \\agent
60
+
61
+ if (message.text && (message.text.indexOf("\\agent") > -1 || message.text.indexOf("\\close") > -1)) { //not reply to a message containing \\agent
63
62
  return 0;
64
63
  }
65
64
 
66
65
  // if (message.text.startsWith("\\")) { //not reply to a message containing \
67
66
  // return null;
68
67
  // }
69
-
70
- var botId = getBotId(message);
71
68
 
72
- winston.debug("botId: " + botId);
69
+ var botId = getBotId(message);
73
70
 
74
- if (!botId) {
71
+ winston.debug("botId: " + botId);
72
+
73
+ if (!botId) {
75
74
  return null;
76
- }else {
77
- //loop fix for messages sent from external bot
75
+ } else {
76
+ //loop fix for messages sent from external bot
78
77
  // botprefix
79
- if (message.sender === 'bot_'+botId || message.sender === botId) {
78
+ if (message.sender === 'bot_' + botId || message.sender === botId) {
80
79
  winston.debug("it s a message sent from bot, exit");
81
- return null;
82
- }else {
80
+ return null;
81
+ } else {
83
82
  messageEvent.emit('message.received.for.bot', message); //UNUSED
84
83
  }
85
84
 
@@ -88,51 +87,99 @@ class BotEvent extends EventEmitter {
88
87
  // qui potresti leggere anche +secret ed evitare prossima query in botNotification
89
88
  // let qbot = Faq_kb.findById(botId); //TODO add cache_bot_here
90
89
  let qbot = Faq_kb.findById(botId).select('+secret')
91
- //TODO unselect secret. secret is unselectable by default in the model
92
-
93
- if (cacheEnabler.faq_kb) {
94
- winston.debug('message.id_project+":faq_kbs:id:"+botId: '+ message.id_project+":faq_kbs:id:"+botId);
95
- // qbot.cache(cacheUtil.defaultTTL, message.id_project+":faq_kbs:id:"+botId)
96
- qbot.cache(cacheUtil.defaultTTL, message.id_project+":faq_kbs:id:"+botId+":secret")
97
- winston.debug('faq_kb cache enabled');
98
- }
90
+ //TODO unselect secret. secret is unselectable by default in the model
99
91
 
100
- qbot.exec(function(err, bot) {
92
+ if (cacheEnabler.faq_kb) {
93
+ winston.debug('message.id_project+":faq_kbs:id:"+botId: ' + message.id_project + ":faq_kbs:id:" + botId);
94
+ // qbot.cache(cacheUtil.defaultTTL, message.id_project+":faq_kbs:id:"+botId)
95
+ qbot.cache(cacheUtil.defaultTTL, message.id_project + ":faq_kbs:id:" + botId + ":secret")
96
+ winston.debug('faq_kb cache enabled');
97
+ }
101
98
 
99
+ qbot.exec(function (err, bot) {
102
100
 
103
-
104
101
  if (err) {
105
- winston.error('Error getting object.', err);
106
- return 0;
102
+ winston.error('Error getting object.', err);
103
+ return 0;
107
104
  }
108
105
  if (!bot) {
109
- winston.warn('Bot not found with id '+botId);
106
+ winston.warn('Bot not found with id ' + botId);
110
107
  }
111
108
 
112
109
  winston.debug("bot debug", bot);
113
- winston.debug('bot debug secret: '+ bot.secret);
110
+ winston.debug('bot debug secret: ' + bot.secret);
114
111
 
115
112
  if (bot) {
116
- if (bot.type==="internal") {
113
+ if (bot.type === "internal") {
117
114
  botEvent.emit('bot.message.received.notify.internal', message);
118
-
119
- }else { //external
115
+
116
+ } else { //external
120
117
  if (bot.url) {
121
- var botNotification = {bot: bot, message: message};
118
+ var botNotification = { bot: bot, message: message };
122
119
  botEvent.emit('bot.message.received.notify.external', botNotification);
123
- }else {
120
+ } else {
124
121
  winston.warn("bot url is not defined", bot);
125
122
  }
126
123
  }
127
- }
124
+ }
128
125
 
129
126
  });
130
-
131
-
132
127
 
133
128
  });
134
129
 
135
- }
130
+ botEvent.on('faqbot.update.virtual.delete', async (chatbot) => {
131
+ winston.verbose("botEvent ON faqbot.update.virtual.delete: ", chatbot);
132
+
133
+ if (chatbot.publishedAt) {
134
+ // Stop the flow if the chatbot is a published one
135
+ return;
136
+ }
137
+
138
+ await Faq.updateMany({ id_faq_kb: chatbot._id }, { trashed: true, trashedAt: chatbot.trashedAt }).catch((err) => {
139
+ winston.error("Event faqbot.update.virtual.delete error updating faqs ", err);
140
+ })
141
+
142
+ let deletedW = await Webhook.findOneAndDelete({ chatbot_id: chatbot._id }).catch((err) => {
143
+ winston.error("Error deleting webhook on chatbot deleting: ", err);
144
+ })
145
+
146
+ let publishedChatbots = await Faq_kb.find({ root_id: chatbot._id }, { _id: 1 }).catch((err) => {
147
+ winston.error("Event faqbot.update.virtual.delete error getting all published chatbots ", err);
148
+ })
149
+
150
+ const publishedChatbotIds = publishedChatbots.map(c => c._id);
151
+
152
+ if (publishedChatbotIds.length > 0) {
153
+
154
+ const batchSize = 20;
155
+ const sleep_ms = 500;
156
+ const batches = [];
157
+ for (let i = 0; i < publishedChatbotIds.length; i += batchSize) {
158
+ batches.push(publishedChatbotIds.slice(i, i + batchSize));
159
+ }
160
+
161
+ for (const batch of batches) {
162
+ await Faq_kb.updateMany(
163
+ { _id: { $in: batch } },
164
+ { $set: { trashed: true, trashedAt: chatbot.trashedAt } }
165
+ );
166
+
167
+ await Faq.updateMany(
168
+ { id_faq_kb: { $in: batch } },
169
+ { $set: { trashed: true, trashedAt: chatbot.trashedAt } }
170
+ );
171
+
172
+ await sleep(sleep_ms);
173
+ }
174
+
175
+ }
176
+ })
177
+
178
+ function sleep(ms) {
179
+ return new Promise(resolve => setTimeout(resolve, ms));
180
+ }
181
+
182
+ }
136
183
 
137
184
  }
138
185
 
package/jobsManager.js CHANGED
@@ -12,7 +12,8 @@ class JobsManager {
12
12
  this.emailNotificatio = undefined;
13
13
  this.activityArchiver = undefined;
14
14
  this.whatsappWorker = undefined;
15
-
15
+ this.multiWorkerQueue = undefined;
16
+
16
17
  this.jobWorkerEnabled = jobWorkerEnabled;
17
18
  // this.jobWorkerEnabled = false;
18
19
  // if (process.env.JOB_WORKER_ENABLED=="true" || process.env.JOB_WORKER_ENABLED == true) {
@@ -93,6 +94,8 @@ class JobsManager {
93
94
  if (this.jobWorkerEnabled == true) {
94
95
  return winston.info("JobsManager jobWorkerEnabled is enabled. Skipping listener for MultiWorker Queue");
95
96
  }
97
+ this.multiWorkerQueue = multiWorkerQueue;
98
+ this.multiWorkerQueue.startJobsWorker();
96
99
  }
97
100
 
98
101
  // listenTrainingQueue(trainingQueue) {
@@ -0,0 +1,22 @@
1
+ module.exports = {
2
+ chatbot: {
3
+ default: 'blank',
4
+ templates: ['empty', 'blank', 'handoff', 'example']
5
+ },
6
+ webhook: {
7
+ default: 'blank_webhook',
8
+ templates: ['empty', 'blank_webhook']
9
+ },
10
+ copilot: {
11
+ default: 'official_copilot',
12
+ templates: ['empty', 'blank_copilot', 'official_copilot']
13
+ },
14
+ voice: {
15
+ default: 'blank_voice',
16
+ templates: ['empty', 'blank_voice']
17
+ },
18
+ voice_twilio: {
19
+ default: 'blank_voice_twilio',
20
+ templates: ['empty', 'blank_voice_twilio']
21
+ }
22
+ }
package/models/faq.js CHANGED
@@ -5,6 +5,7 @@ var { nanoid } = require("nanoid");
5
5
  const uuidv4 = require('uuid/v4');
6
6
 
7
7
  var defaultFullTextLanguage = process.env.DEFAULT_FULLTEXT_INDEX_LANGUAGE || "none";
8
+ let trashExpirationTime = Number(process.env.CHATBOT_TRASH_TTL_SECONDS) || 60 * 60 * 24 * 30; // 30 days
8
9
 
9
10
  var FaqSchema = new Schema({
10
11
  // _id: {
@@ -107,7 +108,15 @@ var FaqSchema = new Schema({
107
108
  default: function () {
108
109
  return this.isNew ? false : undefined;
109
110
  },
110
- }
111
+ },
112
+ trashed: {
113
+ type: Boolean,
114
+ index: true
115
+ },
116
+ trashedAt: {
117
+ type: Date,
118
+ required: false
119
+ },
111
120
  }, {
112
121
  timestamps: true,
113
122
  toJSON: { virtuals: true } //used to polulate messages in toJSON// https://mongoosejs.com/docs/populate.html
@@ -183,6 +192,10 @@ FaqSchema.index(
183
192
  { partialFilterExpression: { "actions.namespace": { $exists: true } } }
184
193
  );
185
194
 
195
+ FaqSchema.index(
196
+ { trashedAt: 1 },
197
+ { expireAfterSeconds: trashExpirationTime }
198
+ );
186
199
 
187
200
  var faq = mongoose.model('faq', FaqSchema);
188
201
 
package/models/faq_kb.js CHANGED
@@ -5,7 +5,7 @@ var winston = require('../config/winston');
5
5
  const { stringify } = require('uuid');
6
6
 
7
7
  var defaultFullTextLanguage = process.env.DEFAULT_FULLTEXT_INDEX_LANGUAGE || "none";
8
-
8
+ let trashExpirationTime = Number(process.env.CHATBOT_TRASH_TTL_SECONDS) || 60 * 60 * 24 * 30; // 30 days
9
9
 
10
10
  var Faq_kbSchema = new Schema({
11
11
  name: {
@@ -58,6 +58,10 @@ var Faq_kbSchema = new Schema({
58
58
  type: Boolean,
59
59
  index: true
60
60
  },
61
+ trashedAt: {
62
+ type: Date,
63
+ required: false
64
+ },
61
65
  secret: {
62
66
  type: String,
63
67
  required: true,
@@ -107,8 +111,13 @@ var Faq_kbSchema = new Schema({
107
111
  index: true,
108
112
  default: 0
109
113
  },
114
+ // publishedBy: {
115
+ // type: String,
116
+ // },
110
117
  publishedBy: {
111
- type: String,
118
+ type: Schema.Types.ObjectId,
119
+ ref: 'user',
120
+ required: false
112
121
  },
113
122
  publishedAt: {
114
123
  type: Date
@@ -140,6 +149,18 @@ var Faq_kbSchema = new Schema({
140
149
  type: String,
141
150
  required: false,
142
151
  index: true
152
+ },
153
+ modified: {
154
+ type: Boolean,
155
+ required: false
156
+ },
157
+ root_id: {
158
+ type: String,
159
+ required: false
160
+ },
161
+ release_note: {
162
+ type: String,
163
+ required: false
143
164
  }
144
165
  },{
145
166
  timestamps: true
@@ -171,6 +192,37 @@ Faq_kbSchema.pre("save", async function (next) {
171
192
  next();
172
193
  });
173
194
 
195
+ Faq_kbSchema.pre('findOneAndUpdate', async function (next) {
196
+
197
+ const update = this.getUpdate();
198
+ const isUnsetSlug = update?.$unset?.slug !== undefined;
199
+
200
+ // $unset.slug is used only on publishing. In this case, skip the slug change and the set of trashedAt
201
+ if (update.trashed === true && !isUnsetSlug) {
202
+
203
+ const docToUpdate = await this.model.findOne(this.getQuery());
204
+ const timestamp = Date.now();
205
+
206
+ if (docToUpdate && docToUpdate.slug) {
207
+ let slug;
208
+ slug = docToUpdate.slug;
209
+ update.trashedAt = new Date();
210
+ update.slug = `${slug || 'undefined'}-trashed-${timestamp}`;
211
+ }
212
+ this.setUpdate(update);
213
+ }
214
+
215
+ next();
216
+
217
+ });
218
+
219
+ Faq_kbSchema.post('findOneAndUpdate', async function (doc) {
220
+ if (doc && doc.trashed === true) {
221
+ botEvent.emit('faqbot.update.virtual.delete', doc)
222
+ }
223
+ })
224
+
225
+
174
226
  Faq_kbSchema.virtual('fullName').get(function () {
175
227
  // winston.debug("faq_kb fullName virtual called");
176
228
  return (this.name);
@@ -188,6 +240,11 @@ Faq_kbSchema.index(
188
240
  { unique: true, partialFilterExpression: { slug: { $exists: true } } }
189
241
  );
190
242
 
243
+ Faq_kbSchema.index(
244
+ { trashedAt: 1 },
245
+ { expireAfterSeconds: trashExpirationTime }
246
+ );
247
+
191
248
 
192
249
  var faq_kb = mongoose.model('faq_kb', Faq_kbSchema);
193
250
 
@@ -209,3 +266,8 @@ function generateSlug(name) {
209
266
  }
210
267
 
211
268
  module.exports = faq_kb
269
+
270
+
271
+
272
+ // Import botEvent after model declaration to avoid circular dependency issues
273
+ const botEvent = require('../event/botEvent');
@@ -0,0 +1,64 @@
1
+ const mongoose = require('mongoose');
2
+ const Schema = mongoose.Schema;
3
+
4
+ const RowSchema = new Schema(
5
+ {
6
+ text: {
7
+ type: String,
8
+ required: true
9
+ },
10
+ level: {
11
+ type: String,
12
+ required: true
13
+ },
14
+ timestamp: {
15
+ type: Date,
16
+ required: true,
17
+ default: Date.now
18
+ }
19
+ }
20
+ );
21
+
22
+ const FlowLogsSchema = new Schema(
23
+ {
24
+ id_project: {
25
+ type: String,
26
+ required: false,
27
+ },
28
+ request_id: {
29
+ type: String,
30
+ required: false,
31
+ },
32
+ level: {
33
+ type: String,
34
+ required: true,
35
+ },
36
+ rows: {
37
+ type: [RowSchema],
38
+ required: false,
39
+ },
40
+ }, {
41
+ timestamps: true
42
+ }
43
+ );
44
+
45
+ FlowLogsSchema.index({ request_id: 1 }, { unique: true });
46
+
47
+ // FlowLogsSchema.pre('findOneAndUpdate', async function (next) {
48
+ // const update = this.getUpdate();
49
+
50
+ // if (update.$push && update.$push.rows) {
51
+ // const doc = await this.model.findOne(this.getQuery());
52
+
53
+ // if (!doc) {
54
+ // update.$push.rows.index = 0;
55
+ // } else {
56
+ // update.$push.rows.index = doc.rows.length;
57
+ // }
58
+ // }
59
+ // next();
60
+ // });
61
+
62
+ const FlowLogs = mongoose.model('FlowLogs', FlowLogsSchema);
63
+
64
+ module.exports = { FlowLogs };
package/models/user.js CHANGED
@@ -65,6 +65,13 @@ var UserSchema = new Schema({
65
65
  public_website: {
66
66
  type: String,
67
67
  required: false
68
+ },
69
+ phone: {
70
+ type: String,
71
+ required: false,
72
+ unique: true,
73
+ trim: true,
74
+ match: [/^\+?[1-9]\d{1,14}$/, 'Invalid phone number format'], // E.164 format
68
75
  }
69
76
  // authType: { // update db old data
70
77
  // type: String,
package/models/webhook.js CHANGED
@@ -13,6 +13,10 @@ const WebhookSchema = mongoose.Schema({
13
13
  type: String,
14
14
  required: true
15
15
  },
16
+ name: {
17
+ type: String,
18
+ required: false
19
+ },
16
20
  chatbot_id: {
17
21
  type: String,
18
22
  required: true
@@ -29,12 +33,38 @@ const WebhookSchema = mongoose.Schema({
29
33
  copilot: {
30
34
  type: Boolean,
31
35
  required: false
36
+ },
37
+ enabled: {
38
+ type: Boolean,
39
+ required: true,
40
+ default: true
32
41
  }
33
42
  }, {
34
43
  timestamps: true
35
44
  })
36
45
 
46
+ // Indexes
37
47
  WebhookSchema.index({ id_project: 1, chatbot_id: 1}, { unique: true })
48
+ WebhookSchema.index({ id_project: 1, webhook_id: 1}, { unique: true })
49
+
50
+ // Middlewares
51
+ WebhookSchema.pre("save", async function (next) {
52
+ if (this.isNew) {
53
+
54
+ try {
55
+ const chatbot = await mongoose.model("faq_kb").findById(this.chatbot_id);
56
+ if (chatbot) {
57
+ this.name = chatbot.name + "-webhook";
58
+ }
59
+
60
+ next();
61
+
62
+ } catch(error) {
63
+ next(error);
64
+ }
65
+ }
66
+ });
67
+
38
68
 
39
69
  const Webhook = mongoose.model("Webhook", WebhookSchema);
40
70
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-server",
3
3
  "description": "The Tiledesk server module",
4
- "version": "2.10.86",
4
+ "version": "2.10.88",
5
5
  "scripts": {
6
6
  "start": "node ./bin/www",
7
7
  "pretest": "mongodb-runner start",
@@ -47,13 +47,13 @@
47
47
  "@tiledesk/tiledesk-messenger-connector": "^0.1.23",
48
48
  "@tiledesk/tiledesk-rasa-connector": "^1.0.10",
49
49
  "@tiledesk/tiledesk-telegram-connector": "^0.1.14",
50
- "@tiledesk/tiledesk-tybot-connector": "^2.0.11",
50
+ "@tiledesk/tiledesk-tybot-connector": "^2.0.12",
51
51
  "@tiledesk/tiledesk-whatsapp-connector": "^0.1.83",
52
52
  "@tiledesk/tiledesk-whatsapp-jobworker": "^0.0.12",
53
53
  "@tiledesk/tiledesk-sms-connector": "^0.1.11",
54
54
  "@tiledesk/tiledesk-vxml-connector": "^0.1.76",
55
- "@tiledesk/tiledesk-voice-twilio-connector": "^0.1.16",
56
- "@tiledesk/tiledesk-multi-worker": "^0.1.20",
55
+ "@tiledesk/tiledesk-voice-twilio-connector": "^0.1.21",
56
+ "@tiledesk/tiledesk-multi-worker": "^0.3.1",
57
57
  "passport-oauth2": "^1.8.0",
58
58
  "amqplib": "^0.5.5",
59
59
  "app-root-path": "^3.0.0",
package/routes/auth.js CHANGED
@@ -85,7 +85,7 @@ router.post('/signup',
85
85
  // return res.status(403).send({ success: false, message: "The password does not meet the minimum vulnerability requirements"})
86
86
  // }
87
87
 
88
- return userService.signup(req.body.email, req.body.password, req.body.firstname, req.body.lastname, false)
88
+ return userService.signup(req.body.email, req.body.password, req.body.firstname, req.body.lastname, false, req.body.phone)
89
89
  .then( async function (savedUser) {
90
90
 
91
91
  winston.debug('-- >> -- >> savedUser ', savedUser.toObject());
package/routes/faq.js CHANGED
@@ -16,6 +16,7 @@ const axios = require("axios").default;
16
16
  var configGlobal = require('../config/global');
17
17
  const roleConstants = require('../models/roleConstants');
18
18
  const roleChecker = require('../middleware/has-role');
19
+ const { ChatbotService } = require('../services/chatbotService');
19
20
 
20
21
  const apiUrl = process.env.API_URL || configGlobal.apiUrl;
21
22
 
@@ -222,6 +223,7 @@ router.post('/ops_update', roleChecker.hasRoleOrTypes('admin', ['bot', 'subscrip
222
223
 
223
224
  let id_faq_kb = req.body.id_faq_kb;
224
225
  let operations = req.body.operations;
226
+ let chatbotService = new ChatbotService();
225
227
 
226
228
  for (let op of operations) {
227
229
  let HTTPREQUEST;
@@ -246,6 +248,7 @@ router.post('/ops_update', roleChecker.hasRoleOrTypes('admin', ['bot', 'subscrip
246
248
  winston.error("err performing operation: ", err);
247
249
  } else {
248
250
  winston.debug("\n\nresbody operation: ", resbody);
251
+ chatbotService.setModified(id_faq_kb, true)
249
252
  }
250
253
  }
251
254
  )
@@ -273,6 +276,7 @@ router.post('/ops_update', roleChecker.hasRoleOrTypes('admin', ['bot', 'subscrip
273
276
  winston.error("err performing operation: ", err);
274
277
  } else {
275
278
  winston.debug("\n\nresbody operation: ", resbody);
279
+ chatbotService.setModified(id_faq_kb, true)
276
280
  }
277
281
  }
278
282
  )
@@ -296,6 +300,7 @@ router.post('/ops_update', roleChecker.hasRoleOrTypes('admin', ['bot', 'subscrip
296
300
  winston.error("err performing operation: ", err);
297
301
  } else {
298
302
  winston.debug("\n\nresbody operation: ", resbody);
303
+ chatbotService.setModified(id_faq_kb, true)
299
304
  }
300
305
  }
301
306
  )
@@ -322,6 +327,7 @@ router.post('/ops_update', roleChecker.hasRoleOrTypes('admin', ['bot', 'subscrip
322
327
  winston.error("err performing operation: ", err);
323
328
  } else {
324
329
  winston.debug("\n\nresbody operation: ", resbody);
330
+ chatbotService.setModified(id_faq_kb, true)
325
331
  }
326
332
  }
327
333
  )