OSDN Git Service

Added ability to edit issues from different project through contextual menu (#5332)
authorJean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
Fri, 8 Oct 2010 03:09:51 +0000 (03:09 +0000)
committerJean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
Fri, 8 Oct 2010 03:09:51 +0000 (03:09 +0000)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4242 e93f8b46-1217-0410-a6f0-8f06a7374b81

app/controllers/context_menus_controller.rb
app/controllers/issues_controller.rb
app/views/context_menus/issues.html.erb
app/views/issues/bulk_edit.rhtml
test/functional/context_menus_controller_test.rb
test/functional/issues_controller_test.rb

index ae85172..3e14383 100644 (file)
@@ -16,9 +16,9 @@ class ContextMenusController < ApplicationController
     @projects = @issues.collect(&:project).compact.uniq
     @project = @projects.first if @projects.size == 1
 
-    @can = {:edit => (@project && User.current.allowed_to?(:edit_issues, @project)),
+    @can = {:edit => User.current.allowed_to?(:edit_issues, @projects),
             :log_time => (@project && User.current.allowed_to?(:log_time, @project)),
-            :update => (@project && (User.current.allowed_to?(:edit_issues, @project) || (User.current.allowed_to?(:change_status, @project) && @allowed_statuses && !@allowed_statuses.empty?))),
+            :update => (User.current.allowed_to?(:edit_issues, @projects) || (User.current.allowed_to?(:change_status, @projects) && !@allowed_statuses.blank?)),
             :move => (@project && User.current.allowed_to?(:move_issues, @project)),
             :copy => (@issue && @project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)),
             :delete => User.current.allowed_to?(:delete_issues, @projects)
@@ -27,6 +27,10 @@ class ContextMenusController < ApplicationController
       @assignables = @project.assignable_users
       @assignables << @issue.assigned_to if @issue && @issue.assigned_to && !@assignables.include?(@issue.assigned_to)
       @trackers = @project.trackers
+    else
+      #when multiple projects, we only keep the intersection of each set
+      @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a}
+      @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t}
     end
     
     @priorities = IssuePriority.all.reverse
index 2221db8..67488b7 100644 (file)
@@ -21,7 +21,7 @@ class IssuesController < ApplicationController
   
   before_filter :find_issue, :only => [:show, :edit, :update]
   before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :move, :perform_move, :destroy]
-  before_filter :check_project_uniqueness, :only => [:bulk_edit, :bulk_update, :move, :perform_move]
+  before_filter :check_project_uniqueness, :only => [:move, :perform_move]
   before_filter :find_project, :only => [:new, :create]
   before_filter :authorize, :except => [:index]
   before_filter :find_optional_project, :only => [:index]
@@ -194,8 +194,10 @@ class IssuesController < ApplicationController
   # Bulk edit a set of issues
   def bulk_edit
     @issues.sort!
-    @available_statuses = Workflow.available_statuses(@project)
-    @custom_fields = @project.all_issue_custom_fields
+    @available_statuses = @projects.map{|p|Workflow.available_statuses(p)}.inject{|memo,w|memo & w}
+    @custom_fields = @projects.map{|p|p.all_issue_custom_fields}.inject{|memo,c|memo & c}
+    @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a}
+    @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t}
   end
 
   def bulk_update
index 3f45f4e..3109ac4 100644 (file)
@@ -33,7 +33,6 @@
        </li>
        <% end %>
 
-  <% if @projects.size == 1 %>
        <li class="folder">                     
                <a href="#" class="submenu"><%= l(:field_priority) %></a>
                <ul>
@@ -43,8 +42,8 @@
                <% end -%>
                </ul>
        </li>
-  <% end %>
 
+  <% #TODO: allow editing versions when multiple projects %>
        <% unless @project.nil? || @project.shared_versions.open.empty? -%>
        <li class="folder">                     
                <a href="#" class="submenu"><%= l(:field_fixed_version) %></a>
@@ -85,7 +84,7 @@
        </li>
        <% end -%>
 
-  <% if Issue.use_field_for_done_ratio? && @projects.size == 1 %>
+  <% if Issue.use_field_for_done_ratio? %>
        <li class="folder">
                <a href="#" class="submenu"><%= l(:field_done_ratio) %></a>
                <ul>
index 5fdfd58..7091e35 100644 (file)
@@ -11,7 +11,7 @@
 <div class="splitcontentleft">
 <p>
        <label><%= l(:field_tracker) %></label>
-       <%= select_tag('issue[tracker_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@project.trackers, :id, :name)) %>
+       <%= select_tag('issue[tracker_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, :id, :name)) %>
 </p>
 <% if @available_statuses.any? %>
 <p>
        <label><%= l(:field_assigned_to) %></label> 
        <%= select_tag('issue[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') +
                                  content_tag('option', l(:label_nobody), :value => 'none') +
-                                 options_from_collection_for_select(@project.assignable_users, :id, :name)) %>
+                                 options_from_collection_for_select(@assignables, :id, :name)) %>
 </p>
+<% if @project %>
 <p>
        <label><%= l(:field_category) %></label> 
        <%= select_tag('issue[category_id]', content_tag('option', l(:label_no_change_option), :value => '') +
                                 content_tag('option', l(:label_none), :value => 'none') +
                                 options_from_collection_for_select(@project.issue_categories, :id, :name)) %>
 </p>
+<% end %>
+<% #TODO: allow editing versions when multiple projects %>
+<% if @project %>
 <p>
        <label><%= l(:field_fixed_version) %></label> 
        <%= select_tag('issue[fixed_version_id]', content_tag('option', l(:label_no_change_option), :value => '') +
                                    content_tag('option', l(:label_none), :value => 'none') +
                                    version_options_for_select(@project.shared_versions.open)) %>
 </p>
+<% end %>
 
 <% @custom_fields.each do |custom_field| %>
        <p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('issue', custom_field) %></p>
index 0202cf2..6d2b45b 100644 (file)
@@ -85,6 +85,18 @@ class ContextMenusControllerTest < ActionController::TestCase
     assert_response :success
     assert_template 'context_menu'
     ids = "ids%5B%5D=1&amp;ids%5B%5D=2&amp;ids%5B%5D=6"
+    assert_tag :tag => 'a', :content => 'Edit',
+                            :attributes => { :href => "/issues/bulk_edit?#{ids}",
+                                             :class => 'icon-edit' }
+    assert_tag :tag => 'a', :content => 'Closed',
+                            :attributes => { :href => "/issues/bulk_edit?#{ids}&amp;issue%5Bstatus_id%5D=5",
+                                             :class => '' }
+    assert_tag :tag => 'a', :content => 'Immediate',
+                            :attributes => { :href => "/issues/bulk_edit?#{ids}&amp;issue%5Bpriority_id%5D=8",
+                                             :class => '' }
+    assert_tag :tag => 'a', :content => 'John Smith',
+                            :attributes => { :href => "/issues/bulk_edit?#{ids}&amp;issue%5Bassigned_to_id%5D=2",
+                                             :class => '' }
     assert_tag :tag => 'a', :content => 'Delete',
                             :attributes => { :href => "/issues/destroy?#{ids}",
                                              :class => 'icon-del' }
index 4db2dae..59b16c3 100644 (file)
@@ -911,6 +911,19 @@ class IssuesControllerTest < ActionController::TestCase
     assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
   end
 
+  def test_get_bulk_edit_on_different_projects
+    @request.session[:user_id] = 2
+    get :bulk_edit, :ids => [1, 2, 6]
+    assert_response :success
+    assert_template 'bulk_edit'
+    
+    # Project specific custom field, date type
+    field = CustomField.find(9)
+    assert !field.is_for_all?
+    assert !field.project_ids.include?(Issue.find(6).project_id)
+    assert_no_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
+  end
+
   def test_bulk_update
     @request.session[:user_id] = 2
     # update issues priority
@@ -930,6 +943,39 @@ class IssuesControllerTest < ActionController::TestCase
     assert_equal 1, journal.details.size
   end
 
+  def test_bulk_update_on_different_projects
+    @request.session[:user_id] = 2
+    # update issues priority
+    post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
+                                     :issue => {:priority_id => 7,
+                                                :assigned_to_id => '',
+                                                :custom_field_values => {'2' => ''}}
+    
+    assert_response 302
+    # check that the issues were updated
+    assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
+    
+    issue = Issue.find(1)
+    journal = issue.journals.find(:first, :order => 'created_on DESC')
+    assert_equal '125', issue.custom_value_for(2).value
+    assert_equal 'Bulk editing', journal.notes
+    assert_equal 1, journal.details.size
+  end
+
+  def test_bulk_update_on_different_projects_without_rights
+    @request.session[:user_id] = 3
+    user = User.find(3)
+    action = { :controller => "issues", :action => "bulk_update" }
+    assert user.allowed_to?(action, Issue.find(1).project)
+    assert ! user.allowed_to?(action, Issue.find(6).project)
+    post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
+                                     :issue => {:priority_id => 7,
+                                                :assigned_to_id => '',
+                                                :custom_field_values => {'2' => ''}}
+    assert_response 403
+    assert_not_equal "Bulk should fail", Journal.last.notes
+  end
+    
   def test_bullk_update_should_send_a_notification
     @request.session[:user_id] = 2
     ActionMailer::Base.deliveries.clear