Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c4cf843
Update index.js
ggazzo Jan 8, 2021
a0c9821
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat i…
renatobecker Jan 8, 2021
383415a
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat i…
renatobecker Jan 15, 2021
1a87b16
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat i…
renatobecker Jan 15, 2021
edeff04
Livechat - auto assign visitor to contact-manager
murtaza98 Jan 18, 2021
40732c6
remove console logs
murtaza98 Jan 18, 2021
818df39
Merge branch 'develop' into livechat/contact-manager-backend
renatobecker Jan 18, 2021
2b2910d
Add improvements to Omnichannel Queue.
renatobecker Jan 18, 2021
a6b9710
Merge branch 'livechat/contact-manager-backend' of https://github.com…
renatobecker Jan 18, 2021
a66872b
Imoprovements on codebase.
renatobecker Jan 19, 2021
79e886a
Merge branch 'develop' into livechat/contact-manager-backend
renatobecker Jan 19, 2021
b3dacd7
Merge branch 'livechat/contact-manager-backend' of https://github.com…
renatobecker Jan 19, 2021
0efe539
Merge branch 'develop' into livechat/contact-manager-backend
renatobecker Jan 19, 2021
f99e81b
Merge branch 'livechat/contact-manager-backend' of https://github.com…
renatobecker Jan 19, 2021
6d99797
Final queue improvements.
renatobecker Jan 20, 2021
f3e7ec2
Merge branch 'develop' into livechat/contact-manager-backend
renatobecker Jan 20, 2021
688013d
Merge branch 'livechat/contact-manager-backend' of https://github.com…
renatobecker Jan 20, 2021
e143ef6
Removed unnecessary imports.
renatobecker Jan 20, 2021
1bb654d
Fix translations missing.
renatobecker Jan 20, 2021
6eb122f
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat i…
renatobecker Jan 20, 2021
ba40ddb
Allow contact manager from different department to view the chat in t…
murtaza98 Jan 21, 2021
ac14c6d
Merge branch 'develop' into livechat/contact-manager-backend
renatobecker Jan 21, 2021
d275a24
Merge branch 'develop' into livechat/contact-manager-backend
renatobecker Jan 22, 2021
700540c
Merge branch 'develop' into livechat/contact-manager-backend
renatobecker Jan 22, 2021
e139a64
Fix Omnichannel Queue delegation.
renatobecker Jan 22, 2021
2997291
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat i…
renatobecker Jan 22, 2021
1bb0b91
Fix conflicts.
renatobecker Jan 22, 2021
00ab686
Fix default agent when unarchiving chats.
renatobecker Jan 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion app/livechat/server/api/lib/inquiries.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,15 @@ export async function findInquiries({ userId, department: filterDepartment, stat

const filter = {
...status && { status },
...department && { department },
$or: [
{
$and: [
{ defaultAgent: { $exists: true } },
{ 'defaultAgent.agentId': userId },
],
},
{ ...department && { department } },
],
};

const cursor = LivechatInquiry.find(filter, options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@ import { callbacks } from '../../../callbacks';
import { settings } from '../../../settings';
import { Users, LivechatDepartmentAgents } from '../../../models';

callbacks.add('livechat.beforeGetNextAgent', (department, ignoreAgentId) => {
callbacks.add('livechat.beforeDelegateAgent', (options = {}) => {
const { department, agent } = options;

if (agent) {
return agent;
}

if (!settings.get('Livechat_assign_new_conversation_to_bot')) {
return null;
}

if (department) {
return LivechatDepartmentAgents.getNextBotForDepartment(department, ignoreAgentId);
return LivechatDepartmentAgents.getNextBotForDepartment(department);
}

return Users.getNextBotAgent(ignoreAgentId);
}, callbacks.priority.HIGH, 'livechat-before-get-next-agent');
return Users.getNextBotAgent();
}, callbacks.priority.HIGH, 'livechat-before-delegate-agent');
2 changes: 1 addition & 1 deletion app/livechat/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import '../lib/messageTypes';
import './config';
import './roomType';
import './hooks/beforeCloseRoom';
import './hooks/beforeGetNextAgent';
import './hooks/beforeDelegateAgent';
import './hooks/leadCapture';
import './hooks/markRoomResponded';
import './hooks/offlineMessage';
Expand Down
76 changes: 71 additions & 5 deletions app/livechat/server/lib/Helper.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import { Meteor } from 'meteor/meteor';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';
import { Match, check } from 'meteor/check';
import { LivechatTransferEventType } from '@rocket.chat/apps-engine/definition/livechat';

import { hasRole } from '../../../authorization';
import { Messages, LivechatRooms, Rooms, Subscriptions, Users, LivechatInquiry, LivechatDepartment, LivechatDepartmentAgents } from '../../../models/server';
import { Livechat } from './Livechat';
import { RoutingManager } from './RoutingManager';
import { callbacks } from '../../../callbacks/server';
import { settings } from '../../../settings';
import { Apps, AppEvents } from '../../../apps/server';
import notifications from '../../../notifications/server/lib/Notifications';
import { sendNotification } from '../../../lib/server';

export const allowAgentSkipQueue = (agent) => {
check(agent, Match.ObjectIncluding({
agentId: String,
}));

return hasRole(agent.agentId, 'bot');
};

export const createLivechatRoom = (rid, name, guest, roomInfo = {}, extraData = {}) => {
check(rid, String);
Expand Down Expand Up @@ -199,6 +210,61 @@ export const dispatchAgentDelegated = (rid, agentId) => {
});
};

export const dispatchInquiryQueued = (inquiry, agent) => {
if (!inquiry?._id) {
return;
}

const { department, rid, v } = inquiry;
const room = LivechatRooms.findOneById(rid);
Meteor.defer(() => callbacks.run('livechat.chatQueued', room));

if (RoutingManager.getConfig().autoAssignAgent) {
return;
}

if (!agent || !allowAgentSkipQueue(agent)) {
LivechatInquiry.queueInquiry(inquiry._id);
}

// Alert only the online agents of the queued request
const onlineAgents = Livechat.getOnlineAgents(department, agent);

const notificationUserName = v && (v.name || v.username);

onlineAgents.forEach((agent) => {
if (agent.agentId) {
agent = Users.findOneById(agent.agentId);
}
const { _id, active, emails, language, status, statusConnection, username } = agent;
sendNotification({
// fake a subscription in order to make use of the function defined above
subscription: {
rid,
t: 'l',
u: {
_id,
},
receiver: [{
active,
emails,
language,
status,
statusConnection,
username,
}],
},
sender: v,
hasMentionToAll: true, // consider all agents to be in the room
hasMentionToHere: false,
message: Object.assign({}, { u: v }),
notificationMessage: TAPi18n.__('User_started_a_new_conversation', { username: notificationUserName }, language),
room: Object.assign(room, { name: TAPi18n.__('New_chat_in_queue', {}, language) }),
mentionIds: [],
});
});
};

export const forwardRoomToAgent = async (room, transferData) => {
if (!room || !room.open) {
return false;
Expand Down Expand Up @@ -351,13 +417,13 @@ export const normalizeTransferredByData = (transferredBy, room) => {
};

export const checkServiceStatus = ({ guest, agent }) => {
if (agent) {
const { agentId } = agent;
const users = Users.findOnlineAgents(agentId);
return users && users.count() > 0;
if (!agent) {
return Livechat.online(guest.department);
}

return Livechat.online(guest.department);
const { agentId } = agent;
const users = Users.findOnlineAgents(agentId);
return users && users.count() > 0;
};

export const userCanTakeInquiry = (user) => {
Expand Down
9 changes: 6 additions & 3 deletions app/livechat/server/lib/Livechat.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const Livechat = {
}

const onlineAgents = Livechat.getOnlineAgents(department);
return (onlineAgents && onlineAgents.count() > 0) || settings.get('Livechat_accept_chats_with_no_agents');
return onlineAgents && onlineAgents.count() > 0;
},

getNextAgent(department) {
Expand All @@ -78,7 +78,11 @@ export const Livechat = {
return Users.findAgents();
},

getOnlineAgents(department) {
getOnlineAgents(department, agent) {
if (agent?.agentId) {
return Users.findOnlineAgents(agent.agentId);
}

if (department) {
return LivechatDepartmentAgents.getOnlineForDepartment(department);
}
Expand Down Expand Up @@ -622,7 +626,6 @@ export const Livechat = {
try {
this.saveTransferHistory(room, transferData);
RoutingManager.unassignAgent(inquiry, departmentId);
Meteor.defer(() => callbacks.run('livechat.chatQueued', LivechatRooms.findOneById(rid)));
} catch (e) {
console.error(e);
throw new Meteor.Error('error-returning-inquiry', 'Error returning inquiry to the queue', { method: 'livechat:returnRoomAsInquiry' });
Expand Down
21 changes: 9 additions & 12 deletions app/livechat/server/lib/QueueManager.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';

import { LivechatRooms, LivechatInquiry } from '../../../models/server';
import { LivechatRooms, LivechatInquiry, Users } from '../../../models/server';
import { checkServiceStatus, createLivechatRoom, createLivechatInquiry } from './Helper';
import { callbacks } from '../../../callbacks/server';
import { RoutingManager } from './RoutingManager';


const queueInquiry = async (room, inquiry, defaultAgent) => {
if (!defaultAgent) {
defaultAgent = RoutingManager.getMethod().delegateAgent(defaultAgent, inquiry);
}
const inquiryAgent = RoutingManager.delegateAgent(defaultAgent, inquiry);
await callbacks.run('livechat.beforeRouteChat', inquiry, inquiryAgent);
inquiry = LivechatInquiry.findOneById(inquiry._id);

inquiry = await callbacks.run('livechat.beforeRouteChat', inquiry, defaultAgent);
if (inquiry.status === 'ready') {
return RoutingManager.delegateInquiry(inquiry, defaultAgent);
}

if (inquiry.status === 'queued') {
Meteor.defer(() => callbacks.run('livechat.chatQueued', room));
return RoutingManager.delegateInquiry(inquiry, inquiryAgent);
}
};
export const QueueManager = {
Expand Down Expand Up @@ -46,7 +41,6 @@ export const QueueManager = {
LivechatRooms.updateRoomCount();

await queueInquiry(room, inquiry, agent);

return room;
},

Expand All @@ -66,7 +60,10 @@ export const QueueManager = {
...department && { department },
};

const defaultAgent = servedBy && { agentId: servedBy._id, username: servedBy.username };
let defaultAgent;
if (servedBy && Users.findOneOnlineAgentByUsername(servedBy.username)) {
defaultAgent = { agentId: servedBy._id, username: servedBy.username };
}

LivechatRooms.unarchiveOneById(rid);
const room = LivechatRooms.findOneById(rid);
Expand Down
24 changes: 14 additions & 10 deletions app/livechat/server/lib/RoutingManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { settings } from '../../../settings/server';
import {
createLivechatSubscription,
dispatchAgentDelegated,
dispatchInquiryQueued,
forwardRoomToAgent,
forwardRoomToDepartment,
removeAgentFromSubscription,
Expand Down Expand Up @@ -38,13 +39,7 @@ export const RoutingManager = {
},

async getNextAgent(department, ignoreAgentId) {
let agent = callbacks.run('livechat.beforeGetNextAgent', department, ignoreAgentId);

if (!agent) {
agent = await this.getMethod().getNextAgent(department, ignoreAgentId);
}

return agent;
return this.getMethod().getNextAgent(department, ignoreAgentId);
},

async delegateInquiry(inquiry, agent) {
Expand Down Expand Up @@ -85,7 +80,7 @@ export const RoutingManager = {
},

unassignAgent(inquiry, departmentId) {
const { _id, rid, department } = inquiry;
const { rid, department } = inquiry;
const room = LivechatRooms.findOneById(rid);

if (!room || !room.open) {
Expand All @@ -110,8 +105,7 @@ export const RoutingManager = {
dispatchAgentDelegated(rid, null);
}

LivechatInquiry.queueInquiry(_id);
this.getMethod().delegateAgent(null, inquiry);
dispatchInquiryQueued(inquiry);
return true;
},

Expand Down Expand Up @@ -161,6 +155,16 @@ export const RoutingManager = {

return false;
},

delegateAgent(agent, inquiry) {
const defaultAgent = callbacks.run('livechat.beforeDelegateAgent', { agent, department: inquiry?.department });
if (defaultAgent) {
LivechatInquiry.setDefaultAgentById(inquiry._id, defaultAgent);
}

dispatchInquiryQueued(inquiry, defaultAgent);
return defaultAgent;
},
};

settings.get('Livechat_Routing_Method', function(key, value) {
Expand Down
4 changes: 0 additions & 4 deletions app/livechat/server/lib/routing/AutoSelection.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ class AutoSelection {

return Users.getNextAgent(ignoreAgentId);
}

delegateAgent(agent) {
return agent;
}
}

RoutingManager.registerMethod('Auto_Selection', AutoSelection);
4 changes: 0 additions & 4 deletions app/livechat/server/lib/routing/External.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ class ExternalQueue {
}
throw new Meteor.Error('no-agent-online', 'Sorry, no online agents');
}

delegateAgent(agent) {
return agent;
}
}

RoutingManager.registerMethod('External', ExternalQueue);
62 changes: 0 additions & 62 deletions app/livechat/server/lib/routing/ManualSelection.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import { Meteor } from 'meteor/meteor';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';

import { Livechat } from '../Livechat';
import { RoutingManager } from '../RoutingManager';
import { sendNotification } from '../../../../lib/server';
import { LivechatRooms, LivechatInquiry, Users } from '../../../../models/server';
import { callbacks } from '../../../../callbacks/server';

/* Manual Selection Queuing Method:
*
Expand All @@ -32,61 +25,6 @@ class ManualSelection {
getNextAgent() {

}

delegateAgent(agent, inquiry) {
const { department, rid, v } = inquiry;
const allAgents = Livechat.getAgents(department);

if (allAgents.count() === 0) {
throw new Meteor.Error('no-agent-available', 'Sorry, no available agents.');
}

// remove agent from room in case the rooms is being transferred or returned to the Queue
LivechatRooms.removeAgentByRoomId(rid);
LivechatInquiry.queueInquiry(inquiry._id);

// Alert only the online agents of the queued request
const onlineAgents = Livechat.getOnlineAgents(department);

const room = LivechatRooms.findOneById(rid);
const notificationUserName = v && (v.name || v.username);

onlineAgents.forEach((agent) => {
if (agent.agentId) {
agent = Users.findOneById(agent.agentId);
}
const { _id, active, emails, language, status, statusConnection, username } = agent;
sendNotification({
// fake a subscription in order to make use of the function defined above
subscription: {
rid,
t: 'l',
u: {
_id,
},
receiver: [{
active,
emails,
language,
status,
statusConnection,
username,
}],
},
sender: v,
hasMentionToAll: true, // consider all agents to be in the room
hasMentionToHere: false,
message: Object.assign({}, { u: v }),
notificationMessage: TAPi18n.__('User_started_a_new_conversation', { username: notificationUserName }, language),
room: Object.assign(room, { name: TAPi18n.__('New_chat_in_queue', {}, language) }),
mentionIds: [],
});
});

Meteor.defer(() => callbacks.run('livechat.chatQueued', room));

return agent;
}
}

RoutingManager.registerMethod('Manual_Selection', ManualSelection);
Loading