@tiledesk/tiledesk-server
Version:
The Tiledesk server module
1,448 lines (1,097 loc) • 102 kB
JavaScript
'use strict';
var departmentService = require('../services/departmentService');
var Request = require("../models/request");
var Project_user = require("../models/project_user");
var Project = require("../models/project");
var messageService = require('../services/messageService');
const requestEvent = require('../event/requestEvent');
const leadEvent = require('../event/leadEvent');
var winston = require('../config/winston');
var RequestConstants = require("../models/requestConstants");
var requestUtil = require("../utils/requestUtil");
var cacheUtil = require("../utils/cacheUtil");
var arrayUtil = require("../utils/arrayUtil");
var cacheEnabler = require("../services/cacheEnabler");
var UIDGenerator = require("../utils/UIDGenerator");
const { TdCache } = require('../utils/TdCache');
const { QuoteManager } = require('./QuoteManager');
var configGlobal = require('../config/global');
const projectService = require('./projectService');
const axios = require("axios").default;
let port = process.env.PORT || '3000';
let TILEBOT_ENDPOINT = "http://localhost:" + port + "/modules/tilebot/ext/";;
if (process.env.TILEBOT_ENDPOINT) {
TILEBOT_ENDPOINT = process.env.TILEBOT_ENDPOINT + "/ext/"
}
let tdCache = new TdCache({
host: process.env.CACHE_REDIS_HOST,
port: process.env.CACHE_REDIS_PORT,
password: process.env.CACHE_REDIS_PASSWORD
});
tdCache.connect();
let qm = new QuoteManager({ tdCache: tdCache });
class RequestService {
constructor() {
this.listen();
}
listen() {
// 12 marzo 2024 I disabled these two functions due to performance problems for a chatbot created by Sponziello "Community bots Sendinblue Hubspot Qapla)"
// this.updateSnapshotLead();
// this.sendMessageUpdateLead();
}
// 12 marzo 2024 I disabled these two functions due to performance problems for a chatbot created by Sponziello "Community bots Sendinblue Hubspot Qapla)"
// updateSnapshotLead() {
// leadEvent.on('lead.update', function (lead) {
// setImmediate(() => {
// winston.debug("updateSnapshotLead on lead.update ", lead);
// Request.updateMany({ lead: lead._id, id_project: lead.id_project }, { "$set": { "snapshot.lead": lead } }, function (err, updates) {
// if (err) {
// winston.error("Error updating requests updateSnapshotLead", err);
// return 0;
// }
// winston.verbose("updateSnapshotLead updated for " + updates.nModified + " request")
// requestEvent.emit('request.update.snapshot.lead', { lead: lead, updates: updates });
// return;
// });
// // Request.find({lead: lead._id, id_project: lead.id_project}, function(err, requests) {
// // if (err) {
// // winston.error("Error getting request by lead", err);
// // return 0;
// // }
// // if (!requests || (requests && requests.length==0)) {
// // winston.warn("No request found for lead id " +lead._id );
// // return 0;
// // }
// // requests.forEach(function(request) {
// // });
// // });
// });
// });
// }
// 12 marzo 2024 I disabled these two functions due to performance problems for a chatbot created by Sponziello "Community bots Sendinblue Hubspot Qapla)"
// sendMessageUpdateLead() {
// leadEvent.on('lead.fullname.email.update', function (lead) {
// winston.debug("lead.fullname.email.update ");
// // leadEvent.on('lead.update', function(lead) {
// setImmediate(() => {
// winston.debug("sendMessageUpdateLead on lead.update ", lead);
// Request.find({ lead: lead._id, id_project: lead.id_project }, function (err, requests) {
// if (err) {
// winston.error("Error getting sendMessageUpdateLead request by lead", err);
// return 0;
// }
// if (!requests || (requests && requests.length == 0)) {
// winston.warn("sendMessageUpdateLead No request found for lead id " + lead._id);
// return 0;
// }
// // winston.info("sendMessageUpdateLead requests ", requests);
// requests.forEach(function (request) {
// winston.debug("sendMessageUpdateLead request ", request);
// // send(sender, senderFullname, recipient, text, id_project, createdBy, attributes, type, metadata, language)
// messageService.send(
// 'system',
// 'Bot',
// // lead.fullname,
// request.request_id,
// "Lead updated",
// request.id_project,
// 'system',
// {
// subtype: "info/support",
// "updateconversation": false,
// messagelabel: { key: "LEAD_UPDATED" },
// updateUserEmail: lead.email,
// updateUserFullname: lead.fullname
// },
// undefined,
// request.language
// );
// });
// });
// });
// });
// }
getAvailableAgentsCount(agents) {
var project_users_available = agents.filter(function (projectUser) {
if (projectUser.user_available == true) {
return true;
}
});
winston.debug('++ AVAILABLE PROJECT USERS count ', project_users_available)
if (project_users_available && project_users_available.length > 0) {
return project_users_available.length;
} else {
return 0;
}
}
//change create with this
routeInternal(request, departmentid, id_project, nobot) {
var that = this;
return new Promise(function (resolve, reject) {
var context = { request: request };
// getOperators(departmentid, projectid, nobot, disableWebHookCall, context)
return departmentService.getOperators(departmentid, id_project, nobot, undefined, context).then(function (result) {
// winston.debug("getOperators", result);
var assigned_at = undefined;
var status = RequestConstants.UNASSIGNED;
var assigned_operator_id;
var participants = [];
var participantsAgents = [];
var participantsBots = [];
var hasBot = false;
if (result.operators && result.operators.length > 0) {
assigned_operator_id = result.operators[0].id_user;
status = RequestConstants.ASSIGNED;
var assigned_operator_idString = assigned_operator_id.toString();
participants.push(assigned_operator_idString);
// botprefix
if (assigned_operator_idString.startsWith("bot_")) {
hasBot = true;
// botprefix
var assigned_operator_idStringBot = assigned_operator_idString.replace("bot_", "");
participantsBots.push(assigned_operator_idStringBot);
} else {
participantsAgents.push(assigned_operator_idString);
hasBot = false; //??
}
assigned_at = Date.now();
}
winston.debug("routeInternal assigned_operator_id: " + assigned_operator_id);
winston.debug("routeInternal status: " + status);
// cosi modifica la request originale forse devi fare il clone?????
request.status = status;
request.participants = participants;
request.participantsAgents = participantsAgents;
request.participantsBots = participantsBots;
request.hasBot = hasBot;
request.department = result.department._id;
// request.agents = result.agents;
request.assigned_at = assigned_at;
request.waiting_time = undefined //reset waiting_time on reroute
if (!request.snapshot) { //if used other methods than .create
request.snapshot = {}
}
request.snapshot.department = result.department;
request.snapshot.agents = result.agents;
request.snapshot.availableAgentsCount = that.getAvailableAgentsCount(result.agents);
return resolve(request);
}).catch(function (err) {
return reject(err);
});
});
}
// TODO changePreflightByRequestId se un agente entra in request freflight true disabilitare add agente e reassing ma mettere un bottone removePreflight???
// usalo no_populate
route(request_id, departmentid, id_project, nobot, no_populate) {
var that = this;
return new Promise(function (resolve, reject) {
winston.debug("request_id:" + request_id);
winston.debug("departmentid:" + departmentid);
winston.debug("id_project:" + id_project);
winston.debug("nobot:" + nobot);
let q = Request
.findOne({ request_id: request_id, id_project: id_project });
// if (cacheEnabler.request) { //(node:60837) UnhandledPromiseRejectionWarning: VersionError: No matching document found for id "633efe246a6cc0eda5732684" version 0 modifiedPaths "status, participants, participantsAgents, department, assigned_at, snapshot, snapshot.department, snapshot.department.updatedAt, snapshot.agents"
// q.cache(cacheUtil.defaultTTL, id_project+":requests:request_id:"+request_id+":simple") //request_cache
// winston.debug('request cache enabled');
// }
return q.exec(function (err, request) {
if (err) {
winston.error(err);
return reject(err);
}
winston.debug('request return', request);
// cambia var in let
//it is important to clone here
var requestBeforeRoute = Object.assign({}, request.toObject());
winston.debug("requestBeforeRoute", requestBeforeRoute);
var beforeParticipants = requestBeforeRoute.participants;
winston.debug("beforeParticipants: ", beforeParticipants);
return that.routeInternal(request, departmentid, id_project, nobot).then( async function (routedRequest) {
winston.debug("after routeInternal", routedRequest);
winston.debug("requestBeforeRoute.status:" + requestBeforeRoute.status);
winston.debug("routedRequest.status:" + routedRequest.status);
let beforeDepartmentId;
if (requestBeforeRoute.department) { //requestBeforeRoute.department can be empty for internal ticket
beforeDepartmentId = requestBeforeRoute.department.toString();
winston.debug("beforeDepartmentId:" + beforeDepartmentId);
}
let afterDepartmentId;
if (routedRequest.department) {
afterDepartmentId = routedRequest.department.toString();
winston.debug("afterDepartmentId:" + afterDepartmentId);
}
winston.debug("requestBefore status: ", requestBeforeRoute.status)
winston.debug("routedRequest status: ", routedRequest.status)
/**
* Case 1
* After internal routing:
* - same STATUS
* - same DEPARTMENT
* - same PARTICIPANTS
*/
if (requestBeforeRoute.status === routedRequest.status &&
beforeDepartmentId === afterDepartmentId &&
requestUtil.arraysEqual(beforeParticipants, routedRequest.participants)) {
winston.verbose("Request " + request.request_id + " contains already the same participants at the same request status. Routed to the same participants");
if (routedRequest.attributes && routedRequest.attributes.fully_abandoned && routedRequest.attributes.fully_abandoned === true) {
request.status = RequestConstants.ABANDONED;
request.attributes.fully_abandoned = true;
request.markModified('status');
request.markModified('attributes');
request.save((err, savedRequest) => {
if (err) {
winston.error("Error updating request with status ABANDONED ", err);
} else {
winston.verbose("Status modified in ABANDONED for request: " + savedRequest._id);
}
})
}
if (no_populate === "true" || no_populate === true) {
winston.debug("no_populate is true");
return resolve(request);
}
return request
.populate('lead')
.populate('department')
.populate('participatingBots')
.populate('participatingAgents')
.populate({ path: 'requester', populate: { path: 'id_user' } })
.execPopulate(function (err, requestComplete) {
winston.debug("requestComplete", requestComplete);
return resolve(requestComplete);
});
}
let project = await projectService.getCachedProject(id_project).catch((err) => {
winston.warn("Error getting cached project. Skip conversation quota check.")
winston.warn("Getting cached project error: ", err)
})
let isTestConversation = false;
let isVoiceConversation = false;
let isStandardConversation = false;
let payload = {
project: project,
request: request
}
if (request.attributes && request.attributes.sourcePage && (request.attributes.sourcePage.indexOf("td_draft=true") > -1)) {
winston.verbose("is a test conversation --> skip quote availability check")
isTestConversation = true;
}
else if (request.channel && (request.channel.name === 'voice-vxml')) {
winston.verbose("is a voice conversation --> skip quote availability check")
isVoiceConversation = true;
}
else {
isStandardConversation = true;
let available = await qm.checkQuote(project, request, 'requests');
if (available === false) {
winston.info("Requests limits reached for project " + project._id)
return reject("Requests limits reached for project " + project._id);
}
}
/**
* Case 2 - Leaving TEMP status
* After internal routing:
* - STATUS changed from 50 to 100 or 200
*/
if (requestBeforeRoute.status === RequestConstants.TEMP && (routedRequest.status === RequestConstants.ASSIGNED || routedRequest.status === RequestConstants.UNASSIGNED)) {
// console.log("Case 2 - Leaving TEMP status")
if (isStandardConversation) {
requestEvent.emit('request.create.quote', payload);
}
}
/**
* Case 3 - Conversation opened through proactive message
* After internal routing:
* - STATUS changed from undefined to 100
*/
if ((!requestBeforeRoute.status || requestBeforeRoute.status === undefined) && routedRequest.status === RequestConstants.ASSIGNED) {
// console.log("Case 3 - 'Proactive' request")
if (isStandardConversation) {
requestEvent.emit('request.create.quote', payload);
}
}
//cacheinvalidation
return routedRequest.save(function (err, savedRequest) {
// https://stackoverflow.com/questions/54792749/mongoose-versionerror-no-matching-document-found-for-id-when-document-is-being
//return routedRequest.update(function(err, savedRequest) {
if (err) {
winston.error('Error saving the request. ', { err: err, routedRequest: routedRequest });
return reject(err);
}
winston.debug("after save savedRequest", savedRequest);
return savedRequest
.populate('lead')
.populate('department')
.populate('participatingBots')
.populate('participatingAgents')
.populate({ path: 'requester', populate: { path: 'id_user' } })
.execPopulate(function (err, requestComplete) {
// return Request //to populate correctly i must re-exec the query
// .findById(savedRequest.id)
// .populate('lead')
// .populate('department')
// .populate('participatingBots')
// .populate('participatingAgents')
// .populate({path:'requester',populate:{path:'id_user'}})
// .exec( function(err, requestComplete) {
if (err) {
winston.error('Error populating the request.', err);
return reject(err);
}
winston.verbose("Request routed", requestComplete.toObject());
var oldParticipants = beforeParticipants;
winston.debug("oldParticipants ", oldParticipants);
let newParticipants = requestComplete.participants;
winston.debug("newParticipants ", newParticipants);
var removedParticipants = oldParticipants.filter(d => !newParticipants.includes(d));
winston.debug("removedParticipants ", removedParticipants);
var addedParticipants = newParticipants.filter(d => !oldParticipants.includes(d));
winston.debug("addedParticipants ", addedParticipants);
requestEvent.emit('request.update', requestComplete);
requestEvent.emit("request.update.comment", { comment: "REROUTE", request: requestComplete });//Deprecated
requestEvent.emit("request.updated", { comment: "REROUTE", request: requestComplete, patch: { removedParticipants: removedParticipants, addedParticipants: addedParticipants } });
requestEvent.emit('request.participants.update', {
beforeRequest: request,
removedParticipants: removedParticipants,
addedParticipants: addedParticipants,
request: requestComplete
});
requestEvent.emit('request.department.update', requestComplete); //se req ha bot manda messaggio \welcome
winston.debug("here end");
return resolve(requestComplete);
});
});
}).catch(function (err) {
return reject(err);
});
});
});
}
reroute(request_id, id_project, nobot) {
var that = this;
var startDate = new Date();
return new Promise(function (resolve, reject) {
// winston.debug("request_id", request_id);
// winston.debug("newstatus", newstatus);
let q = Request
.findOne({ request_id: request_id, id_project: id_project });
if (cacheEnabler.request) {
q.cache(cacheUtil.defaultTTL, id_project + ":requests:request_id:" + request_id + ":simple") //request_cache
winston.debug('request cache enabled');
}
return q.exec(function (err, request) {
if (err) {
winston.error(err);
return reject(err);
}
winston.debug('request cache simple 3', request);
winston.debug("here reroute1 ");
// Cannot read property 'toString' of undefined at /usr/src/app/services/requestService.js:404:61 at /usr/src/app/node_modules/cachegoose/out/extend-query.js:44:13 at Command.cb [as callback] (/usr/src/app/node_modules/cacheman-redis/node/index.js:142:9) at normal_reply (/usr/src/app/node_modules/redis/index.js:655:21) at RedisClient.return_reply (/usr/src/app/node_modules/redis/index.js:753:9) at JavascriptRedisParser.returnReply (/usr/src/app/node_modules/redis/index.js:138:18) at JavascriptRedisParser.execute (/usr/src/app/node_modules/redis-parser/lib/parser.js:544:14) at Socket.<anonymous> (/usr/src/app/node_modules/redis/index.js:219:27) at Socket.emit (events.js:314:20) at addChunk (_stream_readable.js:297:12) at readableAddChunk (_stream_readable.js:272:9) at Socket.Readable.push (_stream_readable.js:213:10) at TCP.onStreamRead (internal/stream_base_commons.js:188:23) {"date":"Tue Mar 21 2023 18:45:47 GMT+0000 (Coordinated Unive
if (request.department === undefined) {
winston.error("Request with request_id " + request_id + " has empty department. So I can't reroute");
return reject("Request with request_id " + request_id + " has empty department. So I can't reroute");
}
return that.route(request_id, request.department.toString(), id_project, nobot).then(function (routedRequest) {
var endDate = new Date();
winston.verbose("Performance Request reroute in millis: " + endDate - startDate);
return resolve(routedRequest);
}).catch(function (err) {
return reject(err);
});
});
});
}
createWithRequester(project_user_id, lead_id, id_project, first_text, departmentid, sourcePage, language, userAgent, status, createdBy, attributes, subject, preflight) {
var request_id = 'support-group-' + id_project + "-" + UIDGenerator.generate();
winston.debug("request_id: " + request_id);
return this.createWithIdAndRequester(request_id, project_user_id, lead_id, id_project, first_text, departmentid, sourcePage, language, userAgent, status, createdBy, attributes, subject, preflight);
}
createWithIdAndRequester(request_id, project_user_id, lead_id, id_project, first_text, departmentid, sourcePage, language, userAgent, status, createdBy, attributes, subject, preflight, channel, location) {
var request = {
request_id: request_id, project_user_id: project_user_id, lead_id: lead_id, id_project: id_project, first_text: first_text,
departmentid: departmentid, sourcePage: sourcePage, language: language, userAgent: userAgent, status: status, createdBy: createdBy,
attributes: attributes, subject: subject, preflight: preflight, channel: channel, location: location
};
return this.create(request);
};
async create(request) {
if (!request.createdAt) {
request.createdAt = new Date();
}
var request_id = request.request_id;
var project_user_id = request.project_user_id;
var lead_id = request.lead_id;
var id_project = request.id_project;
var first_text = request.first_text;
var departmentid = request.departmentid;
var sourcePage = request.sourcePage;
var language = request.language;
var userAgent = request.userAgent;
var status = request.status;
var createdBy = request.createdBy;
var attributes = request.attributes;
var subject = request.subject;
var preflight = request.preflight;
var channel = request.channel;
var location = request.location;
var participants = request.participants || [];
var tags = request.tags;
var notes = request.notes;
var priority = request.priority;
var auto_close = request.auto_close;
var followers = request.followers;
let createdAt = request.createdAt;
if (!departmentid) {
departmentid = 'default';
}
if (!createdBy) {
if (project_user_id) {
createdBy = project_user_id;
} else {
createdBy = "system";
}
}
// Utils
let payload;
let isTestConversation = false;
let isVoiceConversation = false;
let isStandardConversation = false;
var that = this;
return new Promise( async (resolve, reject) => {
var context = {
request: {
request_id: request_id, project_user_id: project_user_id, lead_id: lead_id, id_project: id_project,
first_text: first_text, departmentid: departmentid, sourcePage: sourcePage, language: language, userAgent: userAgent, status: status,
createdBy: createdBy, attributes: attributes, subject: subject, preflight: preflight, channel: channel, location: location,
participants: participants, tags: tags, notes: notes,
priority: priority, auto_close: auto_close, followers: followers
}
};
winston.debug("context", context);
var participantsAgents = [];
var participantsBots = [];
var hasBot = false;
var dep_id = undefined;
var assigned_at = undefined;
var agents = [];
var snapshot = {};
try {
// (method) DepartmentService.getOperators(departmentid: any, projectid: any, nobot: any, disableWebHookCall: any, context: any): Promise<any>
var result = await departmentService.getOperators(departmentid, id_project, false, undefined, context);
winston.debug("getOperators", result);
} catch (err) {
return reject(err);
}
agents = result.agents;
if (status == 50) {
// skip assignment
if (participants.length == 0) {
dep_id = result.department._id;
}
} else {
let project = await projectService.getCachedProject(id_project).catch((err) => {
winston.warn("Error getting cached project. Skip conversation quota check.")
winston.warn("Getting cached project error: ", err)
})
payload = {
project: project,
request: request
}
if (attributes && attributes.sourcePage && (attributes.sourcePage.indexOf("td_draft=true") > -1)) {
winston.verbose("is a test conversation --> skip quote availability check")
isTestConversation = true;
}
else if (channel && (channel.name === 'voice-vxml')) {
isVoiceConversation = true;
let available = await qm.checkQuote(project, request, 'voice_duration');
if (available === false) {
winston.info("Voice duration limits reached for project " + project._id);
return reject("Voice duration limits reached for project " + project._id);
}
}
else {
isStandardConversation = true;
let available = await qm.checkQuote(project, request, 'requests');
if (available === false) {
winston.info("Requests limits reached for project " + project._id)
return reject("Requests limits reached for project " + project._id);
}
}
if (participants.length == 0) {
if (result.operators && result.operators.length > 0) {
participants.push(result.operators[0].id_user.toString());
}
// for preflight it is important to save agents in req for trigger. try to optimize it
dep_id = result.department._id;
}
if (participants.length > 0) {
status = RequestConstants.ASSIGNED;
// botprefix
if (participants[0].startsWith("bot_")) {
hasBot = true;
winston.debug("hasBot:" + hasBot);
// botprefix
var assigned_operator_idStringBot = participants[0].replace("bot_", "");
winston.debug("assigned_operator_idStringBot:" + assigned_operator_idStringBot);
participantsBots.push(assigned_operator_idStringBot);
} else {
participantsAgents.push(participants[0]);
}
assigned_at = Date.now();
} else {
status = RequestConstants.UNASSIGNED;
}
}
if (dep_id) {
snapshot.department = result.department;
}
snapshot.agents = agents;
snapshot.availableAgentsCount = that.getAvailableAgentsCount(agents);
if (request.requester) {
snapshot.requester = request.requester;
}
if (request.lead) {
snapshot.lead = request.lead;
}
var newRequest = new Request({
request_id: request_id,
requester: project_user_id,
lead: lead_id,
first_text: first_text,
subject: subject,
status: status,
participants: participants,
participantsAgents: participantsAgents,
participantsBots: participantsBots,
hasBot: hasBot,
department: dep_id,
// agents: agents,
//others
sourcePage: sourcePage,
language: language,
userAgent: userAgent,
assigned_at: assigned_at,
attributes: attributes,
//standard
id_project: id_project,
createdBy: createdBy,
updatedBy: createdBy,
preflight: preflight,
channel: channel,
location: location,
snapshot: snapshot,
tags: tags,
notes: notes,
priority: priority,
auto_close: auto_close,
followers: followers,
createdAt: createdAt
});
if (isTestConversation) {
newRequest.draft = true;
}
winston.debug('newRequest.', newRequest);
//cacheinvalidation
return newRequest.save( async function (err, savedRequest) {
if (err) {
winston.error('RequestService error for method createWithIdAndRequester for newRequest' + JSON.stringify(newRequest), err);
return reject(err);
}
winston.debug("Request created", savedRequest.toObject());
requestEvent.emit('request.create.simple', savedRequest);
if (isStandardConversation) {
requestEvent.emit('request.create.quote', payload);;
}
return resolve(savedRequest);
});
})
}
// DEPRECATED
// async _create(request) {
// var startDate = new Date();
// if (!request.createdAt) {
// request.createdAt = new Date();
// }
// var request_id = request.request_id;
// var project_user_id = request.project_user_id;
// var lead_id = request.lead_id;
// var id_project = request.id_project;
// var first_text = request.first_text;
// //removed for ticket
// // // lascia che sia nico a fare il replace...certo tu devi fare il test che tutto sia ok quindi dopo demo
// // var first_text;
// // if (request.first_text) { //first_text can be empty for type image
// // first_text = request.first_text.replace(/[\n\r]+/g, ' '); //replace new line with space
// // }
// var departmentid = request.departmentid;
// var sourcePage = request.sourcePage;
// var language = request.language;
// var userAgent = request.userAgent;
// var status = request.status;
// var createdBy = request.createdBy;
// var attributes = request.attributes;
// var subject = request.subject;
// var preflight = request.preflight;
// var channel = request.channel;
// var location = request.location;
// var participants = request.participants || [];
// var tags = request.tags;
// var notes = request.notes;
// var priority = request.priority;
// var auto_close = request.auto_close;
// var followers = request.followers;
// let createdAt = request.createdAt;
// if (!departmentid) {
// departmentid = 'default';
// }
// if (!createdBy) {
// if (project_user_id) {
// createdBy = project_user_id;
// } else {
// createdBy = "system";
// }
// }
// let isTestConversation = false;
// let isVoiceConversation = false;
// var that = this;
// return new Promise(async (resolve, reject) => {
// let q = Project.findOne({ _id: request.id_project, status: 100 });
// if (cacheEnabler.project) {
// q.cache(cacheUtil.longTTL, "projects:id:" + request.id_project) //project_cache
// winston.debug('project cache enabled for /project detail');
// }
// q.exec(async function (err, p) {
// if (err) {
// winston.error('Error getting project ', err);
// }
// if (!p) {
// winston.warn('Project not found ');
// }
// let payload = {
// project: p,
// request: request
// }
// if (attributes && attributes.sourcePage && (attributes.sourcePage.indexOf("td_draft=true") > -1)) {
// winston.verbose("is a test conversation --> skip quote availability check")
// isTestConversation = true;
// }
// else if (channel && (channel.name === 'voice-vxml')) {
// winston.verbose("is a voice conversation --> skip quote availability check")
// isVoiceConversation = true;
// }
// else {
// // console.log("! check quota moved")
// // let available = await qm.checkQuote(p, request, 'requests');
// // if (available === false) {
// // winston.info("Requests limits reached for project " + p._id)
// // return false;
// // }
// }
// var context = {
// request: {
// request_id: request_id, project_user_id: project_user_id, lead_id: lead_id, id_project: id_project,
// first_text: first_text, departmentid: departmentid, sourcePage: sourcePage, language: language, userAgent: userAgent, status: status,
// createdBy: createdBy, attributes: attributes, subject: subject, preflight: preflight, channel: channel, location: location,
// participants: participants, tags: tags, notes: notes,
// priority: priority, auto_close: auto_close, followers: followers
// }
// };
// winston.debug("context", context);
// var participantsAgents = [];
// var participantsBots = [];
// var hasBot = false;
// var dep_id = undefined;
// var assigned_at = undefined;
// var agents = [];
// var snapshot = {};
// try {
// // getOperators(departmentid, projectid, nobot, disableWebHookCall, context) {
// var result = await departmentService.getOperators(departmentid, id_project, false, undefined, context);
// // console.log("************* after get operator: "+new Date().toISOString());
// winston.debug("getOperators", result);
// } catch (err) {
// return reject(err);
// }
// agents = result.agents;
// if (status == 50) {
// // skip assignment
// if (participants.length == 0) {
// dep_id = result.department._id;
// }
// } else {
// if (participants.length == 0) {
// if (result.operators && result.operators.length > 0) {
// participants.push(result.operators[0].id_user.toString());
// }
// // for preflight it is important to save agents in req for trigger. try to optimize it
// dep_id = result.department._id;
// }
// if (participants.length > 0) {
// status = RequestConstants.ASSIGNED;
// /**
// * QUOTAS - START!!!
// */
// if (!isTestConversation && !isVoiceConversation) {
// requestEvent.emit('request.create.quote', payload);
// }
// /**
// * QUOTAS - END!!!
// */
// // botprefix
// if (participants[0].startsWith("bot_")) {
// hasBot = true;
// winston.debug("hasBot:" + hasBot);
// // botprefix
// var assigned_operator_idStringBot = participants[0].replace("bot_", "");
// winston.debug("assigned_operator_idStringBot:" + assigned_operator_idStringBot);
// participantsBots.push(assigned_operator_idStringBot);
// } else {
// participantsAgents.push(participants[0]);
// }
// assigned_at = Date.now();
// } else {
// status = RequestConstants.UNASSIGNED;
// }
// }
// if (dep_id) {
// snapshot.department = result.department;
// }
// // console.log("result.agents",result.agents);
// snapshot.agents = agents;
// snapshot.availableAgentsCount = that.getAvailableAgentsCount(agents);
// if (request.requester) { //.toObject()????
// snapshot.requester = request.requester;
// }
// if (request.lead) {
// snapshot.lead = request.lead;
// }
// // winston.debug("assigned_operator_id", assigned_operator_id);
// // winston.debug("req status", status);
// var newRequest = new Request({
// request_id: request_id,
// requester: project_user_id,
// lead: lead_id,
// first_text: first_text,
// subject: subject,
// status: status,
// participants: participants,
// participantsAgents: participantsAgents,
// participantsBots: participantsBots,
// hasBot: hasBot,
// department: dep_id,
// // agents: agents,
// //others
// sourcePage: sourcePage,
// language: language,
// userAgent: userAgent,
// assigned_at: assigned_at,
// attributes: attributes,
// //standard
// id_project: id_project,
// createdBy: createdBy,
// updatedBy: createdBy,
// preflight: preflight,
// channel: channel,
// location: location,
// snapshot: snapshot,
// tags: tags,
// notes: notes,
// priority: priority,
// auto_close: auto_close,
// followers: followers,
// createdAt: createdAt
// });
// if (isTestConversation) {
// newRequest.draft = true;
// }
// winston.debug('newRequest.', newRequest);
// //cacheinvalidation
// return newRequest.save( async function (err, savedRequest) {
// if (err) {
// winston.error('RequestService error for method createWithIdAndRequester for newRequest' + JSON.stringify(newRequest), err);
// return reject(err);
// }
// winston.debug("Request created", savedRequest.toObject());
// var endDate = new Date();
// winston.verbose("Performance Request created in millis: " + endDate - startDate);
// requestEvent.emit('request.create.simple', savedRequest);
// if (!isTestConversation && !isVoiceConversation) {
// // requestEvent.emit('request.create.quote', payload);;
// }
// return resolve(savedRequest);
// });
// // }).catch(function(err){
// // return reject(err);
// // });
// })
// });
// }
// DEPRECATED
// async __create(request) {
// var startDate = new Date();
// if (!request.createdAt) {
// request.createdAt = new Date();
// }
// var request_id = request.request_id;
// var project_user_id = request.project_user_id;
// var lead_id = request.lead_id;
// var id_project = request.id_project;
// var first_text = request.first_text;
// //removed for ticket
// // // lascia che sia nico a fare il replace...certo tu devi fare il test che tutto sia ok quindi dopo demo
// // var first_text;
// // if (request.first_text) { //first_text can be empty for type image
// // first_text = request.first_text.replace(/[\n\r]+/g, ' '); //replace new line with space
// // }
// var departmentid = request.departmentid;
// var sourcePage = request.sourcePage;
// var language = request.language;
// var userAgent = request.userAgent;
// var status = request.status;
// var createdBy = request.createdBy;
// var attributes = request.attributes;
// var subject = request.subject;
// var preflight = request.preflight;
// var channel = request.channel;
// var location = request.location;
// var participants = request.participants || [];
// var tags = request.tags;
// var notes = request.notes;
// var priority = request.priority;
// var auto_close = request.auto_close;
// var followers = request.followers;
// let createdAt = request.createdAt;
// if (!departmentid) {
// departmentid = 'default';
// }
// if (!createdBy) {
// if (project_user_id) {
// createdBy = project_user_id;
// } else {
// createdBy = "system";
// }
// }
// var that = this;
// return new Promise(async (resolve, reject) => {
// var context = {
// request: {
// request_id: request_id, project_user_id: project_user_id, lead_id: lead_id, id_project: id_project,
// first_text: first_text, departmentid: departmentid, sourcePage: sourcePage, language: language, userAgent: userAgent, status: status,
// createdBy: createdBy, attributes: attributes, subject: subject, preflight: preflight, channel: channel, location: location,
// participants: participants, tags: tags, notes: notes,
// priority: priority, auto_close: auto_close, followers: followers
// }
// };
// winston.debug("context", context);
// var participantsAgents = [];
// var participantsBots = [];
// var hasBot = false;
// var dep_id = undefined;
// var assigned_at = undefined;
// var agents = [];
// var snapshot = {};
// try {
// // getOperators(departmentid, projectid, nobot, disableWebHookCall, context) {
// var result = await departmentService.getOperators(departmentid, id_project, false, undefined, context);
// // console.log("************* after get operator: "+new Date().toISOString());
// winston.debug("getOperators", result);
// } catch (err) {
// return reject(err);
// }
// agents = result.agents;
// if (status == 50) {
// // skip assignment
// if (participants.length == 0) {
// dep_id = result.department._id;
// }
// } else {
// if (participants.length == 0) {
// if (result.operators && result.operators.length > 0) {
// participants.push(result.operators[0].id_user.toString());
// }
// // for preflight it is important to save agents in req for trigger. try to optimize it
// dep_id = result.department._id;
// }
// if (participants.length > 0) {
// status = RequestConstants.ASSIGNED;
// // botprefix
// if (participants[0].startsWith("bot_")) {
// hasBot = true;
// winston.debug("hasBot:" + hasBot);
// // botprefix
// var assigned_operator_idStringBot = participants[0].replace("bot_", "");
// winston.debug("assigned_operator_idStringBot:" + assigned_operator_idStringBot);
// participantsBots.push(assigned_operator_idStringBot);
// } else {
// participantsAgents.push(participants[0]);
// }
// assigned_at = Date.now();
// } else {
// status = RequestConstants.UNASSIGNED;
// }
// }
// if (dep_id) {
// snapshot.department = result.department;
// }
// // console.log("result.agents",result.agents);
// snapshot.agents = agents;
// snapshot.availableAgentsCount = that.getAvailableAgentsCount(agents);
// if (request.requester) { //.toObject()????
// snapshot.requester = request.requester;
// }
// if (request.lead) {
// snapshot.lead = request.lead;
// }
// // winston.debug("assigned_operator_id", assigned_operator_id);
// // winston.debug("req status", status);
// var newRequest = new Request({
// request_id: request_id,
// requester: project_user_id,
// lead: lead_id,
// first_text: first_text,
// subject: subject,
// status: status,
// participants: participants,
// participantsAgents: participantsAgents,
// participantsBots: participantsBots,
// hasBot: hasBot,
// department: dep_id,
// // agents: agents,
// //others
// sourcePage: sourcePage,
// language: language,
// userAgent: userAgent,
// assigned_at: assigned_at,
// attributes: attributes,
// //standard
// id_project: id_project,
// createdBy: createdBy,
// updatedBy: createdBy,
// preflight: preflight,
// channel: channel,
// location: location,
// snapshot: snapshot,
// tags: tags,
// notes: notes,
// priority: priority,
// auto_close: auto_close,
// followers: followers,
// createdAt: createdAt
// });
// winston.debug('newRequest.', newRequest);
// //cacheinvalidation
// return newRequest.save(function (err, savedRequest) {
// if (err) {
// winston.error('RequestService error for method createWithIdAndRequester for newRequest' + JSON.stringify(newRequest), err);
// return reject(err);
// }
// winston.debug("Request created", savedRequest.toObject());
// var endDate = new Date();
// winston.verbose("Performance Request created in millis: " + endDate - startDate);
// requestEvent.emit('request.create.simple', savedRequest);
// let q = Project.findOne({ _id: request.id_project, status: 100 });
// if (cacheEnabler.project) {
// q.cache(cacheUtil.longTTL, "projects:id:" + request.id_project) //project_cache
// winston.debug('project cache enabled for /project detail');
// }
// q.exec(async function (err, p) {
// if (err) {
// winston.error('Error getting project ', err);
// }
// if (!p) {
// winston.warn('Project not found ');
// }
// //TODO REMOVE settings from project
// let payload = {
// project: p,
// request: request
// }
// requestEvent.emit('request.create.quote', payload);;
// });
// return resolve(savedRequest);
// });
// // }).catch(function(err){
// // return reject(err);
// // });
// });
// }
//DEPRECATED. USED ONLY IN SAME TESTS
createWithId(request_id, requester_id, id_project, first_text, departmentid, sourcePage, language, userAgent, status, createdBy, attributes) {
// winston.debug("request_id", request_id);
if (!departmentid) {
departmentid = 'default';
}
if (!createdBy) {
createdBy = requester_id;
}
var that = this;
return new Promise(function (resolve, reject) {
var context = {
request: {
request_id: request_id, requester_id: requester_id, id_project: id_project,
first_text: first_text, departmentid: departmentid, sourcePage: sourcePage, language: language, userAgent: userAgent, status: status,
createdBy: createdBy, attributes: attributes
}
};
// getOperators(departmentid, projectid, nobot, disableWebHookCall, context)
return departmentService.getOperators(departmentid, id_project, false, undefined, context).then(function (result) {
// winston.debug("getOperators", result);
var status = RequestConstants.UNASSIGNED;
var assigned_operator_id;
var participants = [];
var participantsAgents = [];
var participantsBots = [];
var hasBot = false;
var assigned_at = undefined;
if (result.operators && result.operators.length > 0) {
assigned_operator_id = result.operators[0].id_user;
status = RequestConstants.ASSIGNED;
var assigned_operator_idString = assigned_operator_id.toString();
participants.push(assigned_operator_idString);
// botprefix
if (assigned_operator_idString.startsWith("bot_")) {
hasBot = true;
// botprefix
var assigned_operator_idStringBot = assigned_operator_idString.replace("bot_", "");
winston.debug("assigned_operator_idStringBot:" + assigned_operator_idStringBot);
participantsBots.push(assigned_operator_idStringBot);
} else {
participantsAgents.push(assigned_operator_idString);
}
assigned_at = Date.now();
}
// winston.debug("assigned_operator_id", assigned_operator_id);
// winston.debug("status", status);
var newRequest = new Request({
request_id: request_id,
requester_id: requester_id,
first_text: first_text,
status: status,
participants: participants,
participantsAgents: participantsAgents,
participantsBots: participantsBots,
hasBot: hasBot,
department: result.department._id,
agents: result.agents,
//availableAgents: result.available_agents,
// assigned_operator_id: result.assigned_operator_id,
//others
sourcePage: sourcePage,
language: language,
userAgent: userAgent,
assigned_at: assigned_at,
attributes: attributes,
//standard
id_project: id_project,
createdBy: createdBy,
updatedBy: createdBy
});
// winston.debug('newRequest.',newRequest);
//cacheinvalidation
return newRequest.save(function (err, savedRequest) {
if (err) {
winston.error('RequestService error for method createWithId for newRequest' + JSON.stringify(newRequest), err);
return reject(err);
}
winston.ver