Fix (#6971) UI : Add Permission Provider (#6972)

* Fix (#6971)  UI : Add Permission Provider

* Fix description unit test

* Fix unit tests

* Addressing review comments

* Add checkPermission util

* Add permission for protected route

* Clean up

* Fix rule condition validation issue
This commit is contained in:
Sachin Chaurasiya 2022-08-27 16:05:57 +05:30 committed by GitHub
parent 5cefe1bfbb
commit 1081254f7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 424 additions and 66 deletions

View File

@ -31,6 +31,7 @@ import 'react-toastify/dist/ReactToastify.min.css';
import { AuthProvider } from './authentication/auth-provider/AuthProvider';
import Appbar from './components/app-bar/Appbar';
import GlobalSearchProvider from './components/GlobalSearchProvider/GlobalSearchProvider';
import PermissionProvider from './components/PermissionProvider/PermissionProvider';
import WebSocketProvider from './components/web-scoket/web-scoket.provider';
import { toastOptions } from './constants/toast.constants';
import ErrorBoundry from './ErrorBoundry/ErrorBoundry';
@ -56,12 +57,14 @@ const App: FunctionComponent = () => {
<Router>
<ErrorBoundry>
<AuthProvider childComponentType={AppRouter}>
<WebSocketProvider>
<GlobalSearchProvider>
<Appbar />
<AppRouter />
</GlobalSearchProvider>
</WebSocketProvider>
<PermissionProvider>
<WebSocketProvider>
<GlobalSearchProvider>
<Appbar />
<AppRouter />
</GlobalSearchProvider>
</WebSocketProvider>
</PermissionProvider>
</AuthProvider>
</ErrorBoundry>
</Router>

View File

@ -30,9 +30,11 @@ import {
GlobalSettingOptions,
GlobalSettingsMenuCategory,
} from '../../constants/globalSettings.constants';
import { Operation } from '../../generated/entity/policies/accessControl/rule';
import { JWTTokenExpiry, User } from '../../generated/entity/teams/user';
import { EntityReference } from '../../generated/type/entityReference';
import { getEntityName, requiredField } from '../../utils/CommonUtils';
import { checkPemission } from '../../utils/PermissionsUtils';
import { getSettingPath } from '../../utils/RouterUtils';
import SVGIcons, { Icons } from '../../utils/SvgUtils';
import { showErrorToast } from '../../utils/ToastUtils';
@ -43,6 +45,8 @@ import { reactSingleSelectCustomStyle } from '../common/react-select-component/r
import TitleBreadcrumb from '../common/title-breadcrumb/title-breadcrumb.component';
import PageLayout, { leftPanelAntCardStyle } from '../containers/PageLayout';
import ConfirmationModal from '../Modals/ConfirmationModal/ConfirmationModal';
import { usePermissionProvider } from '../PermissionProvider/PermissionProvider';
import { ResourceEntity } from '../PermissionProvider/PermissionProvider.interface';
import { UserDetails } from '../Users/Users.interface';
interface BotsDetailProp extends HTMLAttributes<HTMLDivElement> {
@ -61,6 +65,7 @@ const BotDetails: FC<BotsDetailProp> = ({
updateBotsDetails,
revokeTokenHandler,
}) => {
const { permissions } = usePermissionProvider();
const [displayName, setDisplayName] = useState(botsData.displayName);
const [isDisplayNameEdit, setIsDisplayNameEdit] = useState(false);
const [isDescriptionEdit, setIsDescriptionEdit] = useState(false);
@ -72,6 +77,23 @@ const BotDetails: FC<BotsDetailProp> = ({
const [generateToken, setGenerateToken] = useState<boolean>(false);
const [selectedExpiry, setSelectedExpiry] = useState('7');
const editAllPermission = checkPemission(
Operation.EditAll,
ResourceEntity.BOT,
permissions
);
const displayNamePermission = checkPemission(
Operation.EditDisplayName,
ResourceEntity.BOT,
permissions
);
const descriptionPermission = checkPemission(
Operation.EditDescription,
ResourceEntity.BOT,
permissions
);
const getJWTTokenExpiryOptions = () => {
return Object.keys(JWTTokenExpiry).map((expiry) => {
const expiryValue = JWTTokenExpiry[expiry as keyof typeof JWTTokenExpiry];
@ -209,13 +231,19 @@ const BotDetails: FC<BotsDetailProp> = ({
Add display name
</span>
)}
<button
className="tw-ml-2 focus:tw-outline-none"
data-testid="edit-displayName"
onClick={() => setIsDisplayNameEdit(true)}>
<SVGIcons alt="edit" icon="icon-edit" title="Edit" width="16px" />
</button>
{(displayNamePermission || editAllPermission) && (
<button
className="tw-ml-2 focus:tw-outline-none"
data-testid="edit-displayName"
onClick={() => setIsDisplayNameEdit(true)}>
<SVGIcons
alt="edit"
icon="icon-edit"
title="Edit"
width="16px"
/>
</button>
)}
</Fragment>
)}
</div>
@ -226,9 +254,9 @@ const BotDetails: FC<BotsDetailProp> = ({
return (
<div className="tw--ml-5">
<Description
hasEditAccess
description={botsData.description || ''}
entityName={getEntityName(botsData as unknown as EntityReference)}
hasEditAccess={descriptionPermission || editAllPermission}
isEdit={isDescriptionEdit}
onCancel={() => setIsDescriptionEdit(false)}
onDescriptionEdit={() => setIsDescriptionEdit(true)}
@ -407,7 +435,7 @@ const BotDetails: FC<BotsDetailProp> = ({
<h6 className="tw-mb-2 tw-self-center">
{generateToken ? 'Generate JWT token' : 'JWT Token'}
</h6>
{!generateToken ? (
{!generateToken && editAllPermission ? (
<div className="tw-flex">
<Button
data-testid="generate-token"

View File

@ -68,6 +68,26 @@ const mockProp = {
updateBotsDetails,
};
jest.mock('../PermissionProvider/PermissionProvider', () => ({
usePermissionProvider: jest.fn().mockReturnValue({
permissions: {
bot: {
Create: true,
Delete: true,
ViewAll: true,
EditAll: true,
EditDescription: true,
EditDisplayName: true,
EditCustomFields: true,
},
},
}),
}));
jest.mock('../../utils/PermissionsUtils', () => ({
checkPemission: jest.fn().mockReturnValue(true),
}));
jest.mock('../../axiosAPIs/userAPI', () => {
return {
generateUserToken: jest

View File

@ -24,22 +24,33 @@ import {
} from '../../constants/constants';
import { EntityType } from '../../enums/entity.enum';
import { Bot } from '../../generated/entity/bot';
import { Operation } from '../../generated/entity/policies/accessControl/rule';
import { Include } from '../../generated/type/include';
import { Paging } from '../../generated/type/paging';
import { checkPemission } from '../../utils/PermissionsUtils';
import SVGIcons, { Icons } from '../../utils/SvgUtils';
import { showErrorToast } from '../../utils/ToastUtils';
import DeleteWidgetModal from '../common/DeleteWidget/DeleteWidgetModal';
import NextPrevious from '../common/next-previous/NextPrevious';
import Loader from '../Loader/Loader';
import { usePermissionProvider } from '../PermissionProvider/PermissionProvider';
import { ResourceEntity } from '../PermissionProvider/PermissionProvider.interface';
import { BotListV1Props } from './BotListV1.interfaces';
const BotListV1 = ({ showDeleted }: BotListV1Props) => {
const { permissions } = usePermissionProvider();
const [botUsers, setBotUsers] = useState<Bot[]>([]);
const [paging, setPaging] = useState<Paging>({} as Paging);
const [selectedUser, setSelectedUser] = useState<Bot>();
const [loading, setLoading] = useState(true);
const [currentPage, setCurrentPage] = useState<number>(INITIAL_PAGING_VALUE);
const deletePermission = checkPemission(
Operation.Delete,
ResourceEntity.BOT,
permissions
);
/**
*
* @param after - Pagination value if passed data will be fetched post cursor value
@ -90,8 +101,15 @@ const BotListV1 = ({ showDeleted }: BotListV1Props) => {
width: 90,
render: (_, record) => (
<Space align="center" size={8}>
<Tooltip placement="bottom" title="Delete">
<Tooltip
placement="bottom"
title={
deletePermission
? 'Delete'
: 'You do not have permissions to perform this action.'
}>
<Button
disabled={!deletePermission}
icon={
<SVGIcons
alt="Delete"

View File

@ -0,0 +1,47 @@
import { Operation } from '../../generated/entity/policies/accessControl/resourcePermission';
export type UIPermission = {
[key in ResourceEntity]: OperationPermission;
};
export type OperationPermission = {
[key in Operation]: boolean;
};
export enum ResourceEntity {
ALL = 'all',
BOT = 'bot',
CHART = 'chart',
DASHBOARD = 'dashboard',
DASHBOARDSERVICE = 'dashboardService',
DATABASE = 'database',
DATABASESCHEMA = 'databaseSchema',
DATABASESERVICE = 'databaseService',
EVENTS = 'events',
FEED = 'feed',
GLOSSARY = 'glossary',
GLOSSARYTERM = 'glossaryTerm',
INGESTIONPIPELINE = 'ingestionPipeline',
LOCATION = 'location',
MESSAGINGSERVICE = 'messagingService',
METRICS = 'metrics',
MLMODEL = 'mlmodel',
MLMODELSERVICE = 'mlmodelService',
PIPELINE = 'pipeline',
PIPELINESERVICE = 'pipelineService',
POLICY = 'policy',
REPORT = 'report',
ROLE = 'role',
STORAGESERVICE = 'storageService',
TABLE = 'table',
TAG = 'tag',
TAGCATEGORY = 'tagCategory',
TEAM = 'team',
TESTCASE = 'testCase',
TESTDEFINITION = 'testDefinition',
TESTSUITE = 'testSuite',
TOPIC = 'topic',
TYPE = 'type',
USER = 'user',
WEBHOOK = 'webhook',
}

View File

@ -0,0 +1,89 @@
/*
* Copyright 2021 Collate
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AxiosError } from 'axios';
import { observer } from 'mobx-react';
import React, {
createContext,
FC,
ReactNode,
useContext,
useEffect,
useMemo,
useState,
} from 'react';
import AppState from '../../AppState';
import { getLoggedInUserPermissions } from '../../axiosAPIs/miscAPI';
import { getUIPermission } from '../../utils/PermissionsUtils';
import { showErrorToast } from '../../utils/ToastUtils';
import { UIPermission } from './PermissionProvider.interface';
/**
* Permission Context
* Returns ResourcePermission List for loggedIn User
* @returns PermissionMap
*/
export const PermissionContext = createContext<{
permissions: UIPermission;
}>({ permissions: {} as UIPermission });
interface PermissionProviderProps {
children: ReactNode;
}
/**
*
* @param children:ReactNode
* @returns JSX
*/
const PermissionProvider: FC<PermissionProviderProps> = ({ children }) => {
const [permissions, setPermissions] = useState<UIPermission>(
{} as UIPermission
);
// Update current user details of AppState change
const currentUser = useMemo(() => {
return AppState.getCurrentUserDetails();
}, [AppState.userDetails, AppState.nonSecureUserDetails]);
/**
* Fetch permission for logged in user
*/
const fetchLoggedInUserPermissions = async () => {
try {
const response = await getLoggedInUserPermissions();
setPermissions(getUIPermission(response.data || []));
} catch (error) {
showErrorToast(error as AxiosError);
}
};
useEffect(() => {
/**
* Only fetch permission if user is logged In
*/
if (currentUser && currentUser.id) {
fetchLoggedInUserPermissions();
}
}, [currentUser]);
return (
<PermissionContext.Provider value={{ permissions }}>
{children}
</PermissionContext.Provider>
);
};
export const usePermissionProvider = () => useContext(PermissionContext);
export default observer(PermissionProvider);

View File

@ -93,9 +93,12 @@ jest.mock('../non-admin-action/NonAdminAction', () => {
describe('Test Description Component', () => {
it('Check if it has all child elements', async () => {
const { container } = render(<Description {...mockDescriptionProp} />, {
wrapper: MemoryRouter,
});
const { container } = render(
<Description {...mockDescriptionProp} hasEditAccess />,
{
wrapper: MemoryRouter,
}
);
const descriptionContainer = await findByTestId(container, 'description');
const editDescriptionButton = await findByTestId(
@ -236,4 +239,19 @@ describe('Test Description Component', () => {
// should render requestDescription, as description thread and description are empty value
expect(requestDescription).toBeInTheDocument();
});
it('Should not show edit button if hasEditAccess is false', async () => {
const { container } = render(
<Description {...mockDescriptionProp} hasEditAccess={false} />,
{
wrapper: MemoryRouter,
}
);
const descriptionContainer = await findByTestId(container, 'description');
const editDescriptionButton = queryByTestId(container, 'edit-description');
expect(descriptionContainer).toBeInTheDocument();
expect(editDescriptionButton).toBeNull();
});
});

View File

@ -17,15 +17,11 @@ import { isUndefined } from 'lodash';
import { EntityFieldThreads } from 'Models';
import React, { FC, Fragment } from 'react';
import { useHistory } from 'react-router-dom';
import { useAuthContext } from '../../../authentication/auth-provider/AuthProvider';
import { EntityField } from '../../../constants/feed.constants';
import { EntityType } from '../../../enums/entity.enum';
import { ThreadType } from '../../../generated/entity/feed/thread';
import { Operation } from '../../../generated/entity/policies/accessControl/rule';
import { useAuth } from '../../../hooks/authHooks';
import { isTaskSupported } from '../../../utils/CommonUtils';
import { getEntityFeedLink } from '../../../utils/EntityUtils';
import { hasPemission } from '../../../utils/PermissionsUtils';
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
import {
getRequestDescriptionPath,
@ -54,9 +50,6 @@ const Description: FC<DescriptionProps> = ({
}) => {
const history = useHistory();
const { isAdminUser, userPermissions } = useAuth();
const { isAuthDisabled } = useAuthContext();
const thread = entityFieldThreads?.[0];
const tasks = entityFieldTasks?.[0];
@ -72,19 +65,6 @@ const Description: FC<DescriptionProps> = ({
);
};
const checkPermission = () => {
return (
isAdminUser ||
Boolean(hasEditAccess) ||
hasPemission(
Operation.EditDescription,
entityType as EntityType,
userPermissions
) ||
isAuthDisabled
);
};
const handleUpdate = () => {
onDescriptionEdit && onDescriptionEdit();
};
@ -179,7 +159,7 @@ const Description: FC<DescriptionProps> = ({
const DescriptionActions = () => {
return !isReadOnly ? (
<div className={classNames('tw-w-5 tw-min-w-max tw-flex tw--mt-1')}>
{checkPermission() && (
{hasEditAccess && (
<button
className="tw-w-7 tw-h-8 tw-flex-none focus:tw-outline-none"
data-testid="edit-description"

View File

@ -11,13 +11,18 @@
* limitations under the License.
*/
import { Button, Col, Row, Space, Switch } from 'antd';
import { Button, Col, Empty, Row, Space, Switch } from 'antd';
import React, { useState } from 'react';
import { useHistory } from 'react-router-dom';
import BotListV1 from '../../components/BotListV1/BotListV1.component';
import { usePermissionProvider } from '../../components/PermissionProvider/PermissionProvider';
import { ResourceEntity } from '../../components/PermissionProvider/PermissionProvider.interface';
import { getCreateUserPath } from '../../constants/constants';
import { Operation } from '../../generated/entity/policies/accessControl/rule';
import { checkPemission } from '../../utils/PermissionsUtils';
export const BotsPageV1 = () => {
const { permissions } = usePermissionProvider();
const history = useHistory();
const [showDeleted, setShowDeleted] = useState(false);
@ -29,28 +34,49 @@ export const BotsPageV1 = () => {
setShowDeleted(checked);
};
const viewAllPermission = checkPemission(
Operation.ViewAll,
ResourceEntity.BOT,
permissions
);
const createPermission = checkPemission(
Operation.Create,
ResourceEntity.BOT,
permissions
);
return (
<Row gutter={[16, 16]}>
<Col flex={1} />
<Col>
<Space size={16}>
<Space align="end" size={5}>
<Switch
checked={showDeleted}
id="switch-deleted"
size="small"
onClick={handleShowDeleted}
/>
<label htmlFor="switch-deleted">Show deleted</label>
</Space>
<Button type="primary" onClick={handleAddBotClick}>
Add Bot
</Button>
</Space>
</Col>
<Col span={24}>
<BotListV1 showDeleted={showDeleted} />
</Col>
{viewAllPermission ? (
<>
<Col flex={1} />
<Col>
<Space size={16}>
<Space align="end" size={5}>
<Switch
checked={showDeleted}
id="switch-deleted"
size="small"
onClick={handleShowDeleted}
/>
<label htmlFor="switch-deleted">Show deleted</label>
</Space>
{createPermission && (
<Button type="primary" onClick={handleAddBotClick}>
Add Bot
</Button>
)}
</Space>
</Col>
<Col span={24}>
<BotListV1 showDeleted={showDeleted} />
</Col>
</>
) : (
<Empty description="You do not have permission to view data" />
)}
</Row>
);
};

View File

@ -80,11 +80,12 @@ const AddPolicyPage = () => {
};
const handleSumbit = async () => {
const { condition, ...rest } = ruleData;
const data: CreatePolicy = {
name,
description,
policyType: PolicyType.AccessControl,
rules: [ruleData],
rules: [condition ? { ...rest, condition } : rest],
};
try {

View File

@ -87,9 +87,10 @@ const AddRulePage = () => {
};
const handleSubmit = async () => {
const { condition, ...rest } = ruleData;
const patch = compare(policy, {
...policy,
rules: [...policy.rules, ruleData],
rules: [...policy.rules, condition ? { ...rest, condition } : rest],
});
try {
const data = await patchPolicy(patch, policy.id);

View File

@ -98,11 +98,14 @@ const EditRulePage = () => {
const existingRules = policy.rules;
const updatedRules = existingRules.map((rule) => {
if (rule.name === ruleName) {
return ruleData;
const { condition, ...rest } = ruleData;
return condition ? { ...rest, condition } : rest;
} else {
return rule;
}
});
const patch = compare(policy, {
...policy,
rules: updatedRules,

View File

@ -17,11 +17,15 @@ import { useAuthContext } from '../authentication/auth-provider/AuthProvider';
import { ROUTES } from '../constants/constants';
import { useAuth } from '../hooks/authHooks';
const AdminProtectedRoute = (routeProps: RouteProps) => {
interface AdminProtectedRouteProps extends RouteProps {
hasPermission: boolean;
}
const AdminProtectedRoute = (routeProps: AdminProtectedRouteProps) => {
const { isAdminUser } = useAuth();
const { isAuthDisabled, isAuthenticated } = useAuthContext();
if (isAuthDisabled || isAdminUser) {
if (isAuthDisabled || isAdminUser || routeProps.hasPermission) {
return <Route {...routeProps} />;
} else if (isAuthenticated) {
return <Redirect to={ROUTES.NOT_FOUND} />;

View File

@ -13,11 +13,15 @@
import React from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';
import { usePermissionProvider } from '../components/PermissionProvider/PermissionProvider';
import { ResourceEntity } from '../components/PermissionProvider/PermissionProvider.interface';
import {
GlobalSettingOptions,
GlobalSettingsMenuCategory,
} from '../constants/globalSettings.constants';
import { Operation } from '../generated/entity/policies/policy';
import TeamsPage from '../pages/teams/TeamsPage';
import { checkPemission } from '../utils/PermissionsUtils';
import { getSettingCategoryPath, getSettingPath } from '../utils/RouterUtils';
import AdminProtectedRoute from './AdminProtectedRoute';
import withSuspenseFallback from './withSuspenseFallback';
@ -64,6 +68,8 @@ const SlackSettingsPage = withSuspenseFallback(
);
const GlobalSettingRouter = () => {
const { permissions } = usePermissionProvider();
return (
<Switch>
<Route exact path={getSettingPath()}>
@ -97,6 +103,11 @@ const GlobalSettingRouter = () => {
<AdminProtectedRoute
exact
component={RolesListPage}
hasPermission={checkPemission(
Operation.ViewAll,
ResourceEntity.ROLE,
permissions
)}
path={getSettingPath(
GlobalSettingsMenuCategory.ACCESS,
GlobalSettingOptions.ROLES
@ -106,6 +117,11 @@ const GlobalSettingRouter = () => {
<AdminProtectedRoute
exact
component={RolesDetailPage}
hasPermission={checkPemission(
Operation.ViewAll,
ResourceEntity.ROLE,
permissions
)}
path={getSettingPath(
GlobalSettingsMenuCategory.ACCESS,
GlobalSettingOptions.ROLES,
@ -119,6 +135,11 @@ const GlobalSettingRouter = () => {
<AdminProtectedRoute
exact
component={PoliciesListPage}
hasPermission={checkPemission(
Operation.ViewAll,
ResourceEntity.POLICY,
permissions
)}
path={getSettingPath(
GlobalSettingsMenuCategory.ACCESS,
GlobalSettingOptions.POLICIES
@ -127,6 +148,11 @@ const GlobalSettingRouter = () => {
<AdminProtectedRoute
exact
component={PoliciesDetailPage}
hasPermission={checkPemission(
Operation.ViewAll,
ResourceEntity.POLICY,
permissions
)}
path={getSettingPath(
GlobalSettingsMenuCategory.ACCESS,
GlobalSettingOptions.POLICIES,
@ -136,12 +162,22 @@ const GlobalSettingRouter = () => {
<AdminProtectedRoute
exact
component={UserListPageV1}
hasPermission={checkPemission(
Operation.ViewAll,
ResourceEntity.USER,
permissions
)}
path={getSettingCategoryPath(GlobalSettingsMenuCategory.MEMBERS)}
/>
<AdminProtectedRoute
exact
component={WebhooksPageV1}
hasPermission={checkPemission(
Operation.ViewAll,
ResourceEntity.WEBHOOK,
permissions
)}
path={getSettingPath(
GlobalSettingsMenuCategory.INTEGRATIONS,
GlobalSettingOptions.WEBHOOK
@ -150,6 +186,11 @@ const GlobalSettingRouter = () => {
<AdminProtectedRoute
exact
component={BotsPageV1}
hasPermission={checkPemission(
Operation.ViewAll,
ResourceEntity.BOT,
permissions
)}
path={getSettingPath(
GlobalSettingsMenuCategory.INTEGRATIONS,
GlobalSettingOptions.BOTS
@ -159,6 +200,11 @@ const GlobalSettingRouter = () => {
<AdminProtectedRoute
exact
component={SlackSettingsPage}
hasPermission={checkPemission(
Operation.ViewAll,
ResourceEntity.WEBHOOK,
permissions
)}
path={getSettingPath(
GlobalSettingsMenuCategory.INTEGRATIONS,
GlobalSettingOptions.SLACK
@ -174,6 +220,11 @@ const GlobalSettingRouter = () => {
<AdminProtectedRoute
exact
component={CustomPropertiesPageV1}
hasPermission={checkPemission(
Operation.ViewAll,
ResourceEntity.ALL,
permissions
)}
path={getSettingCategoryPath(
GlobalSettingsMenuCategory.CUSTOM_ATTRIBUTES
)}

View File

@ -11,13 +11,22 @@
* limitations under the License.
*/
import {
OperationPermission,
ResourceEntity,
UIPermission,
} from '../components/PermissionProvider/PermissionProvider.interface';
import { EntityType } from '../enums/entity.enum';
import {
Access,
Permission,
ResourcePermission,
} from '../generated/entity/policies/accessControl/resourcePermission';
import { Operation } from '../generated/entity/policies/policy';
/**
* TODO: Remove this method once we have new permission structure everywhere
*/
export const hasPemission = (
operation: Operation,
entityType: EntityType,
@ -34,4 +43,64 @@ export const hasPemission = (
return currentPermission?.access === Access.Allow;
};
/**
*
* @param operation operation like Edit, Delete
* @param resourceType Resource type like "bot", "table"
* @param permissions UIPermission
* @returns boolean - true/false
*/
export const checkPemission = (
operation: Operation,
resourceType: ResourceEntity,
permissions: UIPermission
) => {
const allResource = permissions.all;
const entityResource = permissions[resourceType];
/**
* If allresource is present then check for permission and return it
*/
if (allResource) {
return allResource.All || allResource[operation];
}
return entityResource[operation];
};
/**
*
* @param permission ResourcePermission
* @returns OperationPermission - {Operation:true/false}
*/
export const getOperationPermissions = (
permission: ResourcePermission
): OperationPermission => {
return permission.permissions.reduce(
(acc: OperationPermission, curr: Permission) => {
return {
...acc,
[curr.operation as Operation]: curr.access === Access.Allow,
};
},
{} as OperationPermission
);
};
/**
*
* @param permissions Take ResourcePermission list
* @returns UIPermission
*/
export const getUIPermission = (
permissions: ResourcePermission[]
): UIPermission => {
return permissions.reduce((acc: UIPermission, curr: ResourcePermission) => {
return {
...acc,
[curr.resource as ResourceEntity]: getOperationPermissions(curr),
};
}, {} as UIPermission);
};
export const LIST_CAP = 1;