Feature #5358 » 5358-first.working.version.diff
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 |