diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2012-07-05 12:20:07 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2012-07-05 12:20:07 +0000 |
commit | 4cecc1beeda2337f50090d9fc0fe1d54fb8d54e2 (patch) | |
tree | ae525d4ae044a57c48e01462eb76e34e485ed6e3 | |
parent | 51a1bf90dda6bc22b29b3801fbb7139b891376e5 (diff) | |
download | redmine-4cecc1beeda2337f50090d9fc0fe1d54fb8d54e2.tar.gz redmine-4cecc1beeda2337f50090d9fc0fe1d54fb8d54e2.zip |
Ability to disable standard fields on a per tracker basis (#1091).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@9912 e93f8b46-1217-0410-a6f0-8f06a7374b81
-rw-r--r-- | app/controllers/context_menus_controller.rb | 1 | ||||
-rw-r--r-- | app/helpers/issues_helper.rb | 42 | ||||
-rw-r--r-- | app/helpers/versions_helper.rb | 4 | ||||
-rw-r--r-- | app/models/issue.rb | 21 | ||||
-rw-r--r-- | app/models/query.rb | 17 | ||||
-rw-r--r-- | app/models/tracker.rb | 39 | ||||
-rw-r--r-- | app/views/context_menus/issues.html.erb | 12 | ||||
-rw-r--r-- | app/views/issues/_attributes.html.erb | 2 | ||||
-rw-r--r-- | app/views/issues/bulk_edit.html.erb | 24 | ||||
-rw-r--r-- | app/views/issues/show.html.erb | 58 | ||||
-rw-r--r-- | app/views/trackers/_form.html.erb | 11 | ||||
-rw-r--r-- | config/locales/en.yml | 1 | ||||
-rw-r--r-- | config/locales/fr.yml | 1 | ||||
-rw-r--r-- | db/migrate/20120705074331_add_trackers_fields_bits.rb | 9 | ||||
-rw-r--r-- | lib/redmine/export/pdf.rb | 92 | ||||
-rw-r--r-- | test/functional/trackers_controller_test.rb | 35 | ||||
-rw-r--r-- | test/unit/issue_test.rb | 46 | ||||
-rw-r--r-- | test/unit/tracker_test.rb | 24 |
18 files changed, 346 insertions, 93 deletions
diff --git a/app/controllers/context_menus_controller.rb b/app/controllers/context_menus_controller.rb index 36041fec6..f371b2e04 100644 --- a/app/controllers/context_menus_controller.rb +++ b/app/controllers/context_menus_controller.rb @@ -65,6 +65,7 @@ class ContextMenusController < ApplicationController end end + @safe_attributes = @issues.map(&:safe_attribute_names).reduce(:&) render :layout => false end diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index d35ada049..ece3f7844 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -92,6 +92,48 @@ module IssuesHelper s.html_safe end + class IssueFieldsRows + include ActionView::Helpers::TagHelper + + def initialize + @left = [] + @right = [] + end + + def left(*args) + args.any? ? @left << cells(*args) : @left + end + + def right(*args) + args.any? ? @right << cells(*args) : @right + end + + def size + @left.size > @right.size ? @left.size : @right.size + end + + def to_html + html = ''.html_safe + blank = content_tag('th', '') + content_tag('td', '') + size.times do |i| + left = @left[i] || blank + right = @right[i] || blank + html << content_tag('tr', left + right) + end + html + end + + def cells(label, text, options={}) + content_tag('th', "#{label}:", options) + content_tag('td', text, options) + end + end + + def issue_fields_rows + r = IssueFieldsRows.new + yield r + r.to_html + end + def render_custom_fields_rows(issue) return if issue.custom_field_values.empty? ordered_values = [] diff --git a/app/helpers/versions_helper.rb b/app/helpers/versions_helper.rb index f1fd7c8b5..e6f886734 100644 --- a/app/helpers/versions_helper.rb +++ b/app/helpers/versions_helper.rb @@ -19,10 +19,10 @@ module VersionsHelper - STATUS_BY_CRITERIAS = %w(category tracker status priority author assigned_to) + STATUS_BY_CRITERIAS = %w(tracker status priority author assigned_to category) def render_issue_status_by(version, criteria) - criteria = 'category' unless STATUS_BY_CRITERIAS.include?(criteria) + criteria = 'tracker' unless STATUS_BY_CRITERIAS.include?(criteria) h = Hash.new {|k,v| k[v] = [0, 0]} begin diff --git a/app/models/issue.rb b/app/models/issue.rb index 96c3f8526..5fc0f1d61 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -336,6 +336,12 @@ class Issue < ActiveRecord::Base :if => lambda {|issue, user| (issue.new_record? || user.allowed_to?(:edit_issues, issue.project)) && user.allowed_to?(:manage_subtasks, issue.project)} + def safe_attribute_names(*args) + names = super(*args) + names -= disabled_core_fields + names + end + # Safely sets attributes # Should be called from controllers instead of #attributes= # attr_accessible is too rough because we still want things like @@ -343,21 +349,22 @@ class Issue < ActiveRecord::Base def safe_attributes=(attrs, user=User.current) return unless attrs.is_a?(Hash) - # User can change issue attributes only if he has :edit permission or if a workflow transition is allowed - attrs = delete_unsafe_attributes(attrs, user) - return if attrs.empty? + attrs = attrs.dup # Project and Tracker must be set before since new_statuses_allowed_to depends on it. - if p = attrs.delete('project_id') + if (p = attrs.delete('project_id')) && safe_attribute?('project_id') if allowed_target_projects(user).collect(&:id).include?(p.to_i) self.project_id = p end end - if t = attrs.delete('tracker_id') + if (t = attrs.delete('tracker_id')) && safe_attribute?('tracker_id') self.tracker_id = t end + attrs = delete_unsafe_attributes(attrs, user) + return if attrs.empty? + if attrs['status_id'] unless new_statuses_allowed_to(user).collect(&:id).include?(attrs['status_id'].to_i) attrs.delete('status_id') @@ -376,6 +383,10 @@ class Issue < ActiveRecord::Base assign_attributes attrs, :without_protection => true end + def disabled_core_fields + tracker ? tracker.disabled_core_fields : [] + end + def done_ratio if Issue.use_status_for_done_ratio? && status && status.default_done_ratio status.default_done_ratio diff --git a/app/models/query.rb b/app/models/query.rb index de5fa4c16..3f4173a1b 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -213,11 +213,13 @@ class Query < ActiveRecord::Base is_public && !@is_for_all && user.allowed_to?(:manage_public_queries, project) end + def trackers + @trackers ||= project.nil? ? Tracker.find(:all, :order => 'position') : project.rolled_up_trackers + end + def available_filters return @available_filters if @available_filters - trackers = project.nil? ? Tracker.find(:all, :order => 'position') : project.rolled_up_trackers - @available_filters = { "status_id" => { :type => :list_status, :order => 1, :values => IssueStatus.find(:all, :order => 'position').collect{|s| [s.name, s.id.to_s] } }, "tracker_id" => { :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] } }, "priority_id" => { :type => :list, :order => 3, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] } }, @@ -300,6 +302,11 @@ class Query < ActiveRecord::Base end add_custom_fields_filters(IssueCustomField.find(:all, :conditions => {:is_filter => true, :is_for_all => true})) end + + Tracker.disabled_core_fields(trackers).each {|field| + @available_filters.delete field + } + @available_filters end @@ -380,6 +387,12 @@ class Query < ActiveRecord::Base :caption => :label_spent_time ) end + + disabled_fields = Tracker.disabled_core_fields(trackers).map {|field| field.sub(/_id$/, '')} + @available_columns.reject! {|column| + disabled_fields.include?(column.name.to_s) + } + @available_columns end diff --git a/app/models/tracker.rb b/app/models/tracker.rb index ce34f782c..109e0f423 100644 --- a/app/models/tracker.rb +++ b/app/models/tracker.rb @@ -16,6 +16,10 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class Tracker < ActiveRecord::Base + + # Other fields should be appended, not inserted! + CORE_FIELDS = %w(assigned_to_id category_id fixed_version_id parent_issue_id start_date due_date estimated_hours done_ratio) + before_destroy :check_integrity has_many :issues has_many :workflows, :dependent => :delete_all do @@ -28,6 +32,8 @@ class Tracker < ActiveRecord::Base has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => "#{table_name_prefix}custom_fields_trackers#{table_name_suffix}", :association_foreign_key => 'custom_field_id' acts_as_list + attr_protected :field_bits + validates_presence_of :name validates_uniqueness_of :name validates_length_of :name, :maximum => 30 @@ -58,6 +64,39 @@ class Tracker < ActiveRecord::Base @issue_statuses = IssueStatus.find_all_by_id(ids).sort end + def disabled_core_fields + i = -1 + @disabled_core_fields ||= CORE_FIELDS.select { i += 1; (fields_bits || 0) & (2 ** i) != 0} + end + + def core_fields + CORE_FIELDS - disabled_core_fields + end + + def core_fields=(fields) + raise ArgumentError.new("Tracker.core_fields takes an array") unless fields.is_a?(Array) + + bits = 0 + CORE_FIELDS.each_with_index do |field, i| + unless fields.include?(field) + bits |= 2 ** i + end + end + self.fields_bits = bits + @disabled_core_fields = nil + core_fields + end + + # Returns the fields that are disabled for all the given trackers + def self.disabled_core_fields(trackers) + trackers.uniq.map(&:disabled_core_fields).reduce(:&) + end + + # Returns the fields that are enabled for one tracker at least + def self.core_fields(trackers) + trackers.uniq.map(&:core_fields).reduce(:|) + end + private def check_integrity raise Exception.new("Can't delete tracker") if Issue.where(:tracker_id => self.id).any? diff --git a/app/views/context_menus/issues.html.erb b/app/views/context_menus/issues.html.erb index e2b87944c..75b0a7652 100644 --- a/app/views/context_menus/issues.html.erb +++ b/app/views/context_menus/issues.html.erb @@ -33,6 +33,7 @@ </li> <% end %> + <% if @safe_attributes.include?('priority_id') -%> <li class="folder"> <a href="#" class="submenu"><%= l(:field_priority) %></a> <ul> @@ -42,9 +43,10 @@ <% end -%> </ul> </li> + <% end %> <% #TODO: allow editing versions when multiple projects %> - <% unless @project.nil? || @project.shared_versions.open.empty? -%> + <% if @safe_attributes.include?('fixed_version_id') && @project && @project.shared_versions.open.any? -%> <li class="folder"> <a href="#" class="submenu"><%= l(:field_fixed_version) %></a> <ul> @@ -57,7 +59,8 @@ </ul> </li> <% end %> - <% if @assignables.present? -%> + + <% if @safe_attributes.include?('assigned_to_id') && @assignables.present? -%> <li class="folder"> <a href="#" class="submenu"><%= l(:field_assigned_to) %></a> <ul> @@ -74,7 +77,8 @@ </ul> </li> <% end %> - <% unless @project.nil? || @project.issue_categories.empty? -%> + + <% if @safe_attributes.include?('category_id') && @project && @project.issue_categories.any? -%> <li class="folder"> <a href="#" class="submenu"><%= l(:field_category) %></a> <ul> @@ -88,7 +92,7 @@ </li> <% end -%> - <% if Issue.use_field_for_done_ratio? %> + <% if @safe_attributes.include?('done_ratio') && Issue.use_field_for_done_ratio? %> <li class="folder"> <a href="#" class="submenu"><%= l(:field_done_ratio) %></a> <ul> diff --git a/app/views/issues/_attributes.html.erb b/app/views/issues/_attributes.html.erb index 0bec53163..d2c13e82b 100644 --- a/app/views/issues/_attributes.html.erb +++ b/app/views/issues/_attributes.html.erb @@ -64,3 +64,5 @@ <% end %> <% end %> + +<% include_calendar_headers_tags %> diff --git a/app/views/issues/bulk_edit.html.erb b/app/views/issues/bulk_edit.html.erb index 946b5255b..63bc1f7df 100644 --- a/app/views/issues/bulk_edit.html.erb +++ b/app/views/issues/bulk_edit.html.erb @@ -33,28 +33,40 @@ <%= select_tag('issue[status_id]',content_tag('option', l(:label_no_change_option), :value => '') + options_from_collection_for_select(@available_statuses, :id, :name)) %> </p> <% end %> + +<% if @safe_attributes.include?('priority_id') -%> <p> <label for='issue_priority_id'><%= l(:field_priority) %></label> <%= select_tag('issue[priority_id]', content_tag('option', l(:label_no_change_option), :value => '') + options_from_collection_for_select(IssuePriority.active, :id, :name)) %> </p> +<% end %> + +<% if @safe_attributes.include?('assigned_to_id') -%> <p> <label for='issue_assigned_to_id'><%= 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') + principals_options_for_select(@assignables)) %> </p> +<% end %> + +<% if @safe_attributes.include?('category_id') -%> <p> <label for='issue_category_id'><%= 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(@categories, :id, :name)) %> </p> +<% end %> + +<% if @safe_attributes.include?('fixed_version_id') -%> <p> <label for='issue_fixed_version_id'><%= 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(@versions.sort)) %> </p> +<% end %> <% @custom_fields.each do |custom_field| %> <p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('issue', custom_field, @projects) %></p> @@ -79,7 +91,8 @@ content_tag('option', l(:general_text_No), :value => '0')) %> </p> <% end %> -<% if @project && User.current.allowed_to?(:manage_subtasks, @project) %> + +<% if @safe_attributes.include?('parent_issue_id') && @project %> <p> <label for='issue_parent_issue_id'><%= l(:field_parent_issue) %></label> <%= text_field_tag 'issue[parent_issue_id]', '', :size => 10 %> @@ -87,15 +100,22 @@ <div id="parent_issue_candidates" class="autocomplete"></div> <%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:project_id => @project) }')" %> <% end %> + +<% if @safe_attributes.include?('start_date') %> <p> <label for='issue_start_date'><%= l(:field_start_date) %></label> <%= text_field_tag 'issue[start_date]', '', :size => 10 %><%= calendar_for('issue_start_date') %> </p> +<% end %> + +<% if @safe_attributes.include?('due_date') %> <p> <label for='issue_due_date'><%= l(:field_due_date) %></label> <%= text_field_tag 'issue[due_date]', '', :size => 10 %><%= calendar_for('issue_due_date') %> </p> -<% if Issue.use_field_for_done_ratio? %> +<% end %> + +<% if @safe_attributes.include?('done_ratio') && Issue.use_field_for_done_ratio? %> <p> <label for='issue_done_ratio'><%= l(:field_done_ratio) %></label> <%= select_tag 'issue[done_ratio]', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %> diff --git a/app/views/issues/show.html.erb b/app/views/issues/show.html.erb index 96e59b451..4f53592b0 100644 --- a/app/views/issues/show.html.erb +++ b/app/views/issues/show.html.erb @@ -32,34 +32,36 @@ </p> <table class="attributes"> -<tr> - <th class="status"><%=l(:field_status)%>:</th><td class="status"><%= h(@issue.status.name) %></td> - <th class="start-date"><%=l(:field_start_date)%>:</th><td class="start-date"><%= format_date(@issue.start_date) %></td> -</tr> -<tr> - <th class="priority"><%=l(:field_priority)%>:</th><td class="priority"><%= h(@issue.priority.name) %></td> - <th class="due-date"><%=l(:field_due_date)%>:</th><td class="due-date"><%= format_date(@issue.due_date) %></td> -</tr> -<tr> - <th class="assigned-to"><%=l(:field_assigned_to)%>:</th><td class="assigned-to"><%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td> - <th class="progress"><%=l(:field_done_ratio)%>:</th><td class="progress"><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td> -</tr> -<tr> - <th class="category"><%=l(:field_category)%>:</th><td class="category"><%=h(@issue.category ? @issue.category.name : "-") %></td> - <% if User.current.allowed_to?(:view_time_entries, @project) %> - <th class="spent-time"><%=l(:label_spent_time)%>:</th> - <td class="spent-time"><%= @issue.total_spent_hours > 0 ? (link_to l_hours(@issue.total_spent_hours), {:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}) : "-" %></td> - <% else %> - <th></th> - <td></td> - <% end %> -</tr> -<tr> - <th class="fixed-version"><%=l(:field_fixed_version)%>:</th><td class="fixed-version"><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td> - <% if @issue.estimated_hours %> - <th class="estimated-hours"><%=l(:field_estimated_hours)%>:</th><td class="estimated-hours"><%= l_hours(@issue.estimated_hours) %></td> - <% end %> -</tr> +<%= issue_fields_rows do |rows| + rows.left l(:field_status), h(@issue.status.name), :class => 'status' + rows.left l(:field_priority), h(@issue.priority.name), :class => 'priority' + + unless @issue.disabled_core_fields.include?('assigned_to_id') + rows.left l(:field_assigned_to), avatar(@issue.assigned_to, :size => "14").to_s + (@issue.assigned_to ? link_to_user(@issue.assigned_to) : "-"), :class => 'assigned-to' + end + unless @issue.disabled_core_fields.include?('category_id') + rows.left l(:field_category), h(@issue.category ? @issue.category.name : "-"), :class => 'category' + end + unless @issue.disabled_core_fields.include?('fixed_version_id') + rows.left l(:field_fixed_version), (@issue.fixed_version ? link_to_version(@issue.fixed_version) : "-"), :class => 'fixed-version' + end + + unless @issue.disabled_core_fields.include?('start_date') + rows.right l(:field_start_date), format_date(@issue.start_date), :class => 'start-date' + end + unless @issue.disabled_core_fields.include?('due_date') + rows.right l(:field_due_date), format_date(@issue.due_date), :class => 'due-date' + end + unless @issue.disabled_core_fields.include?('done_ratio') + rows.right l(:field_done_ratio), progress_bar(@issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%"), :class => 'progress' + end + unless @issue.disabled_core_fields.include?('estimated_hours') + rows.right l(:field_estimated_hours), l_hours(@issue.estimated_hours), :class => 'estimated-hours' + end + if User.current.allowed_to?(:view_time_entries, @project) + rows.right l(:label_spent_time), (@issue.total_spent_hours > 0 ? (link_to l_hours(@issue.total_spent_hours), {:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}) : "-"), :class => 'spent-time' + end +end %> <%= render_custom_fields_rows(@issue) %> <%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %> </table> diff --git a/app/views/trackers/_form.html.erb b/app/views/trackers/_form.html.erb index bfbed3b6b..e8819f41d 100644 --- a/app/views/trackers/_form.html.erb +++ b/app/views/trackers/_form.html.erb @@ -6,6 +6,17 @@ <p><%= f.text_field :name, :required => true %></p> <p><%= f.check_box :is_in_roadmap %></p> +<p> + <label><%= l(:field_core_fields) %></label> + <% Tracker::CORE_FIELDS.each do |field| %> + <label class="block"> + <%= check_box_tag 'tracker[core_fields][]', field, @tracker.core_fields.include?(field) %> + <%= l("field_#{field}".sub(/_id$/, '')) %> + </label> + <% end %> +</p> +<%= hidden_field_tag 'tracker[core_fields][]', '' %> + <% if IssueCustomField.all.any? %> <p> <label><%= l(:label_custom_field_plural) %></label> diff --git a/config/locales/en.yml b/config/locales/en.yml index 25f2ca716..03a850677 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -328,6 +328,7 @@ en: field_repository_is_default: Main repository field_multiple: Multiple values field_ldap_filter: LDAP filter + field_core_fields: Standard fields setting_app_title: Application title setting_app_subtitle: Application subtitle diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 5f9504b09..b341da627 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -327,6 +327,7 @@ fr: field_repository_is_default: Dépôt principal field_multiple: Valeurs multiples field_ldap_filter: Filtre LDAP + field_core_fields: Champs standards setting_app_title: Titre de l'application setting_app_subtitle: Sous-titre de l'application diff --git a/db/migrate/20120705074331_add_trackers_fields_bits.rb b/db/migrate/20120705074331_add_trackers_fields_bits.rb new file mode 100644 index 000000000..5d8458382 --- /dev/null +++ b/db/migrate/20120705074331_add_trackers_fields_bits.rb @@ -0,0 +1,9 @@ +class AddTrackersFieldsBits < ActiveRecord::Migration + def self.up + add_column :trackers, :fields_bits, :integer, :default => 0 + end + + def self.down + remove_column :trackers, :fields_bits + end +end diff --git a/lib/redmine/export/pdf.rb b/lib/redmine/export/pdf.rb index 39ac46824..466b0ccac 100644 --- a/lib/redmine/export/pdf.rb +++ b/lib/redmine/export/pdf.rb @@ -18,6 +18,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. require 'iconv' +require 'tcpdf' require 'fpdf/chinese' require 'fpdf/japanese' require 'fpdf/korean' @@ -497,14 +498,13 @@ module Redmine # Returns a PDF string of a single issue def issue_to_pdf(issue) pdf = ITCPDF.new(current_language) - pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}") + pdf.SetTitle("#{issue.project} - #{issue.tracker} ##{issue.id}") pdf.alias_nb_pages pdf.footer_date = format_date(Date.today) pdf.AddPage pdf.SetFontStyle('B',11) - buf = "#{issue.project} - #{issue.tracker} # #{issue.id}" + buf = "#{issue.project} - #{issue.tracker} ##{issue.id}" pdf.RDMMultiCell(190, 5, buf) - pdf.Ln pdf.SetFontStyle('',8) base_x = pdf.GetX i = 1 @@ -514,62 +514,54 @@ module Redmine pdf.RDMMultiCell(190 - i, 5, buf) i += 1 if i < 35 end + pdf.SetFontStyle('B',11) + pdf.RDMMultiCell(190 - i, 5, issue.subject.to_s) + pdf.SetFontStyle('',8) + pdf.RDMMultiCell(190, 5, "#{format_time(issue.created_on)} - #{issue.author}") pdf.Ln - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_status) + ":","LT") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, issue.status.to_s,"RT") - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_priority) + ":","LT") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, issue.priority.to_s,"RT") - pdf.Ln + left = [] + left << [l(:field_status), issue.status] + left << [l(:field_priority), issue.priority] + left << [l(:field_assigned_to), issue.assigned_to] unless issue.disabled_core_fields.include?('assigned_to_id') + left << [l(:field_category), issue.category] unless issue.disabled_core_fields.include?('category_id') + left << [l(:field_fixed_version), issue.fixed_version] unless issue.disabled_core_fields.include?('fixed_version_id') - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_author) + ":","L") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, issue.author.to_s,"R") - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_category) + ":","L") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, issue.category.to_s,"R") - pdf.Ln + right = [] + right << [l(:field_start_date), format_date(issue.start_date)] unless issue.disabled_core_fields.include?('start_date') + right << [l(:field_due_date), format_date(issue.due_date)] unless issue.disabled_core_fields.include?('due_date') + right << [l(:field_done_ratio), "#{issue.done_ratio}%"] unless issue.disabled_core_fields.include?('done_ratio') + right << [l(:field_estimated_hours), l_hours(issue.estimated_hours)] unless issue.disabled_core_fields.include?('estimated_hours') + right << [l(:label_spent_time), l_hours(issue.total_spent_hours)] if User.current.allowed_to?(:view_time_entries, issue.project) - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_created_on) + ":","L") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, format_date(issue.created_on),"R") - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, issue.assigned_to.to_s,"R") - pdf.Ln + rows = left.size > right.size ? left.size : right.size + while left.size < rows + left << nil + end + while right.size < rows + right << nil + end - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, format_date(issue.updated_on),"RB") - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_due_date) + ":","LB") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, format_date(issue.due_date),"RB") - pdf.Ln + half = (issue.custom_field_values.size / 2.0).ceil + issue.custom_field_values.each_with_index do |custom_value, i| + (i < half ? left : right) << [custom_value.custom_field.name, show_value(custom_value)] + end - for custom_value in issue.custom_field_values + rows = left.size > right.size ? left.size : right.size + rows.times do |i| + item = left[i] pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L") + pdf.RDMCell(35,5, item ? "#{item.first}:" : "", i == 0 ? "LT" : "L") pdf.SetFontStyle('',9) - pdf.RDMMultiCell(155,5, (show_value custom_value),"R") - end - - y0 = pdf.GetY + pdf.RDMCell(60,5, item ? item.last.to_s : "", i == 0 ? "RT" : "R") - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_subject) + ":","LT") - pdf.SetFontStyle('',9) - pdf.RDMMultiCell(155,5, issue.subject,"RT") - pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY) + item = right[i] + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, item ? "#{item.first}:" : "", i == 0 ? "LT" : "L") + pdf.SetFontStyle('',9) + pdf.RDMCell(60,5, item ? item.last.to_s : "", i == 0 ? "RT" : "R") + pdf.Ln + end pdf.SetFontStyle('B',9) pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1) diff --git a/test/functional/trackers_controller_test.rb b/test/functional/trackers_controller_test.rb index 731d19b52..7393088ae 100644 --- a/test/functional/trackers_controller_test.rb +++ b/test/functional/trackers_controller_test.rb @@ -64,10 +64,21 @@ class TrackersControllerTest < ActionController::TestCase tracker = Tracker.first(:order => 'id DESC') assert_equal 'New tracker', tracker.name assert_equal [1], tracker.project_ids.sort + assert_equal Tracker::CORE_FIELDS, tracker.core_fields assert_equal [1, 6], tracker.custom_field_ids.sort assert_equal 0, tracker.workflows.count end + def create_with_disabled_core_fields + assert_difference 'Tracker.count' do + post :create, :tracker => { :name => 'New tracker', :core_fields => ['assigned_to_id', 'fixed_version_id', ''] } + end + assert_redirected_to :action => 'index' + tracker = Tracker.first(:order => 'id DESC') + assert_equal 'New tracker', tracker.name + assert_equal %w(assigned_to_id fixed_version_id), tracker.core_fields + end + def test_create_new_with_workflow_copy assert_difference 'Tracker.count' do post :create, :tracker => { :name => 'New tracker' }, :copy_workflow_from => 1 @@ -107,6 +118,24 @@ class TrackersControllerTest < ActionController::TestCase :type => 'hidden'} end + def test_edit_should_check_core_fields + tracker = Tracker.find(1) + tracker.core_fields = %w(assigned_to_id fixed_version_id) + tracker.save! + + get :edit, :id => 1 + assert_response :success + assert_template 'edit' + + assert_select 'input[name=?][value=assigned_to_id][checked=checked]', 'tracker[core_fields][]' + assert_select 'input[name=?][value=fixed_version_id][checked=checked]', 'tracker[core_fields][]' + + assert_select 'input[name=?][value=category_id]', 'tracker[core_fields][]' + assert_select 'input[name=?][value=category_id][checked=checked]', 'tracker[core_fields][]', 0 + + assert_select 'input[name=?][value=][type=hidden]', 'tracker[core_fields][]' + end + def test_update put :update, :id => 1, :tracker => { :name => 'Renamed', :project_ids => ['1', '2', ''] } @@ -121,6 +150,12 @@ class TrackersControllerTest < ActionController::TestCase assert Tracker.find(1).project_ids.empty? end + def test_update_without_core_fields + put :update, :id => 1, :tracker => { :name => 'Renamed', :core_fields => [''] } + assert_redirected_to :action => 'index' + assert Tracker.find(1).core_fields.empty? + end + def test_update_with_failure put :update, :id => 1, :tracker => { :name => '' } assert_response :success diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb index b5799f3fc..fe8bdf2ac 100644 --- a/test/unit/issue_test.rb +++ b/test/unit/issue_test.rb @@ -403,6 +403,52 @@ class IssueTest < ActiveSupport::TestCase assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id) end + def test_safe_attributes_should_not_include_disabled_field + tracker = Tracker.new(:core_fields => %w(assigned_to_id fixed_version_id)) + + issue = Issue.new(:tracker => tracker) + assert_include 'tracker_id', issue.safe_attribute_names + assert_include 'status_id', issue.safe_attribute_names + assert_include 'subject', issue.safe_attribute_names + assert_include 'description', issue.safe_attribute_names + assert_include 'custom_field_values', issue.safe_attribute_names + assert_include 'custom_fields', issue.safe_attribute_names + assert_include 'lock_version', issue.safe_attribute_names + + tracker.core_fields.each do |field| + assert_include field, issue.safe_attribute_names + end + + tracker.disabled_core_fields.each do |field| + assert_not_include field, issue.safe_attribute_names + end + end + + def test_safe_attributes_should_ignore_disabled_fields + tracker = Tracker.find(1) + tracker.core_fields = %w(assigned_to_id due_date) + tracker.save! + + issue = Issue.new(:tracker => tracker) + issue.safe_attributes = {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'} + assert_nil issue.start_date + assert_equal Date.parse('2012-07-14'), issue.due_date + end + + def test_safe_attributes_should_accept_target_tracker_fields + source = Tracker.find(1) + source.core_fields = [] + source.save! + target = Tracker.find(2) + target.core_fields = %w(assigned_to_id due_date) + target.save! + + issue = Issue.new(:tracker => source) + issue.safe_attributes = {'tracker_id' => 2, 'due_date' => '2012-07-14'} + assert_equal target, issue.tracker + assert_equal Date.parse('2012-07-14'), issue.due_date + end + def test_copy issue = Issue.new.copy_from(1) assert issue.copy? diff --git a/test/unit/tracker_test.rb b/test/unit/tracker_test.rb index 9cf6866a9..91b259827 100644 --- a/test/unit/tracker_test.rb +++ b/test/unit/tracker_test.rb @@ -59,6 +59,30 @@ class TrackerTest < ActiveSupport::TestCase assert_equal [], Tracker.new.issue_statuses end + def test_core_fields_should_be_enabled_by_default + tracker = Tracker.new + assert_equal Tracker::CORE_FIELDS, tracker.core_fields + assert_equal [], tracker.disabled_core_fields + end + + def test_core_fields + tracker = Tracker.new + tracker.core_fields = %w(assigned_to_id due_date) + + assert_equal %w(assigned_to_id due_date), tracker.core_fields + assert_equal Tracker::CORE_FIELDS - %w(assigned_to_id due_date), tracker.disabled_core_fields + end + + def test_core_fields_should_return_fields_enabled_for_any_tracker + trackers = [] + trackers << Tracker.new(:core_fields => %w(assigned_to_id due_date)) + trackers << Tracker.new(:core_fields => %w(assigned_to_id done_ratio)) + trackers << Tracker.new(:core_fields => []) + + assert_equal %w(assigned_to_id due_date done_ratio), Tracker.core_fields(trackers) + assert_equal Tracker::CORE_FIELDS - %w(assigned_to_id due_date done_ratio), Tracker.disabled_core_fields(trackers) + end + def test_sort_should_sort_by_position a = Tracker.new(:name => 'Tracker A', :position => 2) b = Tracker.new(:name => 'Tracker B', :position => 1) |