##// END OF EJS Templates
Allow referencing issue numbers in brackets. This style is used by other...
Allow referencing issue numbers in brackets. This style is used by other bug trackers. Examples: * "[#nnn] Worked on this issue" * "[#nnn, #mmm] Worked on these" * "[#nnn #mmm] Working some more" git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2854 e93f8b46-1217-0410-a6f0-8f06a7374b81

File last commit:

r2729:9ed048dc4212
r2749:609faba6a3d3
Show More
issue.rb
322 lines | 11.8 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'
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"
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
AttachmentsController now handles attachments deletion....
r2114 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"
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' : '') }
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
Makes issue description a non-required field (#2456)....
r2244 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
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,
:conditions => Project.allowed_to_condition(args.first || User.current, :view_issues) } }
Jean-Philippe Lang
Adds missing scope for r2595....
r2528 named_scope :open, :conditions => ["#{IssueStatus.table_name}.is_closed = ?", false], :include => :status
Jean-Philippe Lang
Create the journal after issue save (#3140)....
r2577 after_save :create_journal
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)
(usr || User.current).allowed_to?(:view_issues, self.project)
end
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
Eric Davis
Changed Enumerations to use a Single Table Inheritance...
r2677 self.priority ||= IssuePriority.default
Jean-Philippe Lang
Added default value for enumerations....
r792 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
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
def move_to(new_project, new_tracker = nil, options = {})
options ||= {}
issue = options[:copy] ? self.clone : self
Jean-Philippe Lang
Fixed: Update of time entry fails when the issue has been moved to an other project....
r896 transaction do
Jean-Philippe Lang
Adds ability to bulk copy issues (#1847)....
r2311 if new_project && issue.project_id != new_project.id
Jean-Philippe Lang
Fixed: Update of time entry fails when the issue has been moved to an other project....
r896 # 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?
Jean-Philippe Lang
Adds ability to bulk copy issues (#1847)....
r2311 issue.relations_from.clear
issue.relations_to.clear
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 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
Jean-Philippe Lang
Adds ability to bulk copy issues (#1847)....
r2311 new_category = issue.category.nil? ? nil : new_project.issue_categories.find_by_name(issue.category.name)
issue.category = new_category
issue.fixed_version = nil
issue.project = new_project
Jean-Philippe Lang
Fixed: Update of time entry fails when the issue has been moved to an other project....
r896 end
if new_tracker
Jean-Philippe Lang
Adds ability to bulk copy issues (#1847)....
r2311 issue.tracker = new_tracker
Jean-Philippe Lang
Fixed: Update of time entry fails when the issue has been moved to an other project....
r896 end
Jean-Philippe Lang
Adds ability to bulk copy issues (#1847)....
r2311 if options[:copy]
issue.custom_field_values = self.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h}
issue.status = self.status
end
if issue.save
unless options[:copy]
# Manually update project_id on related time entries
TimeEntry.update_all("project_id = #{new_project.id}", {:issue_id => id})
end
Jean-Philippe Lang
Fixed: Update of time entry fails when the issue has been moved to an other project....
r896 else
Jean-Philippe Lang
Adds ability to bulk copy issues (#1847)....
r2311 Issue.connection.rollback_db_transaction
Jean-Philippe Lang
Fixed: Update of time entry fails when the issue has been moved to an other project....
r896 return false
end
end
Jean-Philippe Lang
Adds ability to bulk copy issues (#1847)....
r2311 return issue
Jean-Philippe Lang
Fixed: Update of time entry fails when the issue has been moved to an other project....
r896 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?
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
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
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
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
Jean-Philippe Lang
Merged Rails 2.2 branch. Redmine now requires Rails 2.2.2....
r2430 errors.add :tracker_id, :invalid unless project.trackers.include?(tracker)
Jean-Philippe Lang
Added per-project tracker selection. Trackers can be selected on project settings....
r907 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 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
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
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
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
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)
Jean-Philippe Lang
Allows multiple roles on the same project (#706). Prerequisite for user groups feature....
r2627 statuses = status.find_new_statuses_allowed_to(user.roles_for_project(project), tracker)
Jean-Philippe Lang
Merged IssuesController change_status and add_note actions....
r1030 statuses << status unless statuses.empty?
Jean-Philippe Lang
Actually block issues from closing when a blocking issue isn't closed (#1740)....
r2700 statuses = statuses.uniq.sort
blocked? ? statuses.reject {|s| s.is_closed?} : statuses
Jean-Philippe Lang
Merged IssuesController change_status and add_note actions....
r1030 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
Eric Davis
Added some RDoc documentation for some models....
r2536 # Returns the total number of hours spent on this issue.
#
# Example:
# spent_hours => 0
# spent_hours => 50
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
Eric Davis
Added some RDoc documentation for some models....
r2536 # Returns the time scheduled for this issue.
#
# 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
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
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
AttachmentsController now handles attachments deletion....
r2114
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?
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
AttachmentsController now handles attachments deletion....
r2114 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
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
(Issue.column_names - %w(id description lock_version created_on updated_on)).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|
next if (@custom_values_before_change[c.custom_field_id]==c.value ||
(@custom_values_before_change[c.custom_field_id].blank? && c.value.blank?))
@current_journal.details << JournalDetail.new(:property => 'cf',
:prop_key => c.custom_field_id,
:old_value => @custom_values_before_change[c.custom_field_id],
:value => c.value)
}
@current_journal.save
end
end
Jean-Philippe Lang
Initial commit...
r2 end