Skip to content

Commit

Permalink
refactor: Deprecate transcript & triggers endpoints and create tests (#…
Browse files Browse the repository at this point in the history
…29861)

Co-authored-by: Murtaza Patrawala <[email protected]>
  • Loading branch information
KevLehman and murtaza98 authored Aug 22, 2023
1 parent 0194971 commit 06d24c1
Show file tree
Hide file tree
Showing 18 changed files with 638 additions and 26 deletions.
50 changes: 49 additions & 1 deletion apps/meteor/app/livechat/imports/server/rest/appearance.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import { Settings } from '@rocket.chat/models';
import { isPOSTLivechatAppearanceParams } from '@rocket.chat/rest-typings';

import { API } from '../../../../api/server';
import { findAppearance } from '../../../server/api/lib/appearance';

API.v1.addRoute(
'livechat/appearance',
{ authRequired: true, permissionsRequired: ['view-livechat-manager'] },
{
authRequired: true,
permissionsRequired: ['view-livechat-manager'],
validateParams: {
POST: isPOSTLivechatAppearanceParams,
},
},
{
async get() {
const { appearance } = await findAppearance();
Expand All @@ -12,5 +21,44 @@ API.v1.addRoute(
appearance,
});
},
async post() {
const settings = this.bodyParams;

const validSettingList = [
'Livechat_title',
'Livechat_title_color',
'Livechat_enable_message_character_limit',
'Livechat_message_character_limit',
'Livechat_show_agent_info',
'Livechat_show_agent_email',
'Livechat_display_offline_form',
'Livechat_offline_form_unavailable',
'Livechat_offline_message',
'Livechat_offline_success_message',
'Livechat_offline_title',
'Livechat_offline_title_color',
'Livechat_offline_email',
'Livechat_conversation_finished_message',
'Livechat_conversation_finished_text',
'Livechat_registration_form',
'Livechat_name_field_registration_form',
'Livechat_email_field_registration_form',
'Livechat_registration_form_message',
];

const valid = settings.every((setting) => validSettingList.includes(setting._id));

if (!valid) {
throw new Error('invalid-setting');
}

await Promise.all(
settings.map((setting) => {
return Settings.updateValueById(setting._id, setting.value);
}),
);

return API.v1.success();
},
},
);
23 changes: 21 additions & 2 deletions apps/meteor/app/livechat/imports/server/rest/triggers.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import { isGETLivechatTriggersParams } from '@rocket.chat/rest-typings';
import { LivechatTrigger } from '@rocket.chat/models';
import { isGETLivechatTriggersParams, isPOSTLivechatTriggersParams } from '@rocket.chat/rest-typings';

import { API } from '../../../../api/server';
import { getPaginationItems } from '../../../../api/server/helpers/getPaginationItems';
import { findTriggers, findTriggerById } from '../../../server/api/lib/triggers';

API.v1.addRoute(
'livechat/triggers',
{ authRequired: true, permissionsRequired: ['view-livechat-manager'], validateParams: isGETLivechatTriggersParams },
{
authRequired: true,
permissionsRequired: ['view-livechat-manager'],
validateParams: {
GET: isGETLivechatTriggersParams,
POST: isPOSTLivechatTriggersParams,
},
},
{
async get() {
const { offset, count } = await getPaginationItems(this.queryParams);
Expand All @@ -22,6 +30,17 @@ API.v1.addRoute(

return API.v1.success(triggers);
},
async post() {
const { _id, name, description, enabled, runOnce, conditions, actions } = this.bodyParams;

if (_id) {
await LivechatTrigger.updateById(_id, { name, description, enabled, runOnce, conditions, actions });
} else {
await LivechatTrigger.insertOne({ name, description, enabled, runOnce, conditions, actions });
}

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

Expand Down
47 changes: 46 additions & 1 deletion apps/meteor/app/livechat/server/api/v1/transcript.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { isPOSTLivechatTranscriptParams } from '@rocket.chat/rest-typings';
import type { IOmnichannelRoom } from '@rocket.chat/core-typings';
import { LivechatRooms, Users } from '@rocket.chat/models';
import { isPOSTLivechatTranscriptParams, isPOSTLivechatTranscriptRequestParams } from '@rocket.chat/rest-typings';

import { i18n } from '../../../../../server/lib/i18n';
import { API } from '../../../../api/server';
import { Livechat as LivechatJS } from '../../lib/Livechat';
import { Livechat } from '../../lib/LivechatTyped';

API.v1.addRoute(
Expand All @@ -18,3 +21,45 @@ API.v1.addRoute(
},
},
);

API.v1.addRoute(
'livechat/transcript/:rid',
{
authRequired: true,
permissionsRequired: ['send-omnichannel-chat-transcript'],
validateParams: {
POST: isPOSTLivechatTranscriptRequestParams,
},
},
{
async delete() {
const { rid } = this.urlParams;
const room = await LivechatRooms.findOneById<Pick<IOmnichannelRoom, 'open' | 'transcriptRequest'>>(rid, {
projection: { open: 1, transcriptRequest: 1 },
});

if (!room?.open) {
throw new Error('error-invalid-room');
}
if (!room.transcriptRequest) {
throw new Error('error-transcript-not-requested');
}

await LivechatRooms.unsetEmailTranscriptRequestedByRoomId(rid);

return API.v1.success();
},
async post() {
const { rid } = this.urlParams;
const { email, subject } = this.bodyParams;

const user = await Users.findOneById(this.userId, {
projection: { _id: 1, username: 1, name: 1, utcOffset: 1 },
});

await LivechatJS.requestTranscript({ rid, email, subject, user });

return API.v1.success();
},
},
);
2 changes: 2 additions & 0 deletions apps/meteor/app/livechat/server/methods/discardTranscript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';

import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';

declare module '@rocket.chat/ui-contexts' {
// eslint-disable-next-line @typescript-eslint/naming-convention
Expand All @@ -14,6 +15,7 @@ declare module '@rocket.chat/ui-contexts' {

Meteor.methods<ServerMethods>({
async 'livechat:discardTranscript'(rid: string) {
methodDeprecationLogger.method('livechat:discardTranscript', '7.0.0');
check(rid, String);

const user = Meteor.userId();
Expand Down
2 changes: 2 additions & 0 deletions apps/meteor/app/livechat/server/methods/requestTranscript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';

import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';
import { Livechat } from '../lib/Livechat';

declare module '@rocket.chat/ui-contexts' {
Expand All @@ -15,6 +16,7 @@ declare module '@rocket.chat/ui-contexts' {

Meteor.methods<ServerMethods>({
async 'livechat:requestTranscript'(rid, email, subject) {
methodDeprecationLogger.method('livechat:requestTranscript', '7.0.0');
check(rid, String);
check(email, String);

Expand Down
2 changes: 2 additions & 0 deletions apps/meteor/app/livechat/server/methods/saveAppearance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { ServerMethods } from '@rocket.chat/ui-contexts';
import { Meteor } from 'meteor/meteor';

import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';

declare module '@rocket.chat/ui-contexts' {
// eslint-disable-next-line @typescript-eslint/naming-convention
Expand All @@ -13,6 +14,7 @@ declare module '@rocket.chat/ui-contexts' {

Meteor.methods<ServerMethods>({
async 'livechat:saveAppearance'(settings) {
methodDeprecationLogger.method('livechat:saveAppearance', '7.0.0');
const uid = Meteor.userId();
if (!uid || !(await hasPermissionAsync(uid, 'view-livechat-manager'))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
Expand Down
2 changes: 2 additions & 0 deletions apps/meteor/app/livechat/server/methods/saveTrigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Match, check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';

import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';

declare module '@rocket.chat/ui-contexts' {
// eslint-disable-next-line @typescript-eslint/naming-convention
Expand All @@ -15,6 +16,7 @@ declare module '@rocket.chat/ui-contexts' {

Meteor.methods<ServerMethods>({
async 'livechat:saveTrigger'(trigger) {
methodDeprecationLogger.method('livechat:saveTrigger', '7.0.0');
const uid = Meteor.userId();
if (!uid || !(await hasPermissionAsync(uid, 'view-livechat-manager'))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ISetting, Serialized } from '@rocket.chat/core-typings';
import { ButtonGroup, Button, Box } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useToastMessageDispatch, useMethod, useTranslation } from '@rocket.chat/ui-contexts';
import { useToastMessageDispatch, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
import type { FC } from 'react';
import React from 'react';

Expand Down Expand Up @@ -47,12 +47,15 @@ const AppearancePage: FC<AppearancePageProps> = ({ settings }) => {
const t = useTranslation();
const dispatchToastMessage = useToastMessageDispatch();

const save = useMethod('livechat:saveAppearance');
const save = useEndpoint('POST', '/v1/livechat/appearance');

const { values, handlers, commit, reset, hasUnsavedChanges } = useForm(reduceAppearance(settings));

const handleSave = useMutableCallback(async () => {
const mappedAppearance = Object.entries(values).map(([_id, value]) => ({ _id, value }));
const mappedAppearance = Object.entries(values).map(([_id, value]) => ({ _id, value })) as {
_id: string;
value: string | boolean | number;
}[];

try {
await save(mappedAppearance);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FieldGroup, Button, ButtonGroup } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useToastMessageDispatch, useRoute, useMethod, useTranslation } from '@rocket.chat/ui-contexts';
import { useToastMessageDispatch, useRoute, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
import React from 'react';

import { ContextualbarScrollableContent, ContextualbarFooter } from '../../../components/Contextualbar';
Expand Down Expand Up @@ -44,7 +44,7 @@ const EditTriggerPage = ({ data, onSave }) => {

const router = useRoute('omnichannel-triggers');

const save = useMethod('livechat:saveTrigger');
const save = useEndpoint('POST', '/v1/livechat/triggers');

const { values, handlers, hasUnsavedChanges } = useForm(getInitialValues(data));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Button, FieldGroup, ButtonGroup } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useToastMessageDispatch, useRoute, useMethod, useTranslation } from '@rocket.chat/ui-contexts';
import { useToastMessageDispatch, useRoute, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
import React, { useMemo } from 'react';

import { ContextualbarScrollableContent, ContextualbarFooter } from '../../../components/Contextualbar';
Expand All @@ -13,7 +13,7 @@ const NewTriggerPage = ({ onSave }) => {

const router = useRoute('omnichannel-triggers');

const save = useMethod('livechat:saveTrigger');
const save = useEndpoint('POST', '/v1/livechat/triggers');

const { values, handlers } = useForm({
name: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ export const useQuickActions = (): {

const closeModal = useCallback(() => setModal(null), [setModal]);

const requestTranscript = useMethod('livechat:requestTranscript');
const requestTranscript = useEndpoint('POST', '/v1/livechat/transcript/:rid', { rid });

const handleRequestTranscript = useCallback(
async (email: string, subject: string) => {
try {
await requestTranscript(rid, email, subject);
await requestTranscript({ email, subject });
closeModal();
dispatchToastMessage({
type: 'success',
Expand All @@ -87,7 +87,7 @@ export const useQuickActions = (): {
dispatchToastMessage({ type: 'error', message: error });
}
},
[closeModal, dispatchToastMessage, requestTranscript, rid, t],
[closeModal, dispatchToastMessage, requestTranscript, t],
);

const sendTranscriptPDF = useEndpoint('POST', '/v1/omnichannel/:rid/request-transcript', { rid });
Expand Down Expand Up @@ -118,11 +118,11 @@ export const useQuickActions = (): {
[closeModal, dispatchToastMessage, rid, sendTranscript],
);

const discardTranscript = useMethod('livechat:discardTranscript');
const discardTranscript = useEndpoint('DELETE', '/v1/livechat/transcript/:rid', { rid });

const handleDiscardTranscript = useCallback(async () => {
try {
await discardTranscript(rid);
await discardTranscript();
dispatchToastMessage({
type: 'success',
message: t('Livechat_transcript_request_has_been_canceled'),
Expand All @@ -131,7 +131,7 @@ export const useQuickActions = (): {
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
}
}, [closeModal, discardTranscript, dispatchToastMessage, rid, t]);
}, [closeModal, discardTranscript, dispatchToastMessage, t]);

const forwardChat = useEndpoint('POST', '/v1/livechat/room.forward');

Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/server/models/raw/LivechatRooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ export class LivechatRoomsRaw extends BaseRaw<IOmnichannelRoom> implements ILive
};

const params = [...firstParams, usersGroup, project, facet];
return this.col.aggregate(params, { readPreference: readSecondaryPreferred() }).toArray();
return this.col.aggregate(params, { readPreference: readSecondaryPreferred(), allowDiskUse: true }).toArray();
}

async findAllNumberOfAbandonedRooms({
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/server/models/raw/LivechatTrigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class LivechatTriggerRaw extends BaseRaw<ILivechatTrigger> implements ILi
return this.find({ enabled: true });
}

updateById(_id: string, data: ILivechatTrigger): Promise<UpdateResult> {
updateById(_id: string, data: Omit<ILivechatTrigger, '_id' | '_updatedAt'>): Promise<UpdateResult> {
return this.updateOne({ _id }, { $set: data } as UpdateFilter<ILivechatTrigger>); // TODO: remove this cast when TypeScript is updated
}
}
Loading

0 comments on commit 06d24c1

Please sign in to comment.