Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions .changeset/nice-balloons-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/rest-typings": patch
---

Adds deprecation warning on `livechat:removeRoom`, use `livechat/inquiries.take` instead
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { API } from '../../../../api/server';
import { getPaginationItems } from '../../../../api/server/helpers/getPaginationItems';
import { findInquiries, findOneInquiryByRoomId } from '../../../server/api/lib/inquiries';
import { takeInquiry } from '../../../server/methods/takeInquiry';
import { takeInquiry } from '../../../server/lib/takeInquiry';

API.v1.addRoute(
'livechat/inquiries.list',
Expand Down
59 changes: 59 additions & 0 deletions apps/meteor/app/livechat/server/lib/takeInquiry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Omnichannel } from '@rocket.chat/core-services';
import { LivechatInquiry, LivechatRooms, Users } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';

import { RoutingManager } from './RoutingManager';
import { isAgentAvailableToTakeContactInquiry } from './contacts/isAgentAvailableToTakeContactInquiry';
import { migrateVisitorIfMissingContact } from './contacts/migrateVisitorIfMissingContact';
import { settings } from '../../../settings/server';

export const takeInquiry = async (
userId: string,
inquiryId: string,
options?: { clientAction: boolean; forwardingToDepartment?: { oldDepartmentId: string; transferData: any } },
): Promise<void> => {
const inquiry = await LivechatInquiry.findOneById(inquiryId);

if (!inquiry) {
throw new Meteor.Error('error-not-found', 'Inquiry not found', {
method: 'livechat:takeInquiry',
});
}

if (inquiry.status === 'taken') {
throw new Meteor.Error('error-inquiry-taken', 'Inquiry already taken', {
method: 'livechat:takeInquiry',
});
}

const user = await Users.findOneOnlineAgentById(userId, settings.get<boolean>('Livechat_enabled_when_agent_idle'));
if (!user) {
throw new Meteor.Error('error-agent-status-service-offline', 'Agent status is offline or Omnichannel service is not active', {
method: 'livechat:takeInquiry',
});
}

const room = await LivechatRooms.findOneById(inquiry.rid);
if (!room || !(await Omnichannel.isWithinMACLimit(room))) {
throw new Meteor.Error('error-mac-limit-reached');
}

const contactId = room.contactId ?? (await migrateVisitorIfMissingContact(room.v._id, room.source));
if (contactId) {
const isAgentAvailableToTakeContactInquiryResult = await isAgentAvailableToTakeContactInquiry(inquiry.v._id, room.source, contactId);
if (!isAgentAvailableToTakeContactInquiryResult.value) {
throw new Meteor.Error(isAgentAvailableToTakeContactInquiryResult.error);
}
}

const agent = {
agentId: user._id,
username: user.username,
};

try {
await RoutingManager.takeInquiry(inquiry, agent, options ?? {}, room);
} catch (e: any) {
throw new Meteor.Error(e.message);
}
};
72 changes: 9 additions & 63 deletions apps/meteor/app/livechat/server/methods/takeInquiry.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { Omnichannel } from '@rocket.chat/core-services';
import type { ServerMethods } from '@rocket.chat/ddp-client';
import { LivechatInquiry, LivechatRooms, Users } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';

import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { settings } from '../../../settings/server';
import { RoutingManager } from '../lib/RoutingManager';
import { isAgentAvailableToTakeContactInquiry } from '../lib/contacts/isAgentAvailableToTakeContactInquiry';
import { migrateVisitorIfMissingContact } from '../lib/contacts/migrateVisitorIfMissingContact';
import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';
import { takeInquiry } from '../lib/takeInquiry';

declare module '@rocket.chat/ddp-client' {
// eslint-disable-next-line @typescript-eslint/naming-convention
Expand All @@ -19,72 +15,22 @@ declare module '@rocket.chat/ddp-client' {
}
}

export const takeInquiry = async (
userId: string,
inquiryId: string,
options?: { clientAction: boolean; forwardingToDepartment?: { oldDepartmentId: string; transferData: any } },
): Promise<void> => {
if (!userId || !(await hasPermissionAsync(userId, 'view-l-room'))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
method: 'livechat:takeInquiry',
});
}

const inquiry = await LivechatInquiry.findOneById(inquiryId);

if (!inquiry) {
throw new Meteor.Error('error-not-found', 'Inquiry not found', {
method: 'livechat:takeInquiry',
});
}

if (inquiry.status === 'taken') {
throw new Meteor.Error('error-inquiry-taken', 'Inquiry already taken', {
method: 'livechat:takeInquiry',
});
}

const user = await Users.findOneOnlineAgentById(userId, settings.get<boolean>('Livechat_enabled_when_agent_idle'));
if (!user) {
throw new Meteor.Error('error-agent-status-service-offline', 'Agent status is offline or Omnichannel service is not active', {
method: 'livechat:takeInquiry',
});
}

const room = await LivechatRooms.findOneById(inquiry.rid);
if (!room || !(await Omnichannel.isWithinMACLimit(room))) {
throw new Meteor.Error('error-mac-limit-reached');
}

const contactId = room.contactId ?? (await migrateVisitorIfMissingContact(room.v._id, room.source));
if (contactId) {
const isAgentAvailableToTakeContactInquiryResult = await isAgentAvailableToTakeContactInquiry(inquiry.v._id, room.source, contactId);
if (!isAgentAvailableToTakeContactInquiryResult.value) {
throw new Meteor.Error(isAgentAvailableToTakeContactInquiryResult.error);
}
}

const agent = {
agentId: user._id,
username: user.username,
};

try {
await RoutingManager.takeInquiry(inquiry, agent, options ?? {}, room);
} catch (e: any) {
throw new Meteor.Error(e.message);
}
};

Meteor.methods<ServerMethods>({
async 'livechat:takeInquiry'(inquiryId, options) {
methodDeprecationLogger.method('livechat:takeInquiry', '8.0.0', '/v1/livechat/inquiries.take');
const uid = Meteor.userId();
if (!uid) {
throw new Meteor.Error('error-not-allowed', 'Invalid User', {
method: 'livechat:takeInquiry',
});
}

if (!(await hasPermissionAsync(uid, 'view-l-room'))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
method: 'livechat:takeInquiry',
});
}

return takeInquiry(uid, inquiryId, options);
},
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MessageFooterCallout, MessageFooterCalloutAction, MessageFooterCalloutContent } from '@rocket.chat/ui-composer';
import { useEndpoint, useMethod, useToastMessageDispatch, useTranslation, useUser } from '@rocket.chat/ui-contexts';
import { useEndpoint, useToastMessageDispatch, useTranslation, useUser } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';
import type { ReactElement } from 'react';
import { useMemo } from 'react';
Expand All @@ -23,7 +23,7 @@ export const ComposerOmnichannelInquiry = (): ReactElement => {
}),
});

const takeInquiry = useMethod('livechat:takeInquiry');
const takeInquiry = useEndpoint('POST', '/v1/livechat/inquiries.take');

const handleTakeInquiry = async (): Promise<void> => {
if (!result.isSuccess) {
Expand All @@ -33,7 +33,7 @@ export const ComposerOmnichannelInquiry = (): ReactElement => {
return;
}
try {
await takeInquiry(result.data.inquiry._id, { clientAction: true });
await takeInquiry({ inquiryId: result.data.inquiry._id, options: { clientAction: true } });
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
}
Expand Down
32 changes: 32 additions & 0 deletions packages/rest-typings/src/v1/omnichannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3366,6 +3366,13 @@ export const isGETLivechatInquiriesListParams = ajv.compile<GETLivechatInquiries
type POSTLivechatInquiriesTakeParams = {
inquiryId: string;
userId?: string;
options?: {
clientAction: boolean;
forwardingToDepartment?: {
oldDepartmentId: string;
transferData: unknown;
};
};
};

const POSTLivechatInquiriesTakeParamsSchema = {
Expand All @@ -3378,6 +3385,31 @@ const POSTLivechatInquiriesTakeParamsSchema = {
type: 'string',
nullable: true,
},
options: {
type: 'object',
nullable: true,
properties: {
clientAction: {
type: 'boolean',
},
forwardingToDepartment: {
type: 'object',
nullable: true,
properties: {
oldDepartmentId: {
type: 'string',
},
transferData: {
type: 'object',
},
},
required: ['oldDepartmentId', 'transferData'],
additionalProperties: false,
},
},
required: ['clientAction'],
additionalProperties: false,
},
},
additionalProperties: false,
required: ['inquiryId'],
Expand Down
Loading