@tiledesk/tiledesk-server 2.10.101 → 2.10.103

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,12 @@
5
5
  🚀 IN PRODUCTION 🚀
6
6
  (https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
7
7
 
8
+ # 2.10.103
9
+ - Update: standard/hybrid namespace management
10
+
11
+ # 2.10.102
12
+ - Update: substituted encode with DOMPurify.sanitize for direct email
13
+
8
14
  # 2.10.101
9
15
  - Update: messenger-connector to 0.1.27
10
16
  - Update: multi-worker to 0.3.3
@@ -49,6 +49,10 @@ var NamespaceSchema = new Schema({
49
49
  type: Boolean,
50
50
  default: false
51
51
  },
52
+ hybrid: {
53
+ type: Boolean,
54
+ default: false
55
+ },
52
56
  engine: {
53
57
  type: EngineSchema,
54
58
  required: false
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.101",
4
+ "version": "2.10.103",
5
5
  "scripts": {
6
6
  "start": "node ./bin/www",
7
7
  "pretest": "mongodb-runner start",
@@ -45,16 +45,15 @@
45
45
  "@tiledesk/tiledesk-json-rules-engine": "^4.0.3",
46
46
  "@tiledesk/tiledesk-kaleyra-proxy": "^0.1.7",
47
47
  "@tiledesk/tiledesk-messenger-connector": "^0.1.27",
48
+ "@tiledesk/tiledesk-multi-worker": "^0.3.3",
48
49
  "@tiledesk/tiledesk-rasa-connector": "^1.0.10",
50
+ "@tiledesk/tiledesk-sms-connector": "^0.1.11",
49
51
  "@tiledesk/tiledesk-telegram-connector": "^0.1.14",
50
52
  "@tiledesk/tiledesk-tybot-connector": "^2.0.19",
53
+ "@tiledesk/tiledesk-voice-twilio-connector": "^0.1.22",
54
+ "@tiledesk/tiledesk-vxml-connector": "^0.1.76",
51
55
  "@tiledesk/tiledesk-whatsapp-connector": "^0.1.84",
52
56
  "@tiledesk/tiledesk-whatsapp-jobworker": "^0.0.12",
53
- "@tiledesk/tiledesk-sms-connector": "^0.1.11",
54
- "@tiledesk/tiledesk-vxml-connector": "^0.1.76",
55
- "@tiledesk/tiledesk-voice-twilio-connector": "^0.1.22",
56
- "@tiledesk/tiledesk-multi-worker": "^0.3.3",
57
- "passport-oauth2": "^1.8.0",
58
57
  "amqplib": "^0.5.5",
59
58
  "app-root-path": "^3.0.0",
60
59
  "bcrypt-nodejs": "0.0.3",
@@ -65,6 +64,7 @@
65
64
  "cors": "^2.8.5",
66
65
  "csv-express": "^1.2.2",
67
66
  "debug": "^4.3.4",
67
+ "dompurify": "^3.2.6",
68
68
  "dotenv": "^8.6.0",
69
69
  "email-templates": "^8.1.0",
70
70
  "eventemitter2": "^6.4.4",
@@ -82,6 +82,7 @@
82
82
  "immutable": "^4.1.0",
83
83
  "jade": "~1.11.0",
84
84
  "jobs-worker-queued": "^0.0.5",
85
+ "jsdom": "^26.1.0",
85
86
  "jsonwebtoken": "^8.5.1",
86
87
  "lodash": "^4.17.21",
87
88
  "marked": "^3.0.4",
@@ -104,6 +105,7 @@
104
105
  "passport-google-oidc": "^0.1.0",
105
106
  "passport-http": "^0.3.0",
106
107
  "passport-jwt": "^4.0.0",
108
+ "passport-oauth2": "^1.8.0",
107
109
  "pdfmake": "^0.2.5",
108
110
  "promise-events": "^0.2.4",
109
111
  "request": "^2.88.2",
package/routes/kb.js CHANGED
@@ -22,6 +22,7 @@ const { kbTypes } = require('../models/kbConstants');
22
22
 
23
23
  const AMQP_MANAGER_URL = process.env.AMQP_MANAGER_URL;
24
24
  const JOB_TOPIC_EXCHANGE = process.env.JOB_TOPIC_EXCHANGE_TRAIN || 'tiledesk-trainer';
25
+ const JOB_TOPIC_EXCHANGE_HYBRID = process.env.JOB_TOPIC_EXCHANGE_TRAIN_HYBRID || 'tiledesk-trainer-hybrid';
25
26
  const KB_WEBHOOK_TOKEN = process.env.KB_WEBHOOK_TOKEN || 'kbcustomtoken';
26
27
  const apiUrl = process.env.API_URL || configGlobal.apiUrl;
27
28
 
@@ -52,6 +53,21 @@ jobManager.connectAndStartPublisher((status, error) => {
52
53
  }
53
54
  })
54
55
 
56
+ let jobManagerHybrid = new JobManager(AMQP_MANAGER_URL, {
57
+ debug: false,
58
+ topic: JOB_TOPIC_EXCHANGE_HYBRID,
59
+ exchange: JOB_TOPIC_EXCHANGE_HYBRID
60
+ })
61
+
62
+ jobManagerHybrid.connectAndStartPublisher((status, error) => {
63
+ if (error) {
64
+ winston.error("connectAndStartPublisher error: ", error);
65
+ } else {
66
+ winston.info("KbRoute - ConnectPublisher done with status: ", status);
67
+ }
68
+ })
69
+
70
+
55
71
  let default_preview_settings = {
56
72
  model: 'gpt-4o',
57
73
  max_tokens: 256,
@@ -63,11 +79,18 @@ let default_preview_settings = {
63
79
  }
64
80
  let default_engine = {
65
81
  name: "pinecone",
66
- type: process.env.PINECONE_TYPE,
82
+ type: process.env.PINECONE_TYPE || "pod",
67
83
  apikey: "",
68
84
  vector_size: 1536,
69
85
  index_name: process.env.PINECONE_INDEX
70
86
  }
87
+ let default_engine_hybrid = {
88
+ name: "pinecone",
89
+ type: process.env.PINECONE_TYPE_HYBRID || "serverless",
90
+ apikey: "",
91
+ vector_size: 1536,
92
+ index_name: process.env.PINECONE_INDEX_HYBRID
93
+ }
71
94
 
72
95
  //let default_context = "Answer if and ONLY if the answer is contained in the context provided. If the answer is not contained in the context provided ALWAYS answer with <NOANS>\n{context}"
73
96
  //let default_context = "You are an helpful assistant for question-answering tasks.\nUse ONLY the following pieces of retrieved context to answer the question.\nIf you don't know the answer, just say that you don't know.\nIf none of the retrieved context answer the question, add this word to the end <NOANS>\n\n{context}";
@@ -149,7 +172,7 @@ router.post('/scrape/single', async (req, res) => {
149
172
  let ns = namespaces.find(n => n.id === kb.namespace);
150
173
  json.engine = ns.engine || default_engine;
151
174
 
152
- if (json.engine.type === 'serverless') {
175
+ if (ns.hybrid === true) {
153
176
  json.hybrid = true;
154
177
  }
155
178
 
@@ -298,6 +321,7 @@ router.post('/qa', async (req, res) => {
298
321
 
299
322
  let ns = namespaces.find(n => n.id === data.namespace);
300
323
  data.engine = ns.engine || default_engine;
324
+ data.hybrid = ns.hybrid;
301
325
 
302
326
  if (data.engine.type === 'serverless') {
303
327
  data.search_type = 'hybrid';
@@ -638,13 +662,32 @@ router.post('/namespace', async (req, res) => {
638
662
  let body = req.body;
639
663
  winston.debug("add namespace body: ", body);
640
664
 
665
+ let engine = default_engine;
666
+
667
+ let hybrid = false;
668
+ if ('hybrid' in req.body) {
669
+ if (typeof req.body.hybrid !== 'boolean') {
670
+ return res.status(400).send({ success: false, error: "Value not accepted for 'hybrid' field. Expected boolean." });
671
+ }
672
+ hybrid = req.body.hybrid;
673
+ }
674
+
675
+ if (hybrid) {
676
+ if (req.project?.profile?.customization?.hybrid) {
677
+ engine = default_engine_hybrid;
678
+ } else {
679
+ return res.status(403).send({ success: false, error: "Hybrid mode is not allowed for the current project" });
680
+ }
681
+ }
682
+
641
683
  var namespace_id = mongoose.Types.ObjectId();
642
684
  let new_namespace = new Namespace({
643
685
  id_project: project_id,
644
686
  id: namespace_id,
645
687
  name: body.name,
688
+ hybrid: hybrid,
646
689
  preview_settings: default_preview_settings,
647
- engine: default_engine
690
+ engine: engine
648
691
  })
649
692
 
650
693
  let namespaces = await Namespace.find({ id_project: project_id }).catch((err) => {
@@ -779,6 +822,7 @@ router.post('/namespace/import/:id', upload.single('uploadFile'), async (req, re
779
822
  // import operation the content's limit is respected
780
823
  let ns = namespaces.find(n => n.id === namespace_id);
781
824
  let engine = ns.engine || default_engine;
825
+ let hybrid = ns.hybrid;
782
826
 
783
827
  if (process.env.NODE_ENV !== "test") {
784
828
  await aiService.deleteNamespace({
@@ -818,7 +862,7 @@ router.post('/namespace/import/:id', upload.single('uploadFile'), async (req, re
818
862
  winston.verbose("resources to be sent to worker: ", resources);
819
863
 
820
864
  if (process.env.NODE_ENV !== "test") {
821
- scheduleScrape(resources);
865
+ scheduleScrape(resources, hybrid);
822
866
  }
823
867
 
824
868
  res.status(200).send({ success: true, message: "Contents imported successfully" });
@@ -1217,16 +1261,14 @@ router.post('/', async (req, res) => {
1217
1261
  }
1218
1262
  let ns = namespaces.find(n => n.id === body.namespace);
1219
1263
  json.engine = ns.engine || default_engine;
1220
-
1221
- if (json.engine.type === 'serverless') {
1222
- json.hybrid = true;
1223
- }
1224
-
1264
+ json.hybrid = ns.hybrid;
1265
+
1225
1266
  let resources = [];
1226
1267
 
1227
1268
  resources.push(json);
1269
+
1228
1270
  if (process.env.NODE_ENV !== 'test') {
1229
- scheduleScrape(resources);
1271
+ scheduleScrape(resources, ns.hybrid);
1230
1272
  }
1231
1273
 
1232
1274
  }
@@ -1345,11 +1387,7 @@ router.post('/multi', upload.single('uploadFile'), async (req, res) => {
1345
1387
 
1346
1388
  let ns = namespaces.find(n => n.id === namespace_id);
1347
1389
  let engine = ns.engine || default_engine;
1348
-
1349
- let hybrid;
1350
- if (engine.type === 'serverless') {
1351
- hybrid = true;
1352
- }
1390
+ let hybrid = ns.hybrid;
1353
1391
 
1354
1392
  let resources = result.map(({ name, status, __v, createdAt, updatedAt, id_project, ...keepAttrs }) => keepAttrs)
1355
1393
  resources = resources.map(({ _id, scrape_options, ...rest }) => {
@@ -1358,7 +1396,7 @@ router.post('/multi', upload.single('uploadFile'), async (req, res) => {
1358
1396
  winston.verbose("resources to be sent to worker: ", resources);
1359
1397
 
1360
1398
  if (process.env.NODE_ENV !== 'test') {
1361
- scheduleScrape(resources);
1399
+ scheduleScrape(resources, hybrid);
1362
1400
  }
1363
1401
  res.status(200).send(result);
1364
1402
 
@@ -1460,6 +1498,7 @@ router.post('/csv', upload.single('uploadFile'), async (req, res) => {
1460
1498
 
1461
1499
  let ns = namespaces.find(n => n.id === namespace_id);
1462
1500
  let engine = ns.engine || default_engine;
1501
+ let hybrid = ns.hybrid;
1463
1502
 
1464
1503
  let resources = result.map(({ name, status, __v, createdAt, updatedAt, id_project, ...keepAttrs }) => keepAttrs)
1465
1504
  resources = resources.map(({ _id, ...rest}) => {
@@ -1467,7 +1506,7 @@ router.post('/csv', upload.single('uploadFile'), async (req, res) => {
1467
1506
  })
1468
1507
  winston.verbose("resources to be sent to worker: ", resources);
1469
1508
  if (process.env.NODE_ENV !== 'test') {
1470
- scheduleScrape(resources);
1509
+ scheduleScrape(resources, hybrid);
1471
1510
  }
1472
1511
  res.status(200).send(result);
1473
1512
  }).catch((err) => {
@@ -1685,9 +1724,19 @@ async function updateStatus(id, status) {
1685
1724
  })
1686
1725
  }
1687
1726
 
1688
- async function scheduleScrape(resources) {
1727
+ async function scheduleScrape(resources, hybrid) {
1689
1728
 
1690
- let scheduler = new Scheduler({ jobManager: jobManager });
1729
+ let scheduler;
1730
+ if (hybrid) {
1731
+ scheduler = new Scheduler({ jobManager: jobManagerHybrid });
1732
+ } else {
1733
+ scheduler = new Scheduler({ jobManager: jobManager });
1734
+ }
1735
+
1736
+ if (!scheduler) {
1737
+ winston.error("ScheduleScrape JobManager is not defined");
1738
+ return false;
1739
+ }
1691
1740
 
1692
1741
  resources.forEach(r => {
1693
1742
  winston.debug("Schedule job with following data: ", r);
@@ -244,7 +244,7 @@ async function validateNamespace(id_project, namespace_id) {
244
244
  try {
245
245
  const namespace = await Namespace.findOne({
246
246
  id_project: id_project,
247
- namespace: namespace_id
247
+ id: namespace_id
248
248
  });
249
249
  return !!namespace; // return true if namespace exists, false otherwise
250
250
  } catch (err) {
@@ -5,9 +5,10 @@ const jwt = require("jsonwebtoken")
5
5
  const FormData = require('form-data');
6
6
 
7
7
  let openai_endpoint = process.env.OPENAI_ENDPOINT;
8
- let kb_endpoint = process.env.KB_ENDPOINT;
9
8
  let kb_endpoint_train = process.env.KB_ENDPOINT_TRAIN;
10
9
  let kb_endpoint_qa = process.env.KB_ENDPOINT_QA;
10
+ let kb_endpoint_train_gpu = process.env.KB_ENDPOINT_TRAIN_GPU;
11
+ let kb_endpoint_qa_gpu = process.env.KB_ENDPOINT_QA_GPU;
11
12
  let secret = process.env.JWT_SECRET_KEY;
12
13
 
13
14
  class AiService {
@@ -85,79 +86,83 @@ class AiService {
85
86
  })
86
87
  }
87
88
 
89
+ // KB - Deprecated?
90
+ // checkStatus(data) {
91
+ // winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint);
92
+
93
+ // return new Promise((resolve, reject) => {
94
+
95
+ // axios({
96
+ // url: kb_endpoint + "/scrape/status",
97
+ // headers: {
98
+ // 'Content-Type': 'application/json'
99
+ // },
100
+ // data: data,
101
+ // method: 'POST'
102
+ // }).then((resbody) => {
103
+ // resolve(resbody);
104
+ // }).catch((err) => {
105
+ // reject(err);
106
+ // })
107
+
108
+ // })
109
+ // }
110
+
111
+ // Deprecated?
112
+ // startScrape(data) {
113
+ // winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint);
114
+
115
+ // return new Promise((resolve, reject) => {
116
+
117
+ // axios({
118
+ // url: kb_endpoint + "/scrape",
119
+ // headers: {
120
+ // 'Content-Type': 'application/json'
121
+ // },
122
+ // data: data,
123
+ // method: 'POST'
124
+ // }).then((resbody) => {
125
+ // resolve(resbody);
126
+ // }).catch((err) => {
127
+ // reject(err);
128
+ // })
129
+
130
+ // })
131
+ // }
132
+
133
+ // Deprecated?
134
+ // ask(data) {
135
+ // winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint);
136
+
137
+ // return new Promise((resolve, reject) => {
138
+
139
+ // axios({
140
+ // url: kb_endpoint + "/qa",
141
+ // headers: {
142
+ // 'Content-Type': 'application/json'
143
+ // },
144
+ // data: data,
145
+ // method: 'POST'
146
+ // }).then((resbody) => {
147
+ // resolve(resbody);
148
+ // }).catch((err) => {
149
+ // reject(err);
150
+ // })
151
+
152
+ // })
153
+ // }
88
154
 
89
- // KB
90
- checkStatus(data) {
91
- winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint);
92
-
93
- return new Promise((resolve, reject) => {
94
-
95
- axios({
96
- url: kb_endpoint + "/scrape/status",
97
- headers: {
98
- 'Content-Type': 'application/json'
99
- },
100
- data: data,
101
- method: 'POST'
102
- }).then((resbody) => {
103
- resolve(resbody);
104
- }).catch((err) => {
105
- reject(err);
106
- })
107
-
108
- })
109
- }
110
-
111
- startScrape(data) {
112
- winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint);
113
-
114
- return new Promise((resolve, reject) => {
115
-
116
- axios({
117
- url: kb_endpoint + "/scrape",
118
- headers: {
119
- 'Content-Type': 'application/json'
120
- },
121
- data: data,
122
- method: 'POST'
123
- }).then((resbody) => {
124
- resolve(resbody);
125
- }).catch((err) => {
126
- reject(err);
127
- })
128
-
129
- })
130
- }
131
-
132
- ask(data) {
133
- winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint);
134
-
135
- return new Promise((resolve, reject) => {
136
-
137
- axios({
138
- url: kb_endpoint + "/qa",
139
- headers: {
140
- 'Content-Type': 'application/json'
141
- },
142
- data: data,
143
- method: 'POST'
144
- }).then((resbody) => {
145
- resolve(resbody);
146
- }).catch((err) => {
147
- reject(err);
148
- })
149
-
150
- })
151
- }
152
-
153
- // PUGLIA AI V2
154
155
  singleScrape(data) {
155
- winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint_train);
156
+ let base_url = kb_endpoint_train;
157
+ if (data.hybrid) {
158
+ base_url = kb_endpoint_train_gpu;
159
+ }
160
+ winston.debug("[OPENAI SERVICE] kb endpoint: " + base_url);
156
161
 
157
162
  return new Promise((resolve, reject) => {
158
163
 
159
164
  axios({
160
- url: kb_endpoint_train + "/scrape/single",
165
+ url: base_url + "/scrape/single",
161
166
  headers: {
162
167
  'Content-Type': 'application/json'
163
168
  },
@@ -173,12 +178,13 @@ class AiService {
173
178
  }
174
179
 
175
180
  scrapeStatus(data) {
176
- winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint_train);
181
+ let base_url = kb_endpoint_train;
182
+ winston.debug("[OPENAI SERVICE] kb endpoint: " + base_url);
177
183
 
178
184
  return new Promise((resolve, reject) => {
179
185
 
180
186
  axios({
181
- url: kb_endpoint_train + "/scrape/status",
187
+ url: base_url + "/scrape/status",
182
188
  headers: {
183
189
  'Content-Type': 'application/json'
184
190
  },
@@ -193,12 +199,16 @@ class AiService {
193
199
  }
194
200
 
195
201
  askNamespace(data) {
196
- winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint_qa);
202
+ let base_url = kb_endpoint_qa;
203
+ if (data.hybrid) {
204
+ base_url = kb_endpoint_qa_gpu;
205
+ }
206
+ winston.debug("[OPENAI SERVICE] kb endpoint: " + base_url);
197
207
 
198
208
  return new Promise((resolve, reject) => {
199
209
 
200
210
  axios({
201
- url: kb_endpoint_qa + "/qa",
211
+ url: base_url + "/qa",
202
212
  headers: {
203
213
  'Content-Type': 'application/json'
204
214
  },
@@ -213,15 +223,16 @@ class AiService {
213
223
  })
214
224
  }
215
225
 
216
- getContentChunks(namespace_id, content_id, engine) {
217
- winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint_train);
226
+ getContentChunks(namespace_id, content_id, engine, hybrid) {
227
+ let base_url = kb_endpoint_train;
228
+ winston.debug("[OPENAI SERVICE] kb endpoint: " + base_url);
218
229
 
219
230
  return new Promise((resolve, reject) => {
220
231
 
221
232
  let payload = { engine: engine };
222
233
  let token = jwt.sign(payload, secret);
223
234
  axios({
224
- url: kb_endpoint_train + "/id/" + content_id + "/namespace/" + namespace_id + "/" + token,
235
+ url: base_url + "/id/" + content_id + "/namespace/" + namespace_id + "/" + token,
225
236
  headers: {
226
237
  'Content-Type': 'application/json'
227
238
  },
@@ -235,12 +246,13 @@ class AiService {
235
246
  }
236
247
 
237
248
  deleteIndex(data) {
238
- winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint_train);
249
+ let base_url = kb_endpoint_train;
250
+ winston.debug("[OPENAI SERVICE] kb endpoint: " + base_url);
239
251
 
240
252
  return new Promise((resolve, reject) => {
241
253
 
242
254
  axios({
243
- url: kb_endpoint_train + "/delete/id",
255
+ url: base_url + "/delete/id",
244
256
  headers: {
245
257
  'Content-Type': 'application/json'
246
258
  },
@@ -255,12 +267,13 @@ class AiService {
255
267
  }
256
268
 
257
269
  deleteNamespace(data) {
258
- winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint_train);
270
+ let base_url = kb_endpoint_train;
271
+ winston.debug("[OPENAI SERVICE] kb endpoint: " + base_url);
259
272
 
260
273
  return new Promise((resolve, reject) => {
261
274
 
262
275
  axios({
263
- url: kb_endpoint_train + "/delete/namespace",
276
+ url: base_url + "/delete/namespace",
264
277
  headers: {
265
278
  'Content-Type': 'application/json'
266
279
  },
@@ -9,6 +9,11 @@ var handlebars = require('handlebars');
9
9
  var encode = require('html-entities').encode;
10
10
  const emailEvent = require('../event/emailEvent');
11
11
 
12
+ const createDOMPurify = require('dompurify');
13
+ const { JSDOM } = require('jsdom');
14
+ const window = new JSDOM('').window;
15
+ const DOMPurify = createDOMPurify(window);
16
+
12
17
  handlebars.registerHelper('ifEquals', function (arg1, arg2, options) {
13
18
  return (arg1 == arg2) ? options.fn(this) : options.inverse(this);
14
19
  });
@@ -1476,13 +1481,15 @@ class EmailService {
1476
1481
  var baseScope = JSON.parse(JSON.stringify(that));
1477
1482
  delete baseScope.pass;
1478
1483
 
1479
-
1480
1484
  let msgText = text;
1481
- msgText = encode(msgText);
1482
1485
  if (this.markdown) {
1483
1486
  msgText = marked(msgText);
1487
+ msgText = DOMPurify.sanitize(msgText);
1488
+ } else {
1489
+ msgText = encode(msgText);
1484
1490
  }
1485
1491
 
1492
+
1486
1493
  winston.debug("msgText: " + msgText);
1487
1494
  winston.debug("baseScope: " + JSON.stringify(baseScope));
1488
1495
 
@@ -0,0 +1,43 @@
1
+ //During the test the env variable is set to test
2
+ process.env.NODE_ENV = 'test';
3
+
4
+ var expect = require('chai').expect;
5
+
6
+ var assert = require('chai').assert;
7
+ var config = require('../config/database');
8
+ var mongoose = require('mongoose');
9
+ var winston = require('../config/winston');
10
+
11
+ mongoose.connect(config.databasetest);
12
+
13
+ var projectService = require("../services/projectService");
14
+ const emailService = require('../services/emailService');
15
+
16
+ let log = false;
17
+
18
+ describe('EmailService', function () {
19
+
20
+
21
+ it('direct', function (done) {
22
+ var userid = "5badfe5d553d1844ad654072";
23
+ projectService.create("test1", userid).then(function (savedProject) {
24
+ // create(fullname, email, id_project, createdBy)
25
+
26
+ let request_id = "support-group-" + savedProject._id + "-123456";
27
+
28
+ //let text = "this is\n<b>the</b>\ntext";
29
+ //let text = 'this is <script>alert("XSS")</script>';
30
+ let text = 'Go to [Google](https://google.com)';
31
+ emailService.sendEmailDirect("my@email.com", text, savedProject._id, request_id, "Suubject").then((response) => {
32
+ console.log("response: ", response);
33
+ done();
34
+ }).catch((err) => {
35
+ console.error("err: ", err)
36
+ done();
37
+ })
38
+
39
+
40
+ });
41
+ });
42
+
43
+ });
package/test/kbRoute.js CHANGED
@@ -3,13 +3,11 @@ process.env.NODE_ENV = 'test';
3
3
  process.env.GPTKEY = "fakegptkey";
4
4
  process.env.LOG_LEVEL = 'critical'
5
5
  process.env.KB_WEBHOOK_TOKEN = "testtoken"
6
- // Similarity
7
- // process.env.PINECONE_INDEX = "test_index"
8
- // process.env.PINECONE_TYPE = "pod"
9
- // Hybrid
10
- process.env.PINECONE_INDEX = "test_hybrid_index"
11
- process.env.PINECONE_TYPE = "serverless"
12
-
6
+ process.env.PINECONE_INDEX = "test_index";
7
+ process.env.PINECONE_TYPE = "pod";
8
+ process.env.PINECONE_INDEX_HYBRID = "test_index_hybrid";
9
+ process.env.PINECONE_TYPE_HYBRID = "serverless";
10
+ process.env.ADMIN_EMAIL = "admin@tiledesk.com";
13
11
 
14
12
  var userService = require('../services/userService');
15
13
  var projectService = require('../services/projectService');
@@ -36,6 +34,14 @@ const faq = require('../models/faq');
36
34
  var expect = chai.expect;
37
35
  var assert = chai.assert;
38
36
 
37
+ let custom_profile_sample = {
38
+ name: "Custom",
39
+ type: "payment",
40
+ subStart: new Date(),
41
+ subEnd: new Date(new Date().setFullYear(new Date().getFullYear() + 1)),
42
+ customization: { hybrid: true }
43
+ }
44
+
39
45
  mongoose.connect(config.databasetest);
40
46
 
41
47
  chai.use(chaiHttp);
@@ -63,7 +69,7 @@ describe('KbRoute', () => {
63
69
 
64
70
  res.should.have.status(200);
65
71
  expect(res.body.length).to.equal(1);
66
- expect(res.body[0].engine.index_name).to.equal('test_hybrid_index')
72
+ expect(res.body[0].engine.index_name).to.equal('test_index')
67
73
 
68
74
  let namespace_id = res.body[0].id;
69
75
 
@@ -1119,7 +1125,7 @@ describe('KbRoute', () => {
1119
1125
  // });
1120
1126
  // })
1121
1127
 
1122
- it('create-namespaces-with-engine', (done) => {
1128
+ it('create-namespaces-with-engine-similarity', (done) => {
1123
1129
 
1124
1130
  var email = "test-signup-" + Date.now() + "@email.com";
1125
1131
  var pwd = "pwd";
@@ -1143,7 +1149,7 @@ describe('KbRoute', () => {
1143
1149
  expect(res.body.name).to.equal('MyCustomNamespace');
1144
1150
  should.exist(res.body.engine)
1145
1151
  expect(res.body.engine.name).to.equal('pinecone');
1146
- expect(res.body.engine.type).to.equal('serverless');
1152
+ expect(res.body.engine.type).to.equal('pod');
1147
1153
 
1148
1154
  // Get again all namespace. A new default namespace should not be created.
1149
1155
  chai.request(server)
@@ -1167,6 +1173,99 @@ describe('KbRoute', () => {
1167
1173
  });
1168
1174
  })
1169
1175
 
1176
+ it('create-namespaces-with-engine-hybrid-rejected', (done) => {
1177
+
1178
+ var email = "test-signup-" + Date.now() + "@email.com";
1179
+ var pwd = "pwd";
1180
+
1181
+ userService.signup(email, pwd, "Test Firstname", "Test lastname").then(function (savedUser) {
1182
+ projectService.create("test-faqkb-create", savedUser._id).then(function (savedProject) {
1183
+
1184
+ chai.request(server)
1185
+ .post('/' + savedProject._id + '/kb/namespace')
1186
+ .auth(email, pwd)
1187
+ .send({ name: "MyCustomNamespace", hybrid: true })
1188
+ .end((err, res) => {
1189
+
1190
+ if (err) { console.error("err: ", err) }
1191
+ if (log) { console.log("create new namespace res.body: ", res.body) }
1192
+
1193
+ res.should.have.status(403);
1194
+ res.body.should.be.a('object');
1195
+ expect(res.body.success).to.equal(false);
1196
+ expect(res.body.error).to.equal('Hybrid mode is not allowed for the current project');
1197
+
1198
+ done();
1199
+ })
1200
+ });
1201
+ });
1202
+ })
1203
+
1204
+ it('create-namespaces-with-engine-hybrid-accepted', (done) => {
1205
+
1206
+ var email = "test-signup-" + Date.now() + "@email.com";
1207
+ var pwd = "pwd";
1208
+
1209
+ userService.signup(email, pwd, "Test Firstname", "Test lastname").then(function (savedUser) {
1210
+ projectService.create("test-faqkb-create", savedUser._id).then(function (savedProject) {
1211
+
1212
+ chai.request(server)
1213
+ .post('/auth/signin')
1214
+ .send({ email: "admin@tiledesk.com", password: "adminadmin" })
1215
+ .end((err, res) => {
1216
+
1217
+ if (err) { console.error("err: ", err) }
1218
+ if (log) { console.log("login with superadmin res.body: ", res.body) };
1219
+
1220
+ res.should.have.status(200);
1221
+ res.body.should.be.a('object');
1222
+ expect(res.body.success).to.equal(true);
1223
+ expect(res.body.token).not.equal(null);
1224
+
1225
+ let superadmin_token = res.body.token;
1226
+
1227
+
1228
+ chai.request(server)
1229
+ .put('/projects/' + savedProject._id)
1230
+ .set('Authorization', superadmin_token)
1231
+ .send({ profile: custom_profile_sample })
1232
+ .end((err, res) => {
1233
+
1234
+ if (err) { console.error("err: ", err) }
1235
+ if (log) { console.log("update project res.body: ", res.body) }
1236
+
1237
+ res.should.have.status(200);
1238
+ res.body.should.be.a('object');
1239
+ expect(res.body.profile.customization.hybrid).to.equal(true);
1240
+
1241
+ chai.request(server)
1242
+ .post('/' + savedProject._id + '/kb/namespace')
1243
+ .auth(email, pwd)
1244
+ .send({ name: "MyCustomNamespace", hybrid: true })
1245
+ .end((err, res) => {
1246
+
1247
+ if (err) { console.error("err: ", err) }
1248
+ if (log) { console.log("create new namespace res.body: ", res.body) }
1249
+
1250
+ res.should.have.status(200);
1251
+ res.body.should.be.a('object');
1252
+ should.not.exist(res.body._id)
1253
+ should.exist(res.body.id)
1254
+ expect(res.body.name).to.equal('MyCustomNamespace');
1255
+ should.exist(res.body.engine)
1256
+ expect(res.body.engine.name).to.equal('pinecone');
1257
+ expect(res.body.engine.type).to.equal('serverless');
1258
+
1259
+ done();
1260
+ })
1261
+ })
1262
+
1263
+ })
1264
+
1265
+ })
1266
+ });
1267
+ })
1268
+
1170
1269
  it('import-namespace', (done) => {
1171
1270
 
1172
1271
  var email = "test-signup-" + Date.now() + "@email.com";
@@ -1488,23 +1587,28 @@ describe('KbRoute', () => {
1488
1587
  })
1489
1588
 
1490
1589
  describe('Unanswered Questions', () => {
1590
+
1491
1591
  it('add-unanswered-question', (done) => {
1492
1592
  var email = "test-signup-" + Date.now() + "@email.com";
1493
1593
  var pwd = "pwd";
1494
1594
 
1495
1595
  userService.signup(email, pwd, "Test Firstname", "Test lastname").then(function (savedUser) {
1496
1596
  projectService.create("test-unanswered-create", savedUser._id).then(function (savedProject) {
1597
+
1497
1598
  chai.request(server)
1498
1599
  .get('/' + savedProject._id + '/kb/namespace/all')
1499
1600
  .auth(email, pwd)
1500
1601
  .end((err, res) => {
1602
+
1501
1603
  if (err) { console.error("err: ", err); }
1604
+ if (log) { console.log("get namespaces res.body: ", res.body); }
1605
+
1502
1606
  res.should.have.status(200);
1503
1607
  expect(res.body.length).to.equal(1);
1504
1608
 
1505
1609
  let namespace_id = res.body[0].id;
1506
1610
 
1507
- let question = {
1611
+ let data = {
1508
1612
  namespace: namespace_id,
1509
1613
  question: "Come funziona il prodotto?"
1510
1614
  }
@@ -1512,9 +1616,12 @@ describe('KbRoute', () => {
1512
1616
  chai.request(server)
1513
1617
  .post('/' + savedProject._id + '/kb/unanswered')
1514
1618
  .auth(email, pwd)
1515
- .send(question)
1619
+ .send(data)
1516
1620
  .end((err, res) => {
1621
+
1517
1622
  if (err) { console.error("err: ", err); }
1623
+ if (log) { console.log("create unanswered question res.body: ", res.body); }
1624
+
1518
1625
  res.should.have.status(200);
1519
1626
  res.body.should.be.a('object');
1520
1627
  expect(res.body.namespace).to.equal(namespace_id);
@@ -1538,13 +1645,15 @@ describe('KbRoute', () => {
1538
1645
  .auth(email, pwd)
1539
1646
  .end((err, res) => {
1540
1647
  if (err) { console.error("err: ", err); }
1648
+ if (log) { console.log("get namespaces res.body: ", res.body); }
1649
+
1541
1650
  res.should.have.status(200);
1542
1651
  expect(res.body.length).to.equal(1);
1543
1652
 
1544
1653
  let namespace_id = res.body[0].id;
1545
1654
 
1546
1655
  // First add a question
1547
- let question = {
1656
+ let data = {
1548
1657
  namespace: namespace_id,
1549
1658
  question: "Come funziona il prodotto?"
1550
1659
  }
@@ -1552,14 +1661,16 @@ describe('KbRoute', () => {
1552
1661
  chai.request(server)
1553
1662
  .post('/' + savedProject._id + '/kb/unanswered')
1554
1663
  .auth(email, pwd)
1555
- .send(question)
1664
+ .send(data)
1556
1665
  .end((err, res) => {
1557
1666
  if (err) { console.error("err: ", err); }
1667
+ if (log) { console.log("add unanswered question res.body: ", res.body); }
1668
+
1558
1669
  res.should.have.status(200);
1559
1670
 
1560
1671
  // Then get all questions
1561
1672
  chai.request(server)
1562
- .get('/' + savedProject._id + '/kb/unanswered?namespace=' + namespace_id)
1673
+ .get('/' + savedProject._id + '/kb/unanswered/' + namespace_id)
1563
1674
  .auth(email, pwd)
1564
1675
  .end((err, res) => {
1565
1676
  if (err) { console.error("err: ", err); }
@@ -1623,7 +1734,7 @@ describe('KbRoute', () => {
1623
1734
 
1624
1735
  // Verify it's deleted
1625
1736
  chai.request(server)
1626
- .get('/' + savedProject._id + '/kb/unanswered?namespace=' + namespace_id)
1737
+ .get('/' + savedProject._id + '/kb/unanswered/' + namespace_id)
1627
1738
  .auth(email, pwd)
1628
1739
  .end((err, res) => {
1629
1740
  if (err) { console.error("err: ", err); }
@@ -1687,7 +1798,7 @@ describe('KbRoute', () => {
1687
1798
 
1688
1799
  // Verify they're deleted
1689
1800
  chai.request(server)
1690
- .get('/' + savedProject._id + '/kb/unanswered?namespace=' + namespace_id)
1801
+ .get('/' + savedProject._id + '/kb/unanswered/' + namespace_id)
1691
1802
  .auth(email, pwd)
1692
1803
  .end((err, res) => {
1693
1804
  if (err) { console.error("err: ", err); }
@@ -1789,7 +1900,7 @@ describe('KbRoute', () => {
1789
1900
  )).then(() => {
1790
1901
  // Then count them
1791
1902
  chai.request(server)
1792
- .get('/' + savedProject._id + '/kb/unanswered/count?namespace=' + namespace_id)
1903
+ .get('/' + savedProject._id + '/kb/unanswered/count/' + namespace_id)
1793
1904
  .auth(email, pwd)
1794
1905
  .end((err, res) => {
1795
1906
  if (err) { console.error("err: ", err); }