Feature #12005 » workflow_hidden_fields_redmine2.4_v1.0.patch
app/helpers/issues_helper.rb (working copy) | ||
---|---|---|
160 | 160 |
end |
161 | 161 | |
162 | 162 |
def render_custom_fields_rows(issue) |
163 |
values = issue.visible_custom_field_values
|
|
163 |
values = issue.viewable_custom_field_values
|
|
164 | 164 |
return if values.empty? |
165 | 165 |
ordered_values = [] |
166 | 166 |
half = (values.size / 2.0).ceil |
... | ... | |
260 | 260 |
strings = [] |
261 | 261 |
values_by_field = {} |
262 | 262 |
details.each do |detail| |
263 |
unless detail.journal.issue.hidden_attribute?(detail.prop_key, options[:user]) |
|
263 | 264 |
if detail.property == 'cf' |
264 | 265 |
field = detail.custom_field |
265 | 266 |
if field && field.multiple? |
... | ... | |
274 | 275 |
end |
275 | 276 |
end |
276 | 277 |
strings << show_detail(detail, no_html, options) |
278 |
end |
|
277 | 279 |
end |
278 | 280 |
values_by_field.each do |field, changes| |
279 | 281 |
detail = JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s) |
280 |
detail.instance_variable_set "@custom_field", field |
|
281 |
if changes[:added].any? |
|
282 |
detail.value = changes[:added] |
|
283 |
strings << show_detail(detail, no_html, options) |
|
284 |
elsif changes[:deleted].any? |
|
285 |
detail.old_value = changes[:deleted] |
|
286 |
strings << show_detail(detail, no_html, options) |
|
282 |
unless ( detail.journal != nil && detail.journal.issue.hidden_attribute?(detail.prop_key, options[:user])) |
|
283 |
detail.instance_variable_set "@custom_field", field |
|
284 |
if changes[:added].any? |
|
285 |
detail.value = changes[:added] |
|
286 |
strings << show_detail(detail, no_html, options) |
|
287 |
elsif changes[:deleted].any? |
|
288 |
detail.old_value = changes[:deleted] |
|
289 |
strings << show_detail(detail, no_html, options) |
|
290 |
end |
|
287 | 291 |
end |
288 | 292 |
end |
289 | 293 |
strings |
app/helpers/workflows_helper.rb (working copy) | ||
---|---|---|
25 | 25 |
def field_permission_tag(permissions, status, field, role) |
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"] unless field_required?(field) |
|
28 | 29 |
options << [l(:label_required), "required"] unless field_required?(field) |
29 | 30 |
html_options = {} |
30 | 31 |
selected = permissions[status.id][name] |
app/models/project.rb (working copy) | ||
---|---|---|
152 | 152 |
user.allowed_to?(:view_project, self) |
153 | 153 |
end |
154 | 154 | |
155 |
# Returns list of attributes that are hidden on all statuses of all trackers for +user+ or the current user. |
|
156 |
def completely_hidden_attribute_names(user=nil) |
|
157 |
user_real = user || User.current |
|
158 |
roles = user_real.admin ? Role.all : user_real.roles_for_project(self) |
|
159 |
return {} if roles.empty? |
|
160 | ||
161 |
result = {} |
|
162 |
workflow_permissions = WorkflowPermission.where(:tracker_id => trackers.map(&:id), :old_status_id => IssueStatus.all.map(&:id), :role_id => roles.map(&:id), :rule => 'hidden').all |
|
163 | ||
164 |
if workflow_permissions.any? |
|
165 |
workflow_rules = workflow_permissions.inject({}) do |h, wp| |
|
166 |
h[wp.field_name] ||= [] |
|
167 |
h[wp.field_name] << wp.rule |
|
168 |
h |
|
169 |
end |
|
170 |
workflow_rules.each do |attr, rules| |
|
171 |
next if rules.size < (roles.size * trackers.size * IssueStatus.all.size) |
|
172 |
uniq_rules = rules.uniq |
|
173 |
if uniq_rules.size == 1 |
|
174 |
result[attr] = uniq_rules.first |
|
175 |
else |
|
176 |
result[attr] = 'required' |
|
177 |
end |
|
178 |
end |
|
179 |
end |
|
180 | ||
181 |
result.keys |
|
182 |
end |
|
183 | ||
184 | ||
155 | 185 |
# Returns a SQL conditions string used to find all projects visible by the specified user. |
156 | 186 |
# |
157 | 187 |
# Examples: |
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/issue.rb (working copy) | ||
---|---|---|
483 | 483 |
end |
484 | 484 |
end |
485 | 485 | |
486 |
# Returns the custom_field_values that can be viewed by the given user, also always excludes Fix Info, RNs and TAT, as it is printed separately below description. |
|
487 |
def viewable_custom_field_values(user=nil) |
|
488 |
custom_field_values.reject do |value| |
|
489 |
hidden_attribute_names(user).include?(value.custom_field_id.to_s) |
|
490 |
end |
|
491 |
end |
|
492 | ||
486 | 493 |
# Returns the names of attributes that are read-only for user or the current user |
487 | 494 |
# For users with multiple roles, the read-only fields are the intersection of |
488 | 495 |
# read-only fields of each role |
489 |
# The result is an array of strings where sustom fields are represented with their ids
|
|
496 |
# The result is an array of strings where custom fields are represented with their ids
|
|
490 | 497 |
# |
491 | 498 |
# Examples: |
492 | 499 |
# issue.read_only_attribute_names # => ['due_date', '2'] |
493 | 500 |
# issue.read_only_attribute_names(user) # => [] |
494 | 501 |
def read_only_attribute_names(user=nil) |
495 |
workflow_rule_by_attribute(user).reject {|attr, rule| rule != 'readonly'}.keys |
|
502 |
workflow_rule_by_attribute(user).reject {|attr, rule| rule != 'readonly' && rule != 'hidden' }.keys
|
|
496 | 503 |
end |
497 | 504 | |
505 |
# Same as above, return the names of attributes that are hidden for user or the current user |
|
506 |
def hidden_attribute_names(user=nil) |
|
507 |
workflow_rule_by_attribute(user).reject {|attr, rule| rule != 'hidden'}.keys |
|
508 |
end |
|
509 | ||
498 | 510 |
# Returns the names of required attributes for user or the current user |
499 | 511 |
# For users with multiple roles, the required fields are the intersection of |
500 | 512 |
# required fields of each role |
... | ... | |
512 | 524 |
required_attribute_names(user).include?(name.to_s) |
513 | 525 |
end |
514 | 526 | |
527 |
# Returns true if the attribute should be hidden for user |
|
528 |
def hidden_attribute?(name, user=nil) |
|
529 |
hidden_attribute_names(user).include?(name.to_s) |
|
530 |
end |
|
531 | ||
532 | ||
515 | 533 |
# Returns a hash of the workflow rule by attribute for the given user |
516 | 534 |
# |
517 | 535 |
# Examples: |
app/views/mailer/_issue.text.erb (working copy) | ||
---|---|---|
1 | 1 |
<%= "#{issue.tracker.name} ##{issue.id}: #{issue.subject}" %> |
2 | 2 |
<%= issue_url %> |
3 | 3 | |
4 |
<%= render_email_issue_attributes(issue, users.first) %> |
|
4 |
* <%=l(:field_author)%>: <%= issue.author %> |
|
5 |
<% unless issue.hidden_attribute?('status', user) %> |
|
6 |
* <%=l(:field_status)%>: <%= issue.status %> |
|
7 |
<% end %> |
|
8 |
<% unless issue.hidden_attribute?('priority', user) %> |
|
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) %> |
|
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) %> |
|
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) %> |
|
18 |
* <%=l(:field_fixed_version)%>: <%= issue.fixed_version %> |
|
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 %> |
|
24 |
<% end -%> |
|
5 | 25 |
---------------------------------------- |
6 | 26 |
<%= issue.description %> |
7 | 27 |
app/views/mailer/_issue.html.erb (working copy) | ||
---|---|---|
1 | 1 |
<h1><%= link_to(h("#{issue.tracker.name} ##{issue.id}: #{issue.subject}"), issue_url) %></h1> |
2 | 2 | |
3 |
<%= render_email_issue_attributes(issue, users.first, true) %> |
|
3 |
<ul> |
|
4 |
<li><%=l(:field_author)%>: <%=h issue.author %></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 %> |
|
20 |
<% issue.custom_field_values.each do |c| %> |
|
21 |
<% unless issue.hidden_attribute?(c.custom_field.id, user) %> |
|
22 |
<li><%=h c.custom_field.name %>: <%=h show_value(c) %></li> |
|
23 |
<% end %> |
|
24 |
<% end %> |
|
25 |
</ul> |
|
4 | 26 | |
5 | 27 |
<%= textilizable(issue, :description, :only_path => false) %> |
6 | 28 |
app/views/issues/show.html.erb (working copy) | ||
---|---|---|
33 | 33 | |
34 | 34 |
<table class="attributes"> |
35 | 35 |
<%= issue_fields_rows do |rows| |
36 |
unless @issue.hidden_attribute?('status') |
|
36 | 37 |
rows.left l(:field_status), h(@issue.status.name), :class => 'status' |
38 |
end |
|
39 |
unless @issue.hidden_attribute?('priority_id') |
|
37 | 40 |
rows.left l(:field_priority), h(@issue.priority.name), :class => 'priority' |
38 | 41 | |
39 |
unless @issue.disabled_core_fields.include?('assigned_to_id') |
|
42 |
unless @issue.disabled_core_fields.include?('assigned_to_id') || @issue.hidden_attribute?('assigned_to_id')
|
|
40 | 43 |
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 | 44 |
end |
42 |
unless @issue.disabled_core_fields.include?('category_id') |
|
45 |
unless @issue.disabled_core_fields.include?('category_id') || @issue.hidden_attribute?('category_id')
|
|
43 | 46 |
rows.left l(:field_category), h(@issue.category ? @issue.category.name : "-"), :class => 'category' |
44 | 47 |
end |
45 |
unless @issue.disabled_core_fields.include?('fixed_version_id') |
|
48 |
unless @issue.disabled_core_fields.include?('fixed_version_id') || @issue.hidden_attribute?('fixed_version_id')
|
|
46 | 49 |
rows.left l(:field_fixed_version), (@issue.fixed_version ? link_to_version(@issue.fixed_version) : "-"), :class => 'fixed-version' |
47 | 50 |
end |
48 | 51 | |
49 |
unless @issue.disabled_core_fields.include?('start_date') |
|
52 |
unless @issue.disabled_core_fields.include?('start_date') || @issue.hidden_attribute?('start_date')
|
|
50 | 53 |
rows.right l(:field_start_date), format_date(@issue.start_date), :class => 'start-date' |
51 | 54 |
end |
52 |
unless @issue.disabled_core_fields.include?('due_date') |
|
55 |
unless @issue.disabled_core_fields.include?('due_date') || @issue.hidden_attribute?('due_date')
|
|
53 | 56 |
rows.right l(:field_due_date), format_date(@issue.due_date), :class => 'due-date' |
54 | 57 |
end |
55 |
unless @issue.disabled_core_fields.include?('done_ratio') |
|
58 |
unless @issue.disabled_core_fields.include?('done_ratio') || @issue.hidden_attribute?('done_ratio')
|
|
56 | 59 |
rows.right l(:field_done_ratio), progress_bar(@issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%"), :class => 'progress' |
57 | 60 |
end |
58 |
unless @issue.disabled_core_fields.include?('estimated_hours') |
|
61 |
unless @issue.disabled_core_fields.include?('estimated_hours') || @issue.hidden_attribute?('estimated_hours')
|
|
59 | 62 |
unless @issue.estimated_hours.nil? |
60 | 63 |
rows.right l(:field_estimated_hours), l_hours(@issue.estimated_hours), :class => 'estimated-hours' |
61 | 64 |
end |
config/locales/en.yml (working copy) | ||
---|---|---|
888 | 888 |
label_fields_permissions: Fields permissions |
889 | 889 |
label_readonly: Read-only |
890 | 890 |
label_required: Required |
891 |
label_hidden: Hidden
|
|
891 |
label_hidden: " Hidden "
|
|
892 | 892 |
label_attribute_of_project: "Project's %{name}" |
893 | 893 |
label_attribute_of_issue: "Issue's %{name}" |
894 | 894 |
label_attribute_of_author: "Author's %{name}" |
lib/redmine/export/pdf.rb (working copy) | ||
---|---|---|
550 | 550 |
pdf.Ln |
551 | 551 | |
552 | 552 |
left = [] |
553 |
left << [l(:field_status), issue.status] |
|
554 |
left << [l(:field_priority), issue.priority] |
|
555 |
left << [l(:field_assigned_to), issue.assigned_to] unless issue.disabled_core_fields.include?('assigned_to_id') |
|
556 |
left << [l(:field_category), issue.category] unless issue.disabled_core_fields.include?('category_id') |
|
557 |
left << [l(:field_fixed_version), issue.fixed_version] unless issue.disabled_core_fields.include?('fixed_version_id') |
|
553 |
left << [l(:field_status), issue.status] unless issue.hidden_attribute?('status')
|
|
554 |
left << [l(:field_priority), issue.priority] unless issue.hidden_attribute?('priority_id')
|
|
555 |
left << [l(:field_assigned_to), issue.assigned_to] unless issue.disabled_core_fields.include?('assigned_to_id') or issue.hidden_attribute?('assigned_to_id')
|
|
556 |
left << [l(:field_category), issue.category] unless issue.disabled_core_fields.include?('category_id') or issue.hidden_attribute?('category_id')
|
|
557 |
left << [l(:field_fixed_version), issue.fixed_version] unless issue.disabled_core_fields.include?('fixed_version_id') or issue.hidden_attribute?('fixed_version_id')
|
|
558 | 558 | |
559 | 559 |
right = [] |
560 |
right << [l(:field_start_date), format_date(issue.start_date)] unless issue.disabled_core_fields.include?('start_date') |
|
561 |
right << [l(:field_due_date), format_date(issue.due_date)] unless issue.disabled_core_fields.include?('due_date') |
|
562 |
right << [l(:field_done_ratio), "#{issue.done_ratio}%"] unless issue.disabled_core_fields.include?('done_ratio') |
|
563 |
right << [l(:field_estimated_hours), l_hours(issue.estimated_hours)] unless issue.disabled_core_fields.include?('estimated_hours') |
|
560 |
right << [l(:field_start_date), format_date(issue.start_date)] unless issue.disabled_core_fields.include?('start_date') or issue.hidden_attribute?('start_date')
|
|
561 |
right << [l(:field_due_date), format_date(issue.due_date)] unless issue.disabled_core_fields.include?('due_date') or issue.hidden_attribute?('due_date')
|
|
562 |
right << [l(:field_done_ratio), "#{issue.done_ratio}%"] unless issue.disabled_core_fields.include?('done_ratio') or issue.hidden_attribute?('done_ratio')
|
|
563 |
right << [l(:field_estimated_hours), l_hours(issue.estimated_hours)] unless issue.disabled_core_fields.include?('estimated_hours') or issue.hidden_attribute?('estimated_hours')
|
|
564 | 564 |
right << [l(:label_spent_time), l_hours(issue.total_spent_hours)] if User.current.allowed_to?(:view_time_entries, issue.project) |
565 | 565 | |
566 | 566 |
rows = left.size > right.size ? left.size : right.size |