ChiliProject is not maintained anymore. Please be advised that there will be no more updates.

We do not recommend that you setup new ChiliProject instances and we urge all existing users to migrate their data to a maintained system, e.g. Redmine. We will provide a migration script later. In the meantime, you can use the instructions by Christian Daehn.

category-share.diff

Daniel Neis, 2011-02-27 09:31 pm

Download (9.6 kB)

 
b/app/controllers/issue_categories_controller.rb
25 25
  
26 26
  verify :method => :post, :only => :destroy
27 27

  
28
  helper :projects
29

  
28 30
  def new
29 31
    @category = @project.issue_categories.build(params[:category])
30 32
    if request.post?
b/app/helpers/projects_helper.rb
105 105
    sharing = 'none' unless Version::VERSION_SHARINGS.include?(sharing)
106 106
    l("label_version_sharing_#{sharing}")
107 107
  end
108

  
109
  def format_category_sharing(sharing)
110
    sharing = 'none' unless IssueCategory::SHARINGS.include?(sharing)
111
    l("label_version_sharing_#{sharing}")
112
  end
108 113
end
b/app/models/issue.rb
143 143
      unless new_project.shared_versions.include?(issue.fixed_version)
144 144
        issue.fixed_version = nil
145 145
      end
146
      # Keep the category if it's still valid in the new_project
147
      unless new_project.shared_categories.include?(issue.category)
148
        issue.category = nil
149
      end
146 150
      issue.project = new_project
147 151
      if issue.parent && issue.parent.project_id != issue.project_id
148 152
        issue.parent_issue_id = nil
......
313 317
        errors.add_to_base I18n.t(:error_can_not_reopen_issue_on_closed_version)
314 318
      end
315 319
    end
320

  
321
    if category
322
      if !assignable_categories.include?(category)
323
        errors.add :category_id, :inclusion
324
      end
325
    end
316 326
    
317 327
    # Checks that the issue can not be added/moved to a disabled tracker
318 328
    if project && (tracker_id_changed? || project_id_changed?)
......
414 424
  def assignable_versions
415 425
    @assignable_versions ||= (project.shared_versions.open + [Version.find_by_id(fixed_version_id_was)]).compact.uniq.sort
416 426
  end
427

  
428
  # Categories that the issue can be assigned to
429
  def assignable_categories
430
    @assignable_categories ||= (project.shared_categories + [IssueCategory.find_by_id(category_id_was)]).compact.uniq.sort
431
  end
417 432
  
418 433
  # Returns true if this issue is blocked by another issue that is still open
419 434
  def blocked?
......
573 588
    # Update issues assigned to the version
574 589
    update_versions(["#{Issue.table_name}.fixed_version_id = ?", version.id])
575 590
  end
591

  
592
  # Unassigns issues from +category+ if it's no longer shared with issue's project
593
  def self.update_categories_from_sharing_change(category)
594
    # Update issues assigned to the category
595
    update_categories(["#{Issue.table_name}.category_id = ?", category.id])
596
  end
576 597
  
577 598
  # Unassigns issues from versions that are no longer shared
578 599
  # after +project+ was moved
......
776 797
      end
777 798
    end
778 799
  end
800

  
801
  # Update issues so their categories are not pointing to a
802
  # fixed_version that is not shared with the issue's project
803
  def self.update_categories(conditions=nil)
804
    # Only need to update issues with a fixed_version from
805
    # a different project and that is not systemwide shared
806
    Issue.all(:conditions => merge_conditions("#{Issue.table_name}.category_id IS NOT NULL" +
807
                                                " AND #{Issue.table_name}.project_id <> #{IssueCategory.table_name}.project_id" +
808
                                                " AND #{IssueCategory.table_name}.sharing <> 'system'",
809
                                                conditions),
810
              :include => [:project, :category]
811
              ).each do |issue|
812
      next if issue.project.nil? || issue.category.nil?
813
      unless issue.project.shared_categories.include?(issue.category)
814
        issue.init_journal(User.current)
815
        issue.category = nil
816
        issue.save
817
      end
818
    end
819
  end
779 820
  
780 821
  # Callback on attachment deletion
781 822
  def attachment_removed(obj)
b/app/models/issue_category.rb
16 16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 17

  
18 18
class IssueCategory < ActiveRecord::Base
19
  after_update :update_issues_from_sharing_change
19 20
  belongs_to :project
20 21
  belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
21 22
  has_many :issues, :foreign_key => 'category_id', :dependent => :nullify
23

  
24
  SHARINGS = %w(none descendants hierarchy tree system)
22 25
  
23 26
  validates_presence_of :name
24 27
  validates_uniqueness_of :name, :scope => [:project_id]
25 28
  validates_length_of :name, :maximum => 30
29
  validates_inclusion_of :sharing, :in => SHARINGS
26 30
  
27 31
  alias :destroy_without_reassign :destroy
28 32
  
......
40 44
  end
41 45
  
42 46
  def to_s; name end
47

  
48
  # Returns the sharings that +user+ can set the category to
49
  def allowed_sharings(user = User.current)
50
    SHARINGS.select do |s|
51
      if sharing == s
52
        true
53
      else
54
        case s
55
        when 'system'
56
          # Only admin users can set a systemwide sharing
57
          user.admin?
58
        when 'hierarchy', 'tree'
59
          # Only users allowed to manage versions of the root project can
60
          # set sharing to hierarchy or tree
61
          project.nil? || user.allowed_to?(:manage_versions, project.root)
62
        else
63
          true
64
        end
65
      end
66
    end
67
  end
68

  
69
  # Update the issue's fixed versions. Used if a version's sharing changes.
70
  def update_issues_from_sharing_change
71
    if sharing_changed?
72
      if SHARINGS.index(sharing_was).nil? ||
73
          SHARINGS.index(sharing).nil? ||
74
          SHARINGS.index(sharing_was) > SHARINGS.index(sharing)
75
        Issue.update_categories_from_sharing_change self
76
      end
77
    end
78
  end
43 79
end
b/app/models/project.rb
384 384
                                          "))")
385 385
  end
386 386

  
387
  # Returns a scope of the Versions used by the project
388
  def shared_categories
389
    @shared_categories ||=
390
      IssueCategory.find(:all, :include => :project,
391
                     :conditions => "#{Project.table_name}.id = #{id}" +
392
                                    " OR (#{Project.table_name}.status = #{Project::STATUS_ACTIVE} AND (" +
393
                                          " #{IssueCategory.table_name}.sharing = 'system'" +
394
                                          " OR (#{Project.table_name}.lft >= #{root.lft} AND #{Project.table_name}.rgt <= #{root.rgt} AND #{IssueCategory.table_name}.sharing = 'tree')" +
395
                                          " OR (#{Project.table_name}.lft < #{lft} AND #{Project.table_name}.rgt > #{rgt} AND #{IssueCategory.table_name}.sharing IN ('hierarchy', 'descendants'))" +
396
                                          " OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt} AND #{IssueCategory.table_name}.sharing = 'hierarchy')" +
397
                                          "))")
398
  end
399

  
387 400
  # Returns a hash of project users grouped by role
388 401
  def users_by_role
389 402
    members.find(:all, :include => [:user, :roles]).inject({}) do |h, m|
b/app/views/issue_categories/_form.rhtml
3 3
<div class="box">
4 4
<p><%= f.text_field :name, :size => 30, :required => true %></p>
5 5
<p><%= f.select :assigned_to_id, @project.users.sort.collect{|u| [u.name, u.id]}, :include_blank => true %></p>
6
<p><%= f.select :sharing, @category.allowed_sharings.collect{|c| [format_category_sharing(c), c]} %></p>
6 7
</div>
b/app/views/issues/_attributes.rhtml
9 9

  
10 10
<p><%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), {:required => true}, :disabled => !@issue.leaf? %></p>
11 11
<p><%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %></p>
12
<% unless @project.issue_categories.empty? %>
13
<p><%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>
12
<% unless @issue.assignable_categories.empty? %>
13
<p><%= f.select :category_id, (@issue.assignable_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>
14 14
<%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'),
15 15
                     l(:label_issue_category_new),
16 16
                     'category[name]', 
b/db/migrate/20110216000000_add_issue_category_sharing.rb
1
class AddIssueCategorySharing < ActiveRecord::Migration
2
  def self.up
3
    add_column :issue_categories, :sharing, :string, :default => 'none', :null => false
4
    add_index :issue_categories, :sharing
5
  end
6

  
7
  def self.down
8
    remove_column :issue_categories, :sharing
9
  end
10
end