##// END OF EJS Templates
Introduce virtual MenuNodes (#15880)....
Introduce virtual MenuNodes (#15880). They are characterized by having a blank url. they will only be rendered if the user is authorized to see at least one of its children. they render as links which do nothing when clicked. Patch by Jan Schulz-Hofen. git-svn-id: http://svn.redmine.org/redmine/trunk@15501 e93f8b46-1217-0410-a6f0-8f06a7374b81

File last commit:

r15110:90d14b71b365
r15119:53710d80fc88
Show More
issue.rb
1708 lines | 56.9 KiB | text/x-ruby | RubyLexer
Jean-Philippe Lang
Keep track of issue description changes (#746)....
r4834 # Redmine - project management software
Jean-Philippe Lang
Updates copyright for 2016....
r14856 # Copyright (C) 2006-2016 Jean-Philippe Lang
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 #
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690 #
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690 #
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Issue < ActiveRecord::Base
Jean-Philippe Lang
Makes issue safe_attributes extensible (#6000)....
r4377 include Redmine::SafeAttributes
Jean-Philippe Lang
Ignore non-working days when rescheduling an issue (#2161)....
r10531 include Redmine::Utils::DateCalculation
Jean-Philippe Lang
Adds a specific error message for when the start date is too earlier than the minimum start date (#14086)....
r11696 include Redmine::I18n
Jean-Philippe Lang
Replaces awesome_nested_set gem with a simple and more robust implementation of nested sets....
r13459 before_save :set_parent_id
include Redmine::NestedSet::IssueNestedSet
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 belongs_to :project
belongs_to :tracker
Jean-Philippe Lang
Removed unneeded :foreign_key option on belongs_to associations....
r13102 belongs_to :status, :class_name => 'IssueStatus'
belongs_to :author, :class_name => 'User'
belongs_to :assigned_to, :class_name => 'Principal'
belongs_to :fixed_version, :class_name => 'Version'
belongs_to :priority, :class_name => 'IssuePriority'
belongs_to :category, :class_name => 'IssueCategory'
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330
Jean-Philippe Lang
Set :inverse_of option on journals association....
r13541 has_many :journals, :as => :journalized, :dependent => :destroy, :inverse_of => :journalized
Jean-Philippe Lang
Private issue notes (#1554)....
r10336 has_many :visible_journals,
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 lambda {where(["(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(User.current, :view_private_notes)}))", false])},
Jean-Philippe Lang
Private issue notes (#1554)....
r10336 :class_name => 'Journal',
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 :as => :journalized
Jean-Philippe Lang
Private issue notes (#1554)....
r10336
Jean-Philippe Lang
Fixed that time entries custom values are not deleted when deleting a project or an issue (#15709)....
r12146 has_many :time_entries, :dependent => :destroy
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 has_and_belongs_to_many :changesets, lambda {order("#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC")}
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all
has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Fixed: MailHandler does not include JournalDetail for attached files (#7966)....
r6192 acts_as_attachable :after_add => :attachment_added, :after_remove => :attachment_removed
Jean-Philippe Lang
Custom fields refactoring: most of code moved from controllers to models (using new module ActsAsCustomizable)....
r1578 acts_as_customizable
Jean-Philippe Lang
Added "Watch" functionality on issues. It allows users to receive mail notifications about issue changes....
r450 acts_as_watchable
Jean-Philippe Lang
Search custom fields and journals with different queries to take advantage of indexes on text columns if present....
r13473 acts_as_searchable :columns => ['subject', "#{table_name}.description"],
Jean-Philippe Lang
Option to search open issues only (#10734)....
r13476 :preload => [:project, :status, :tracker],
:scope => lambda {|options| options[:open_issues] ? self.open : self.all}
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100
Eric Davis
Include the issue status in search results and the Activity page. (#3700)...
r2729 acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"},
Jean-Philippe Lang
Different icon for closed issues in search result (#992)....
r2254 :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}},
:type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') }
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 acts_as_activity_provider :scope => preload(:project, :author, :tracker),
Jean-Philippe Lang
Display latest user's activity on account/show view....
r2064 :author_key => :author_id
Eric Davis
Adds a Setting to control how an Issue's done_ratio is calculated:...
r3037
DONE_RATIO_OPTIONS = %w(issue_field issue_status)
Eric Davis
Refactor: Replace @journal with @issue.current_journal...
r3426
attr_reader :current_journal
Jean-Philippe Lang
Private issue notes (#1554)....
r10336 delegate :notes, :notes=, :private_notes, :private_notes=, :to => :current_journal, :allow_nil => true
Eric Davis
Adds named scopes to replace custom finders....
r3443
Jean-Philippe Lang
Skip some validations if attribute did not change....
r13341 validates_presence_of :subject, :project, :tracker
validates_presence_of :priority, :if => Proc.new {|issue| issue.new_record? || issue.priority_id_changed?}
validates_presence_of :status, :if => Proc.new {|issue| issue.new_record? || issue.status_id_changed?}
validates_presence_of :author, :if => Proc.new {|issue| issue.new_record? || issue.author_id_changed?}
Eric Davis
Adds named scopes to replace custom finders....
r3443
Jean-Philippe Lang
Added several validates_length_of...
r590 validates_length_of :subject, :maximum => 255
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 validates_inclusion_of :done_ratio, :in => 0..100
Jean-Philippe Lang
Negative estimated hours should not be valid (#12735)....
r10895 validates :estimated_hours, :numericality => {:greater_than_or_equal_to => 0, :allow_nil => true, :message => :invalid}
Jean-Philippe Lang
Adds a custom validator for dates (#12736)....
r10894 validates :start_date, :date => true
validates :due_date, :date => true
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 validate :validate_issue, :validate_required_fields
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 attr_protected :id
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330
Jean-Philippe Lang
Rewrites named scopes with ARel queries....
r10723 scope :visible, lambda {|*args|
Jean-Philippe Lang
Upgrade to Rails 4.2.0 (#14534)....
r13510 joins(:project).
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 where(Issue.visible_condition(args.shift || User.current, *args))
Jean-Philippe Lang
Rewrites named scopes with ARel queries....
r10723 }
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Toshi MARUYAMA
model: replace Rails2 "named_scope" to Rails3 "scope"...
r9355 scope :open, lambda {|*args|
Jean-Philippe Lang
Use open scope in version issues count methods....
r8165 is_closed = args.size > 0 ? !args.first : false
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 joins(:status).
where("#{IssueStatus.table_name}.is_closed = ?", is_closed)
Jean-Philippe Lang
Use open scope in version issues count methods....
r8165 }
Eric Davis
Adds a Setting to control how an Issue's done_ratio is calculated:...
r3037
Jean-Philippe Lang
Rewrites named scopes with ARel queries....
r10723 scope :recently_updated, lambda { order("#{Issue.table_name}.updated_on DESC") }
scope :on_active_project, lambda {
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 joins(:project).
where("#{Project.table_name}.status = ?", Project::STATUS_ACTIVE)
Jean-Philippe Lang
Rewrites named scopes with ARel queries....
r10723 }
Jean-Philippe Lang
Gantt perf: fixed that Project#start_date and #due_date run way too much queries....
r10905 scope :fixed_version, lambda {|versions|
ids = [versions].flatten.compact.map {|v| v.is_a?(Version) ? v.id : v}
ids.any? ? where(:fixed_version_id => ids) : where('1=0')
}
Jean-Philippe Lang
Adds a scope to get issues assigned to a user....
r14338 scope :assigned_to, lambda {|arg|
arg = Array(arg).uniq
ids = arg.map {|p| p.is_a?(Principal) ? p.id : p}
ids += arg.select {|p| p.is_a?(User)}.map(&:group_ids).flatten.uniq
ids.compact!
ids.any? ? where(:assigned_to_id => ids) : none
}
Eric Davis
Rewrite the Gantt chart. #6276...
r3958
Jean-Philippe Lang
When changing tracker, clear the attributes that are disabled for the new tracker (#17527)....
r13798 before_validation :clear_disabled_fields
Jean-Philippe Lang
Fixed: journal details duplicated when an issue is saved twice (#3690)....
r3385 before_create :default_assign
Toshi MARUYAMA
code format cleanup app/models/issue.rb...
r12000 before_save :close_duplicates, :update_done_ratio_from_issue_status,
Jean-Philippe Lang
Fixed that previous assignee is not notified on issue update (#15714)....
r12144 :force_updated_on_change, :update_closed_on, :set_assigned_to_was
Toshi MARUYAMA
remove trailing white-spaces from app/models/issue.rb...
r12807 after_save {|issue| issue.send :after_project_change if !issue.id_changed? && issue.project_id_changed?}
Toshi MARUYAMA
code format cleanup app/models/issue.rb...
r12000 after_save :reschedule_following_issues, :update_nested_set_attributes,
:update_parent_attributes, :create_journal
Jean-Philippe Lang
Option to copy subtasks when copying issue(s) (#6965)....
r10144 # Should be after_create but would be called before previous after_save callbacks
after_save :after_create_from_copy
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 after_destroy :update_parent_attributes
Jean-Philippe Lang
Use AR callbacks instead of observers (removed in Rails4) for notifications....
r11791 after_create :send_notification
Jean-Philippe Lang
Fixed that previous assignee is not notified on issue update (#15714)....
r12144 # Keep it at the end of after_save callbacks
after_save :clear_assigned_to_was
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds Issue#visible_condition to build issue visibility statement....
r5021 # Returns a SQL conditions string used to find all issues visible by the specified user
def self.visible_condition(user, options={})
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 Project.allowed_to_condition(user, :view_issues, options) do |role, user|
Jean-Philippe Lang
Adds issue visibility by role/tracker (#285)....
r15083 sql = if user.id && user.logged?
Jean-Philippe Lang
Anonymous users should always see public issues only (#11872)....
r10254 case role.issues_visibility
when 'all'
Jean-Philippe Lang
Adds issue visibility by role/tracker (#285)....
r15083 '1=1'
Jean-Philippe Lang
Anonymous users should always see public issues only (#11872)....
r10254 when 'default'
Jean-Philippe Lang
Prevents invalid SQL with invalid group_ids (#14902)....
r11932 user_ids = [user.id] + user.groups.map(&:id).compact
Jean-Philippe Lang
Anonymous users should not see private issues with anonymous author (#11872)....
r10250 "(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
Jean-Philippe Lang
Anonymous users should always see public issues only (#11872)....
r10254 when 'own'
Jean-Philippe Lang
Prevents invalid SQL with invalid group_ids (#14902)....
r11932 user_ids = [user.id] + user.groups.map(&:id).compact
Jean-Philippe Lang
Anonymous users should not see private issues with anonymous author (#11872)....
r10250 "(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
else
'1=0'
end
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 else
Jean-Philippe Lang
Anonymous users should always see public issues only (#11872)....
r10254 "(#{table_name}.is_private = #{connection.quoted_false})"
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 end
Jean-Philippe Lang
Adds issue visibility by role/tracker (#285)....
r15083 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
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 end
Jean-Philippe Lang
Adds Issue#visible_condition to build issue visibility statement....
r5021 end
Jean-Philippe Lang
Fixed: issue details view discloses relations to issues that the user is not allowed to view (#2589)....
r2341 # Returns true if usr or current user is allowed to view the issue
def visible?(usr=nil)
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 (usr || User.current).allowed_to?(:view_issues, self.project) do |role, user|
Jean-Philippe Lang
Adds issue visibility by role/tracker (#285)....
r15083 visible = if user.logged?
Jean-Philippe Lang
Anonymous users should always see public issues only (#11872)....
r10254 case role.issues_visibility
when 'all'
true
when 'default'
!self.is_private? || (self.author == user || user.is_or_belongs_to?(assigned_to))
when 'own'
self.author == user || user.is_or_belongs_to?(assigned_to)
else
false
end
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 else
Jean-Philippe Lang
Anonymous users should always see public issues only (#11872)....
r10254 !self.is_private?
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 end
Jean-Philippe Lang
Adds issue visibility by role/tracker (#285)....
r15083 unless role.permissions_all_trackers?(:view_issues)
visible &&= role.permissions_tracker_ids?(:view_issues, tracker_id)
end
visible
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 end
Jean-Philippe Lang
Fixed: issue details view discloses relations to issues that the user is not allowed to view (#2589)....
r2341 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds permission to edit and delete issues by role/tracker (#285)....
r15084 # Returns true if user or current user is allowed to edit or add notes to the issue
Jean-Philippe Lang
Code cleanup, use named routes....
r10838 def editable?(user=User.current)
Jean-Philippe Lang
Adds permission to edit and delete issues by role/tracker (#285)....
r15084 attributes_editable?(user) || notes_addable?(user)
Jean-Philippe Lang
Added Issue#attributes_editable?...
r13614 end
# Returns true if user or current user is allowed to edit the issue
def attributes_editable?(user=User.current)
Jean-Philippe Lang
Adds permission to edit and delete issues by role/tracker (#285)....
r15084 user_tracker_permission?(user, :edit_issues)
end
Jean-Philippe Lang
Same permission for editing the issue and its attachments....
r15094 # Overrides Redmine::Acts::Attachable::InstanceMethods#attachments_editable?
def attachments_editable?(user=User.current)
attributes_editable?(user)
end
Jean-Philippe Lang
Adds permission to edit and delete issues by role/tracker (#285)....
r15084 # 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)
Jean-Philippe Lang
Code cleanup, use named routes....
r10838 end
Jean-Philippe Lang
Removed after_initialize methods....
r8168 def initialize(attributes=nil, *args)
super
Jean-Philippe Lang
Added default value for enumerations....
r792 if new_record?
# set default values for new records only
Eric Davis
Changed Enumerations to use a Single Table Inheritance...
r2677 self.priority ||= IssuePriority.default
Jean-Philippe Lang
Initialize watcher_user_ids for new records to prevent useless queries on each #watched_by?....
r8434 self.watcher_user_ids = []
Jean-Philippe Lang
Added default value for enumerations....
r792 end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds Issue#status_was that returns the initial issue status....
r11182 def create_or_update
super
ensure
@status_was = nil
end
private :create_or_update
Jean-Philippe Lang
Fixed that deleting a project with subtasks may fail (#11185)....
r9675 # AR#Persistence#destroy would raise and RecordNotFound exception
# if the issue was already deleted or updated (non matching lock_version).
# This is a problem when bulk deleting issues or deleting a project
# (because an issue may already be deleted if its parent was deleted
# first).
# The issue is reloaded by the nested_set before being deleted so
# the lock_version condition should not be an issue but we handle it.
def destroy
super
Jean-Philippe Lang
Replaces awesome_nested_set gem with a simple and more robust implementation of nested sets....
r13459 rescue ActiveRecord::StaleObjectError, ActiveRecord::RecordNotFound
Jean-Philippe Lang
Fixed that deleting a project with subtasks may fail (#11185)....
r9675 # Stale or already deleted
begin
reload
rescue ActiveRecord::RecordNotFound
# The issue was actually already deleted
@destroyed = true
return freeze
end
# The issue was stale, retry to destroy
super
end
Jean-Philippe Lang
Fixed that #reload raises a Stack too deep error with ruby 2.0....
r11267 alias :base_reload :reload
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 def reload(*args)
@workflow_rule_by_attribute = nil
Jean-Philippe Lang
Versions that are not shared should not be assignable when selecting another project (#11506)....
r9903 @assignable_versions = nil
Jean-Philippe Lang
Fixed that relations may not be refreshed when adding a follows relation (#13251)....
r11231 @relations = nil
Jean-Philippe Lang
Clear @spent_hours on reload (#18410)....
r13243 @spent_hours = nil
Jean-Philippe Lang
Code cleanup....
r13892 @total_spent_hours = nil
Jean-Philippe Lang
Don't store total estimated hours on parent issues (#16092)....
r13890 @total_estimated_hours = nil
Jean-Philippe Lang
Fixed that #reload raises a Stack too deep error with ruby 2.0....
r11267 base_reload(*args)
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 end
Jean-Philippe Lang
Custom fields refactoring: most of code moved from controllers to models (using new module ActsAsCustomizable)....
r1578 # Overrides Redmine::Acts::Customizable::InstanceMethods#available_custom_fields
def available_custom_fields
Jean-Philippe Lang
Prevent N queries on custom_fields when call /issues API....
r12638 (project && tracker) ? (project.all_issue_custom_fields & tracker.custom_fields) : []
Jean-Philippe Lang
Custom fields refactoring: most of code moved from controllers to models (using new module ActsAsCustomizable)....
r1578 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Role-based issue custom field visibility (#5037)....
r11782 def visible_custom_field_values(user=nil)
user_real = user || User.current
custom_field_values.select do |value|
value.custom_field.visible_by?(project, user_real)
end
end
Jean-Philippe Lang
Use the regular issue form to copy a single issue....
r8432 # Copies attributes from another issue, arg can be an id or an Issue
Jean-Philippe Lang
Adds an option of the copy form to enable/disable attachments copy (#3055)....
r8557 def copy_from(arg, options={})
Eric Davis
Only copy visible issues....
r3584 issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg)
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 self.attributes = issue.attributes.dup.except("id", "root_id", "parent_id", "lft", "rgt", "created_on", "updated_on")
self.custom_field_values = issue.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h}
Jean-Philippe Lang
Copy issue status on project copy (#3877)....
r2961 self.status = issue.status
Jean-Philippe Lang
Code cleanup....
r8405 self.author = User.current
Jean-Philippe Lang
Adds an option of the copy form to enable/disable attachments copy (#3055)....
r8557 unless options[:attachments] == false
Toshi MARUYAMA
remove trailing white-spaces from app/models/issue.rb...
r12807 self.attachments = issue.attachments.map do |attachement|
Jean-Philippe Lang
Adds an option of the copy form to enable/disable attachments copy (#3055)....
r8557 attachement.copy(:container => self)
end
Jean-Philippe Lang
Copy attachments on issue and project copy (#3055)....
r8556 end
Jean-Philippe Lang
Use the regular issue form to copy a single issue....
r8432 @copied_from = issue
Jean-Philippe Lang
Option to copy subtasks when copying issue(s) (#6965)....
r10144 @copy_options = options
Jean-Philippe Lang
Added the hability to copy an issue....
r860 self
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Deprecated Issue#move_to_project....
r8419 # Returns an unsaved copy of the issue
Jean-Philippe Lang
Fixed MissingFeatureException: let user choose to copy attachments or not when bulk copying issues....
r9271 def copy(attributes=nil, copy_options={})
copy = self.class.new.copy_from(self, copy_options)
Jean-Philippe Lang
Deprecated Issue#move_to_project....
r8419 copy.attributes = attributes if attributes
copy
end
Jean-Philippe Lang
Use the regular issue form to copy a single issue....
r8432 # Returns true if the issue is a copy
def copy?
@copied_from.present?
end
Jean-Philippe Lang
Default status per tracker (#5991)....
r13153 def status_id=(status_id)
if status_id.to_s != self.status_id.to_s
self.status = (status_id.present? ? IssueStatus.find_by_id(status_id) : nil)
end
self.status_id
end
# Sets the status.
Jean-Philippe Lang
Typo....
r13330 def status=(status)
Jean-Philippe Lang
Default status per tracker (#5991)....
r13153 if status != self.status
@workflow_rule_by_attribute = nil
end
association(:status).writer(status)
Jean-Philippe Lang
Cleans up status assignment in IssuesController#new handled by Issue#safe_attributes= now....
r3492 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Added default value for enumerations....
r792 def priority_id=(pid)
self.priority = nil
write_attribute(:priority_id, pid)
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Jean-Philippe Lang
Enable tracker update on issue edit form (#2405)....
r2994
Jean-Philippe Lang
Allows project to be changed from the regular issue update action (#4769, #9803)....
r8411 def category_id=(cid)
self.category = nil
write_attribute(:category_id, cid)
end
def fixed_version_id=(vid)
self.fixed_version = nil
write_attribute(:fixed_version_id, vid)
end
Jean-Philippe Lang
Code cleanup....
r13131 def tracker_id=(tracker_id)
if tracker_id.to_s != self.tracker_id.to_s
self.tracker = (tracker_id.present? ? Tracker.find_by_id(tracker_id) : nil)
end
self.tracker_id
end
Jean-Philippe Lang
Default status per tracker (#5991)....
r13153 # Sets the tracker.
# This will set the status to the default status of the new tracker if:
# * the status was the default for the previous tracker
# * or if the status was not part of the new tracker statuses
# * or the status was nil
Jean-Philippe Lang
Code cleanup....
r13131 def tracker=(tracker)
Jean-Philippe Lang
Fixed that subtasks lose their custom fields when copying an issue to a different project (#22342)....
r14936 tracker_was = self.tracker
Jean-Philippe Lang
Code cleanup....
r14937 association(:tracker).writer(tracker)
Jean-Philippe Lang
Fixed that subtasks lose their custom fields when copying an issue to a different project (#22342)....
r14936 if tracker != tracker_was
Jean-Philippe Lang
Code cleanup....
r14937 if status == tracker_was.try(:default_status)
Jean-Philippe Lang
Default status per tracker (#5991)....
r13153 self.status = nil
elsif status && tracker && !tracker.issue_status_ids.include?(status.id)
self.status = nil
end
Jean-Philippe Lang
Fixed that subtasks lose their custom fields when copying an issue to a different project (#22342)....
r14936 reassign_custom_field_values
Jean-Philippe Lang
Code cleanup....
r14937 @workflow_rule_by_attribute = nil
Jean-Philippe Lang
Fixed that subtasks lose their custom fields when copying an issue to a different project (#22342)....
r14936 end
Jean-Philippe Lang
Default status per tracker (#5991)....
r13153 self.status ||= default_status
self.tracker
Jean-Philippe Lang
Enable tracker update on issue edit form (#2405)....
r2994 end
Toshi MARUYAMA
remove trailing white-spaces except SQL from app/models/issue.rb....
r6396
Jean-Philippe Lang
Extracted some code from #move_to_project to a callback....
r8404 def project_id=(project_id)
if project_id.to_s != self.project_id.to_s
self.project = (project_id.present? ? Project.find_by_id(project_id) : nil)
end
Jean-Philippe Lang
Code cleanup....
r13131 self.project_id
Jean-Philippe Lang
Extracted some code from #move_to_project to a callback....
r8404 end
Jean-Philippe Lang
Default status per tracker (#5991)....
r13153 # Sets the project.
# Unless keep_tracker argument is set to true, this will change the tracker
# to the first tracker of the new project if the previous tracker is not part
# of the new project trackers.
Jean-Philippe Lang
Default target version for new issues (#1828)....
r14404 # This will:
# * clear the fixed_version is it's no longer valid for the new project.
# * clear the parent issue if it's no longer valid for the new project.
# * set the category to the category with the same name in the new
# project if it exists, or clear it if it doesn't.
# * for new issue, set the fixed_version to the project default version
# if it's a valid fixed_version.
Jean-Philippe Lang
Allows project to be changed from the regular issue update action (#4769, #9803)....
r8411 def project=(project, keep_tracker=false)
Jean-Philippe Lang
Extracted some code from #move_to_project to a callback....
r8404 project_was = self.project
Jean-Philippe Lang
Code cleanup....
r13131 association(:project).writer(project)
Jean-Philippe Lang
Extracted some code from #move_to_project to a callback....
r8404 if project_was && project && project_was != project
Jean-Philippe Lang
Versions that are not shared should not be assignable when selecting another project (#11506)....
r9903 @assignable_versions = nil
Jean-Philippe Lang
Allows project to be changed from the regular issue update action (#4769, #9803)....
r8411 unless keep_tracker || project.trackers.include?(tracker)
self.tracker = project.trackers.first
end
Jean-Philippe Lang
Extracted some code from #move_to_project to a callback....
r8404 # Reassign to the category with same name if any
if category
self.category = project.issue_categories.find_by_name(category.name)
end
# Keep the fixed_version if it's still valid in the new_project
if fixed_version && fixed_version.project != project && !project.shared_versions.include?(fixed_version)
self.fixed_version = nil
end
Jean-Philippe Lang
Adds a setting to allow subtasks to belong to other projects (#5487)....
r10376 # Clear the parent task if it's no longer valid
unless valid_parent_project?
Jean-Philippe Lang
Extracted some code from #move_to_project to a callback....
r8404 self.parent_issue_id = nil
end
Jean-Philippe Lang
Fixed that subtasks lose their custom fields when copying an issue to a different project (#22342)....
r14936 reassign_custom_field_values
Jean-Philippe Lang
Default status per tracker (#5991)....
r13153 @workflow_rule_by_attribute = nil
Jean-Philippe Lang
Extracted some code from #move_to_project to a callback....
r8404 end
Jean-Philippe Lang
Default target version for new issues (#1828)....
r14404 # Set fixed_version to the project default version if it's valid
if new_record? && fixed_version.nil? && project && project.default_version_id?
if project.shared_versions.open.exists?(project.default_version_id)
self.fixed_version_id = project.default_version_id
end
end
Jean-Philippe Lang
Default status per tracker (#5991)....
r13153 self.project
Jean-Philippe Lang
Extracted some code from #move_to_project to a callback....
r8404 end
Jean-Philippe Lang
Normalize issue description EOLs do prevent false journal details (#8712)....
r6029 def description=(arg)
if arg.is_a?(String)
arg = arg.gsub(/(\r\n|\n|\r)/, "\r\n")
end
write_attribute(:description, arg)
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Merged rails-3.2 branch....
r9346 # Overrides assign_attributes so that project and tracker get assigned first
def assign_attributes_with_project_and_tracker_first(new_attributes, *args)
Jean-Philippe Lang
Fixes tracker_id and custom_field_values assignment order for issues (#4353)....
r3025 return if new_attributes.nil?
Jean-Philippe Lang
Makes project and tracker assigned first in #attributes=...
r8011 attrs = new_attributes.dup
attrs.stringify_keys!
%w(project project_id tracker tracker_id).each do |attr|
if attrs.has_key?(attr)
send "#{attr}=", attrs.delete(attr)
end
Jean-Philippe Lang
Fixes tracker_id and custom_field_values assignment order for issues (#4353)....
r3025 end
Jean-Philippe Lang
Merged rails-3.2 branch....
r9346 send :assign_attributes_without_project_and_tracker_first, attrs, *args
Jean-Philippe Lang
Fixes tracker_id and custom_field_values assignment order for issues (#4353)....
r3025 end
Jean-Philippe Lang
Fixed: SystemStackError (stack level too deep) on Issue#attributes= after model reload (#4838)....
r3313 # Do not redefine alias chain on reload (see #4838)
Jean-Philippe Lang
Merged rails-3.2 branch....
r9346 alias_method_chain(:assign_attributes, :project_and_tracker_first) unless method_defined?(:assign_attributes_without_project_and_tracker_first)
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 def attributes=(new_attributes)
assign_attributes new_attributes
end
Jean-Philippe Lang
Estimated time recognizes improved time formats (#1092)....
r1346 def estimated_hours=(h)
write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h)
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Allows project to be changed from the regular issue update action (#4769, #9803)....
r8411 safe_attributes 'project_id',
Jean-Philippe Lang
Implements /issues/new form for creating issues outside a project (#1003)....
r13617 'tracker_id',
Jean-Philippe Lang
Makes issue safe_attributes extensible (#6000)....
r4377 'status_id',
'category_id',
'assigned_to_id',
'priority_id',
'fixed_version_id',
'subject',
'description',
'start_date',
'due_date',
'done_ratio',
'estimated_hours',
'custom_field_values',
'custom_fields',
'lock_version',
Jean-Philippe Lang
Private issue notes (#1554)....
r10336 'notes',
Jean-Philippe Lang
Adds permission to edit and delete issues by role/tracker (#285)....
r15084 :if => lambda {|issue, user| issue.new_record? || issue.attributes_editable?(user) }
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Private issue notes (#1554)....
r10336 safe_attributes 'notes',
Jean-Philippe Lang
Adds permission to edit and delete issues by role/tracker (#285)....
r15084 :if => lambda {|issue, user| issue.notes_addable?(user)}
Jean-Philippe Lang
Private issue notes (#1554)....
r10336
safe_attributes 'private_notes',
Toshi MARUYAMA
remove trailing white-spaces from app/models/issue.rb...
r12807 :if => lambda {|issue, user| !issue.new_record? && user.allowed_to?(:set_notes_private, issue.project)}
Jean-Philippe Lang
Private issue notes (#1554)....
r10336
Jean-Philippe Lang
Use safe_attributes for issue watchers assignment....
r8077 safe_attributes 'watcher_user_ids',
Toshi MARUYAMA
remove trailing white-spaces from app/models/issue.rb...
r12807 :if => lambda {|issue, user| issue.new_record? && user.allowed_to?(:add_issue_watchers, issue.project)}
Jean-Philippe Lang
Use safe_attributes for issue watchers assignment....
r8077
Jean-Philippe Lang
Private issues (#7414)....
r5346 safe_attributes 'is_private',
:if => lambda {|issue, user|
user.allowed_to?(:set_issues_private, issue.project) ||
Jean-Philippe Lang
Prevents author load (#18290)....
r13194 (issue.author_id == user.id && user.allowed_to?(:set_own_issues_private, issue.project))
Jean-Philippe Lang
Private issues (#7414)....
r5346 }
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Code cleanup....
r8078 safe_attributes 'parent_issue_id',
Jean-Philippe Lang
Adds permission to edit and delete issues by role/tracker (#285)....
r15084 :if => lambda {|issue, user| (issue.new_record? || issue.attributes_editable?(user)) &&
Jean-Philippe Lang
Code cleanup....
r8078 user.allowed_to?(:manage_subtasks, issue.project)}
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 def safe_attribute_names(user=nil)
names = super
Jean-Philippe Lang
Ability to disable standard fields on a per tracker basis (#1091)....
r9729 names -= disabled_core_fields
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 names -= read_only_attribute_names(user)
Jean-Philippe Lang
Implements /issues/new form for creating issues outside a project (#1003)....
r13617 if new_record?
Jean-Philippe Lang
Replace tabs with spaces and remove trailing tabs in several files (#20140)....
r13983 # Make sure that project_id can always be set for new issues
Jean-Philippe Lang
Adds a :copy_issues permission (#18855)....
r13603 names |= %w(project_id)
end
Jean-Philippe Lang
Adds settings to control start/due dates and priority on parent tasks (#5490)....
r13887 if dates_derived?
names -= %w(start_date due_date)
end
if priority_derived?
names -= %w(priority_id)
end
Jean-Philippe Lang
Adds a setting to control done ratio on parent tasks (#5490)....
r13888 if done_ratio_derived?
names -= %w(done_ratio)
end
Jean-Philippe Lang
Ability to disable standard fields on a per tracker basis (#1091)....
r9729 names
end
Jean-Philippe Lang
Set a white list of issue attributes that can be mass-assigned from controllers....
r3194 # Safely sets attributes
# Should be called from controllers instead of #attributes=
# attr_accessible is too rough because we still want things like
# Issue.new(:project => foo) to work
def safe_attributes=(attrs, user=User.current)
Jean-Philippe Lang
Moved some permission checks for issue update from controller to model....
r4279 return unless attrs.is_a?(Hash)
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 attrs = attrs.deep_dup
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Allows project to be changed from the regular issue update action (#4769, #9803)....
r8411 # Project and Tracker must be set before since new_statuses_allowed_to depends on it.
Jean-Philippe Lang
Ability to disable standard fields on a per tracker basis (#1091)....
r9729 if (p = attrs.delete('project_id')) && safe_attribute?('project_id')
Jean-Philippe Lang
Perf: don't load all projects....
r11726 if allowed_target_projects(user).where(:id => p.to_i).exists?
Jean-Philippe Lang
Check project assignment on issue copy/move....
r8433 self.project_id = p
end
Jean-Philippe Lang
Do not clear category on project change if category with same exists (#16941)....
r14333
if project_id_changed? && attrs['category_id'].to_s == category_id_was.to_s
# Discard submitted category on previous project
attrs.delete('category_id')
end
Jean-Philippe Lang
Allows project to be changed from the regular issue update action (#4769, #9803)....
r8411 end
Jean-Philippe Lang
Check project assignment on issue copy/move....
r8433
Jean-Philippe Lang
Ability to disable standard fields on a per tracker basis (#1091)....
r9729 if (t = attrs.delete('tracker_id')) && safe_attribute?('tracker_id')
Jean-Philippe Lang
Adds Issue#allowed_target_trackers (#7839)....
r15048 if allowed_target_trackers(user).where(:id => t.to_i).exists?
self.tracker_id = t
end
Jean-Philippe Lang
Makes MailHandler accept all issue attributes and custom fields that can be set/updated (#4071, #4807, #5622, #6110)....
r4280 end
Jean-Philippe Lang
Fixed that creating an issue without tracker_id attribute ignores custom field values (#19368)....
r13701 if project
Jean-Philippe Lang
Adds Issue#allowed_target_trackers (#7839)....
r15048 # Set a default tracker to accept custom field values
Jean-Philippe Lang
Fixed that creating an issue without tracker_id attribute ignores custom field values (#19368)....
r13701 # even if tracker is not specified
Jean-Philippe Lang
Adds Issue#allowed_target_trackers (#7839)....
r15048 self.tracker ||= allowed_target_trackers(user).first
Jean-Philippe Lang
Fixed that creating an issue without tracker_id attribute ignores custom field values (#19368)....
r13701 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Makes new issue initial status settable in workflow (#5816)....
r14076 statuses_allowed = new_statuses_allowed_to(user)
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 if (s = attrs.delete('status_id')) && safe_attribute?('status_id')
Jean-Philippe Lang
Makes new issue initial status settable in workflow (#5816)....
r14076 if statuses_allowed.collect(&:id).include?(s.to_i)
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 self.status_id = s
Jean-Philippe Lang
Bulk edit refactoring....
r3364 end
end
Jean-Philippe Lang
Makes new issue initial status settable in workflow (#5816)....
r14076 if new_record? && !statuses_allowed.include?(status)
self.status = statuses_allowed.first || default_status
end
Jean-Philippe Lang
Verify assigned_to_id when assigning safe_attributes (#22127)....
r14841 if (u = attrs.delete('assigned_to_id')) && safe_attribute?('assigned_to_id')
if u.blank?
self.assigned_to_id = nil
else
u = u.to_i
if assignable_users.any?{|assignable_user| assignable_user.id == u}
self.assigned_to_id = u
end
end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 attrs = delete_unsafe_attributes(attrs, user)
return if attrs.empty?
Jean-Philippe Lang
Code cleanup....
r8078 if attrs['parent_issue_id'].present?
Jean-Philippe Lang
Fixed that entering #nnn as parent task should validate (#11979)....
r10447 s = attrs['parent_issue_id'].to_s
Jean-Philippe Lang
"Parent task is invalid" while editing child issues with restricted Issues Visibility (#12851)....
r10998 unless (m = s.match(%r{\A#?(\d+)\z})) && (m[1] == parent_id.to_s || Issue.visible(user).exists?(m[1]))
Jean-Philippe Lang
Fixed: No validation errors when entering an invalid "Parent task" (#11979)....
r10404 @invalid_parent_issue_id = attrs.delete('parent_issue_id')
end
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 if attrs['custom_field_values'].present?
Jean-Philippe Lang
Role-based issue custom field visibility (#5037)....
r11782 editable_custom_field_ids = editable_custom_field_values(user).map {|v| v.custom_field_id.to_s}
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 attrs['custom_field_values'].select! {|k, v| editable_custom_field_ids.include?(k.to_s)}
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 end
if attrs['custom_fields'].present?
Jean-Philippe Lang
Role-based issue custom field visibility (#5037)....
r11782 editable_custom_field_ids = editable_custom_field_values(user).map {|v| v.custom_field_id.to_s}
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 attrs['custom_fields'].select! {|c| editable_custom_field_ids.include?(c['id'].to_s)}
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 end
Jean-Philippe Lang
Use safe_attributes for issue watchers assignment....
r8077 # mass-assignment security bypass
Jean-Philippe Lang
Merged rails-3.2 branch....
r9346 assign_attributes attrs, :without_protection => true
Jean-Philippe Lang
Set a white list of issue attributes that can be mass-assigned from controllers....
r3194 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Ability to disable standard fields on a per tracker basis (#1091)....
r9729 def disabled_core_fields
tracker ? tracker.disabled_core_fields : []
end
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 # Returns the custom_field_values that can be edited by the given user
def editable_custom_field_values(user=nil)
Jean-Philippe Lang
Role-based issue custom field visibility (#5037)....
r11782 visible_custom_field_values(user).reject do |value|
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 read_only_attribute_names(user).include?(value.custom_field_id.to_s)
end
end
Jean-Philippe Lang
Field set as read-only still available in the issues list context menu (#16755)....
r12849 # Returns the custom fields that can be edited by the given user
def editable_custom_fields(user=nil)
editable_custom_field_values(user).map(&:custom_field).uniq
end
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 # Returns the names of attributes that are read-only for user or the current user
# For users with multiple roles, the read-only fields are the intersection of
# read-only fields of each role
# The result is an array of strings where sustom fields are represented with their ids
#
# Examples:
# issue.read_only_attribute_names # => ['due_date', '2']
# issue.read_only_attribute_names(user) # => []
def read_only_attribute_names(user=nil)
Jean-Philippe Lang
ruby1.8 compatibility (#703, #3521)....
r9802 workflow_rule_by_attribute(user).reject {|attr, rule| rule != 'readonly'}.keys
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 end
# Returns the names of required attributes for user or the current user
# For users with multiple roles, the required fields are the intersection of
# required fields of each role
# The result is an array of strings where sustom fields are represented with their ids
#
# Examples:
# issue.required_attribute_names # => ['due_date', '2']
# issue.required_attribute_names(user) # => []
def required_attribute_names(user=nil)
Jean-Philippe Lang
ruby1.8 compatibility (#703, #3521)....
r9802 workflow_rule_by_attribute(user).reject {|attr, rule| rule != 'required'}.keys
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 end
# Returns true if the attribute is required for user
def required_attribute?(name, user=nil)
required_attribute_names(user).include?(name.to_s)
end
# Returns a hash of the workflow rule by attribute for the given user
#
# Examples:
# issue.workflow_rule_by_attribute # => {'due_date' => 'required', 'start_date' => 'readonly'}
def workflow_rule_by_attribute(user=nil)
return @workflow_rule_by_attribute if @workflow_rule_by_attribute && user.nil?
user_real = user || User.current
Jean-Philippe Lang
Prevents useless COUNT queries....
r13132 roles = user_real.admin ? Role.all.to_a : user_real.roles_for_project(project)
Jean-Philippe Lang
Don't consider roles without issue add/edit permissions for determining fields permissions (#15988)....
r13365 roles = roles.select(&:consider_workflow?)
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 return {} if roles.empty?
result = {}
Jean-Philippe Lang
Prevents useless COUNT queries....
r13132 workflow_permissions = WorkflowPermission.where(:tracker_id => tracker_id, :old_status_id => status_id, :role_id => roles.map(&:id)).to_a
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 if workflow_permissions.any?
workflow_rules = workflow_permissions.inject({}) do |h, wp|
Jean-Philippe Lang
Fixed that custom fields with hidden/read-only combination may be displayed on issue form (#19297)....
r13755 h[wp.field_name] ||= {}
h[wp.field_name][wp.role_id] = wp.rule
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 h
end
Jean-Philippe Lang
Fixed that custom fields with hidden/read-only combination may be displayed on issue form (#19297)....
r13755 fields_with_roles = {}
IssueCustomField.where(:visible => false).joins(:roles).pluck(:id, "role_id").each do |field_id, role_id|
fields_with_roles[field_id] ||= []
fields_with_roles[field_id] << role_id
end
roles.each do |role|
fields_with_roles.each do |field_id, role_ids|
unless role_ids.include?(role.id)
field_name = field_id.to_s
workflow_rules[field_name] ||= {}
workflow_rules[field_name][role.id] = 'readonly'
end
end
end
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 workflow_rules.each do |attr, rules|
next if rules.size < roles.size
Jean-Philippe Lang
Fixed that custom fields with hidden/read-only combination may be displayed on issue form (#19297)....
r13755 uniq_rules = rules.values.uniq
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 if uniq_rules.size == 1
result[attr] = uniq_rules.first
else
result[attr] = 'required'
end
end
end
@workflow_rule_by_attribute = result if user.nil?
result
end
private :workflow_rule_by_attribute
Eric Davis
Adds a Setting to control how an Issue's done_ratio is calculated:...
r3037 def done_ratio
Eric Davis
Fixes reverting an issue to a status with a done_ratio of 0%. #5170...
r4072 if Issue.use_status_for_done_ratio? && status && status.default_done_ratio
Jean-Philippe Lang
Issue#done_ratio should not break if status is nil....
r3045 status.default_done_ratio
Eric Davis
Adds a Setting to control how an Issue's done_ratio is calculated:...
r3037 else
read_attribute(:done_ratio)
end
end
def self.use_status_for_done_ratio?
Setting.issue_done_ratio == 'issue_status'
end
def self.use_field_for_done_ratio?
Setting.issue_done_ratio == 'issue_field'
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Toshi MARUYAMA
Rails3: model: replace deprecated 'validate' method at Issue model...
r7309 def validate_issue
Jean-Philippe Lang
Don't validate start date when updating an issue without changing it (#14086)....
r11701 if due_date && start_date && (start_date_changed? || due_date_changed?) && due_date < start_date
Jean-Philippe Lang
Merged Rails 2.2 branch. Redmine now requires Rails 2.2.2....
r2430 errors.add :due_date, :greater_than_start_date
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Don't validate start date when updating an issue without changing it (#14086)....
r11701 if start_date && start_date_changed? && soonest_start && start_date < soonest_start
Jean-Philippe Lang
Adds a specific error message for when the start date is too earlier than the minimum start date (#14086)....
r11696 errors.add :start_date, :earlier_than_minimum_start_date, :date => format_date(soonest_start)
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds version status to limit issue assignments (#1245)....
r2906 if fixed_version
if !assignable_versions.include?(fixed_version)
errors.add :fixed_version_id, :inclusion
Jean-Philippe Lang
Code cleanup....
r13126 elsif reopening? && fixed_version.closed?
Toshi MARUYAMA
Rails3: model: replace deprecated errors.add_to_base at validate_issue of Issue...
r7470 errors.add :base, I18n.t(:error_can_not_reopen_issue_on_closed_version)
Jean-Philippe Lang
Adds version status to limit issue assignments (#1245)....
r2906 end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Enable tracker update on issue edit form (#2405)....
r2994 # Checks that the issue can not be added/moved to a disabled tracker
if project && (tracker_id_changed? || project_id_changed?)
Jean-Philippe Lang
Don't add the inclusion error when tracker is not set, the blank error is enough....
r15110 if tracker && !project.trackers.include?(tracker)
Jean-Philippe Lang
Enable tracker update on issue edit form (#2405)....
r2994 errors.add :tracker_id, :inclusion
end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 # Checks parent issue assignment
Jean-Philippe Lang
Fixed: No validation errors when entering an invalid "Parent task" (#11979)....
r10404 if @invalid_parent_issue_id.present?
errors.add :parent_issue_id, :invalid
elsif @parent_issue
Jean-Philippe Lang
Adds a setting to allow subtasks to belong to other projects (#5487)....
r10376 if !valid_parent_project?(@parent_issue)
errors.add :parent_issue_id, :invalid
Jean-Philippe Lang
Can't set parent issue when issue relations among child issues are present (#13654)....
r14674 elsif (@parent_issue != parent) && (
self.would_reschedule?(@parent_issue) ||
@parent_issue.self_and_ancestors.any? {|a| a.relations_from.any? {|r| r.relation_type == IssueRelation::TYPE_PRECEDES && r.issue_to.would_reschedule?(self)}}
)
Jean-Philippe Lang
Fixed: Circular loop when using relations and subtasks (#8794)....
r11411 errors.add :parent_issue_id, :invalid
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 elsif !new_record?
# moving an existing issue
Jean-Philippe Lang
Replaces awesome_nested_set gem with a simple and more robust implementation of nested sets....
r13459 if move_possible?(@parent_issue)
# move accepted
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 else
Jean-Philippe Lang
Adds a setting to allow subtasks to belong to other projects (#5487)....
r10376 errors.add :parent_issue_id, :invalid
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 end
end
end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 # Validates the issue against additional workflow requirements
def validate_required_fields
user = new_record? ? author : current_journal.try(:user)
required_attribute_names(user).each do |attribute|
if attribute =~ /^\d+$/
attribute = attribute.to_i
v = custom_field_values.detect {|v| v.custom_field_id == attribute }
Jean-Philippe Lang
List custom fields with multiple values set as required by workflow can be blank (#20677)....
r14288 if v && Array(v.value).detect(&:present?).nil?
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 errors.add :base, v.custom_field.name + ' ' + l('activerecord.errors.messages.blank')
end
else
Jean-Philippe Lang
Fixed that a disabled field which is required by workflow rules blocks issue creation/update (#17744)....
r13175 if respond_to?(attribute) && send(attribute).blank? && !disabled_core_fields.include?(attribute)
Jean-Philippe Lang
Don't require category or target version when they are not available (#20583)....
r14351 next if attribute == 'category_id' && project.try(:issue_categories).blank?
next if attribute == 'fixed_version_id' && assignable_versions.blank?
Jean-Philippe Lang
Workflow enhancement: editable and required fields configurable by role, tracker and status (#703, #3521)....
r9794 errors.add attribute, :blank
end
end
end
end
Jean-Philippe Lang
Don't validate custom fields that are not editable (#19193)....
r13663 # Overrides Redmine::Acts::Customizable::InstanceMethods#validate_custom_field_values
# so that custom values that are not editable are not validated (eg. a custom field that
# is marked as required should not trigger a validation error if the user is not allowed
# to edit this field).
def validate_custom_field_values
user = new_record? ? author : current_journal.try(:user)
if new_record? || custom_field_values_changed?
editable_custom_field_values(user).each(&:validate_value)
end
end
Eric Davis
Adds a Setting to control how an Issue's done_ratio is calculated:...
r3037 # Set the done_ratio using the status if that setting is set. This will keep the done_ratios
# even if the user turns off the setting later
def update_done_ratio_from_issue_status
Eric Davis
Fixes reverting an issue to a status with a done_ratio of 0%. #5170...
r4072 if Issue.use_status_for_done_ratio? && status && status.default_done_ratio
Jean-Philippe Lang
Allow blank value for IssueStatus#default_done_ratio....
r3043 self.done_ratio = status.default_done_ratio
Eric Davis
Adds a Setting to control how an Issue's done_ratio is calculated:...
r3037 end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 def init_journal(user, notes = "")
@current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes)
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Toshi MARUYAMA
replace tab to space at app/models/issue.rb...
r13257 # Returns the current journal or nil if it's not initialized
Jean-Philippe Lang
Fixed that IssueRelation should not be responsible for calling Issue#init_journal (#18237)....
r13152 def current_journal
@current_journal
end
Jean-Philippe Lang
Moved journal details generation to Journal model....
r13321 # Returns the names of attributes that are journalized when updating the issue
def journalized_attribute_names
Jean-Philippe Lang
When changing tracker, clear the attributes that are disabled for the new tracker (#17527)....
r13798 names = Issue.column_names - %w(id root_id lft rgt lock_version created_on updated_on closed_on)
if tracker
names -= tracker.disabled_core_fields
end
names
Jean-Philippe Lang
Moved journal details generation to Journal model....
r13321 end
Jean-Philippe Lang
Better handling of issue update conflicts (#8691)....
r8654 # Returns the id of the last journal or nil
def last_journal_id
if new_record?
nil
else
Jean-Philippe Lang
Code cleanup....
r9994 journals.maximum(:id)
Jean-Philippe Lang
Better handling of issue update conflicts (#8691)....
r8654 end
end
Jean-Philippe Lang
Code cleanup....
r9996 # Returns a scope for journals that have an id greater than journal_id
def journals_after(journal_id)
scope = journals.reorder("#{Journal.table_name}.id ASC")
if journal_id.present?
scope = scope.where("#{Journal.table_name}.id > ?", journal_id.to_i)
end
scope
end
Jean-Philippe Lang
Adds Issue#status_was that returns the initial issue status....
r11182 # Returns the initial status of the issue
# Returns nil for a new issue
def status_was
Jean-Philippe Lang
Prevents a status load in #status_was when status is not changed (#18290)....
r13195 if status_id_changed?
if status_id_was.to_i > 0
@status_was ||= IssueStatus.find_by_id(status_id_was)
end
else
@status_was ||= status
Jean-Philippe Lang
Adds Issue#status_was that returns the initial issue status....
r11182 end
end
Jean-Philippe Lang
Automatic closing of duplicate issues....
r657 # Return true if the issue is closed, otherwise false
def closed?
Jean-Philippe Lang
Code cleanup, use safer #closed?...
r13123 status.present? && status.is_closed?
Jean-Philippe Lang
Automatic closing of duplicate issues....
r657 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Code cleanup....
r13126 # Returns true if the issue was closed when loaded
def was_closed?
status_was.present? && status_was.is_closed?
end
Jean-Philippe Lang
Adds version status to limit issue assignments (#1245)....
r2906 # Return true if the issue is being reopened
Jean-Philippe Lang
Code cleanup....
r13126 def reopening?
if new_record?
false
else
status_id_changed? && !closed? && was_closed?
Jean-Philippe Lang
Adds version status to limit issue assignments (#1245)....
r2906 end
end
Jean-Philippe Lang
Code cleanup....
r13126 alias :reopened? :reopening?
Jean-Philippe Lang
Fixed: journal details duplicated when an issue is saved twice (#3690)....
r3385
# Return true if the issue is being closed
def closing?
Jean-Philippe Lang
Code cleanup....
r13126 if new_record?
closed?
else
status_id_changed? && closed? && !was_closed?
Jean-Philippe Lang
Fixed: journal details duplicated when an issue is saved twice (#3690)....
r3385 end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds a css class (overdue) to overdue issues on issue lists and detail views (#2337)....
r2138 # Returns true if the issue is overdue
def overdue?
Jean-Philippe Lang
Replace Date.today with User.current.today (#22320)....
r14997 due_date.present? && (due_date < User.current.today) && !closed?
Jean-Philippe Lang
Adds a css class (overdue) to overdue issues on issue lists and detail views (#2337)....
r2138 end
Eric Davis
Rewrite the Gantt chart. #6276...
r3958
# Is the amount of work done less than it should for the due date
def behind_schedule?
return false if start_date.nil? || due_date.nil?
Toshi MARUYAMA
code format cleanup app/models/issue.rb...
r11857 done_date = start_date + ((due_date - start_date + 1) * done_ratio / 100).floor
Jean-Philippe Lang
Replace Date.today with User.current.today (#22320)....
r14997 return done_date <= User.current.today
Eric Davis
Rewrite the Gantt chart. #6276...
r3958 end
Eric Davis
Updated issue delete confirmation when it has child issues. #6191...
r3991
# Does this issue have children?
def children?
!leaf?
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Added a 'Assignable' boolean on Role model....
r643 # Users the issue can be assigned to
def assignable_users
Jean-Philippe Lang
Makes Project#assignable_users return a scope that prevents 2*n queries....
r13127 users = project.assignable_users.to_a
Jean-Philippe Lang
Don't include locked user in assignable users (#21477)....
r14590 users << author if author && author.active?
Jean-Philippe Lang
Assignee is removed on issue update if assignee account is locked (#8884)....
r6188 users << assigned_to if assigned_to
Eric Davis
Don't duplicate users in Issue#assignable_users. From r4240...
r4127 users.uniq.sort
Jean-Philippe Lang
Added a 'Assignable' boolean on Role model....
r643 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds version status to limit issue assignments (#1245)....
r2906 # Versions that the issue can be assigned to
def assignable_versions
Jean-Philippe Lang
Versions that are not shared should not be assignable when selecting another project (#11506)....
r9903 return @assignable_versions if @assignable_versions
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 versions = project.shared_versions.open.to_a
Jean-Philippe Lang
Versions that are not shared should not be assignable when selecting another project (#11506)....
r9903 if fixed_version
if fixed_version_id_changed?
# nothing to do
elsif project_id_changed?
if project.shared_versions.include?(fixed_version)
versions << fixed_version
end
else
versions << fixed_version
end
end
@assignable_versions = versions.uniq.sort
Jean-Philippe Lang
Adds version status to limit issue assignments (#1245)....
r2906 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Actually block issues from closing when a blocking issue isn't closed (#1740)....
r2700 # Returns true if this issue is blocked by another issue that is still open
def blocked?
!relations_to.detect {|ir| ir.relation_type == 'blocks' && !ir.issue_from.closed?}.nil?
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Default status per tracker (#5991)....
r13153 # Returns the default status of the issue based on its tracker
# Returns nil if tracker is nil
def default_status
tracker.try(:default_status)
end
Jean-Philippe Lang
Fixed that improper statuses are proposed when changing status before tracker on the issue form (#10619)....
r9244 # Returns an array of statuses that user is able to apply
Jean-Philippe Lang
Code cleanup....
r8706 def new_statuses_allowed_to(user=User.current, include_default=false)
Jean-Philippe Lang
When copying issues, let the status be changed to default or left unchanged....
r9270 if new_record? && @copied_from
Jean-Philippe Lang
Default status per tracker (#5991)....
r13153 [default_status, @copied_from.status].compact.uniq.sort
Jean-Philippe Lang
When copying issues, let the status be changed to default or left unchanged....
r9270 else
initial_status = nil
if new_record?
Jean-Philippe Lang
Makes new issue initial status settable in workflow (#5816)....
r14076 # nop
Jean-Philippe Lang
Default status per tracker (#5991)....
r13153 elsif tracker_id_changed?
if Tracker.where(:id => tracker_id_was, :default_status_id => status_id_was).any?
initial_status = default_status
elsif tracker.issue_status_ids.include?(status_id_was)
initial_status = IssueStatus.find_by_id(status_id_was)
else
initial_status = default_status
end
Jean-Philippe Lang
Code cleanup....
r13133 else
initial_status = status_was
Jean-Philippe Lang
When copying issues, let the status be changed to default or left unchanged....
r9270 end
Jean-Philippe Lang
Additional status transitions for assignees do not work if assigned to a group (#14447)....
r11826
initial_assigned_to_id = assigned_to_id_changed? ? assigned_to_id_was : assigned_to_id
Toshi MARUYAMA
remove trailing white-spaces from app/models/issue.rb...
r12807 assignee_transitions_allowed = initial_assigned_to_id.present? &&
Jean-Philippe Lang
Additional status transitions for assignees do not work if assigned to a group (#14447)....
r11826 (user.id == initial_assigned_to_id || user.group_ids.include?(initial_assigned_to_id))
Jean-Philippe Lang
Code cleanup....
r13133 statuses = []
Jean-Philippe Lang
Makes new issue initial status settable in workflow (#5816)....
r14076 statuses += IssueStatus.new_statuses_allowed(
initial_status,
user.admin ? Role.all.to_a : user.roles_for_project(project),
tracker,
author == user,
assignee_transitions_allowed
)
Jean-Philippe Lang
When copying issues, let the status be changed to default or left unchanged....
r9270 statuses << initial_status unless statuses.empty?
Jean-Philippe Lang
Makes new issue initial status settable in workflow (#5816)....
r14076 statuses << default_status if include_default || (new_record? && statuses.empty?)
Jean-Philippe Lang
When copying issues, let the status be changed to default or left unchanged....
r9270 statuses = statuses.compact.uniq.sort
Jean-Philippe Lang
Code cleanup....
r13133 if blocked?
statuses.reject!(&:is_closed?)
end
statuses
Jean-Philippe Lang
When copying issues, let the status be changed to default or left unchanged....
r9270 end
Jean-Philippe Lang
Merged IssuesController change_status and add_note actions....
r1030 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Missing notification if previous assignee was a group (#19197)....
r13667 # Returns the previous assignee (user or group) if changed
Jean-Philippe Lang
Notify previous assignee when assignee changes (#2694)....
r8575 def assigned_to_was
Jean-Philippe Lang
Fixed that previous assignee is not notified on issue update (#15714)....
r12144 # assigned_to_id_was is reset before after_save callbacks
user_id = @previous_assigned_to_id || assigned_to_id_was
if user_id && user_id != assigned_to_id
Jean-Philippe Lang
Missing notification if previous assignee was a group (#19197)....
r13667 @assigned_to_was ||= Principal.find_by_id(user_id)
Jean-Philippe Lang
Notify previous assignee when assignee changes (#2694)....
r8575 end
end
Jean-Philippe Lang
Internal error when moving an issue to a project without trackers (#20463)....
r14230 # Returns the original tracker
def tracker_was
Tracker.find_by_id(tracker_id_was)
end
Jean-Philippe Lang
Private issue notes (#1554)....
r10336 # Returns the users that should be notified
def notified_users
Jean-Philippe Lang
Notify previous assignee when assignee changes (#2694)....
r8575 notified = []
Eric Davis
Added User#notify_about? to check when a user should be notified about an event...
r4104 # Author and assignee are always notified unless they have been
# locked or don't want to be notified
Jean-Philippe Lang
Notify previous assignee when assignee changes (#2694)....
r8575 notified << author if author
Jean-Philippe Lang
Ability to assign issues to groups (#2964)....
r6186 if assigned_to
Jean-Philippe Lang
Notify previous assignee when assignee changes (#2694)....
r8575 notified += (assigned_to.is_a?(Group) ? assigned_to.users : [assigned_to])
end
if assigned_to_was
notified += (assigned_to_was.is_a?(Group) ? assigned_to_was.users : [assigned_to_was])
Jean-Philippe Lang
Ability to assign issues to groups (#2964)....
r6186 end
Jean-Philippe Lang
Notify previous assignee when assignee changes (#2694)....
r8575 notified = notified.select {|u| u.active? && u.notify_about?(self)}
notified += project.notified_users
Jean-Philippe Lang
Do not notify users that are no longer allowed to view an issue (#3589, #4263)....
r3007 notified.uniq!
# Remove users that can not view the issue
notified.reject! {|user| !visible?(user)}
Jean-Philippe Lang
Private issue notes (#1554)....
r10336 notified
end
# Returns the email addresses that should be notified
def recipients
notified_users.collect(&:mail)
Jean-Philippe Lang
Do not notify users that are no longer allowed to view an issue (#3589, #4263)....
r3007 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Role-based issue custom field visibility (#5037)....
r11782 def each_notification(users, &block)
if users.any?
if custom_field_values.detect {|value| !value.custom_field.visible?}
users_by_custom_field_visibility = users.group_by do |user|
visible_custom_field_values(user).map(&:custom_field_id).sort
end
users_by_custom_field_visibility.values.each do |users|
yield(users)
end
else
yield(users)
end
end
end
Jean-Philippe Lang
Import issues from CSV file (#950)....
r14111 def notify?
@notify != false
end
def notify=(arg)
@notify = arg
end
Jean-Philippe Lang
Makes spent time column available on the issue list (#971)....
r7953 # Returns the number of hours spent on this issue
def spent_hours
@spent_hours ||= time_entries.sum(:hours) || 0
end
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 # Returns the total number of hours spent on this issue and its descendants
Jean-Philippe Lang
Makes spent time column available on the issue list (#971)....
r7953 def total_spent_hours
Jean-Philippe Lang
Preload total spent time on the issue list with 1 query (#11253)....
r14025 @total_spent_hours ||= if leaf?
Jean-Philippe Lang
Code cleanup....
r13892 spent_hours
else
Jean-Philippe Lang
Preload total spent time on the issue list with 1 query (#11253)....
r14025 self_and_descendants.joins(:time_entries).sum("#{TimeEntry.table_name}.hours").to_f || 0.0
Jean-Philippe Lang
Code cleanup....
r13892 end
Jean-Philippe Lang
Simple time tracking functionality added. Time can be logged at issue or project level....
r365 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Don't store total estimated hours on parent issues (#16092)....
r13890 def total_estimated_hours
if leaf?
estimated_hours
else
@total_estimated_hours ||= self_and_descendants.sum(:estimated_hours)
end
end
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 def relations
Jean-Philippe Lang
Moved IssueRelations to IssueRelation::Relations....
r10750 @relations ||= IssueRelation::Relations.new(self, (relations_from + relations_to).sort)
Jean-Philippe Lang
Ability to load relations on /issues API (#7366)....
r6193 end
Toshi MARUYAMA
remove trailing white-spaces except SQL from app/models/issue.rb....
r6396
Jean-Philippe Lang
Ability to load relations on /issues API (#7366)....
r6193 # Preloads relations for a collection of issues
def self.load_relations(issues)
if issues.any?
Jean-Philippe Lang
Cleanup of finders with :conditions option....
r11733 relations = IssueRelation.where("issue_from_id IN (:ids) OR issue_to_id IN (:ids)", :ids => issues.map(&:id)).all
Jean-Philippe Lang
Ability to load relations on /issues API (#7366)....
r6193 issues.each do |issue|
issue.instance_variable_set "@relations", relations.select {|r| r.issue_from_id == issue.id || r.issue_to_id == issue.id}
end
end
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 end
Toshi MARUYAMA
remove trailing white-spaces except SQL from app/models/issue.rb....
r6396
Jean-Philippe Lang
Fixes methods comments....
r14027 # Preloads visible spent time for a collection of issues
Jean-Philippe Lang
Makes spent time column available on the issue list (#971)....
r7953 def self.load_visible_spent_hours(issues, user=User.current)
if issues.any?
Jean-Philippe Lang
Limit queries to given issues only....
r14026 hours_by_issue_id = TimeEntry.visible(user).where(:issue_id => issues.map(&:id)).group(:issue_id).sum(:hours)
Jean-Philippe Lang
Makes spent time column available on the issue list (#971)....
r7953 issues.each do |issue|
issue.instance_variable_set "@spent_hours", (hours_by_issue_id[issue.id] || 0)
Jean-Philippe Lang
Preload total spent time on the issue list with 1 query (#11253)....
r14025 end
end
end
Jean-Philippe Lang
Fixes methods comments....
r14027 # Preloads visible total spent time for a collection of issues
Jean-Philippe Lang
Preload total spent time on the issue list with 1 query (#11253)....
r14025 def self.load_visible_total_spent_hours(issues, user=User.current)
if issues.any?
Jean-Philippe Lang
Limit queries to given issues only....
r14026 hours_by_issue_id = TimeEntry.visible(user).joins(:issue).
joins("JOIN #{Issue.table_name} parent ON parent.root_id = #{Issue.table_name}.root_id" +
" AND parent.lft <= #{Issue.table_name}.lft AND parent.rgt >= #{Issue.table_name}.rgt").
where("parent.id IN (?)", issues.map(&:id)).group("parent.id").sum(:hours)
Jean-Philippe Lang
Preload total spent time on the issue list with 1 query (#11253)....
r14025 issues.each do |issue|
issue.instance_variable_set "@total_spent_hours", (hours_by_issue_id[issue.id] || 0)
Jean-Philippe Lang
Makes spent time column available on the issue list (#971)....
r7953 end
end
end
Jean-Philippe Lang
Makes related issues available for display and filtering on the issue list (#3239, #3265)....
r10303 # Preloads visible relations for a collection of issues
def self.load_visible_relations(issues, user=User.current)
if issues.any?
issue_ids = issues.map(&:id)
# Relations with issue_from in given issues and visible issue_to
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 relations_from = IssueRelation.joins(:issue_to => :project).
where(visible_condition(user)).where(:issue_from_id => issue_ids).to_a
Jean-Philippe Lang
Makes related issues available for display and filtering on the issue list (#3239, #3265)....
r10303 # Relations with issue_to in given issues and visible issue_from
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 relations_to = IssueRelation.joins(:issue_from => :project).
where(visible_condition(user)).
where(:issue_to_id => issue_ids).to_a
Jean-Philippe Lang
Makes related issues available for display and filtering on the issue list (#3239, #3265)....
r10303 issues.each do |issue|
relations =
relations_from.select {|relation| relation.issue_from_id == issue.id} +
relations_to.select {|relation| relation.issue_to_id == issue.id}
Jean-Philippe Lang
Moved IssueRelations to IssueRelation::Relations....
r10750 issue.instance_variable_set "@relations", IssueRelation::Relations.new(issue, relations.sort)
Jean-Philippe Lang
Makes related issues available for display and filtering on the issue list (#3239, #3265)....
r10303 end
end
end
Jean-Philippe Lang
Adds REST API for issue relations (#7366)....
r6056 # Finds an issue relation given its id.
def find_relation(relation_id)
Jean-Philippe Lang
Cleanup of finders with :conditions option....
r11733 IssueRelation.where("issue_to_id = ? OR issue_from_id = ?", id, id).find(relation_id)
Jean-Philippe Lang
Adds REST API for issue relations (#7366)....
r6056 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Can't set parent issue when issue relations among child issues are present (#13654)....
r14674 # Returns true if this issue blocks the other issue, otherwise returns false
def blocks?(other)
all = [self]
last = [self]
while last.any?
current = last.map {|i| i.relations_from.where(:relation_type => IssueRelation::TYPE_BLOCKS).map(&:issue_to)}.flatten.uniq
current -= last
current -= all
return true if current.include?(other)
last = current
all += last
end
false
end
# Returns true if the other issue might be rescheduled if the start/due dates of this issue change
def would_reschedule?(other)
all = [self]
last = [self]
while last.any?
current = last.map {|i|
i.relations_from.where(:relation_type => IssueRelation::TYPE_PRECEDES).map(&:issue_to) +
i.leaves.to_a +
i.ancestors.map {|a| a.relations_from.where(:relation_type => IssueRelation::TYPE_PRECEDES).map(&:issue_to)}
}.flatten.uniq
current -= last
current -= all
return true if current.include?(other)
last = current
all += last
end
false
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Make the 'duplicates of' relation asymmetric:...
r1474 # Returns an array of issues that duplicate this one
Jean-Philippe Lang
Automatic closing of duplicate issues....
r657 def duplicates
Jean-Philippe Lang
Make the 'duplicates of' relation asymmetric:...
r1474 relations_to.select {|r| r.relation_type == IssueRelation::TYPE_DUPLICATES}.collect {|r| r.issue_from}
Jean-Philippe Lang
Automatic closing of duplicate issues....
r657 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Gantt chart: display issues that don't have a due date if they are assigned to a version with a date (#184)....
r1441 # Returns the due date or the target due date if any
# Used on gantt chart
def due_before
due_date || (fixed_version ? fixed_version.effective_date : nil)
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Eric Davis
Added some RDoc documentation for some models....
r2536 # Returns the time scheduled for this issue.
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690 #
Eric Davis
Added some RDoc documentation for some models....
r2536 # Example:
# Start Date: 2/26/09, End Date: 3/04/09
# duration => 6
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 def duration
(start_date && due_date) ? due_date - start_date : 0
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Ignore non-working days when rescheduling an issue (#2161)....
r10531 # Returns the duration in working days
def working_duration
(start_date && due_date) ? working_days(start_date, due_date) : 0
end
Jean-Philippe Lang
Precede-Follow relation should move following issues earlier when rescheduling issue earlier (#4590)....
r10651 def soonest_start(reload=false)
Jean-Philippe Lang
Adds settings to control start/due dates and priority on parent tasks (#5490)....
r13887 if @soonest_start.nil? || reload
dates = relations_to(reload).collect{|relation| relation.successor_soonest_start}
p = @parent_issue || parent
if p && Setting.parent_issue_dates == 'derived'
dates << p.soonest_start
end
@soonest_start = dates.compact.max
end
@soonest_start
Jean-Philippe Lang
Makes subtasks rescheduled when a 'precedes' relation is set on a parent task....
r3460 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Ignore non-working days when rescheduling an issue (#2161)....
r10531 # Sets start_date on the given date or the next working day
# and changes due_date to keep the same working duration.
def reschedule_on(date)
wd = working_duration
date = next_working_date(date)
self.start_date = date
self.due_date = add_working_days(date, wd)
end
# Reschedules the issue on the given date or the next working day and saves the record.
# If the issue is a parent task, this is done by rescheduling its subtasks.
def reschedule_on!(date)
Jean-Philippe Lang
Makes subtasks rescheduled when a 'precedes' relation is set on a parent task....
r3460 return if date.nil?
Jean-Philippe Lang
Adds settings to control start/due dates and priority on parent tasks (#5490)....
r13887 if leaf? || !dates_derived?
Jean-Philippe Lang
Precede-Follow relation should move following issues earlier when rescheduling issue earlier (#4590)....
r10651 if start_date.nil? || start_date != date
if start_date && start_date > date
# Issue can not be moved earlier than its soonest start date
date = [soonest_start(true), date].compact.max
end
Jean-Philippe Lang
Ignore non-working days when rescheduling an issue (#2161)....
r10531 reschedule_on(date)
Jean-Philippe Lang
Prevent ActiveRecord::StaleObjectError in Issue#reschedule_after (#7920)....
r8744 begin
save
rescue ActiveRecord::StaleObjectError
reload
Jean-Philippe Lang
Ignore non-working days when rescheduling an issue (#2161)....
r10531 reschedule_on(date)
Jean-Philippe Lang
Prevent ActiveRecord::StaleObjectError in Issue#reschedule_after (#7920)....
r8744 save
end
Jean-Philippe Lang
Makes subtasks rescheduled when a 'precedes' relation is set on a parent task....
r3460 end
else
leaves.each do |leaf|
Jean-Philippe Lang
Fixed the behaviour for when rescheduling a parent task (#4590)....
r10653 if leaf.start_date
# Only move subtask if it starts at the same date as the parent
# or if it starts before the given date
Toshi MARUYAMA
remove trailing white-spaces from app/models/issue.rb...
r12807 if start_date == leaf.start_date || date > leaf.start_date
Jean-Philippe Lang
Fixed the behaviour for when rescheduling a parent task (#4590)....
r10653 leaf.reschedule_on!(date)
end
else
leaf.reschedule_on!(date)
end
Jean-Philippe Lang
Makes subtasks rescheduled when a 'precedes' relation is set on a parent task....
r3460 end
end
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds settings to control start/due dates and priority on parent tasks (#5490)....
r13887 def dates_derived?
!leaf? && Setting.parent_issue_dates == 'derived'
end
def priority_derived?
!leaf? && Setting.parent_issue_priority == 'derived'
end
Jean-Philippe Lang
Adds a setting to control done ratio on parent tasks (#5490)....
r13888 def done_ratio_derived?
!leaf? && Setting.parent_issue_done_ratio == 'derived'
end
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 def <=>(issue)
if issue.nil?
-1
elsif root_id != issue.root_id
(root_id || 0) <=> (issue.root_id || 0)
else
(lft || 0) <=> (issue.lft || 0)
end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Time report can be done at issue level (closes #970) + timelog views xhtml validation....
r1304 def to_s
"#{tracker} ##{id}: #{subject}"
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds more css classes to the roadmap issues (#3214)....
r2602 # Returns a string of css classes that apply to the issue
Jean-Philippe Lang
Adds 'assigned-to-my-group' css class to issues that are assigned to a user's group (#12681)....
r11776 def css_classes(user=User.current)
Jean-Philippe Lang
Adds "tracker-[id]" CSS class to issues (#13309)....
r11279 s = "issue tracker-#{tracker_id} status-#{status_id} #{priority.try(:css_classes)}"
Jean-Philippe Lang
Adds more css classes to the roadmap issues (#3214)....
r2602 s << ' closed' if closed?
s << ' overdue' if overdue?
Jean-Philippe Lang
Adds css classes to parent/child issues (#7986)....
r5101 s << ' child' if child?
s << ' parent' unless leaf?
Jean-Philippe Lang
Private issues (#7414)....
r5346 s << ' private' if is_private?
Jean-Philippe Lang
Adds 'assigned-to-my-group' css class to issues that are assigned to a user's group (#12681)....
r11776 if user.logged?
s << ' created-by-me' if author_id == user.id
s << ' assigned-to-me' if assigned_to_id == user.id
Toshi MARUYAMA
fix wrong issue 'assigned-to-my-group' css class (#16038)...
r12569 s << ' assigned-to-my-group' if user.groups.any? {|g| g.id == assigned_to_id}
Jean-Philippe Lang
Adds 'assigned-to-my-group' css class to issues that are assigned to a user's group (#12681)....
r11776 end
Jean-Philippe Lang
Adds more css classes to the roadmap issues (#3214)....
r2602 s
end
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009
Jean-Philippe Lang
Optimize updates of issue's shared versions....
r3023 # Unassigns issues from +version+ if it's no longer shared with issue's project
def self.update_versions_from_sharing_change(version)
# Update issues assigned to the version
update_versions(["#{Issue.table_name}.fixed_version_id = ?", version.id])
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Optimize updates of issue's shared versions....
r3023 # Unassigns issues from versions that are no longer shared
# after +project+ was moved
def self.update_versions_from_hierarchy_change(project)
moved_project_ids = project.self_and_descendants.reload.collect(&:id)
# Update issues of the moved projects and issues assigned to a version of a moved project
Toshi MARUYAMA
code format clean up Issue#update_versions_from_hierarchy_change...
r12806 Issue.update_versions(
["#{Version.table_name}.project_id IN (?) OR #{Issue.table_name}.project_id IN (?)",
moved_project_ids, moved_project_ids]
)
Jean-Philippe Lang
Optimize updates of issue's shared versions....
r3023 end
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 def parent_issue_id=(arg)
Jean-Philippe Lang
Fixed: No validation errors when entering an invalid "Parent task" (#11979)....
r10404 s = arg.to_s.strip.presence
if s && (m = s.match(%r{\A#?(\d+)\z})) && (@parent_issue = Issue.find_by_id(m[1]))
Jean-Philippe Lang
Fixed that issue nested set update is triggered even if parent is not changed (#15135)....
r11996 @invalid_parent_issue_id = nil
elsif s.blank?
@parent_issue = nil
@invalid_parent_issue_id = nil
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 else
@parent_issue = nil
Jean-Philippe Lang
Fixed: No validation errors when entering an invalid "Parent task" (#11979)....
r10404 @invalid_parent_issue_id = arg
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 def parent_issue_id
Jean-Philippe Lang
Fixed: No validation errors when entering an invalid "Parent task" (#11979)....
r10404 if @invalid_parent_issue_id
@invalid_parent_issue_id
elsif instance_variable_defined? :@parent_issue
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 @parent_issue.nil? ? nil : @parent_issue.id
else
parent_id
end
end
Jean-Philippe Lang
Replaces awesome_nested_set gem with a simple and more robust implementation of nested sets....
r13459 def set_parent_id
self.parent_id = parent_issue_id
end
Toshi MARUYAMA
replace tabs to spaces at app/models/issue.rb...
r11192 # Returns true if issue's project is a valid
# parent issue project
Jean-Philippe Lang
Adds a setting to allow subtasks to belong to other projects (#5487)....
r10376 def valid_parent_project?(issue=parent)
return true if issue.nil? || issue.project_id == project_id
case Setting.cross_project_subtasks
when 'system'
true
when 'tree'
issue.project.root == project.root
when 'hierarchy'
issue.project.is_or_is_ancestor_of?(project) || issue.project.is_descendant_of?(project)
when 'descendants'
issue.project.is_or_is_ancestor_of?(project)
else
false
end
end
Jean-Philippe Lang
Parent issue autocomplete does not follow to the "Allow cross-project subtasks" setting (#14281)....
r13037 # Returns an issue scope based on project and scope
def self.cross_project_scope(project, scope=nil)
if project.nil?
return Issue
end
case scope
when 'all', 'system'
Issue
when 'tree'
Issue.joins(:project).where("(#{Project.table_name}.lft >= :lft AND #{Project.table_name}.rgt <= :rgt)",
:lft => project.root.lft, :rgt => project.root.rgt)
when 'hierarchy'
Issue.joins(:project).where("(#{Project.table_name}.lft >= :lft AND #{Project.table_name}.rgt <= :rgt) OR (#{Project.table_name}.lft < :lft AND #{Project.table_name}.rgt > :rgt)",
:lft => project.lft, :rgt => project.rgt)
when 'descendants'
Issue.joins(:project).where("(#{Project.table_name}.lft >= :lft AND #{Project.table_name}.rgt <= :rgt)",
:lft => project.lft, :rgt => project.rgt)
else
Issue.where(:project_id => project.id)
end
end
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 def self.by_tracker(project)
Jean-Philippe Lang
Code cleanup, removed raw SQL queries....
r13080 count_and_group_by(:project => project, :association => :tracker)
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 end
def self.by_version(project)
Jean-Philippe Lang
Code cleanup, removed raw SQL queries....
r13080 count_and_group_by(:project => project, :association => :fixed_version)
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 end
def self.by_priority(project)
Jean-Philippe Lang
Code cleanup, removed raw SQL queries....
r13080 count_and_group_by(:project => project, :association => :priority)
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 end
def self.by_category(project)
Jean-Philippe Lang
Code cleanup, removed raw SQL queries....
r13080 count_and_group_by(:project => project, :association => :category)
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 end
def self.by_assigned_to(project)
Jean-Philippe Lang
Code cleanup, removed raw SQL queries....
r13080 count_and_group_by(:project => project, :association => :assigned_to)
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 end
def self.by_author(project)
Jean-Philippe Lang
Code cleanup, removed raw SQL queries....
r13080 count_and_group_by(:project => project, :association => :author)
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 end
def self.by_subproject(project)
Jean-Philippe Lang
Code cleanup, removed raw SQL queries....
r13080 r = count_and_group_by(:project => project, :with_subprojects => true, :association => :project)
r.reject {|r| r["project_id"] == project.id.to_s}
end
# Query generator for selecting groups of issue counts for a project
# based on specific criteria
#
# Options
# * project - Project to search in.
# * with_subprojects - Includes subprojects issues if set to true.
# * association - Symbol. Association for grouping.
def self.count_and_group_by(options)
assoc = reflect_on_association(options[:association])
select_field = assoc.foreign_key
Issue.
visible(User.current, :project => options[:project], :with_subprojects => options[:with_subprojects]).
Jean-Philippe Lang
Fixed tests broken by r13461....
r13085 joins(:status, assoc.name).
Jean-Philippe Lang
Code cleanup, removed raw SQL queries....
r13080 group(:status_id, :is_closed, select_field).
count.
map do |columns, total|
status_id, is_closed, field_value = columns
Jean-Philippe Lang
Fixed test failure with MySQL introduced by r13467....
r13087 is_closed = ['t', 'true', '1'].include?(is_closed.to_s)
Jean-Philippe Lang
Code cleanup, removed raw SQL queries....
r13080 {
"status_id" => status_id.to_s,
Jean-Philippe Lang
Fixed test failure with SQLServer introduced by r13461....
r13086 "closed" => is_closed,
Jean-Philippe Lang
Code cleanup, removed raw SQL queries....
r13080 select_field => field_value.to_s,
"total" => total.to_s
}
end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Perf: don't load all projects....
r11726 # Returns a scope of projects that user can assign the issue to
Jean-Philippe Lang
Check project assignment on issue copy/move....
r8433 def allowed_target_projects(user=User.current)
Jean-Philippe Lang
Removed :move_issues permission (#18855)....
r13599 current_project = new_record? ? nil : project
self.class.allowed_target_projects(user, current_project)
Jean-Philippe Lang
Check project assignment on issue copy/move....
r8433 end
Jean-Philippe Lang
Removed :move_issues permission (#18855)....
r13599 # Returns a scope of projects that user can assign issues to
# If current_project is given, it will be included in the scope
def self.allowed_target_projects(user=User.current, current_project=nil)
condition = Project.allowed_to_condition(user, :add_issues)
if current_project
condition = ["(#{condition}) OR #{Project.table_name}.id = ?", current_project.id]
end
Jean-Philippe Lang
Don't propose projects without trackers when editing an issue (#20463)....
r14231 Project.where(condition).having_trackers
Jean-Philippe Lang
Fixes behaviour of move_issues permission for non member role (#5309)....
r3569 end
Jean-Philippe Lang
Adds Issue#allowed_target_trackers (#7839)....
r15048
# Returns a scope of trackers that user can assign the issue to
def allowed_target_trackers(user=User.current)
Jean-Philippe Lang
Limit trackers for new issue to certain roles (#7839)....
r15082 self.class.allowed_target_trackers(project, user, tracker_id_was)
Jean-Philippe Lang
Adds Issue#allowed_target_trackers (#7839)....
r15048 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)
Jean-Philippe Lang
Limit trackers for new issue to certain roles (#7839)....
r15082 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
Jean-Philippe Lang
Adds Issue#allowed_target_trackers (#7839)....
r15048 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Optimize updates of issue's shared versions....
r3023 private
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds permission to edit and delete issues by role/tracker (#285)....
r15084 def user_tracker_permission?(user, permission)
Jean-Philippe Lang
Always authorize admin users....
r15093 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
Jean-Philippe Lang
Adds permission to edit and delete issues by role/tracker (#285)....
r15084 end
Jean-Philippe Lang
Extracted some code from #move_to_project to a callback....
r8404 def after_project_change
# Update project_id on related time entries
Toshi MARUYAMA
Rails4: replace deprecated Relation#update_all at Issue model...
r12257 TimeEntry.where({:issue_id => id}).update_all(["project_id = ?", project_id])
Jean-Philippe Lang
Extracted some code from #move_to_project to a callback....
r8404
# Delete issue relations
unless Setting.cross_project_issue_relations?
relations_from.clear
relations_to.clear
end
Jean-Philippe Lang
Adds a setting to allow subtasks to belong to other projects (#5487)....
r10376 # Move subtasks that were in the same project
Jean-Philippe Lang
Extracted some code from #move_to_project to a callback....
r8404 children.each do |child|
Jean-Philippe Lang
Adds a setting to allow subtasks to belong to other projects (#5487)....
r10376 next unless child.project_id == project_id_was
Jean-Philippe Lang
Allows project to be changed from the regular issue update action (#4769, #9803)....
r8411 # Change project and keep project
child.send :project=, project, true
Jean-Philippe Lang
Extracted some code from #move_to_project to a callback....
r8404 unless child.save
raise ActiveRecord::Rollback
end
end
end
Jean-Philippe Lang
Adds a "Copied from/to" relation when copying issue(s) (#6899)....
r10282 # Callback for after the creation of an issue by copy
# * adds a "copied to" relation with the copied issue
# * copies subtasks from the copied issue
Jean-Philippe Lang
Option to copy subtasks when copying issue(s) (#6965)....
r10144 def after_create_from_copy
Jean-Philippe Lang
Adds a "Copied from/to" relation when copying issue(s) (#6899)....
r10282 return unless copy? && !@after_create_from_copy_handled
Jean-Philippe Lang
Option to copy subtasks when copying issue(s) (#6965)....
r10144
Jean-Philippe Lang
Do not link copied issues when copying a project (#6899)....
r10286 if (@copied_from.project_id == project_id || Setting.cross_project_issue_relations?) && @copy_options[:link] != false
Jean-Philippe Lang
Fixed that IssueRelation should not be responsible for calling Issue#init_journal (#18237)....
r13152 if @current_journal
@copied_from.init_journal(@current_journal.user)
end
Jean-Philippe Lang
Adds a "Copied from/to" relation when copying issue(s) (#6899)....
r10282 relation = IssueRelation.new(:issue_from => @copied_from, :issue_to => self, :relation_type => IssueRelation::TYPE_COPIED_TO)
unless relation.save
logger.error "Could not create relation while copying ##{@copied_from.id} to ##{id} due to validation errors: #{relation.errors.full_messages.join(', ')}" if logger
end
end
unless @copied_from.leaf? || @copy_options[:subtasks] == false
Jean-Philippe Lang
Fixed that copying an issue as a child of itself creates an extra issue (#13328)....
r11283 copy_options = (@copy_options || {}).merge(:subtasks => false)
copied_issue_ids = {@copied_from.id => self.id}
@copied_from.reload.descendants.reorder("#{Issue.table_name}.lft").each do |child|
# Do not copy self when copying an issue as a descendant of the copied issue
next if child == self
# Do not copy subtasks of issues that were not copied
next unless copied_issue_ids[child.parent_id]
# Do not copy subtasks that are not visible to avoid potential disclosure of private data
Jean-Philippe Lang
Option to copy subtasks when copying issue(s) (#6965)....
r10144 unless child.visible?
logger.error "Subtask ##{child.id} was not copied during ##{@copied_from.id} copy because it is not visible to the current user" if logger
next
end
Jean-Philippe Lang
Fixed that copying an issue as a child of itself creates an extra issue (#13328)....
r11283 copy = Issue.new.copy_from(child, copy_options)
Jean-Philippe Lang
Fixed that IssueRelation should not be responsible for calling Issue#init_journal (#18237)....
r13152 if @current_journal
copy.init_journal(@current_journal.user)
end
Jean-Philippe Lang
Option to copy subtasks when copying issue(s) (#6965)....
r10144 copy.author = author
copy.project = project
Jean-Philippe Lang
Fixed that copying an issue as a child of itself creates an extra issue (#13328)....
r11283 copy.parent_issue_id = copied_issue_ids[child.parent_id]
Jean-Philippe Lang
Option to copy subtasks when copying issue(s) (#6965)....
r10144 unless copy.save
logger.error "Could not copy subtask ##{child.id} while copying ##{@copied_from.id} to ##{id} due to validation errors: #{copy.errors.full_messages.join(', ')}" if logger
Jean-Philippe Lang
Fixed that copying an issue as a child of itself creates an extra issue (#13328)....
r11283 next
Jean-Philippe Lang
Option to copy subtasks when copying issue(s) (#6965)....
r10144 end
Jean-Philippe Lang
Fixed that copying an issue as a child of itself creates an extra issue (#13328)....
r11283 copied_issue_ids[child.id] = copy.id
Jean-Philippe Lang
Option to copy subtasks when copying issue(s) (#6965)....
r10144 end
end
Jean-Philippe Lang
Adds a "Copied from/to" relation when copying issue(s) (#6899)....
r10282 @after_create_from_copy_handled = true
Jean-Philippe Lang
Option to copy subtasks when copying issue(s) (#6965)....
r10144 end
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 def update_nested_set_attributes
Jean-Philippe Lang
Replaces awesome_nested_set gem with a simple and more robust implementation of nested sets....
r13459 if parent_id_changed?
Jean-Philippe Lang
Fixed that issue nested set update is triggered even if parent is not changed (#15135)....
r11996 update_nested_set_attributes_on_parent_change
end
remove_instance_variable(:@parent_issue) if instance_variable_defined?(:@parent_issue)
end
# Updates the nested set for when an existing issue is moved
def update_nested_set_attributes_on_parent_change
Jean-Philippe Lang
Replaces awesome_nested_set gem with a simple and more robust implementation of nested sets....
r13459 former_parent_id = parent_id_was
Jean-Philippe Lang
Fixed that issue nested set update is triggered even if parent is not changed (#15135)....
r11996 # delete invalid relations of all descendants
self_and_descendants.each do |issue|
issue.relations.each do |relation|
relation.destroy unless relation.valid?
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 end
end
Jean-Philippe Lang
Fixed that issue nested set update is triggered even if parent is not changed (#15135)....
r11996 # update former parent
recalculate_attributes_for(former_parent_id) if former_parent_id
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 def update_parent_attributes
Jean-Philippe Lang
Replaces awesome_nested_set gem with a simple and more robust implementation of nested sets....
r13459 if parent_id
recalculate_attributes_for(parent_id)
association(:parent).reset
end
Eric Davis
Recalculate inherited attributes on parents when a child is moved under a new parent. #5524...
r3707 end
def recalculate_attributes_for(issue_id)
if issue_id && p = Issue.find_by_id(issue_id)
Jean-Philippe Lang
Adds settings to control start/due dates and priority on parent tasks (#5490)....
r13887 if p.priority_derived?
Jean-Philippe Lang
Only consider open subtasks when computing the priority of a parent issue (#5880)....
r14682 # priority = highest priority of open children
if priority_position = p.children.open.joins(:priority).maximum("#{IssuePriority.table_name}.position")
Jean-Philippe Lang
Adds settings to control start/due dates and priority on parent tasks (#5490)....
r13887 p.priority = IssuePriority.find_by_position(priority_position)
Jean-Philippe Lang
Only consider open subtasks when computing the priority of a parent issue (#5880)....
r14682 else
p.priority = IssuePriority.default
Jean-Philippe Lang
Adds settings to control start/due dates and priority on parent tasks (#5490)....
r13887 end
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds settings to control start/due dates and priority on parent tasks (#5490)....
r13887 if p.dates_derived?
# start/due dates = lowest/highest dates of children
p.start_date = p.children.minimum(:start_date)
p.due_date = p.children.maximum(:due_date)
if p.start_date && p.due_date && p.due_date < p.start_date
p.start_date, p.due_date = p.due_date, p.start_date
end
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds a setting to control done ratio on parent tasks (#5490)....
r13888 if p.done_ratio_derived?
# done ratio = weighted average ratio of leaves
unless Issue.use_status_for_done_ratio? && p.status && p.status.default_done_ratio
Jean-Philippe Lang
Calculate done_ratio based on children instead of leaves (#20995)....
r14493 child_count = p.children.count
if child_count > 0
average = p.children.where("estimated_hours > 0").average(:estimated_hours).to_f
Jean-Philippe Lang
Adds a setting to control done ratio on parent tasks (#5490)....
r13888 if average == 0
average = 1
end
Jean-Philippe Lang
Calculate done_ratio based on children instead of leaves (#20995)....
r14493 done = p.children.joins(:status).
Jean-Philippe Lang
Adds a setting to control done ratio on parent tasks (#5490)....
r13888 sum("COALESCE(CASE WHEN estimated_hours > 0 THEN estimated_hours ELSE NULL END, #{average}) " +
"* (CASE WHEN is_closed = #{self.class.connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f
Jean-Philippe Lang
Calculate done_ratio based on children instead of leaves (#20995)....
r14493 progress = done / (average * child_count)
Jean-Philippe Lang
Adds a setting to control done ratio on parent tasks (#5490)....
r13888 p.done_ratio = progress.round
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 end
end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 # ancestors will be recursively updated
Jean-Philippe Lang
Merged rails-3.2 branch....
r9346 p.save(:validate => false)
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Optimize updates of issue's shared versions....
r3023 # Update issues so their versions are not pointing to a
# fixed_version that is not shared with the issue's project
def self.update_versions(conditions=nil)
# Only need to update issues with a fixed_version from
# a different project and that is not systemwide shared
Jean-Philippe Lang
Merged rails-4.1 branch (#14534)....
r13100 Issue.joins(:project, :fixed_version).
Jean-Philippe Lang
Cleanup of finders with :conditions option....
r11733 where("#{Issue.table_name}.fixed_version_id IS NOT NULL" +
Jean-Philippe Lang
Use scoped method instead of merge_conditions....
r8170 " AND #{Issue.table_name}.project_id <> #{Version.table_name}.project_id" +
Jean-Philippe Lang
Cleanup of finders with :conditions option....
r11733 " AND #{Version.table_name}.sharing <> 'system'").
where(conditions).each do |issue|
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009 next if issue.project.nil? || issue.fixed_version.nil?
unless issue.project.shared_versions.include?(issue.fixed_version)
issue.init_journal(User.current)
issue.fixed_version = nil
issue.save
end
end
end
Toshi MARUYAMA
remove trailing white-spaces except SQL from app/models/issue.rb....
r6396
Etienne Massip
Fixed comment....
r10194 # Callback on file attachment
Jean-Philippe Lang
Moved journal details generation to Journal model....
r13321 def attachment_added(attachment)
if current_journal && !attachment.new_record?
current_journal.journalize_attachment(attachment, :added)
Jean-Philippe Lang
Fixed: MailHandler does not include JournalDetail for attached files (#7966)....
r6192 end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
AttachmentsController now handles attachments deletion....
r2114 # Callback on attachment deletion
Jean-Philippe Lang
Moved journal details generation to Journal model....
r13321 def attachment_removed(attachment)
if current_journal && !attachment.new_record?
current_journal.journalize_attachment(attachment, :removed)
current_journal.save
Jean-Philippe Lang
Rails 3.1 compatibility....
r8953 end
Jean-Philippe Lang
AttachmentsController now handles attachments deletion....
r2114 end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Fixed that IssueRelation should not be responsible for calling Issue#init_journal (#18237)....
r13152 # Called after a relation is added
def relation_added(relation)
Jean-Philippe Lang
Moved journal details generation to Journal model....
r13321 if current_journal
current_journal.journalize_relation(relation, :added)
current_journal.save
Jean-Philippe Lang
Fixed that IssueRelation should not be responsible for calling Issue#init_journal (#18237)....
r13152 end
end
# Called after a relation is removed
def relation_removed(relation)
Jean-Philippe Lang
Moved journal details generation to Journal model....
r13321 if current_journal
current_journal.journalize_relation(relation, :removed)
current_journal.save
Jean-Philippe Lang
Fixed that IssueRelation should not be responsible for calling Issue#init_journal (#18237)....
r13152 end
end
Jean-Philippe Lang
Fixed: journal details duplicated when an issue is saved twice (#3690)....
r3385 # Default assignment based on category
def default_assign
if assigned_to.nil? && category && category.assigned_to
self.assigned_to = category.assigned_to
end
end
# Updates start/due dates of following issues
def reschedule_following_issues
if start_date_changed? || due_date_changed?
relations_from.each do |relation|
relation.set_issue_to_dates
end
end
end
# Closes duplicates if the issue is being closed
def close_duplicates
if closing?
duplicates.each do |duplicate|
Toshi MARUYAMA
fix typos of source comments at Issue model...
r12798 # Reload is needed in case the duplicate was updated by a previous duplicate
Jean-Philippe Lang
Fixed: journal details duplicated when an issue is saved twice (#3690)....
r3385 duplicate.reload
# Don't re-close it if it's already closed
next if duplicate.closed?
# Same user and notes
if @current_journal
duplicate.init_journal(@current_journal.user, @current_journal.notes)
Jean-Philippe Lang
Private notes get copied without private flag to Duplicate issues (#22072)....
r14814 duplicate.private_notes = @current_journal.private_notes
Jean-Philippe Lang
Fixed: journal details duplicated when an issue is saved twice (#3690)....
r3385 end
duplicate.update_attribute :status, self.status
end
end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds closed_on column that stores the time of the last closing (#824)....
r11172 # Make sure updated_on is updated when adding a note and set updated_on now
# so we can set closed_on with the same value on closing
Jean-Philippe Lang
Fixed that updated_on is not updated when updating an issue (#10964)....
r9520 def force_updated_on_change
Jean-Philippe Lang
Adds closed_on column that stores the time of the last closing (#824)....
r11172 if @current_journal || changed?
Jean-Philippe Lang
Fixed that updated_on is not updated when updating an issue (#10964)....
r9520 self.updated_on = current_time_from_proper_timezone
Jean-Philippe Lang
Adds closed_on column that stores the time of the last closing (#824)....
r11172 if new_record?
self.created_on = updated_on
end
end
end
# Callback for setting closed_on when the issue is closed.
# The closed_on attribute stores the time of the last closing
# and is preserved when the issue is reopened.
def update_closed_on
Jean-Philippe Lang
Code cleanup....
r13126 if closing?
Jean-Philippe Lang
Adds closed_on column that stores the time of the last closing (#824)....
r11172 self.closed_on = updated_on
Jean-Philippe Lang
Fixed that updated_on is not updated when updating an issue (#10964)....
r9520 end
end
Jean-Philippe Lang
Create the journal after issue save (#3140)....
r2577 # Saves the changes in a Journal
# Called after_save
def create_journal
Jean-Philippe Lang
Moved journal details generation to Journal model....
r13321 if current_journal
current_journal.save
Jean-Philippe Lang
Create the journal after issue save (#3140)....
r2577 end
end
Eric Davis
Refactor: Extracted the select_all calls to a new private method....
r3251
Jean-Philippe Lang
Use AR callbacks instead of observers (removed in Rails4) for notifications....
r11791 def send_notification
Jean-Philippe Lang
Import issues from CSV file (#950)....
r14111 if notify? && Setting.notified_events.include?('issue_added')
Jean-Philippe Lang
Use AR callbacks instead of observers (removed in Rails4) for notifications....
r11791 Mailer.deliver_issue_add(self)
end
end
Jean-Philippe Lang
Fixed that previous assignee is not notified on issue update (#15714)....
r12144 # Stores the previous assignee so we can still have access
# to it during after_save callbacks (assigned_to_id_was is reset)
def set_assigned_to_was
@previous_assigned_to_id = assigned_to_id_was
end
# Clears the previous assignee at the end of after_save callbacks
def clear_assigned_to_was
@assigned_to_was = nil
@previous_assigned_to_id = nil
end
Jean-Philippe Lang
When changing tracker, clear the attributes that are disabled for the new tracker (#17527)....
r13798
def clear_disabled_fields
if tracker
tracker.disabled_core_fields.each do |attribute|
send "#{attribute}=", nil
end
Jean-Philippe Lang
Fixed that issue validation fails if % done field is deactivated (#19731)....
r13859 self.done_ratio ||= 0
Jean-Philippe Lang
When changing tracker, clear the attributes that are disabled for the new tracker (#17527)....
r13798 end
end
Jean-Philippe Lang
Initial commit...
r2 end