]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4099 Added new global permission to enable dashboard sharing for non-admin...
authorJean-Baptiste Vilain <jean-baptiste.vilain@sonarsource.com>
Wed, 19 Jun 2013 17:08:13 +0000 (19:08 +0200)
committerJean-Baptiste Vilain <jean-baptiste.vilain@sonarsource.com>
Wed, 19 Jun 2013 17:08:13 +0000 (19:08 +0200)
15 files changed:
plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties
sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
sonar-server/src/main/webapp/WEB-INF/app/controllers/dashboards_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/controllers/measures_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/models/dashboard.rb
sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter.rb
sonar-server/src/main/webapp/WEB-INF/app/models/role.rb [deleted file]
sonar-server/src/main/webapp/WEB-INF/app/views/dashboards/_create_form.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/dashboards/_edit_form.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/measures/_edit_form.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/roles/global.html.erb
sonar-server/src/main/webapp/WEB-INF/db/migrate/413_add_dashboard_sharing_permission.rb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/lib/need_authorization.rb

index fc6c3b895adcc0d5be1a61550eeed59b1a56509d..377c43aba48e7cf4be38fbef61bfe1c42d5b9300 100644 (file)
@@ -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.
 
 
 #------------------------------------------------------------------------------
index 85fb8a3f1ad77dc9b64ab1f147fb142c08f04584..edcbbc9969c514eb1a54f675b8fa2185d92265a4 100644 (file)
@@ -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
index 1d75faef1a79d2bfeece4e26bfe6f47bf4c602fb..4e43875c862ed7cd45557fda100d37a8812f7cee 100644 (file)
@@ -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;
index ca949ed9e893725b182e358dc697420d08dfefaa..01fbc469a6976cdddf30fce4928025fffac98031 100644 (file)
@@ -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
 
index 2aea260bac5fe6199ab1fc68ffe0532cf9cb9ed7..9f93c3e3b5fe3706a1a4e4ac51997917c7b5a854 100644 (file)
@@ -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
 
index f4337a54e6d75186d18cec714bb00c689dace004..1ee10af6bf75e28634b4ce8c9df377333656cd20 100644 (file)
@@ -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
index 2eeb1828ba12449b18890dc904fb03d5746409b3..1f4bb44e29e8b834ae03ea55523281d360ea2861 100644 (file)
@@ -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 (file)
index 7778bad..0000000
+++ /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
index a570962e7533d47f219ae1e1b12f1c2a50559de1..13606eac007ee24ef1cdc098b5ad97048b1c784e 100644 (file)
@@ -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 -%>/>
index faa26a5436393674ef3c82f3569fcdd8b4c607c5..ee8aab6036346c62e7fe441ed091df1b82edf63b 100644 (file)
@@ -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>
         <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
index b5eb71a2b6882abe49614d4e38eac33f6566cee9..43aff0bae8109e283b4fc783fdabb750e955278c 100644 (file)
             <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>
 
index 7465c6f8ec001260a83fbf2a6140266181e1c590..5b9f6b439844f2be0db78f98966eb0b2137b3622 100644 (file)
@@ -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) -%>
index ad41fea07dacf23a89eb926716bc6b896913ccfa..912ea799922bbe9a056f17dc66944554ff3c1de2 100644 (file)
@@ -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 (file)
index 0000000..978f598
--- /dev/null
@@ -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
index 9d3dd68193a07bb743e3e903cfffdcc1d03502e2..1deab73eb622b735c54c011ac6f7de571a44684e 100644 (file)
@@ -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.