diff options
15 files changed, 110 insertions, 59 deletions
diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties index fc6c3b895ad..377c43aba48 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -332,7 +332,7 @@ sidebar.tools=Tools #------------------------------------------------------------------------------ action_plans.page=Action Plans -administrators.page=Administrators +global_permissions.page=Global Permissions backup.page=Backup clouds.page=Clouds components.page=Components @@ -2186,10 +2186,12 @@ metric.confirmed_issues.description=Confirmed issues global_role.role=Role global_role.users=Users global_role.groups=Groups -global_role.admin=System Administrators +global_role.admin=System Administration global_role.admin.desc=Ability to perform all administration functions for the instance: global configuration and personalization of default dashboards. -global_role.profileadmin=Quality Profile Administrators +global_role.profileadmin=Quality Profile Administration global_role.profileadmin.desc=Ability to perform any action on the quality profiles. +global_role.sharedashboard=Dashboard Sharing +global_role.sharedashboard.desc=Ability to share eligible dashboards. #------------------------------------------------------------------------------ diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java index 85fb8a3f1ad..edcbbc9969c 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java @@ -32,7 +32,7 @@ import java.util.List; */ public class DatabaseVersion implements BatchComponent, ServerComponent { - public static final int LAST_VERSION = 412; + public static final int LAST_VERSION = 413; public static enum Status { UP_TO_DATE, REQUIRES_UPGRADE, REQUIRES_DOWNGRADE, FRESH_INSTALL diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql index 1d75faef1a7..4e43875c862 100644 --- a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql +++ b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql @@ -6,7 +6,8 @@ ALTER TABLE GROUPS ALTER COLUMN ID RESTART WITH 3; INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (1, 1, null, 'admin'); INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (2, 1, null, 'profileadmin'); -ALTER TABLE GROUP_ROLES ALTER COLUMN ID RESTART WITH 3; +INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (3, 1, null, 'sharedashboard'); +ALTER TABLE GROUP_ROLES ALTER COLUMN ID RESTART WITH 4; INSERT INTO GROUPS_USERS(USER_ID, GROUP_ID) VALUES (1, 1); INSERT INTO GROUPS_USERS(USER_ID, GROUP_ID) VALUES (1, 2); @@ -172,6 +173,7 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('405'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('410'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('411'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('412'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('413'); INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '2011-09-26 22:27:48.0', '2011-09-26 22:27:48.0', null, null); ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2; diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/dashboards_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/dashboards_controller.rb index ca949ed9e89..01fbc469a69 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/dashboards_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/dashboards_controller.rb @@ -59,19 +59,15 @@ class DashboardsController < ApplicationController active_dashboard = current_user.active_dashboards.to_a.find { |ad| ad.name==@dashboard.name } if active_dashboard - flash[:error]=Api::Utils.message('dashboard.error_create_existing_name') - - redirect_to :action => 'index', :resource => params[:resource] + @dashboard.errors.add(Api::Utils.message('dashboard.error_create_existing_name')) + render :partial => 'dashboards/create_form', :status => 400, :resource => params[:resource] elsif @dashboard.save add_default_dashboards_if_first_user_dashboard(@dashboard.global?) last_index=current_user.active_dashboards.max_by(&:order_index).order_index current_user.active_dashboards.create(:dashboard => @dashboard, :user => current_user, :order_index => (last_index+1)) - - redirect_to :action => 'index', :resource => params[:resource], :highlight => @dashboard.id + render :text => @dashboard.id.to_s, :resource => params[:resource], :highlight => @dashboard.id, :status => 200 else - flash[:error]=@dashboard.errors.full_messages.join('<br/>') - - redirect_to :action => 'index', :resource => params[:resource] + render :partial => 'dashboards/create_form', :status => 400, :resource => params[:resource] end end @@ -86,16 +82,18 @@ class DashboardsController < ApplicationController def update verify_post_request - dashboard=Dashboard.find(params[:id]) - if dashboard.editable_by?(current_user) - load_dashboard_from_params(dashboard) - - unless dashboard.save - flash[:error]=dashboard.errors.full_messages.join('<br/>') + @dashboard = Dashboard.find(params[:id]) + if @dashboard.editable_by?(current_user) + load_dashboard_from_params(@dashboard) + if @dashboard.save + render :text => @dashboard.id.to_s, :resource => params[:resource], :status => 200 + else + render :partial => 'dashboards/edit_form', :status => 400, :resource => params[:resource] end + else + # TODO - notify error ? + render :text => @dashboard.id.to_s, :resource => params[:resource], :status => 200 end - - redirect_to :action => 'index', :resource => params[:resource] end def delete_form @@ -184,11 +182,11 @@ class DashboardsController < ApplicationController end def load_dashboard_from_params(dashboard) - dashboard.name=params[:name] - dashboard.description=params[:description] - dashboard.is_global=(params[:global].present?) - dashboard.shared=(params[:shared].present? && is_admin?) - dashboard.column_layout=Dashboard::DEFAULT_LAYOUT if !dashboard.column_layout + dashboard.name = params[:name] + dashboard.description = params[:description] + dashboard.is_global = params[:global].present? + dashboard.shared = params[:shared].present? && has_role?(:sharedashboard) + dashboard.column_layout = Dashboard::DEFAULT_LAYOUT if !dashboard.column_layout dashboard.user = User.find_active_by_login(params[:owner]) unless params[:owner].nil? end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/measures_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/measures_controller.rb index 2aea260bac5..9f93c3e3b5f 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/measures_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/measures_controller.rb @@ -141,7 +141,7 @@ class MeasuresController < ApplicationController @filter.description=params[:description] @filter.shared=(params[:shared]=='true') - if has_role?(:admin) + if has_role?(:admin) && params[:owner] @filter.user = User.find_by_login(params[:owner]) end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/dashboard.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/dashboard.rb index f4337a54e6d..1ee10af6bf7 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/dashboard.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/dashboard.rb @@ -32,6 +32,8 @@ class Dashboard < ActiveRecord::Base validates_uniqueness_of :name, :scope => :user_id validates_inclusion_of :is_global, :in => [true, false] + validate :user_rights_consistency + before_destroy :check_not_default_before_destroy def name(l10n=false) @@ -43,6 +45,12 @@ class Dashboard < ActiveRecord::Base end end + def user_rights_consistency + if shared? && !user.has_role?(:sharedashboard) + errors.add(:user, "cannot own this dashboard because it has insufficient rights") + end + end + def shared? read_attribute(:shared) || false end @@ -75,6 +83,14 @@ class Dashboard < ActiveRecord::Base self.user_id==user.id end + def can_be_shared_by(user) + owner?(user) && user.has_role?(:sharedashboard) + end + + def can_be_reassigned_by(user) + shared? && user.has_role?(:admin) + end + def number_of_columns column_layout.split('-').size end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter.rb index 2eeb1828ba1..1f4bb44e29e 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter.rb @@ -98,6 +98,10 @@ class MeasureFilter < ActiveRecord::Base criteria[:onFavourites]=='true' end + def can_be_reassigned_by(user) + user.has_role?(:admin) && shared + end + def criteria(key=nil) @criteria ||= HashWithIndifferentAccess.new if key diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/role.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/role.rb deleted file mode 100644 index 7778badb856..00000000000 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/role.rb +++ /dev/null @@ -1,22 +0,0 @@ - # - # Sonar, entreprise quality control tool. - # Copyright (C) 2008-2013 SonarSource - # mailto:contact AT sonarsource DOT com - # - # SonarQube 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. - # - # SonarQube 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. - # -class Role < ActiveRecord::Base - ADMIN = 'sonar_admin' -end
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/dashboards/_create_form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/dashboards/_create_form.html.erb index a570962e753..13606eac007 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/dashboards/_create_form.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/dashboards/_create_form.html.erb @@ -11,7 +11,7 @@ <div class="modal-body"> <% if @dashboard %> <% @dashboard.errors.each do |attr, msg| %> - <p class="error"><%= h msg -%></p> + <p class="error"><%= h "#{attr} #{msg}" -%></p> <% end %> <% end %> <div class="modal-field"> @@ -22,7 +22,7 @@ <label for="description"><%= h message('description') -%></label> <input id="description" name="description" type="text" size="50" maxlength="4000" value="<%= h @dashboard.description -%>"/> </div> - <% if is_admin? %> + <% if has_role?(:sharedashboard) %> <div class="modal-field"> <label for="shared"><%= h message('shared') -%></label> <input id="shared" name="shared" type="checkbox" value="true" <%= 'checked' if @dashboard.shared -%>/> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/dashboards/_edit_form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/dashboards/_edit_form.html.erb index faa26a54363..ee8aab60363 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/dashboards/_edit_form.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/dashboards/_edit_form.html.erb @@ -11,7 +11,7 @@ </div> <div class="modal-body"> <% @dashboard.errors.each do |attr, msg| %> - <p class="error"><%= h msg -%></p> + <p class="error"><%= h "#{attr} #{msg}" -%></p> <% end %> <div class="modal-field"> <label for="name"><%= h message('name') -%> <em class="mandatory">*</em></label> @@ -21,15 +21,19 @@ <label for="description"><%= h message('description') -%></label> <input id="description" name="description" type="text" size="50" maxlength="4000" value="<%= h @dashboard.description -%>"/> </div> - <% if is_admin? %> + <% if @dashboard.can_be_reassigned_by(current_user) %> <div class="modal-field"> <label for="owner"><%= h message('owner') -%></label> <%= user_select_tag('owner', :html_id => 'select-dashboard-owner', :selected_user => @dashboard.user) -%> </div> + <% end %> + <% if @dashboard.can_be_shared_by(current_user) %> <div class="modal-field"> <label for="shared"><%= h message('shared') -%></label> <input id="shared" name="shared" type="checkbox" value="true" <%= 'checked' if @dashboard.shared -%>/> </div> + <% else %> + <input id="shared" name="shared" type="hidden" value="<%= @dashboard.shared %>"/> <% end %> </div> <div class="modal-foot"> @@ -38,3 +42,9 @@ </div> </fieldset> </form> + +<script> + $j("#edit-dashboard-form").modalForm({success: function (data) { + window.location = baseUrl + '/dashboards'; + }}); +</script>
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb index b5eb71a2b68..43aff0bae81 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb @@ -130,7 +130,7 @@ <li class="<%= 'active' if request.request_uri.include?('/groups') -%>"> <a href="<%= ApplicationController.root_context -%>/groups/index"><%= message('user_groups.page') -%></a></li> <li class="<%= 'active' if request.request_uri.include?('/roles/global') -%>"> - <a href="<%= ApplicationController.root_context -%>/roles/global"><%= message('administrators.page') -%></a></li> + <a href="<%= ApplicationController.root_context -%>/roles/global"><%= message('global_permissions.page') -%></a></li> <li class="<%= 'active' if request.request_uri.include?('/roles/projects') -%>"> <a href="<%= ApplicationController.root_context -%>/roles/projects"><%= message('roles.page') -%></a></li> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_edit_form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_edit_form.html.erb index 7465c6f8ec0..5b9f6b43984 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_edit_form.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_edit_form.html.erb @@ -6,7 +6,7 @@ </div> <div class="modal-body"> <% @filter.errors.each do |attr, msg| %> - <p class="error"><%= h msg -%></p> + <p class="error"><%= h "#{attr} #{msg}" -%></p> <% end %> <div class="modal-field"> <label for="name"><%= h message('name') -%> <em class="mandatory">*</em></label> @@ -16,7 +16,7 @@ <label for="description"><%= h message('description') -%></label> <input id="description" name="description" type="text" size="50" maxlength="4000" value="<%= h @filter.description -%>"/> </div> - <% if is_admin? %> + <% if @filter.can_be_reassigned_by(current_user) %> <div class="modal-field"> <label for="owner"><%= h message('owner') -%></label> <%= user_select_tag('owner', :html_id => 'select-filter-owner', :selected_user => @filter.user) -%> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/roles/global.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/roles/global.html.erb index ad41fea07da..912ea799922 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/roles/global.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/roles/global.html.erb @@ -1,4 +1,4 @@ -<h1 class="marginbottom10"><%= message 'administrators.page' -%></h1> +<h1 class="marginbottom10"><%= message 'global_permissions.page' -%></h1> <table class="data width100" id="global-roles"> <thead> @@ -9,7 +9,7 @@ </tr> </thead> <tbody> - <% ['admin', 'profileadmin'].each do |globalRole| %> + <% ['admin', 'profileadmin', 'sharedashboard'].each do |globalRole| %> <tr class="<%= cycle('even', 'odd', :name => 'globalRole') -%>" > <td valign="top"> <b><%= message('global_role.' + globalRole) -%></b><br/> diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/413_add_dashboard_sharing_permission.rb b/sonar-server/src/main/webapp/WEB-INF/db/migrate/413_add_dashboard_sharing_permission.rb new file mode 100644 index 00000000000..978f598220d --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/db/migrate/413_add_dashboard_sharing_permission.rb @@ -0,0 +1,41 @@ +# +# Sonar, entreprise quality control tool. +# Copyright (C) 2008-2013 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube 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. +# +# SonarQube 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. +# + +# +# Sonar 3.7 +# + +class AddDashboardSharingPermission < ActiveRecord::Migration + + def self.up + group_roles=GroupRole.find(:all, :conditions => {:role => 'admin', :resource_id => nil}) + groups = group_roles.map { |ur| ur.group_id } + groups.each do |group_id| + GroupRole.create(:group_id => group_id, :role => 'sharedashboard', :resource_id => nil) + end + + user_roles=UserRole.find(:all, :conditions => {:role => 'admin', :resource_id => nil}) + users = user_roles.map { |ur| ur.user_id } + users.each do |user_id| + UserRole.create(:user_id => user_id, :role=> 'sharedashboard', :resource_id => nil) + end + end + +end diff --git a/sonar-server/src/main/webapp/WEB-INF/lib/need_authorization.rb b/sonar-server/src/main/webapp/WEB-INF/lib/need_authorization.rb index 9d3dd68193a..1deab73eb62 100644 --- a/sonar-server/src/main/webapp/WEB-INF/lib/need_authorization.rb +++ b/sonar-server/src/main/webapp/WEB-INF/lib/need_authorization.rb @@ -59,7 +59,7 @@ module NeedAuthorization def has_role?(role, objects=nil) if objects.nil? role_symbol=role.to_sym - if role_symbol==:admin || role_symbol==:profileadmin + if role_symbol==:admin || role_symbol==:profileadmin || role_symbol==:sharedashboard AuthorizerFactory.authorizer.has_role?(self, role_symbol) else # There's no concept of global users or global codeviewers. |