##// END OF EJS Templates
Backported r2429, r2430, r248 to r2491 and r2522 from trunk (request and controller objects added to the hooks by default.)....
Backported r2429, r2430, r248 to r2491 and r2522 from trunk (request and controller objects added to the hooks by default.). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2558 e93f8b46-1217-0410-a6f0-8f06a7374b81

File last commit:

r2308:fae04f3ae1f6
r2490:36b5d4f6af04
Show More
issue.rb
280 lines | 10.1 KiB | text/x-ruby | RubyLexer
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 # redMine - project management software
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 # Copyright (C) 2006-2007 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.
#
# 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.
#
# 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
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'
belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id'
belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id'
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"
Jean-Philippe Lang
Commit messages are now scanned for referenced or fixed issue IDs....
r470
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
Jean-Philippe Lang
Merged r2116, r2117 and r2187 from trunk....
r2215 acts_as_attachable :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"
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id}: #{o.subject}"},
Jean-Philippe Lang
Search engines now supports pagination....
r755 :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}}
Jean-Philippe Lang
Added "Watch" functionality on issues. It allows users to receive mail notifications about issue changes....
r450
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
Jean-Philippe Lang
Activity refactoring....
r1692
Jean-Philippe Lang
Merged r2246 and r2248 from trunk (#2456)....
r2308 validates_presence_of :subject, :priority, :project, :tracker, :author, :status
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
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330
Jean-Philippe Lang
Added default value for enumerations....
r792 def after_initialize
if new_record?
# set default values for new records only
self.status ||= IssueStatus.default
self.priority ||= Enumeration.default('IPRI')
end
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
(project && tracker) ? project.all_issue_custom_fields.select {|c| tracker.custom_fields.include? c } : []
end
Jean-Philippe Lang
Added the hability to copy an issue....
r860 def copy_from(arg)
issue = arg.is_a?(Issue) ? arg : Issue.find(arg)
self.attributes = issue.attributes.dup
self.custom_values = issue.custom_values.collect {|v| v.clone}
self
end
Jean-Philippe Lang
Fixed: Update of time entry fails when the issue has been moved to an other project....
r896 # Move an issue to a new project and tracker
def move_to(new_project, new_tracker = nil)
transaction do
if new_project && project_id != new_project.id
# delete issue relations
Jean-Philippe Lang
Do not clear issue relations when moving an issue to another project if cross-project issue relations are allowed (closes #696)....
r1150 unless Setting.cross_project_issue_relations?
self.relations_from.clear
self.relations_to.clear
end
Jean-Philippe Lang
Fixed: Update of time entry fails when the issue has been moved to an other project....
r896 # issue is moved to another project
Jean-Philippe Lang
When moving an issue to another project, reassign it to the category with same name if any (#1653)....
r1688 # reassign to the category with same name if any
new_category = category.nil? ? nil : new_project.issue_categories.find_by_name(category.name)
self.category = new_category
Jean-Philippe Lang
Fixed: Update of time entry fails when the issue has been moved to an other project....
r896 self.fixed_version = nil
self.project = new_project
end
if new_tracker
self.tracker = new_tracker
end
if save
# Manually update project_id on related time entries
TimeEntry.update_all("project_id = #{new_project.id}", {:issue_id => id})
else
rollback_db_transaction
return false
end
end
return true
end
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
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
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 def validate
if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty?
errors.add :due_date, :activerecord_error_not_a_date
end
if self.due_date and self.start_date and self.due_date < self.start_date
errors.add :due_date, :activerecord_error_greater_than_start_date
end
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
errors.add :start_date, :activerecord_error_invalid
end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Jean-Philippe Lang
Added per-project tracker selection. Trackers can be selected on project settings....
r907 def validate_on_create
errors.add :tracker_id, :activerecord_error_invalid unless project.trackers.include?(tracker)
end
Jean-Philippe Lang
Each category can now be associated to a user, so that new issues in that category are automatically assigned to that user....
r574 def before_create
# default assignment based on category
if assigned_to.nil? && category && category.assigned_to
self.assigned_to = category.assigned_to
end
end
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 def before_save
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 if @current_journal
# attributes changes
(Issue.column_names - %w(id description)).each {|c|
@current_journal.details << JournalDetail.new(:property => 'attr',
:prop_key => c,
:old_value => @issue_before_change.send(c),
:value => send(c)) unless send(c)==@issue_before_change.send(c)
}
# custom fields changes
custom_values.each {|c|
Jean-Philippe Lang
Fixed: custom field displayed as deleted in the issue history even if no value was set....
r695 next if (@custom_values_before_change[c.custom_field_id]==c.value ||
(@custom_values_before_change[c.custom_field_id].blank? && c.value.blank?))
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 @current_journal.details << JournalDetail.new(:property => 'cf',
:prop_key => c.custom_field_id,
:old_value => @custom_values_before_change[c.custom_field_id],
Jean-Philippe Lang
Fixed: custom field displayed as deleted in the issue history even if no value was set....
r695 :value => c.value)
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 }
Jean-Philippe Lang
Fixed: unable to add a file to an issue without entering a note....
r840 @current_journal.save
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Jean-Philippe Lang
Fixed: unable to add a file to an issue without entering a note....
r840 # Save the issue even if the journal is not saved (because empty)
true
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 def after_save
Jean-Philippe Lang
Fixed: auto closing of duplicates doesn't work....
r1148 # Reload is needed in order to get the right status
reload
Jean-Philippe Lang
Automatic closing of duplicate issues....
r657 # Update start/due dates of following issues
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503 relations_from.each(&:set_issue_to_dates)
Jean-Philippe Lang
Automatic closing of duplicate issues....
r657
# Close duplicates if the issue was closed
if @issue_before_change && !@issue_before_change.closed? && self.closed?
duplicates.each do |duplicate|
Jean-Philippe Lang
Fixed: ActiveRecord::StaleObjectError exception on closing a set of circular duplicate issues (#1105)....
r1345 # Reload is need in case the duplicate was updated by a previous duplicate
duplicate.reload
Jean-Philippe Lang
Automatic closing of duplicate issues....
r657 # Don't re-close it if it's already closed
next if duplicate.closed?
# Same user and notes
duplicate.init_journal(@current_journal.user, @current_journal.notes)
duplicate.update_attribute :status, self.status
end
end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
def init_journal(user, notes = "")
@current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes)
@issue_before_change = self.clone
Jean-Philippe Lang
Fixed: auto closing of duplicates doesn't work....
r1148 @issue_before_change.status = self.status
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 @custom_values_before_change = {}
self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value }
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
Jean-Philippe Lang
Simple time tracking functionality added. Time can be logged at issue or project level....
r365
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
Jean-Philippe Lang
Merged r2109, r2118, r2130, r2131, r2134, r2135, r2136 and r2139 to r2145 from trunk....
r2144 # Returns true if the issue is overdue
def overdue?
!due_date.nil? && (due_date < Date.today)
end
Jean-Philippe Lang
Added a 'Assignable' boolean on Role model....
r643 # Users the issue can be assigned to
def assignable_users
Jean-Philippe Lang
Added 'Bulk edit' functionality....
r806 project.assignable_users
Jean-Philippe Lang
Added a 'Assignable' boolean on Role model....
r643 end
Jean-Philippe Lang
Merged IssuesController change_status and add_note actions....
r1030 # Returns an array of status that user is able to apply
def new_statuses_allowed_to(user)
statuses = status.find_new_statuses_allowed_to(user.role_for_project(project), tracker)
statuses << status unless statuses.empty?
statuses.uniq.sort
end
Jean-Philippe Lang
More flexible mail notifications settings at user level. A user has now 3 options:...
r842 # Returns the mail adresses of users that should be notified for the issue
def recipients
recipients = project.recipients
Jean-Philippe Lang
Fixed: locked users should not receive email notifications....
r1061 # Author and assignee are always notified unless they have been locked
recipients << author.mail if author && author.active?
recipients << assigned_to.mail if assigned_to && assigned_to.active?
Jean-Philippe Lang
More flexible mail notifications settings at user level. A user has now 3 options:...
r842 recipients.compact.uniq
end
Jean-Philippe Lang
Simple time tracking functionality added. Time can be logged at issue or project level....
r365 def spent_hours
@spent_hours ||= time_entries.sum(:hours) || 0
end
Jean-Philippe Lang
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:...
r503
def relations
(relations_from + relations_to).sort
end
def all_dependent_issues
dependencies = []
relations_from.each do |relation|
dependencies << relation.issue_to
dependencies += relation.issue_to.all_dependent_issues
end
dependencies
end
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
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
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
def soonest_start
@soonest_start ||= relations_to.collect{|relation| relation.successor_soonest_start}.compact.min
end
Jean-Philippe Lang
Include subprojects on the issue list, calendar and gantt by default....
r1164
def self.visible_by(usr)
with_scope(:find => { :conditions => Project.visible_by(usr) }) do
yield
end
end
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
Jean-Philippe Lang
Merged r2116, r2117 and r2187 from trunk....
r2215
private
# Callback on attachment deletion
def attachment_removed(obj)
journal = init_journal(User.current)
journal.details << JournalDetail.new(:property => 'attachment',
:prop_key => obj.id,
:old_value => obj.filename)
journal.save
end
Jean-Philippe Lang
Initial commit...
r2 end