[permissions] Adapt defaultPath to permissions (#12689)
We had two linked issues 1. default path was not taking permissions into account and could link to an object user does not have read access on's page 2. visiting the url of an object the user does not have read access on was possible and returned a "blank" page Before https://github.com/user-attachments/assets/e4da1de5-d7e9-4644-ba8e-cd366a9b0fad After https://github.com/user-attachments/assets/6576f662-d3a0-4173-8b48-233cc0a04cdf Also tested with V1.
This commit is contained in:
@ -2,6 +2,7 @@ import { renderHook } from '@testing-library/react';
|
||||
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
|
||||
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
@ -23,6 +24,9 @@ const renderHooks = ({
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const setCurrentUser = useSetRecoilState(currentUserState);
|
||||
const setCurrentUserWorkspace = useSetRecoilState(
|
||||
currentUserWorkspaceState,
|
||||
);
|
||||
const setObjectMetadataItems = useSetRecoilState(
|
||||
objectMetadataItemsState,
|
||||
);
|
||||
@ -56,6 +60,7 @@ const renderHooks = ({
|
||||
|
||||
if (withCurrentUser) {
|
||||
setCurrentUser(mockedUserData);
|
||||
setCurrentUserWorkspace(mockedUserData.currentUserWorkspace);
|
||||
}
|
||||
return useDefaultHomePagePath();
|
||||
},
|
||||
|
||||
@ -2,8 +2,11 @@ import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVisitedObjectMetadataItemIdState';
|
||||
import { ObjectPathInfo } from '@/navigation/types/ObjectPathInfo';
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@ -11,10 +14,23 @@ import { getAppPath } from '~/utils/navigation/getAppPath';
|
||||
|
||||
export const useDefaultHomePagePath = () => {
|
||||
const currentUser = useRecoilValue(currentUserState);
|
||||
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
|
||||
|
||||
const {
|
||||
activeNonSystemObjectMetadataItems,
|
||||
alphaSortedActiveNonSystemObjectMetadataItems,
|
||||
} = useFilteredObjectMetadataItems();
|
||||
|
||||
const readableAlphaSortedActiveNonSystemObjectMetadataItems = useMemo(() => {
|
||||
return alphaSortedActiveNonSystemObjectMetadataItems.filter((item) => {
|
||||
const objectPermissions = objectPermissionsByObjectMetadataId[item.id];
|
||||
return objectPermissions?.canReadObjectRecords;
|
||||
});
|
||||
}, [
|
||||
alphaSortedActiveNonSystemObjectMetadataItems,
|
||||
objectPermissionsByObjectMetadataId,
|
||||
]);
|
||||
|
||||
const prefetchViews = useRecoilValue(prefetchViewsState);
|
||||
const lastVisitedObjectMetadataItemId = useRecoilValue(
|
||||
lastVisitedObjectMetadataItemIdState,
|
||||
@ -39,7 +55,7 @@ export const useDefaultHomePagePath = () => {
|
||||
|
||||
const firstObjectPathInfo = useMemo<ObjectPathInfo | null>(() => {
|
||||
const [firstObjectMetadataItem] =
|
||||
alphaSortedActiveNonSystemObjectMetadataItems;
|
||||
readableAlphaSortedActiveNonSystemObjectMetadataItems;
|
||||
|
||||
if (!isDefined(firstObjectMetadataItem)) {
|
||||
return null;
|
||||
@ -48,10 +64,14 @@ export const useDefaultHomePagePath = () => {
|
||||
const view = getFirstView(firstObjectMetadataItem?.id);
|
||||
|
||||
return { objectMetadataItem: firstObjectMetadataItem, view };
|
||||
}, [alphaSortedActiveNonSystemObjectMetadataItems, getFirstView]);
|
||||
}, [readableAlphaSortedActiveNonSystemObjectMetadataItems, getFirstView]);
|
||||
|
||||
const defaultObjectPathInfo = useMemo<ObjectPathInfo | null>(() => {
|
||||
if (!isDefined(lastVisitedObjectMetadataItemId)) {
|
||||
if (
|
||||
!isDefined(lastVisitedObjectMetadataItemId) ||
|
||||
!objectPermissionsByObjectMetadataId[lastVisitedObjectMetadataItemId]
|
||||
?.canReadObjectRecords
|
||||
) {
|
||||
return firstObjectPathInfo;
|
||||
}
|
||||
|
||||
@ -72,6 +92,7 @@ export const useDefaultHomePagePath = () => {
|
||||
getActiveObjectMetadataItemMatchingId,
|
||||
getFirstView,
|
||||
lastVisitedObjectMetadataItemId,
|
||||
objectPermissionsByObjectMetadataId,
|
||||
]);
|
||||
|
||||
const defaultHomePagePath = useMemo(() => {
|
||||
@ -79,6 +100,10 @@ export const useDefaultHomePagePath = () => {
|
||||
return AppPath.SignInUp;
|
||||
}
|
||||
|
||||
if (isEmpty(readableAlphaSortedActiveNonSystemObjectMetadataItems)) {
|
||||
return `${AppPath.Settings}/${SettingsPath.ProfilePage}`;
|
||||
}
|
||||
|
||||
if (!isDefined(defaultObjectPathInfo)) {
|
||||
return AppPath.NotFound;
|
||||
}
|
||||
@ -91,7 +116,11 @@ export const useDefaultHomePagePath = () => {
|
||||
{ objectNamePlural: namePlural },
|
||||
viewId ? { viewId } : undefined,
|
||||
);
|
||||
}, [currentUser, defaultObjectPathInfo]);
|
||||
}, [
|
||||
currentUser,
|
||||
defaultObjectPathInfo,
|
||||
readableAlphaSortedActiveNonSystemObjectMetadataItems,
|
||||
]);
|
||||
|
||||
return { defaultHomePagePath };
|
||||
};
|
||||
|
||||
@ -5,6 +5,8 @@ import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionM
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
@ -23,8 +25,7 @@ import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewCompon
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { NotFound } from '~/pages/not-found/NotFound';
|
||||
|
||||
const StyledIndexContainer = styled.div`
|
||||
display: flex;
|
||||
@ -68,7 +69,7 @@ export const RecordIndexContainerGater = () => {
|
||||
const hasObjectReadPermissions = objectPermissions.canReadObjectRecords;
|
||||
|
||||
if (!hasObjectReadPermissions) {
|
||||
return <></>;
|
||||
return <NotFound />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@ -128,6 +128,12 @@ export const mockedUserData: MockedUser = {
|
||||
currentWorkspace: mockCurrentWorkspace,
|
||||
currentUserWorkspace: {
|
||||
settingsPermissions: [SettingPermissionType.WORKSPACE_MEMBERS],
|
||||
objectPermissions: [
|
||||
{
|
||||
objectMetadataId: '4a45f524-b8cb-40e8-8450-28e402b442cf',
|
||||
canReadObjectRecords: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
locale: 'en',
|
||||
workspaces: [{ workspace: mockCurrentWorkspace }],
|
||||
|
||||
Reference in New Issue
Block a user