legacy_diff_note.rb 2.82 KB
Newer Older
1
class LegacyDiffNote < Note
2 3
  include NoteOnDiff

4 5 6 7 8 9 10
  serialize :st_diff

  validates :line_code, presence: true, line_code: true

  before_create :set_diff

  class << self
11 12
    def build_discussion_id(noteable_type, noteable_id, line_code)
      [super(noteable_type, noteable_id), line_code].join("-")
13 14 15
    end
  end

16
  def legacy_diff_note?
17 18 19
    true
  end

20 21
  def diff_attributes
    { line_code: line_code }
22 23
  end

24 25 26 27 28 29 30 31
  def project_repository
    if RequestStore.active?
      RequestStore.fetch("project:#{project_id}:repository") { self.project.repository }
    else
      self.project.repository
    end
  end

32 33
  def diff_file_hash
    line_code.split('_')[0] if line_code
34 35 36 37 38 39
  end

  def diff
    @diff ||= Gitlab::Git::Diff.new(st_diff) if st_diff.respond_to?(:map)
  end

40
  def diff_file
41
    @diff_file ||= Gitlab::Diff::File.new(diff, repository: project_repository) if diff
42 43 44
  end

  def diff_line
45
    @diff_line ||= diff_file.line_for_line_code(self.line_code) if diff_file
46 47
  end

48 49
  def for_line?(line)
    !line.meta? && diff_file.line_code(line) == self.line_code
50 51 52 53 54 55 56 57 58 59
  end

  # Check if this note is part of an "active" discussion
  #
  # This will always return true for anything except MergeRequest noteables,
  # which have special logic.
  #
  # If the note's current diff cannot be matched in the MergeRequest's current
  # diff, it's considered inactive.
  def active?
60
    return @active if defined?(@active)
61
    return true if for_commit?
62
    return true unless diff_line
63 64 65 66 67 68 69
    return false unless noteable

    noteable_diff = find_noteable_diff

    if noteable_diff
      parsed_lines = Gitlab::Diff::Parser.new.parse(noteable_diff.diff.each_line)

70
      @active = parsed_lines.any? { |line_obj| line_obj.text == diff_line.text }
71 72 73 74 75 76 77
    else
      @active = false
    end

    @active
  end

78
  private
79

80 81 82
  def find_diff
    return nil unless noteable
    return @diff if defined?(@diff)
83

84
    @diff = noteable.raw_diffs(Commit.max_diff_options).find do |d|
85
      d.new_path && Digest::SHA1.hexdigest(d.new_path) == diff_file_hash
86 87 88
    end
  end

89 90 91 92 93
  def set_diff
    # First lets find notes with same diff
    # before iterating over all mr diffs
    diff = diff_for_line_code unless for_merge_request?
    diff ||= find_diff
94

95
    self.st_diff = diff.to_hash if diff
96 97
  end

98 99 100 101 102
  def diff_for_line_code
    attributes = {
      noteable_type: noteable_type,
      line_code: line_code
    }
103

104 105 106 107
    if for_commit?
      attributes[:commit_id] = commit_id
    else
      attributes[:noteable_id] = noteable_id
108 109
    end

110
    self.class.where(attributes).last.try(:diff)
111 112 113 114
  end

  # Find the diff on noteable that matches our own
  def find_noteable_diff
115
    diffs = noteable.raw_diffs(Commit.max_diff_options)
116 117
    diffs.find { |d| d.new_path == self.diff.new_path }
  end
118 119 120 121

  def build_discussion_id
    self.class.build_discussion_id(noteable_type, noteable_id || commit_id, line_code)
  end
122
end