@@ -133,11 +133,13 @@ class SettingsNav extends React.Component { | |||
</IndexLink> | |||
</li> | |||
)} | |||
<li> | |||
<IndexLink to="/roles/global" activeClassName="active"> | |||
{translate('global_permissions.page')} | |||
</IndexLink> | |||
</li> | |||
{!this.props.customOrganizations && ( | |||
<li> | |||
<IndexLink to="/roles/global" activeClassName="active"> | |||
{translate('global_permissions.page')} | |||
</IndexLink> | |||
</li> | |||
)} | |||
{!this.props.customOrganizations && ( | |||
<li> | |||
<IndexLink to="/permission_templates" activeClassName="active"> |
@@ -0,0 +1,43 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
// @flow | |||
import React from 'react'; | |||
import { connect } from 'react-redux'; | |||
import GlobalPermissionsApp from '../../permissions/global/components/App'; | |||
import { getOrganizationByKey } from '../../../store/rootReducer'; | |||
import type { Organization } from '../../../store/organizations/duck'; | |||
class OrganizationPermissions extends React.Component { | |||
props: { | |||
organization: Organization | |||
}; | |||
render () { | |||
return ( | |||
<GlobalPermissionsApp organization={this.props.organization}/> | |||
); | |||
} | |||
} | |||
const mapStateToProps = (state, ownProps) => ({ | |||
organization: getOrganizationByKey(state, ownProps.params.organizationKey) | |||
}); | |||
export default connect(mapStateToProps)(OrganizationPermissions); |
@@ -26,6 +26,7 @@ const ADMIN_PATHS = [ | |||
'edit', | |||
'groups', | |||
'delete', | |||
'permissions', | |||
'permission_templates' | |||
]; | |||
@@ -57,6 +58,11 @@ export default class OrganizationNavigation extends React.Component { | |||
{translate('user_groups.page')} | |||
</Link> | |||
</li> | |||
<li> | |||
<Link to={`/organizations/${organization.key}/permissions`} activeClassName="active"> | |||
{translate('permissions')} | |||
</Link> | |||
</li> | |||
<li> | |||
<Link to={`/organizations/${organization.key}/permission_templates`} activeClassName="active"> | |||
{translate('permission_templates')} |
@@ -51,6 +51,15 @@ exports[`test admin 1`] = ` | |||
user_groups.page | |||
</Link> | |||
</li> | |||
<li> | |||
<Link | |||
activeClassName="active" | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to="/organizations/foo/permissions"> | |||
permissions | |||
</Link> | |||
</li> | |||
<li> | |||
<Link | |||
activeClassName="active" |
@@ -25,6 +25,7 @@ import OrganizationFavoriteProjects from './components/OrganizationFavoriteProje | |||
import OrganizationAdmin from './components/OrganizationAdmin'; | |||
import OrganizationEdit from './components/OrganizationEdit'; | |||
import OrganizationGroups from './components/OrganizationGroups'; | |||
import OrganizationPermissions from './components/OrganizationPermissions'; | |||
import OrganizationPermissionTemplates from './components/OrganizationPermissionTemplates'; | |||
import OrganizationDelete from './components/OrganizationDelete'; | |||
@@ -37,6 +38,7 @@ export default ( | |||
<Route path="delete" component={OrganizationDelete}/> | |||
<Route path="edit" component={OrganizationEdit}/> | |||
<Route path="groups" component={OrganizationGroups}/> | |||
<Route path="permissions" component={OrganizationPermissions}/> | |||
<Route path="permission_templates" component={OrganizationPermissionTemplates}/> | |||
</Route> | |||
</Route> |
@@ -48,6 +48,12 @@ const PERMISSIONS_ORDER = [ | |||
'provisioning' | |||
]; | |||
const PERMISSIONS_FOR_CUSTOM_ORG = [ | |||
'admin', | |||
'scan', | |||
'provisioning' | |||
]; | |||
class AllHoldersList extends React.Component { | |||
componentDidMount () { | |||
this.props.loadHolders(); | |||
@@ -74,10 +80,16 @@ class AllHoldersList extends React.Component { | |||
} | |||
render () { | |||
const permissions = PERMISSIONS_ORDER.map(p => ({ | |||
const order = (this.props.organization && !this.props.organization.isDefault) ? | |||
PERMISSIONS_FOR_CUSTOM_ORG : | |||
PERMISSIONS_ORDER; | |||
const l10nPrefix = this.props.organization ? 'organizations_permissions' : 'global_permissions'; | |||
const permissions = order.map(p => ({ | |||
key: p, | |||
name: translate('global_permissions', p), | |||
description: translate('global_permissions', p, 'desc') | |||
name: translate(l10nPrefix, p), | |||
description: translate(l10nPrefix, p, 'desc') | |||
})); | |||
return ( | |||
@@ -109,19 +121,19 @@ const mapStateToProps = state => ({ | |||
selectedPermission: getPermissionsAppSelectedPermission(state) | |||
}); | |||
const mapDispatchToProps = dispatch => ({ | |||
loadHolders: () => dispatch(loadHolders()), | |||
onSearch: query => dispatch(updateQuery(query)), | |||
onFilter: filter => dispatch(updateFilter(filter)), | |||
onSelectPermission: permission => dispatch(selectPermission(permission)), | |||
const mapDispatchToProps = (dispatch, ownProps) => ({ | |||
loadHolders: () => dispatch(loadHolders(ownProps.organization)), | |||
onSearch: query => dispatch(updateQuery(query, ownProps.organization)), | |||
onFilter: filter => dispatch(updateFilter(filter, ownProps.organization)), | |||
onSelectPermission: permission => dispatch(selectPermission(permission, ownProps.organization)), | |||
grantPermissionToUser: (login, permission) => | |||
dispatch(grantToUser(login, permission)), | |||
dispatch(grantToUser(login, permission, ownProps.organization)), | |||
revokePermissionFromUser: (login, permission) => | |||
dispatch(revokeFromUser(login, permission)), | |||
dispatch(revokeFromUser(login, permission, ownProps.organization)), | |||
grantPermissionToGroup: (groupName, permission) => | |||
dispatch(grantToGroup(groupName, permission)), | |||
dispatch(grantToGroup(groupName, permission, ownProps.organization)), | |||
revokePermissionFromGroup: (groupName, permission) => | |||
dispatch(revokeFromGroup(groupName, permission)) | |||
dispatch(revokeFromGroup(groupName, permission, ownProps.organization)) | |||
}); | |||
export default connect( |
@@ -17,6 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
// @flow | |||
import React from 'react'; | |||
import PageHeader from './PageHeader'; | |||
import AllHoldersList from './AllHoldersList'; | |||
@@ -26,12 +27,16 @@ import '../../styles.css'; | |||
// TODO helmet | |||
export default class App extends React.Component { | |||
props: { | |||
organization?: {} | |||
}; | |||
render () { | |||
return ( | |||
<div className="page page-limited"> | |||
<PageHeader/> | |||
<PageError/> | |||
<AllHoldersList/> | |||
<AllHoldersList organization={this.props.organization}/> | |||
</div> | |||
); | |||
} |
@@ -37,7 +37,7 @@ import { | |||
getPermissionsAppSelectedPermission | |||
} from '../../../../store/rootReducer'; | |||
export const loadHolders = () => (dispatch, getState) => { | |||
export const loadHolders = organization => (dispatch, getState) => { | |||
const query = getPermissionsAppQuery(getState()); | |||
const filter = getPermissionsAppFilter(getState()); | |||
const selectedPermission = getPermissionsAppSelectedPermission(getState()); | |||
@@ -47,13 +47,13 @@ export const loadHolders = () => (dispatch, getState) => { | |||
const requests = []; | |||
if (filter !== 'groups') { | |||
requests.push(api.getGlobalPermissionsUsers(query, selectedPermission)); | |||
requests.push(api.getGlobalPermissionsUsers(query, selectedPermission, organization)); | |||
} else { | |||
requests.push(Promise.resolve([])); | |||
} | |||
if (filter !== 'users') { | |||
requests.push(api.getGlobalPermissionsGroups(query, selectedPermission)); | |||
requests.push(api.getGlobalPermissionsGroups(query, selectedPermission, organization)); | |||
} else { | |||
requests.push(Promise.resolve([])); | |||
} | |||
@@ -70,46 +70,46 @@ export const loadHolders = () => (dispatch, getState) => { | |||
}); | |||
}; | |||
export const updateQuery = (query = '') => dispatch => { | |||
export const updateQuery = (query = '', organization) => dispatch => { | |||
dispatch({ type: UPDATE_QUERY, query }); | |||
if (query.length === 0 || query.length > 2) { | |||
dispatch(loadHolders()); | |||
dispatch(loadHolders(organization)); | |||
} | |||
}; | |||
export const updateFilter = filter => dispatch => { | |||
export const updateFilter = (filter, organization) => dispatch => { | |||
dispatch({ type: UPDATE_FILTER, filter }); | |||
dispatch(loadHolders()); | |||
dispatch(loadHolders(organization)); | |||
}; | |||
export const selectPermission = permission => (dispatch, getState) => { | |||
export const selectPermission = (permission, organization) => (dispatch, getState) => { | |||
const selectedPermission = getPermissionsAppSelectedPermission(getState()); | |||
if (selectedPermission !== permission) { | |||
dispatch({ type: SELECT_PERMISSION, permission }); | |||
} else { | |||
dispatch({ type: SELECT_PERMISSION, permission: null }); | |||
} | |||
dispatch(loadHolders()); | |||
dispatch(loadHolders(organization)); | |||
}; | |||
export const grantToUser = (login, permission) => dispatch => { | |||
api.grantPermissionToUser(null, login, permission).then(() => { | |||
export const grantToUser = (login, permission, organization) => dispatch => { | |||
api.grantPermissionToUser(null, login, permission, organization).then(() => { | |||
dispatch({ type: GRANT_PERMISSION_TO_USER, login, permission }); | |||
}).catch(e => { | |||
return parseError(e).then(message => dispatch(raiseError(message))); | |||
}); | |||
}; | |||
export const revokeFromUser = (login, permission) => dispatch => { | |||
api.revokePermissionFromUser(null, login, permission).then(() => { | |||
export const revokeFromUser = (login, permission, organization) => dispatch => { | |||
api.revokePermissionFromUser(null, login, permission, organization).then(() => { | |||
dispatch({ type: REVOKE_PERMISSION_TO_USER, login, permission }); | |||
}).catch(e => { | |||
return parseError(e).then(message => dispatch(raiseError(message))); | |||
}); | |||
}; | |||
export const grantToGroup = (groupName, permission) => dispatch => { | |||
api.grantPermissionToGroup(null, groupName, permission).then(() => { | |||
export const grantToGroup = (groupName, permission, organization) => dispatch => { | |||
api.grantPermissionToGroup(null, groupName, permission, organization).then(() => { | |||
dispatch({ | |||
type: GRANT_PERMISSION_TO_GROUP, | |||
groupName, | |||
@@ -120,8 +120,8 @@ export const grantToGroup = (groupName, permission) => dispatch => { | |||
}); | |||
}; | |||
export const revokeFromGroup = (groupName, permission) => dispatch => { | |||
api.revokePermissionFromGroup(null, groupName, permission).then(() => { | |||
export const revokeFromGroup = (groupName, permission, organization) => dispatch => { | |||
api.revokePermissionFromGroup(null, groupName, permission, organization).then(() => { | |||
dispatch({ | |||
type: REVOKE_PERMISSION_FROM_GROUP, | |||
groupName, |
@@ -2315,6 +2315,27 @@ global_permissions.scan.desc=Ability to get all settings required to perform an | |||
global_permissions.provisioning=Create Projects | |||
global_permissions.provisioning.desc=Ability to initialize a project so its settings can be configured before the first analysis. | |||
#------------------------------------------------------------------------------ | |||
# | |||
# ORGANIZATIONS PERMISSIONS | |||
# | |||
#------------------------------------------------------------------------------ | |||
organizations_permissions.admin=Administer Organization | |||
organizations_permissions.admin.desc=Ability to perform all administration functions for the organization. | |||
organizations_permissions.profileadmin=Administer Quality Profiles | |||
organizations_permissions.profileadmin.desc=Ability to perform any action on quality profiles. | |||
organizations_permissions.gateadmin=Administer Quality Gates | |||
organizations_permissions.gateadmin.desc=Ability to perform any action on quality gates. | |||
organizations_permissions.scan=Execute Analysis | |||
organizations_permissions.scan.desc=Ability to get all settings required to perform an analysis (including the secured settings like passwords) and to push analysis results to the SonarQube server. | |||
organizations_permissions.provisioning=Create Projects | |||
organizations_permissions.provisioning.desc=Ability to initialize a project so its settings can be configured before the first analysis. | |||
#------------------------------------------------------------------------------ | |||
# | |||
# PROJECTS PERMISSIONS |