annotate app/models/.svn/text-base/issue_relation.rb.svn-base @ 45:65d9e2cabaa3 luisf

Added tipoftheday to the config/settings in order to correct previous issues. Tip of the day is now working correctly. Added the heading strings to the locales files.
author luisf
date Tue, 23 Nov 2010 11:50:01 +0000
parents 513646585e45
children af80e5618e9b
rev   line source
Chris@0 1 # redMine - project management software
Chris@0 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
Chris@0 3 #
Chris@0 4 # This program is free software; you can redistribute it and/or
Chris@0 5 # modify it under the terms of the GNU General Public License
Chris@0 6 # as published by the Free Software Foundation; either version 2
Chris@0 7 # of the License, or (at your option) any later version.
Chris@0 8 #
Chris@0 9 # This program is distributed in the hope that it will be useful,
Chris@0 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 12 # GNU General Public License for more details.
Chris@0 13 #
Chris@0 14 # You should have received a copy of the GNU General Public License
Chris@0 15 # along with this program; if not, write to the Free Software
Chris@0 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Chris@0 17
Chris@0 18 class IssueRelation < ActiveRecord::Base
Chris@0 19 belongs_to :issue_from, :class_name => 'Issue', :foreign_key => 'issue_from_id'
Chris@0 20 belongs_to :issue_to, :class_name => 'Issue', :foreign_key => 'issue_to_id'
Chris@0 21
Chris@0 22 TYPE_RELATES = "relates"
Chris@0 23 TYPE_DUPLICATES = "duplicates"
Chris@0 24 TYPE_DUPLICATED = "duplicated"
Chris@0 25 TYPE_BLOCKS = "blocks"
Chris@0 26 TYPE_BLOCKED = "blocked"
Chris@0 27 TYPE_PRECEDES = "precedes"
Chris@0 28 TYPE_FOLLOWS = "follows"
Chris@0 29
Chris@0 30 TYPES = { TYPE_RELATES => { :name => :label_relates_to, :sym_name => :label_relates_to, :order => 1, :sym => TYPE_RELATES },
Chris@0 31 TYPE_DUPLICATES => { :name => :label_duplicates, :sym_name => :label_duplicated_by, :order => 2, :sym => TYPE_DUPLICATED },
Chris@0 32 TYPE_DUPLICATED => { :name => :label_duplicated_by, :sym_name => :label_duplicates, :order => 3, :sym => TYPE_DUPLICATES, :reverse => TYPE_DUPLICATES },
Chris@0 33 TYPE_BLOCKS => { :name => :label_blocks, :sym_name => :label_blocked_by, :order => 4, :sym => TYPE_BLOCKED },
Chris@0 34 TYPE_BLOCKED => { :name => :label_blocked_by, :sym_name => :label_blocks, :order => 5, :sym => TYPE_BLOCKS, :reverse => TYPE_BLOCKS },
Chris@0 35 TYPE_PRECEDES => { :name => :label_precedes, :sym_name => :label_follows, :order => 6, :sym => TYPE_FOLLOWS },
Chris@0 36 TYPE_FOLLOWS => { :name => :label_follows, :sym_name => :label_precedes, :order => 7, :sym => TYPE_PRECEDES, :reverse => TYPE_PRECEDES }
Chris@0 37 }.freeze
Chris@0 38
Chris@0 39 validates_presence_of :issue_from, :issue_to, :relation_type
Chris@0 40 validates_inclusion_of :relation_type, :in => TYPES.keys
Chris@0 41 validates_numericality_of :delay, :allow_nil => true
Chris@0 42 validates_uniqueness_of :issue_to_id, :scope => :issue_from_id
Chris@0 43
Chris@0 44 attr_protected :issue_from_id, :issue_to_id
Chris@0 45
Chris@0 46 def validate
Chris@0 47 if issue_from && issue_to
Chris@0 48 errors.add :issue_to_id, :invalid if issue_from_id == issue_to_id
Chris@0 49 errors.add :issue_to_id, :not_same_project unless issue_from.project_id == issue_to.project_id || Setting.cross_project_issue_relations?
Chris@0 50 errors.add_to_base :circular_dependency if issue_to.all_dependent_issues.include? issue_from
Chris@0 51 errors.add_to_base :cant_link_an_issue_with_a_descendant if issue_from.is_descendant_of?(issue_to) || issue_from.is_ancestor_of?(issue_to)
Chris@0 52 end
Chris@0 53 end
Chris@0 54
Chris@0 55 def other_issue(issue)
Chris@0 56 (self.issue_from_id == issue.id) ? issue_to : issue_from
Chris@0 57 end
Chris@0 58
Chris@0 59 # Returns the relation type for +issue+
Chris@0 60 def relation_type_for(issue)
Chris@0 61 if TYPES[relation_type]
Chris@0 62 if self.issue_from_id == issue.id
Chris@0 63 relation_type
Chris@0 64 else
Chris@0 65 TYPES[relation_type][:sym]
Chris@0 66 end
Chris@0 67 end
Chris@0 68 end
Chris@0 69
Chris@0 70 def label_for(issue)
Chris@0 71 TYPES[relation_type] ? TYPES[relation_type][(self.issue_from_id == issue.id) ? :name : :sym_name] : :unknow
Chris@0 72 end
Chris@0 73
Chris@0 74 def before_save
Chris@0 75 reverse_if_needed
Chris@0 76
Chris@0 77 if TYPE_PRECEDES == relation_type
Chris@0 78 self.delay ||= 0
Chris@0 79 else
Chris@0 80 self.delay = nil
Chris@0 81 end
Chris@0 82 set_issue_to_dates
Chris@0 83 end
Chris@0 84
Chris@0 85 def set_issue_to_dates
Chris@0 86 soonest_start = self.successor_soonest_start
Chris@0 87 if soonest_start
Chris@0 88 issue_to.reschedule_after(soonest_start)
Chris@0 89 end
Chris@0 90 end
Chris@0 91
Chris@0 92 def successor_soonest_start
Chris@0 93 return nil unless (TYPE_PRECEDES == self.relation_type) && (issue_from.start_date || issue_from.due_date)
Chris@0 94 (issue_from.due_date || issue_from.start_date) + 1 + delay
Chris@0 95 end
Chris@0 96
Chris@0 97 def <=>(relation)
Chris@0 98 TYPES[self.relation_type][:order] <=> TYPES[relation.relation_type][:order]
Chris@0 99 end
Chris@0 100
Chris@0 101 private
Chris@0 102
Chris@0 103 # Reverses the relation if needed so that it gets stored in the proper way
Chris@0 104 def reverse_if_needed
Chris@0 105 if TYPES.has_key?(relation_type) && TYPES[relation_type][:reverse]
Chris@0 106 issue_tmp = issue_to
Chris@0 107 self.issue_to = issue_from
Chris@0 108 self.issue_from = issue_tmp
Chris@0 109 self.relation_type = TYPES[relation_type][:reverse]
Chris@0 110 end
Chris@0 111 end
Chris@0 112 end