From 00eb93463c8266e081f31544ec36910ee86f71b7 Mon Sep 17 00:00:00 2001 From: Marie <51697796+ijreilly@users.noreply.github.com> Date: Mon, 23 Jun 2025 19:35:08 +0200 Subject: [PATCH] [permissions V2] Fix - filter objects to search (#12803) In morph relation pickers, we were not taking into account permissions when computing the list of objects to search for, while we should not search for objects we don't have read permissions on (permission denied error) --- .../hooks/useCommandMenuSearchRecords.tsx | 20 ++++++++++++++++++- .../useMultipleRecordPickerPerformSearch.ts | 18 +++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuSearchRecords.tsx b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuSearchRecords.tsx index 3a7100537..137317653 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuSearchRecords.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuSearchRecords.tsx @@ -5,7 +5,9 @@ import { ActionType } from '@/action-menu/actions/types/ActionType'; import { MAX_SEARCH_RESULTS } from '@/command-menu/constants/MaxSearchResults'; import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu'; import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState'; +import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions'; import { AppPath } from '@/types/AppPath'; import { t } from '@lingui/core/macro'; import { useMemo } from 'react'; @@ -19,12 +21,28 @@ export const useCommandMenuSearchRecords = () => { const commandMenuSearch = useRecoilValue(commandMenuSearchState); const [deferredCommandMenuSearch] = useDebounce(commandMenuSearch, 300); + const { objectPermissionsByObjectMetadataId } = useObjectPermissions(); + const { objectMetadataItems } = useObjectMetadataItems(); + + const nonReadableObjectMetadataItemsNameSingular = useMemo(() => { + return Object.values(objectMetadataItems) + .filter((objectMetadataItem) => { + const objectPermission = + objectPermissionsByObjectMetadataId[objectMetadataItem.id]; + + return !objectPermission?.canReadObjectRecords; + }) + .map((objectMetadataItem) => objectMetadataItem.nameSingular); + }, [objectMetadataItems, objectPermissionsByObjectMetadataId]); const { data: searchData, loading } = useSearchQuery({ variables: { searchInput: deferredCommandMenuSearch ?? '', limit: MAX_SEARCH_RESULTS, - excludedObjectNameSingulars: ['workspaceMember'], + excludedObjectNameSingulars: [ + 'workspaceMember', + ...nonReadableObjectMetadataItemsNameSingular, + ], }, }); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch.ts index 789441eb7..c3e82d9e7 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch.ts @@ -1,5 +1,6 @@ import { SEARCH_QUERY } from '@/command-menu/graphql/queries/search'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions'; import { usePerformCombinedFindManyRecords } from '@/object-record/multiple-objects/hooks/usePerformCombinedFindManyRecords'; import { multipleRecordPickerIsLoadingComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerIsLoadingComponentState'; import { multipleRecordPickerPaginationState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPaginationState'; @@ -23,6 +24,8 @@ export const useMultipleRecordPickerPerformSearch = () => { const { performCombinedFindManyRecords } = usePerformCombinedFindManyRecords(); + const { objectPermissionsByObjectMetadataId } = useObjectPermissions(); + const performSearch = useRecoilCallback( ({ snapshot, set }) => async ({ @@ -97,6 +100,13 @@ export const useMultipleRecordPickerPerformSearch = () => { ({ isSelected }) => isSelected, ); + const filteredSearchableObjectMetadataItems = + searchableObjectMetadataItems.filter( + (objectMetadataItem) => + objectPermissionsByObjectMetadataId[objectMetadataItem.id] + .canReadObjectRecords === true, + ); + const [ searchRecordsFilteredOnPickedRecords, searchRecordsExcludingPickedRecords, @@ -104,7 +114,7 @@ export const useMultipleRecordPickerPerformSearch = () => { ] = await performSearchQueries({ client, searchFilter, - searchableObjectMetadataItems, + searchableObjectMetadataItems: filteredSearchableObjectMetadataItems, pickedRecordIds: selectedPickableMorphItems.map( ({ recordId }) => recordId, ), @@ -357,7 +367,11 @@ export const useMultipleRecordPickerPerformSearch = () => { false, ); }, - [client, performCombinedFindManyRecords], + [ + client, + performCombinedFindManyRecords, + objectPermissionsByObjectMetadataId, + ], ); return { performSearch };