diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index d3949cb..2285979 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -174,6 +174,7 @@ class IssuesController < ApplicationController @assignables << @issue.assigned_to if @issue.assigned_to && !@assignables.include?(@issue.assigned_to) @can = {:edit => User.current.allowed_to?(:edit_issues, @project), :change_status => User.current.allowed_to?(:change_issue_status, @project), + :add => User.current.allowed_to?(:add_issues, @project), :move => User.current.allowed_to?(:move_issues, @project), :delete => User.current.allowed_to?(:delete_issues, @project)} render :layout => false diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 377073f..394e545 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -192,43 +192,45 @@ class ProjectsController < ApplicationController end # Add a new issue to @project + # The new issue will be created from an existing one if copy_from parameter is given def add_issue - @tracker = Tracker.find(params[:tracker_id]) - @priorities = Enumeration::get_values('IPRI') + @issue = params[:copy_from] ? Issue.new.copy_from(params[:copy_from]) : Issue.new(params[:issue]) + @issue.project = @project + @issue.author = User.current + @issue.tracker ||= Tracker.find(params[:tracker_id]) default_status = IssueStatus.default unless default_status - flash.now[:error] = 'No default issue status defined. Please check your configuration.' + flash.now[:error] = 'No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").' render :nothing => true, :layout => true return - end - @issue = Issue.new(:project => @project, :tracker => @tracker) + end @issue.status = default_status @allowed_statuses = ([default_status] + default_status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker))if logged_in_user + if request.get? - @issue.start_date = Date.today - @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue) } + @issue.start_date ||= Date.today + @custom_values = @issue.custom_values.empty? ? + @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue) } : + @issue.custom_values else - @issue.attributes = params[:issue] - requested_status = IssueStatus.find_by_id(params[:issue][:status_id]) + # Check that the user is allowed to apply the requested status @issue.status = (@allowed_statuses.include? requested_status) ? requested_status : default_status - - @issue.author_id = self.logged_in_user.id if self.logged_in_user - # Multiple file upload - @attachments = [] - params[:attachments].each { |a| - @attachments << Attachment.new(:container => @issue, :file => a, :author => logged_in_user) unless a.size == 0 - } if params[:attachments] and params[:attachments].is_a? Array - @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) } + @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) } @issue.custom_values = @custom_values if @issue.save - @attachments.each(&:save) + if params[:attachments] && params[:attachments].is_a?(Array) + # Save attachments + params[:attachments].each {|a| Attachment.create(:container => @issue, :file => a, :author => User.current) unless a.size == 0} + end flash[:notice] = l(:notice_successful_create) Mailer.deliver_issue_add(@issue) if Setting.notified_events.include?('issue_added') redirect_to :action => 'list_issues', :id => @project + return end end + @priorities = Enumeration::get_values('IPRI') end # Show filtered/sorted issues list of @project diff --git a/app/models/issue.rb b/app/models/issue.rb index 972bf01..0d2d6fc 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -54,6 +54,13 @@ class Issue < ActiveRecord::Base end end + def copy_from(arg) + issue = arg.is_a?(Issue) ? arg : Issue.find(arg) + self.attributes = issue.attributes.dup + self.custom_values = issue.custom_values.collect {|v| v.clone} + self + end + def priority_id=(pid) self.priority = nil write_attribute(:priority_id, pid) diff --git a/app/views/issues/context_menu.rhtml b/app/views/issues/context_menu.rhtml index caf6a76..798fd42 100644 --- a/app/views/issues/context_menu.rhtml +++ b/app/views/issues/context_menu.rhtml @@ -31,6 +31,8 @@ :selected => @issue.assigned_to.nil?, :disabled => !(@can[:edit] || @can[:change_status]) %> +
  • <%= context_menu_link l(:button_copy), {:controller => 'projects', :action => 'add_issue', :id => @project, :copy_from => @issue}, + :class => 'icon-copy', :disabled => !@can[:add] %>
  • <%= context_menu_link l(:button_move), {:controller => 'projects', :action => 'move_issues', :id => @project, "issue_ids[]" => @issue.id }, :class => 'icon-move', :disabled => !@can[:move] %>
  • <%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, diff --git a/app/views/issues/show.rhtml b/app/views/issues/show.rhtml index ed615c6..dfeccc6 100644 --- a/app/views/issues/show.rhtml +++ b/app/views/issues/show.rhtml @@ -3,6 +3,7 @@ <%= link_to_if_authorized l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue}, :class => 'icon icon-edit', :accesskey => accesskey(:edit) %> <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, :class => 'icon icon-time' %> <%= watcher_tag(@issue, User.current) %> +<%= link_to_if_authorized l(:button_copy), {:controller => 'projects', :action => 'add_issue', :id => @project, :copy_from => @issue }, :class => 'icon icon-copy' %> <%= link_to_if_authorized l(:button_move), {:controller => 'projects', :action => 'move_issues', :id => @project, "issue_ids[]" => @issue.id }, :class => 'icon icon-move' %> <%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> diff --git a/app/views/projects/add_issue.rhtml b/app/views/projects/add_issue.rhtml index 8382d6c..a689229 100644 --- a/app/views/projects/add_issue.rhtml +++ b/app/views/projects/add_issue.rhtml @@ -1,10 +1,10 @@ -

    <%=l(:label_issue_new)%>: <%= @tracker.name %>

    +

    <%=l(:label_issue_new)%>: <%= @issue.tracker %>

    <% labelled_tabular_form_for :issue, @issue, :url => {:action => 'add_issue'}, :html => {:multipart => true, :id => 'issue-form'} do |f| %> - <%= hidden_field_tag 'tracker_id', @tracker.id %> - <%= render :partial => 'issues/form', :locals => {:f => f} %> + <%= f.hidden_field :tracker_id %> + <%= render :partial => 'issues/form', :locals => {:f => f} %> <%= submit_tag l(:button_create) %> <%= link_to_remote l(:label_preview), { :url => { :controller => 'issues', :action => 'preview', :id => @issue }, diff --git a/lang/en.yml b/lang/en.yml index ec0ee30..4a52d28 100644 --- a/lang/en.yml +++ b/lang/en.yml @@ -476,6 +476,7 @@ button_unarchive: Unarchive button_reset: Reset button_rename: Rename button_change_password: Change password +button_copy: Copy status_active: active status_registered: registered diff --git a/lang/fr.yml b/lang/fr.yml index 0aeed30..e5a2b84 100644 --- a/lang/fr.yml +++ b/lang/fr.yml @@ -476,6 +476,7 @@ button_unarchive: Désarchiver button_reset: Réinitialiser button_rename: Renommer button_change_password: Changer de mot de passe +button_copy: Copier status_active: actif status_registered: enregistré diff --git a/public/images/copy.png b/public/images/copy.png new file mode 100644 index 0000000000000000000000000000000000000000..dccaa0614c0018226b20f390d96f269764f18aff GIT binary patch literal 291 zc%17D@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPHFD{+k|aV|Q z%+*scvQWrRE&sB(+6IOO2J@L-%mV6UFY)wsWxviP!z(3W!P%Y< z6yhxKh%9Dc;1&X5#!GkW{s0A8(j9#r85lP9bN@+X1@eUgd_r9RGcX)Gc5La=t^fc3 zfByXWy?giCCR@t_Wf@C?{DK)Ap4~_Ta(q2q978H@B_}j6x~VD%Fc{6~X>?#bV!+GG z%Vylu+ECP`Aeg#fj^GSIDJiZb3FXcmI~H^+T;bqqToX`MC}_xZlTAdBP4X;*(M(20 Z2I~aAy*qO@-31!V;OXk;vd$@?2>_lQRbv1E literal 0 Hc$@ 1, :tracker_id => 1 + assert_response :success + assert_template 'add_issue' + post :add_issue, :id => 1, :issue => {:tracker_id => 1, :subject => 'This is the test_add_issue issue', :description => 'This is the description', :priority_id => 5} + assert_redirected_to 'projects/list_issues' + assert Issue.find_by_subject('This is the test_add_issue issue') + end + + def test_copy_issue + @request.session[:user_id] = 2 + get :add_issue, :id => 1, :copy_from => 1 + assert_template 'add_issue' + assert_not_nil assigns(:issue) + orig = Issue.find(1) + assert_equal orig.subject, assigns(:issue).subject + end end diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb index 254bffa..5ddd4bd 100644 --- a/test/unit/issue_test.rb +++ b/test/unit/issue_test.rb @@ -18,13 +18,23 @@ require File.dirname(__FILE__) + '/../test_helper' class IssueTest < Test::Unit::TestCase - fixtures :projects, :users, :members, :trackers, :issue_statuses, :issue_categories, :enumerations, :issues + fixtures :projects, :users, :members, :trackers, :issue_statuses, :issue_categories, :enumerations, :issues, :custom_fields, :custom_values def test_category_based_assignment issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => Enumeration.get_values('IPRI').first, :subject => 'Assignment test', :description => 'Assignment test', :category_id => 1) assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to end + def test_copy + issue = Issue.new.copy_from(1) + assert issue.save + issue.reload + orig = Issue.find(1) + assert_equal orig.subject, issue.subject + assert_equal orig.tracker, issue.tracker + assert_equal orig.custom_values.first.value, issue.custom_values.first.value + end + def test_close_duplicates # Create 3 issues issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :priority => Enumeration.get_values('IPRI').first, :subject => 'Duplicates test', :description => 'Duplicates test')