##// END OF EJS Templates
Converted a test to shoulda and added more checks for it's assignments....
Converted a test to shoulda and added more checks for it's assignments. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@3361 e93f8b46-1217-0410-a6f0-8f06a7374b81

File last commit:

r3194:0a05cc2a3780
r3247:778117fead2b
Show More
issue.rb
471 lines | 17.2 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
Eric Davis
Adds a Setting to control how an Issue's done_ratio is calculated:...
r3037
DONE_RATIO_OPTIONS = %w(issue_field issue_status)
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
Eric Davis
Adds a Setting to control how an Issue's done_ratio is calculated:...
r3037
before_save :update_done_ratio_from_issue_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)
Jean-Philippe Lang
Reset timestamps and wiki page hierarchy on project copy....
r2858 self.attributes = issue.attributes.dup.except("id", "created_on", "updated_on")
Jean-Philippe Lang
Added the hability to copy an issue....
r860 self.custom_values = issue.custom_values.collect {|v| v.clone}
Jean-Philippe Lang
Copy issue status on project copy (#3877)....
r2961 self.status = issue.status
Jean-Philippe Lang
Added the hability to copy an issue....
r860 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
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009 # Keep the fixed_version if it's still valid in the new_project
unless new_project.shared_versions.include?(issue.fixed_version)
issue.fixed_version = nil
end
Jean-Philippe Lang
Adds ability to bulk copy issues (#1847)....
r2311 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}
Eric Davis
Enhanced the Issue Bulk Copy feature:...
r3008 issue.status = if options[:attributes] && options[:attributes][:status_id]
IssueStatus.find_by_id(options[:attributes][:status_id])
else
self.status
end
end
# Allow bulk setting of attributes on the issue
if options[:attributes]
issue.attributes = options[:attributes]
Jean-Philippe Lang
Adds ability to bulk copy issues (#1847)....
r2311 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
Enable tracker update on issue edit form (#2405)....
r2994
def tracker_id=(tid)
self.tracker = nil
write_attribute(:tracker_id, tid)
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
Jean-Philippe Lang
Estimated time recognizes improved time formats (#1092)....
r1346
Jean-Philippe Lang
Fixes tracker_id and custom_field_values assignment order for issues (#4353)....
r3025 # Overrides attributes= so that tracker_id gets assigned first
def attributes_with_tracker_first=(new_attributes, *args)
return if new_attributes.nil?
new_tracker_id = new_attributes['tracker_id'] || new_attributes[:tracker_id]
if new_tracker_id
self.tracker_id = new_tracker_id
end
Jean-Philippe Lang
Fixed: undefined method `stringify_keys!' error in Issue#attributes_with_tracker_first= with ruby1.9 (#4540)....
r3175 send :attributes_without_tracker_first=, new_attributes, *args
Jean-Philippe Lang
Fixes tracker_id and custom_field_values assignment order for issues (#4353)....
r3025 end
alias_method_chain :attributes=, :tracker_first
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
Set a white list of issue attributes that can be mass-assigned from controllers....
r3194 SAFE_ATTRIBUTES = %w(
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
) unless const_defined?(:SAFE_ATTRIBUTES)
# 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
# TODO: move workflow/permission checks from controllers to here
def safe_attributes=(attrs, user=User.current)
return if attrs.nil?
self.attributes = attrs.reject {|k,v| !SAFE_ATTRIBUTES.include?(k)}
end
Eric Davis
Adds a Setting to control how an Issue's done_ratio is calculated:...
r3037 def done_ratio
Jean-Philippe Lang
Issue#done_ratio should not break if status is nil....
r3045 if Issue.use_status_for_done_ratio? && status && status.default_done_ratio?
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
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
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?
errors.add_to_base I18n.t(:error_can_not_reopen_issue_on_closed_version)
end
end
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
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 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
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
Jean-Philippe Lang
Allow blank value for IssueStatus#default_done_ratio....
r3043 if Issue.use_status_for_done_ratio? && status && status.default_done_ratio?
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
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 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
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
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
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
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
Do not notify users that are no longer allowed to view an issue (#3589, #4263)....
r3007 notified = project.notified_users
Jean-Philippe Lang
Fixed: locked users should not receive email notifications....
r1061 # Author and assignee are always notified unless they have been locked
Jean-Philippe Lang
Do not notify users that are no longer allowed to view an issue (#3589, #4263)....
r3007 notified << author if author && author.active?
notified << assigned_to if assigned_to && assigned_to.active?
notified.uniq!
# Remove users that can not view the issue
notified.reject! {|user| !visible?(user)}
notified.collect(&:mail)
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
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009
Jean-Philippe Lang
Optimize updates of issue's shared versions....
r3023 # Unassigns issues from +version+ if it's no longer shared with issue's project
def self.update_versions_from_sharing_change(version)
# Update issues assigned to the version
update_versions(["#{Issue.table_name}.fixed_version_id = ?", version.id])
end
# 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
private
# 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
Issue.all(:conditions => merge_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'",
conditions),
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009 :include => [:project, :fixed_version]
).each do |issue|
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
Jean-Philippe Lang
Adds more css classes to the roadmap issues (#3214)....
r2602
Jean-Philippe Lang
AttachmentsController now handles attachments deletion....
r2114 # 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