##// END OF EJS Templates
When copying issues, let the status be changed to default or left unchanged....
When copying issues, let the status be changed to default or left unchanged. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@9404 e93f8b46-1217-0410-a6f0-8f06a7374b81

File last commit:

r9270:09375960d69d
r9270:09375960d69d
Show More
issue.rb
1078 lines | 37.9 KiB | text/x-ruby | RubyLexer
Jean-Philippe Lang
Keep track of issue description changes (#746)....
r4834 # Redmine - project management software
# Copyright (C) 2006-2011 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
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
belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
Jean-Philippe Lang
Ability to assign issues to groups (#2964)....
r6186 belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id'
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id'
Eric Davis
Changed Enumerations to use a Single Table Inheritance...
r2677 belongs_to :priority, :class_name => 'IssuePriority', :foreign_key => 'priority_id'
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id'
has_many :journals, :as => :journalized, :dependent => :destroy
Jean-Philippe Lang
Let the user choose when deleting issues with reported hours (closes #734, #71):...
r1168 has_many :time_entries, :dependent => :delete_all
Jean-Philippe Lang
Fixed: associated revisions are displayed in wrong order on issue view (#1546)....
r1582 has_and_belongs_to_many :changesets, :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: subtasks are deleted (not destroyed) when destroying parent issue (#7385)....
r4615 acts_as_nested_set :scope => 'root_id', :dependent => :destroy
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 engine: display total results count (#906) and count by result type....
r1664 acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"],
:include => [:project, :journals],
# sort by id so that limited eager loading doesn't break with postgresql
:order_column => "#{table_name}.id"
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
Display latest user's activity on account/show view....
r2064 acts_as_activity_provider :find_options => {:include => [:project, :author, :tracker]},
: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
Eric Davis
Adds named scopes to replace custom finders....
r3443
Jean-Philippe Lang
Makes issue description a non-required field (#2456)....
r2244 validates_presence_of :subject, :priority, :project, :tracker, :author, :status
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
Added 'Estimated hours' attribute on issues....
r720 validates_numericality_of :estimated_hours, :allow_nil => true
Toshi MARUYAMA
Rails3: model: replace deprecated 'validate' method at Issue model...
r7309 validate :validate_issue
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330
Jean-Philippe Lang
Fixed that 'My page' blocks may display issues that the user is no longer allowed to view (#2590)....
r2320 named_scope :visible, lambda {|*args| { :include => :project,
Jean-Philippe Lang
Makes visible scopes accept projects option and deprecate Project.visible_by....
r5204 :conditions => Issue.visible_condition(args.shift || User.current, *args) } }
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Use open scope in version issues count methods....
r8165 named_scope :open, lambda {|*args|
is_closed = args.size > 0 ? !args.first : false
{:conditions => ["#{IssueStatus.table_name}.is_closed = ?", is_closed], :include => :status}
}
Eric Davis
Adds a Setting to control how an Issue's done_ratio is calculated:...
r3037
Eric Davis
Rewrite the Gantt chart. #6276...
r3958 named_scope :recently_updated, :order => "#{Issue.table_name}.updated_on DESC"
Eric Davis
Adds named scopes to replace custom finders....
r3443 named_scope :with_limit, lambda { |limit| { :limit => limit} }
named_scope :on_active_project, :include => [:status, :project, :tracker],
:conditions => ["#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"]
Eric Davis
Rewrite the Gantt chart. #6276...
r3958
Jean-Philippe Lang
Fixed: journal details duplicated when an issue is saved twice (#3690)....
r3385 before_create :default_assign
Jean-Philippe Lang
Fixed: precedes/follows relations no longer update start/due dates (#5803)....
r4149 before_save :close_duplicates, :update_done_ratio_from_issue_status
Jean-Philippe Lang
Extracted some code from #move_to_project to a callback....
r8404 after_save {|issue| issue.send :after_project_change if !issue.id_changed? && issue.project_id_changed?}
Jean-Philippe Lang
Fixed: precedes/follows relations no longer update start/due dates (#5803)....
r4149 after_save :reschedule_following_issues, :update_nested_set_attributes, :update_parent_attributes, :create_journal
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 after_destroy :update_parent_attributes
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|
case role.issues_visibility
Jean-Philippe Lang
Private issues (#7414)....
r5346 when 'all'
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 nil
Jean-Philippe Lang
Private issues (#7414)....
r5346 when 'default'
Jean-Philippe Lang
Ability to assign issues to groups (#2964)....
r6186 user_ids = [user.id] + user.groups.map(&:id)
Jean-Philippe Lang
Fixed: User with groups may not see issues assigned to him or to its groups (#9478)....
r7651 "(#{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
Adds an issues visibility level on roles (#7412)....
r5296 when 'own'
Jean-Philippe Lang
Ability to assign issues to groups (#2964)....
r6186 user_ids = [user.id] + user.groups.map(&:id)
Jean-Philippe Lang
Fixed: User with groups may not see issues assigned to him or to its groups (#9478)....
r7651 "(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 else
'1=0'
end
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|
case role.issues_visibility
Jean-Philippe Lang
Private issues (#7414)....
r5346 when 'all'
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 true
Jean-Philippe Lang
Private issues (#7414)....
r5346 when 'default'
Jean-Philippe Lang
Ability to assign issues to groups (#2964)....
r6186 !self.is_private? || self.author == user || user.is_or_belongs_to?(assigned_to)
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 when 'own'
Jean-Philippe Lang
Ability to assign issues to groups (#2964)....
r6186 self.author == user || user.is_or_belongs_to?(assigned_to)
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 else
false
end
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
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
self.status ||= IssueStatus.default
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
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
Save queries....
r5125 (project && tracker) ? (project.all_issue_custom_fields & tracker.custom_fields.all) : []
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
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
self.attachments = issue.attachments.map do |attachement|
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
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
def copy(attributes=nil)
copy = self.class.new.copy_from(self)
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
Adds ability to bulk copy issues (#1847)....
r2311 # Moves/copies an issue to a new project and tracker
# Returns the moved/copied issue on success, false on failure
Jean-Philippe Lang
Code cleanup....
r8407 def move_to_project(new_project, new_tracker=nil, options={})
Jean-Philippe Lang
Deprecated Issue#move_to_project....
r8419 ActiveSupport::Deprecation.warn "Issue#move_to_project is deprecated, use #project= instead."
Etienne Massip
Save an @Issue#save@....
r8092 if options[:copy]
Jean-Philippe Lang
Deprecated Issue#move_to_project....
r8419 issue = self.copy
Etienne Massip
Save an @Issue#save@....
r8092 else
issue = self
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Code cleanup....
r8406 issue.init_journal(User.current, options[:notes])
Jean-Philippe Lang
Allows project to be changed from the regular issue update action (#4769, #9803)....
r8411 # Preserve previous behaviour
# #move_to_project doesn't change tracker automatically
issue.send :project=, new_project, true
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 if new_tracker
issue.tracker = new_tracker
end
# Allow bulk setting of attributes on the issue
if options[:attributes]
issue.attributes = options[:attributes]
end
Jean-Philippe Lang
Code cleanup....
r8406
Jean-Philippe Lang
Code cleanup....
r8407 issue.save ? issue : false
Jean-Philippe Lang
Fixed: Update of time entry fails when the issue has been moved to an other project....
r896 end
Jean-Philippe Lang
Cleans up status assignment in IssuesController#new handled by Issue#safe_attributes= now....
r3492
def status_id=(sid)
self.status = nil
write_attribute(:status_id, sid)
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
Enable tracker update on issue edit form (#2405)....
r2994 def tracker_id=(tid)
self.tracker = nil
Jean-Philippe Lang
Fixes tracker_id and custom_field_values assignment order for issues (#4353)....
r3025 result = write_attribute(:tracker_id, tid)
@custom_field_values = nil
result
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
end
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
write_attribute(:project_id, project ? project.id : nil)
association_instance_set('project', project)
if project_was && project && project_was != project
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
if parent && parent.project_id != project_id
self.parent_issue_id = nil
end
@custom_field_values = nil
end
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
Makes project and tracker assigned first in #attributes=...
r8011 # Overrides attributes= so that project and tracker get assigned first
def 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
Makes project and tracker assigned first in #attributes=...
r8011 send :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
Makes project and tracker assigned first in #attributes=...
r8011 alias_method_chain(:attributes=, :project_and_tracker_first) unless method_defined?(:attributes_without_project_and_tracker_first=)
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
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',
:if => lambda {|issue, user|
Jean-Philippe Lang
Use the regular issue form to copy a single issue....
r8432 if issue.new_record?
issue.copy?
elsif user.allowed_to?(:move_issues, issue.project)
Jean-Philippe Lang
Check permission before retrieving projects....
r8412 projects = Issue.allowed_target_projects_on_move(user)
projects.include?(issue.project) && projects.size > 1
end
Jean-Philippe Lang
Allows project to be changed from the regular issue update action (#4769, #9803)....
r8411 }
Jean-Philippe Lang
Makes issue safe_attributes extensible (#6000)....
r4377 safe_attributes 'tracker_id',
'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',
:if => lambda {|issue, user| issue.new_record? || user.allowed_to?(:edit_issues, issue.project) }
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Makes issue safe_attributes extensible (#6000)....
r4377 safe_attributes 'status_id',
'assigned_to_id',
'fixed_version_id',
'done_ratio',
Jean-Philippe Lang
Display issue form fields according to permissions....
r8107 'lock_version',
Jean-Philippe Lang
Makes issue safe_attributes extensible (#6000)....
r4377 :if => lambda {|issue, user| issue.new_statuses_allowed_to(user).any? }
Jean-Philippe Lang
Moved some permission checks for issue update from controller to model....
r4279
Jean-Philippe Lang
Use safe_attributes for issue watchers assignment....
r8077 safe_attributes 'watcher_user_ids',
:if => lambda {|issue, user| issue.new_record? && user.allowed_to?(:add_issue_watchers, issue.project)}
Jean-Philippe Lang
Private issues (#7414)....
r5346 safe_attributes 'is_private',
:if => lambda {|issue, user|
user.allowed_to?(:set_issues_private, issue.project) ||
(issue.author == user && user.allowed_to?(:set_own_issues_private, issue.project))
}
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Code cleanup....
r8078 safe_attributes 'parent_issue_id',
:if => lambda {|issue, user| (issue.new_record? || user.allowed_to?(:edit_issues, issue.project)) &&
user.allowed_to?(:manage_subtasks, issue.project)}
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
Moved some permission checks for issue update from controller to model....
r4279 # User can change issue attributes only if he has :edit permission or if a workflow transition is allowed
Jean-Philippe Lang
Makes issue safe_attributes extensible (#6000)....
r4377 attrs = delete_unsafe_attributes(attrs, user)
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690 return if attrs.empty?
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.
if p = attrs.delete('project_id')
Jean-Philippe Lang
Check project assignment on issue copy/move....
r8433 if allowed_target_projects(user).collect(&:id).include?(p.to_i)
self.project_id = p
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
Makes MailHandler accept all issue attributes and custom fields that can be set/updated (#4071, #4807, #5622, #6110)....
r4280 if t = attrs.delete('tracker_id')
self.tracker_id = t
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Bulk edit refactoring....
r3364 if attrs['status_id']
Jean-Philippe Lang
Makes MailHandler accept all issue attributes and custom fields that can be set/updated (#4071, #4807, #5622, #6110)....
r4280 unless new_statuses_allowed_to(user).collect(&:id).include?(attrs['status_id'].to_i)
Jean-Philippe Lang
Bulk edit refactoring....
r3364 attrs.delete('status_id')
end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 unless leaf?
attrs.reject! {|k,v| %w(priority_id done_ratio start_date due_date estimated_hours).include?(k)}
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Code cleanup....
r8078 if attrs['parent_issue_id'].present?
attrs.delete('parent_issue_id') unless Issue.visible(user).exists?(attrs['parent_issue_id'].to_i)
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
Use safe_attributes for issue watchers assignment....
r8077 # mass-assignment security bypass
self.send :attributes=, attrs, false
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
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
added svn:eol-style native property on /app files...
r330 if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty?
Jean-Philippe Lang
Merged Rails 2.2 branch. Redmine now requires Rails 2.2.2....
r2430 errors.add :due_date, :not_a_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
added svn:eol-style native property on /app files...
r330 if self.due_date and self.start_date and self.due_date < self.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
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 if start_date && soonest_start && start_date < soonest_start
Jean-Philippe Lang
Merged Rails 2.2 branch. Redmine now requires Rails 2.2.2....
r2430 errors.add :start_date, :invalid
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
elsif reopened? && 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?)
unless project.trackers.include?(tracker)
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
if @parent_issue
if @parent_issue.project_id != project_id
errors.add :parent_issue_id, :not_same_project
elsif !new_record?
# moving an existing issue
if @parent_issue.root_id != root_id
# we can always move to another tree
elsif move_possible?(@parent_issue)
# move accepted inside tree
else
errors.add :parent_issue_id, :not_a_valid_parent
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
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)
Jean-Philippe Lang
Code cleanup....
r8406 if new_record?
@current_journal.notify = false
else
@attributes_before_change = attributes.dup
@custom_values_before_change = {}
Jean-Philippe Lang
Adds support for multiselect custom fields (#1189)....
r8601 self.custom_field_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value }
Jean-Philippe Lang
Code cleanup....
r8406 end
Jean-Philippe Lang
Fixed: Issue updated_on is not updated when a user adds a note with no edit privilege....
r1757 # Make sure updated_on is updated when adding a note.
updated_on_will_change!
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 @current_journal
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
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
journals.first(:order => "#{Journal.table_name}.id DESC").try(:id)
end
end
Jean-Philippe Lang
Automatic closing of duplicate issues....
r657 # Return true if the issue is closed, otherwise false
def closed?
self.status.is_closed?
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 # Return true if the issue is being reopened
def reopened?
if !new_record? && status_id_changed?
status_was = IssueStatus.find_by_id(status_id_was)
status_new = IssueStatus.find_by_id(status_id)
if status_was && status_new && status_was.is_closed? && !status_new.is_closed?
return true
end
end
false
end
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?
if !new_record? && status_id_changed?
status_was = IssueStatus.find_by_id(status_id_was)
status_new = IssueStatus.find_by_id(status_id)
if status_was && status_new && !status_was.is_closed? && status_new.is_closed?
return true
end
end
false
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
Closed issue are not overdue, fixes r2140 (#2337)....
r2357 !due_date.nil? && (due_date < Date.today) && !status.is_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?
done_date = start_date + ((due_date - start_date+1)* done_ratio/100).floor
return done_date <= Date.today
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
Eric Davis
Allow assigning issues back to the author. #4199...
r4126 users = project.assignable_users
users << author if author
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
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009 @assignable_versions ||= (project.shared_versions.open + [Version.find_by_id(fixed_version_id_was)]).compact.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
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
[IssueStatus.default, @copied_from.status].compact.uniq.sort
else
initial_status = nil
if new_record?
initial_status = IssueStatus.default
elsif status_id_was
initial_status = IssueStatus.find_by_id(status_id_was)
end
initial_status ||= status
statuses = initial_status.find_new_statuses_allowed_to(
user.admin ? Role.all : user.roles_for_project(project),
tracker,
author == user,
assigned_to_id_changed? ? assigned_to_id_was == user.id : assigned_to_id == user.id
)
statuses << initial_status unless statuses.empty?
statuses << IssueStatus.default if include_default
statuses = statuses.compact.uniq.sort
blocked? ? statuses.reject {|s| s.is_closed?} : statuses
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
Notify previous assignee when assignee changes (#2694)....
r8575 def assigned_to_was
if assigned_to_id_changed? && assigned_to_id_was.present?
@assigned_to_was ||= User.find_by_id(assigned_to_id_was)
end
end
Jean-Philippe Lang
Do not notify users that are no longer allowed to view an issue (#3589, #4263)....
r3007 # Returns the mail adresses of users that should be notified
Jean-Philippe Lang
More flexible mail notifications settings at user level. A user has now 3 options:...
r842 def recipients
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)}
notified.collect(&:mail)
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
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
Eric Davis
Added some RDoc documentation for some models....
r2536 #
# Example:
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 # spent_hours => 0.0
# spent_hours => 50.2
Jean-Philippe Lang
Makes spent time column available on the issue list (#971)....
r7953 def total_spent_hours
Jean-Philippe Lang
Rails3.1 compatibility...
r8155 @total_spent_hours ||= self_and_descendants.sum("#{TimeEntry.table_name}.hours",
:joins => "LEFT JOIN #{TimeEntry.table_name} ON #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id").to_f || 0.0
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
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 def relations
Jean-Philippe Lang
Ability to load relations on /issues API (#7366)....
r6193 @relations ||= (relations_from + relations_to).sort
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?
relations = IssueRelation.all(:conditions => ["issue_from_id IN (:ids) OR issue_to_id IN (:ids)", {:ids => issues.map(&:id)}])
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
Makes spent time column available on the issue list (#971)....
r7953 # Preloads visible spent time for a collection of issues
def self.load_visible_spent_hours(issues, user=User.current)
if issues.any?
hours_by_issue_id = TimeEntry.visible(user).sum(:hours, :group => :issue_id)
issues.each do |issue|
issue.instance_variable_set "@spent_hours", (hours_by_issue_id[issue.id] || 0)
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)
IssueRelation.find(relation_id, :conditions => ["issue_to_id = ? OR issue_from_id = ?", id, id])
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Prevent SystemStackError on Issue#all_dependent_issues with mutiple circular dependencies (#7320)....
r4984 def all_dependent_issues(except=[])
except << self
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 dependencies = []
relations_from.each do |relation|
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690 if relation.issue_to && !except.include?(relation.issue_to)
Jean-Philippe Lang
Prevent SystemStackError on Issue#all_dependent_issues with circular dependency (#7320)....
r4603 dependencies << relation.issue_to
dependencies += relation.issue_to.all_dependent_issues(except)
end
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 end
dependencies
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
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 def soonest_start
Jean-Philippe Lang
Makes subtasks rescheduled when a 'precedes' relation is set on a parent task....
r3460 @soonest_start ||= (
relations_to.collect{|relation| relation.successor_soonest_start} +
ancestors.collect(&:soonest_start)
).compact.max
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Makes subtasks rescheduled when a 'precedes' relation is set on a parent task....
r3460 def reschedule_after(date)
return if date.nil?
if leaf?
if start_date.nil? || start_date < date
self.start_date, self.due_date = date, date + duration
Jean-Philippe Lang
Prevent ActiveRecord::StaleObjectError in Issue#reschedule_after (#7920)....
r8744 begin
save
rescue ActiveRecord::StaleObjectError
reload
self.start_date, self.due_date = date, date + duration
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|
leaf.reschedule_after(date)
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 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
def css_classes
s = "issue status-#{status.position} priority-#{priority.position}"
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 more css classes to the roadmap issues (#3214)....
r2602 s << ' created-by-me' if User.current.logged? && author_id == User.current.id
s << ' assigned-to-me' if User.current.logged? && assigned_to_id == User.current.id
s
end
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009
Jean-Philippe Lang
Better handling of attachments when issue validation fails (#10253)....
r8771 # Saves an issue and a time_entry from the parameters
Eric Davis
Refactor: Moved the contents of #issue_update into Issue....
r3431 def save_issue_with_child_records(params, existing_time_entry=nil)
Jean-Philippe Lang
Fixes Issue#save_issue_with_child_records so that time entry do not get saved if issue save fails....
r3550 Issue.transaction do
Jean-Philippe Lang
Check for a valid time entry if comments have been entered when updating an issue (#7581)....
r4990 if params[:time_entry] && (params[:time_entry][:hours].present? || params[:time_entry][:comments].present?) && User.current.allowed_to?(:log_time, project)
Jean-Philippe Lang
Fixes Issue#save_issue_with_child_records so that time entry do not get saved if issue save fails....
r3550 @time_entry = existing_time_entry || TimeEntry.new
@time_entry.project = project
@time_entry.issue = self
@time_entry.user = User.current
Jean-Philippe Lang
Use user's time zone when logging time while editing ticket (#9619)....
r7798 @time_entry.spent_on = User.current.today
Jean-Philippe Lang
Fixes Issue#save_issue_with_child_records so that time entry do not get saved if issue save fails....
r3550 @time_entry.attributes = params[:time_entry]
self.time_entries << @time_entry
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Better handling of attachments when issue validation fails (#10253)....
r8771 # TODO: Rename hook
Redmine::Hook.call_hook(:controller_issues_edit_before_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal})
if save
Jean-Philippe Lang
Fixes Issue#save_issue_with_child_records so that time entry do not get saved if issue save fails....
r3550 # TODO: Rename hook
Jean-Philippe Lang
Better handling of attachments when issue validation fails (#10253)....
r8771 Redmine::Hook.call_hook(:controller_issues_edit_after_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal})
else
raise ActiveRecord::Rollback
Eric Davis
Refactor: Moved the contents of #issue_update into Issue....
r3431 end
end
end
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
Issue.update_versions(["#{Version.table_name}.project_id IN (?) OR #{Issue.table_name}.project_id IN (?)", moved_project_ids, moved_project_ids])
end
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 def parent_issue_id=(arg)
parent_issue_id = arg.blank? ? nil : arg.to_i
if parent_issue_id && @parent_issue = Issue.find_by_id(parent_issue_id)
@parent_issue.id
else
@parent_issue = nil
nil
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
if instance_variable_defined? :@parent_issue
@parent_issue.nil? ? nil : @parent_issue.id
else
parent_id
end
end
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 # Extracted from the ReportsController.
def self.by_tracker(project)
Eric Davis
Refactor: Extracted the select_all calls to a new private method....
r3251 count_and_group_by(:project => project,
:field => 'tracker_id',
:joins => Tracker.table_name)
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 end
def self.by_version(project)
Eric Davis
Refactor: Extracted the select_all calls to a new private method....
r3251 count_and_group_by(:project => project,
:field => 'fixed_version_id',
:joins => Version.table_name)
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 end
def self.by_priority(project)
Eric Davis
Refactor: Extracted the select_all calls to a new private method....
r3251 count_and_group_by(:project => project,
:field => 'priority_id',
:joins => IssuePriority.table_name)
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 end
def self.by_category(project)
Eric Davis
Refactor: Extracted the select_all calls to a new private method....
r3251 count_and_group_by(:project => project,
:field => 'category_id',
:joins => IssueCategory.table_name)
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 end
def self.by_assigned_to(project)
Eric Davis
Refactor: Extracted the select_all calls to a new private method....
r3251 count_and_group_by(:project => project,
:field => 'assigned_to_id',
:joins => User.table_name)
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 end
def self.by_author(project)
Eric Davis
Refactor: Extracted the select_all calls to a new private method....
r3251 count_and_group_by(:project => project,
:field => 'author_id',
:joins => User.table_name)
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 end
def self.by_subproject(project)
ActiveRecord::Base.connection.select_all("select s.id as status_id,
s.is_closed as closed,
Jean-Philippe Lang
Adds visibility condition to Issue.by_* count methods....
r5245 #{Issue.table_name}.project_id as project_id,
count(#{Issue.table_name}.id) as total
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 from
Jean-Philippe Lang
Adds visibility condition to Issue.by_* count methods....
r5245 #{Issue.table_name}, #{Project.table_name}, #{IssueStatus.table_name} s
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 where
Jean-Philippe Lang
Adds visibility condition to Issue.by_* count methods....
r5245 #{Issue.table_name}.status_id=s.id
and #{Issue.table_name}.project_id = #{Project.table_name}.id
and #{visible_condition(User.current, :project => project, :with_subprojects => true)}
and #{Issue.table_name}.project_id <> #{project.id}
group by s.id, s.is_closed, #{Issue.table_name}.project_id") if project.descendants.active.any?
Eric Davis
Refactor: Moved the raw SQL finders from ReportsController to Issue....
r3248 end
# End ReportsController extraction
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Check project assignment on issue copy/move....
r8433 # Returns an array of projects that user can assign the issue to
def allowed_target_projects(user=User.current)
if new_record?
Project.all(:conditions => Project.allowed_to_condition(user, :add_issues))
else
self.class.allowed_target_projects_on_move(user)
end
end
# Returns an array of projects that user can move issues to
Jean-Philippe Lang
Allows project to be changed from the regular issue update action (#4769, #9803)....
r8411 def self.allowed_target_projects_on_move(user=User.current)
Jean-Philippe Lang
Fixed that issues can be moved to projects with issue tracking disabled (#10467)....
r9139 Project.all(:conditions => Project.allowed_to_condition(user, :move_issues))
Jean-Philippe Lang
Fixes behaviour of move_issues permission for non member role (#5309)....
r3569 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
Extracted some code from #move_to_project to a callback....
r8404 def after_project_change
# Update project_id on related time entries
TimeEntry.update_all(["project_id = ?", project_id], {:issue_id => id})
# Delete issue relations
unless Setting.cross_project_issue_relations?
relations_from.clear
relations_to.clear
end
# Move subtasks
children.each do |child|
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 subtasking (#443) including:...
r3459 def update_nested_set_attributes
if root_id.nil?
# issue was just created
self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id)
set_default_left_and_right
Issue.update_all("root_id = #{root_id}, lft = #{lft}, rgt = #{rgt}", ["id = ?", id])
if @parent_issue
move_to_child_of(@parent_issue)
end
reload
elsif parent_issue_id != parent_id
Eric Davis
Recalculate inherited attributes on parents when a child is moved under a new parent. #5524...
r3707 former_parent_id = parent_id
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 # moving an existing issue
if @parent_issue && @parent_issue.root_id == root_id
# inside the same tree
move_to_child_of(@parent_issue)
else
# to another tree
unless root?
move_to_right_of(root)
reload
end
old_root_id = root_id
self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id )
target_maxright = nested_set_scope.maximum(right_column_name) || 0
offset = target_maxright + 1 - lft
Issue.update_all("root_id = #{root_id}, lft = lft + #{offset}, rgt = rgt + #{offset}",
["root_id = ? AND lft >= ? AND rgt <= ? ", old_root_id, lft, rgt])
self[left_column_name] = lft + offset
self[right_column_name] = rgt + offset
if @parent_issue
move_to_child_of(@parent_issue)
end
end
reload
# delete invalid relations of all descendants
self_and_descendants.each do |issue|
issue.relations.each do |relation|
relation.destroy unless relation.valid?
end
end
Eric Davis
Recalculate inherited attributes on parents when a child is moved under a new parent. #5524...
r3707 # update former parent
recalculate_attributes_for(former_parent_id) if former_parent_id
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 end
remove_instance_variable(:@parent_issue) if instance_variable_defined?(:@parent_issue)
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
Eric Davis
Recalculate inherited attributes on parents when a child is moved under a new parent. #5524...
r3707 recalculate_attributes_for(parent_id) if parent_id
end
def recalculate_attributes_for(issue_id)
if issue_id && p = Issue.find_by_id(issue_id)
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 # priority = highest priority of children
Jean-Philippe Lang
Use :joins instead of :include in calculations....
r8262 if priority_position = p.children.maximum("#{IssuePriority.table_name}.position", :joins => :priority)
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 p.priority = IssuePriority.find_by_position(priority_position)
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 # 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
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 # done ratio = weighted average ratio of leaves
Eric Davis
Fixes reverting an issue to a status with a done_ratio of 0%. #5170...
r4072 unless Issue.use_status_for_done_ratio? && p.status && p.status.default_done_ratio
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 leaves_count = p.leaves.count
if leaves_count > 0
average = p.leaves.average(:estimated_hours).to_f
if average == 0
average = 1
end
Jean-Philippe Lang
Use :joins instead of :include in calculations....
r8262 done = p.leaves.sum("COALESCE(estimated_hours, #{average}) * (CASE WHEN is_closed = #{connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)", :joins => :status).to_f
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 progress = done / (average * leaves_count)
p.done_ratio = progress.round
end
end
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 # estimate = sum of leaves estimates
p.estimated_hours = p.leaves.sum(:estimated_hours).to_f
p.estimated_hours = nil if p.estimated_hours == 0.0
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
p.save(false)
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
Use scoped method instead of merge_conditions....
r8170 Issue.scoped(:conditions => conditions).all(
:conditions => "#{Issue.table_name}.fixed_version_id IS NOT NULL" +
" AND #{Issue.table_name}.project_id <> #{Version.table_name}.project_id" +
" AND #{Version.table_name}.sharing <> 'system'",
:include => [:project, :fixed_version]
).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
Jean-Philippe Lang
Fixed: MailHandler does not include JournalDetail for attached files (#7966)....
r6192 # Callback on attachment deletion
def attachment_added(obj)
if @current_journal && !obj.new_record?
@current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => obj.id, :value => obj.filename)
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
def attachment_removed(obj)
Jean-Philippe Lang
Rails 3.1 compatibility....
r8953 if @current_journal && !obj.new_record?
@current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => obj.id, :old_value => obj.filename)
@current_journal.save
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: 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|
# Reload is need in case the duplicate was updated by a previous duplicate
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)
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
Create the journal after issue save (#3140)....
r2577 # Saves the changes in a Journal
# Called after_save
def create_journal
if @current_journal
# attributes changes
Jean-Philippe Lang
Code cleanup....
r8406 if @attributes_before_change
(Issue.column_names - %w(id root_id lft rgt lock_version created_on updated_on)).each {|c|
before = @attributes_before_change[c]
after = send(c)
next if before == after || (before.blank? && after.blank?)
@current_journal.details << JournalDetail.new(:property => 'attr',
:prop_key => c,
:old_value => before,
:value => after)
}
end
if @custom_values_before_change
# custom fields changes
Jean-Philippe Lang
Adds support for multiselect custom fields (#1189)....
r8601 custom_field_values.each {|c|
Jean-Philippe Lang
Code cleanup....
r8406 before = @custom_values_before_change[c.custom_field_id]
after = c.value
next if before == after || (before.blank? && after.blank?)
Jean-Philippe Lang
Adds support for multiselect custom fields (#1189)....
r8601
if before.is_a?(Array) || after.is_a?(Array)
before = [before] unless before.is_a?(Array)
after = [after] unless after.is_a?(Array)
# values removed
(before - after).reject(&:blank?).each do |value|
@current_journal.details << JournalDetail.new(:property => 'cf',
:prop_key => c.custom_field_id,
:old_value => value,
:value => nil)
end
# values added
(after - before).reject(&:blank?).each do |value|
@current_journal.details << JournalDetail.new(:property => 'cf',
:prop_key => c.custom_field_id,
:old_value => nil,
:value => value)
end
else
@current_journal.details << JournalDetail.new(:property => 'cf',
:prop_key => c.custom_field_id,
:old_value => before,
:value => after)
end
Jean-Philippe Lang
Code cleanup....
r8406 }
end
Jean-Philippe Lang
Create the journal after issue save (#3140)....
r2577 @current_journal.save
Jean-Philippe Lang
Fixed: journal details duplicated when an issue is saved twice (#3690)....
r3385 # reset current journal
init_journal @current_journal.user, @current_journal.notes
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
# Query generator for selecting groups of issue counts for a project
# based on specific criteria
#
# Options
# * project - Project to search in.
# * field - String. Issue field to key off of in the grouping.
# * joins - String. The table name to join against.
def self.count_and_group_by(options)
project = options.delete(:project)
select_field = options.delete(:field)
joins = options.delete(:joins)
Jean-Philippe Lang
Adds visibility condition to Issue.by_* count methods....
r5245 where = "#{Issue.table_name}.#{select_field}=j.id"
Toshi MARUYAMA
remove trailing white-spaces excluding SQL from issue model source....
r5690
Eric Davis
Refactor: Extracted the select_all calls to a new private method....
r3251 ActiveRecord::Base.connection.select_all("select s.id as status_id,
s.is_closed as closed,
j.id as #{select_field},
Jean-Philippe Lang
Adds visibility condition to Issue.by_* count methods....
r5245 count(#{Issue.table_name}.id) as total
Eric Davis
Refactor: Extracted the select_all calls to a new private method....
r3251 from
Jean-Philippe Lang
Adds visibility condition to Issue.by_* count methods....
r5245 #{Issue.table_name}, #{Project.table_name}, #{IssueStatus.table_name} s, #{joins} j
Eric Davis
Refactor: Extracted the select_all calls to a new private method....
r3251 where
Jean-Philippe Lang
Adds visibility condition to Issue.by_* count methods....
r5245 #{Issue.table_name}.status_id=s.id
Eric Davis
Refactor: Extracted the select_all calls to a new private method....
r3251 and #{where}
Jean-Philippe Lang
Adds visibility condition to Issue.by_* count methods....
r5245 and #{Issue.table_name}.project_id=#{Project.table_name}.id
and #{visible_condition(User.current, :project => project)}
Eric Davis
Refactor: Extracted the select_all calls to a new private method....
r3251 group by s.id, s.is_closed, j.id")
end
Jean-Philippe Lang
Initial commit...
r2 end