Skip to content

Commit

Permalink
fix: uses detailed permissions for a user of a specific role
Browse files Browse the repository at this point in the history
  • Loading branch information
mholthausen committed Jun 1, 2023
1 parent 6c0cc59 commit fc03cd7
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 75 deletions.
47 changes: 26 additions & 21 deletions src/bootstrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -531,34 +531,37 @@ const loadPlugins = async (map: OlMap) => {
const checkRoles = (
list: string[],
featureEditRoles: FeatureEditConfiguration
): EditLevel => {
): EditLevel[] => {
const {
fullEditRoles, limitedEditRoles
authorizedRolesForCreate,
authorizedRolesForUpdate,
authorizedRolesForDelete
} = featureEditRoles;

const result: EditLevel[] = [];

for (const element of list) {
if (fullEditRoles) {
for (const role of fullEditRoles) {
if (typeof role === 'string' && element === role) {
return 'FULL';
} else if (role instanceof RegExp && role.test(element)) {
return 'FULL';
}
}
if (authorizedRolesForCreate?.some(role => matchRole(role, element))) {
result.push('CREATE');
}

if (limitedEditRoles) {
for (const role of limitedEditRoles) {
if (typeof role === 'string' && element === role) {
return 'LIMITED';
} else if (role instanceof RegExp && role.test(element)) {
return 'LIMITED';
}
}
if (authorizedRolesForUpdate?.some(role => matchRole(role, element))) {
result.push('UPDATE');
}
if (authorizedRolesForDelete?.some(role => matchRole(role, element))) {
result.push('DELETE');
}
}
return result;
};

return 'NONE';
const matchRole = (role: string | RegExp, element: string): boolean => {
if (typeof role === 'string') {
return element === role;
}
if (role instanceof RegExp) {
return role.test(element);
}
return false;
};

const renderApp = async () => {
Expand Down Expand Up @@ -612,9 +615,11 @@ const renderApp = async () => {
const userRoles: string[] | undefined =
client?.getKeycloak()?.tokenParsed?.realm_access?.roles;

let allowedEditMode: EditLevel = 'NONE';
let allowedEditMode: EditLevel[] = ['NONE'];

if (userRoles && ClientConfiguration.featureEditRoles) {
console.log(userRoles);
console.log(ClientConfiguration.featureEditRoles);
allowedEditMode = checkRoles(
userRoles,
ClientConfiguration.featureEditRoles
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export const EditFeatureGeometryToolbar: React.FC<EditFeatureGeometryToolbarProp
>
<ToggleGroup>
{
allowedEditMode === 'FULL' ?
allowedEditMode.includes('CREATE') ?
<DrawButton
icon={
<FontAwesomeIcon icon={faPencil} />
Expand All @@ -218,23 +218,27 @@ export const EditFeatureGeometryToolbar: React.FC<EditFeatureGeometryToolbarProp
/>
: <></>
}
<ModifyButton
icon={
<FontAwesomeIcon icon={faDrawPolygon} />
}
pressedIcon={
<FontAwesomeIcon icon={faDrawPolygon} />
}
name="edit"
digitizeLayer={editLayer}
tooltip={t('EditFeatureGeometryToolbar.edit')}
onModifyStart={updateRevision}
onModifyEnd={updateRevision}
onTranslateEnd={updateRevision}
{...btnTooltipProps}
/>
{
allowedEditMode === 'FULL' ?
allowedEditMode.includes('UPDATE') ?
<ModifyButton
icon={
<FontAwesomeIcon icon={faDrawPolygon} />
}
pressedIcon={
<FontAwesomeIcon icon={faDrawPolygon} />
}
name="edit"
digitizeLayer={editLayer}
tooltip={t('EditFeatureGeometryToolbar.edit')}
onModifyStart={updateRevision}
onModifyEnd={updateRevision}
onTranslateEnd={updateRevision}
{...btnTooltipProps}
/>
: <></>
}
{
allowedEditMode.includes('DELETE') ?
<DeleteButton
icon={
<FontAwesomeIcon icon={faTrash} />
Expand Down
18 changes: 13 additions & 5 deletions src/components/EditFeatureDrawer/EditFeatureSwitch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,11 @@ export const EditFeatureSwitch: React.FC<EditFeatureSwitchProps> = () => {
state => state.editFeature.userEditMode
);

useGetFeatureInfo(layer, (featureCollection) => {
if (featureCollection.features.length) {
useGetFeatureInfo(layer, featureCollection => {
if (
featureCollection.features.length &&
(allowedEditMode.includes('UPDATE') || allowedEditMode.includes('DELETE'))
) {
dispatch(setFeature(featureCollection.features[0]));
}
});
Expand Down Expand Up @@ -136,9 +139,12 @@ export const EditFeatureSwitch: React.FC<EditFeatureSwitchProps> = () => {

return (
<div className="edit-feature-switch">
{allowedEditMode === 'FULL' && (
{allowedEditMode.includes('CREATE') && (
<>
<div>{t('EditFeatureSwitch.usageHint')}</div>
{
allowedEditMode.includes('UPDATE') &&
<div>{t('EditFeatureSwitch.usageHint')}</div>
}
<Button
loading={loading}
onClick={onCreateClick}
Expand All @@ -147,7 +153,9 @@ export const EditFeatureSwitch: React.FC<EditFeatureSwitchProps> = () => {
</Button>
</>
)}
{allowedEditMode === 'LIMITED' && (
{!allowedEditMode.includes('CREATE') &&
(allowedEditMode.includes('UPDATE') ||
allowedEditMode.includes('DELETE')) && (
<div>{t('EditFeatureSwitch.limitedUsageHint')}</div>
)}
</div>
Expand Down
38 changes: 25 additions & 13 deletions src/components/EditFeatureDrawer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,17 @@ export const EditFeatureDrawer: React.FC<EditFeatureDrawerProps> = ({
layer: layer,
featureId: id
});
if (updatedFeatures?.features[0]) {
if (
updatedFeatures?.features[0] &&
(allowedEditMode.includes('UPDATE') ||
allowedEditMode.includes('DELETE'))
) {
dispatch(setFeature(updatedFeatures?.features[0]));
}
return;
}, [dispatch, getFeature, layer]);
},
[allowedEditMode, dispatch, getFeature, layer]
);

const update = useCallback(() => {
if (!map || !layerId) {
Expand Down Expand Up @@ -240,18 +246,24 @@ export const EditFeatureDrawer: React.FC<EditFeatureDrawerProps> = ({
<div
className='btn-container'
>
<ResetButton
feature={feature}
form={form}
/>
<SaveButton
form={form}
layerId={layerId}
onSuccess={onSaveSuccess}
onError={onSaveError}
/>
{
allowedEditMode === 'FULL' &&
allowedEditMode.includes('CREATE') ||
allowedEditMode.includes('UPDATE') ?
<>
<ResetButton
feature={feature}
form={form}
/>
<SaveButton
form={form}
layerId={layerId}
onSuccess={onSaveSuccess}
onError={onSaveError}
/>
</>: <></>
}
{
allowedEditMode.includes('DELETE') &&
<DeleteButton
feature={feature}
layerId={layerId}
Expand Down
40 changes: 28 additions & 12 deletions src/components/MultiSearch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ import SearchResultsPanel, {
import useAppDispatch from '../../hooks/useAppDispatch';
import './index.less';

import useAppSelector from '../../hooks/useAppSelector';

import {
setLayerId
} from '../../store/editFeature';
Expand All @@ -62,6 +64,7 @@ import {
show as showEditFeatureDrawer
} from '../../store/editFeatureDrawerOpen';


interface MultiSearchProps extends InputProps {
useNominatim: boolean;
delay?: number;
Expand Down Expand Up @@ -99,6 +102,10 @@ export const MultiSearch: React.FC<MultiSearchProps> = ({
const [nominatimResults, setNominatimResults] = useState<NominatimPlace[]>([]);
const [searchResults, setSearchResults] = useState<ResultCategory[]>([]);

const allowedEditMode = useAppSelector(
state => state.editFeature.userEditMode
);

useEffect(() => {
window.addEventListener('mousedown', handleClickAway);

Expand Down Expand Up @@ -391,18 +398,27 @@ export const MultiSearch: React.FC<MultiSearchProps> = ({
setResultsVisible(false);
};

return [
<Tooltip
key='edit'
title={t('EditFeatureButton.title')}
placement='bottom'
>
<Button
onClick={onEditFeatureBtnClick}
icon={<EditOutlined />}
/>
</Tooltip>
];
if (
allowedEditMode.includes('CREATE') ||
allowedEditMode.includes('DELETE') ||
allowedEditMode.includes('UPDATE')
) {
return [
<Tooltip
key="edit"
title={t('EditFeatureButton.title')}
placement="bottom"
>
<Button
onClick={onEditFeatureBtnClick}
icon={<EditOutlined />}
/>
</Tooltip>
];
} else {
return [<></>];
}

};

const resultRenderer = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,12 @@ export const LayerTreeContextMenu: React.FC<LayerTreeContextMenuProps> = ({
dropdownMenuItems.push(...downloadItems);
}

if (layer.get('editable') && allowedEditMode !== 'NONE') {
if (
layer.get('editable') &&
(allowedEditMode.includes('CREATE') ||
allowedEditMode.includes('UPDATE') ||
allowedEditMode.includes('DELETE'))
) {
dropdownMenuItems.push({
label: t('LayerTreeContextMenu.editLayer'),
key: 'editLayer'
Expand Down
5 changes: 3 additions & 2 deletions src/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ declare module 'clientConfig' {
exposedPaths?: string[];
};
export type FeatureEditConfiguration = {
fullEditRoles?: (string | RegExp)[];
limitedEditRoles?: (string | RegExp)[];
authorizedRolesForCreate?: (string | RegExp)[];
authorizedRolesForUpdate?: (string | RegExp)[];
authorizedRolesForDelete?: (string | RegExp)[];
};
type ClientConfiguration = {
shogunBase?: string;
Expand Down
8 changes: 4 additions & 4 deletions src/store/editFeature/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import {
Feature
} from 'geojson';

export type EditLevel = 'NONE' | 'FULL' | 'LIMITED';
export type EditLevel = 'CREATE' | 'UPDATE' | 'DELETE' | 'NONE';
export interface EditFeatureState {
layerId: string | null;
feature: Feature | null;
userEditMode: EditLevel;
userEditMode: EditLevel[];
}

const initialState: EditFeatureState = {
layerId: null,
feature: null,
userEditMode: 'NONE'
userEditMode: ['NONE']
};

const editFeatureSlice = createSlice({
Expand All @@ -34,7 +34,7 @@ const editFeatureSlice = createSlice({
state.layerId = null;
state.feature = null;
},
setUserEditMode(state, action: PayloadAction<EditLevel>) {
setUserEditMode(state, action: PayloadAction<EditLevel[]>) {
state.userEditMode = action.payload;
}
}
Expand Down

0 comments on commit fc03cd7

Please sign in to comment.