diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2016-06-06 09:41:50 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2016-06-06 09:41:50 +0000 |
commit | 6e68d008c4dc50f46585e30aabaa5bc9859bee0f (patch) | |
tree | dddbcaecd80051789282556982fad7270c2e5b9d /app | |
parent | 7a974437e6414682d6b318a3b1130d728f51907a (diff) | |
download | redmine-6e68d008c4dc50f46585e30aabaa5bc9859bee0f.tar.gz redmine-6e68d008c4dc50f46585e30aabaa5bc9859bee0f.zip |
Merged 15430, 15464 to 15469, 15475, 15476 (#285, #7839).
git-svn-id: http://svn.redmine.org/redmine/branches/3.3-stable@15478 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/context_menus_controller.rb | 7 | ||||
-rw-r--r-- | app/controllers/issues_controller.rb | 21 | ||||
-rw-r--r-- | app/helpers/issues_helper.rb | 10 | ||||
-rw-r--r-- | app/models/issue.rb | 98 | ||||
-rw-r--r-- | app/models/issue_import.rb | 2 | ||||
-rw-r--r-- | app/models/mail_handler.rb | 13 | ||||
-rw-r--r-- | app/models/role.rb | 51 | ||||
-rw-r--r-- | app/views/issues/_action_menu.html.erb | 2 | ||||
-rw-r--r-- | app/views/issues/_edit.html.erb | 29 | ||||
-rw-r--r-- | app/views/issues/_form.html.erb | 2 | ||||
-rw-r--r-- | app/views/issues/_history.html.erb | 2 | ||||
-rw-r--r-- | app/views/issues/index.html.erb | 2 | ||||
-rw-r--r-- | app/views/issues/show.html.erb | 2 | ||||
-rw-r--r-- | app/views/roles/_form.html.erb | 61 |
14 files changed, 238 insertions, 64 deletions
diff --git a/app/controllers/context_menus_controller.rb b/app/controllers/context_menus_controller.rb index 1e5652d09..66ec35085 100644 --- a/app/controllers/context_menus_controller.rb +++ b/app/controllers/context_menus_controller.rb @@ -29,11 +29,11 @@ class ContextMenusController < ApplicationController @allowed_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&) - @can = {:edit => User.current.allowed_to?(:edit_issues, @projects), + @can = {:edit => @issues.all?(&:attributes_editable?), :log_time => (@project && User.current.allowed_to?(:log_time, @project)), :copy => User.current.allowed_to?(:copy_issues, @projects) && Issue.allowed_target_projects.any?, :add_watchers => User.current.allowed_to?(:add_issue_watchers, @projects), - :delete => User.current.allowed_to?(:delete_issues, @projects) + :delete => @issues.all?(&:deletable?) } if @project if @issue @@ -41,12 +41,11 @@ class ContextMenusController < ApplicationController else @assignables = @project.assignable_users end - @trackers = @project.trackers else #when multiple projects, we only keep the intersection of each set @assignables = @projects.map(&:assignable_users).reduce(:&) - @trackers = @projects.map(&:trackers).reduce(:&) end + @trackers = @projects.map {|p| Issue.allowed_target_trackers(p) }.reduce(:&) @versions = @projects.map {|p| p.shared_versions.open}.reduce(:&) @priorities = IssuePriority.active.reverse diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index cf402de22..67956667a 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -211,6 +211,10 @@ class IssuesController < ApplicationController unless User.current.allowed_to?(:copy_issues, @projects) raise ::Unauthorized end + else + unless @issues.all?(&:attributes_editable?) + raise ::Unauthorized + end end @allowed_projects = Issue.allowed_target_projects @@ -230,7 +234,7 @@ class IssuesController < ApplicationController end @custom_fields = @issues.map{|i|i.editable_custom_fields}.reduce(:&) @assignables = target_projects.map(&:assignable_users).reduce(:&) - @trackers = target_projects.map(&:trackers).reduce(:&) + @trackers = target_projects.map {|p| Issue.allowed_target_trackers(p) }.reduce(:&) @versions = target_projects.map {|p| p.shared_versions.open}.reduce(:&) @categories = target_projects.map {|p| p.issue_categories}.reduce(:&) if @copy @@ -263,6 +267,10 @@ class IssuesController < ApplicationController unless User.current.allowed_to?(:add_issues, target_projects) raise ::Unauthorized end + else + unless @issues.all?(&:attributes_editable?) + raise ::Unauthorized + end end unsaved_issues = [] @@ -316,6 +324,7 @@ class IssuesController < ApplicationController end def destroy + raise Unauthorized unless @issues.all?(&:deletable?) @hours = TimeEntry.where(:issue_id => @issues.map(&:id)).sum(:hours).to_f if @hours > 0 case params[:todo] @@ -465,9 +474,15 @@ class IssuesController < ApplicationController @issue.safe_attributes = attrs if @issue.project - @issue.tracker ||= @issue.project.trackers.first + @issue.tracker ||= @issue.allowed_target_trackers.first if @issue.tracker.nil? - render_error l(:error_no_tracker_in_project) + if @issue.project.trackers.any? + # None of the project trackers is allowed to the user + render_error :message => l(:error_no_tracker_allowed_for_new_issue_in_project), :status => 403 + else + # Project has no trackers + render_error l(:error_no_tracker_in_project) + end return false end if @issue.status.nil? diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index b505765d8..ce6d9f8f2 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -168,6 +168,16 @@ module IssuesHelper link_to(l(:button_add), new_project_issue_path(issue.project, :issue => attrs)) end + def trackers_options_for_select(issue) + trackers = issue.allowed_target_trackers + if issue.new_record? && issue.parent_issue_id.present? + trackers = trackers.reject do |tracker| + issue.tracker_id != tracker.id && tracker.disabled_core_fields.include?('parent_issue_id') + end + end + trackers.collect {|t| [t.name, t.id]} + end + class IssueFieldsRows include ActionView::Helpers::TagHelper diff --git a/app/models/issue.rb b/app/models/issue.rb index 0ee8ff3d3..e0b99e4e6 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -120,10 +120,10 @@ class Issue < ActiveRecord::Base # Returns a SQL conditions string used to find all issues visible by the specified user def self.visible_condition(user, options={}) Project.allowed_to_condition(user, :view_issues, options) do |role, user| - if user.id && user.logged? + sql = if user.id && user.logged? case role.issues_visibility when 'all' - nil + '1=1' when 'default' user_ids = [user.id] + user.groups.map(&:id).compact "(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))" @@ -136,13 +136,22 @@ class Issue < ActiveRecord::Base else "(#{table_name}.is_private = #{connection.quoted_false})" end + unless role.permissions_all_trackers?(:view_issues) + tracker_ids = role.permissions_tracker_ids(:view_issues) + if tracker_ids.any? + sql = "(#{sql} AND #{table_name}.tracker_id IN (#{tracker_ids.join(',')}))" + else + sql = '1=0' + end + end + sql end end # Returns true if usr or current user is allowed to view the issue def visible?(usr=nil) (usr || User.current).allowed_to?(:view_issues, self.project) do |role, user| - if user.logged? + visible = if user.logged? case role.issues_visibility when 'all' true @@ -156,17 +165,36 @@ class Issue < ActiveRecord::Base else !self.is_private? end + unless role.permissions_all_trackers?(:view_issues) + visible &&= role.permissions_tracker_ids?(:view_issues, tracker_id) + end + visible end end - # Returns true if user or current user is allowed to edit or add a note to the issue + # Returns true if user or current user is allowed to edit or add notes to the issue def editable?(user=User.current) - attributes_editable?(user) || user.allowed_to?(:add_issue_notes, project) + attributes_editable?(user) || notes_addable?(user) end # Returns true if user or current user is allowed to edit the issue def attributes_editable?(user=User.current) - user.allowed_to?(:edit_issues, project) + user_tracker_permission?(user, :edit_issues) + end + + # Overrides Redmine::Acts::Attachable::InstanceMethods#attachments_editable? + def attachments_editable?(user=User.current) + attributes_editable?(user) + end + + # Returns true if user or current user is allowed to add notes to the issue + def notes_addable?(user=User.current) + user_tracker_permission?(user, :add_issue_notes) + end + + # Returns true if user or current user is allowed to delete the issue + def deletable?(user=User.current) + user_tracker_permission?(user, :delete_issues) end def initialize(attributes=nil, *args) @@ -416,10 +444,10 @@ class Issue < ActiveRecord::Base 'custom_fields', 'lock_version', 'notes', - :if => lambda {|issue, user| issue.new_record? || user.allowed_to?(:edit_issues, issue.project) } + :if => lambda {|issue, user| issue.new_record? || issue.attributes_editable?(user) } safe_attributes 'notes', - :if => lambda {|issue, user| user.allowed_to?(:add_issue_notes, issue.project)} + :if => lambda {|issue, user| issue.notes_addable?(user)} safe_attributes 'private_notes', :if => lambda {|issue, user| !issue.new_record? && user.allowed_to?(:set_notes_private, issue.project)} @@ -434,7 +462,7 @@ class Issue < ActiveRecord::Base } safe_attributes 'parent_issue_id', - :if => lambda {|issue, user| (issue.new_record? || user.allowed_to?(:edit_issues, issue.project)) && + :if => lambda {|issue, user| (issue.new_record? || issue.attributes_editable?(user)) && user.allowed_to?(:manage_subtasks, issue.project)} def safe_attribute_names(user=nil) @@ -479,12 +507,14 @@ class Issue < ActiveRecord::Base end if (t = attrs.delete('tracker_id')) && safe_attribute?('tracker_id') - self.tracker_id = t + if allowed_target_trackers(user).where(:id => t.to_i).exists? + self.tracker_id = t + end end if project - # Set the default tracker to accept custom field values + # Set a default tracker to accept custom field values # even if tracker is not specified - self.tracker ||= project.trackers.first + self.tracker ||= allowed_target_trackers(user).first end statuses_allowed = new_statuses_allowed_to(user) @@ -822,16 +852,6 @@ class Issue < ActiveRecord::Base !leaf? end - def assignable_trackers - trackers = project.trackers - if new_record? && parent_issue_id.present? - trackers = trackers.reject do |tracker| - tracker_id != tracker.id && tracker.disabled_core_fields.include?('parent_issue_id') - end - end - trackers - end - # Users the issue can be assigned to def assignable_users users = project.assignable_users.to_a @@ -1373,9 +1393,43 @@ class Issue < ActiveRecord::Base end Project.where(condition).having_trackers end + + # Returns a scope of trackers that user can assign the issue to + def allowed_target_trackers(user=User.current) + self.class.allowed_target_trackers(project, user, tracker_id_was) + end + + # Returns a scope of trackers that user can assign project issues to + def self.allowed_target_trackers(project, user=User.current, current_tracker=nil) + if project + scope = project.trackers.sorted + unless user.admin? + roles = user.roles_for_project(project).select {|r| r.has_permission?(:add_issues)} + unless roles.any? {|r| r.permissions_all_trackers?(:add_issues)} + tracker_ids = roles.map {|r| r.permissions_tracker_ids(:add_issues)}.flatten.uniq + if current_tracker + tracker_ids << current_tracker + end + scope = scope.where(:id => tracker_ids) + end + end + scope + else + Tracker.none + end + end private + def user_tracker_permission?(user, permission) + if user.admin? + true + else + roles = user.roles_for_project(project).select {|r| r.has_permission?(permission)} + roles.any? {|r| r.permissions_all_trackers?(permission) || r.permissions_tracker_ids?(permission, tracker_id)} + end + end + def after_project_change # Update project_id on related time entries TimeEntry.where({:issue_id => id}).update_all(["project_id = ?", project_id]) diff --git a/app/models/issue_import.rb b/app/models/issue_import.rb index b6b20a1b1..5b19ac966 100644 --- a/app/models/issue_import.rb +++ b/app/models/issue_import.rb @@ -37,7 +37,7 @@ class IssueImport < Import # Returns a scope of trackers that user is allowed to # import issue to def allowed_target_trackers - project.trackers + Issue.allowed_target_trackers(project, user) end def tracker diff --git a/app/models/mail_handler.rb b/app/models/mail_handler.rb index 40bd02a07..a619f115d 100644 --- a/app/models/mail_handler.rb +++ b/app/models/mail_handler.rb @@ -199,7 +199,14 @@ class MailHandler < ActionMailer::Base end issue = Issue.new(:author => user, :project => project) - issue.safe_attributes = issue_attributes_from_keywords(issue) + attributes = issue_attributes_from_keywords(issue) + if handler_options[:no_permission_check] + issue.tracker_id = attributes['tracker_id'] + if project + issue.tracker_id ||= project.trackers.first.try(:id) + end + end + issue.safe_attributes = attributes issue.safe_attributes = {'custom_field_values' => custom_field_values_from_keywords(issue)} issue.subject = cleaned_up_subject if issue.subject.blank? @@ -420,10 +427,6 @@ class MailHandler < ActionMailer::Base 'done_ratio' => get_keyword(:done_ratio, :format => '(\d|10)?0') }.delete_if {|k, v| v.blank? } - if issue.new_record? && attrs['tracker_id'].nil? - attrs['tracker_id'] = issue.project.trackers.first.try(:id) - end - attrs end diff --git a/app/models/role.rb b/app/models/role.rb index defbc311d..89538aa4d 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -73,6 +73,7 @@ class Role < ActiveRecord::Base acts_as_positioned :scope => :builtin serialize :permissions, ::Role::PermissionsAttributeCoder + store :settings, :accessors => [:permissions_all_trackers, :permissions_tracker_ids] attr_protected :builtin validates_presence_of :name @@ -188,6 +189,56 @@ class Role < ActiveRecord::Base setable_permissions end + def permissions_tracker_ids(*args) + if args.any? + Array(permissions_tracker_ids[args.first.to_s]).map(&:to_i) + else + super || {} + end + end + + def permissions_tracker_ids=(arg) + h = arg.to_hash + h.values.each {|v| v.reject!(&:blank?)} + super(h) + end + + # Returns true if tracker_id belongs to the list of + # trackers for which permission is given + def permissions_tracker_ids?(permission, tracker_id) + permissions_tracker_ids(permission).include?(tracker_id) + end + + def permissions_all_trackers + super || {} + end + + def permissions_all_trackers=(arg) + super(arg.to_hash) + end + + # Returns true if permission is given for all trackers + def permissions_all_trackers?(permission) + permissions_all_trackers[permission.to_s].to_s != '0' + end + + # Sets the trackers that are allowed for a permission. + # tracker_ids can be an array of tracker ids or :all for + # no restrictions. + # + # Examples: + # role.set_permission_trackers :add_issues, [1, 3] + # role.set_permission_trackers :add_issues, :all + def set_permission_trackers(permission, tracker_ids) + h = {permission.to_s => (tracker_ids == :all ? '1' : '0')} + self.permissions_all_trackers = permissions_all_trackers.merge(h) + + h = {permission.to_s => (tracker_ids == :all ? [] : tracker_ids)} + self.permissions_tracker_ids = permissions_tracker_ids.merge(h) + + self + end + # Find all the roles that can be given to a project member def self.find_all_givable Role.givable.to_a diff --git a/app/views/issues/_action_menu.html.erb b/app/views/issues/_action_menu.html.erb index c3304626d..b535faec9 100644 --- a/app/views/issues/_action_menu.html.erb +++ b/app/views/issues/_action_menu.html.erb @@ -3,5 +3,5 @@ <%= link_to l(:button_log_time), new_issue_time_entry_path(@issue), :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project) %> <%= watcher_link(@issue, User.current) %> <%= link_to l(:button_copy), project_copy_issue_path(@project, @issue), :class => 'icon icon-copy' if User.current.allowed_to?(:copy_issues, @project) && Issue.allowed_target_projects.any? %> -<%= link_to l(:button_delete), issue_path(@issue), :data => {:confirm => issues_destroy_confirmation_message(@issue)}, :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %> +<%= link_to l(:button_delete), issue_path(@issue), :data => {:confirm => issues_destroy_confirmation_message(@issue)}, :method => :delete, :class => 'icon icon-del' if @issue.deletable? %> </div> diff --git a/app/views/issues/_edit.html.erb b/app/views/issues/_edit.html.erb index 24a01cad0..67e33246d 100644 --- a/app/views/issues/_edit.html.erb +++ b/app/views/issues/_edit.html.erb @@ -27,21 +27,22 @@ <% end %> </fieldset> <% end %> - - <fieldset><legend><%= l(:field_notes) %></legend> - <%= f.text_area :notes, :cols => 60, :rows => 10, :class => 'wiki-edit', :no_label => true %> - <%= wikitoolbar_for 'issue_notes' %> - - <% if @issue.safe_attribute? 'private_notes' %> - <%= f.check_box :private_notes, :no_label => true %> <label for="issue_private_notes"><%= l(:field_private_notes) %></label> + <% if @issue.notes_addable? %> + <fieldset><legend><%= l(:field_notes) %></legend> + <%= f.text_area :notes, :cols => 60, :rows => 10, :class => 'wiki-edit', :no_label => true %> + <%= wikitoolbar_for 'issue_notes' %> + + <% if @issue.safe_attribute? 'private_notes' %> + <%= f.check_box :private_notes, :no_label => true %> <label for="issue_private_notes"><%= l(:field_private_notes) %></label> + <% end %> + + <%= call_hook(:view_issues_edit_notes_bottom, { :issue => @issue, :notes => @notes, :form => f }) %> + </fieldset> + + <fieldset><legend><%= l(:label_attachment_plural) %></legend> + <p><%= render :partial => 'attachments/form', :locals => {:container => @issue} %></p> + </fieldset> <% end %> - - <%= call_hook(:view_issues_edit_notes_bottom, { :issue => @issue, :notes => @notes, :form => f }) %> - </fieldset> - - <fieldset><legend><%= l(:label_attachment_plural) %></legend> - <p><%= render :partial => 'attachments/form', :locals => {:container => @issue} %></p> - </fieldset> </div> <%= f.hidden_field :lock_version %> diff --git a/app/views/issues/_form.html.erb b/app/views/issues/_form.html.erb index 788a2f38e..1e82b6f84 100644 --- a/app/views/issues/_form.html.erb +++ b/app/views/issues/_form.html.erb @@ -14,7 +14,7 @@ <% end %> <% if @issue.safe_attribute? 'tracker_id' %> -<p><%= f.select :tracker_id, @issue.assignable_trackers.collect {|t| [t.name, t.id]}, {:required => true}, +<p><%= f.select :tracker_id, trackers_options_for_select(@issue), {:required => true}, :onchange => "updateIssueFrom('#{escape_javascript update_issue_form_path(@project, @issue)}', this)" %></p> <% end %> diff --git a/app/views/issues/_history.html.erb b/app/views/issues/_history.html.erb index 993dfee3c..307ac909b 100644 --- a/app/views/issues/_history.html.erb +++ b/app/views/issues/_history.html.erb @@ -1,4 +1,4 @@ -<% reply_links = authorize_for('issues', 'edit') -%> +<% reply_links = issue.notes_addable? -%> <% for journal in journals %> <div id="change-<%= journal.id %>" class="<%= journal.css_classes %>"> <div id="note-<%= journal.indice %>"> diff --git a/app/views/issues/index.html.erb b/app/views/issues/index.html.erb index 7dcba2629..fd762023f 100644 --- a/app/views/issues/index.html.erb +++ b/app/views/issues/index.html.erb @@ -1,5 +1,5 @@ <div class="contextual"> - <% if User.current.allowed_to?(:add_issues, @project, :global => true) && (@project.nil? || @project.trackers.any?) %> + <% if User.current.allowed_to?(:add_issues, @project, :global => true) && (@project.nil? || Issue.allowed_target_trackers(@project).any?) %> <%= link_to l(:label_issue_new), _new_project_issue_path(@project), :class => 'icon icon-add new-issue' %> <% end %> </div> diff --git a/app/views/issues/show.html.erb b/app/views/issues/show.html.erb index 70a7fe165..2cbff32e5 100644 --- a/app/views/issues/show.html.erb +++ b/app/views/issues/show.html.erb @@ -77,7 +77,7 @@ end %> <% if @issue.description? %> <div class="description"> <div class="contextual"> - <%= link_to l(:button_quote), quoted_issue_path(@issue), :remote => true, :method => 'post', :class => 'icon icon-comment' if authorize_for('issues', 'edit') %> + <%= link_to l(:button_quote), quoted_issue_path(@issue), :remote => true, :method => 'post', :class => 'icon icon-comment' if @issue.notes_addable? %> </div> <p><strong><%=l(:field_description)%></strong></p> diff --git a/app/views/roles/_form.html.erb b/app/views/roles/_form.html.erb index 84d5de185..39acc34a4 100644 --- a/app/views/roles/_form.html.erb +++ b/app/views/roles/_form.html.erb @@ -7,17 +7,17 @@ <% end %> <% unless @role.anonymous? %> - <p><%= f.select :issues_visibility, Role::ISSUES_VISIBILITY_OPTIONS.collect {|v| [l(v.last), v.first]} %></p> + <p class="view_issues_shown"><%= f.select :issues_visibility, Role::ISSUES_VISIBILITY_OPTIONS.collect {|v| [l(v.last), v.first]} %></p> <% end %> <% unless @role.anonymous? %> - <p><%= f.select :time_entries_visibility, Role::TIME_ENTRIES_VISIBILITY_OPTIONS.collect {|v| [l(v.last), v.first]} %></p> + <p class="view_time_entries_shown"><%= f.select :time_entries_visibility, Role::TIME_ENTRIES_VISIBILITY_OPTIONS.collect {|v| [l(v.last), v.first]} %></p> <% end %> <p><%= f.select :users_visibility, Role::USERS_VISIBILITY_OPTIONS.collect {|v| [l(v.last), v.first]} %></p> <% unless @role.builtin? %> - <p id="manage_members_options"> + <p class="manage_members_shown"> <label><%= l(:label_member_management) %></label> <label class="block"> <%= radio_button_tag 'role[all_roles_managed]', 1, @role.all_roles_managed?, :id => 'role_all_roles_managed_on', @@ -52,7 +52,8 @@ <% perms_by_module[mod].each do |permission| %> <label class="floating"> <%= check_box_tag 'role[permissions][]', permission.name, (@role.permissions.include? permission.name), - :id => "role_permissions_#{permission.name}" %> + :id => "role_permissions_#{permission.name}", + :data => {:shows => ".#{permission.name}_shown"} %> <%= l_or_humanize(permission.name, :prefix => 'permission_') %> </label> <% end %> @@ -62,10 +63,50 @@ <%= hidden_field_tag 'role[permissions][]', '' %> </div> -<%= javascript_tag do %> -$(document).ready(function(){ - $("#role_permissions_manage_members").change(function(){ - $("#manage_members_options").toggle($(this).is(":checked")); - }).change(); -}); +<div id="role-permissions-trackers" class="view_issues_shown"> +<h3><%= l(:label_issue_tracking) %></h3> +<% permissions = %w(view_issues add_issues edit_issues add_issue_notes delete_issues) %> + +<div class="autoscroll"> +<table class="list"> + <thead> + <tr> + <th><%= l(:label_tracker) %></th> + <% permissions.each do |permission| %> + <th class="<%= "#{permission}_shown" %>"><%= l("permission_#{permission}") %></th> + <% end %> + </thead> + <tbody> + <tr> + <td class="name"><b><%= l(:label_tracker_all) %></b></td> + <% permissions.each do |permission| %> + <td class="<%= "#{permission}_shown" %>"> + <%= hidden_field_tag "role[permissions_all_trackers][#{permission}]", '0', :id => nil %> + <%= check_box_tag "role[permissions_all_trackers][#{permission}]", + '1', + @role.permissions_all_trackers?(permission), + :class => "#{permission}_shown", + :data => {:disables => ".#{permission}_tracker"} %> + </td> + <% end %> + </tr> + <% Tracker.sorted.all.each do |tracker| %> + <tr class="<%= cycle("odd", "even") %>"> + <td class="name"><%= tracker.name %></td> + <% permissions.each do |permission| %> + <td class="<%= "#{permission}_shown" %>"><%= check_box_tag "role[permissions_tracker_ids][#{permission}][]", + tracker.id, + @role.permissions_tracker_ids?(permission, tracker.id), + :class => "#{permission}_tracker", + :id => "role_permissions_tracker_ids_add_issues_#{tracker.id}" %></td> + <% end %> + </tr> + <% end %> + </tbody> +</table> +</div> + +<% permissions.each do |permission| %> + <%= hidden_field_tag "role[permissions_tracker_ids][#{permission}][]", '' %> <% end %> +</div> |