From 0711475d78e9529d2e0286b5a496671b1361ce4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 18 Jan 2019 13:21:54 +0100 Subject: [PATCH] Copy user permission administration for groups --- scm-ui/public/locales/en/groups.json | 6 + .../groups/components/SetGroupPermissions.js | 198 ++++++++++++++++++ .../navLinks/SetPermissionsNavLink.js | 28 +++ .../src/groups/components/navLinks/index.js | 3 +- .../src/groups/components/setPermissions.js | 13 ++ scm-ui/src/groups/containers/SingleGroup.js | 16 +- 6 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 scm-ui/src/groups/components/SetGroupPermissions.js create mode 100644 scm-ui/src/groups/components/navLinks/SetPermissionsNavLink.js create mode 100644 scm-ui/src/groups/components/setPermissions.js diff --git a/scm-ui/public/locales/en/groups.json b/scm-ui/public/locales/en/groups.json index f1ebb95e18..7caa89e5ee 100644 --- a/scm-ui/public/locales/en/groups.json +++ b/scm-ui/public/locales/en/groups.json @@ -63,5 +63,11 @@ "submit": "Yes", "cancel": "No" } + }, + "set-permissions-button": { + "label": "Set permissions" + }, + "permissions": { + "set-permissions-successful": "Permissions successfully set" } } diff --git a/scm-ui/src/groups/components/SetGroupPermissions.js b/scm-ui/src/groups/components/SetGroupPermissions.js new file mode 100644 index 0000000000..ae4fb1f8d8 --- /dev/null +++ b/scm-ui/src/groups/components/SetGroupPermissions.js @@ -0,0 +1,198 @@ +// @flow +import React from "react"; +import type { Group } from "@scm-manager/ui-types"; +import { + Notification, + ErrorNotification, + SubmitButton +} from "@scm-manager/ui-components"; +import { translate } from "react-i18next"; +import { setPermissions } from "./setPermissions"; +import { apiClient } from "@scm-manager/ui-components"; +import PermissionCheckbox from "../../users/components/PermissionCheckbox"; +import { connect } from "react-redux"; +import { getLink } from "../../modules/indexResource"; + +type Props = { + group: Group, + t: string => string, + permissionLink: string +}; + +type State = { + permissions: { [string]: boolean }, + loading: boolean, + error?: Error, + permissionsChanged: boolean, + permissionsSubmitted: boolean, + modifiable: boolean +}; + +class SetGroupPermissions extends React.Component { + constructor(props: Props) { + super(props); + + this.state = { + permissions: { perm1: false, perm2: false }, + loading: true, + permissionsChanged: false, + permissionsSubmitted: false, + modifiable: false + }; + } + + setLoadingState = () => { + this.setState({ + ...this.state, + loading: true + }); + }; + + setErrorState = (error: Error) => { + this.setState({ + ...this.state, + error: error, + loading: false + }); + }; + + setSuccessfulState = () => { + this.setState({ + ...this.state, + loading: false, + permissionsSubmitted: true, + permissionsChanged: false + }); + }; + + componentDidMount(): void { + apiClient + .get(this.props.permissionLink) + .then(response => { + return response.json(); + }) + .then(response => { + const availablePermissions = response.permissions; + const permissions = {}; + availablePermissions.forEach(p => { + permissions[p] = false; + }); + this.setState({ permissions }, this.loadPermissionsForGroup); + }); + } + + loadPermissionsForGroup = () => { + apiClient + .get(this.props.group._links.permissions.href) + .then(response => { + return response.json(); + }) + .then(response => { + const checkedPermissions = response.permissions; + const modifiable = !!response._links.overwrite; + this.setState(state => { + const newPermissions = state.permissions; + checkedPermissions.forEach(name => (newPermissions[name] = true)); + return { + loading: false, + modifiable: modifiable, + permissions: newPermissions + }; + }); + }); + }; + + submit = (event: Event) => { + event.preventDefault(); + if (this.state.permissions) { + const { group } = this.props; + const { permissions } = this.state; + this.setLoadingState(); + const selectedPermissions = Object.entries(permissions) + .filter(e => e[1]) + .map(e => e[0]); + setPermissions(group._links.permissions.href, selectedPermissions) + .then(result => { + if (result.error) { + this.setErrorState(result.error); + } else { + this.setSuccessfulState(); + } + }) + .catch(err => {}); + } + }; + + render() { + const { t } = this.props; + const { loading, permissionsSubmitted, error } = this.state; + + let message = null; + + if (permissionsSubmitted) { + message = ( + this.onClose()} + /> + ); + } else if (error) { + message = ; + } + + return ( +
+ {message} + {this.renderPermissions()} + + + ); + } + + renderPermissions = () => { + const { modifiable, permissions } = this.state; + return Object.keys(permissions).map(p => ( +
+ +
+ )); + }; + + valueChanged = (value: boolean, name: string) => { + this.setState(state => { + const newPermissions = state.permissions; + newPermissions[name] = value; + return { + permissions: newPermissions, + permissionsChanged: true + }; + }); + }; + + onClose = () => { + this.setState({ + permissionsSubmitted: false + }); + }; +} + +const mapStateToProps = state => { + const permissionLink = getLink(state, "permissions"); + return { + permissionLink + }; +}; + +export default connect(mapStateToProps)( + translate("groups")(SetGroupPermissions) +); diff --git a/scm-ui/src/groups/components/navLinks/SetPermissionsNavLink.js b/scm-ui/src/groups/components/navLinks/SetPermissionsNavLink.js new file mode 100644 index 0000000000..41bc57da30 --- /dev/null +++ b/scm-ui/src/groups/components/navLinks/SetPermissionsNavLink.js @@ -0,0 +1,28 @@ +//@flow +import React from "react"; +import { translate } from "react-i18next"; +import type { Group } from "@scm-manager/ui-types"; +import { NavLink } from "@scm-manager/ui-components"; + +type Props = { + t: string => string, + group: Group, + permissionsUrl: String +}; + +class ChangePermissionNavLink extends React.Component { + render() { + const { t, permissionsUrl } = this.props; + + if (!this.hasPermissionToSetPermission()) { + return null; + } + return ; + } + + hasPermissionToSetPermission = () => { + return this.props.group._links.permissions; + }; +} + +export default translate("groups")(ChangePermissionNavLink); diff --git a/scm-ui/src/groups/components/navLinks/index.js b/scm-ui/src/groups/components/navLinks/index.js index 30fdd34b6d..e589e5b6c9 100644 --- a/scm-ui/src/groups/components/navLinks/index.js +++ b/scm-ui/src/groups/components/navLinks/index.js @@ -1,2 +1,3 @@ export { default as DeleteGroupNavLink } from "./DeleteGroupNavLink"; -export { default as EditGroupNavLink } from "./EditGroupNavLink"; +export { default as EditGroupNavLink } from "./EditGroupNavLink"; +export { default as SetPermissionsNavLink } from "./SetPermissionsNavLink"; diff --git a/scm-ui/src/groups/components/setPermissions.js b/scm-ui/src/groups/components/setPermissions.js new file mode 100644 index 0000000000..4c54036fab --- /dev/null +++ b/scm-ui/src/groups/components/setPermissions.js @@ -0,0 +1,13 @@ +//@flow +import { apiClient } from "@scm-manager/ui-components"; + +export const CONTENT_TYPE_PERMISSIONS = + "application/vnd.scmm-permissionCollection+json;v=2"; + +export function setPermissions(url: string, permissions: string[]) { + return apiClient + .put(url, { permissions: permissions }, CONTENT_TYPE_PERMISSIONS) + .then(response => { + return response; + }); +} diff --git a/scm-ui/src/groups/containers/SingleGroup.js b/scm-ui/src/groups/containers/SingleGroup.js index 1dd4aa569f..ce60898700 100644 --- a/scm-ui/src/groups/containers/SingleGroup.js +++ b/scm-ui/src/groups/containers/SingleGroup.js @@ -11,7 +11,11 @@ import { } from "@scm-manager/ui-components"; import { Route } from "react-router"; import { Details } from "./../components/table"; -import { DeleteGroupNavLink, EditGroupNavLink } from "./../components/navLinks"; +import { + DeleteGroupNavLink, + EditGroupNavLink, + SetPermissionsNavLink +} from "./../components/navLinks"; import type { Group } from "@scm-manager/ui-types"; import type { History } from "history"; import { @@ -27,6 +31,7 @@ import { import { translate } from "react-i18next"; import EditGroup from "./EditGroup"; import { getGroupsLink } from "../../modules/indexResource"; +import SetGroupPermissions from "../components/SetGroupPermissions"; type Props = { name: string, @@ -102,6 +107,11 @@ class SingleGroup extends React.Component { exact component={() => } /> + } + />
@@ -110,6 +120,10 @@ class SingleGroup extends React.Component { to={`${url}`} label={t("single-group.information-label")} /> +