Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use Single contact Id settings in routing manager #33490

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
0640b4b
feat: use room manager settings
Gustrb Oct 8, 2024
335b566
Create clean-ravens-melt.md
Gustrb Oct 8, 2024
2cfa527
chore: add contact id to inquiry
Gustrb Oct 10, 2024
d580ca4
chore: add contact unverification
Gustrb Oct 10, 2024
d7b302a
chore: pick settings commit
Gustrb Oct 10, 2024
51da9f7
chore: merge ifs
Gustrb Oct 11, 2024
53a4c39
chore: improve the code
Gustrb Oct 13, 2024
1c09a17
feat: added `Livechat_Block_Unverified_Contacts` setting support
Gustrb Oct 13, 2024
f095ab6
fix: oopsie typo
Gustrb Oct 13, 2024
657c8a8
chore: sorry linter
Gustrb Oct 14, 2024
43b8c0b
chore: move import
Gustrb Oct 14, 2024
588c69c
fix: sorry linter
Gustrb Oct 14, 2024
664cb21
chore: not pick room if it is with an unverified contact
Gustrb Oct 14, 2024
aa1ad50
chore: only add to the queue inquiries that can be processed
Gustrb Oct 15, 2024
67e084d
chore: improve docs
Gustrb Oct 15, 2024
baea9d5
chore: lint-fix
Gustrb Oct 15, 2024
eea01d1
fix: remove the contactId from the ILivechatVisitor
Gustrb Oct 15, 2024
281e819
feat: add method to search inquiry by contactId
Gustrb Oct 15, 2024
d2ed619
chore: channels were already being created
Gustrb Oct 15, 2024
3387e51
feat: move contact verification livechat settings to EE
Gustrb Oct 15, 2024
bd2ebdb
chore: lint-fix
Gustrb Oct 16, 2024
7d910d9
chore: move service into correct license
Gustrb Oct 16, 2024
85d1e4d
chore: change license
Gustrb Oct 16, 2024
58d6aa9
chore: remove settings
Gustrb Oct 16, 2024
0d26dba
chore: remove right settings
Gustrb Oct 16, 2024
36d3718
chore: remove setting
Gustrb Oct 16, 2024
e8ba3ca
chore: use makeFunction and patch
Gustrb Oct 16, 2024
771901e
chore: removing unused import
Gustrb Oct 17, 2024
c749bb1
chore: apply suggestions
Gustrb Oct 17, 2024
e245c1a
chore: moving unverifyContactChannel to model
Gustrb Oct 17, 2024
696e3e3
chore: remove isSingleContactId call
Gustrb Oct 17, 2024
bba7f8a
chore: remove server import of client field
Gustrb Oct 17, 2024
045471b
chore: use License.hasModule
Gustrb Oct 17, 2024
1e31245
chore: improve shouldTriggerVerificationApp
Gustrb Oct 17, 2024
db411ca
Merge branch 'feat/single-contact-id' into feat/use-room-manager-sett…
Gustrb Oct 17, 2024
e4c40a6
Merge branch 'feat/single-contact-id' into feat/use-room-manager-sett…
Gustrb Oct 18, 2024
d4fd6a1
Merge branch 'feat/single-contact-id' into feat/use-room-manager-sett…
Gustrb Oct 18, 2024
a7d95d3
Merge branch 'feat/single-contact-id' into feat/use-room-manager-sett…
Gustrb Oct 18, 2024
b25ac47
chore: remove unused method
Gustrb Oct 18, 2024
08ff9f6
Merge branch 'feat/single-contact-id' into feat/use-room-manager-sett…
Gustrb Oct 18, 2024
7afe046
Merge branch 'feat/single-contact-id' into feat/use-room-manager-sett…
Gustrb Oct 18, 2024
cf869aa
chore: remove uncessary method
Gustrb Oct 18, 2024
569f902
chore: remove changeset
Gustrb Oct 18, 2024
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
4 changes: 4 additions & 0 deletions apps/meteor/app/livechat/server/lib/Contacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,3 +543,7 @@ export async function validateContactManager(contactManagerUserId: string) {
export const verifyContactChannel = makeFunction(async (_params: VerifyContactChannelParams): Promise<ILivechatContact | null> => null);

export const mergeContacts = makeFunction(async (_contactId: string, _visitorId: string): Promise<ILivechatContact | null> => null);

export const shouldTriggerVerificationApp = makeFunction(
async (_contactId: ILivechatContact['_id'], _source: IOmnichannelSource): Promise<boolean> => false,
);
5 changes: 4 additions & 1 deletion apps/meteor/app/livechat/server/lib/Helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import {
notifyOnSubscriptionChanged,
} from '../../../lib/server/lib/notifyListener';
import { settings } from '../../../settings/server';
import { migrateVisitorIfMissingContact } from './Contacts';
import { getContactIdByVisitorId, migrateVisitorIfMissingContact } from './Contacts';
import { Livechat as LivechatTyped } from './LivechatTyped';
import { queueInquiry, saveQueueInquiry } from './QueueManager';
import { RoutingManager } from './RoutingManager';
Expand Down Expand Up @@ -195,6 +195,8 @@ export const createLivechatInquiry = async ({
visitor: { _id, username, department, status, activity },
});

const contactId = await getContactIdByVisitorId(_id);
pierre-lehnen-rc marked this conversation as resolved.
Show resolved Hide resolved

const result = await LivechatInquiry.findOneAndUpdate(
{
rid,
Expand All @@ -209,6 +211,7 @@ export const createLivechatInquiry = async ({
token,
status,
...(activity?.length && { activity }),
contactId,
},
t: 'l',
priorityWeight: LivechatPriorityWeight.NOT_SPECIFIED,
Expand Down
16 changes: 14 additions & 2 deletions apps/meteor/app/livechat/server/lib/QueueManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
type OmnichannelSourceType,
} from '@rocket.chat/core-typings';
import { Logger } from '@rocket.chat/logger';
import { LivechatDepartment, LivechatDepartmentAgents, LivechatInquiry, LivechatRooms, Users } from '@rocket.chat/models';
import { LivechatContacts, LivechatDepartment, LivechatDepartmentAgents, LivechatInquiry, LivechatRooms, Users } from '@rocket.chat/models';
import { Random } from '@rocket.chat/random';
import { Match, check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
Expand All @@ -25,6 +25,7 @@ import {
} from '../../../lib/server/lib/notifyListener';
import { settings } from '../../../settings/server';
import { i18n } from '../../../utils/lib/i18n';
import { shouldTriggerVerificationApp } from './Contacts';
import { createLivechatRoom, createLivechatInquiry, allowAgentSkipQueue } from './Helper';
import { Livechat } from './LivechatTyped';
import { RoutingManager } from './RoutingManager';
Expand Down Expand Up @@ -179,6 +180,7 @@ export class QueueManager {
department: Match.Maybe(String),
name: Match.Maybe(String),
activity: Match.Maybe([String]),
contactId: Match.Maybe(String),
}),
);

Expand Down Expand Up @@ -255,7 +257,17 @@ export class QueueManager {
void notifyOnSettingChanged(livechatSetting);
}

const newRoom = (await this.queueInquiry(inquiry, room, defaultAgent)) ?? (await LivechatRooms.findOneById(rid));
let newRoom;
// Note: if the contact is not verified, we cannot add it to the queue, since no agent should be able to pick the conversation
// up. So if the contact is not verified we don't add it to queue and wait an event to be sent to properly add it to queue
if (inquiry.v.contactId && (await shouldTriggerVerificationApp(inquiry.v.contactId, room.source))) {
newRoom = await LivechatRooms.findOneById(rid);
await LivechatContacts.updateContactChannel(inquiry.v._id, { verified: true });
// void Apps.self?.triggerEvent(AppEvents.IPostContactVerificationAppAssigned, inquiry.v, room);
} else {
newRoom = (await this.queueInquiry(inquiry, room, defaultAgent)) ?? (await LivechatRooms.findOneById(rid));
}

if (!newRoom) {
logger.error(`Room with id ${rid} not found`);
throw new Error('room-not-found');
Expand Down
1 change: 1 addition & 0 deletions apps/meteor/app/livechat/server/lib/RoutingManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export const RoutingManager: Routing = {
async delegateInquiry(inquiry, agent, options = {}, room) {
const { department, rid } = inquiry;
logger.debug(`Attempting to delegate inquiry ${inquiry._id}`);

if (!agent || (agent.username && !(await Users.findOneOnlineAgentByUserList(agent.username)) && !(await allowAgentSkipQueue(agent)))) {
logger.debug(`Agent offline or invalid. Using routing method to get next agent for inquiry ${inquiry._id}`);
agent = await this.getNextAgent(department);
Expand Down
6 changes: 6 additions & 0 deletions apps/meteor/app/livechat/server/methods/takeInquiry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Meteor } from 'meteor/meteor';

import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { settings } from '../../../settings/server';
import { shouldTriggerVerificationApp, migrateVisitorIfMissingContact } from '../lib/Contacts';
import { RoutingManager } from '../lib/RoutingManager';

declare module '@rocket.chat/ddp-client' {
Expand Down Expand Up @@ -54,6 +55,11 @@ export const takeInquiry = async (
throw new Error('error-mac-limit-reached');
}

const contactId = await migrateVisitorIfMissingContact(inquiry.v._id, room.source);
if (contactId && (await shouldTriggerVerificationApp(contactId, room.source))) {
throw new Error('error-unverified-contact');
}

const agent = {
agentId: user._id,
username: user.username,
Expand Down
1 change: 1 addition & 0 deletions apps/meteor/ee/server/patches/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ import './getInstanceList';
import './isDepartmentCreationAvailable';
import './verifyContactChannel';
import './mergeContacts';
import './shouldTriggerVerificationApp';
43 changes: 43 additions & 0 deletions apps/meteor/ee/server/patches/shouldTriggerVerificationApp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { IOmnichannelSource, ILivechatContact } from '@rocket.chat/core-typings';
import { License } from '@rocket.chat/license';
import { LivechatContacts } from '@rocket.chat/models';

import { shouldTriggerVerificationApp } from '../../../app/livechat/server/lib/Contacts';
import { settings } from '../../../app/settings/server';

const runShouldTriggerVerificationApp = async (
_next: any,
contactId: ILivechatContact['_id'],
source: IOmnichannelSource,
): Promise<boolean> => {
const contact = await LivechatContacts.findOneById<Pick<ILivechatContact, '_id' | 'unknown' | 'channels'>>(contactId, {
projection: {
_id: 1,
unknown: 1,
channels: 1,
},
});

// Sanity check, should never happen
if (!contact) {
return false;
}

if (contact.unknown && settings.get<boolean>('Livechat_Block_Unknown_Contacts')) {
return true;
}

const isContactVerified = (contact.channels?.filter((channel) => channel.verified && channel.name === source.type) || []).length > 0;

if (!isContactVerified && settings.get<boolean>('Livechat_Block_Unverified_Contacts')) {
return true;
}

if (!settings.get<boolean>('Livechat_Request_Verification_On_First_Contact_Only')) {
return true;
}

return false;
};

shouldTriggerVerificationApp.patch(runShouldTriggerVerificationApp, () => License.hasModule('contact-id-verification'));
5 changes: 4 additions & 1 deletion packages/core-typings/src/IInquiry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ export interface ILivechatInquiryRecord extends IRocketChatRecord {
ts: Date;
message: string;
status: LivechatInquiryStatus;
v: Pick<ILivechatVisitor, '_id' | 'username' | 'status' | 'name' | 'token' | 'phone' | 'activity'> & { lastMessageTs?: Date };
v: Pick<ILivechatVisitor, '_id' | 'username' | 'status' | 'name' | 'token' | 'phone' | 'activity'> & {
lastMessageTs?: Date;
contactId?: string;
};
t: 'l';

department?: string;
Expand Down
Loading