git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@8538 e93f8b46-1217-0410-a6f0-8f06a7374b81tags/1.4.0
@@ -1,85 +0,0 @@ | |||
# Redmine - project management software | |||
# Copyright (C) 2006-2011 Jean-Philippe Lang | |||
# | |||
# This program is free software; you can redistribute it and/or | |||
# modify it under the terms of the GNU General Public License | |||
# as published by the Free Software Foundation; either version 2 | |||
# 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 General Public License for more details. | |||
# | |||
# You should have received a copy of the GNU 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 IssueMovesController < ApplicationController | |||
menu_item :issues | |||
default_search_scope :issues | |||
before_filter :find_issues, :check_project_uniqueness | |||
before_filter :authorize | |||
def new | |||
prepare_for_issue_move | |||
render :layout => false if request.xhr? | |||
end | |||
def create | |||
prepare_for_issue_move | |||
if request.post? | |||
new_tracker = params[:new_tracker_id].blank? ? nil : @target_project.trackers.find_by_id(params[:new_tracker_id]) | |||
unsaved_issue_ids = [] | |||
moved_issues = [] | |||
@issues.each do |issue| | |||
issue.reload | |||
call_hook(:controller_issues_move_before_save, { :params => params, :issue => issue, :target_project => @target_project, :copy => !!@copy }) | |||
if r = issue.move_to_project(@target_project, new_tracker, {:copy => @copy, :attributes => extract_changed_attributes_for_move(params), :notes => @notes}) | |||
moved_issues << r | |||
else | |||
unsaved_issue_ids << issue.id | |||
end | |||
end | |||
set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids) | |||
if params[:follow] | |||
if @issues.size == 1 && moved_issues.size == 1 | |||
redirect_to :controller => 'issues', :action => 'show', :id => moved_issues.first | |||
else | |||
redirect_to :controller => 'issues', :action => 'index', :project_id => (@target_project || @project) | |||
end | |||
else | |||
redirect_to :controller => 'issues', :action => 'index', :project_id => @project | |||
end | |||
return | |||
end | |||
end | |||
private | |||
def prepare_for_issue_move | |||
@issues.sort! | |||
@copy = params[:copy_options] && params[:copy_options][:copy] | |||
@allowed_projects = Issue.allowed_target_projects_on_move | |||
@target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id] | |||
@target_project ||= @project | |||
@trackers = @target_project.trackers | |||
@available_statuses = Workflow.available_statuses(@project) | |||
@notes = params[:notes] | |||
@notes ||= '' | |||
end | |||
def extract_changed_attributes_for_move(params) | |||
changed_attributes = {} | |||
[:assigned_to_id, :status_id, :start_date, :due_date, :priority_id].each do |valid_attribute| | |||
unless params[valid_attribute].blank? | |||
changed_attributes[valid_attribute] = (params[valid_attribute] == 'none' ? nil : params[valid_attribute]) | |||
end | |||
end | |||
changed_attributes | |||
end | |||
end |
@@ -206,9 +206,11 @@ class IssuesController < ApplicationController | |||
end | |||
end | |||
# Bulk edit a set of issues | |||
# Bulk edit/copy a set of issues | |||
def bulk_edit | |||
@issues.sort! | |||
@copy = params[:copy].present? | |||
@notes = params[:notes] | |||
if User.current.allowed_to?(:move_issues, @projects) | |||
@allowed_projects = Issue.allowed_target_projects_on_move | |||
@@ -226,18 +228,21 @@ class IssuesController < ApplicationController | |||
@assignables = target_projects.map(&:assignable_users).inject{|memo,a| memo & a} | |||
@trackers = target_projects.map(&:trackers).inject{|memo,t| memo & t} | |||
@notes = params[:notes] | |||
render :layout => false if request.xhr? | |||
end | |||
def bulk_update | |||
@issues.sort! | |||
@copy = params[:copy].present? | |||
attributes = parse_params_for_bulk_issue_attributes(params) | |||
unsaved_issue_ids = [] | |||
moved_issues = [] | |||
@issues.each do |issue| | |||
issue.reload | |||
if @copy | |||
issue = Issue.new.copy_from(issue) | |||
end | |||
journal = issue.init_journal(User.current, params[:notes]) | |||
issue.safe_attributes = attributes | |||
call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue }) |
@@ -1,4 +0,0 @@ | |||
# encoding: utf-8 | |||
# | |||
module IssueMovesHelper | |||
end |
@@ -110,7 +110,7 @@ | |||
<li><%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue}, | |||
:class => 'icon-duplicate', :disabled => !@can[:copy] %></li> | |||
<% end %> | |||
<li><%= context_menu_link l(:button_copy), new_issue_move_path(:ids => @issues.collect(&:id), :copy_options => {:copy => 't'}), | |||
<li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :copy => '1'}, | |||
:class => 'icon-copy', :disabled => !@can[:move] %></li> | |||
<li><%= context_menu_link l(:button_delete), issues_path(:ids => @issues.collect(&:id), :back_url => @back), | |||
:method => :delete, :confirm => issues_destroy_confirmation_message(@issues), :class => 'icon-del', :disabled => !@can[:delete] %></li> |
@@ -1,79 +0,0 @@ | |||
<h2><%= @copy ? l(:button_copy) : l(:button_move) %></h2> | |||
<ul> | |||
<% @issues.each do |issue| -%> | |||
<li><%= link_to_issue issue %></li> | |||
<% end -%> | |||
</ul> | |||
<% form_tag({:action => 'create'}, :id => 'move_form') do %> | |||
<%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join("\n").html_safe %> | |||
<div class="box tabular"> | |||
<fieldset class="attributes"> | |||
<legend><%= l(:label_change_properties) %></legend> | |||
<div class="splitcontentleft"> | |||
<p><label for="new_project_id"><%=l(:field_project)%>:</label> | |||
<%= select_tag "new_project_id", | |||
project_tree_options_for_select(@allowed_projects, :selected => @target_project), | |||
:onchange => remote_function(:url => { :action => 'new' }, | |||
:method => :get, | |||
:update => 'content', | |||
:with => "Form.serialize('move_form')") %></p> | |||
<p><label for="new_tracker_id"><%=l(:field_tracker)%>:</label> | |||
<%= select_tag "new_tracker_id", "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, "id", "name") %></p> | |||
<p> | |||
<label for='status_id'><%= l(:field_status) %></label> | |||
<%= select_tag('status_id', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@available_statuses, :id, :name)) %> | |||
</p> | |||
<p> | |||
<label for='priority_id'><%= l(:field_priority) %></label> | |||
<%= select_tag('priority_id', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(IssuePriority.active, :id, :name)) %> | |||
</p> | |||
<p> | |||
<label for='assigned_to_id'><%= l(:field_assigned_to) %></label> | |||
<%= select_tag('assigned_to_id', content_tag('option', l(:label_no_change_option), :value => '') + | |||
content_tag('option', l(:label_nobody), :value => 'none') + | |||
principals_options_for_select(@target_project.assignable_users)) %> | |||
</p> | |||
</div> | |||
<div class="splitcontentright"> | |||
<p> | |||
<label for='start_date'><%= l(:field_start_date) %></label> | |||
<%= text_field_tag 'start_date', '', :size => 10 %><%= calendar_for('start_date') %> | |||
</p> | |||
<p> | |||
<label for='due_date'><%= l(:field_due_date) %></label> | |||
<%= text_field_tag 'due_date', '', :size => 10 %><%= calendar_for('due_date') %> | |||
</p> | |||
</div> | |||
</fieldset> | |||
<fieldset><legend><%= l(:field_notes) %></legend> | |||
<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> | |||
<%= wikitoolbar_for 'notes' %> | |||
</fieldset> | |||
<%= call_hook(:view_issues_move_bottom, :issues => @issues, :target_project => @target_project, :copy => !!@copy) %> | |||
</div> | |||
<% if @copy %> | |||
<%= hidden_field_tag("copy_options[copy]", "1") %> | |||
<%= submit_tag l(:button_copy) %> | |||
<%= submit_tag l(:button_copy_and_follow), :name => 'follow' %> | |||
<% else %> | |||
<%= submit_tag l(:button_move) %> | |||
<%= submit_tag l(:button_move_and_follow), :name => 'follow' %> | |||
<% end %> | |||
<% end %> | |||
<% content_for :header_tags do %> | |||
<%= robot_exclusion_tag %> | |||
<% end %> |
@@ -3,6 +3,6 @@ | |||
<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %> | |||
<%= watcher_tag(@issue, User.current) %> | |||
<%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %> | |||
<%= link_to_if_authorized l(:button_copy), {:controller => 'issue_moves', :action => 'new', :id => @issue, :copy_options => {:copy => 't'}}, :class => 'icon icon-copy' %> | |||
<%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'bulk_edit', :id => @issue, :copy => '1'}, :class => 'icon icon-copy' %> | |||
<%= link_to l(:button_delete), issue_path(@issue), :confirm => issues_destroy_confirmation_message(@issue), :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %> | |||
</div> |
@@ -1,4 +1,4 @@ | |||
<h2><%= l(:label_bulk_edit_selected_issues) %></h2> | |||
<h2><%= @copy ? l(:button_copy) : l(:label_bulk_edit_selected_issues) %></h2> | |||
<ul><%= @issues.collect {|i| | |||
content_tag('li', | |||
@@ -102,7 +102,11 @@ | |||
</div> | |||
<p> | |||
<% if @target_project %> | |||
<% if @copy %> | |||
<%= hidden_field_tag 'copy', '1' %> | |||
<%= submit_tag l(:button_copy) %> | |||
<%= submit_tag l(:button_copy_and_follow), :name => 'follow' %> | |||
<% elsif @target_project %> | |||
<%= submit_tag l(:button_move) %> | |||
<%= submit_tag l(:button_move_and_follow), :name => 'follow' %> | |||
<% else %> |
@@ -40,9 +40,6 @@ ActionController::Routing::Routes.draw do |map| | |||
end | |||
end | |||
map.resources :issue_moves, :only => [:new, :create], | |||
:path_prefix => '/issues', :as => 'move' | |||
# Misc issue routes. TODO: move into resources | |||
map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', | |||
:action => 'issues', :conditions => { :method => :get } |
@@ -76,7 +76,7 @@ Redmine::AccessControl.map do |map| | |||
map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]} | |||
map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin | |||
map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin | |||
map.permission :move_issues, {:issue_moves => [:new, :create]}, :require => :loggedin | |||
map.permission :move_issues, {:issues => [:bulk_edit, :bulk_update]}, :require => :loggedin | |||
map.permission :delete_issues, {:issues => :destroy}, :require => :member | |||
# Queries | |||
map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member |
@@ -47,7 +47,7 @@ class ContextMenusControllerTest < ActionController::TestCase | |||
:attributes => { :href => '/projects/ecookbook/issues/1/copy', | |||
:class => 'icon-duplicate' } | |||
assert_tag :tag => 'a', :content => 'Copy', | |||
:attributes => { :href => '/issues/move/new?copy_options%5Bcopy%5D=t&ids%5B%5D=1', | |||
:attributes => { :href => '/issues/bulk_edit?copy=1&ids%5B%5D=1', | |||
:class => 'icon-copy' } | |||
assert_no_tag :tag => 'a', :content => 'Move' | |||
assert_tag :tag => 'a', :content => 'Delete', | |||
@@ -86,7 +86,7 @@ class ContextMenusControllerTest < ActionController::TestCase | |||
:attributes => { :href => "/issues/bulk_update?#{ids}&issue%5Bassigned_to_id%5D=3", | |||
:class => '' } | |||
assert_tag :tag => 'a', :content => 'Copy', | |||
:attributes => { :href => "/issues/move/new?copy_options%5Bcopy%5D=t&#{ids}", | |||
:attributes => { :href => "/issues/bulk_edit?copy=1&#{ids}", | |||
:class => 'icon-copy' } | |||
assert_no_tag :tag => 'a', :content => 'Move' | |||
assert_tag :tag => 'a', :content => 'Delete', |
@@ -1,116 +0,0 @@ | |||
require File.expand_path('../../test_helper', __FILE__) | |||
class IssueMovesControllerTest < ActionController::TestCase | |||
fixtures :projects, :trackers, :issue_statuses, :issues, | |||
:enumerations, :users, :issue_categories, | |||
:projects_trackers, | |||
:roles, | |||
:member_roles, | |||
:members, | |||
:enabled_modules, | |||
:workflows, | |||
:journals, :journal_details | |||
def setup | |||
User.current = nil | |||
end | |||
def test_get_issue_moves_new | |||
@request.session[:user_id] = 2 | |||
get :new, :id => 1 | |||
assert_tag :tag => 'option', :content => 'eCookbook', | |||
:attributes => { :value => '1', :selected => 'selected' } | |||
%w(new_tracker_id status_id priority_id assigned_to_id).each do |field| | |||
assert_tag :tag => 'option', :content => '(No change)', :attributes => { :value => '' }, | |||
:parent => {:tag => 'select', :attributes => {:id => field}} | |||
assert_no_tag :tag => 'option', :attributes => {:selected => 'selected'}, | |||
:parent => {:tag => 'select', :attributes => {:id => field}} | |||
end | |||
# Be sure we don't include inactive enumerations | |||
assert ! IssuePriority.find(15).active? | |||
assert_no_tag :option, :attributes => {:value => '15'}, | |||
:parent => {:tag => 'select', :attributes => {:id => 'priority_id'} } | |||
end | |||
def test_bulk_copy_to_another_project | |||
@request.session[:user_id] = 2 | |||
assert_difference 'Issue.count', 2 do | |||
assert_no_difference 'Project.find(1).issues.count' do | |||
post :create, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'} | |||
end | |||
end | |||
assert_redirected_to '/projects/ecookbook/issues' | |||
end | |||
context "#create via bulk copy" do | |||
should "allow not changing the issue's attributes" do | |||
@request.session[:user_id] = 2 | |||
issue_before_move = Issue.find(1) | |||
assert_difference 'Issue.count', 1 do | |||
assert_no_difference 'Project.find(1).issues.count' do | |||
post :create, :ids => [1], :new_project_id => 2, | |||
:copy_options => {:copy => '1'}, :new_tracker_id => '', | |||
:assigned_to_id => '', :status_id => '', | |||
:start_date => '', :due_date => '' | |||
end | |||
end | |||
issue_after_move = Issue.first(:order => 'id desc', :conditions => {:project_id => 2}) | |||
assert_equal issue_before_move.tracker_id, issue_after_move.tracker_id | |||
assert_equal issue_before_move.status_id, issue_after_move.status_id | |||
assert_equal issue_before_move.assigned_to_id, issue_after_move.assigned_to_id | |||
end | |||
should "allow changing the issue's attributes" do | |||
# Fixes random test failure with Mysql | |||
# where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2}) | |||
# doesn't return the expected results | |||
Issue.delete_all("project_id=2") | |||
@request.session[:user_id] = 2 | |||
assert_difference 'Issue.count', 2 do | |||
assert_no_difference 'Project.find(1).issues.count' do | |||
post :create, :ids => [1, 2], :new_project_id => 2, | |||
:copy_options => {:copy => '1'}, :new_tracker_id => '', | |||
:assigned_to_id => 4, :status_id => 3, | |||
:start_date => '2009-12-01', :due_date => '2009-12-31' | |||
end | |||
end | |||
copied_issues = Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2}) | |||
assert_equal 2, copied_issues.size | |||
copied_issues.each do |issue| | |||
assert_equal 2, issue.project_id, "Project is incorrect" | |||
assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect" | |||
assert_equal 3, issue.status_id, "Status is incorrect" | |||
assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect" | |||
assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect" | |||
end | |||
end | |||
should "allow adding a note when copying" do | |||
@request.session[:user_id] = 2 | |||
assert_difference 'Issue.count', 1 do | |||
post :create, :ids => [1], :copy_options => {:copy => '1'}, | |||
:notes => 'Copying one issue', :new_tracker_id => '', | |||
:assigned_to_id => 4, :status_id => 3, | |||
:start_date => '2009-12-01', :due_date => '2009-12-31' | |||
end | |||
issue = Issue.first(:order => 'id DESC') | |||
assert_equal 1, issue.journals.size | |||
journal = issue.journals.first | |||
assert_equal 0, journal.details.size | |||
assert_equal 'Copying one issue', journal.notes | |||
end | |||
end | |||
def test_copy_to_another_project_should_follow_when_needed | |||
@request.session[:user_id] = 2 | |||
post :create, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :follow => '1' | |||
issue = Issue.first(:order => 'id DESC') | |||
assert_redirected_to :controller => 'issues', :action => 'show', :id => issue | |||
end | |||
end |
@@ -2319,6 +2319,87 @@ class IssuesControllerTest < ActionController::TestCase | |||
assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier | |||
end | |||
def test_bulk_copy_to_another_project | |||
@request.session[:user_id] = 2 | |||
assert_difference 'Issue.count', 2 do | |||
assert_no_difference 'Project.find(1).issues.count' do | |||
post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}, :copy => '1' | |||
end | |||
end | |||
assert_redirected_to '/projects/ecookbook/issues' | |||
end | |||
def test_bulk_copy_should_allow_not_changing_the issue_attributes | |||
@request.session[:user_id] = 2 | |||
issue_before_move = Issue.find(1) | |||
assert_difference 'Issue.count', 1 do | |||
assert_no_difference 'Project.find(1).issues.count' do | |||
post :bulk_update, :ids => [1], :copy => '1', | |||
:issue => { | |||
:project_id => '2', :tracker_id => '', :assigned_to_id => '', | |||
:status_id => '', :start_date => '', :due_date => '' | |||
} | |||
end | |||
end | |||
issue_after_move = Issue.first(:order => 'id desc', :conditions => {:project_id => 2}) | |||
assert_equal issue_before_move.tracker_id, issue_after_move.tracker_id | |||
assert_equal issue_before_move.status_id, issue_after_move.status_id | |||
assert_equal issue_before_move.assigned_to_id, issue_after_move.assigned_to_id | |||
end | |||
def test_bulk_copy_should_allow_changing_the_issue_attributes | |||
# Fixes random test failure with Mysql | |||
# where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2}) | |||
# doesn't return the expected results | |||
Issue.delete_all("project_id=2") | |||
@request.session[:user_id] = 2 | |||
assert_difference 'Issue.count', 2 do | |||
assert_no_difference 'Project.find(1).issues.count' do | |||
post :bulk_update, :ids => [1, 2], :copy => '1', | |||
:issue => { | |||
:project_id => '2', :tracker_id => '', :assigned_to_id => '4', | |||
:status_id => '3', :start_date => '2009-12-01', :due_date => '2009-12-31' | |||
} | |||
end | |||
end | |||
copied_issues = Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2}) | |||
assert_equal 2, copied_issues.size | |||
copied_issues.each do |issue| | |||
assert_equal 2, issue.project_id, "Project is incorrect" | |||
assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect" | |||
assert_equal 3, issue.status_id, "Status is incorrect" | |||
assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect" | |||
assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect" | |||
end | |||
end | |||
def test_bulk_copy_should_allow_adding_a_note | |||
@request.session[:user_id] = 2 | |||
assert_difference 'Issue.count', 1 do | |||
post :bulk_update, :ids => [1], :copy => '1', | |||
:notes => 'Copying one issue', | |||
:issue => { | |||
:project_id => '', :tracker_id => '', :assigned_to_id => '4', | |||
:status_id => '3', :start_date => '2009-12-01', :due_date => '2009-12-31' | |||
} | |||
end | |||
issue = Issue.first(:order => 'id DESC') | |||
assert_equal 1, issue.journals.size | |||
journal = issue.journals.first | |||
assert_equal 0, journal.details.size | |||
assert_equal 'Copying one issue', journal.notes | |||
end | |||
def test_bulk_copy_to_another_project_should_follow_when_needed | |||
@request.session[:user_id] = 2 | |||
post :bulk_update, :ids => [1], :copy => '1', :issue => {:project_id => 2}, :follow => '1' | |||
issue = Issue.first(:order => 'id DESC') | |||
assert_redirected_to :controller => 'issues', :action => 'show', :id => issue | |||
end | |||
def test_destroy_issue_with_no_time_entries | |||
assert_nil TimeEntry.find_by_issue_id(2) | |||
@request.session[:user_id] = 2 |
@@ -1,31 +0,0 @@ | |||
# Redmine - project management software | |||
# Copyright (C) 2006-2011 Jean-Philippe Lang | |||
# | |||
# This program is free software; you can redistribute it and/or | |||
# modify it under the terms of the GNU General Public License | |||
# as published by the Free Software Foundation; either version 2 | |||
# 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 General Public License for more details. | |||
# | |||
# You should have received a copy of the GNU 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. | |||
require File.expand_path('../../../test_helper', __FILE__) | |||
class RoutingIssueMovesTest < ActionController::IntegrationTest | |||
def test_issue_moves | |||
assert_routing( | |||
{ :method => 'get', :path => "/issues/move/new" }, | |||
{ :controller => 'issue_moves', :action => 'new' } | |||
) | |||
assert_routing( | |||
{ :method => 'post', :path => "/issues/move" }, | |||
{ :controller => 'issue_moves', :action => 'create' } | |||
) | |||
end | |||
end |