From 5f1475b78259c1b5a117c6bf31ec94ecaf665a0f Mon Sep 17 00:00:00 2001 From: Aleksander Nicacio da Silva Date: Wed, 4 Oct 2023 18:15:56 -0300 Subject: [PATCH 1/3] fix: inconsistent behavior when removing subscriptions and inquiries --- .../client/lib/stream/queueManager.ts | 9 ++++++-- .../client/views/room/hooks/useOpenRoom.ts | 10 +++++++++ .../views/room/providers/RoomProvider.tsx | 22 ++----------------- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/apps/meteor/app/livechat/client/lib/stream/queueManager.ts b/apps/meteor/app/livechat/client/lib/stream/queueManager.ts index 28d09958535a..a82b8026386d 100644 --- a/apps/meteor/app/livechat/client/lib/stream/queueManager.ts +++ b/apps/meteor/app/livechat/client/lib/stream/queueManager.ts @@ -13,13 +13,18 @@ const events = { }, changed: async (inquiry: ILivechatInquiryRecord) => { if (inquiry.status !== 'queued' || (inquiry.department && !departments.has(inquiry.department))) { - return LivechatInquiry.remove(inquiry._id); + return removeInquiry(inquiry); } LivechatInquiry.upsert({ _id: inquiry._id }, { ...inquiry, alert: true, _updatedAt: new Date(inquiry._updatedAt) }); await queryClient.invalidateQueries(['/v1/rooms.info', inquiry.rid]); }, - removed: (inquiry: ILivechatInquiryRecord) => LivechatInquiry.remove(inquiry._id), + removed: (inquiry: ILivechatInquiryRecord) => removeInquiry(inquiry), +}; + +const removeInquiry = async (inquiry: ILivechatInquiryRecord) => { + await queryClient.invalidateQueries(['rooms', { reference: inquiry.rid, type: 'l' }]); + return LivechatInquiry.remove(inquiry._id); }; const getInquiriesFromAPI = async () => { diff --git a/apps/meteor/client/views/room/hooks/useOpenRoom.ts b/apps/meteor/client/views/room/hooks/useOpenRoom.ts index c2b694414002..d529145aaf17 100644 --- a/apps/meteor/client/views/room/hooks/useOpenRoom.ts +++ b/apps/meteor/client/views/room/hooks/useOpenRoom.ts @@ -8,6 +8,7 @@ import { omit } from '../../../../lib/utils/omit'; import { NotAuthorizedError } from '../../../lib/errors/NotAuthorizedError'; import { OldUrlRoomError } from '../../../lib/errors/OldUrlRoomError'; import { RoomNotFoundError } from '../../../lib/errors/RoomNotFoundError'; +import { queryClient } from '../../../lib/queryClient'; export function useOpenRoom({ type, reference }: { type: RoomType; reference: string }) { const user = useUser(); @@ -102,6 +103,15 @@ export function useOpenRoom({ type, reference }: { type: RoomType; reference: st }, { retry: 0, + onError: async (error) => { + if (['l', 'v'].includes(type) && error instanceof RoomNotFoundError) { + const { ChatRoom } = await import('../../../../app/models/client'); + + ChatRoom.remove(reference); + queryClient.removeQueries(['rooms', reference]); + queryClient.removeQueries(['/v1/rooms.info', reference]); + } + }, }, ); } diff --git a/apps/meteor/client/views/room/providers/RoomProvider.tsx b/apps/meteor/client/views/room/providers/RoomProvider.tsx index e19fa8136f59..beaf40584ce2 100644 --- a/apps/meteor/client/views/room/providers/RoomProvider.tsx +++ b/apps/meteor/client/views/room/providers/RoomProvider.tsx @@ -1,10 +1,10 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { usePermission, useStream, useUserId, useRouter } from '@rocket.chat/ui-contexts'; +import { useStream, useRouter } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import type { ReactNode, ContextType, ReactElement } from 'react'; import React, { useMemo, memo, useEffect, useCallback } from 'react'; -import { ChatRoom, ChatSubscription } from '../../../../app/models/client'; +import { ChatSubscription } from '../../../../app/models/client'; import { RoomHistoryManager } from '../../../../app/ui-utils/client'; import { UserAction } from '../../../../app/ui/client/lib/UserAction'; import { useReactiveQuery } from '../../../hooks/useReactiveQuery'; @@ -32,8 +32,6 @@ const RoomProvider = ({ rid, children }: RoomProviderProps): ReactElement => { const subscribeToRoom = useStream('room-data'); const queryClient = useQueryClient(); - const userId = useUserId(); - const isLivechatAdmin = usePermission('view-livechat-rooms'); const { t: roomType } = room ?? {}; // TODO: move this to omnichannel context only @@ -55,22 +53,6 @@ const RoomProvider = ({ rid, children }: RoomProviderProps): ReactElement => { } }, [isSuccess, room, router]); - const { _id: servedById } = room?.servedBy ?? {}; - - // TODO: Review the necessity of this effect when we move away from cached collections - useEffect(() => { - if (roomType !== 'l' || !servedById) { - return; - } - - if (!isLivechatAdmin && servedById !== userId) { - ChatRoom.remove(rid); - queryClient.removeQueries(['rooms', rid]); - queryClient.removeQueries(['rooms', { reference: rid, type: 'l' }]); - queryClient.removeQueries(['/v1/rooms.info', rid]); - } - }, [isLivechatAdmin, queryClient, userId, rid, roomType, servedById]); - const subscriptionQuery = useReactiveQuery(['subscriptions', { rid }], () => ChatSubscription.findOne({ rid }) ?? null); const pseudoRoom = useMemo(() => { From 118f9e260ee4add53c31174642f3f76c8747d945 Mon Sep 17 00:00:00 2001 From: Aleksander Nicacio da Silva Date: Wed, 4 Oct 2023 18:17:46 -0300 Subject: [PATCH 2/3] chore: changeset --- .changeset/long-cars-dream.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/long-cars-dream.md diff --git a/.changeset/long-cars-dream.md b/.changeset/long-cars-dream.md new file mode 100644 index 000000000000..95f226d6dfb4 --- /dev/null +++ b/.changeset/long-cars-dream.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixed intermittent errors caused by the removal of subscriptions and inquiries when lacking permissions. From e8dfb9c258427a7f4ff52c0e43d64ef05f32c555 Mon Sep 17 00:00:00 2001 From: Aleksander Nicacio da Silva Date: Tue, 17 Oct 2023 11:41:03 -0300 Subject: [PATCH 3/3] fix: adjusted room query invalidation --- .../client/lib/stream/queueManager.ts | 21 ++++++++++++++----- .../views/room/providers/RoomProvider.tsx | 19 +---------------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/apps/meteor/app/livechat/client/lib/stream/queueManager.ts b/apps/meteor/app/livechat/client/lib/stream/queueManager.ts index a82b8026386d..906ace402bb9 100644 --- a/apps/meteor/app/livechat/client/lib/stream/queueManager.ts +++ b/apps/meteor/app/livechat/client/lib/stream/queueManager.ts @@ -8,8 +8,13 @@ import { LivechatInquiry } from '../../collections/LivechatInquiry'; const departments = new Set(); const events = { - added: (inquiry: ILivechatInquiryRecord) => { - departments.has(inquiry.department) && LivechatInquiry.insert({ ...inquiry, alert: true, _updatedAt: new Date(inquiry._updatedAt) }); + added: async (inquiry: ILivechatInquiryRecord) => { + if (!departments.has(inquiry.department)) { + return; + } + + LivechatInquiry.insert({ ...inquiry, alert: true, _updatedAt: new Date(inquiry._updatedAt) }); + await invalidateRoomQueries(inquiry.rid); }, changed: async (inquiry: ILivechatInquiryRecord) => { if (inquiry.status !== 'queued' || (inquiry.department && !departments.has(inquiry.department))) { @@ -17,14 +22,20 @@ const events = { } LivechatInquiry.upsert({ _id: inquiry._id }, { ...inquiry, alert: true, _updatedAt: new Date(inquiry._updatedAt) }); - await queryClient.invalidateQueries(['/v1/rooms.info', inquiry.rid]); + await invalidateRoomQueries(inquiry.rid); }, removed: (inquiry: ILivechatInquiryRecord) => removeInquiry(inquiry), }; +const invalidateRoomQueries = async (rid: string) => { + await queryClient.invalidateQueries(['rooms', { reference: rid, type: 'l' }]); + await queryClient.removeQueries(['rooms', rid]); + await queryClient.removeQueries(['/v1/rooms.info', rid]); +}; + const removeInquiry = async (inquiry: ILivechatInquiryRecord) => { - await queryClient.invalidateQueries(['rooms', { reference: inquiry.rid, type: 'l' }]); - return LivechatInquiry.remove(inquiry._id); + await LivechatInquiry.remove(inquiry._id); + return queryClient.invalidateQueries(['rooms', { reference: inquiry.rid, type: 'l' }]); }; const getInquiriesFromAPI = async () => { diff --git a/apps/meteor/client/views/room/providers/RoomProvider.tsx b/apps/meteor/client/views/room/providers/RoomProvider.tsx index beaf40584ce2..82c66c6f5d8d 100644 --- a/apps/meteor/client/views/room/providers/RoomProvider.tsx +++ b/apps/meteor/client/views/room/providers/RoomProvider.tsx @@ -1,6 +1,5 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { useStream, useRouter } from '@rocket.chat/ui-contexts'; -import { useQueryClient } from '@tanstack/react-query'; +import { useRouter } from '@rocket.chat/ui-contexts'; import type { ReactNode, ContextType, ReactElement } from 'react'; import React, { useMemo, memo, useEffect, useCallback } from 'react'; @@ -29,22 +28,6 @@ const RoomProvider = ({ rid, children }: RoomProviderProps): ReactElement => { const { data: room, isSuccess } = useRoomQuery(rid); - const subscribeToRoom = useStream('room-data'); - - const queryClient = useQueryClient(); - const { t: roomType } = room ?? {}; - - // TODO: move this to omnichannel context only - useEffect(() => { - if (roomType !== 'l') { - return; - } - - return subscribeToRoom(rid, (room) => { - queryClient.setQueryData(['rooms', rid], room); - }); - }, [subscribeToRoom, rid, queryClient, roomType]); - // TODO: the following effect is a workaround while we don't have a general and definitive solution for it const router = useRouter(); useEffect(() => {