@tiledesk/tiledesk-server 2.4.100 → 2.4.102
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +9 -0
- package/app.js +45 -9
- package/event/emailEvent.js +13 -0
- package/event/integrationEvent.js +13 -0
- package/models/integrations.js +23 -0
- package/package.json +3 -3
- package/pubmodules/cache/mongoose-cachegoose-fn.js +12 -0
- package/pubmodules/emailNotification/requestNotification.js +1 -0
- package/routes/auth.js +29 -8
- package/routes/email.js +4 -2
- package/routes/faq_kb.js +3 -8
- package/routes/integration.js +199 -0
- package/routes/kb.js +0 -2
- package/routes/kbsettings.js +8 -76
- package/routes/openai.js +52 -14
- package/routes/project.js +3 -4
- package/routes/quotes.js +52 -0
- package/routes/request.js +515 -499
- package/routes/users.js +5 -1
- package/services/QuoteManager.js +304 -0
- package/services/cacheEnabler.js +5 -0
- package/services/chatbotService.js +0 -1
- package/services/emailService.js +610 -586
- package/services/messageService.js +236 -202
- package/services/openaiService.js +15 -17
- package/services/requestService.js +1739 -1420
- package/services/trainingService.js +6 -2
- package/test/messageService.js +154 -92
- package/test/mock/MockTdCache.js +46 -0
- package/test/mock/emailMock.js +9 -0
- package/test/mock/messageMock.js +46 -0
- package/test/mock/projectMock.js +171 -0
- package/test/mock/requestMock.js +127 -0
- package/test/quoteManager.js +282 -0
- package/test/requestRoute.js +1 -1
- package/test/requestService.js +1196 -1079
- package/utils/TdCache.js +253 -0
package/routes/users.js
CHANGED
@@ -195,7 +195,11 @@ router.post('/loginemail', function (req, res) {
|
|
195
195
|
let chatbot_id = req.body.bot_id;
|
196
196
|
|
197
197
|
if (!project_id) {
|
198
|
-
res.status(500).send({ success: false, error: "missing 'id_project' field" })
|
198
|
+
res.status(500).send({ success: false, error: "missing 'id_project' field" });
|
199
|
+
}
|
200
|
+
|
201
|
+
if (!chatbot_id) {
|
202
|
+
res.status(500).send({ success: false, error: "missing 'bot_id' field" });
|
199
203
|
}
|
200
204
|
|
201
205
|
if (!chatbot_id) {
|
@@ -0,0 +1,304 @@
|
|
1
|
+
const { ceil, floor } = require('lodash');
|
2
|
+
let winston = require('../config/winston');
|
3
|
+
const requestEvent = require('../event/requestEvent');
|
4
|
+
const messageEvent = require('../event/messageEvent');
|
5
|
+
const emailEvent = require('../event/emailEvent');
|
6
|
+
|
7
|
+
const PLANS_LIST = {
|
8
|
+
FREE_TRIAL: { requests: 3000, messages: 0, tokens: 250000, email: 200 }, // same as PREMIUM
|
9
|
+
SANDBOX: { requests: 200, messages: 0, tokens: 10000, email: 200 },
|
10
|
+
BASIC: { requests: 800, messages: 0, tokens: 50000, email: 200 },
|
11
|
+
PREMIUM: { requests: 3000, messages: 0, tokens: 250000, email: 200 },
|
12
|
+
CUSTOM: { requests: 3000, messages: 0, tokens: 250000, email: 200 }
|
13
|
+
}
|
14
|
+
|
15
|
+
const typesList = ['requests', 'messages', 'email', 'tokens']
|
16
|
+
|
17
|
+
let quotes_enabled = true;
|
18
|
+
|
19
|
+
class QuoteManager {
|
20
|
+
|
21
|
+
constructor(config) {
|
22
|
+
|
23
|
+
if (!config) {
|
24
|
+
throw new Error('config is mandatory')
|
25
|
+
}
|
26
|
+
|
27
|
+
if (!config.tdCache) {
|
28
|
+
throw new Error('config.tdCache is mandatory')
|
29
|
+
}
|
30
|
+
|
31
|
+
this.tdCache = config.tdCache;
|
32
|
+
this.project;
|
33
|
+
|
34
|
+
}
|
35
|
+
|
36
|
+
// INCREMENT KEY SECTION - START
|
37
|
+
async incrementRequestsCount(project, request) {
|
38
|
+
|
39
|
+
this.project = project;
|
40
|
+
let key = await this.generateKey(request, 'requests');
|
41
|
+
winston.verbose("[QuoteManager] incrementRequestsCount key: " + key);
|
42
|
+
|
43
|
+
await this.tdCache.incr(key)
|
44
|
+
return key;
|
45
|
+
}
|
46
|
+
|
47
|
+
async incrementMessagesCount(project, message) {
|
48
|
+
|
49
|
+
this.project = project;
|
50
|
+
let key = await this.generateKey(message, 'messages');
|
51
|
+
winston.verbose("[QuoteManager] incrementMessagesCount key: " + key);
|
52
|
+
|
53
|
+
await this.tdCache.incr(key)
|
54
|
+
return key;
|
55
|
+
}
|
56
|
+
|
57
|
+
async incrementEmailCount(project, email) {
|
58
|
+
|
59
|
+
this.project = project;
|
60
|
+
let key = await this.generateKey(email, 'email');
|
61
|
+
winston.info("[QuoteManager] incrementEmailCount key: " + key);
|
62
|
+
|
63
|
+
await this.tdCache.incr(key)
|
64
|
+
return key;
|
65
|
+
}
|
66
|
+
|
67
|
+
async incrementTokenCount(project, data) { // ?? cosa passo? il messaggio per vedere la data?
|
68
|
+
|
69
|
+
this.project = project;
|
70
|
+
let key = await this.generateKey(data, 'tokens');
|
71
|
+
winston.info("[QuoteManager] incrementTokenCount key: " + key);
|
72
|
+
|
73
|
+
if (quotes_enabled === false) {
|
74
|
+
winston.debug("QUOTES DISABLED - incrementTokenCount")
|
75
|
+
return key;
|
76
|
+
}
|
77
|
+
|
78
|
+
await this.tdCache.incrby(key, data.tokens);
|
79
|
+
return key;
|
80
|
+
}
|
81
|
+
// INCREMENT KEY SECTION - END
|
82
|
+
|
83
|
+
|
84
|
+
async generateKey(object, type) {
|
85
|
+
|
86
|
+
winston.info("generateKey object ", object)
|
87
|
+
winston.info("generateKey type " + type)
|
88
|
+
let subscriptionDate;
|
89
|
+
if (this.project.profile.subStart) {
|
90
|
+
subscriptionDate = this.project.profile.subStart;
|
91
|
+
} else {
|
92
|
+
subscriptionDate = this.project.createdAt;
|
93
|
+
}
|
94
|
+
let objectDate = object.createdAt;
|
95
|
+
winston.info("objectDate " + objectDate);
|
96
|
+
|
97
|
+
// converts date in timestamps and transform from ms to s
|
98
|
+
const objectDateTimestamp = ceil(objectDate.getTime() / 1000);
|
99
|
+
const subscriptionDateTimestamp = ceil(subscriptionDate.getTime() / 1000);
|
100
|
+
|
101
|
+
let ndays = (objectDateTimestamp - subscriptionDateTimestamp) / 86400; // 86400 is the number of seconds in 1 day
|
102
|
+
let nmonths = floor(ndays / 30); // number of month to add to the initial subscription date;
|
103
|
+
|
104
|
+
let date = new Date(subscriptionDate);
|
105
|
+
date.setMonth(date.getMonth() + nmonths);
|
106
|
+
|
107
|
+
return "quotes:" + type + ":" + this.project._id + ":" + date.toLocaleDateString();
|
108
|
+
}
|
109
|
+
|
110
|
+
/**
|
111
|
+
* Get current quote for a single type (tokens or request or ...)
|
112
|
+
*/
|
113
|
+
async getCurrentQuote(project, object, type) {
|
114
|
+
|
115
|
+
this.project = project;
|
116
|
+
let key = await this.generateKey(object, type);
|
117
|
+
winston.info("[QuoteManager] getCurrentQuote key: " + key);
|
118
|
+
|
119
|
+
let quote = await this.tdCache.get(key);
|
120
|
+
return Number(quote);
|
121
|
+
}
|
122
|
+
|
123
|
+
/**
|
124
|
+
* Get quotes for a all types (tokens and request and ...)
|
125
|
+
*/
|
126
|
+
async getAllQuotes(project, obj) {
|
127
|
+
|
128
|
+
this.project = project;
|
129
|
+
|
130
|
+
let quotes = {}
|
131
|
+
for (let type of typesList) {
|
132
|
+
|
133
|
+
let key = await this.generateKey(obj, type);
|
134
|
+
let quote = await this.tdCache.get(key);
|
135
|
+
|
136
|
+
quotes[type] = {
|
137
|
+
quote: Number(quote)
|
138
|
+
};
|
139
|
+
}
|
140
|
+
return quotes;
|
141
|
+
}
|
142
|
+
|
143
|
+
/**
|
144
|
+
* Perform a check on a single type.
|
145
|
+
* Returns TRUE if the limit is not reached --> operation can be performed
|
146
|
+
* Returns FALSE if the limit is reached --> operation can't be performed
|
147
|
+
*/
|
148
|
+
async checkQuote(project, object, type) {
|
149
|
+
|
150
|
+
winston.info("checkQuote project ", project);
|
151
|
+
winston.info("checkQuote object ", object);
|
152
|
+
winston.info("checkQuote type " + type);
|
153
|
+
if (quotes_enabled === false) {
|
154
|
+
winston.info("QUOTES DISABLED - checkQuote for type " + type);
|
155
|
+
return true;
|
156
|
+
}
|
157
|
+
|
158
|
+
this.project = project;
|
159
|
+
let limits = await this.getPlanLimits();
|
160
|
+
winston.info("limits for current plan: ", limits)
|
161
|
+
let quote = await this.getCurrentQuote(project, object, type);
|
162
|
+
winston.info("getCurrentQuote resp: ", quote)
|
163
|
+
|
164
|
+
if (quote == null) {
|
165
|
+
return true;
|
166
|
+
}
|
167
|
+
|
168
|
+
if (quote < limits[type]) {
|
169
|
+
return true;
|
170
|
+
} else {
|
171
|
+
return false;
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
|
176
|
+
async getPlanLimits() {
|
177
|
+
|
178
|
+
let limits;
|
179
|
+
if (this.project.profile.type === 'payment') {
|
180
|
+
|
181
|
+
const plan = this.project.profile.name;
|
182
|
+
switch (plan) {
|
183
|
+
case 'Sandbox':
|
184
|
+
limits = PLANS_LIST.SANDBOX;
|
185
|
+
break;
|
186
|
+
case 'Basic':
|
187
|
+
limits = PLANS_LIST.BASIC;
|
188
|
+
break;
|
189
|
+
case 'Premium':
|
190
|
+
limits = PLANS_LIST.PREMIUM;
|
191
|
+
break;
|
192
|
+
case 'Custom':
|
193
|
+
limits = PLANS_LIST.CUSTOM;
|
194
|
+
break;
|
195
|
+
case 'Sandbox':
|
196
|
+
limits = PLANS_LIST.SANDBOX;
|
197
|
+
break;
|
198
|
+
case 'Growth':
|
199
|
+
limits = PLANS_LIST.BASIC
|
200
|
+
break;
|
201
|
+
case 'Scale':
|
202
|
+
limits = PLANS_LIST.PREMIUM
|
203
|
+
break;
|
204
|
+
case 'Plus':
|
205
|
+
limits = PLANS_LIST.CUSTOM
|
206
|
+
break;
|
207
|
+
default:
|
208
|
+
limits = PLANS_LIST.FREE_TRIAL;
|
209
|
+
}
|
210
|
+
} else {
|
211
|
+
limits = PLANS_LIST.FREE_TRIAL;
|
212
|
+
}
|
213
|
+
return limits;
|
214
|
+
}
|
215
|
+
|
216
|
+
|
217
|
+
|
218
|
+
start() {
|
219
|
+
winston.verbose('QuoteManager start');
|
220
|
+
|
221
|
+
if (process.env.QUOTES_ENABLED !== undefined) {
|
222
|
+
if (process.env.QUOTES_ENABLED === false || process.env.QUOTES_ENABLED === 'false') {
|
223
|
+
quotes_enabled = false;
|
224
|
+
}
|
225
|
+
}
|
226
|
+
|
227
|
+
// TODO - Try to generalize to avoid repetition
|
228
|
+
let incrementEventHandler = (object) => { }
|
229
|
+
let checkEventHandler = (object) => { }
|
230
|
+
|
231
|
+
|
232
|
+
// REQUESTS EVENTS - START
|
233
|
+
// requestEvent.on('request.create.quote.before', async (payload) => {
|
234
|
+
// let result = await this.checkQuote(payload.project, payload.request, 'requests');
|
235
|
+
// if (result == true) {
|
236
|
+
// winston.info("Limit not reached - a request can be created")
|
237
|
+
// } else {
|
238
|
+
// winston.info("Requests limit reached for the current plan!")
|
239
|
+
// }
|
240
|
+
// return result;
|
241
|
+
// });
|
242
|
+
|
243
|
+
requestEvent.on('request.create.quote', async (payload) => {
|
244
|
+
if (quotes_enabled === true) {
|
245
|
+
winston.verbose("request.create.quote event catched");
|
246
|
+
let result = await this.incrementRequestsCount(payload.project, payload.request);
|
247
|
+
return result;
|
248
|
+
} else {
|
249
|
+
winston.info("QUOTES DISABLED - request.create.quote event")
|
250
|
+
}
|
251
|
+
})
|
252
|
+
// REQUESTS EVENTS - END
|
253
|
+
|
254
|
+
|
255
|
+
// MESSAGES EVENTS - START
|
256
|
+
// messageEvent.on('message.create.quote.before', async (payload) => {
|
257
|
+
// let result = await this.checkQuote(payload.project, payload.message, 'messages');
|
258
|
+
// if (result == true) {
|
259
|
+
// winston.info("Limit not reached - a message can be created")
|
260
|
+
// } else {
|
261
|
+
// winston.info("Messages limit reached for the current plan!")
|
262
|
+
// }
|
263
|
+
// return result;
|
264
|
+
// })
|
265
|
+
|
266
|
+
messageEvent.on('message.create.quote', async (payload) => {
|
267
|
+
if (quotes_enabled === true) {
|
268
|
+
winston.verbose("message.create.quote event catched");
|
269
|
+
let result = await this.incrementMessagesCount(payload.project, payload.message);
|
270
|
+
return result;
|
271
|
+
} else {
|
272
|
+
winston.info("QUOTES DISABLED - message.create.quote event")
|
273
|
+
}
|
274
|
+
})
|
275
|
+
// MESSAGES EVENTS - END
|
276
|
+
|
277
|
+
|
278
|
+
// EMAIL EVENTS - START - Warning! Can't be used for check quote
|
279
|
+
// emailEvent.on('email.send.before', async (payload) => {
|
280
|
+
// let result = await this.checkQuote(payload.project, payload.email, 'email');
|
281
|
+
// if (result == true) {
|
282
|
+
// winston.info("Limit not reached - a message can be created")
|
283
|
+
// } else {
|
284
|
+
// winston.info("Email limit reached for the current plan!")
|
285
|
+
// }
|
286
|
+
// return result;
|
287
|
+
// })
|
288
|
+
|
289
|
+
emailEvent.on('email.send.quote', async (payload) => {
|
290
|
+
if (quotes_enabled === true) {
|
291
|
+
winston.info("email.send event catched");
|
292
|
+
let result = await this.incrementEmailCount(payload.project, payload.email);
|
293
|
+
return result;
|
294
|
+
} else {
|
295
|
+
winston.info("QUOTES DISABLED - email.send event")
|
296
|
+
}
|
297
|
+
})
|
298
|
+
// EMAIL EVENTS - END
|
299
|
+
}
|
300
|
+
|
301
|
+
|
302
|
+
}
|
303
|
+
|
304
|
+
module.exports = { QuoteManager };
|
package/services/cacheEnabler.js
CHANGED
@@ -42,6 +42,11 @@ class CacheEnabler {
|
|
42
42
|
this.widgets = false;
|
43
43
|
}
|
44
44
|
|
45
|
+
this.integrations = true;
|
46
|
+
if (process.env.CACHE_INTEGRATIONS_ENABLED=="false" || process.env.CACHE_INTEGRATIONS_ENABLED==false) {
|
47
|
+
this.integrations = false;
|
48
|
+
}
|
49
|
+
|
45
50
|
// this.user = true;
|
46
51
|
// if (process.env.CACHE_USER_ENABLED=="false" || process.env.CACHE_USER_ENABLED==false) {
|
47
52
|
// this.user = false;
|
@@ -32,7 +32,6 @@ class ChatbotService {
|
|
32
32
|
async getBotById(id_faq_kb, published, api_url, chatbot_templates_api_url, token, project_id, globals) {
|
33
33
|
|
34
34
|
winston.debug("[CHATBOT SERVICE] getBotById");
|
35
|
-
console.log("getBotById globals: ", globals);
|
36
35
|
|
37
36
|
// private bot
|
38
37
|
if (published == "false") {
|