From 972f00eb473ffd07292bb0960428c0181046b613 Mon Sep 17 00:00:00 2001 From: Go MAEDA Date: Sat, 26 Dec 2020 01:36:19 +0000 Subject: [PATCH] Create custom field by copy (#34307). Patch by Takenori TAKAKI. git-svn-id: http://svn.redmine.org/redmine/trunk@20692 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/custom_fields_controller.rb | 3 + app/models/custom_field.rb | 20 +++++ app/views/custom_fields/_index.html.erb | 1 + app/views/custom_fields/new.html.erb | 1 + .../custom_fields_controller_test.rb | 73 +++++++++++++++++++ test/unit/custom_field_test.rb | 49 +++++++++++++ 6 files changed, 147 insertions(+) diff --git a/app/controllers/custom_fields_controller.rb b/app/controllers/custom_fields_controller.rb index 893bc4819..41a41ebe9 100644 --- a/app/controllers/custom_fields_controller.rb +++ b/app/controllers/custom_fields_controller.rb @@ -98,6 +98,9 @@ class CustomFieldsController < ApplicationController if @custom_field.nil? render :action => 'select_type' else + if params[:copy].present? && (@copy_from = CustomField.find_by(id: params[:copy])) + @custom_field.copy_from(@copy_from) + end @custom_field.safe_attributes = params[:custom_field] end end diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb index e0ea10cc8..816a52fb8 100644 --- a/app/models/custom_field.rb +++ b/app/models/custom_field.rb @@ -102,6 +102,26 @@ class CustomField < ActiveRecord::Base 'extensions_allowed', 'full_width_layout') + def copy_from(arg, options={}) + return if arg.blank? + + custom_field = arg.is_a?(CustomField) ? arg : CustomField.find_by(id: arg.to_s) + self.attributes = custom_field.attributes.dup.except('id', 'name', 'position') + custom_field.enumerations.each do |e| + new_enumeration = self.enumerations.build + new_enumeration.attributes = e.attributes.except('id') + end + self.default_value = nil if custom_field.enumerations.any? + if %w(IssueCustomField TimeEntryCustomField ProjectCustomField VersionCustomField).include?(self.class.name) + self.role_ids = custom_field.role_ids.dup + end + if self.is_a?(IssueCustomField) + self.tracker_ids = custom_field.tracker_ids.dup + self.project_ids = custom_field.project_ids.dup + end + self + end + def format @format ||= Redmine::FieldFormat.find(field_format) end diff --git a/app/views/custom_fields/_index.html.erb b/app/views/custom_fields/_index.html.erb index 04d4aa21d..81fe21404 100644 --- a/app/views/custom_fields/_index.html.erb +++ b/app/views/custom_fields/_index.html.erb @@ -22,6 +22,7 @@ <% end %> <%= reorder_handle(custom_field, :url => custom_field_path(custom_field), :param => 'custom_field') %> + <%= link_to_function l(:button_copy), "location.href = '#{new_custom_field_path(:copy => custom_field)}&type=' + encodeURIComponent(($('.tabs a.selected').attr('id')||'').split('tab-').pop())", :class => 'icon icon-copy' %> <%= delete_link custom_field_path(custom_field) %> diff --git a/app/views/custom_fields/new.html.erb b/app/views/custom_fields/new.html.erb index db422296b..45b5cc0cf 100644 --- a/app/views/custom_fields/new.html.erb +++ b/app/views/custom_fields/new.html.erb @@ -3,6 +3,7 @@ <%= labelled_form_for :custom_field, @custom_field, :url => custom_fields_path, :html => {:id => 'custom_field_form'} do |f| %> <%= render :partial => 'form', :locals => { :f => f } %> <%= hidden_field_tag 'type', @custom_field.type %> +<%= hidden_field_tag 'copy', @copy_from.id if @copy_from %> <% end %> <%= javascript_tag do %> diff --git a/test/functional/custom_fields_controller_test.rb b/test/functional/custom_fields_controller_test.rb index fd042dea6..a2ca38083 100644 --- a/test/functional/custom_fields_controller_test.rb +++ b/test/functional/custom_fields_controller_test.rb @@ -325,6 +325,56 @@ class CustomFieldsControllerTest < Redmine::ControllerTest assert_select 'input[type=radio][name=type]' end + def test_new_with_copy + role_ids = [1, 2] + tracker_ids = [1, 2] + project_ids = [1, 2, 3] + + copy_from = CustomField.find(1) + copy_from.role_ids = role_ids + copy_from.tracker_ids = tracker_ids + copy_from.project_ids = project_ids + copy_from.save + + get :new, :params => {:copy => copy_from.id.to_s, :type => IssueCustomField} + assert_response :success + + assert_select 'form' do + # field_format selected + assert_select 'select[name=?]', 'custom_field[field_format]' do + assert_select "option[value=\"#{copy_from.field_format}\"][selected=selected]" + end + # blank name + assert_select 'input[name=?][value=""]', 'custom_field[name]' + # description copied + assert_select 'textarea[name=?]', 'custom_field[description]', :text => copy_from.description + # role checked + role_ids.each do |role_id| + assert_select "input[type=checkbox][name=?][value=#{role_id}][checked=checked]", 'custom_field[role_ids][]' + end + # role not checked + (Role.givable.pluck(:id) - role_ids).each do |role_id| + assert_select "input[type=checkbox][name=?][value=#{role_id}]", 'custom_field[role_ids][]' + end + # tracker checked + tracker_ids.each do |tracker_id| + assert_select "input[type=checkbox][name=?][value=#{tracker_id}][checked=checked]", 'custom_field[tracker_ids][]' + end + # tracker not checked + (Tracker.all.pluck(:id) - tracker_ids).each do |tracker_id| + assert_select "input[type=checkbox][name=?][value=#{tracker_id}]", 'custom_field[tracker_ids][]' + end + # project checked + project_ids.each do |project_id| + assert_select "input[type=checkbox][name=?][value=#{project_id}][checked=checked]", 'custom_field[project_ids][]' + end + # project not checked + (Project.all.pluck(:id) - project_ids).each do |project_id| + assert_select "input[type=checkbox][name=?][value=#{project_id}]", 'custom_field[project_ids][]' + end + end + end + def test_create_list_custom_field field = new_record(IssueCustomField) do post( @@ -449,6 +499,29 @@ class CustomFieldsControllerTest < Redmine::ControllerTest assert_select 'input[type=radio][name=type]' end + def test_create_with_enumerations + custom_field = IssueCustomField.create(:field_format => 'enumeration', :name => 'IssueCustomField') + custom_field.enumerations.build(:name => 'enumeration1', :position => 1) + custom_field.enumerations.build(:name => 'enumeration2', :position => 2) + assert custom_field.save + + assert_difference 'CustomField.count' do + post( + :create, + :params => { + :type => 'IssueCustomField', + :copy => custom_field.id, + :custom_field => {:name => 'Copy'} + } + ) + assert_response 302 + end + field = IssueCustomField.order('id desc').first + assert_equal 'Copy', field.name + assert_equal ['enumeration1', 'enumeration2'], field.enumerations.pluck(:name).sort + assert_equal [1, 2], field.enumerations.pluck(:position).sort + end + def test_edit get( :edit, diff --git a/test/unit/custom_field_test.rb b/test/unit/custom_field_test.rb index f5d8e8027..3e18512d6 100644 --- a/test/unit/custom_field_test.rb +++ b/test/unit/custom_field_test.rb @@ -372,4 +372,53 @@ class CustomFieldTest < ActiveSupport::TestCase field2 = IssueCustomField.create!(:name => 'Another long text', :field_format => 'text') assert !field2.full_text_formatting? end + + def test_copy_from + custom_field = CustomField.find(1) + copy = CustomField.new.copy_from(custom_field) + + assert_nil copy.id + assert_equal '', copy.name + assert_nil copy.position + (custom_field.attribute_names - ['id', 'name', 'position']).each do |attribute_name| + assert_equal custom_field.send(attribute_name).to_s, copy.send(attribute_name).to_s + end + + copy.name = 'Copy' + assert copy.save + end + + def test_copy_from_should_copy_enumerations + custom_field = CustomField.create(:field_format => 'enumeration', :name => 'CustomField') + custom_field.enumerations.build(:name => 'enumeration1', :position => 1) + custom_field.enumerations.build(:name => 'enumeration2', :position => 2) + assert custom_field.save + + copy = CustomField.new.copy_from(custom_field) + copy.name = 'Copy' + assert copy.save + assert_equal ['enumeration1', 'enumeration2'], copy.enumerations.pluck(:name) + assert_equal [1, 2], copy.enumerations.pluck(:position) + end + + def test_copy_from_should_copy_roles + %w(IssueCustomField TimeEntryCustomField ProjectCustomField VersionCustomField).each do |klass_name| + klass = klass_name.constantize + custom_field = klass.new(:name => klass_name, :role_ids => [1, 2, 3, 4, 5]) + copy = klass.new.copy_from(custom_field) + assert_equal [1, 2, 3, 4, 5], copy.role_ids.sort + end + end + + def test_copy_from_should_copy_trackers + issue_custom_field = IssueCustomField.new(:name => 'IssueCustomField', :tracker_ids => [1, 2, 3]) + copy = IssueCustomField.new.copy_from(issue_custom_field) + assert_equal [1, 2, 3], copy.tracker_ids + end + + def test_copy_from_should_copy_projects + issue_custom_field = IssueCustomField.new(:name => 'IssueCustomField', :project_ids => [1, 2, 3, 4, 5, 6]) + copy = IssueCustomField.new.copy_from(issue_custom_field) + assert_equal [1, 2, 3, 4, 5, 6], copy.project_ids + end end -- 2.39.5