Project

General

Profile

Feature #12005 » workflow_hidden_field_DR_v0.011.patch

David Robinson, 2013-02-12 16:00

View differences:

config/locales/en.yml (working copy)
881 882
  label_fields_permissions: Fields permissions
882 883
  label_readonly: Read-only
883 884
  label_required: Required
885
  label_hidden: " Hidden "
884 886
  label_attribute_of_project: "Project's %{name}"
885 887
  label_attribute_of_author: "Author's %{name}"
886 888
  label_attribute_of_assigned_to: "Assignee's %{name}"
app/helpers/issues_helper.rb (working copy)
146 146
  end
147 147

  
148 148
  def render_custom_fields_rows(issue)
149
    return if issue.custom_field_values.empty?
149
    local_viewablecf=issue.viewable_custom_field_values
150
    return if local_viewablecf.empty?
150 151
    ordered_values = []
151
    half = (issue.custom_field_values.size / 2.0).ceil
152
    half = (local_viewablecf.size / 2.0).ceil
152 153
    half.times do |i|
153
      ordered_values << issue.custom_field_values[i]
154
      ordered_values << issue.custom_field_values[i + half]
154
      ordered_values << local_viewablecf[i]
155
      ordered_values << local_viewablecf[i + half]
155 156
    end
156 157
    s = "<tr>\n"
157 158
    n = 0
......
221 222
    strings = []
222 223
    values_by_field = {}
223 224
    details.each do |detail|
224
      if detail.property == 'cf'
225
        field_id = detail.prop_key
226
        field = CustomField.find_by_id(field_id)
227
        if field && field.multiple?
228
          values_by_field[field_id] ||= {:added => [], :deleted => []}
229
          if detail.old_value
230
            values_by_field[field_id][:deleted] << detail.old_value
231
          end
232
          if detail.value
233
            values_by_field[field_id][:added] << detail.value
234
          end
235
          next
236
        end
225
      unless detail.journal.issue.hidden_attribute?(detail.prop_key, options[:user])
226
	      if detail.property == 'cf'
227
      		field_id = detail.prop_key
228
      		field = CustomField.find_by_id(field_id)
229
      		if field && field.multiple?
230
      		  values_by_field[field_id] ||= {:added => [], :deleted => []}
231
      		  if detail.old_value
232
      		    values_by_field[field_id][:deleted] << detail.old_value
233
      		  end
234
      		  if detail.value
235
      		    values_by_field[field_id][:added] << detail.value
236
      		  end
237
      		  next
238
		      end
239
	      end
240
	      strings << show_detail(detail, no_html, options)
237 241
      end
238
      strings << show_detail(detail, no_html, options)
239 242
    end
240 243
    values_by_field.each do |field_id, changes|
241
      detail = JournalDetail.new(:property => 'cf', :prop_key => field_id)
242
      if changes[:added].any?
243
        detail.value = changes[:added]
244
        strings << show_detail(detail, no_html, options)
245
      elsif changes[:deleted].any?
246
        detail.old_value = changes[:deleted]
247
        strings << show_detail(detail, no_html, options)
248
      end
244
	     detail = JournalDetail.new(:property => 'cf', :prop_key => field_id)
245
      unless detail.journal.issue.hidden_attribute?(detail.prop_key, options[:user])
246
	      if changes[:added].any?
247
      		detail.value = changes[:added]
248
      		strings << show_detail(detail, no_html, options)
249
	      elsif changes[:deleted].any?
250
      		detail.old_value = changes[:deleted]
251
      		strings << show_detail(detail, no_html, options)
252
	      end
253
      end	
249 254
    end
250 255
    strings
251 256
  end
......
385 390
      # csv lines
386 391
      issues.each do |issue|
387 392
        col_values = columns.collect do |column|
388
          s = if column.is_a?(QueryCustomFieldColumn)
389
            cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
390
            show_value(cv)
393
	        hidden_fields = issue.hidden_attribute_names.map {|field| field.sub(/_id$/, '')}
394
	        if hidden_fields.include?(column.is_a?(QueryCustomFieldColumn) ? column.custom_field.id.to_s : column.name.to_s)  
395
            ""
391 396
          else
392
            value = column.value(issue)
393
            if value.is_a?(Date)
394
              format_date(value)
395
            elsif value.is_a?(Time)
396
              format_time(value)
397
            elsif value.is_a?(Float)
398
              ("%.2f" % value).gsub('.', decimal_separator)
397
            s = if column.is_a?(QueryCustomFieldColumn)
398
              cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
399
              show_value(cv)
399 400
            else
400
              value
401
              value = column.value(issue)
402
              if value.is_a?(Date)
403
                format_date(value)
404
              elsif value.is_a?(Time)
405
                format_time(value)
406
              elsif value.is_a?(Float)
407
                ("%.2f" % value).gsub('.', decimal_separator)
408
              else
409
                value
410
              end
401 411
            end
412
            s.to_s
402 413
          end
403
          s.to_s
404 414
        end
405 415
        csv << [ issue.id.to_s ] + col_values.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) }
406 416
      end
app/helpers/workflows_helper.rb (working copy)
25 25
  def field_permission_tag(permissions, status, field)
26 26
    name = field.is_a?(CustomField) ? field.id.to_s : field
27 27
    options = [["", ""], [l(:label_readonly), "readonly"]]
28
    options << [l(:label_hidden), "hidden"]
28 29
    options << [l(:label_required), "required"] unless field_required?(field)
29 30

  
30 31
    select_tag("permissions[#{name}][#{status.id}]", options_for_select(options, permissions[status.id][name]))
app/models/issue.rb (working copy)
446 446
    end
447 447
  end
448 448

  
449
  # Returns the custom_field_values that can be viewed by the given user
450
  # For now: just exclude Fix Info and RNs, as it is printed seperately below description.
451
  def viewable_custom_field_values(user=nil)
452
    custom_field_values.reject do |value|
453
      hidden_attribute_names(user).include?(value.custom_field_id.to_s)
454
    end
455
  end
456

  
449 457
  # Returns the names of attributes that are read-only for user or the current user
450 458
  # For users with multiple roles, the read-only fields are the intersection of
451 459
  # read-only fields of each role
......
455 463
  #   issue.read_only_attribute_names # => ['due_date', '2']
456 464
  #   issue.read_only_attribute_names(user) # => []
457 465
  def read_only_attribute_names(user=nil)
458
    workflow_rule_by_attribute(user).reject {|attr, rule| rule != 'readonly'}.keys
466
    workflow_rule_by_attribute(user).reject {|attr, rule| rule != 'readonly' and rule != 'hidden'}.keys
459 467
  end
460 468

  
469
  # Same as above, but for hidden fields
470
  def hidden_attribute_names(user=nil)
471
    workflow_rule_by_attribute(user).reject {|attr, rule| rule != 'hidden'}.keys
472
  end
473

  
461 474
  # Returns the names of required attributes for user or the current user
462 475
  # For users with multiple roles, the required fields are the intersection of
463 476
  # required fields of each role
......
475 488
    required_attribute_names(user).include?(name.to_s)
476 489
  end
477 490

  
491
  # Returns true if the attribute should be hidden for user
492
  def hidden_attribute?(name, user=nil)
493
    hidden_attribute_names(user).include?(name.to_s)
494
  end
495

  
496

  
478 497
  # Returns a hash of the workflow rule by attribute for the given user
479 498
  #
480 499
  # Examples:
app/models/mailer.rb (working copy)
32 32
  # Example:
33 33
  #   issue_add(issue) => Mail::Message object
34 34
  #   Mailer.issue_add(issue).deliver => sends an email to issue recipients
35
  def issue_add(issue)
35
  def issue_add(issue, ausers)
36 36
    redmine_headers 'Project' => issue.project.identifier,
37 37
                    'Issue-Id' => issue.id,
38 38
                    'Issue-Author' => issue.author.login
......
41 41
    @author = issue.author
42 42
    @issue = issue
43 43
    @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue)
44
    recipients = issue.recipients
45
    cc = issue.watcher_recipients - recipients
44

  
45
    @auser = ausers[0]
46
    recipients = ausers.map(&:mail)
47
    cc = issue.watcher_recipient_users.map(&:mail).select {|rcpt| recipients.include?(rcpt)}
46 48
    mail :to => recipients,
47 49
      :cc => cc,
48 50
      :subject => "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
49 51
  end
50 52

  
53

  
54

  
51 55
  # Builds a Mail::Message object used to email recipients of the edited issue.
52 56
  #
53 57
  # Example:
54
  #   issue_edit(journal) => Mail::Message object
55
  #   Mailer.issue_edit(journal).deliver => sends an email to issue recipients
56
  def issue_edit(journal)
58
  #   issue_edit(journal, users) => Mail::Message object
59
  #   Mailer.issue_edit(journal, users).deliver => sends an email to +users+
60
  def issue_edit(journal, ausers)
57 61
    issue = journal.journalized.reload
58 62
    redmine_headers 'Project' => issue.project.identifier,
59 63
                    'Issue-Id' => issue.id,
......
62 66
    message_id journal
63 67
    references issue
64 68
    @author = journal.user
65
    recipients = journal.recipients
66
    # Watchers in cc
67
    cc = journal.watcher_recipients - recipients
69
    @auser = ausers[0]
70
    recipients = ausers.map(&:mail)
71
    cc = issue.watcher_recipient_users.map(&:mail).select {|rcpt| recipients.include?(rcpt)}
72
    recipients.reject! {|rcpt| cc.include?(rcpt)}
73

  
68 74
    s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
69 75
    s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
70 76
    s << issue.subject
app/models/issue_observer.rb (working copy)
16 16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 17

  
18 18
class IssueObserver < ActiveRecord::Observer
19
  def after_create(issue)
20
    Mailer.issue_add(issue).deliver if Setting.notified_events.include?('issue_added')
19
  def after_create(issue)    
20
    if Setting.notified_events.include?('issue_added')    
21
      recipients = issue.notified_users + issue.watcher_recipient_users
22

  
23
      if recipients.any?
24
        variations = recipients.collect { |user| issue.hidden_attribute_names(user) }.uniq
25
        recipient_groups = Array.new(variations.count) { Array.new }
26
        recipients.each do |user|
27
          recipient_groups[variations.index(issue.hidden_attribute_names(user))] << user
28
        end
29

  
30
        recipient_groups.each do |group|
31
          Mailer.issue_add(issue, group).deliver
32
        end
33
      end
34
    end
21 35
  end
22 36
end
app/models/project.rb (working copy)
146 146
    user.allowed_to?(:view_project, self)
147 147
  end
148 148

  
149
  # Returns list of attributes that are hidden on all statuses of all trackers for +user+ or the current user.
150
  def completely_hidden_attribute_names(user=nil)
151
    user_real = user || User.current
152
    roles = user_real.admin ? Role.all : user_real.roles_for_project(self)
153
    return {} if roles.empty?
154

  
155
    result = {}
156
    workflow_permissions = WorkflowPermission.where(:tracker_id => trackers.map(&:id), :old_status_id => IssueStatus.all.map(&:id), :role_id => roles.map(&:id), :rule => 'hidden').all
157

  
158
    if workflow_permissions.any?
159
      workflow_rules = workflow_permissions.inject({}) do |h, wp|
160
        h[wp.field_name] ||= []
161
        h[wp.field_name] << wp.rule
162
        h
163
      end
164
      workflow_rules.each do |attr, rules|
165
        next if rules.size < (roles.size * trackers.size * IssueStatus.all.size)
166
        uniq_rules = rules.uniq
167
        if uniq_rules.size == 1
168
          result[attr] = uniq_rules.first
169
        else
170
          result[attr] = 'required'
171
        end
172
      end
173
    end
174

  
175
    result.keys    
176
  end
177

  
178

  
149 179
  # Returns a SQL conditions string used to find all projects visible by the specified user.
150 180
  #
151 181
  # Examples:
app/models/journal_observer.rb (working copy)
23 23
          (Setting.notified_events.include?('issue_status_updated') && journal.new_status.present?) ||
24 24
          (Setting.notified_events.include?('issue_priority_updated') && journal.new_value_for('priority_id').present?)
25 25
        )
26
      Mailer.issue_edit(journal).deliver
26

  
27
      recipients = journal.journalized.notified_users
28
      recipients += journal.journalized.watcher_recipient_users
29
      if journal.private_notes?
30
        recipients = recipients.select {|user| user.allowed_to?(:view_private_notes, journal.journalized.project)}
31
      end
32
      
33
      if recipients.any?
34
        variations = recipients.collect { |user| journal.issue.hidden_attribute_names(user) }.uniq
35
        recipient_groups = Array.new(variations.count) { Array.new }
36
        recipients.each do |user|
37
          recipient_groups[variations.index(journal.issue.hidden_attribute_names(user))] << user
38
        end
39

  
40

  
41
        recipient_groups.each do |group|
42
          Mailer.issue_edit(journal, group).deliver
43
        end
44
      end
27 45
    end
28 46
  end
29 47
end
app/models/workflow_permission.rb (working copy)
16 16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 17

  
18 18
class WorkflowPermission < WorkflowRule
19
  validates_inclusion_of :rule, :in => %w(readonly required)
19
  validates_inclusion_of :rule, :in => %w(readonly required hidden)
20 20
  validate :validate_field_name
21 21

  
22 22
  # Replaces the workflow permissions for the given tracker and role
23 23
  #
24 24
  # Example:
25
  #   WorkflowPermission.replace_permissions role, tracker, {'due_date' => {'1' => 'readonly', '2' => 'required'}}
25
  #   WorkflowPermission.replace_permissions role, tracker, {'due_date' => {'1' => 'readonly', '2' => 'required', '3' => 'hidden'}}
26 26
  def self.replace_permissions(tracker, role, permissions)
27 27
    destroy_all(:tracker_id => tracker.id, :role_id => role.id)
28 28

  
app/models/query.rb (working copy)
49 49
  end
50 50

  
51 51
  def value(issue)
52
    issue.send name
52
    hidden_fields = issue.hidden_attribute_names.map {|field| field.sub(/_id$/, '')}
53
    if hidden_fields.include?(name.to_s)
54
      ""
55
    else
56
      issue.send name
57
    end
53 58
  end
54 59

  
55 60
  def css_classes
......
369 382
    Tracker.disabled_core_fields(trackers).each {|field|
370 383
      @available_filters.delete field
371 384
    }
385

  
386
    if project != nil
387
      hidden_fields = project.completely_hidden_attribute_names
388
    else
389
      hidden_fields = []
390
      all_projects.each { |prj| 
391
        if prj.visible? and User.current.roles_for_project(prj).count > 0
392
          hidden_fields = hidden_fields == [] ? prj.completely_hidden_attribute_names : hidden_fields & prj.completely_hidden_attribute_names
393
        end
394
      }
395
    end
396

  
397
    hidden_fields.each {|field|
398
      @available_filters.delete field
399
    }
400

  
372 401
    @available_filters.each do |field, options|
373 402
      options[:name] ||= l(options[:label] || "field_#{field}".gsub(/_id$/, ''))
374 403
    end
......
460 489
  def available_columns
461 490
    return @available_columns if @available_columns
462 491
    @available_columns = ::Query.available_columns.dup
492
   
493
    if project == nil
494
      hidden_fields = []
495
      all_projects.each { |prj| 
496
        if prj.visible? and User.current.roles_for_project(prj).count > 0
497
          hidden_fields = hidden_fields == [] ? prj.completely_hidden_attribute_names : hidden_fields & prj.completely_hidden_attribute_names
498
        end
499
      }
500
    else
501
      hidden_fields = project.completely_hidden_attribute_names
502
    end
503
    hidden_fields.map! {|field| field.sub(/_id$/, '')}
504

  
463 505
    @available_columns += (project ?
464 506
                            project.all_issue_custom_fields :
465 507
                            IssueCustomField.find(:all)
466
                           ).collect {|cf| QueryCustomFieldColumn.new(cf) }
508
                           ).collect {|cf| QueryCustomFieldColumn.new(cf) }.reject{|column| hidden_fields.include?(column.custom_field.id.to_s) }
467 509

  
468 510
    if User.current.allowed_to?(:view_time_entries, project, :global => true)
469 511
      index = nil
......
486 528
    @available_columns.reject! {|column|
487 529
      disabled_fields.include?(column.name.to_s)
488 530
    }
531
    
532
    @available_columns.reject! {|column|
533
      hidden_fields.include?(column.name.to_s)
534
    }
489 535

  
490 536
    @available_columns
491 537
  end
......
1010 1078
    @available_filters ||= {}
1011 1079

  
1012 1080
    custom_fields.select(&:is_filter?).each do |field|
1013
      case field.field_format
1014
      when "text"
1015
        options = { :type => :text, :order => 20 }
1016
      when "list"
1017
        options = { :type => :list_optional, :values => field.possible_values, :order => 20}
1018
      when "date"
1019
        options = { :type => :date, :order => 20 }
1020
      when "bool"
1021
        options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]], :order => 20 }
1022
      when "int"
1023
        options = { :type => :integer, :order => 20 }
1024
      when "float"
1025
        options = { :type => :float, :order => 20 }
1026
      when "user", "version"
1027
        next unless project
1028
        values = field.possible_values_options(project)
1029
        if User.current.logged? && field.field_format == 'user'
1030
          values.unshift ["<< #{l(:label_me)} >>", "me"]
1081
      unless project == nil or project.completely_hidden_attribute_names.include?(field.id.to_s)
1082
        case field.field_format
1083
        when "text"
1084
          options = { :type => :text, :order => 20 }
1085
        when "list"
1086
          options = { :type => :list_optional, :values => field.possible_values, :order => 20}
1087
        when "date"
1088
          options = { :type => :date, :order => 20 }
1089
        when "bool"
1090
          options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]], :order => 20 }
1091
        when "int"
1092
          options = { :type => :integer, :order => 20 }
1093
        when "float"
1094
          options = { :type => :float, :order => 20 }
1095
        when "user", "version"
1096
          next unless project
1097
          values = field.possible_values_options(project)
1098
          if User.current.logged? && field.field_format == 'user'
1099
            values.unshift ["<< #{l(:label_me)} >>", "me"]
1100
          end
1101
          options = { :type => :list_optional, :values => values, :order => 20}
1102
        else
1103
          options = { :type => :string, :order => 20 }
1031 1104
        end
1032
        options = { :type => :list_optional, :values => values, :order => 20}
1033
      else
1034
        options = { :type => :string, :order => 20 }
1105
        filter_id = "cf_#{field.id}"
1106
        filter_name = field.name
1107
        if assoc.present?
1108
          filter_id = "#{assoc}.#{filter_id}"
1109
          filter_name = l("label_attribute_of_#{assoc}", :name => filter_name)
1110
        end
1111
        @available_filters[filter_id] = options.merge({
1112
                 :name => filter_name,
1113
                 :format => field.field_format,
1114
                 :field => field
1115
               })
1035 1116
      end
1036
      filter_id = "cf_#{field.id}"
1037
      filter_name = field.name
1038
      if assoc.present?
1039
        filter_id = "#{assoc}.#{filter_id}"
1040
        filter_name = l("label_attribute_of_#{assoc}", :name => filter_name)
1041
      end
1042
      @available_filters[filter_id] = options.merge({
1043
               :name => filter_name,
1044
               :format => field.field_format,
1045
               :field => field
1046
             })
1047 1117
    end
1048 1118
  end
1049 1119

  
app/views/issues/_history.html.erb (working copy)
1 1
<% reply_links = authorize_for('issues', 'edit') -%>
2 2
<% for journal in journals %>
3
  <div id="change-<%= journal.id %>" class="<%= journal.css_classes %>">
4
    <div id="note-<%= journal.indice %>">
5
    <h4><%= link_to "##{journal.indice}", {:anchor => "note-#{journal.indice}"}, :class => "journal-link" %>
6
    <%= avatar(journal.user, :size => "24") %>
7
    <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %></h4>
8

  
9
    <% if journal.details.any? %>
10
    <ul class="details">
11
      <% details_to_strings(journal.details).each do |string| %>
12
       <li><%= string %></li>
3
  <% if details_to_strings(journal.details).any? || journal.notes.blank? == false %>
4
    <div id="change-<%= journal.id %>" class="<%= journal.css_classes %>">
5
      <div id="note-<%= journal.indice %>">
6
      <h4><%= link_to "##{journal.indice}", {:anchor => "note-#{journal.indice}"}, :class => "journal-link" %>
7
      <%= avatar(journal.user, :size => "24") %>
8
      <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %></h4>
9
  
10
      <% if journal.details.any? %>
11
      <ul class="details">
12
        <% details_to_strings(journal.details).each do |string| %>
13
         <li><%= string %></li>
14
        <% end %>
15
      </ul>
13 16
      <% end %>
14
    </ul>
15
    <% end %>
16
    <%= render_notes(issue, journal, :reply_links => reply_links) unless journal.notes.blank? %>
17
      <%= render_notes(issue, journal, :reply_links => reply_links) unless journal.notes.blank? %>
18
      </div>
17 19
    </div>
18
  </div>
19
  <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %>
20
    <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %>
21
  <% end %>
20 22
<% end %>
21 23

  
22 24
<% heads_for_wiki_formatter if User.current.allowed_to?(:edit_issue_notes, issue.project) || User.current.allowed_to?(:edit_own_issue_notes, issue.project) %>
app/views/issues/show.html.erb (working copy)
33 33

  
34 34
<table class="attributes">
35 35
<%= issue_fields_rows do |rows|
36
  rows.left l(:field_status), h(@issue.status.name), :class => 'status'
37
  rows.left l(:field_priority), h(@issue.priority.name), :class => 'priority'
36
  unless @issue.hidden_attribute?('status')
37
    rows.left l(:field_status), h(@issue.status.name), :class => 'status'
38
  end
39
  unless @issue.hidden_attribute?('priority')
40
    rows.left l(:field_priority), h(@issue.priority.name), :class => 'priority'
41
  end
38 42

  
39
  unless @issue.disabled_core_fields.include?('assigned_to_id')
43
  unless @issue.disabled_core_fields.include?('assigned_to_id') || @issue.hidden_attribute?('assigned_to_id')
40 44
    rows.left l(:field_assigned_to), avatar(@issue.assigned_to, :size => "14").to_s.html_safe + (@issue.assigned_to ? link_to_user(@issue.assigned_to) : "-"), :class => 'assigned-to'
41 45
  end
42
  unless @issue.disabled_core_fields.include?('category_id')
46
  unless @issue.disabled_core_fields.include?('category_id') || @issue.hidden_attribute?('category_id')
43 47
    rows.left l(:field_category), h(@issue.category ? @issue.category.name : "-"), :class => 'category'
44 48
  end
45
  unless @issue.disabled_core_fields.include?('fixed_version_id')
49
  unless @issue.disabled_core_fields.include?('fixed_version_id') || @issue.hidden_attribute?('fixed_version_id')
46 50
    rows.left l(:field_fixed_version), (@issue.fixed_version ? link_to_version(@issue.fixed_version) : "-"), :class => 'fixed-version'
47 51
  end
48 52

  
49
  unless @issue.disabled_core_fields.include?('start_date')
53
  unless @issue.disabled_core_fields.include?('start_date') || @issue.hidden_attribute?('start_date')
50 54
    rows.right l(:field_start_date), format_date(@issue.start_date), :class => 'start-date'
51 55
  end
52
  unless @issue.disabled_core_fields.include?('due_date')
56
  unless @issue.disabled_core_fields.include?('due_date') || @issue.hidden_attribute?('due_date')
53 57
    rows.right l(:field_due_date), format_date(@issue.due_date), :class => 'due-date'
54 58
  end
55
  unless @issue.disabled_core_fields.include?('done_ratio')
59
  unless @issue.disabled_core_fields.include?('done_ratio') || @issue.hidden_attribute?('done_ratio')
56 60
    rows.right l(:field_done_ratio), progress_bar(@issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%"), :class => 'progress'
57 61
  end
58
  unless @issue.disabled_core_fields.include?('estimated_hours')
62
  unless @issue.disabled_core_fields.include?('estimated_hours') || @issue.hidden_attribute?('estimated_hours')
59 63
    unless @issue.estimated_hours.nil?
60 64
      rows.right l(:field_estimated_hours), l_hours(@issue.estimated_hours), :class => 'estimated-hours'
61 65
    end
app/views/issues/_form_custom_fields.html.erb (working copy)
1 1
<div class="splitcontent">
2 2
<div class="splitcontentleft">
3 3
<% i = 0 %>
4
<% split_on = (@issue.custom_field_values.size / 2.0).ceil - 1 %>
4
<% split_on = (@issue.editable_custom_field_values.size / 2.0).ceil - 1 %>
5 5
<% @issue.editable_custom_field_values.each do |value| %>
6 6
  <p><%= custom_field_tag_with_label :issue, value, :required => @issue.required_attribute?(value.custom_field_id) %></p>
7 7
<% if i == split_on -%>
app/views/mailer/issue_edit.html.erb (working copy)
1 1
<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => h(@journal.user)) %>
2 2

  
3 3
<ul>
4
<% details_to_strings(@journal.details, false, :only_path => false).each do |string| %>
4
<% details_to_strings(@journal.details, false, :only_path => false, :user => @auser).each do |string| %>
5 5
  <li><%= string %></li>
6 6
<% end %>
7 7
</ul>
8 8

  
9 9
<%= textilizable(@journal, :notes, :only_path => false) %>
10 10
<hr />
11
<%= render :partial => 'issue', :formats => [:html], :locals => { :issue => @issue, :issue_url => @issue_url } %>
11
<%= render :partial => 'issue', :formats => [:html], :locals => { :issue => @issue, :issue_url => @issue_url, :user => @auser } %>
app/views/mailer/_issue.text.erb (working copy)
2 2
<%= issue_url %>
3 3

  
4 4
* <%=l(:field_author)%>: <%= issue.author %>
5
<% unless issue.hidden_attribute?('status', user) %>
5 6
* <%=l(:field_status)%>: <%= issue.status %>
7
<% end %>
8
<% unless issue.hidden_attribute?('priority', user) %>
6 9
* <%=l(:field_priority)%>: <%= issue.priority %>
10
<% end %>
11
<% unless issue.disabled_core_fields.include?('assigned_to_id') || issue.hidden_attribute?('assigned_to_id', user) %>
7 12
* <%=l(:field_assigned_to)%>: <%= issue.assigned_to %>
13
<% end %>
14
<% unless issue.disabled_core_fields.include?('category_id') || issue.hidden_attribute?('category_id', user) %>
8 15
* <%=l(:field_category)%>: <%= issue.category %>
16
<% end %>
17
<% unless issue.disabled_core_fields.include?('fixed_version_id') || issue.hidden_attribute?('fixed_version_id', user) %>
9 18
* <%=l(:field_fixed_version)%>: <%= issue.fixed_version %>
10
<% issue.custom_field_values.each do |c| %>* <%= c.custom_field.name %>: <%= show_value(c) %>
19
<% end %>
20
<% issue.custom_field_values.each do |c| %>
21
<% unless issue.hidden_attribute?(c.custom_field.id, user) %>
22
* <%= c.custom_field.name %>: <%= show_value(c) %>
23
<% end %>
11 24
<% end -%>
12 25
----------------------------------------
13 26
<%= issue.description %>
app/views/mailer/issue_add.text.erb (working copy)
1 1
<%= l(:text_issue_added, :id => "##{@issue.id}", :author => @issue.author) %>
2 2

  
3 3
----------------------------------------
4
<%= render :partial => 'issue', :formats => [:text], :locals => { :issue => @issue, :issue_url => @issue_url } %>
4
<%= render :partial => 'issue', :formats => [:text], :locals => { :issue => @issue, :issue_url => @issue_url, :user => @auser } %>
app/views/mailer/_issue.html.erb (working copy)
2 2

  
3 3
<ul>
4 4
<li><%=l(:field_author)%>: <%=h issue.author %></li>
5
<li><%=l(:field_status)%>: <%=h issue.status %></li>
6
<li><%=l(:field_priority)%>: <%=h issue.priority %></li>
7
<li><%=l(:field_assigned_to)%>: <%=h issue.assigned_to %></li>
8
<li><%=l(:field_category)%>: <%=h issue.category %></li>
9
<li><%=l(:field_fixed_version)%>: <%=h issue.fixed_version %></li>
5
<% unless issue.hidden_attribute?('status', user) %>
6
  <li><%=l(:field_status)%>: <%=h issue.status %></li>
7
<% end %>
8
<% unless issue.hidden_attribute?('priority', user) %>
9
  <li><%=l(:field_priority)%>: <%=h issue.priority %></li>
10
<% end %>
11
<% unless issue.disabled_core_fields.include?('assigned_to_id') || issue.hidden_attribute?('assigned_to_id', user) %>
12
  <li><%=l(:field_assigned_to)%>: <%=h issue.assigned_to %></li>
13
<% end %>
14
<% unless issue.disabled_core_fields.include?('category_id') || issue.hidden_attribute?('category_id', user) %>
15
  <li><%=l(:field_category)%>: <%=h issue.category %></li>
16
<% end %>
17
<% unless issue.disabled_core_fields.include?('fixed_version_id') || issue.hidden_attribute?('fixed_version_id', user) %>
18
  <li><%=l(:field_fixed_version)%>: <%=h issue.fixed_version %></li>
19
<% end %>
10 20
<% issue.custom_field_values.each do |c| %>
11
  <li><%=h c.custom_field.name %>: <%=h show_value(c) %></li>
21
  <% unless issue.hidden_attribute?(c.custom_field.id, user) %>
22
    <li><%=h c.custom_field.name %>: <%=h show_value(c) %></li>
23
  <% end %>
12 24
<% end %>
13 25
</ul>
14 26

  
app/views/mailer/issue_add.html.erb (working copy)
1 1
<%= l(:text_issue_added, :id => "##{@issue.id}", :author => h(@issue.author)) %>
2 2
<hr />
3
<%= render :partial => 'issue', :formats => [:html], :locals => { :issue => @issue, :issue_url => @issue_url } %>
3
<%= render :partial => 'issue', :formats => [:html], :locals => { :issue => @issue, :issue_url => @issue_url, :user => @auser } %>
app/views/mailer/issue_edit.text.erb (working copy)
1 1
<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => @journal.user) %>
2 2

  
3
<% details_to_strings(@journal.details, true).each do |string| -%>
3
<% details_to_strings(@journal.details, true, :user => @auser).each do |string| -%>
4 4
<%= string %>
5 5
<% end -%>
6 6

  
......
9 9

  
10 10
<% end -%>
11 11
----------------------------------------
12
<%= render :partial => 'issue', :formats => [:text], :locals => { :issue => @issue, :issue_url => @issue_url } %>
12
<%= render :partial => 'issue', :formats => [:text], :locals => { :issue => @issue, :issue_url => @issue_url, :user => @auser } %>
lib/plugins/acts_as_watchable/lib/acts_as_watchable.rb (working copy)
81 81
          notified_watchers.collect(&:mail)
82 82
        end
83 83

  
84
        # Returns an array of watchers
85
        def watcher_recipient_users
86
          notified = watcher_users.active
87
          notified.reject! {|user| user.mail_notification == 'none'}
88

  
89
          if respond_to?(:visible?)
90
            notified.reject! {|user| !visible?(user)}
91
          end
92
          notified
93
        end
94

  
84 95
        module ClassMethods; end
85 96
      end
86 97
    end
lib/redmine/export/pdf.rb (working copy)
520 520
        pdf.Ln
521 521

  
522 522
        left = []
523
        left << [l(:field_status), issue.status]
524
        left << [l(:field_priority), issue.priority]
525
        left << [l(:field_assigned_to), issue.assigned_to] unless issue.disabled_core_fields.include?('assigned_to_id')
526
        left << [l(:field_category), issue.category] unless issue.disabled_core_fields.include?('category_id')
527
        left << [l(:field_fixed_version), issue.fixed_version] unless issue.disabled_core_fields.include?('fixed_version_id')
523
        left << [l(:field_status), issue.status] unless issue.hidden_attribute?('status')
524
        left << [l(:field_priority), issue.priority] unless issue.hidden_attribute?('priority')
525
        left << [l(:field_assigned_to), issue.assigned_to] unless issue.disabled_core_fields.include?('assigned_to_id') or issue.hidden_attribute?('assigned_to_id')
526
        left << [l(:field_category), issue.category] unless issue.disabled_core_fields.include?('category_id') or issue.hidden_attribute?('category_id')
527
        left << [l(:field_fixed_version), issue.fixed_version] unless issue.disabled_core_fields.include?('fixed_version_id') or issue.hidden_attribute?('fixed_version_id')
528 528

  
529 529
        right = []
530
        right << [l(:field_start_date), format_date(issue.start_date)] unless issue.disabled_core_fields.include?('start_date')
531
        right << [l(:field_due_date), format_date(issue.due_date)] unless issue.disabled_core_fields.include?('due_date')
532
        right << [l(:field_done_ratio), "#{issue.done_ratio}%"] unless issue.disabled_core_fields.include?('done_ratio')
533
        right << [l(:field_estimated_hours), l_hours(issue.estimated_hours)] unless issue.disabled_core_fields.include?('estimated_hours')
530
        right << [l(:field_start_date), format_date(issue.start_date)] unless issue.disabled_core_fields.include?('start_date') or issue.hidden_attribute?('start_date')
531
        right << [l(:field_due_date), format_date(issue.due_date)] unless issue.disabled_core_fields.include?('due_date') or issue.hidden_attribute?('due_date')
532
        right << [l(:field_done_ratio), "#{issue.done_ratio}%"] unless issue.disabled_core_fields.include?('done_ratio') or issue.hidden_attribute?('done_ratio')
533
        right << [l(:field_estimated_hours), l_hours(issue.estimated_hours)] unless issue.disabled_core_fields.include?('estimated_hours') or issue.hidden_attribute?('estimated_hours')
534 534
        right << [l(:label_spent_time), l_hours(issue.total_spent_hours)] if User.current.allowed_to?(:view_time_entries, issue.project)
535 535

  
536 536
        rows = left.size > right.size ? left.size : right.size
......
541 541
          right << nil
542 542
        end
543 543

  
544
        half = (issue.custom_field_values.size / 2.0).ceil
545
        issue.custom_field_values.each_with_index do |custom_value, i|
546
          (i < half ? left : right) << [custom_value.custom_field.name, show_value(custom_value)]
544
        half = (issue.viewable_custom_field_values.size / 2.0).ceil
545
        issue.viewable_custom_field_values.each_with_index do |custom_value, i|
546
          (i < half ? left : right) << [custom_value.custom_field.name, show_value(custom_value)] unless issue.hidden_attribute?(custom_value.custom_field.name)
547 547
        end
548 548

  
549 549
        rows = left.size > right.size ? left.size : right.size
(11-11/13)