@tiledesk/tiledesk-server 2.3.5 → 2.3.7-1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. package/.github/workflows/docker-community-worker-push-latest.yml +23 -0
  2. package/.github/workflows/docker-image-tag-worker-community-tag-push.yml +22 -0
  3. package/CHANGELOG.md +361 -3
  4. package/Dockerfile-jobs +31 -0
  5. package/app.js +62 -69
  6. package/channels/chat21/chat21Handler.js +37 -6
  7. package/channels/chat21/chat21WebHook.js +52 -29
  8. package/channels/chat21/package-lock.json +663 -706
  9. package/channels/chat21/package.json +2 -2
  10. package/config/labels/widget.json +337 -136
  11. package/deploy.sh +2 -0
  12. package/event/messageEvent.js +110 -9
  13. package/jobs.js +80 -0
  14. package/jobsManager.js +47 -0
  15. package/middleware/has-role.js +10 -3
  16. package/middleware/ipFilter.js +220 -0
  17. package/middleware/passport.js +8 -2
  18. package/models/department.js +1 -1
  19. package/models/faq.js +77 -25
  20. package/models/faq_kb.js +19 -0
  21. package/models/message.js +10 -8
  22. package/models/project.js +10 -0
  23. package/models/project_user.js +10 -0
  24. package/models/request.js +12 -1
  25. package/package.json +12 -11
  26. package/pubmodules/activities/activityArchiver.js +216 -90
  27. package/pubmodules/activities/routes/activity.js +1 -1
  28. package/pubmodules/apps/index.js +8 -0
  29. package/pubmodules/apps/listener.js +27 -0
  30. package/pubmodules/cache/index.js +2 -0
  31. package/pubmodules/cache/mongoose-cachegoose-fn.js +630 -0
  32. package/pubmodules/canned/cannedResponse.js +4 -0
  33. package/pubmodules/canned/cannedResponseRoute.js +10 -5
  34. package/pubmodules/dialogflow/index.js +10 -0
  35. package/pubmodules/dialogflow/listener.js +66 -0
  36. package/pubmodules/emailNotification/requestNotification.js +58 -28
  37. package/pubmodules/events/eventRoute.js +49 -24
  38. package/pubmodules/messageTransformer/messageHandlebarsTransformerInterceptor.js +6 -1
  39. package/pubmodules/messageTransformer/messageTransformerInterceptor.js +10 -4
  40. package/pubmodules/pubModulesManager.js +173 -7
  41. package/pubmodules/queue/index.js +4 -0
  42. package/pubmodules/queue/reconnect.js +331 -0
  43. package/pubmodules/queue/reconnectFanout.js +256 -0
  44. package/pubmodules/rasa/listener.js +5 -5
  45. package/pubmodules/routing-queue/index.js +3 -0
  46. package/pubmodules/routing-queue/listener.js +328 -0
  47. package/pubmodules/rules/conciergeBot.js +4 -4
  48. package/pubmodules/scheduler/tasks/closeAgentUnresponsiveRequestTask.js +6 -1
  49. package/pubmodules/scheduler/tasks/closeBotUnresponsiveRequestTask.js +7 -1
  50. package/pubmodules/tilebot/index.js +11 -0
  51. package/pubmodules/tilebot/listener.js +85 -0
  52. package/pubmodules/trigger/rulesTrigger.js +137 -14
  53. package/pubmodules/trigger/start.js +5 -1
  54. package/pubmodules/whatsapp/index.js +7 -0
  55. package/pubmodules/whatsapp/listener.js +32 -0
  56. package/routes/auth.js +7 -2
  57. package/routes/campaigns.js +3 -3
  58. package/routes/department.js +3 -2
  59. package/routes/email.js +32 -2
  60. package/routes/faq.js +37 -2
  61. package/routes/faq_kb.js +496 -133
  62. package/routes/faqpub.js +5 -0
  63. package/routes/lead.js +56 -0
  64. package/routes/message.js +196 -14
  65. package/routes/messagesRoot.js +39 -0
  66. package/routes/project.js +76 -4
  67. package/routes/project_user.js +11 -1
  68. package/routes/project_user_test.js +19 -0
  69. package/routes/request.js +134 -30
  70. package/routes/troubleshooting.js +12 -0
  71. package/routes/users-util.js +39 -0
  72. package/routes/users.js +1 -1
  73. package/routes/widget.js +64 -2
  74. package/services/BotSubscriptionNotifier.js +5 -0
  75. package/services/banUserNotifier.js +86 -0
  76. package/services/cacheEnabler.js +56 -0
  77. package/services/chatbotService.js +101 -0
  78. package/services/departmentService.js +25 -3
  79. package/services/emailService.js +170 -28
  80. package/services/faqBotHandler.js +2 -3
  81. package/services/faqService.js +28 -3
  82. package/services/geoService.js +36 -6
  83. package/services/labelService.js +1 -1
  84. package/services/leadService.js +3 -2
  85. package/services/messageService.js +4 -2
  86. package/services/modulesManager.js +23 -76
  87. package/services/operatingHoursService.js +9 -4
  88. package/services/requestService.js +75 -39
  89. package/services/subscriptionNotifier.js +9 -4
  90. package/services/trainingService.js +106 -0
  91. package/template/email/assignedEmailMessage.html +21 -11
  92. package/template/email/assignedRequest.html +21 -11
  93. package/template/email/beenInvitedExistingUser.html +16 -6
  94. package/template/email/beenInvitedNewUser.html +16 -6
  95. package/template/email/emailDirect.html +130 -0
  96. package/template/email/newMessage.html +18 -8
  97. package/template/email/newMessageFollower.html +22 -12
  98. package/template/email/passwordChanged.html +15 -5
  99. package/template/email/pooledEmailMessage.html +21 -11
  100. package/template/email/pooledRequest.html +20 -10
  101. package/template/email/resetPassword.html +15 -5
  102. package/template/email/sendTranscript.html +7 -4
  103. package/template/email/ticket.html +17 -7
  104. package/template/email/verify.html +15 -5
  105. package/test/cannedRoute.js +157 -0
  106. package/test/chatbot-mock.js +127 -0
  107. package/test/example-json-intents.txt +1 -0
  108. package/test/example-json.txt +1 -0
  109. package/test/example.json +1 -0
  110. package/test/faqRoute.js +353 -208
  111. package/test/faqkbRoute.js +669 -64
  112. package/test/imageRoute.js +1 -1
  113. package/test/messageRoute.js +387 -5
  114. package/test/requestRoute.js +6 -6
  115. package/test/requestService.js +55 -4
  116. package/test-int/cache-project.js +90 -0
  117. package/test-int/cache-project_user.js +88 -0
  118. package/utils/UIDGenerator.js +20 -0
  119. package/utils/cacheUtil.js +2 -2
  120. package/utils/orgUtil.js +3 -3
  121. package/utils/promiseUtil.js +31 -0
  122. package/utils/recipientEmailUtil.js +66 -0
  123. package/utils/sendEmailUtil.js +34 -0
  124. package/utils/sendMessageUtil.js +1 -1
  125. package/utils/stringUtil.js +12 -0
  126. package/websocket/webSocketServer.js +33 -10
package/routes/faq_kb.js CHANGED
@@ -1,21 +1,27 @@
1
1
  var express = require('express');
2
2
  var router = express.Router();
3
3
  var Faq_kb = require("../models/faq_kb");
4
- var Faq= require("../models/faq");
4
+ var Faq = require("../models/faq");
5
5
  var Department = require("../models/department");
6
6
  var faqService = require("../services/faqService");
7
7
  const botEvent = require('../event/botEvent');
8
+ const faqBotEvent = require('../event/faqBotEvent');
8
9
  var winston = require('../config/winston');
9
10
  var httpUtil = require("../utils/httpUtil");
11
+ const { forEach } = require('lodash');
12
+ var multer = require('multer')
13
+ var upload = multer()
14
+ var configGlobal = require('../config/global');
15
+
16
+ var chatbot_templates_api_url = "https://chatbot-templates.herokuapp.com/chatbots/public/templates"
10
17
 
11
18
  router.post('/', function (req, res) {
12
19
  winston.info('create BOT ', req.body);
13
- // create(name, url, projectid, user_id, type, description, webhook_url, webhook_enabled, language, template)
14
- faqService.create(req.body.name, req.body.url, req.projectid, req.user.id, req.body.type, req.body.description, undefined, undefined, req.body.language, req.body.template).then(function(savedFaq_kb) {
20
+ //create(name, url, projectid, user_id, type, description, webhook_url, webhook_enabled, language, template)
21
+ faqService.create(req.body.name, req.body.url, req.projectid, req.user.id, req.body.type, req.body.description, undefined, undefined, req.body.language, req.body.template, req.body.mainCategory, req.body.intentsEngine).then(function (savedFaq_kb) {
15
22
  res.json(savedFaq_kb);
16
23
  });
17
24
 
18
-
19
25
  });
20
26
 
21
27
 
@@ -23,7 +29,7 @@ router.post('/train', function (req, res) {
23
29
 
24
30
  winston.info('train BOT ', req.body);
25
31
 
26
- Faq_kb.findById(req.body.id_faq_kb).exec(function(err, faq_kb) {
32
+ Faq_kb.findById(req.body.id_faq_kb).exec(function (err, faq_kb) {
27
33
  if (err) {
28
34
  return res.status(500).send({ success: false, msg: 'Error getting object.' });
29
35
  }
@@ -32,59 +38,59 @@ router.post('/train', function (req, res) {
32
38
  }
33
39
  winston.debug('faq_kb ', faq_kb.toJSON());
34
40
 
35
- winston.debug('faq_kb.type :'+ faq_kb.type);
36
- if (faq_kb.type =="internal" && faq_kb.url) {
41
+ winston.debug('faq_kb.type :' + faq_kb.type);
42
+ if (faq_kb.type == "internal" && faq_kb.url) {
37
43
 
38
44
 
39
45
 
40
- var train = {
41
- language:faq_kb.language,
42
- nlu:[]
46
+ var train = {
47
+ language: faq_kb.language,
48
+ nlu: []
43
49
  };
44
- winston.info("train", train);
45
-
46
-
47
- var query = { "id_project": req.projectid, "id_faq_kb": req.body.id_faq_kb};
48
-
49
- Faq.find(query)
50
- .limit(10000)
51
- .lean().
52
- exec(async (err, faqs) => {
53
- if (err) {
54
- return res.status(500).send({ success: false, msg: 'Error getting object.' });
55
- }
56
- if (faqs && faqs.length>0) {
57
- winston.info("faqs exact", faqs);
58
-
59
- faqs.forEach(function(f) {
60
- var intent = {
61
- intent:f.intent_display_name,
62
- examples:[]
63
- }
64
- var questions = f.question.split("\n");
65
- winston.info("questions", questions);
66
-
67
- questions.forEach(function(q) {
68
- winston.info("q", q);
69
- intent.examples.push(q);
70
- });
71
- winston.info("intent", intent);
72
- train.nlu.push(intent);
73
- });
74
- winston.info("train", train);
75
-
76
- try {
77
- var trainHttp = await httpUtil.call(faq_kb.url+"/trainandload", undefined, train, "POST");
78
- }catch(e) {
79
- winston.error("error training", e);
50
+ winston.info("train", train);
51
+
52
+
53
+ var query = { "id_project": req.projectid, "id_faq_kb": req.body.id_faq_kb };
54
+
55
+ Faq.find(query)
56
+ .limit(10000)
57
+ .lean().
58
+ exec(async (err, faqs) => {
59
+ if (err) {
60
+ return res.status(500).send({ success: false, msg: 'Error getting object.' });
80
61
  }
81
-
62
+ if (faqs && faqs.length > 0) {
63
+ winston.info("faqs exact", faqs);
64
+
65
+ faqs.forEach(function (f) {
66
+ var intent = {
67
+ intent: f.intent_display_name,
68
+ examples: []
69
+ }
70
+ var questions = f.question.split("\n");
71
+ winston.info("questions", questions);
72
+
73
+ questions.forEach(function (q) {
74
+ winston.info("q", q);
75
+ intent.examples.push(q);
76
+ });
77
+ winston.info("intent", intent);
78
+ train.nlu.push(intent);
79
+ });
80
+ winston.info("train", train);
82
81
 
83
- return res.json({train:train, httpResponse:trainHttp});
84
- // return res.json(trainHttp);
85
- }else {
86
- return res.status(400).send({ success: false, msg: 'no faq to train on external bot.' });
87
- }
82
+ try {
83
+ var trainHttp = await httpUtil.call(faq_kb.url + "/trainandload", undefined, train, "POST");
84
+ } catch (e) {
85
+ winston.error("error training", e);
86
+ }
87
+
88
+
89
+ return res.json({ train: train, httpResponse: trainHttp });
90
+ // return res.json(trainHttp);
91
+ } else {
92
+ return res.status(400).send({ success: false, msg: 'no faq to train on external bot.' });
93
+ }
88
94
  });
89
95
  } else {
90
96
  winston.debug('external query: ');
@@ -93,28 +99,28 @@ router.post('/train', function (req, res) {
93
99
 
94
100
  });
95
101
 
96
- /*
97
- {
98
- "language":"it",
99
- "nlu":[
100
- {
101
- "intent":"eta",
102
- "examples":[
103
- "quanti anni hai",
104
- "dimmi la tua età",
105
- "quanto sei grande",
106
- "parlami della tua età"
107
- ]
108
- },
109
- {
110
- "intent":"brutteparole",
111
- "examples":[
112
- "non dire parolacce",
113
- "le brutte parole non dovrebbero dirsi"
114
- ]
115
- }
116
- ]
117
- }
102
+ /*
103
+ {
104
+ "language":"it",
105
+ "nlu":[
106
+ {
107
+ "intent":"eta",
108
+ "examples":[
109
+ "quanti anni hai",
110
+ "dimmi la tua età",
111
+ "quanto sei grande",
112
+ "parlami della tua età"
113
+ ]
114
+ },
115
+ {
116
+ "intent":"brutteparole",
117
+ "examples":[
118
+ "non dire parolacce",
119
+ "le brutte parole non dovrebbero dirsi"
120
+ ]
121
+ }
122
+ ]
123
+ }
118
124
  */
119
125
 
120
126
  });
@@ -124,7 +130,7 @@ router.post('/askbot', function (req, res) {
124
130
 
125
131
  winston.debug('ASK BOT ', req.body);
126
132
 
127
- Faq_kb.findById(req.body.id_faq_kb).exec(function(err, faq_kb) {
133
+ Faq_kb.findById(req.body.id_faq_kb).exec(function (err, faq_kb) {
128
134
  if (err) {
129
135
  return res.status(500).send({ success: false, msg: 'Error getting object.' });
130
136
  }
@@ -132,73 +138,73 @@ router.post('/askbot', function (req, res) {
132
138
  return res.status(404).send({ success: false, msg: 'Object not found.' });
133
139
  }
134
140
  winston.debug('faq_kb ', faq_kb.toJSON());
135
- winston.debug('faq_kb.type :'+ faq_kb.type);
136
- if (faq_kb.type =="internal") {
141
+ winston.debug('faq_kb.type :' + faq_kb.type);
142
+ if (faq_kb.type == "internal" || faq_kb.type == "tilebot") {
137
143
 
138
144
 
139
145
 
140
-
141
146
 
142
- var query = { "id_project": req.projectid, "id_faq_kb": req.body.id_faq_kb, "question": req.body.question};
143
147
 
144
- Faq.find(query)
145
- .lean().
146
- exec(function (err, faqs) {
147
- if (err) {
148
- return res.status(500).send({ success: false, msg: 'Error getting object.' });
149
- }
150
- if (faqs && faqs.length>0) {
151
- winston.debug("faqs exact", faqs);
148
+ var query = { "id_project": req.projectid, "id_faq_kb": req.body.id_faq_kb, "question": req.body.question };
152
149
 
153
- faqs.forEach(f => {
154
- f.score = 100;
155
- });
156
- var result = {hits:faqs};
150
+ Faq.find(query)
151
+ .lean().
152
+ exec(function (err, faqs) {
153
+ if (err) {
154
+ return res.status(500).send({ success: false, msg: 'Error getting object.' });
155
+ }
156
+ if (faqs && faqs.length > 0) {
157
+ winston.debug("faqs exact", faqs);
158
+
159
+ faqs.forEach(f => {
160
+ f.score = 100;
161
+ });
162
+ var result = { hits: faqs };
157
163
 
158
164
 
159
- res.json(result);
160
- }else {
161
- query = { "id_project": req.projectid, "id_faq_kb": req.body.id_faq_kb};
165
+ res.json(result);
166
+ } else {
167
+ query = { "id_project": req.projectid, "id_faq_kb": req.body.id_faq_kb };
162
168
 
163
- var search_obj = {"$search": req.body.question};
169
+ var search_obj = { "$search": req.body.question };
164
170
 
165
- if (faq_kb.language) {
171
+ if (faq_kb.language) {
166
172
  search_obj["$language"] = faq_kb.language;
167
- }
168
- query.$text = search_obj;
169
- winston.debug("fulltext search query", query);
173
+ }
174
+ query.$text = search_obj;
175
+ winston.debug("fulltext search query", query);
170
176
 
171
177
 
172
- winston.debug('internal ft query: '+ query);
173
-
174
- Faq.find(query, {score: { $meta: "textScore" } })
175
- .sort( { score: { $meta: "textScore" } } ) //https://docs.mongodb.com/manual/reference/operator/query/text/#sort-by-text-search-score
176
- .lean().
177
- exec(function (err, faqs) {
178
- if (err) {
179
- winston.error('Error getting object.', err);
180
- return res.status(500).send({ success: false, msg: 'Error getting fulltext object.' });
181
- }
182
-
183
- winston.debug("faqs", faqs);
184
-
185
- var result = {hits:faqs};
186
- res.json(result);
187
- });
178
+ winston.debug('internal ft query: ' + query);
179
+
180
+ Faq.find(query, { score: { $meta: "textScore" } })
181
+ .sort({ score: { $meta: "textScore" } }) //https://docs.mongodb.com/manual/reference/operator/query/text/#sort-by-text-search-score
182
+ .lean().
183
+ exec(function (err, faqs) {
184
+ if (err) {
185
+ winston.error('Error getting object.', err);
186
+ return res.status(500).send({ success: false, msg: 'Error getting fulltext object.' });
187
+ }
188
+
189
+ winston.debug("faqs", faqs);
190
+
191
+ var result = { hits: faqs };
192
+ res.json(result);
193
+ });
194
+
195
+
196
+ }
188
197
 
189
-
190
- }
191
198
 
192
-
193
- });
199
+ });
200
+
194
201
 
195
-
196
- }else {
202
+ } else {
197
203
  winston.debug('external query: ');
198
204
  return res.status(400).send({ success: false, msg: 'askbot on external bot.' });
199
205
  }
200
-
201
-
206
+
207
+
202
208
  });
203
209
 
204
210
  });
@@ -210,28 +216,39 @@ router.put('/:faq_kbid', function (req, res) {
210
216
  winston.debug(req.body);
211
217
 
212
218
  var update = {};
213
- if (req.body.name!=undefined) {
219
+ if (req.body.name != undefined) {
214
220
  update.name = req.body.name;
215
221
  }
216
- if (req.body.description!=undefined) {
222
+ if (req.body.description != undefined) {
217
223
  update.description = req.body.description;
218
224
  }
219
- if (req.body.url!=undefined) {
225
+ if (req.body.url != undefined) {
220
226
  update.url = req.body.url;
221
227
  }
222
- if (req.body.webhook_url!=undefined) {
228
+ if (req.body.webhook_url != undefined) {
223
229
  update.webhook_url = req.body.webhook_url;
224
230
  }
225
- if (req.body.webhook_enabled!=undefined) {
231
+ if (req.body.webhook_enabled != undefined) {
226
232
  update.webhook_enabled = req.body.webhook_enabled;
227
233
  }
228
-
229
- if (req.body.type!=undefined) {
234
+ if (req.body.type != undefined) {
230
235
  update.type = req.body.type;
231
236
  }
232
- if (req.body.trashed!=undefined) {
237
+ if (req.body.trashed != undefined) {
233
238
  update.trashed = req.body.trashed;
234
239
  }
240
+ if (req.body.public != undefined) {
241
+ update.public = req.body.public;
242
+ }
243
+ if (req.body.certified != undefined) {
244
+ update.certified = req.body.certified;
245
+ }
246
+ if (req.body.mainCategory != undefined) {
247
+ update.mainCategory = req.body.mainCategory;
248
+ }
249
+ if (req.body.intentsEngine != undefined) {
250
+ update.intentsEngine = req.body.intentsEngine;
251
+ }
235
252
 
236
253
  Faq_kb.findByIdAndUpdate(req.params.faq_kbid, update, { new: true, upsert: true }, function (err, updatedFaq_kb) {
237
254
  if (err) {
@@ -317,10 +334,10 @@ router.get('/', function (req, res) {
317
334
  */
318
335
  var query = { "id_project": req.projectid, "trashed": { $in: [null, false] } };
319
336
 
320
- if (req.query.all!="true") {
337
+ if (req.query.all != "true") {
321
338
  query.type = { $ne: "identity" }
322
339
  }
323
-
340
+
324
341
  winston.debug("query", query);
325
342
 
326
343
  Faq_kb.find(query, function (err, faq_kb) {
@@ -335,4 +352,350 @@ router.get('/', function (req, res) {
335
352
 
336
353
  });
337
354
 
355
+ router.post('/fork/:id_faq_kb', async (req, res) => {
356
+
357
+ let id_faq_kb = req.params.id_faq_kb;
358
+ winston.info('id_faq_kb: ' + id_faq_kb);
359
+
360
+ const api_url = process.env.API_URL || configGlobal.apiUrl;
361
+ winston.info("fork --> base_url: " + api_url); // check if correct
362
+
363
+ let current_project_id = req.projectid;
364
+ winston.info("current project id: " + current_project_id);
365
+
366
+ let landing_project_id = req.query.projectid;
367
+ winston.info("landing project id " + landing_project_id)
368
+
369
+ let public = req.query.public;
370
+ winston.info("public " + public);
371
+
372
+ let token = req.headers.authorization;
373
+
374
+ let cs = req.app.get('chatbot_service')
375
+
376
+ let chatbot = await cs.getBotById(id_faq_kb, public, api_url, chatbot_templates_api_url, token, current_project_id);
377
+ winston.debug("chatbot: ", chatbot)
378
+
379
+ if (!chatbot) {
380
+ return res.status(500).send({ success: false, message: "Unable to get chatbot" });
381
+ }
382
+
383
+ let savedChatbot = await cs.createBot(api_url, token, chatbot, landing_project_id);
384
+ winston.info("savedChatbot: ", savedChatbot)
385
+
386
+ if (!savedChatbot) {
387
+ return res.status(500).send({ success: false, message: "Unable to create new chatbot" });
388
+ }
389
+
390
+ let import_result = await cs.importFaqs(api_url, savedChatbot._id, token, chatbot, landing_project_id);
391
+ winston.info("imported: ", import_result);
392
+
393
+ if (import_result.success == "false") {
394
+ return res.status(500).send({ success: false, message: "Unable to import intents in the new chatbot" });
395
+ }
396
+
397
+ return res.status(200).send({ message: "Chatbot forked successfully", bot_id: savedChatbot._id });
398
+
399
+ })
400
+
401
+
402
+ router.post('/importjson/:id_faq_kb', upload.single('uploadFile'), (req, res) => {
403
+
404
+ let id_faq_kb = req.params.id_faq_kb;
405
+ winston.info('import on id_faq_kb: ', id_faq_kb);
406
+
407
+ let json_string;
408
+ let json;
409
+ if (req.file) {
410
+ json_string = req.file.buffer.toString('utf-8');
411
+ json = JSON.parse(json_string);
412
+ } else {
413
+ json = req.body;
414
+ }
415
+
416
+ winston.info("json source " + json_string)
417
+
418
+ if (req.query.intentsOnly && req.query.intentsOnly == "true") {
419
+
420
+ winston.info("intents only")
421
+
422
+ json.intents.forEach((intent) => {
423
+
424
+ let new_faq = {
425
+ id_faq_kb: id_faq_kb,
426
+ id_project: req.projectid,
427
+ createdBy: req.user.id,
428
+ intent_display_name: intent.intent_display_name,
429
+ question: intent.question,
430
+ answer: intent.answer,
431
+ reply: intent.reply,
432
+ form: intent.form,
433
+ enabled: intent.enabled,
434
+ webhook_enabled: intent.webhook_enabled,
435
+ language: intent.language,
436
+ actions: intent.actions
437
+ }
438
+
439
+ // overwrite duplicated intents
440
+ if (req.query.overwrite == "true") {
441
+ Faq.findOneAndUpdate({ id_faq_kb: id_faq_kb, intent_display_name: intent.intent_display_name }, new_faq, { new: true, upsert: true, rawResult: true }, (err, savingResult) => {
442
+ if (err) {
443
+ winston.error("findOneAndUpdate (upsert) FAQ ERROR ", err);
444
+ } else {
445
+ if (savingResult.lastErrorObject.updatedExisting == true) {
446
+ winston.info("updated existing intent")
447
+ faqBotEvent.emit('faq.update', savingResult.value);
448
+ } else {
449
+ winston.info("new intent crated")
450
+ faqBotEvent.emit('faq.create', savingResult.value);
451
+ }
452
+ }
453
+ })
454
+
455
+ // don't overwrite duplicated intents
456
+ } else {
457
+ Faq.create(new_faq, (err, savedFaq) => {
458
+ if (err) {
459
+ winston.debug("create new FAQ ERROR ", err);
460
+ if (err.code == 11000) {
461
+ winston.error("Duplicate intent_display_name.");
462
+ winston.info("Skip duplicated intent_display_name");
463
+ } else {
464
+ winston.info("new intent crated")
465
+ faqBotEvent.emit('faq.create', savedFaq);
466
+ }
467
+ }
468
+ })
469
+ }
470
+
471
+ })
472
+
473
+ return res.status(200).send({ success: true, msg: "Intents imported successfully" })
474
+
475
+ } else {
476
+
477
+ if (req.query.create && req.query.create == 'true') {
478
+ faqService.create(json.name, undefined, req.projectid, req.user.id, "tilebot", json.description, json.webhook_url, json.webhook_enabled, json.language, undefined, undefined, undefined).then((savedFaq_kb) => {
479
+ winston.debug("saved (and imported) faq kb: ", savedFaq_kb);
480
+ botEvent.emit('faqbot.create', savedFaq_kb);
481
+
482
+ json.intents.forEach((intent) => {
483
+
484
+ let new_faq = {
485
+ id_faq_kb: savedFaq_kb._id,
486
+ id_project: req.projectid,
487
+ createdBy: req.user.id,
488
+ intent_display_name: intent.intent_display_name,
489
+ question: intent.question,
490
+ answer: intent.answer,
491
+ reply: intent.reply,
492
+ form: intent.form,
493
+ enabled: intent.enabled,
494
+ webhook_enabled: intent.webhook_enabled,
495
+ language: intent.language,
496
+ actions: intent.actions
497
+ }
498
+
499
+ // TO DELETE: no used when req.query.create = 'true'
500
+ if (req.query.overwrite == "true") {
501
+ Faq.findOneAndUpdate({ id_faq_kb: id_faq_kb, intent_display_name: intent.intent_display_name }, new_faq, { new: true, upsert: true, rawResult: true }, (err, savingResult) => {
502
+ if (err) {
503
+ winston.error("findOneAndUpdate (upsert) FAQ ERROR ", err);
504
+ } else {
505
+
506
+ if (savingResult.lastErrorObject.updatedExisting == true) {
507
+ winston.info("updated existing intent")
508
+ faqBotEvent.emit('faq.update', savingResult.value);
509
+ } else {
510
+ winston.info("new intent crated")
511
+ faqBotEvent.emit('faq.create', savingResult.value);
512
+ }
513
+
514
+ }
515
+
516
+ })
517
+
518
+ // don't overwrite duplicated intents
519
+ } else {
520
+ Faq.create(new_faq, (err, savedFaq) => {
521
+ if (err) {
522
+ winston.debug("create new FAQ ERROR ", err);
523
+ if (err.code == 11000) {
524
+ winston.error("Duplicate intent_display_name.");
525
+ winston.info("Skip duplicated intent_display_name");
526
+ } else {
527
+ winston.info("new intent crated")
528
+ faqBotEvent.emit('faq.create', savedFaq);
529
+ }
530
+ }
531
+ })
532
+ }
533
+
534
+ })
535
+ return res.status(200).send(savedFaq_kb);
536
+
537
+ }).catch((err) => {
538
+ winston.error("error saving faq_kb: ", err);
539
+ return res.status(500).send(err);
540
+ })
541
+
542
+ } else {
543
+
544
+ Faq_kb.findById(id_faq_kb, (err, faq_kb) => {
545
+ if (err) {
546
+ winston.error("GET FAQ-KB ERROR", err);
547
+ return res.status(500).send({ success: false, msg: "Error getting bot." });
548
+ }
549
+ if (!faq_kb) {
550
+ return res.status(404).send({ success: false, msg: 'Bot not found.' });
551
+ }
552
+
553
+ // should be wrong
554
+ //const json = JSON.parse(json_string);
555
+
556
+ if (json.webhook_enabled) {
557
+ faq_kb.webhook_enabled = json.webhook_enabled;
558
+ }
559
+ if (json.webhook_url) {
560
+ faq_kb.webhook_url = json.webhook_url;
561
+ }
562
+ if (json.language) {
563
+ faq_kb.language = json.language;
564
+ }
565
+ if (json.name) {
566
+ faq_kb.name = json.name;
567
+ }
568
+ if (json.description) {
569
+ faq_kb.description = json.description;
570
+ }
571
+
572
+ Faq_kb.findByIdAndUpdate(id_faq_kb, faq_kb, { new: true }, (err, updatedFaq_kb) => {
573
+ if (err) {
574
+ return res.status(500).send({ success: false, msg: "Error updating bot." });
575
+ }
576
+
577
+ botEvent.emit('faqbot.update', updatedFaq_kb);
578
+
579
+ json.intents.forEach((intent) => {
580
+
581
+ let new_faq = {
582
+ id_faq_kb: updatedFaq_kb._id,
583
+ id_project: req.projectid,
584
+ createdBy: req.user.id,
585
+ intent_display_name: intent.intent_display_name,
586
+ question: intent.question,
587
+ answer: intent.answer,
588
+ reply: intent.reply,
589
+ form: intent.form,
590
+ enabled: intent.enabled,
591
+ webhook_enabled: intent.webhook_enabled,
592
+ language: intent.language,
593
+ actions: intent.actions
594
+ }
595
+
596
+ // overwrite duplicated intents
597
+ if (req.query.overwrite == "true") {
598
+ Faq.findOneAndUpdate({ id_faq_kb: id_faq_kb, intent_display_name: intent.intent_display_name }, new_faq, { new: true, upsert: true, rawResult: true }, (err, savingResult) => {
599
+ if (err) {
600
+ winston.error("findOneAndUpdate (upsert) FAQ ERROR ", err);
601
+ } else {
602
+
603
+ if (savingResult.lastErrorObject.updatedExisting == true) {
604
+ winston.info("updated existing intent")
605
+ faqBotEvent.emit('faq.update', savingResult.value);
606
+ } else {
607
+ winston.info("new intent crated")
608
+ faqBotEvent.emit('faq.create', savingResult.value);
609
+ }
610
+
611
+ }
612
+
613
+ })
614
+
615
+ // don't overwrite duplicated intents
616
+ } else {
617
+ Faq.create(new_faq, (err, savedFaq) => {
618
+ if (err) {
619
+ winston.debug("create new FAQ ERROR ", err);
620
+ if (err.code == 11000) {
621
+ winston.error("Duplicate intent_display_name.");
622
+ winston.info("Skip duplicated intent_display_name");
623
+ } else {
624
+ winston.info("new intent crated")
625
+ faqBotEvent.emit('faq.create', savedFaq);
626
+ }
627
+ }
628
+ })
629
+ }
630
+
631
+ })
632
+
633
+ return res.send(updatedFaq_kb);
634
+
635
+ })
636
+
637
+ })
638
+ }
639
+
640
+ }
641
+
642
+ })
643
+
644
+ router.get('/exportjson/:id_faq_kb', (req, res) => {
645
+
646
+ winston.info("exporting bot...")
647
+
648
+
649
+ let id_faq_kb = req.params.id_faq_kb;
650
+
651
+ Faq_kb.findById(id_faq_kb, (err, faq_kb) => {
652
+ if (err) {
653
+ winston.error('GET FAQ-KB ERROR ', err)
654
+ return res.status(500).send({ success: false, msg: 'Error getting bot.' });
655
+ } else {
656
+ winston.debug('FAQ-KB: ', faq_kb)
657
+
658
+
659
+ faqService.getAll(id_faq_kb).then((faqs) => {
660
+
661
+ const intents = faqs.map(({ _id, id_project, topic, status, id_faq_kb, createdBy, intent_id, createdAt, updatedAt, __v, ...keepAttrs }) => keepAttrs)
662
+
663
+ let json = {
664
+ webhook_enabled: faq_kb.webhook_enabled,
665
+ webhook_url: faq_kb.webhook_url,
666
+ language: faq_kb.language,
667
+ name: faq_kb.name,
668
+ description: faq_kb.description,
669
+ intents: intents
670
+ }
671
+
672
+ if (req.query.intentsOnly == 'true') {
673
+ let intents_obj = {
674
+ intents: intents
675
+ }
676
+ let intents_string = JSON.stringify(intents_obj);
677
+ res.set({ "Content-Disposition": "attachment; filename=\"intents.json\"" });
678
+ return res.send(intents_string);
679
+
680
+ } else {
681
+
682
+ // if (req.query.file == "false") {
683
+ // return res.status(200).send(json);
684
+ // }
685
+ let json_string = JSON.stringify(json);
686
+ res.set({ "Content-Disposition": "attachment; filename=\"bot.json\"" });
687
+ return res.send(json_string);
688
+ }
689
+
690
+
691
+ }).catch((err) => {
692
+ winston.error('GET FAQ ERROR: ', err)
693
+ return res.status(500).send({ success: false, msg: 'Error getting faqs.' });
694
+ })
695
+ }
696
+ })
697
+
698
+ })
699
+
700
+
338
701
  module.exports = router;