Project

General

Profile

Feature #5358 » redmine-5358.diff

Daniel Neis Araujo, 2011-02-16 18:21

View differences:

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
......
414 418
  def assignable_versions
415 419
    @assignable_versions ||= (project.shared_versions.open + [Version.find_by_id(fixed_version_id_was)]).compact.uniq.sort
416 420
  end
421

  
422
  # Categories that the issue can be assigned to
423
  def assignable_categories
424
    @assignable_categories  ||= (project.shared_categories.open + [IssueCategory.find_by_id(issue_category_id_was)]).compact.uniq.sort
425
  end
417 426
  
418 427
  # Returns true if this issue is blocked by another issue that is still open
419 428
  def blocked?
......
573 582
    # Update issues assigned to the version
574 583
    update_versions(["#{Issue.table_name}.fixed_version_id = ?", version.id])
575 584
  end
585

  
586
  # Unassigns issues from +category+ if it's no longer shared with issue's project
587
  def self.update_categories_from_sharing_change(version)
588
    # Update issues assigned to the version
589
    update_categories(["#{Issue.table_name}.category_id = ?", category.id])
590
  end
576 591
  
577 592
  # Unassigns issues from versions that are no longer shared
578 593
  # after +project+ was moved
......
776 791
      end
777 792
    end
778 793
  end
794

  
795
  # Update issues so their categories are not pointing to a
796
  # fixed_version that is not shared with the issue's project
797
  def self.update_categories(conditions=nil)
798
    # Only need to update issues with a fixed_version from
799
    # a different project and that is not systemwide shared
800
    Issue.all(:conditions => merge_conditions("#{Issue.table_name}.category_id IS NOT NULL" +
801
                                                " AND #{Issue.table_name}.project_id <> #{Version.table_name}.project_id" +
802
                                                " AND #{IssueCategory.table_name}.sharing <> 'system'",
803
                                                conditions),
804
              :include => [:project, :category]
805
              ).each do |issue|
806
      next if issue.project.nil? || issue.category.nil?
807
      unless issue.project.shared_categories.include?(issue.category)
808
        issue.init_journal(User.current)
809
        issue.category = nil
810
        issue.save
811
      end
812
    end
813
  end
779 814
  
780 815
  # Callback on attachment deletion
781 816
  def attachment_removed(obj)
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 => VERSION_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
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.scoped(: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 #{Version.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|
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_version_sharing(c), c]} %></p>
6 7
</div>
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]', 
db/migrate/20110216000000_add_issue_category_sharing.rb
1
class AddVersionsSharing < 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
(1-1/10)