Skip to content
Merged
6 changes: 6 additions & 0 deletions .changeset/cuddly-dots-end.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:saveAgentInfo` with new endpoint replacing it; `livechat/agents.saveInfo`
46 changes: 45 additions & 1 deletion apps/meteor/app/livechat/server/api/v1/agent.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import type { ILivechatAgent } from '@rocket.chat/core-typings';
import { ILivechatAgentStatus } from '@rocket.chat/core-typings';
import { Users } from '@rocket.chat/models';
import { isGETAgentNextToken, isPOSTLivechatAgentStatusProps } from '@rocket.chat/rest-typings';
import {
isGETAgentNextToken,
isPOSTLivechatAgentSaveInfoParams,
isPOSTLivechatAgentStatusProps,
POSTLivechatAgentSaveInfoSuccessResponse,
validateBadRequestErrorResponse,
validateForbiddenErrorResponse,
validateUnauthorizedErrorResponse,
} from '@rocket.chat/rest-typings';

import { API } from '../../../../api/server';
import type { ExtractRoutesFromAPI } from '../../../../api/server/ApiClass';
import { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission';
import { hasRoleAsync } from '../../../../authorization/server/functions/hasRole';
import { RoutingManager } from '../../lib/RoutingManager';
import { getRequiredDepartment } from '../../lib/departmentsLib';
import { saveAgentInfo } from '../../lib/omni-users';
import { setUserStatusLivechat, allowAgentChangeServiceStatus } from '../../lib/utils';
import { findRoom, findGuest, findAgent, findOpenRoom } from '../lib/livechat';

Expand Down Expand Up @@ -124,3 +135,36 @@ API.v1.addRoute(
},
},
);

const livechatAgentsEndpoints = API.v1.post(
'livechat/agents.saveInfo',
{
response: {
200: POSTLivechatAgentSaveInfoSuccessResponse,
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
403: validateForbiddenErrorResponse,
},
authRequired: true,
permissionsRequired: ['manage-livechat-agents'],
body: isPOSTLivechatAgentSaveInfoParams,
},
async function action() {
const { agentId, agentData, agentDepartments } = this.bodyParams;

if (!(await hasRoleAsync(agentId, 'livechat-agent'))) {
return API.v1.failure('error-user-is-not-agent');
}

await saveAgentInfo(agentId, agentData, agentDepartments);

return API.v1.success();
},
);

type LivechatAgentsEndpoints = ExtractRoutesFromAPI<typeof livechatAgentsEndpoints>;

declare module '@rocket.chat/rest-typings' {
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface
interface Endpoints extends LivechatAgentsEndpoints {}
}
2 changes: 2 additions & 0 deletions apps/meteor/app/livechat/server/methods/saveAgentInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Meteor } from 'meteor/meteor';

import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { hasRoleAsync } from '../../../authorization/server/functions/hasRole';
import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';
import { saveAgentInfo } from '../lib/omni-users';

declare module '@rocket.chat/ddp-client' {
Expand All @@ -14,6 +15,7 @@ declare module '@rocket.chat/ddp-client' {

Meteor.methods<ServerMethods>({
async 'livechat:saveAgentInfo'(_id, agentData, agentDepartments) {
methodDeprecationLogger.method('livechat:saveAgentInfo', '8.0.0', '/v1/livechat/agents.saveInfo');
check(_id, String);
check(agentData, Object);
check(agentDepartments, [String]);
Expand Down
14 changes: 7 additions & 7 deletions apps/meteor/client/views/omnichannel/agents/AgentEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { ILivechatAgent, ILivechatAgentStatus, ILivechatDepartmentAgents }
import { Field, FieldLabel, FieldGroup, FieldRow, TextInput, Button, Box, Icon, Select, ButtonGroup } from '@rocket.chat/fuselage';
import type { SelectOption } from '@rocket.chat/fuselage';
import { useEffectEvent } from '@rocket.chat/fuselage-hooks';
import { useToastMessageDispatch, useSetting, useMethod, useTranslation, useEndpoint, useRouter } from '@rocket.chat/ui-contexts';
import { useToastMessageDispatch, useSetting, useTranslation, useEndpoint, useRouter } from '@rocket.chat/ui-contexts';
import { useQueryClient } from '@tanstack/react-query';
import { useId, useMemo } from 'react';
import { useForm, Controller, FormProvider } from 'react-hook-form';
Expand Down Expand Up @@ -79,17 +79,17 @@ const AgentEdit = ({ agentData, agentDepartments }: AgentEditProps) => {
formState: { isDirty },
} = methods;

const saveAgentInfo = useMethod('livechat:saveAgentInfo');
const saveAgentInfo = useEndpoint('POST', '/v1/livechat/agents.saveInfo');
const saveAgentStatus = useEndpoint('POST', '/v1/livechat/agent.status');

const handleSave = useEffectEvent(async ({ status, departments, ...data }: AgentEditFormData) => {
try {
await saveAgentStatus({ agentId: agentData._id, status });
await saveAgentInfo(
agentData._id,
data,
departments.map((dep) => dep.value),
);
await saveAgentInfo({
agentId: agentData._id,
agentData: data,
agentDepartments: departments.map((dep) => dep.value),
});
dispatchToastMessage({ type: 'success', message: t('Success') });
router.navigate('/omnichannel/agents');

Expand Down
13 changes: 5 additions & 8 deletions apps/meteor/tests/data/livechat/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Credentials } from '@rocket.chat/api-client';
import { UserStatus, type ILivechatAgent, type IUser } from '@rocket.chat/core-typings';
import { Random } from '@rocket.chat/random';

import { api, credentials, request, methodCall } from '../api-data';
import { api, credentials, request } from '../api-data';
import { password } from '../user';
import { createUser, login, setUserAway, setUserStatus } from '../users.helper';
import { createAgent, makeAgentAvailable, makeAgentUnavailable } from './rooms';
Expand Down Expand Up @@ -104,15 +104,12 @@ export const updateLivechatSettingsForUser = async (
agentDepartments: string[] = [],
): Promise<void> => {
await request
.post(methodCall('livechat:saveAgentInfo'))
.post(api('livechat/agents.saveInfo'))
.set(credentials)
.send({
message: JSON.stringify({
method: 'livechat:saveAgentInfo',
params: [agentId, livechatSettings, agentDepartments],
id: 'id',
msg: 'method',
}),
agentId,
agentData: livechatSettings,
agentDepartments,
})
.expect('Content-Type', 'application/json')
.expect(200);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,7 @@ test.describe.serial('OC - Manage Agents', () => {

await poOmnichannelAgents.btnEdit.click();
await poOmnichannelAgents.selectDepartment(department.data.name);
const reg = new RegExp(`/api/v1/method.call/${encodeURIComponent('livechat:saveAgentInfo')}`);
const response = page.waitForResponse(reg);
const response = page.waitForResponse('**/api/v1/livechat/agents.saveInfo');
await poOmnichannelAgents.btnSave.click();

/**
Expand Down
42 changes: 42 additions & 0 deletions packages/rest-typings/src/v1/omnichannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1723,6 +1723,48 @@ const POSTLivechatAgentStatusPropsSchema = {

export const isPOSTLivechatAgentStatusProps = ajv.compile<POSTLivechatAgentStatusProps>(POSTLivechatAgentStatusPropsSchema);

type POSTLivechatAgentSaveInfoParams = {
agentId: string;
agentData: Record<string, unknown>;
agentDepartments: string[];
};

const POSTLivechatAgentSaveInfoParamsSchema = {
type: 'object',
properties: {
agentId: {
type: 'string',
},
agentData: {
type: 'object',
additionalProperties: true,
},
agentDepartments: {
type: 'array',
items: {
type: 'string',
},
},
},
required: ['agentId', 'agentData', 'agentDepartments'],
additionalProperties: false,
};

export const isPOSTLivechatAgentSaveInfoParams = ajv.compile<POSTLivechatAgentSaveInfoParams>(POSTLivechatAgentSaveInfoParamsSchema);

const POSTLivechatAgentSaveInfoSuccessResponseSchema = {
type: 'object',
properties: {
success: {
type: 'boolean',
enum: [true],
},
},
additionalProperties: false,
};

export const POSTLivechatAgentSaveInfoSuccessResponse = ajv.compile<void>(POSTLivechatAgentSaveInfoSuccessResponseSchema);

type LivechatAnalyticsAgentsTotalServiceTimeProps = PaginatedRequest<{
start: string;
end: string;
Expand Down
Loading