{loading ?
: null}
{!isNil(total) ?
: null}
diff --git a/web/client/components/catalog/__tests__/Catalog-test.jsx b/web/client/components/catalog/__tests__/Catalog-test.jsx
index 00eb33b71c..fa7e163a51 100644
--- a/web/client/components/catalog/__tests__/Catalog-test.jsx
+++ b/web/client/components/catalog/__tests__/Catalog-test.jsx
@@ -182,4 +182,46 @@ describe('Test Catalog panel', () => {
expect(spyOnSearch.calls[0].arguments[0]).toEqual({ format: 'csw', url: 'url', startPosition: 1, maxRecords: 4, text: '', options: {service: SERVICE} });
expect(catalogPagination.length).toBe(1); // Pagination is displayed
});
+ it('test manage service with permission', () => {
+ const SERVICE = {
+ type: "csw",
+ url: "url",
+ title: "csw"
+ };
+ ReactDOM.render(
, document.getElementById("container"));
+ const container = document.getElementById("container");
+ expect(container).toBeTruthy();
+ let editEl = document.querySelector('.glyphicon-pencil');
+ let addEl = document.querySelector('.glyphicon-plus');
+ expect(editEl).toBeTruthy();
+ expect(addEl).toBeTruthy();
+ });
+ it('test manage service with no permission', () => {
+ const SERVICE = {
+ type: "csw",
+ url: "url",
+ title: "csw"
+ };
+ ReactDOM.render(
, document.getElementById("container"));
+ const container = document.getElementById("container");
+ expect(container).toBeTruthy();
+ let editEl = document.querySelector('.glyphicon-pencil');
+ let addEl = document.querySelector('.glyphicon-plus');
+ expect(editEl).toBeFalsy();
+ expect(addEl).toBeFalsy();
+ });
});
diff --git a/web/client/components/catalog/__tests__/CatalogServiceSelector-test.jsx b/web/client/components/catalog/__tests__/CatalogServiceSelector-test.jsx
new file mode 100644
index 0000000000..77360f8ced
--- /dev/null
+++ b/web/client/components/catalog/__tests__/CatalogServiceSelector-test.jsx
@@ -0,0 +1,45 @@
+/**
+ * Copyright 2024, GeoSolutions Sas.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+import React from 'react';
+import ReactDOM from 'react-dom';
+import expect from 'expect';
+import CatalogServiceSelector from '../CatalogServiceSelector';
+
+describe('Test CatalogServiceEditor', () => {
+ beforeEach((done) => {
+ document.body.innerHTML = '
';
+ setTimeout(done);
+ });
+ afterEach((done) => {
+ ReactDOM.unmountComponentAtNode(document.getElementById("container"));
+ document.body.innerHTML = '';
+ setTimeout(done);
+ });
+
+ it('creates the component with defaults', () => {
+ ReactDOM.render(
, document.getElementById("container"));
+ expect(document.getElementById('container')).toBeTruthy();
+ expect(document.querySelector('input')).toBeTruthy();
+ expect(document.querySelector('.glyphicon-pencil')).toBeFalsy();
+ expect(document.querySelector('.glyphicon-plus')).toBeFalsy();
+ });
+ it('test isValidServiceSelected', () => {
+ ReactDOM.render(
, document.getElementById("container"));
+ expect(document.getElementById('container')).toBeTruthy();
+ expect(document.querySelector('input')).toBeTruthy();
+ expect(document.querySelector('.glyphicon-pencil')).toBeFalsy();
+ expect(document.querySelector('.glyphicon-plus')).toBeTruthy();
+ });
+ it('test isValidServiceSelected & canEdit', () => {
+ ReactDOM.render(
, document.getElementById("container"));
+ expect(document.getElementById('container')).toBeTruthy();
+ expect(document.querySelector('input')).toBeTruthy();
+ expect(document.querySelector('.glyphicon-pencil')).toBeTruthy();
+ expect(document.querySelector('.glyphicon-plus')).toBeTruthy();
+ });
+});
diff --git a/web/client/plugins/DashboardEditor.jsx b/web/client/plugins/DashboardEditor.jsx
index 793180d381..fa7a752815 100644
--- a/web/client/plugins/DashboardEditor.jsx
+++ b/web/client/plugins/DashboardEditor.jsx
@@ -12,12 +12,12 @@ import { createSelector } from 'reselect';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { createPlugin } from '../utils/PluginsUtils';
-import { isDashboardEditing, isDashboardLoading, isDashboardAvailable } from '../selectors/dashboard';
+import { isDashboardEditing, isDashboardLoading, canEditServiceSelector } from '../selectors/dashboard';
import { dashboardSelector, dashboardsLocalizedSelector } from './widgetbuilder/commons';
import { toggleConnection } from '../actions/widgets';
-import { setEditing, setEditorAvailable, triggerShowConnections } from '../actions/dashboard';
+import { initPlugin, setEditing, setEditorAvailable, triggerShowConnections } from '../actions/dashboard';
import withDashboardExitButton from './widgetbuilder/enhancers/withDashboardExitButton';
import WidgetTypeBuilder from './widgetbuilder/WidgetTypeBuilder';
@@ -42,6 +42,7 @@ const Builder =
* @prop {object} cfg.catalog **Deprecated** in favor of `cfg.services`. Can contain a catalog configuration
* @prop {object} cfg.services Object with the catalogs available to select layers for maps, charts and tables. The format is the same of the `Catalog` plugin.
* @prop {string} cfg.selectedService the key of service selected by default from the list of `cfg.services`
+ * @prop {string} cfg.servicesPermission object with permission properties to manage catalog service. Configurations are `editingAllowedRoles` & `editingAllowedGroups`. By default `editingAllowedRoles: ["ADMIN"]`
* @prop {boolean} cfg.disableEmptyMap disable empty map entry from the available maps of map widget
*/
class DashboardEditorComponent extends React.Component {
@@ -61,7 +62,8 @@ class DashboardEditorComponent extends React.Component {
style: PropTypes.object,
pluginCfg: PropTypes.object,
catalog: PropTypes.object,
- disableEmptyMap: PropTypes.bool
+ disableEmptyMap: PropTypes.bool,
+ servicesPermission: PropTypes.object
};
static defaultProps = {
id: "dashboard-editor",
@@ -74,9 +76,13 @@ class DashboardEditorComponent extends React.Component {
position: "left",
onMount: () => { },
onUnmount: () => { },
- setEditing: () => { }
+ setEditing: () => { },
+ servicesPermission: {
+ editingAllowedRoles: ["ALL"]
+ }
};
componentDidMount() {
+ this.props.onInit({ servicesPermission: this.props.servicesPermission });
this.props.onMount();
}
@@ -94,6 +100,7 @@ class DashboardEditorComponent extends React.Component {
disableEmptyMap={this.props.disableEmptyMap}
defaultSelectedService={defaultSelectedService}
defaultServices={defaultServices}
+ canEditService={this.props.canEditService}
enabled={this.props.editing}
onClose={() => this.props.setEditing(false)}
catalog={this.props.catalog}
@@ -107,10 +114,11 @@ const Plugin = connect(
createSelector(
isDashboardEditing,
isDashboardLoading,
- isDashboardAvailable,
- (editing, isDashboardOpened) => ({ editing, isDashboardOpened })
+ canEditServiceSelector,
+ (editing, isDashboardOpened, canEditService) => ({ editing, isDashboardOpened, canEditService })
), {
setEditing,
+ onInit: initPlugin,
onMount: () => setEditorAvailable(true),
onUnmount: () => setEditorAvailable(false)
}
diff --git a/web/client/plugins/MetadataExplorer.jsx b/web/client/plugins/MetadataExplorer.jsx
index 58e51d870b..4e8abdbd9f 100644
--- a/web/client/plugins/MetadataExplorer.jsx
+++ b/web/client/plugins/MetadataExplorer.jsx
@@ -39,7 +39,8 @@ import {
toggleAdvancedSettings,
toggleTemplate,
toggleThumbnail,
- setNewServiceStatus
+ setNewServiceStatus,
+ initPlugin
} from '../actions/catalog';
import { setControlProperty, toggleControl } from '../actions/controls';
import { changeLayerProperties } from '../actions/layers';
@@ -74,7 +75,8 @@ import {
getSupportedFormatsSelector,
getSupportedGFIFormatsSelector,
getNewServiceStatusSelector,
- showFormatErrorSelector
+ showFormatErrorSelector,
+ canEditServiceSelector
} from '../selectors/catalog';
import { layersSelector } from '../selectors/layers';
import { currentLocaleSelector, currentMessagesSelector } from '../selectors/locale';
@@ -121,7 +123,8 @@ const metadataExplorerSelector = createStructuredSelector({
formatsLoading: formatsLoadingSelector,
formatOptions: getSupportedFormatsSelector,
infoFormatOptions: getSupportedGFIFormatsSelector,
- isNewServiceAdded: getNewServiceStatusSelector
+ isNewServiceAdded: getNewServiceStatusSelector,
+ canEdit: canEditServiceSelector
});
@@ -174,7 +177,10 @@ class MetadataExplorerComponent extends React.Component {
// side panel properties
width: PropTypes.number,
dockStyle: PropTypes.object,
- group: PropTypes.string
+ group: PropTypes.string,
+ onInitPlugin: PropTypes.func,
+ editingAllowedRoles: PropTypes.array,
+ editingAllowedGroups: PropTypes.array
};
static defaultProps = {
@@ -191,6 +197,7 @@ class MetadataExplorerComponent extends React.Component {
},
panelClassName: "catalog-panel",
closeCatalog: () => {},
+ onInitPlugin: () => {},
closeGlyph: "1-close",
zoomToLayer: true,
@@ -205,9 +212,17 @@ class MetadataExplorerComponent extends React.Component {
dockStyle: {},
group: null,
services: {},
- servicesWithBackgrounds: {}
+ servicesWithBackgrounds: {},
+ editingAllowedRoles: ["ALL"]
};
+ componentDidMount() {
+ this.props.onInitPlugin({
+ editingAllowedRoles: this.props.editingAllowedRoles,
+ editingAllowedGroups: this.props.editingAllowedGroups
+ });
+ }
+
componentWillUnmount() {
this.props.closeCatalog();
}
@@ -275,7 +290,8 @@ const MetadataExplorerPlugin = connect(metadataExplorerSelector, {
onToggle: toggleControl.bind(null, 'backgroundSelector', null),
onLayerChange: setControlProperty.bind(null, 'backgroundSelector'),
onStartChange: setControlProperty.bind(null, 'backgroundSelector', 'start'),
- setNewServiceStatus
+ setNewServiceStatus,
+ onInitPlugin: initPlugin
})(MetadataExplorerComponent);
/**
diff --git a/web/client/plugins/__tests__/DashboardEditor-test.jsx b/web/client/plugins/__tests__/DashboardEditor-test.jsx
new file mode 100644
index 0000000000..575fb2247f
--- /dev/null
+++ b/web/client/plugins/__tests__/DashboardEditor-test.jsx
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2024, GeoSolutions Sas.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+import expect from 'expect';
+import React from 'react';
+import ReactDOM from 'react-dom';
+import DashboardEditorPlugin from '../DashboardEditor';
+import { getPluginForTest } from './pluginsTestUtils';
+
+describe('DashboardEditorPlugin Plugin', () => {
+ beforeEach(() => {
+ document.body.innerHTML = '
';
+ });
+
+ afterEach(() => {
+ ReactDOM.unmountComponentAtNode(document.getElementById("container"));
+ document.body.innerHTML = '';
+ });
+ it('test DashboardEditorPlugin plugin on mount', () => {
+ const {Plugin, actions} = getPluginForTest(DashboardEditorPlugin, {});
+ ReactDOM.render(
, document.getElementById("container"));
+
+ expect(actions.length).toBeTruthy();
+ const actionTypes = actions.map(a => a.type);
+ expect(actionTypes.includes("DASHBOARD:INIT_PLUGIN")).toBeTruthy();
+ expect(actionTypes.includes("DASHBOARD:SET_AVAILABLE")).toBeTruthy();
+ });
+ it('test DashboardEditorPlugin plugin on unmount', () => {
+ const {Plugin, actions} = getPluginForTest(DashboardEditorPlugin, {});
+ ReactDOM.render(, document.getElementById("container"));
+
+ ReactDOM.render(, document.getElementById("container"));
+ expect(actions).toBeTruthy();
+ expect(actions.find(a => a.type === "DASHBOARD:SET_AVAILABLE")).toBeTruthy();
+ });
+});
diff --git a/web/client/plugins/__tests__/MetadataExplorer-test.jsx b/web/client/plugins/__tests__/MetadataExplorer-test.jsx
index 235103cd24..96096bf314 100644
--- a/web/client/plugins/__tests__/MetadataExplorer-test.jsx
+++ b/web/client/plugins/__tests__/MetadataExplorer-test.jsx
@@ -26,17 +26,19 @@ describe('MetadataExplorer Plugin', () => {
ReactDOM.render(, document.getElementById("container"));
expect(document.getElementById('catalog-root')).toBeTruthy();
});
+ it('test MetadataExplorerPlugin plugin on mount', () => {
+ const {Plugin, actions} = getPluginForTest(MetadataExplorerPlugin, {});
+ ReactDOM.render(, document.getElementById("container"));
+
+ expect(actions.length).toBeTruthy();
+ expect(actions.map(a => a.type).includes("CATALOG:INIT_PLUGIN")).toBeTruthy();
+ });
it('test MetadataExplorerPlugin plugin on unmount', () => {
const {Plugin, actions} = getPluginForTest(MetadataExplorerPlugin, {});
ReactDOM.render(, document.getElementById("container"));
ReactDOM.render(, document.getElementById("container"));
- expect(actions.length).toBe(4);
- expect(actions[0].type).toBe("CATALOG:CATALOG_CLOSE");
- expect(actions[1].type).toBe("SET_CONTROL_PROPERTIES");
- expect(actions[1].control).toBe("metadataexplorer");
- expect(actions[2].type).toBe("CATALOG:CHANGE_CATALOG_MODE");
- expect(actions[2].mode).toBe("view");
- expect(actions[3].type).toBe("CATALOG:RESET_CATALOG");
+ expect(actions.length).toBeTruthy();
+ expect(actions.map(a => a.type).includes("CATALOG:CATALOG_CLOSE")).toBeTruthy();
});
});
diff --git a/web/client/plugins/widgetbuilder/ChartLayerSelector.jsx b/web/client/plugins/widgetbuilder/ChartLayerSelector.jsx
index 4dc2f89c1b..daaa011b77 100644
--- a/web/client/plugins/widgetbuilder/ChartLayerSelector.jsx
+++ b/web/client/plugins/widgetbuilder/ChartLayerSelector.jsx
@@ -56,7 +56,8 @@ export default connect((state) =>({
onItemClick,
showLayers,
toggleLayerSelector,
- selectedCatalog
+ selectedCatalog,
+ canEditService
}) => {
const _canProceed = showLayers ? canProceed && !isEmpty(layer) : canProceed && selected && layer && castArray(selected).length === castArray(layer).length;
const getProcessArguments = () => {
@@ -111,6 +112,7 @@ export default connect((state) =>({
>}
+ canEditService={canEditService}
/>
);
});
diff --git a/web/client/plugins/widgetbuilder/LayerSelector.jsx b/web/client/plugins/widgetbuilder/LayerSelector.jsx
index 63fde01a1e..8c258ab1c0 100644
--- a/web/client/plugins/widgetbuilder/LayerSelector.jsx
+++ b/web/client/plugins/widgetbuilder/LayerSelector.jsx
@@ -31,7 +31,7 @@ const Catalog = compose(
* @prop {function} [layerValidationStream]
*/
export default ({ onClose = () => { }, setSelected = () => { }, onLayerChoice = () => { }, stepButtons, selected, error, canProceed, layer, catalog, defaultServices,
- onChangeSelectedService, defaultSelectedService, onChangeCatalogMode, dashboardServices, dashboardSelectedService} = {}) =>
+ onChangeSelectedService, defaultSelectedService, onChangeCatalogMode, dashboardServices, dashboardSelectedService, canEditService} = {}) =>
(
@@ -47,5 +47,6 @@ export default ({ onClose = () => { }, setSelected = () => { }, onLayerChoice =
onChangeSelectedService(service, dashboardServices || defaultServices)} services={ dashboardServices || defaultServices} selected={selected} catalog={catalog} onRecordSelected={r => setSelected(r)} />
+ onChangeSelectedService={(service) => onChangeSelectedService(service, dashboardServices || defaultServices)} services={ dashboardServices || defaultServices} selected={selected} catalog={catalog} onRecordSelected={r => setSelected(r)}
+ canEditService={canEditService}/>
);
diff --git a/web/client/plugins/widgetbuilder/MapLayerSelector.jsx b/web/client/plugins/widgetbuilder/MapLayerSelector.jsx
index bd76b15655..4e8e7e037c 100644
--- a/web/client/plugins/widgetbuilder/MapLayerSelector.jsx
+++ b/web/client/plugins/widgetbuilder/MapLayerSelector.jsx
@@ -30,7 +30,7 @@ const Catalog = compose(
*/
export default ({ onClose = () => { }, setSelected = () => { }, onLayerChoice = () => { }, toggleLayerSelector = () => {}, selected, canProceed, layer,
catalog, onChangeSelectedService, defaultServices,
- defaultSelectedService, onChangeCatalogMode, dashboardServices, dashboardSelectedService} = {}) =>
+ defaultSelectedService, onChangeCatalogMode, dashboardServices, dashboardSelectedService, canEditService} = {}) =>
(
@@ -62,5 +62,6 @@ export default ({ onClose = () => { }, setSelected = () => { }, onLayerChoice =
onChangeSelectedService={(service) => onChangeSelectedService(service, dashboardServices || defaultServices)} services={ dashboardServices || defaultServices}
catalog={catalog}
selected={selected}
- onRecordSelected={r => setSelected(r)} />
+ onRecordSelected={r => setSelected(r)}
+ canEditService={canEditService} />
);
diff --git a/web/client/reducers/__tests__/catalog-test.js b/web/client/reducers/__tests__/catalog-test.js
index ac0da650cc..1cb1459de4 100644
--- a/web/client/reducers/__tests__/catalog-test.js
+++ b/web/client/reducers/__tests__/catalog-test.js
@@ -55,7 +55,8 @@ import {
changeServiceFormat,
setLoading,
formatsLoading,
- setSupportedFormats
+ setSupportedFormats,
+ initPlugin
} from '../../actions/catalog';
import { MAP_CONFIG_LOADED } from '../../actions/config';
@@ -344,4 +345,23 @@ describe('Test the catalog reducer', () => {
expect(state.newService.formatUrlUsed).toBe(url);
expect(state.newService.supportedFormats).toEqual(formats);
});
+ it('INIT_PLUGIN ', () => {
+ const option = {
+ editingAllowedRoles: ["ADMIN"],
+ editingAllowedGroups: []
+ };
+ let state = catalog({
+ newService: {}
+ }, initPlugin(option));
+ expect(state.editingAllowedRoles).toEqual(option.editingAllowedRoles);
+ expect(state.editingAllowedGroups).toEqual(option.editingAllowedGroups);
+
+ state = catalog({
+ newService: {},
+ editingAllowedRoles: ["ADMIN"],
+ editingAllowedGroups: []
+ }, initPlugin());
+ expect(state.editingAllowedRoles).toEqual(option.editingAllowedRoles);
+ expect(state.editingAllowedGroups).toEqual(option.editingAllowedGroups);
+ });
});
diff --git a/web/client/reducers/__tests__/dashboard-test.js b/web/client/reducers/__tests__/dashboard-test.js
index b5679d1d36..1333adffd4 100644
--- a/web/client/reducers/__tests__/dashboard-test.js
+++ b/web/client/reducers/__tests__/dashboard-test.js
@@ -22,7 +22,8 @@ import {
setDashboardCatalogMode,
setDashboardServiceSaveLoading,
dashboardDeleteService,
- updateDashboardService
+ updateDashboardService,
+ initPlugin
} from '../../actions/dashboard';
import { insertWidget, updateWidget, deleteWidget } from '../../actions/widgets';
@@ -146,5 +147,14 @@ describe('Test the dashboard reducer', () => {
expect(state.selectedService).toBe('test');
});
+ it('dashboard onInitPlugin', () => {
+ let action = initPlugin({option: "test"});
+ let state = dashboard({}, action);
+ expect(state.option).toBeTruthy();
+ expect(state.option).toBe("test");
+ action = initPlugin();
+ state = dashboard({serviceStarted: false}, action);
+ expect(state).toEqual({serviceStarted: false});
+ });
});
diff --git a/web/client/reducers/catalog.js b/web/client/reducers/catalog.js
index ccb842e725..6b358854ab 100644
--- a/web/client/reducers/catalog.js
+++ b/web/client/reducers/catalog.js
@@ -32,7 +32,8 @@ import {
FORMAT_OPTIONS_LOADING,
SHOW_FORMAT_ERROR,
SET_FORMAT_OPTIONS,
- NEW_SERVICE_STATUS
+ NEW_SERVICE_STATUS,
+ INIT_PLUGIN
} from '../actions/catalog';
import { MAP_CONFIG_LOADED } from '../actions/config';
@@ -68,6 +69,12 @@ function catalog(state = {
newService: {}
}, action) {
switch (action.type) {
+ case INIT_PLUGIN:
+ return {
+ ...state,
+ editingAllowedRoles: action?.options?.editingAllowedRoles || state.editingAllowedRoles,
+ editingAllowedGroups: action?.options?.editingAllowedGroups || state.editingAllowedGroups
+ };
case SAVING_SERVICE:
return {
...state,
diff --git a/web/client/reducers/dashboard.js b/web/client/reducers/dashboard.js
index bb49ea01f6..5e3cf8efb6 100644
--- a/web/client/reducers/dashboard.js
+++ b/web/client/reducers/dashboard.js
@@ -23,7 +23,8 @@ import {
DASHBOARD_ADD_NEW_SERVICE,
DASHBOARD_CATALOG_MODE,
DASHBOARD_DELETE_SERVICE,
- DASHBOARD_SAVE_SERVICE_LOADING
+ DASHBOARD_SAVE_SERVICE_LOADING,
+ INIT_PLUGIN
} from '../actions/dashboard';
import { INSERT, UPDATE, DELETE } from '../actions/widgets';
@@ -36,6 +37,9 @@ function dashboard(state = {
saveServiceLoading: false
}, action) {
switch (action.type) {
+ case INIT_PLUGIN: {
+ return { ...state, ...action?.options };
+ }
case SET_EDITOR_AVAILABLE: {
return set("editor.available", action.available, state);
}
diff --git a/web/client/selectors/__tests__/catalog-test.js b/web/client/selectors/__tests__/catalog-test.js
index d341a5f3d8..7ed69533e9 100644
--- a/web/client/selectors/__tests__/catalog-test.js
+++ b/web/client/selectors/__tests__/catalog-test.js
@@ -33,7 +33,8 @@ import {
formatsLoadingSelector,
getSupportedFormatsSelector,
getSupportedGFIFormatsSelector,
- getFormatUrlUsedSelector
+ getFormatUrlUsedSelector,
+ canEditServiceSelector
} from '../catalog';
import { set } from '../../utils/ImmutableUtils';
@@ -349,4 +350,102 @@ describe('Test catalog selectors', () => {
});
expect(toolState).toBe(true);
});
+ describe("canEditServiceSelector", () => {
+ it('test ADMIN role ', () => {
+ const canEdit = canEditServiceSelector({
+ catalog: {
+ editingAllowedRoles: ['ADMIN'],
+ editingAllowedGroups: []
+ },
+ security: {
+ user: {
+ role: "ADMIN"
+ }
+ }
+ });
+ expect(canEdit).toBe(true);
+ });
+ it("test ALL user role", () => {
+ const canEdit = canEditServiceSelector({
+ catalog: {
+ editingAllowedRoles: ['ALL'],
+ editingAllowedGroups: []
+ },
+ security: {
+ user: {
+ role: "ADMIN"
+ }
+ }
+ });
+ expect(canEdit).toBe(true);
+ });
+ it("test custom user role", () => {
+ const canEdit = canEditServiceSelector({
+ catalog: {
+ editingAllowedRoles: ['ROLE1'],
+ editingAllowedGroups: []
+ },
+ security: {
+ user: {
+ role: "ROLE1"
+ }
+ }
+ });
+ expect(canEdit).toBe(true);
+ });
+ it("test user role not matching", () => {
+ const canEdit = canEditServiceSelector({
+ catalog: {
+ editingAllowedRoles: ['ADMIN'],
+ editingAllowedGroups: []
+ },
+ security: {
+ user: {
+ role: "ROLE1"
+ }
+ }
+ });
+ expect(canEdit).toBe(false);
+ });
+ it("test group matching", () => {
+ const canEdit = canEditServiceSelector({
+ catalog: {
+ editingAllowedRoles: [],
+ editingAllowedGroups: ['group1']
+ },
+ security: {
+ user: {
+ role: "ROLE1",
+ groups: {
+ group: {
+ enabled: true,
+ groupName: "group1"
+ }
+ }
+ }
+ }
+ });
+ expect(canEdit).toBe(true);
+ });
+ it("test group not matching", () => {
+ const canEdit = canEditServiceSelector({
+ catalog: {
+ editingAllowedRoles: [],
+ editingAllowedGroups: ['group1']
+ },
+ security: {
+ user: {
+ role: "ROLE1",
+ groups: {
+ group: {
+ enabled: true,
+ groupName: "geo"
+ }
+ }
+ }
+ }
+ });
+ expect(canEdit).toBe(false);
+ });
+ });
});
diff --git a/web/client/selectors/__tests__/dashboard-test.js b/web/client/selectors/__tests__/dashboard-test.js
index 8e9048c1d3..def125eed8 100644
--- a/web/client/selectors/__tests__/dashboard-test.js
+++ b/web/client/selectors/__tests__/dashboard-test.js
@@ -25,7 +25,8 @@ import {
dashboardSaveServiceSelector,
dashboardResourceInfoSelector,
dashbaordInfoDetailsUriFromIdSelector,
- dashboardInfoDetailsSettingsFromIdSelector
+ dashboardInfoDetailsSettingsFromIdSelector,
+ canEditServiceSelector
} from '../dashboard';
describe('dashboard selectors', () => {
@@ -149,4 +150,114 @@ describe('dashboard selectors', () => {
}
}})).toBe("detailsSettings");
});
+ describe("canEditServiceSelector", () => {
+ it('test ADMIN role ', () => {
+ const canEdit = canEditServiceSelector({
+ dashboard: {
+ servicesPermission: {
+ editingAllowedRoles: ['ADMIN'],
+ editingAllowedGroups: []
+ }
+ },
+ security: {
+ user: {
+ role: "ADMIN"
+ }
+ }
+ });
+ expect(canEdit).toBe(true);
+ });
+ it("test ALL user role", () => {
+ const canEdit = canEditServiceSelector({
+ dashboard: {
+ servicesPermission: {
+ editingAllowedRoles: ['ALL'],
+ editingAllowedGroups: []
+ }
+ },
+ security: {
+ user: {
+ role: "ADMIN"
+ }
+ }
+ });
+ expect(canEdit).toBe(true);
+ });
+ it("test custom user role", () => {
+ const canEdit = canEditServiceSelector({
+ dashboard: {
+ servicesPermission: {
+ editingAllowedRoles: ['ROLE1'],
+ editingAllowedGroups: []
+ }
+ },
+ security: {
+ user: {
+ role: "ROLE1"
+ }
+ }
+ });
+ expect(canEdit).toBe(true);
+ });
+ it("test user role not matching", () => {
+ const canEdit = canEditServiceSelector({
+ dashboard: {
+ servicesPermission: {
+ editingAllowedRoles: ['ADMIN'],
+ editingAllowedGroups: []
+ }
+ },
+ security: {
+ user: {
+ role: "ROLE1"
+ }
+ }
+ });
+ expect(canEdit).toBe(false);
+ });
+ it("test group matching", () => {
+ const canEdit = canEditServiceSelector({
+ dashboard: {
+ servicesPermission: {
+ editingAllowedRoles: [],
+ editingAllowedGroups: ['group1']
+ }
+ },
+ security: {
+ user: {
+ role: "ROLE1",
+ groups: {
+ group: {
+ enabled: true,
+ groupName: "group1"
+ }
+ }
+ }
+ }
+ });
+ expect(canEdit).toBe(true);
+ });
+ it("test group not matching", () => {
+ const canEdit = canEditServiceSelector({
+ dashboard: {
+ servicesPermission: {
+ editingAllowedRoles: [],
+ editingAllowedGroups: ['group1']
+ }
+ },
+ security: {
+ user: {
+ role: "ROLE1",
+ groups: {
+ group: {
+ enabled: true,
+ groupName: "geo"
+ }
+ }
+ }
+ }
+ });
+ expect(canEdit).toBe(false);
+ });
+ });
});
diff --git a/web/client/selectors/catalog.js b/web/client/selectors/catalog.js
index 4f38c24f93..b3656eba9d 100644
--- a/web/client/selectors/catalog.js
+++ b/web/client/selectors/catalog.js
@@ -11,6 +11,7 @@ import { get } from 'lodash';
import { projectionSelector } from './map';
import { getDefaultSupportedGetFeatureInfoFormats } from '../utils/WMSUtils';
+import { isUserAllowedSelectorCreator } from './security';
export const staticServicesSelector = (state) => get(state, "catalog.default.staticServices");
export const servicesSelector = (state) => get(state, "catalog.services");
@@ -65,3 +66,19 @@ export const getSupportedGFIFormatsSelector = (state) => get(state, "catalog.new
export const getFormatUrlUsedSelector = (state) => get(state, "catalog.newService.formatUrlUsed", '');
export const getNewServiceStatusSelector = (state) => get(state, "catalog.isNewServiceAdded", false);
export const showFormatErrorSelector = (state) => get(state, "catalog.showFormatError", false);
+export const editingAllowedRolesSelector = (state) => get(state, "catalog.editingAllowedRoles", []);
+export const editingAllowedGroupsSelector = (state) => get(state, "catalog.editingAllowedGroups", []);
+/**
+ * selects canEdit status of styleeditor service from state
+ * @memberof selectors.styleeditor
+ * @param {object} state the state
+ * @return {bool}
+ */
+export const canEditServiceSelector = (state) => {
+ const allowedRoles = editingAllowedRolesSelector(state);
+ const allowedGroups = editingAllowedGroupsSelector(state);
+ return isUserAllowedSelectorCreator({
+ allowedRoles,
+ allowedGroups
+ })(state);
+};
diff --git a/web/client/selectors/dashboard.js b/web/client/selectors/dashboard.js
index 5f565ce8be..1ba41b10c6 100644
--- a/web/client/selectors/dashboard.js
+++ b/web/client/selectors/dashboard.js
@@ -8,6 +8,7 @@
import { createSelector } from 'reselect';
import {get} from 'lodash';
import { pathnameSelector } from './router';
+import { isUserAllowedSelectorCreator } from './security';
export const getDashboardId = state => state?.dashboard?.resource?.id;
export const isDashboardAvailable = state => state && state.dashboard && state.dashboard.editor && state.dashboard.editor.available;
@@ -31,4 +32,14 @@ export const dashboardSaveServiceSelector = state => state.dashboard?.saveServi
export const dashboardResourceInfoSelector = state => get(state, "dashboard.resource");
export const dashbaordInfoDetailsUriFromIdSelector = state => state?.dashboard?.resource?.attributes?.details;
export const dashboardInfoDetailsSettingsFromIdSelector = state => get(dashboardResource(state), "attributes.detailsSettings");
+export const editingAllowedRolesSelector = state => get(state, "dashboard.servicesPermission.editingAllowedRoles", []);
+export const editingAllowedGroupsSelector = state => get(state, "dashboard.servicesPermission.editingAllowedGroups", []);
+export const canEditServiceSelector = state => {
+ const allowedRoles = editingAllowedRolesSelector(state);
+ const allowedGroups = editingAllowedGroupsSelector(state);
+ return isUserAllowedSelectorCreator({
+ allowedRoles,
+ allowedGroups
+ })(state);
+};