BigW Consortium Gitlab

legacy_diff_note.rb 2.87 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
  end

52 53 54 55
  def original_line_code
    self.line_code
  end

56 57 58 59 60 61 62 63
  # 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?
64
    return @active if defined?(@active)
65
    return true if for_commit?
66
    return true unless diff_line
67 68 69 70 71 72 73
    return false unless noteable

    noteable_diff = find_noteable_diff

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

74
      @active = parsed_lines.any? { |line_obj| line_obj.text == diff_line.text }
75 76 77 78 79 80 81
    else
      @active = false
    end

    @active
  end

82
  private
83

84 85 86
  def find_diff
    return nil unless noteable
    return @diff if defined?(@diff)
87

88
    @diff = noteable.raw_diffs(Commit.max_diff_options).find do |d|
89
      d.new_path && Digest::SHA1.hexdigest(d.new_path) == diff_file_hash
90 91 92
    end
  end

93 94 95 96 97
  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
98

99
    self.st_diff = diff.to_hash if diff
100 101
  end

102 103 104 105 106
  def diff_for_line_code
    attributes = {
      noteable_type: noteable_type,
      line_code: line_code
    }
107

108 109 110 111
    if for_commit?
      attributes[:commit_id] = commit_id
    else
      attributes[:noteable_id] = noteable_id
112 113
    end

114
    self.class.where(attributes).last.try(:diff)
115 116 117 118
  end

  # Find the diff on noteable that matches our own
  def find_noteable_diff
119
    diffs = noteable.raw_diffs(Commit.max_diff_options)
120 121
    diffs.find { |d| d.new_path == self.diff.new_path }
  end
122 123 124 125

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