Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
66 changes: 66 additions & 0 deletions apps/meteor/app/livechat/server/lib/takeInquiry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
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 { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { settings } from '../../../settings/server';

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'))) {
Comment thread
lucas-a-pelegrino marked this conversation as resolved.
Outdated
Comment thread
lucas-a-pelegrino marked this conversation as resolved.
Outdated
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);
}
};
Comment thread
lucas-a-pelegrino marked this conversation as resolved.
67 changes: 3 additions & 64 deletions apps/meteor/app/livechat/server/methods/takeInquiry.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
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,65 +14,9 @@ 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', {
Expand Down
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 @@ -3324,6 +3324,13 @@ export const isGETLivechatInquiriesListParams = ajv.compile<GETLivechatInquiries
type POSTLivechatInquiriesTakeParams = {
inquiryId: string;
userId?: string;
options?: {
clientAction: boolean;
forwardingToDepartment?: {
departmentId: string;
transferData: unknown;
};
};
};
Comment thread
lucas-a-pelegrino marked this conversation as resolved.

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