diff --git a/.changeset/cool-pets-switch.md b/.changeset/cool-pets-switch.md new file mode 100644 index 0000000000000..38cadab03f70f --- /dev/null +++ b/.changeset/cool-pets-switch.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": patch +"@rocket.chat/rest-typings": patch +--- + +Adds deprecation warning on `livechat:removeCustomField` with new endpoint replacing it; `livechat/custom-fields.delete` diff --git a/apps/meteor/app/livechat/server/api/v1/customField.ts b/apps/meteor/app/livechat/server/api/v1/customField.ts index 981562eef36e2..4b89f019e50d3 100644 --- a/apps/meteor/app/livechat/server/api/v1/customField.ts +++ b/apps/meteor/app/livechat/server/api/v1/customField.ts @@ -1,6 +1,16 @@ -import { isLivechatCustomFieldsProps, isPOSTLivechatCustomFieldParams, isPOSTLivechatCustomFieldsParams } from '@rocket.chat/rest-typings'; +import { LivechatCustomField } from '@rocket.chat/models'; +import { + isLivechatCustomFieldsProps, + isPOSTLivechatCustomFieldParams, + isPOSTLivechatCustomFieldsParams, + isPOSTLivechatRemoveCustomFields, + POSTLivechatRemoveCustomFieldSuccess, + validateBadRequestErrorResponse, + validateUnauthorizedErrorResponse, +} from '@rocket.chat/rest-typings'; import { API } from '../../../../api/server'; +import type { ExtractRoutesFromAPI } from '../../../../api/server/ApiClass'; import { getPaginationItems } from '../../../../api/server/helpers/getPaginationItems'; import { setCustomFields, setMultipleCustomFields } from '../../lib/custom-fields'; import { findLivechatCustomFields, findCustomFieldById } from '../lib/customFields'; @@ -80,3 +90,34 @@ API.v1.addRoute( }, }, ); + +const livechatCustomFieldsEndpoints = API.v1.post( + 'livechat/custom-fields.delete', + { + response: { + 200: POSTLivechatRemoveCustomFieldSuccess, + 400: validateBadRequestErrorResponse, + 401: validateUnauthorizedErrorResponse, + }, + authRequired: true, + permissionsRequired: ['view-livechat-manager'], // is this permission appropriate for the targeted action? + body: isPOSTLivechatRemoveCustomFields, + }, + async function action() { + const { customFieldId } = this.bodyParams; + + const result = await LivechatCustomField.removeById(customFieldId); + if (result.deletedCount === 0) { + return API.v1.failure('Custom field not found'); + } + + return API.v1.success(); + }, +); + +type LivechatCustomFieldsEndpoints = ExtractRoutesFromAPI; + +declare module '@rocket.chat/rest-typings' { + // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface + interface Endpoints extends LivechatCustomFieldsEndpoints {} +} diff --git a/apps/meteor/app/livechat/server/methods/removeCustomField.ts b/apps/meteor/app/livechat/server/methods/removeCustomField.ts index ad02df5823377..2dd9de6bb8a02 100644 --- a/apps/meteor/app/livechat/server/methods/removeCustomField.ts +++ b/apps/meteor/app/livechat/server/methods/removeCustomField.ts @@ -5,6 +5,7 @@ import { Meteor } from 'meteor/meteor'; import type { DeleteResult } from 'mongodb'; import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; declare module '@rocket.chat/ddp-client' { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -15,6 +16,7 @@ declare module '@rocket.chat/ddp-client' { Meteor.methods({ async 'livechat:removeCustomField'(_id) { + methodDeprecationLogger.method('livechat:removeCustomField', '8.0.0', '/v1/livechat/custom-fields.delete'); const uid = Meteor.userId(); if (!uid || !(await hasPermissionAsync(uid, 'view-livechat-manager'))) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { diff --git a/apps/meteor/client/views/omnichannel/customFields/useRemoveCustomField.tsx b/apps/meteor/client/views/omnichannel/customFields/useRemoveCustomField.tsx index d15da67020eea..80164cdab9540 100644 --- a/apps/meteor/client/views/omnichannel/customFields/useRemoveCustomField.tsx +++ b/apps/meteor/client/views/omnichannel/customFields/useRemoveCustomField.tsx @@ -1,6 +1,6 @@ import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { GenericModal } from '@rocket.chat/ui-client'; -import { useSetModal, useToastMessageDispatch, useMethod } from '@rocket.chat/ui-contexts'; +import { useSetModal, useToastMessageDispatch, useEndpoint } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; @@ -8,13 +8,13 @@ export const useRemoveCustomField = () => { const { t } = useTranslation(); const setModal = useSetModal(); const dispatchToastMessage = useToastMessageDispatch(); - const removeCustomField = useMethod('livechat:removeCustomField'); + const removeCustomField = useEndpoint('POST', '/v1/livechat/custom-fields.delete'); const queryClient = useQueryClient(); const handleDelete = useEffectEvent((id: string) => { const onDeleteAgent = async () => { try { - await removeCustomField(id); + await removeCustomField({ customFieldId: id }); dispatchToastMessage({ type: 'success', message: t('Custom_Field_Removed') }); queryClient.invalidateQueries({ queryKey: ['livechat-customFields'], diff --git a/apps/meteor/tests/data/livechat/custom-fields.ts b/apps/meteor/tests/data/livechat/custom-fields.ts index f4878f6f754d6..dc063b100e374 100644 --- a/apps/meteor/tests/data/livechat/custom-fields.ts +++ b/apps/meteor/tests/data/livechat/custom-fields.ts @@ -42,16 +42,11 @@ export const createCustomField = (customField: ExtendedCustomField): Promise new Promise((resolve, reject) => { void request - .post(methodCall('livechat:removeCustomField')) + .post(api('livechat/custom-fields.delete')) + .set(credentials) .send({ - message: JSON.stringify({ - method: 'livechat:removeCustomField', - params: [customFieldID], - id: 'id', - msg: 'method', - }), + customFieldId: customFieldID, }) - .set(credentials) .end((err: Error, res: Response): void => { if (err) { return reject(err); diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center.spec.ts index 430c3a683f9d8..f772fae53ab82 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center.spec.ts @@ -1,7 +1,6 @@ import { faker } from '@faker-js/faker'; import { createToken } from '../../../client/lib/utils/createToken'; -import { IS_EE } from '../config/constants'; import { Users } from '../fixtures/userStates'; import { OmnichannelContacts } from '../page-objects/omnichannel-contacts-list'; import { OmnichannelSection } from '../page-objects/omnichannel-section'; @@ -32,17 +31,6 @@ const DELETE_CONTACT = { phones: [faker.phone.number('+############')], }; -const NEW_CUSTOM_FIELD = { - searchable: true, - field: 'hiddenCustomField', - label: 'hiddenCustomField', - defaultValue: 'test_contact_center_hidden_customField', - scope: 'visitor', - visibility: 'hidden', - required: true, - regexp: '', -}; - const URL = { contactCenter: '/omnichannel-directory/contacts', newContact: '/omnichannel-directory/contacts/new', @@ -72,19 +60,11 @@ test.describe('Omnichannel Contact Center', () => { test.beforeAll(async ({ api }) => { // Add contacts await Promise.all([api.post('/omnichannel/contacts', EXISTING_CONTACT), api.post('/omnichannel/contacts', DELETE_CONTACT)]); - - if (IS_EE) { - await api.post('/livechat/custom.field', NEW_CUSTOM_FIELD); - } }); test.afterAll(async ({ api }) => { // Remove added contacts await Promise.all([api.delete(`/livechat/visitor/${NEW_CONTACT.token}`), api.delete(`/livechat/visitor/${EXISTING_CONTACT.token}`)]); - - if (IS_EE) { - await api.post('method.call/livechat:removeCustomField', { message: NEW_CUSTOM_FIELD.field }); - } }); test.beforeEach(async ({ page }) => { diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts index ce1b70db848ff..e5db53a53a785 100644 --- a/packages/rest-typings/src/v1/omnichannel.ts +++ b/packages/rest-typings/src/v1/omnichannel.ts @@ -3989,6 +3989,36 @@ export const isPOSTLivechatRoomsCloseAllSuccessResponse = ajv.compile<{ removedR POSTLivechatRoomsCloseAllSuccessResponseSchema, ); +type POSTLivechatRemoveCustomFields = { + customFieldId: string; +}; + +const POSTLivechatRemoveCustomFieldsSchema = { + type: 'object', + properties: { + customFieldId: { + type: 'string', + }, + }, + required: ['customFieldId'], + additionalProperties: false, +}; + +export const isPOSTLivechatRemoveCustomFields = ajv.compile(POSTLivechatRemoveCustomFieldsSchema); + +const POSTLivechatRemoveCustomFieldSuccessSchema = { + type: 'object', + properties: { + success: { + type: 'boolean', + enum: [true], + }, + }, + additionalProperties: false, +}; + +export const POSTLivechatRemoveCustomFieldSuccess = ajv.compile(POSTLivechatRemoveCustomFieldSuccessSchema); + export type ILivechatContactWithManagerData = Omit & { contactManager?: Pick; };