Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Admin roles summary #2752

Draft
wants to merge 25 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
620d623
sort and highlight system roles
okauppinen Nov 1, 2024
5f3180d
add buttons for default permissions
okauppinen Nov 1, 2024
261612e
remove CollapsePanel imports
okauppinen Nov 1, 2024
2e52f0f
update localization
okauppinen Nov 1, 2024
0155c30
add layer details mapping and edit/add layer functions
okauppinen Nov 1, 2024
39aeb22
add summaries to select
okauppinen Nov 1, 2024
b02e731
add summary table for permissions
okauppinen Nov 1, 2024
8bd8db4
add summary table for layer details
okauppinen Nov 1, 2024
f597f21
update localization
okauppinen Nov 1, 2024
f2062a9
add util for admin
okauppinen Nov 2, 2024
1d7119d
refactor admin util functions
okauppinen Nov 5, 2024
3ddf8e8
remove systemRoles
okauppinen Nov 5, 2024
8bb2bd1
use isSystem and map response
okauppinen Nov 5, 2024
1887ef9
remove constants, systemRoles and use map response from util
okauppinen Nov 5, 2024
8018db6
use function for permissons key
okauppinen Nov 6, 2024
81bdcfd
move permissions key to map response
okauppinen Nov 6, 2024
5c69313
fix splitted roles
okauppinen Nov 6, 2024
6b22ece
listen maplayer update event
okauppinen Nov 8, 2024
d581ea6
selectedRole -> selected
okauppinen Nov 8, 2024
c94d7fd
remove published column
okauppinen Nov 8, 2024
a2000ba
fix layer column style and hide additional locales
okauppinen Nov 8, 2024
2cb274b
fix loc key and danger delete only when roles
okauppinen Nov 8, 2024
b5413d5
use selected lang instead of first
okauppinen Nov 27, 2024
278d5a2
resolve merge conflict
okauppinen Nov 27, 2024
f2093d4
add role to test
okauppinen Nov 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions bundles/admin/admin-layereditor/resources/locale/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,24 @@ Oskari.registerLocalization(
"PUBLISH": "Publish",
"VIEW_LAYER": "View",
"DOWNLOAD": "Download",
"VIEW_PUBLISHED": "View in Embedded map",
"role": "Role"
"VIEW_PUBLISHED": "View in Embedded map"
},
"permissions": {
"role": "Role",
"default": "Default permissions",
"onlyAdmin": "Only admin",
"published": "Published",
"removeOther": "Remove from additional roles",
"confirm": {
"remove": "Remove {count} permissions from the map layer?",
"override": "Layer has permissions for system roles. Do you want to set default permissions?"
},
"tooltip": {
"default": "Set default permissions for the layer (view, publish and view published)",
"onlyAdmin": "To set the layer visible only for admin users. You can add also permissions for additional roles to limit visibility.",
"published": "Guest user can view the map layer in published/embedded map.",
"removeOther": "Remove all permissions from additional roles."
}
}
}
}
Expand Down
20 changes: 18 additions & 2 deletions bundles/admin/admin-layereditor/resources/locale/fi.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,24 @@ Oskari.registerLocalization(
"PUBLISH": "Julkaisuoikeus",
"VIEW_LAYER": "Katseluoikeus",
"DOWNLOAD": "Latausoikeus",
"VIEW_PUBLISHED": "Katseluoikeus upotetussa kartassa",
"role": "Rooli"
"VIEW_PUBLISHED": "Katseluoikeus upotetussa kartassa"
},
"permissions": {
"role": "Rooli",
"default": "Oletusoikeudet",
"onlyAdmin": "Vain admin",
"published": "Julkinen",
"removeOther": "Poista lisärooleilta",
"confirm": {
"remove": "Poistetaan karttatasolta {count} oikeutta?",
"override": "Tasolla on jo perusrooleille oikeuksia. Haluatko asettaa oletusoikeudet?"
},
"tooltip": {
"default": "Aseta tasolle oletusoikeudet (katselu- ja julkaisoikeus sekä katseluoikeus upotetussa kartassa)",
"onlyAdmin": "Aseta näkyviin vain adminille. Voit lisäksi asettaa oikeuksia lisärooleille rajoittaaksesi tason näkyvyyttä.",
"published": "Vierailijan katseluoikeus upotetussa kartassa",
"removeOther": "Poista kaikki oikeudet lisärooleilta"
}
}
}
}
Expand Down
20 changes: 18 additions & 2 deletions bundles/admin/admin-layereditor/resources/locale/sv.js
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,24 @@ Oskari.registerLocalization(
"PUBLISH": "rätt att publicera",
"VIEW_LAYER": "rätt att visa",
"DOWNLOAD": "rätt att ladda ner",
"VIEW_PUBLISHED": "rätt att visa en publicerat vy",
"role": "Roll"
"VIEW_PUBLISHED": "rätt att visa en publicerat vy"
},
"permissions": {
"role": "Roll",
"default": "Standardrättigheter",
"onlyAdmin": "Endast admin",
"published": "Publicerat",
"removeOther": "Ta bort från ytterligare roller",
"confirm": {
"remove": "Ta bort {count} rättigheter från kartlagret?",
"override": "Layer har rättigheter för systemroller. Vill du ställa in standardrättigheter?"
},
"tooltip": {
"default": "Ställ in standardbehörigheter för lagret (visa, publicera och visa publicerat)",
"onlyAdmin": "För att ställa in lagret synligt endast för administratörsanvändare. Du kan även lägga till behörigheter för ytterligare roller för att begränsa synligheten.",
"published": "Gästanvändare kan se lagret i publicerat vy.",
"removeOther": "Ta bort alla behörigheter från ytterligare roller."
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Message } from 'oskari-ui';
import { handlePermissionForAllRoles, handlePermissionForSingleRole } from './PermissionUtil';
import { getWarningsForStyles } from './VisualizationTabPane/RasterStyle/helper';
import { TIME_SERIES_UI } from './VisualizationTabPane/TimeSeries';
import { getRolesFromResponse } from '../../../util/rolesHelper';

const LayerComposingModel = Oskari.clazz.get('Oskari.mapframework.domain.LayerComposingModel');
const DEFAULT_TAB = 'general';
Expand Down Expand Up @@ -1087,10 +1088,11 @@ class UIHandler extends StateHandler {
this.loadingCount--;
const currentLayer = this.getState().layer;
this.layerHelper.initPermissionsForLayer(currentLayer, data.roles);
const roles = getRolesFromResponse(data, 'name');
this.updateState({
layer: currentLayer,
loading: this.isLoading(),
metadata: data
metadata: { ...data, roles }
});
// invalidate cache if it was populated
Object.keys(__VALIDATOR_CACHE).forEach(key => delete __VALIDATOR_CACHE[key]);
Expand Down Expand Up @@ -1136,6 +1138,12 @@ class UIHandler extends StateHandler {
this.updateState({ layer });
}

setPermissions (permissions = {}) {
const { layer } = this.getState();
layer.role_permissions = permissions;
this.updateState({ layer });
}

saveVectorStyleToLayer (style, isEdit) {
const layer = this.getState().layer;
if (!Array.isArray(layer.vectorStyles)) {
Expand Down Expand Up @@ -1281,6 +1289,7 @@ const wrapped = controllerMixin(UIHandler, [
'showLayerMetadata',
'clearLayerCoverage',
'showLayerCoverage',
'toggleDeclutter'
'toggleDeclutter',
'setPermissions'
]);
export { wrapped as AdminLayerFormHandler };
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { Checkbox, Collapse, CollapsePanel, List, ListItem, Message } from 'oskari-ui';
import { Checkbox, Collapse, List, ListItem, Message } from 'oskari-ui';
import { Controller } from 'oskari-ui/util';
import { StyledFormField } from '../styled';
import styled from 'styled-components';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { Button, Message, Confirm, Tooltip } from 'oskari-ui';
import { ROLE_TYPES, SYSTEM_PERMISSIONS, PUBLISHED } from '../../../../util/constants';
import { getDefaultPermisions, hasDefaultPermissions, onlyAdmin, viewPublished } from '../../../../util/rolesHelper';

const Content = styled.div`
margin-bottom: 20px;
display: flex;
flex-direction: row;
> * {
margin-right: 10px;
}
`;

const ConfirmButton = ({ label, callback, confirm, ...rest }) => {
if (!confirm) {
return (
<Tooltip title={<Message messageKey={`permissions.tooltip.${label}`} />}>
<Button onClick={callback} { ...rest }>
<Message messageKey={`permissions.${label}`} />
</Button>
</Tooltip>
);
}
return (
<Confirm
placement='bottom'
title={confirm}
onConfirm={callback}>
<Tooltip title={<Message messageKey={`permissions.tooltip.${label}`} />}>
<Button { ...rest }>
<Message messageKey={`permissions.${label}`} />
</Button>
</Tooltip>
</Confirm>
);
};
ConfirmButton.propTypes = {
label: PropTypes.string.isRequired,
callback: PropTypes.func.isRequired,
confirm: PropTypes.any
};

export const DefaultPermissions = ({ roles, permissions, controller }) => {
const count = roles.reduce((sum, { name, isSystem }) => {
const key = isSystem ? 'system' : 'other';
sum[key] += permissions[name]?.length || 0;
return sum;
}, { system: 0, other: 0 });

const updatePermissions = (removeFrom, addToRoleType) => {
let updated = { ...permissions };
const remove = removeFrom === 'system'
? roles.filter(r => r.isSystem)
: roles.filter(r => !r.isSystem);
remove.forEach(({ name }) => {
updated[name] = [];
});
if (addToRoleType === 'default') {
const defaults = getDefaultPermisions(roles);
updated = { ...updated, ...defaults };
} else if (addToRoleType) {
const { name } = roles.find(r => r.type === addToRoleType);
updated[name] = [...SYSTEM_PERMISSIONS];
}
controller.setPermissions(updated);
};
const togglePublished = () => {
const guest = roles.find(r => r.type === ROLE_TYPES.GUEST).name;
controller.togglePermission(guest, PUBLISHED);
};
return (
<Content>
<ConfirmButton
label='default'
type={hasDefaultPermissions(roles, permissions) ? 'primary' : 'default'}
confirm={count.system > 0 && <Message messageKey='permissions.confirm.override'/>}
callback={() => updatePermissions('system', 'default')}/>
<ConfirmButton
label='onlyAdmin'
type={onlyAdmin(roles, permissions) ? 'primary' : 'default'}
confirm={count.system > 0 && <Message messageKey='permissions.confirm.override'/>}
callback={() => updatePermissions('system', ROLE_TYPES.ADMIN)}/>
<ConfirmButton
label='published'
type={viewPublished(roles, permissions) ? 'primary' : 'default'}
callback={() => togglePublished()}/>
<ConfirmButton
danger={count.other > 0}
label='removeOther'
confirm={count.other > 0 && <Message messageKey='permissions.confirm.remove' messageArgs={{ count: count.other }}/>}
callback={() => updatePermissions()}/>
</Content>
);
};

DefaultPermissions.propTypes = {
roles: PropTypes.array.isRequired,
permissions: PropTypes.object.isRequired,
controller: PropTypes.object.isRequired
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { Message } from 'oskari-ui';

const RowContainer = styled.div`
display: flex;
Expand All @@ -19,12 +20,13 @@ export const PERMISSION_TYPE_COLUMN_SIZE = {
padding: 5
};

// TODO: isHeaderRow rename prop
const TextColumn = styled.div`
flex-grow: 1;
width: ${TEXT_COLUMN_SIZE.width}px;
padding-left: ${TEXT_COLUMN_SIZE.padding}px;
align-self: ${props => props.isHeaderRow ? 'flex-end' : 'stretch'};
font-weight: ${props => props.isHeaderRow ? 'bold' : 'normal'};
font-weight: ${props => props.isHeaderRow || props.isSystemRole ? 'bold' : 'normal'};
`;

const StyledPermissionDiv = styled.div`
Expand Down Expand Up @@ -54,13 +56,13 @@ const SelectAllDiv = styled.div`
padding-bottom: 5px;
`;

export const PermissionRow = (props) => {
const checkboxDivs = props.checkboxes.map(checkbox => {
var content = checkbox;
if (props.isHeaderRow) {
export const PermissionRow = ({ isHeaderRow, checkboxes, role }) => {
const checkboxDivs = checkboxes.map(checkbox => {
let content = checkbox;
if (isHeaderRow) {
content = (
<React.Fragment>
<HeaderPermissionText>{checkbox.props.permissionDescription}</HeaderPermissionText>
<HeaderPermissionText>{checkbox.props.description}</HeaderPermissionText>
<Break/>
<SelectAllDiv>{content}</SelectAllDiv>
</React.Fragment>);
Expand All @@ -69,19 +71,19 @@ export const PermissionRow = (props) => {
{content}
</StyledPermissionDiv>);
});

const label = isHeaderRow ? <Message messageKey='permissions.role'/> : role.name;
return (
<RowContainer>
<TextColumn isHeaderRow={props.isHeaderRow}>
{ props.text }
<TextColumn isHeaderRow={isHeaderRow || role.isSystem}>
{ label }
</TextColumn>
{ checkboxDivs }
</RowContainer>
);
};

PermissionRow.propTypes = {
text: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
role: PropTypes.object,
checkboxes: PropTypes.array.isRequired,
isHeaderRow: PropTypes.bool.isRequired
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('<PermissionRow/>', () => {
const mockText = 'Mock rolename text';
const mockCheckboxes = [<Checkbox data-testid={mockText} key={'key1'} onChange={() => console.log('Not called in this test')}/>,
<Checkbox data-testid={mockText} key={'key2'} onChange={() => console.log('Not called in this test')}/>];
const row = render(<PermissionRow text={mockText} checkboxes={mockCheckboxes}
const row = render(<PermissionRow text={mockText} checkboxes={mockCheckboxes} role={{ name: mockText }}
isHeaderRow={false}/>);

expect(screen.queryAllByText(mockText)).toHaveLength(1);
Expand Down
Loading