summaryrefslogtreecommitdiff
path: root/app/models/issue_link.rb
blob: ba97874ed39b017a6ec889f51ea426dae67e3d0c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# frozen_string_literal: true

class IssueLink < ApplicationRecord
  include FromUnion

  belongs_to :source, class_name: 'Issue'
  belongs_to :target, class_name: 'Issue'

  validates :source, presence: true
  validates :target, presence: true
  validates :source, uniqueness: { scope: :target_id, message: 'is already related' }
  validate :check_self_relation
  validate :check_opposite_relation

  scope :for_source_issue, ->(issue) { where(source_id: issue.id) }
  scope :for_target_issue, ->(issue) { where(target_id: issue.id) }

  TYPE_RELATES_TO = 'relates_to'
  TYPE_BLOCKS = 'blocks'
  # we don't store is_blocked_by in the db but need it for displaying the relation
  # from the target (used in IssueLink.inverse_link_type)
  TYPE_IS_BLOCKED_BY = 'is_blocked_by'

  enum link_type: { TYPE_RELATES_TO => 0, TYPE_BLOCKS => 1 }

  def self.inverse_link_type(type)
    type
  end

  private

  def check_self_relation
    return unless source && target

    if source == target
      errors.add(:source, 'cannot be related to itself')
    end
  end

  def check_opposite_relation
    return unless source && target

    if IssueLink.find_by(source: target, target: source)
      errors.add(:source, 'is already related to this issue')
    end
  end
end

IssueLink.prepend_if_ee('EE::IssueLink')