Project

General

Profile

Feature #5358 » 5358-first.working.version.diff

Daniel Neis Araujo, 2011-02-18 00:38

View differences:

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?
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
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)
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
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|
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>
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 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
(2-2/10)