@tiledesk/tiledesk-server 2.17.4 → 2.18.3
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 -3
- package/app.js +4 -0
- package/channels/chat21/chat21WebHook.js +6 -1
- package/docs/routes-answered.md +153 -0
- package/event/authEvent.js +16 -0
- package/event/projectUserEvent.js +39 -0
- package/event/roleEvent.js +9 -0
- package/middleware/has-role.js +160 -121
- package/middleware/passport.js +180 -179
- package/migrations/1757601159298-project_user_role_type.js +104 -0
- package/models/department.js +3 -0
- package/models/groupMemberSchama.js +19 -0
- package/models/kb_setting.js +74 -4
- package/models/permissionConstants.js +19 -0
- package/models/project_user.js +86 -8
- package/models/request.js +1 -0
- package/models/role.js +31 -0
- package/models/roleConstants.js +2 -0
- package/package.json +1 -1
- package/pubmodules/analytics/analytics.js +2 -2
- package/pubmodules/cache/mongoose-cachegoose-fn.js +37 -0
- package/pubmodules/canned/cannedResponseRoute.js +34 -6
- package/pubmodules/routing-queue/listener.js +7 -1
- package/pubmodules/trigger/rulesTrigger.js +1 -6
- package/routes/answered.js +227 -0
- package/routes/auth.js +3 -1
- package/routes/department.js +7 -1
- package/routes/message.js +4 -1
- package/routes/project.js +41 -3
- package/routes/project_user.js +62 -11
- package/routes/request.js +32 -30
- package/routes/roles.js +151 -0
- package/routes/unanswered.js +32 -19
- package/routes/widget.js +3 -1
- package/services/cacheEnabler.js +5 -8
- package/services/departmentService.js +39 -11
- package/services/emailService.js +2 -2
- package/services/pendingInvitationService.js +2 -0
- package/services/projectService.js +3 -1
- package/services/projectUserService.js +67 -4
- package/services/subscriptionNotifierQueued.js +8 -0
- package/services/updateRequestSnapshotQueued.js +0 -3
- package/test/departmentService.js +5 -0
- package/test/messageRoute.js +7 -4
- package/test/projectUserRoute.js +116 -0
- package/test/requestService.js +7 -3
- package/test-int/bot.js +3 -2
- package/websocket/webSocketServer.js +273 -225
- package/routes/auth_newjwt.js +0 -648
package/middleware/passport.js
CHANGED
|
@@ -81,13 +81,20 @@ winston.info('Authentication Oauth2 Signin enabled : ' + enableOauth2Signin);
|
|
|
81
81
|
|
|
82
82
|
var jwthistory = undefined;
|
|
83
83
|
try {
|
|
84
|
-
|
|
85
|
-
} catch
|
|
86
|
-
|
|
84
|
+
jwthistory = require('@tiledesk-ent/tiledesk-server-jwthistory');
|
|
85
|
+
} catch(err) {
|
|
86
|
+
winston.info("jwthistory not present", err);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
let JWT_HISTORY_ENABLED = false;
|
|
90
|
+
if (process.env.JWT_HISTORY_ENABLED==true || process.env.JWT_HISTORY_ENABLED=="true") {
|
|
91
|
+
JWT_HISTORY_ENABLED = true;
|
|
92
|
+
}
|
|
93
|
+
winston.debug("JWT_HISTORY_ENABLED: " + JWT_HISTORY_ENABLED);
|
|
94
|
+
|
|
95
|
+
|
|
90
96
|
|
|
97
|
+
module.exports = function(passport) {
|
|
91
98
|
// passport.serializeUser(function(user, done) {
|
|
92
99
|
// console.log("serializeUser");
|
|
93
100
|
|
|
@@ -231,218 +238,212 @@ module.exports = function (passport) {
|
|
|
231
238
|
done(null, configSecret); //pub_jwt pp_jwt
|
|
232
239
|
}
|
|
233
240
|
}
|
|
234
|
-
}
|
|
241
|
+
};
|
|
235
242
|
|
|
236
243
|
|
|
237
|
-
|
|
244
|
+
winston.debug("passport opts: ", opts);
|
|
238
245
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
246
|
+
passport.use(new JwtStrategy(opts, async(req, jwt_payload, done) => {
|
|
247
|
+
// passport.use(new JwtStrategy(opts, function(req, jwt_payload, done) {
|
|
248
|
+
winston.debug("jwt_payload",jwt_payload);
|
|
249
|
+
// console.log("req",req);
|
|
250
|
+
|
|
243
251
|
|
|
252
|
+
// console.log("jwt_payload._doc._id",jwt_payload._doc._id);
|
|
244
253
|
|
|
245
|
-
// console.log("jwt_payload._doc._id",jwt_payload._doc._id);
|
|
246
254
|
|
|
255
|
+
if (jwt_payload._id == undefined && (jwt_payload._doc == undefined || (jwt_payload._doc && jwt_payload._doc._id==undefined))) {
|
|
256
|
+
var err = "jwt_payload._id or jwt_payload._doc._id can t be undefined" ;
|
|
257
|
+
winston.error(err);
|
|
258
|
+
return done(null, false);
|
|
259
|
+
}
|
|
260
|
+
//JWT OLD format
|
|
261
|
+
const identifier = jwt_payload._id || jwt_payload._doc._id;
|
|
262
|
+
|
|
263
|
+
// const subject = jwt_payload.sub || jwt_payload._id || jwt_payload._doc._id;
|
|
264
|
+
winston.debug("passport identifier: " + identifier);
|
|
247
265
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
winston.error(err);
|
|
251
|
-
return done(null, false);
|
|
252
|
-
}
|
|
253
|
-
//JWT OLD format
|
|
254
|
-
const identifier = jwt_payload._id || jwt_payload._doc._id;
|
|
266
|
+
const subject = jwt_payload.sub;
|
|
267
|
+
winston.debug("passport subject: " + subject);
|
|
255
268
|
|
|
256
|
-
|
|
257
|
-
winston.debug("passport identifier: " + identifier);
|
|
269
|
+
winston.debug("passport identifier: " + identifier + " subject " + subject);
|
|
258
270
|
|
|
259
|
-
|
|
260
|
-
|
|
271
|
+
var fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
|
|
272
|
+
winston.debug("fullUrl:"+ fullUrl);
|
|
261
273
|
|
|
262
|
-
|
|
274
|
+
winston.debug("req.disablePassportEntityCheck:"+req.disablePassportEntityCheck);
|
|
263
275
|
|
|
264
|
-
|
|
265
|
-
|
|
276
|
+
if (req && req.disablePassportEntityCheck) { //req can be null
|
|
277
|
+
// jwt_payload.id = jwt_payload._id; //often req.user.id is used inside code. req.user.id is a mongoose getter of _id
|
|
278
|
+
// is better to rename req.user.id to req.user._id in all files
|
|
279
|
+
winston.debug("req.disablePassportEntityCheck enabled");
|
|
280
|
+
return done(null, jwt_payload);
|
|
281
|
+
}
|
|
282
|
+
winston.debug("jwthistory passport",jwthistory);
|
|
283
|
+
|
|
284
|
+
//TODO check into DB if JWT is revoked
|
|
285
|
+
if (jwthistory && JWT_HISTORY_ENABLED==true) {
|
|
286
|
+
var jwtRevoked = await jwthistory.isJWTRevoked(jwt_payload.jti);
|
|
287
|
+
winston.debug("passport jwt jwtRevoked: "+ jwtRevoked);
|
|
288
|
+
if (jwtRevoked) {
|
|
289
|
+
winston.warn("passport jwt is revoked with jti: "+ jwt_payload.jti);
|
|
290
|
+
return done(null, false);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
266
293
|
|
|
267
|
-
|
|
294
|
+
if (subject == "bot") {
|
|
295
|
+
winston.debug("Passport JWT bot");
|
|
268
296
|
|
|
269
|
-
|
|
270
|
-
// jwt_payload.id = jwt_payload._id; //often req.user.id is used inside code. req.user.id is a mongoose getter of _id
|
|
271
|
-
// is better to rename req.user.id to req.user._id in all files
|
|
272
|
-
winston.debug("req.disablePassportEntityCheck enabled");
|
|
273
|
-
return done(null, jwt_payload);
|
|
274
|
-
}
|
|
297
|
+
let qbot = Faq_kb.findOne({_id: identifier}); //TODO add cache_bot_here
|
|
275
298
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
299
|
+
if (cacheEnabler.faq_kb) {
|
|
300
|
+
let id_project = jwt_payload.id_project;
|
|
301
|
+
winston.debug("jwt_payload.id_project:"+jwt_payload.id_project);
|
|
302
|
+
qbot.cache(cacheUtil.defaultTTL, id_project+":faq_kbs:id:"+identifier)
|
|
303
|
+
winston.debug('faq_kb cache enabled');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
qbot.exec(function(err, faq_kb) {
|
|
307
|
+
|
|
308
|
+
if (err) {
|
|
309
|
+
winston.error("Passport JWT bot err", err);
|
|
310
|
+
return done(err, false);
|
|
311
|
+
}
|
|
312
|
+
if (faq_kb) {
|
|
313
|
+
winston.debug("Passport JWT bot user", faq_kb);
|
|
314
|
+
return done(null, faq_kb);
|
|
315
|
+
} else {
|
|
316
|
+
winston.warn("Passport JWT bot not user");
|
|
317
|
+
return done(null, false);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
// } else if (subject=="projects") {
|
|
321
|
+
|
|
322
|
+
} else if (subject=="subscription") {
|
|
323
|
+
|
|
324
|
+
Subscription.findOne({_id: identifier}, function(err, subscription) {
|
|
325
|
+
if (err) {
|
|
326
|
+
winston.error("Passport JWT subscription err", err);
|
|
327
|
+
return done(err, false);
|
|
328
|
+
}
|
|
329
|
+
if (subscription) {
|
|
330
|
+
winston.debug("Passport JWT subscription user", subscription);
|
|
331
|
+
return done(null, subscription);
|
|
332
|
+
} else {
|
|
333
|
+
winston.warn("Passport JWT subscription not user", subscription);
|
|
334
|
+
return done(null, false);
|
|
284
335
|
}
|
|
336
|
+
});
|
|
285
337
|
|
|
286
|
-
|
|
287
|
-
|
|
338
|
+
} else if (subject=="userexternal") {
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
if (jwt_payload) {
|
|
288
342
|
|
|
289
|
-
|
|
343
|
+
// const audUrl = new URL(jwt_payload.aud);
|
|
344
|
+
// winston.info("audUrl: "+ audUrl );
|
|
290
345
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
346
|
+
// const path = audUrl.pathname;
|
|
347
|
+
// winston.info("audUrl path: " + path );
|
|
348
|
+
|
|
349
|
+
// const AudienceType = path.split("/")[1];
|
|
350
|
+
// winston.info("audUrl AudienceType: " + AudienceType );
|
|
297
351
|
|
|
298
|
-
|
|
352
|
+
// const AudienceId = path.split("/")[2];
|
|
353
|
+
// winston.info("audUrl AudienceId: " + AudienceId );
|
|
299
354
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
return done(err, false);
|
|
303
|
-
}
|
|
304
|
-
if (faq_kb) {
|
|
305
|
-
winston.debug("Passport JWT bot user", faq_kb);
|
|
306
|
-
return done(null, faq_kb);
|
|
307
|
-
} else {
|
|
308
|
-
winston.warn("Passport JWT bot not user");
|
|
309
|
-
return done(null, false);
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
// } else if (subject=="projects") {
|
|
355
|
+
// jwt_payload._id = AudienceId + "-" + jwt_payload._id;
|
|
356
|
+
|
|
313
357
|
|
|
314
|
-
} else if (subject == "subscription") {
|
|
315
358
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
return done(err, false);
|
|
320
|
-
}
|
|
321
|
-
if (subscription) {
|
|
322
|
-
winston.debug("Passport JWT subscription user", subscription);
|
|
323
|
-
return done(null, subscription);
|
|
324
|
-
} else {
|
|
325
|
-
winston.warn("Passport JWT subscription not user", subscription);
|
|
326
|
-
return done(null, false);
|
|
327
|
-
}
|
|
328
|
-
});
|
|
359
|
+
winston.debug("Passport JWT userexternal", jwt_payload);
|
|
360
|
+
var userM = UserUtil.decorateUser(jwt_payload);
|
|
361
|
+
winston.debug("Passport JWT userexternal userM", userM);
|
|
329
362
|
|
|
330
|
-
|
|
363
|
+
return done(null, userM );
|
|
364
|
+
} else {
|
|
365
|
+
var err = {msg: "No jwt_payload passed. Its required"};
|
|
366
|
+
winston.error("Passport JWT userexternal err", err);
|
|
367
|
+
return done(err, false);
|
|
368
|
+
}
|
|
331
369
|
|
|
370
|
+
} else if (subject=="guest") {
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
if (jwt_payload) {
|
|
374
|
+
winston.debug("Passport JWT guest", jwt_payload);
|
|
375
|
+
var userM = UserUtil.decorateUser(jwt_payload);
|
|
376
|
+
winston.debug("Passport JWT guest userM", userM);
|
|
377
|
+
return done(null, userM );
|
|
378
|
+
} else {
|
|
379
|
+
var err = {msg: "No jwt_payload passed. Its required"};
|
|
380
|
+
winston.error("Passport JWT guest err", err);
|
|
381
|
+
return done(err, false);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
} else {
|
|
385
|
+
winston.debug("Passport JWT generic user");
|
|
386
|
+
let quser = User.findOne({_id: identifier, status: 100}) //TODO user_cache_here
|
|
387
|
+
//@DISABLED_CACHE .cache(cacheUtil.defaultTTL, "users:id:"+identifier)
|
|
388
|
+
|
|
389
|
+
if (cacheEnabler.user) {
|
|
390
|
+
quser.cache(cacheUtil.defaultTTL, "users:id:"+identifier)
|
|
391
|
+
winston.debug('user cache enabled');
|
|
392
|
+
}
|
|
332
393
|
|
|
333
|
-
|
|
394
|
+
quser.exec(function(err, user) {
|
|
395
|
+
if (err) {
|
|
396
|
+
winston.error("Passport JWT generic err ", err);
|
|
397
|
+
return done(err, false);
|
|
398
|
+
}
|
|
399
|
+
if (user) {
|
|
400
|
+
winston.debug("Passport JWT generic user ", user);
|
|
401
|
+
return done(null, user);
|
|
402
|
+
} else {
|
|
403
|
+
winston.debug("Passport JWT generic not user");
|
|
404
|
+
return done(null, false);
|
|
405
|
+
}
|
|
406
|
+
});
|
|
334
407
|
|
|
335
|
-
|
|
336
|
-
|
|
408
|
+
}
|
|
409
|
+
|
|
337
410
|
|
|
338
|
-
// const path = audUrl.pathname;
|
|
339
|
-
// winston.info("audUrl path: " + path );
|
|
340
411
|
|
|
341
|
-
|
|
342
|
-
// winston.info("audUrl AudienceType: " + AudienceType );
|
|
412
|
+
}));
|
|
343
413
|
|
|
344
|
-
// const AudienceId = path.split("/")[2];
|
|
345
|
-
// winston.info("audUrl AudienceId: " + AudienceId );
|
|
346
414
|
|
|
347
|
-
// jwt_payload._id = AudienceId + "-" + jwt_payload._id;
|
|
348
415
|
|
|
416
|
+
passport.use(new BasicStrategy(function(userid, password, done) {
|
|
417
|
+
|
|
418
|
+
winston.debug("BasicStrategy: " + userid);
|
|
419
|
+
|
|
349
420
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
winston.debug("Passport JWT userexternal userM", userM);
|
|
421
|
+
var email = userid.toLowerCase();
|
|
422
|
+
winston.debug("email lowercase: " + email);
|
|
353
423
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
424
|
+
User.findOne({ email: email, status: 100}, 'email firstname lastname password emailverified id') //TODO user_cache_here. NOT used frequently. ma attento select. ATTENTO QUI NN USEREI LA SELECT altrimenti con JWT ho tuttto USER mentre con basich auth solo aluni campi
|
|
425
|
+
//@DISABLED_CACHE .cache(cacheUtil.defaultTTL, "users:email:"+email)
|
|
426
|
+
.exec(function (err, user) {
|
|
427
|
+
|
|
428
|
+
if (err) {
|
|
429
|
+
// console.log("BasicStrategy err.stop");
|
|
430
|
+
return done(err);
|
|
431
|
+
}
|
|
432
|
+
if (!user) { return done(null, false); }
|
|
433
|
+
|
|
434
|
+
user.comparePassword(password, function (err, isMatch) {
|
|
435
|
+
if (isMatch && !err) {
|
|
362
436
|
|
|
437
|
+
// if user is found and password is right create a token
|
|
438
|
+
// console.log("BasicStrategy ok");
|
|
439
|
+
return done(null, user);
|
|
363
440
|
|
|
364
|
-
if (jwt_payload) {
|
|
365
|
-
winston.debug("Passport JWT guest", jwt_payload);
|
|
366
|
-
var userM = UserUtil.decorateUser(jwt_payload);
|
|
367
|
-
winston.debug("Passport JWT guest userM", userM);
|
|
368
|
-
return done(null, userM);
|
|
369
441
|
} else {
|
|
370
|
-
|
|
371
|
-
winston.error("Passport JWT guest err", err);
|
|
372
|
-
return done(err, false);
|
|
442
|
+
return done(err);
|
|
373
443
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
let quser = User.findOne({_id: identifier, status: 100}) //TODO user_cache_here
|
|
378
|
-
//@DISABLED_CACHE .cache(cacheUtil.defaultTTL, "users:id:"+identifier)
|
|
379
|
-
|
|
380
|
-
if (cacheEnabler.user) {
|
|
381
|
-
quser.cache(cacheUtil.defaultTTL, "users:id:" + identifier)
|
|
382
|
-
winston.debug('user cache enabled');
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
quser.exec(function (err, user) {
|
|
386
|
-
if (err) {
|
|
387
|
-
winston.error("Passport JWT generic err ", err);
|
|
388
|
-
return done(err, false);
|
|
389
|
-
}
|
|
390
|
-
if (user) {
|
|
391
|
-
winston.debug("Passport JWT generic user ", user);
|
|
392
|
-
return done(null, user);
|
|
393
|
-
} else {
|
|
394
|
-
winston.debug("Passport JWT generic not user");
|
|
395
|
-
return done(null, false);
|
|
396
|
-
}
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
}));
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
passport.use(new BasicStrategy(function (userid, password, done) {
|
|
406
|
-
|
|
407
|
-
winston.debug("BasicStrategy: " + userid);
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
var email = userid.toLowerCase();
|
|
411
|
-
winston.debug("email lowercase: " + email);
|
|
412
|
-
|
|
413
|
-
User.findOne({
|
|
414
|
-
email: email,
|
|
415
|
-
status: 100
|
|
416
|
-
}, 'email firstname lastname password emailverified id') //TODO user_cache_here. NOT used frequently. ma attento select. ATTENTO QUI NN USEREI LA SELECT altrimenti con JWT ho tuttto USER mentre con basich auth solo aluni campi
|
|
417
|
-
//@DISABLED_CACHE .cache(cacheUtil.defaultTTL, "users:email:"+email)
|
|
418
|
-
.exec(function (err, user) {
|
|
419
|
-
|
|
420
|
-
if (err) {
|
|
421
|
-
// console.log("BasicStrategy err.stop");
|
|
422
|
-
return done(err);
|
|
423
|
-
}
|
|
424
|
-
if (!user) {
|
|
425
|
-
return done(null, false);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
user.comparePassword(password, function (err, isMatch) {
|
|
429
|
-
if (isMatch && !err) {
|
|
430
|
-
|
|
431
|
-
// if user is found and password is right create a token
|
|
432
|
-
// console.log("BasicStrategy ok");
|
|
433
|
-
return done(null, user);
|
|
434
|
-
|
|
435
|
-
} else {
|
|
436
|
-
return done(err);
|
|
437
|
-
}
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
// if (user) { return done(null, user); }
|
|
442
|
-
// if (!user) { return done(null, false); }
|
|
443
|
-
// if (!user.verifyPassword(password)) { return done(null, false); }
|
|
444
|
-
});
|
|
445
|
-
}));
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
}));
|
|
446
447
|
|
|
447
448
|
|
|
448
449
|
if (enableGoogleSignin == true) {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
var Project_user = require("../models/project_user");
|
|
2
|
+
var winston = require('../config/winston');
|
|
3
|
+
|
|
4
|
+
const BATCH_SIZE = 100;
|
|
5
|
+
/** Log a progress line every this many bulkWrite rounds (plus always after the 1st). */
|
|
6
|
+
const PROGRESS_LOG_EVERY_BATCHES = 10;
|
|
7
|
+
|
|
8
|
+
/** Only documents that still need roleType (idempotent re-runs). */
|
|
9
|
+
const WITHOUT_ROLE_TYPE = {
|
|
10
|
+
$or: [{ roleType: { $exists: false } }, { roleType: null }]
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const AGENT_ROLES_FILTER = {
|
|
14
|
+
$and: [
|
|
15
|
+
{
|
|
16
|
+
$or: [
|
|
17
|
+
{ role: 'agent' },
|
|
18
|
+
{ role: 'supervisor' },
|
|
19
|
+
{ role: 'admin' },
|
|
20
|
+
{ role: 'owner' }
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
WITHOUT_ROLE_TYPE
|
|
24
|
+
]
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const USER_ROLES_FILTER = {
|
|
28
|
+
$and: [{ $or: [{ role: 'user' }, { role: 'guest' }] }, WITHOUT_ROLE_TYPE]
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
async function batchSetRoleType(filter, roleType, phaseLabel) {
|
|
32
|
+
const totalMatching = await Project_user.countDocuments(filter);
|
|
33
|
+
const started = Date.now();
|
|
34
|
+
winston.info(
|
|
35
|
+
`[project_user_role_type] ${phaseLabel}: ${totalMatching} documents match filter; streaming _id + bulkWrite in chunks of ${BATCH_SIZE}`
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
let modified = 0;
|
|
39
|
+
let scanned = 0;
|
|
40
|
+
let bulkRounds = 0;
|
|
41
|
+
const cursor = Project_user.find(filter).select('_id').lean().cursor();
|
|
42
|
+
let batch = [];
|
|
43
|
+
|
|
44
|
+
function logProgress(reason) {
|
|
45
|
+
const elapsedSec = ((Date.now() - started) / 1000).toFixed(1);
|
|
46
|
+
winston.info(
|
|
47
|
+
`[project_user_role_type] ${phaseLabel} ${reason}: scanned=${scanned}/${totalMatching}, modifiedThisPhase=${modified}, ${elapsedSec}s elapsed`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
for await (const doc of cursor) {
|
|
52
|
+
scanned++;
|
|
53
|
+
batch.push({
|
|
54
|
+
updateOne: {
|
|
55
|
+
filter: { _id: doc._id, ...WITHOUT_ROLE_TYPE },
|
|
56
|
+
update: { $set: { roleType } }
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
if (batch.length >= BATCH_SIZE) {
|
|
60
|
+
const result = await Project_user.bulkWrite(batch);
|
|
61
|
+
modified += result.modifiedCount;
|
|
62
|
+
batch = [];
|
|
63
|
+
bulkRounds++;
|
|
64
|
+
if (bulkRounds === 1 || bulkRounds % PROGRESS_LOG_EVERY_BATCHES === 0) {
|
|
65
|
+
logProgress(`progress (bulk round ${bulkRounds})`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (batch.length > 0) {
|
|
70
|
+
const result = await Project_user.bulkWrite(batch);
|
|
71
|
+
modified += result.modifiedCount;
|
|
72
|
+
bulkRounds++;
|
|
73
|
+
logProgress(`final partial batch (bulk round ${bulkRounds})`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
logProgress('phase complete');
|
|
77
|
+
return modified;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Make any changes you need to make to the database here
|
|
82
|
+
*/
|
|
83
|
+
async function up() {
|
|
84
|
+
try {
|
|
85
|
+
const agentsModified = await batchSetRoleType(AGENT_ROLES_FILTER, 1, 'agents roleType=1');
|
|
86
|
+
winston.info(`[project_user_role_type] Agents phase done: ${agentsModified} documents modified`);
|
|
87
|
+
|
|
88
|
+
const usersModified = await batchSetRoleType(USER_ROLES_FILTER, 2, 'users/guest roleType=2');
|
|
89
|
+
winston.info(`[project_user_role_type] Users/guest phase done: ${usersModified} documents modified`);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
winston.error('[project_user_role_type] Error applying migration:', err);
|
|
92
|
+
throw err;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Make any changes that UNDO the up function side effects here (if possible)
|
|
98
|
+
*/
|
|
99
|
+
async function down() {
|
|
100
|
+
// Write migration here
|
|
101
|
+
// console.log("down*********");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = { up, down };
|
package/models/department.js
CHANGED
|
@@ -3,6 +3,8 @@ var Schema = mongoose.Schema;
|
|
|
3
3
|
var routingConstants = require('../models/routingConstants');
|
|
4
4
|
var winston = require('../config/winston');
|
|
5
5
|
var TagSchema = require("../models/tag");
|
|
6
|
+
var GroupMemberSchema = require("../models/groupMemberSchama");
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
var DepartmentSchema = new Schema({
|
|
8
10
|
id_bot: {
|
|
@@ -34,6 +36,7 @@ var DepartmentSchema = new Schema({
|
|
|
34
36
|
id_group: {
|
|
35
37
|
type: String,
|
|
36
38
|
},
|
|
39
|
+
groups: [GroupMemberSchema],
|
|
37
40
|
// used??
|
|
38
41
|
online_msg: {
|
|
39
42
|
type: String,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
var mongoose = require('mongoose');
|
|
2
|
+
var Schema = mongoose.Schema;
|
|
3
|
+
var winston = require('../config/winston');
|
|
4
|
+
|
|
5
|
+
var GroupMemberSchema = new Schema({
|
|
6
|
+
|
|
7
|
+
group_id: {
|
|
8
|
+
type: String,
|
|
9
|
+
required: true
|
|
10
|
+
},
|
|
11
|
+
percentage: {
|
|
12
|
+
type: Number,
|
|
13
|
+
required: true,
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
module.exports = GroupMemberSchema;
|
package/models/kb_setting.js
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
let mongoose = require('mongoose');
|
|
2
2
|
let Schema = mongoose.Schema;
|
|
3
3
|
let winston = require('../config/winston');
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
const DEFAULT_UNANSWERED_TTL_SEC = 7 * 24 * 60 * 60; // 7 days
|
|
6
|
+
const DEFAULT_ANSWERED_TTL_SEC = 7 * 24 * 60 * 60; // 7 days
|
|
7
|
+
|
|
8
|
+
function ttlSecondsFromEnv(raw, fallbackSec) {
|
|
9
|
+
if (raw == null || String(raw).trim() === '') return fallbackSec;
|
|
10
|
+
const n = Number(raw);
|
|
11
|
+
return Number.isFinite(n) && n >= 0 ? n : fallbackSec;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let expireAfterSeconds = ttlSecondsFromEnv(
|
|
15
|
+
process.env.UNANSWERED_QUESTION_EXPIRATION_TIME,
|
|
16
|
+
DEFAULT_UNANSWERED_TTL_SEC
|
|
17
|
+
);
|
|
18
|
+
let expireAnsweredAfterSeconds = ttlSecondsFromEnv(
|
|
19
|
+
process.env.ANSWERED_QUESTION_EXPIRATION_TIME,
|
|
20
|
+
DEFAULT_ANSWERED_TTL_SEC
|
|
21
|
+
);
|
|
22
|
+
|
|
5
23
|
|
|
6
24
|
const EngineSchema = new Schema({
|
|
7
25
|
name: {
|
|
@@ -199,13 +217,63 @@ const UnansweredQuestionSchema = new Schema({
|
|
|
199
217
|
question: {
|
|
200
218
|
type: String,
|
|
201
219
|
required: true
|
|
220
|
+
},
|
|
221
|
+
request_id: {
|
|
222
|
+
type: String,
|
|
223
|
+
required: false,
|
|
224
|
+
},
|
|
225
|
+
sender: {
|
|
226
|
+
type: String,
|
|
227
|
+
required: false,
|
|
202
228
|
}
|
|
203
229
|
},{
|
|
204
230
|
timestamps: true
|
|
205
231
|
});
|
|
206
232
|
|
|
207
|
-
|
|
208
|
-
|
|
233
|
+
const AnsweredQuestionSchema = new Schema({
|
|
234
|
+
id_project: {
|
|
235
|
+
type: String,
|
|
236
|
+
required: true,
|
|
237
|
+
index: true
|
|
238
|
+
},
|
|
239
|
+
namespace: {
|
|
240
|
+
type: String,
|
|
241
|
+
required: true,
|
|
242
|
+
index: true
|
|
243
|
+
},
|
|
244
|
+
question: {
|
|
245
|
+
type: String,
|
|
246
|
+
required: true
|
|
247
|
+
},
|
|
248
|
+
answer: {
|
|
249
|
+
type: String,
|
|
250
|
+
required: true
|
|
251
|
+
},
|
|
252
|
+
tokens: {
|
|
253
|
+
type: Number,
|
|
254
|
+
required: false
|
|
255
|
+
},
|
|
256
|
+
request_id: {
|
|
257
|
+
type: String,
|
|
258
|
+
required: false
|
|
259
|
+
}
|
|
260
|
+
}, {
|
|
261
|
+
timestamps: true
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Add TTL index to automatically delete documents
|
|
265
|
+
UnansweredQuestionSchema.index({ createdAt: 1 }, { expireAfterSeconds: expireAfterSeconds });
|
|
266
|
+
UnansweredQuestionSchema.index({ id_project: 1, namespace: 1, createdAt: -1 });
|
|
267
|
+
UnansweredQuestionSchema.index({ question: "text" });
|
|
268
|
+
|
|
269
|
+
AnsweredQuestionSchema.index({ createdAt: 1 }, { expireAfterSeconds: expireAnsweredAfterSeconds });
|
|
270
|
+
AnsweredQuestionSchema.index({ id_project: 1, namespace: 1, createdAt: -1 });
|
|
271
|
+
AnsweredQuestionSchema.index(
|
|
272
|
+
{ question: "text", answer: "text" },
|
|
273
|
+
{ weights: { question: 3, answer: 1 } }
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
|
|
209
277
|
|
|
210
278
|
// DEPRECATED !! - Start
|
|
211
279
|
const KBSettingSchema = new Schema({
|
|
@@ -242,6 +310,7 @@ const Engine = mongoose.model('Engine', EngineSchema)
|
|
|
242
310
|
const Namespace = mongoose.model('Namespace', NamespaceSchema)
|
|
243
311
|
const KB = mongoose.model('KB', KBSchema)
|
|
244
312
|
const UnansweredQuestion = mongoose.model('UnansweredQuestion', UnansweredQuestionSchema)
|
|
313
|
+
const AnsweredQuestion = mongoose.model('AnsweredQuestion', AnsweredQuestionSchema)
|
|
245
314
|
|
|
246
315
|
|
|
247
316
|
module.exports = {
|
|
@@ -249,5 +318,6 @@ module.exports = {
|
|
|
249
318
|
Namespace: Namespace,
|
|
250
319
|
Engine: Engine,
|
|
251
320
|
KB: KB,
|
|
252
|
-
UnansweredQuestion: UnansweredQuestion
|
|
321
|
+
UnansweredQuestion: UnansweredQuestion,
|
|
322
|
+
AnsweredQuestion: AnsweredQuestion
|
|
253
323
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const OWNER_ROLE = [
|
|
2
|
+
];
|
|
3
|
+
|
|
4
|
+
const ADMIN_ROLE = [
|
|
5
|
+
"request_read_all"
|
|
6
|
+
];
|
|
7
|
+
const AGENT_ROLE= [
|
|
8
|
+
"request_read_group"
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
// console.log("ADMIN_ROLE", ADMIN_ROLE.concat(AGENT_ROLE));
|
|
12
|
+
module.exports = {
|
|
13
|
+
"agent": AGENT_ROLE,
|
|
14
|
+
"admin": ADMIN_ROLE.concat(AGENT_ROLE),
|
|
15
|
+
"owner": OWNER_ROLE.concat(ADMIN_ROLE).concat(AGENT_ROLE)
|
|
16
|
+
|
|
17
|
+
}
|
|
18
|
+
// const ADMIN_ROLE = Object.assign({}, ADMIN_ROLE, AGENT_ROLE)
|
|
19
|
+
// const ADMIN_ROLE = { ...ADMIN_ROLE, ...AGENT_ROLE }
|