diff options
author | Stas Vilchik <vilchiks@gmail.com> | 2015-08-26 16:55:32 +0200 |
---|---|---|
committer | Stas Vilchik <vilchiks@gmail.com> | 2015-08-26 16:55:32 +0200 |
commit | 5da21a945d8b11b647ee8c0eca996a005386317f (patch) | |
tree | 66032324c96a91fe275b167dfac097c079377862 /server | |
parent | db17082eea791372e587b9762b0871766591fa18 (diff) | |
download | sonarqube-5da21a945d8b11b647ee8c0eca996a005386317f.tar.gz sonarqube-5da21a945d8b11b647ee8c0eca996a005386317f.zip |
SONAR-6805 Rewrite project permissions page on a project level
Diffstat (limited to 'server')
13 files changed, 130 insertions, 77 deletions
diff --git a/server/sonar-web/src/main/js/apps/global-permissions/groups-view.js b/server/sonar-web/src/main/js/apps/global-permissions/groups-view.js index fbc0691ed6d..950c9888a61 100644 --- a/server/sonar-web/src/main/js/apps/global-permissions/groups-view.js +++ b/server/sonar-web/src/main/js/apps/global-permissions/groups-view.js @@ -4,6 +4,22 @@ define([ './templates' ], function (Modal) { + function getSearchUrl(permission, project) { + var url = baseUrl + '/api/permissions/groups?ps=100&permission=' + permission; + if (project) { + url = url + '&projectId=' + project; + } + return url; + } + + function getExtra (permission, project) { + var extra = { permission: permission }; + if (project) { + extra.projectId = project; + } + return extra; + } + return Modal.extend({ template: Templates['global-permissions-groups'], @@ -18,12 +34,10 @@ define([ return item.name; }, queryParam: 'q', - searchUrl: baseUrl + '/api/permissions/groups?ps=100&permission=' + this.options.permission, + searchUrl: getSearchUrl(this.options.permission, this.options.project), selectUrl: baseUrl + '/api/permissions/add_group', deselectUrl: baseUrl + '/api/permissions/remove_group', - extra: { - permission: this.options.permission - }, + extra: getExtra(this.options.permission, this.options.project), selectParameter: 'groupName', selectParameterValue: 'name', parse: function (r) { diff --git a/server/sonar-web/src/main/js/apps/global-permissions/permission-groups.jsx b/server/sonar-web/src/main/js/apps/global-permissions/permission-groups.jsx index e710f3713b0..7a38d84c0a6 100644 --- a/server/sonar-web/src/main/js/apps/global-permissions/permission-groups.jsx +++ b/server/sonar-web/src/main/js/apps/global-permissions/permission-groups.jsx @@ -27,6 +27,7 @@ export default React.createClass({ e.preventDefault(); new GroupsView({ permission: this.props.permission.key, + project: this.props.project, refresh: this.props.refresh }).render(); } diff --git a/server/sonar-web/src/main/js/apps/global-permissions/permission-users.jsx b/server/sonar-web/src/main/js/apps/global-permissions/permission-users.jsx index 3d8fe5df33f..56f52feed0d 100644 --- a/server/sonar-web/src/main/js/apps/global-permissions/permission-users.jsx +++ b/server/sonar-web/src/main/js/apps/global-permissions/permission-users.jsx @@ -28,6 +28,7 @@ export default React.createClass({ e.preventDefault(); new UsersView({ permission: this.props.permission.key, + project: this.props.project, refresh: this.props.refresh }).render(); } diff --git a/server/sonar-web/src/main/js/apps/global-permissions/permission.jsx b/server/sonar-web/src/main/js/apps/global-permissions/permission.jsx index 1e87875a64b..ac259f521de 100644 --- a/server/sonar-web/src/main/js/apps/global-permissions/permission.jsx +++ b/server/sonar-web/src/main/js/apps/global-permissions/permission.jsx @@ -23,13 +23,19 @@ export default React.createClass({ requestUsers() { const url = `${window.baseUrl}/api/permissions/users`; - const data = { permission: this.props.permission.key, ps: MAX_ITEMS }; + let data = { permission: this.props.permission.key, ps: MAX_ITEMS }; + if (this.props.project) { + data.projectId = this.props.project; + } $.get(url, data).done(r => this.setState({ users: r.users, totalUsers: r.paging && r.paging.total })); }, requestGroups() { const url = `${window.baseUrl}/api/permissions/groups`; - const data = { permission: this.props.permission.key, ps: MAX_ITEMS }; + let data = { permission: this.props.permission.key, ps: MAX_ITEMS }; + if (this.props.project) { + data.projectId = this.props.project; + } $.get(url, data).done(r => this.setState({ groups: r.groups, totalGroups: r.paging && r.paging.total })); }, @@ -40,11 +46,13 @@ export default React.createClass({ <p className="spacer-top" dangerouslySetInnerHTML={{ __html: this.props.permission.description }}/> <ul className="list-inline spacer-top"> <PermissionUsers permission={this.props.permission} + project={this.props.project} max={MAX_ITEMS} items={this.state.users} total={this.state.totalUsers || this.props.permission.usersCount} refresh={this.requestUsers}/> <PermissionGroups permission={this.props.permission} + project={this.props.project} max={MAX_ITEMS} items={this.state.groups} total={this.state.totalGroups || this.props.permission.groupsCount} diff --git a/server/sonar-web/src/main/js/apps/global-permissions/permissions-list.jsx b/server/sonar-web/src/main/js/apps/global-permissions/permissions-list.jsx index 432f020e1e1..e019fbcbfec 100644 --- a/server/sonar-web/src/main/js/apps/global-permissions/permissions-list.jsx +++ b/server/sonar-web/src/main/js/apps/global-permissions/permissions-list.jsx @@ -8,7 +8,7 @@ export default React.createClass({ renderPermissions() { return this.props.permissions.map(permission => { - return <Permission key={permission.key} permission={permission}/> + return <Permission key={permission.key} permission={permission} project={this.props.project}/>; }); }, diff --git a/server/sonar-web/src/main/js/apps/global-permissions/users-view.js b/server/sonar-web/src/main/js/apps/global-permissions/users-view.js index 1c0a0937038..8146bfef5e9 100644 --- a/server/sonar-web/src/main/js/apps/global-permissions/users-view.js +++ b/server/sonar-web/src/main/js/apps/global-permissions/users-view.js @@ -4,6 +4,22 @@ define([ './templates' ], function (Modal) { + function getSearchUrl (permission, project) { + var url = baseUrl + '/api/permissions/users?ps=100&permission=' + permission; + if (project) { + url = url + '&projectId=' + project; + } + return url; + } + + function getExtra (permission, project) { + var extra = { permission: permission }; + if (project) { + extra.projectId = project; + } + return extra; + } + return Modal.extend({ template: Templates['global-permissions-users'], @@ -18,12 +34,10 @@ define([ return item.name + '<br><span class="note">' + item.login + '</span>'; }, queryParam: 'q', - searchUrl: baseUrl + '/api/permissions/users?ps=100&permission=' + this.options.permission, + searchUrl: getSearchUrl(this.options.permission, this.options.project), selectUrl: baseUrl + '/api/permissions/add_user', deselectUrl: baseUrl + '/api/permissions/remove_user', - extra: { - permission: this.options.permission - }, + extra: getExtra(this.options.permission, this.options.project), selectParameter: 'login', selectParameterValue: 'login', parse: function (r) { diff --git a/server/sonar-web/src/main/js/apps/main/app.jsx b/server/sonar-web/src/main/js/apps/main/app.jsx index 97c3d781c2f..938b2e8e184 100644 --- a/server/sonar-web/src/main/js/apps/main/app.jsx +++ b/server/sonar-web/src/main/js/apps/main/app.jsx @@ -23,7 +23,7 @@ const APP_URL_MAPPING = { 'overview': 'overview/app', 'permission_templates': 'select-list/app', 'profiles': 'quality-profiles/app', - 'project_roles': 'select-list/app', + 'project_roles': 'project-permissions/app', 'provisioning': 'provisioning/app', 'quality_gates': 'quality-gates/app', 'roles/global': 'global-permissions/app', diff --git a/server/sonar-web/src/main/js/apps/project-permissions/app.jsx b/server/sonar-web/src/main/js/apps/project-permissions/app.jsx index 478924e9233..54d4fee2fb6 100644 --- a/server/sonar-web/src/main/js/apps/project-permissions/app.jsx +++ b/server/sonar-web/src/main/js/apps/project-permissions/app.jsx @@ -1,11 +1,14 @@ import React from 'react'; import Main from './main'; - -const $ = jQuery; +import MainComponent from './main-component'; export default { start(options) { var el = document.querySelector(options.el); - React.render(<Main/>, el); + if (options.component) { + React.render(<MainComponent component={options.component}/>, el); + } else { + React.render(<Main/>, el); + } } }; diff --git a/server/sonar-web/src/main/js/apps/project-permissions/main-component.jsx b/server/sonar-web/src/main/js/apps/project-permissions/main-component.jsx new file mode 100644 index 00000000000..2df3f3694a9 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/project-permissions/main-component.jsx @@ -0,0 +1,55 @@ +import _ from 'underscore'; +import React from 'react'; +import PermissionsList from '../global-permissions/permissions-list'; + +let $ = jQuery; + +const PERMISSIONS_ORDER = ['user', 'codeviewer', 'issueadmin', 'admin']; + +export default React.createClass({ + getInitialState() { + return { permissions: [] }; + }, + + componentDidMount() { + this.requestPermissions(); + }, + + sortPermissions(permissions) { + return _.sortBy(permissions, p => PERMISSIONS_ORDER.indexOf(p.key)); + }, + + mergePermissionsToProjects(projects, basePermissions) { + return projects.map(project => { + // it's important to keep the order of the project permissions the same as the order of base permissions + let permissions = basePermissions.map(basePermission => { + let projectPermission = _.findWhere(project.permissions, { key: basePermission.key }); + return _.extend({ usersCount: 0, groupsCount: 0 }, basePermission, projectPermission); + }); + return _.extend({}, project, { permissions: permissions }); + }); + }, + + requestPermissions(page = 1, query = '') { + let url = `${window.baseUrl}/api/permissions/search_project_permissions`; + let data = { projectId: this.props.component.uuid, p: page, q: query }; + $.get(url, data).done(r => { + let permissions = this.sortPermissions(r.permissions); + let projects = this.mergePermissionsToProjects(r.projects, permissions); + this.setState({ permissions: projects[0].permissions }); + }); + }, + + render() { + return ( + <div className="page"> + <header id="project-permissions-header" className="page-header"> + <h1 className="page-title">{window.t('roles.page')}</h1> + <p className="page-description">{window.t('roles.page.description2')}</p> + </header> + + <PermissionsList permissions={this.state.permissions} project={this.props.component.uuid}/> + </div> + ); + } +}); diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_roles_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_roles_controller.rb index b6923e8d593..2dab45040b0 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_roles_controller.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_roles_controller.rb @@ -22,11 +22,9 @@ class ProjectRolesController < ApplicationController SECTION=Navigation::SECTION_RESOURCE - # GET /project_roles/@project def index - @project=Project.by_key(params[:id]) + @project = Project.by_key(params[:id]) access_denied unless is_admin?(@project) - @snapshot=@project.last_snapshot end end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project_roles/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project_roles/index.html.erb index 3cc6ca69a66..e69de29bb2d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/project_roles/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/project_roles/index.html.erb @@ -1,57 +0,0 @@ -<div class="page"> - <header class="page-header"> - <h1 class="page-title"><%= message('project_links.page') -%></h1> - <div class="page-actions"> - <div class="button-group"> - <%= link_to message('projects_role.apply_template'), - {:controller => :roles, :action => :apply_template_form, :components => [@project.key], :names => @project.name, :results_count => 1}, - :id => "apply-template-#{u @project.kee}", :class => 'open-modal link-action button' %> - </div> - </div> - <p class="page-description"><%= message('project_links.page.description') -%></p> - </header> - - <table class="data width100"> - <thead> - <tr> - <th> </th> - <th> - <%= message('projects_role.user') -%><br/> - <span class="small gray" style="font-size: 11px; font-weight: normal;"><%= message('projects_role.user.desc') -%></span> - </th> - <th> - <%= message('projects_role.admin') -%><br/> - <span class="small gray" style="font-size: 11px; font-weight: normal;"><%= message('projects_role.admin.desc') -%></span> - </th> - <th> - <%= message('projects_role.issueadmin') -%><br/> - <span class="small gray" style="font-size: 11px; font-weight: normal;"><%= message('projects_role.issueadmin.desc') -%></span> - </th> - <th> - <%= message('projects_role.codeviewer') -%><br/> - <span class="small gray" style="font-size: 11px; font-weight: normal;"><%= message('projects_role.codeviewer.desc') -%></span> - </th> - </tr> - </thead> - <tbody> - <tr class="even"> - <td valign="top"><b>Users</b></td> - <% ['user', 'admin', 'issueadmin', 'codeviewer'].each do |permission| -%> - <td valign="top"> - <span id="<%= permission -%>-role-users"><%= users(permission, @project.id).map(&:name).join(', ') %></span> - (<%= link_to_edit_roles_permission_form(message('select'), permission, @project.id, "select-#{permission}-edit-users") %>)<br/> - </td> - <% end %> - </tr> - <tr class="odd"> - <td valign="top"><b>Groups</b></td> - <% ['user', 'admin', 'issueadmin', 'codeviewer'].each do |permission| -%> - <td valign="top"> - <span id="<%= permission -%>-role-groups"><%= groups(permission, @project.id).map{|g| group_name(g)}.join(', ') %></span> - (<%= link_to_edit_groups_permission_form(message('select'), permission, @project.id, "select-#{permission}-edit-groups") %>)<br/> - </td> - <% end %> - </tr> - </tbody> - </table> -</div> diff --git a/server/sonar-web/test/medium/global-permissions.spec.js b/server/sonar-web/test/medium/global-permissions.spec.js index dbc525846d6..9209f73907a 100644 --- a/server/sonar-web/test/medium/global-permissions.spec.js +++ b/server/sonar-web/test/medium/global-permissions.spec.js @@ -16,7 +16,7 @@ define(function (require) { .checkElementInclude('#global-permissions-list > li h3', 'Administer System') .checkElementInclude('#global-permissions-list > li p', 'Ability to perform all administration') .checkElementInclude('#global-permissions-list > li ul > li:first-child', 'Administrator') - .checkElementInclude('#global-permissions-list > li ul > li:last-child', '1') + .checkElementInclude('#global-permissions-list > li ul > li:last-child', '1'); }); }); }); diff --git a/server/sonar-web/test/medium/project-permissions.spec.js b/server/sonar-web/test/medium/project-permissions.spec.js index 4eaf5a7db96..28edb1099f9 100644 --- a/server/sonar-web/test/medium/project-permissions.spec.js +++ b/server/sonar-web/test/medium/project-permissions.spec.js @@ -7,7 +7,7 @@ define(function (require) { return this.remote .open() .mockFromFile('/api/permissions/search_project_permissions', 'permissions/project-permissions.json') - .startApp('project-permissions/app') + .startApp('project-permissions/app', { component: null }) .checkElementExist('#project-permissions-header') .checkElementExist('#projects') .checkElementCount('#projects > thead > tr > th', 3) @@ -18,5 +18,21 @@ define(function (require) { .checkElementInclude('#projects > tbody > tr:first-child td:nth-child(3)', '1') .checkElementInclude('#projects > tbody > tr:first-child td:nth-child(3)', '2'); }); + + bdd.it('should show permissions on the project page', function () { + return this.remote + .open() + .mockFromFile('/api/permissions/search_project_permissions', 'permissions/project-permissions.json') + .mockFromFile('/api/permissions/users', 'permissions/users.json') + .mockFromFile('/api/permissions/groups', 'permissions/groups.json') + .startApp('project-permissions/app') + .checkElementExist('#project-permissions-header') + .checkElementExist('#global-permissions-list') + .checkElementCount('#global-permissions-list > li', 2) + .checkElementInclude('#global-permissions-list > li h3', 'See Source Code') + .checkElementInclude('#global-permissions-list > li p', 'Ability to view the project\'s source code.') + .checkElementInclude('#global-permissions-list > li ul > li:first-child', 'Administrator') + .checkElementInclude('#global-permissions-list > li ul > li:last-child', '1'); + }); }); }); |