@tiledesk/tiledesk-server 2.8.0 → 2.8.1
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 +8 -0
- package/deploy.sh +1 -1
- package/models/request.js +3 -0
- package/package.json +1 -1
- package/pubmodules/analytics/analytics.js +28 -1
- package/routes/kb.js +60 -7
- package/services/QuoteManager.js +5 -5
- package/services/openaiService.js +19 -0
- package/services/requestService.js +5 -3
- package/template/email/beenInvitedNewUser.html +216 -221
- package/test/requestRoute.js +46 -0
package/CHANGELOG.md
CHANGED
@@ -6,6 +6,14 @@
|
|
6
6
|
(https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
|
7
7
|
|
8
8
|
# 2.8.1
|
9
|
+
- Added trashed=false in chatbot namespace query
|
10
|
+
- Return empty array if no chatbots are using the namespace
|
11
|
+
- Enhanced kb context
|
12
|
+
- Added enpoint to retrieve all content's chunks
|
13
|
+
- Added limit on namespaces
|
14
|
+
- Restore beenInvitedNewUser email
|
15
|
+
|
16
|
+
# 2.8.0
|
9
17
|
- Enable quotas for conversations, tokens, and direct email.
|
10
18
|
- Added namespaces to knowledge base
|
11
19
|
- Updated tybot-connector to 0.2.82
|
package/deploy.sh
CHANGED
package/models/request.js
CHANGED
package/package.json
CHANGED
@@ -186,6 +186,11 @@ router.get('/requests/aggregate/status', function(req, res) {
|
|
186
186
|
winston.debug('req.query.participant', req.query.participant);
|
187
187
|
query.participants = req.query.participant;
|
188
188
|
}
|
189
|
+
|
190
|
+
if (req.query.channel) {
|
191
|
+
winston.debug('req.query.channel', req.query.channel);
|
192
|
+
query['channel.name'] = req.query.channel;
|
193
|
+
}
|
189
194
|
|
190
195
|
winston.debug("QueryParams_LastDayCHART:", lastdays,req.query.department_id)
|
191
196
|
winston.debug("Query_LastDayCHART", query)
|
@@ -632,6 +637,11 @@ router.get('/requests/aggregate/status', function(req, res) {
|
|
632
637
|
query.participants = req.query.participant;
|
633
638
|
}
|
634
639
|
|
640
|
+
if (req.query.channel) {
|
641
|
+
winston.debug('req.query.channel', req.query.channel);
|
642
|
+
query['channel.name'] = req.query.channel;
|
643
|
+
}
|
644
|
+
|
635
645
|
|
636
646
|
winston.debug("QueryParams_AvgTime:", lastdays,req.query.department_id)
|
637
647
|
winston.debug("Query_AvgTIME", query)
|
@@ -801,6 +811,10 @@ router.get('/requests/aggregate/status', function(req, res) {
|
|
801
811
|
query.participants = req.query.participant;
|
802
812
|
}
|
803
813
|
|
814
|
+
if (req.query.channel) {
|
815
|
+
winston.debug('req.query.channel', req.query.channel);
|
816
|
+
query['channel.name'] = req.query.channel;
|
817
|
+
}
|
804
818
|
|
805
819
|
winston.debug("QueryParams_DurationTIME:", lastdays,req.query.department_id)
|
806
820
|
winston.debug("Query_DurationTIME", query)
|
@@ -930,7 +944,10 @@ router.get('/requests/aggregate/status', function(req, res) {
|
|
930
944
|
query.participants = req.query.participant;
|
931
945
|
}
|
932
946
|
|
933
|
-
|
947
|
+
if (req.query.channel) {
|
948
|
+
winston.debug('req.query.channel', req.query.channel);
|
949
|
+
query['channel.name'] = req.query.channel;
|
950
|
+
}
|
934
951
|
|
935
952
|
winston.debug("QueryParams_SatisfactionTIME:", lastdays,req.query.department_id)
|
936
953
|
winston.debug("Query_SatisfactionTIME", query)
|
@@ -1056,6 +1073,11 @@ router.get('/requests/hasBot/count', function(req, res) {
|
|
1056
1073
|
query.department= new ObjectId(req.query.department_id);
|
1057
1074
|
|
1058
1075
|
}
|
1076
|
+
|
1077
|
+
if (req.query.channel) {
|
1078
|
+
winston.debug('req.query.channel', req.query.channel);
|
1079
|
+
query['channel.name'] = req.query.channel;
|
1080
|
+
}
|
1059
1081
|
|
1060
1082
|
winston.debug("QueryParams_LastDayCHART:", lastdays,req.query.department_id)
|
1061
1083
|
winston.debug("Query_LastDayCHART", query)
|
@@ -1410,6 +1432,11 @@ router.get('/messages/count', function(req, res) {
|
|
1410
1432
|
query.recipient = req.query.recipient;
|
1411
1433
|
}
|
1412
1434
|
|
1435
|
+
if (req.query.channel) {
|
1436
|
+
winston.debug('req.query.channel', req.query.channel);
|
1437
|
+
query['channel.name'] = req.query.channel;
|
1438
|
+
}
|
1439
|
+
|
1413
1440
|
|
1414
1441
|
winston.debug("Query_LastDayCHART", query)
|
1415
1442
|
|
package/routes/kb.js
CHANGED
@@ -36,9 +36,12 @@ let default_preview_settings = {
|
|
36
36
|
max_tokens: 128,
|
37
37
|
temperature: 0.7,
|
38
38
|
top_k: 4,
|
39
|
-
context: "You are an awesome AI Assistant."
|
39
|
+
//context: "You are an awesome AI Assistant."
|
40
|
+
context: null
|
40
41
|
}
|
41
42
|
|
43
|
+
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}"
|
44
|
+
|
42
45
|
/**
|
43
46
|
* ****************************************
|
44
47
|
* Proxy Section - Start
|
@@ -200,10 +203,11 @@ router.post('/qa', async (req, res) => {
|
|
200
203
|
}
|
201
204
|
}
|
202
205
|
|
206
|
+
// Check if "Advanced Mode" is active. In such case the default_context must be not appended
|
203
207
|
if (data.system_context) {
|
204
|
-
data.system_context = data.system_context + "
|
208
|
+
data.system_context = data.system_context + " \n" + default_context;
|
205
209
|
}
|
206
|
-
|
210
|
+
|
207
211
|
openaiService.askNamespace(data).then((resp) => {
|
208
212
|
winston.debug("qa resp: ", resp.data);
|
209
213
|
let answer = resp.data;
|
@@ -384,11 +388,52 @@ router.get('/namespace/all', async (req, res) => {
|
|
384
388
|
})
|
385
389
|
})
|
386
390
|
|
391
|
+
router.get('/namespace/:id/chunks/:content_id', async (req, res) => {
|
392
|
+
|
393
|
+
let project_id = req.projectid;
|
394
|
+
let namespace_id = req.params.id;
|
395
|
+
let content_id = req.params.content_id;
|
396
|
+
|
397
|
+
let namespaces = await Namespace.find({ id_project: project_id }).catch((err) => {
|
398
|
+
winston.error("find namespaces error: ", err)
|
399
|
+
return res.status(500).send({ success: false, error: err })
|
400
|
+
})
|
401
|
+
|
402
|
+
let namespaceIds = namespaces.map(namespace => namespace.id);
|
403
|
+
if (!namespaceIds.includes(namespace_id)) {
|
404
|
+
return res.status(403).send({ success: false, error: "Not allowed. The namespace does not belong to the current project." })
|
405
|
+
}
|
406
|
+
|
407
|
+
let content = await KB.find({ id_project: project_id, namespace: namespace_id, _id: content_id }).catch((err) => {
|
408
|
+
winston.error("find content error: ", err);
|
409
|
+
return res.status(403).send({ success: false, error: err })
|
410
|
+
})
|
411
|
+
|
412
|
+
if(!content) {
|
413
|
+
return res.status(403).send({ success: false, error: "Not allowed. The conten does not belong to the current namespace." })
|
414
|
+
}
|
415
|
+
|
416
|
+
openaiService.getContentChunks(namespace_id, content_id).then((resp) => {
|
417
|
+
let chunks = resp.data;
|
418
|
+
winston.debug("chunks for content " + content_id);
|
419
|
+
winston.debug("chunks found ", chunks);
|
420
|
+
return res.status(200).send(chunks);
|
421
|
+
|
422
|
+
}).catch((err) => {
|
423
|
+
console.log("error getting content chunks err.response: ", err.response)
|
424
|
+
console.log("error getting content chunks err.data: ", err.data)
|
425
|
+
return res.status(500).send({ success: false, error: err });
|
426
|
+
})
|
427
|
+
|
428
|
+
})
|
429
|
+
|
387
430
|
router.get('/namespace/:id/chatbots', async (req, res) => {
|
388
431
|
|
389
432
|
let project_id = req.projectid;
|
390
433
|
let namespace_id = req.params.id;
|
391
434
|
|
435
|
+
let chatbotsArray = [];
|
436
|
+
|
392
437
|
let namespaces = await Namespace.find({ id_project: project_id }).catch((err) => {
|
393
438
|
winston.error("find namespaces error: ", err)
|
394
439
|
res.status(500).send({ success: false, error: err })
|
@@ -406,16 +451,15 @@ router.get('/namespace/:id/chatbots', async (req, res) => {
|
|
406
451
|
|
407
452
|
if (!intents || intents.length == 0) {
|
408
453
|
winston.verbose("No intents found for the selected chatbot")
|
409
|
-
return res.status(200).send(
|
454
|
+
return res.status(200).send(chatbotsArray);
|
410
455
|
}
|
411
456
|
|
412
457
|
let chatbots = intents.map(i => i.id_faq_kb);
|
413
458
|
let uniqueChatbots = [...new Set(chatbots)];
|
414
459
|
|
415
|
-
let chatbotsArray = [];
|
416
460
|
let chatbotPromises = uniqueChatbots.map(async (c_id) => {
|
417
461
|
try {
|
418
|
-
let chatbot = await faq_kb.
|
462
|
+
let chatbot = await faq_kb.findOne({ _id: c_id, trashed: false });
|
419
463
|
if (chatbot) {
|
420
464
|
let data = {
|
421
465
|
_id: chatbot._id,
|
@@ -431,7 +475,7 @@ router.get('/namespace/:id/chatbots', async (req, res) => {
|
|
431
475
|
await Promise.all(chatbotPromises);
|
432
476
|
|
433
477
|
winston.debug("chatbotsArray: ", chatbotsArray);
|
434
|
-
|
478
|
+
|
435
479
|
res.status(200).send(chatbotsArray);
|
436
480
|
})
|
437
481
|
|
@@ -457,6 +501,15 @@ router.post('/namespace', async (req, res) => {
|
|
457
501
|
new_namespace.default = true;
|
458
502
|
}
|
459
503
|
|
504
|
+
let quoteManager = req.app.get('quote_manager');
|
505
|
+
let limits = await quoteManager.getPlanLimits(req.project);
|
506
|
+
let ns_limit = limits.namespace;
|
507
|
+
console.log("Limit of namespaces for current plan " + ns_limit);
|
508
|
+
|
509
|
+
if (namespaces.length >= ns_limit) {
|
510
|
+
return res.status(403).send({ success: false, error: "Maximum number of resources reached for the current plan", plan_limit: ns_limit });
|
511
|
+
}
|
512
|
+
|
460
513
|
new_namespace.save((err, savedNamespace) => {
|
461
514
|
if (err) {
|
462
515
|
winston.error("create namespace error: ", err);
|
package/services/QuoteManager.js
CHANGED
@@ -14,11 +14,11 @@ const emailEvent = require('../event/emailEvent');
|
|
14
14
|
// }
|
15
15
|
|
16
16
|
const PLANS_LIST = {
|
17
|
-
FREE_TRIAL: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20,
|
18
|
-
SANDBOX: { requests: 200, messages: 0, tokens: 100000, email: 200, chatbots: 2,
|
19
|
-
BASIC: { requests: 800, messages: 0, tokens: 2000000, email: 200, chatbots: 5,
|
20
|
-
PREMIUM: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20,
|
21
|
-
CUSTOM: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20,
|
17
|
+
FREE_TRIAL: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20, namespace: 3, kbs: 50 }, // same as PREMIUM
|
18
|
+
SANDBOX: { requests: 200, messages: 0, tokens: 100000, email: 200, chatbots: 2, namespace: 1, kbs: 50 },
|
19
|
+
BASIC: { requests: 800, messages: 0, tokens: 2000000, email: 200, chatbots: 5, namespace: 1, kbs: 150 },
|
20
|
+
PREMIUM: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20, namespace: 3, kbs: 300 },
|
21
|
+
CUSTOM: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20, namespace: 3, kbs: 1000 }
|
22
22
|
}
|
23
23
|
|
24
24
|
const typesList = ['requests', 'messages', 'email', 'tokens', 'chatbots', 'kbs']
|
@@ -162,6 +162,25 @@ class OpenaiService {
|
|
162
162
|
})
|
163
163
|
}
|
164
164
|
|
165
|
+
getContentChunks(namespace_id, content_id) {
|
166
|
+
winston.info("[OPENAI SERVICE] kb endpoint: " + kb_endpoint_train);
|
167
|
+
winston.info(kb_endpoint_train + "/id/" + content_id + "/namespace/" + namespace_id)
|
168
|
+
return new Promise((resolve, reject) => {
|
169
|
+
|
170
|
+
axios({
|
171
|
+
url: kb_endpoint_train + "/id/" + content_id + "/namespace/" + namespace_id,
|
172
|
+
headers: {
|
173
|
+
'Content-Type': 'application/json'
|
174
|
+
},
|
175
|
+
method: 'GET'
|
176
|
+
}).then((resbody) => {
|
177
|
+
resolve(resbody)
|
178
|
+
}).catch((err) => {
|
179
|
+
reject(err)
|
180
|
+
})
|
181
|
+
})
|
182
|
+
}
|
183
|
+
|
165
184
|
deleteIndex(data) {
|
166
185
|
winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint_train);
|
167
186
|
|
@@ -1266,14 +1266,16 @@ class RequestService {
|
|
1266
1266
|
|
1267
1267
|
}
|
1268
1268
|
|
1269
|
-
setClosedAtByRequestId(request_id, id_project, closed_at, closed_by) {
|
1269
|
+
setClosedAtByRequestId(request_id, id_project, created_at, closed_at, closed_by) {
|
1270
1270
|
|
1271
1271
|
return new Promise(function (resolve, reject) {
|
1272
1272
|
// winston.debug("request_id", request_id);
|
1273
1273
|
// winston.debug("newstatus", newstatus);
|
1274
1274
|
|
1275
|
+
let duration = Math.abs(new Date(created_at) - new Date(closed_at))
|
1276
|
+
|
1275
1277
|
return Request
|
1276
|
-
.findOneAndUpdate({ request_id: request_id, id_project: id_project }, { closed_at: closed_at, closed_by: closed_by }, { new: true, upsert: false })
|
1278
|
+
.findOneAndUpdate({ request_id: request_id, id_project: id_project }, { closed_at: closed_at, closed_by: closed_by, duration: duration }, { new: true, upsert: false })
|
1277
1279
|
.populate('lead')
|
1278
1280
|
.populate('department')
|
1279
1281
|
.populate('participatingBots')
|
@@ -1448,7 +1450,7 @@ class RequestService {
|
|
1448
1450
|
}
|
1449
1451
|
|
1450
1452
|
// setClosedAtByRequestId(request_id, id_project, closed_at, closed_by)
|
1451
|
-
return that.setClosedAtByRequestId(request_id, id_project, new Date().getTime(), closed_by).then(function (updatedRequest) {
|
1453
|
+
return that.setClosedAtByRequestId(request_id, id_project, request.createdAt, new Date().getTime(), closed_by).then(function (updatedRequest) {
|
1452
1454
|
|
1453
1455
|
winston.verbose("Request closed with id: " + updatedRequest.id);
|
1454
1456
|
winston.debug("Request closed ", updatedRequest);
|
@@ -1,235 +1,230 @@
|
|
1
|
-
<!DOCTYPE html
|
2
|
-
|
3
|
-
<html
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
8
|
-
box-sizing: border-box;
|
9
|
-
font-size: 14px;
|
10
|
-
margin: 0;
|
11
|
-
"
|
12
|
-
>
|
13
|
-
<head>
|
1
|
+
<!DOCTYPE html
|
2
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
+
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
|
4
|
+
style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
5
|
+
|
6
|
+
<head>
|
14
7
|
<meta name="viewport" content="width=device-width" />
|
15
8
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
16
|
-
<title>New
|
9
|
+
<title>New email from Tiledesk</title>
|
17
10
|
|
18
11
|
<style type="text/css">
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
}
|
24
|
-
|
25
|
-
img.CToWUd {
|
26
|
-
margin-bottom: 16px;
|
27
|
-
max-width: 200px !important;
|
28
|
-
width: 200px !important;
|
29
|
-
min-width: 200px !important;
|
30
|
-
outline: none;
|
31
|
-
text-decoration: none;
|
32
|
-
border: none;
|
33
|
-
height: auto;
|
34
|
-
margin-left: 0px;
|
35
|
-
}
|
36
|
-
|
37
|
-
body {
|
38
|
-
background-color: #e2e7e9;
|
39
|
-
-webkit-font-smoothing: antialiased;
|
40
|
-
-webkit-text-size-adjust: none;
|
41
|
-
width: 100% !important;
|
42
|
-
height: 100%;
|
43
|
-
line-height: 1.6em;
|
44
|
-
padding: 30px 0px;
|
45
|
-
}
|
46
|
-
|
47
|
-
.box-container {
|
48
|
-
display: flex;
|
49
|
-
flex-direction: column;
|
50
|
-
justify-content: center;
|
51
|
-
align-items: center;
|
52
|
-
width: 100%;
|
53
|
-
margin-bottom: 30px;
|
54
|
-
/* position: fixed;
|
55
|
-
top: 90px; */
|
56
|
-
}
|
57
|
-
|
58
|
-
.box {
|
59
|
-
background-color: #fff;
|
60
|
-
width: 600px;
|
61
|
-
min-height: 400px;
|
62
|
-
border-radius: 8px;
|
63
|
-
}
|
64
|
-
|
65
|
-
.header-image {
|
66
|
-
background-image: url('https://img.freepik.com/vettori-premium/illustrazione-di-progettazione-del-pacchetto-piatto-di-finanza_205077-4142.jpg?w=2000');
|
67
|
-
background-size: cover;
|
68
|
-
background-repeat: no-repeat;
|
69
|
-
height: 200px;
|
70
|
-
width: 100%;
|
71
|
-
margin-bottom: 40px;
|
72
|
-
border-radius: 8px;
|
73
|
-
}
|
74
|
-
|
75
|
-
.header {
|
76
|
-
text-align: center;
|
77
|
-
}
|
78
|
-
|
79
|
-
h1 {
|
80
|
-
padding: 0px 40px;
|
81
|
-
}
|
82
|
-
|
83
|
-
.content-body {
|
84
|
-
padding: 10px 30px;
|
85
|
-
}
|
86
|
-
|
87
|
-
a {
|
88
|
-
/* box-sizing: border-box; */
|
89
|
-
font-size: 16px;
|
90
|
-
font-weight: 600;
|
91
|
-
color: #3c3c3c;
|
92
|
-
text-decoration: none;
|
93
|
-
margin: 0;
|
94
|
-
margin-bottom: 10px;
|
95
|
-
}
|
96
|
-
|
97
|
-
a:hover {
|
98
|
-
text-decoration: underline;
|
99
|
-
}
|
100
|
-
|
101
|
-
@media only screen and (max-width: 640px) {
|
102
|
-
body {
|
103
|
-
padding: 0 !important;
|
104
|
-
}
|
105
|
-
|
106
|
-
h1 {
|
107
|
-
font-weight: 800 !important;
|
108
|
-
margin: 20px 0 5px !important;
|
109
|
-
text-align: center !important;
|
110
|
-
}
|
111
|
-
|
112
|
-
h2 {
|
113
|
-
font-weight: 800 !important;
|
114
|
-
margin: 20px 0 5px !important;
|
115
|
-
}
|
116
|
-
|
117
|
-
h3 {
|
118
|
-
font-weight: 800 !important;
|
119
|
-
margin: 20px 0 5px !important;
|
120
|
-
}
|
121
|
-
|
122
|
-
h4 {
|
123
|
-
font-weight: 800 !important;
|
124
|
-
margin: 20px 0 5px !important;
|
125
|
-
}
|
126
|
-
|
127
|
-
h1 {
|
128
|
-
font-size: 22px !important;
|
129
|
-
}
|
130
|
-
|
131
|
-
h2 {
|
132
|
-
font-size: 18px !important;
|
12
|
+
img {
|
13
|
+
max-width: 100%;
|
14
|
+
margin-left: 16px;
|
15
|
+
text-align: center !important;
|
133
16
|
}
|
134
17
|
|
135
|
-
|
136
|
-
|
18
|
+
img.CToWUd {
|
19
|
+
margin-bottom: 16px;
|
20
|
+
max-width: 200px !important;
|
21
|
+
width: 200px !important;
|
22
|
+
min-width: 200px !important;
|
23
|
+
outline: none;
|
24
|
+
text-decoration: none;
|
25
|
+
border: none;
|
26
|
+
height: auto;
|
27
|
+
margin-left: 0px;
|
137
28
|
}
|
138
29
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
padding: 0 !important;
|
30
|
+
body {
|
31
|
+
-webkit-font-smoothing: antialiased;
|
32
|
+
-webkit-text-size-adjust: none;
|
33
|
+
width: 100% !important;
|
34
|
+
height: 100%;
|
35
|
+
line-height: 1.6em;
|
146
36
|
}
|
147
37
|
|
148
|
-
|
149
|
-
|
38
|
+
body {
|
39
|
+
background-color: #f6f6f6;
|
150
40
|
}
|
151
41
|
|
152
|
-
|
153
|
-
|
42
|
+
@media only screen and (max-width: 640px) {
|
43
|
+
body {
|
44
|
+
padding: 0 !important;
|
45
|
+
}
|
46
|
+
|
47
|
+
h1 {
|
48
|
+
font-weight: 800 !important;
|
49
|
+
margin: 20px 0 5px !important;
|
50
|
+
text-align: center !important;
|
51
|
+
}
|
52
|
+
|
53
|
+
h2 {
|
54
|
+
font-weight: 800 !important;
|
55
|
+
margin: 20px 0 5px !important;
|
56
|
+
}
|
57
|
+
|
58
|
+
h3 {
|
59
|
+
font-weight: 800 !important;
|
60
|
+
margin: 20px 0 5px !important;
|
61
|
+
}
|
62
|
+
|
63
|
+
h4 {
|
64
|
+
font-weight: 800 !important;
|
65
|
+
margin: 20px 0 5px !important;
|
66
|
+
}
|
67
|
+
|
68
|
+
h1 {
|
69
|
+
font-size: 22px !important;
|
70
|
+
}
|
71
|
+
|
72
|
+
h2 {
|
73
|
+
font-size: 18px !important;
|
74
|
+
}
|
75
|
+
|
76
|
+
h3 {
|
77
|
+
font-size: 16px !important;
|
78
|
+
}
|
79
|
+
|
80
|
+
.container {
|
81
|
+
padding: 0 !important;
|
82
|
+
width: 100% !important;
|
83
|
+
}
|
84
|
+
|
85
|
+
.content {
|
86
|
+
padding: 0 !important;
|
87
|
+
}
|
88
|
+
|
89
|
+
.content-wrap {
|
90
|
+
padding: 10px !important;
|
91
|
+
}
|
92
|
+
|
93
|
+
.invoice {
|
94
|
+
width: 100% !important;
|
95
|
+
}
|
154
96
|
}
|
155
|
-
}
|
156
97
|
</style>
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
<
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
98
|
+
</head>
|
99
|
+
|
100
|
+
<body itemscope itemtype="http://schema.org/EmailMessage"
|
101
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; background-color: #f6f6f6; margin: 0;"
|
102
|
+
bgcolor="#f6f6f6">
|
103
|
+
|
104
|
+
<table class="body-wrap"
|
105
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; background-color: #f6f6f6; margin: 0;"
|
106
|
+
bgcolor="#f6f6f6">
|
107
|
+
<tr
|
108
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
109
|
+
<td style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;"
|
110
|
+
valign="top"></td>
|
111
|
+
<td class="container" width="600"
|
112
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; display: block !important; max-width: 600px !important; clear: both !important; margin: 0 auto;"
|
113
|
+
valign="top">
|
114
|
+
<div class="content"
|
115
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; max-width: 600px; display: block; margin: 0 auto; padding: 20px;">
|
116
|
+
|
117
|
+
<div style="text-align:center">
|
118
|
+
<!--
|
119
|
+
<a href="http://www.tiledesk.com"
|
120
|
+
style="color:#2daae1;font-weight:bold;text-decoration:none;word-break:break-word" target="_blank">
|
121
|
+
<img src="https://tiledesk.com/wp-content/uploads/2023/01/tiledesk_log_email_200.png" class="CToWUd">
|
122
|
+
</a>
|
123
|
+
-->
|
124
|
+
</div>
|
125
|
+
<table class="main" width="100%" cellpadding="0" cellspacing="0"
|
126
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; border-radius: 3px; background-color: #fff; margin: 0; border: 1px solid #e9e9e9;"
|
127
|
+
bgcolor="#fff">
|
128
|
+
|
129
|
+
<!-- <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
130
|
+
|
131
|
+
</tr> -->
|
132
|
+
|
133
|
+
<tr
|
134
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
135
|
+
<td class="content-wrap"
|
136
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 20px;"
|
137
|
+
valign="top">
|
138
|
+
<table width="100%" cellpadding="0" cellspacing="0"
|
139
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
140
|
+
|
141
|
+
|
142
|
+
<tr
|
143
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
144
|
+
|
145
|
+
<td class="content-block"
|
146
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;"
|
147
|
+
valign="top">
|
148
|
+
<h2
|
149
|
+
style="text-align: center; letter-spacing: 1px; font-weight: 400; line-height:24px ">
|
150
|
+
{{currentUserFirstname}} {{currentUserLastname}} has invited you to the
|
151
|
+
Tiledesk project
|
152
|
+
<strong> {{projectName}}</strong>
|
153
|
+
</h2>
|
154
|
+
|
155
|
+
<!-- <br> <br><strong
|
156
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">{{to}},</strong> -->
|
157
|
+
|
158
|
+
<br> <br>
|
159
|
+
I invited you to take on the role of {{invitedUserRole}} of the Tiledesk
|
160
|
+
<strong>
|
161
|
+
{{projectName}}</strong> project
|
162
|
+
|
163
|
+
|
164
|
+
<div style="text-align: center;">
|
165
|
+
<br><br>
|
166
|
+
|
167
|
+
<a href="{{baseScope.baseUrl}}/#/handle-invitation/{{pendinginvitationid}}/{{projectName}}/{{currentUserFirstname}}/{{currentUserLastname}}"
|
168
|
+
style=" background-color: #ff8574 !important; border: none; color: white; padding: 12px 30px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; font-weight: 600; letter-spacing: 1px; margin: 4px 2px; cursor: pointer;">
|
169
|
+
GO TO THE PROJECT
|
170
|
+
</a>
|
171
|
+
</div>
|
172
|
+
|
173
|
+
<br><br> The Tiledesk Team
|
174
|
+
</td>
|
175
|
+
</tr>
|
176
|
+
|
177
|
+
<tr
|
178
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
179
|
+
<td class="content-block"
|
180
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;"
|
181
|
+
valign="top">
|
182
|
+
</td>
|
183
|
+
</tr>
|
184
|
+
</table>
|
185
|
+
</td>
|
186
|
+
</tr>
|
187
|
+
|
188
|
+
<tr>
|
189
|
+
<td>
|
190
|
+
<hr style="width:94%;height:1px;border:none;background-color: #cacaca;">
|
191
|
+
|
192
|
+
<div style="display: flex; padding: 20px 18px; color: #888888; align-items: center;">
|
193
|
+
<span>Powered by </span>
|
194
|
+
<span style="display: flex;"><img
|
195
|
+
src="https://tiledesk.com/wp-content/uploads/2023/05/tiledesk-solo_logo_new_gray.png"
|
196
|
+
width="15" height="15" style="margin-left: 6px; margin-top: 2px;" /></span>
|
197
|
+
<span style="font-weight: bold; margin-left: 2px;">Tiledesk</span>
|
198
|
+
</div>
|
199
|
+
|
200
|
+
</td>
|
201
|
+
</tr>
|
202
|
+
|
203
|
+
</table>
|
204
|
+
<div class="footer"
|
205
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;">
|
206
|
+
<table width="100%"
|
207
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
208
|
+
<tr
|
209
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
210
|
+
<td class="aligncenter content-block"
|
211
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0;"
|
212
|
+
align="center" valign="top">
|
213
|
+
<span><a href="http://www.tiledesk.com"
|
214
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">
|
215
|
+
Tiledesk.com </a></span>
|
216
|
+
<br><span><a href="%unsubscribe_url%"
|
217
|
+
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">Unsubscribe</a></span>
|
218
|
+
</td>
|
219
|
+
</tr>
|
220
|
+
</table>
|
221
|
+
</div>
|
222
|
+
</div>
|
223
|
+
</td>
|
224
|
+
<td style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;"
|
225
|
+
valign="top"></td>
|
226
|
+
</tr>
|
227
|
+
</table>
|
228
|
+
</body>
|
229
|
+
|
230
|
+
</html>
|
package/test/requestRoute.js
CHANGED
@@ -84,6 +84,52 @@ describe('RequestRoute', () => {
|
|
84
84
|
});
|
85
85
|
|
86
86
|
|
87
|
+
it('createSimpleAndCloseForDuration', function (done) {
|
88
|
+
// this.timeout(10000);
|
89
|
+
|
90
|
+
var email = "test-request-create-" + Date.now() + "@email.com";
|
91
|
+
var pwd = "pwd";
|
92
|
+
|
93
|
+
userService.signup(email, pwd, "Test Firstname", "Test lastname").then(function (savedUser) {
|
94
|
+
projectService.create("request-create", savedUser._id, { email: { template: { assignedRequest: "123" } } }).then(function (savedProject) {
|
95
|
+
|
96
|
+
chai.request(server)
|
97
|
+
.post('/' + savedProject._id + '/requests/')
|
98
|
+
.auth(email, pwd)
|
99
|
+
.set('content-type', 'application/json')
|
100
|
+
.send({ "first_text": "first_text" })
|
101
|
+
.end(function (err, res) {
|
102
|
+
//console.log("res", res);
|
103
|
+
//console.log("res.body", res.body);
|
104
|
+
res.should.have.status(200);
|
105
|
+
res.body.should.be.a('object');
|
106
|
+
|
107
|
+
//console.log("res.body: ", res.body)
|
108
|
+
|
109
|
+
setTimeout(() => {
|
110
|
+
|
111
|
+
chai.request(server)
|
112
|
+
.put('/' + savedProject._id + '/requests/' + res.body.request_id + '/close')
|
113
|
+
.auth(email, pwd)
|
114
|
+
.send()
|
115
|
+
.end((err, res) => {
|
116
|
+
|
117
|
+
if (err) { console.error("err: ", err) };
|
118
|
+
console.log("request duration: ", res.body.duration)
|
119
|
+
|
120
|
+
res.body.should.have.property('duration');
|
121
|
+
res.body.duration.should.be.above(2000);
|
122
|
+
|
123
|
+
done();
|
124
|
+
})
|
125
|
+
|
126
|
+
}, 2000)
|
127
|
+
|
128
|
+
});
|
129
|
+
});
|
130
|
+
});
|
131
|
+
}).timeout(5000);
|
132
|
+
|
87
133
|
|
88
134
|
|
89
135
|
|