discussion.rb 3.4 KB
Newer Older
1 2 3
class Discussion
  NUMBER_OF_TRUNCATED_DIFF_LINES = 16

D
Douwe Maan 已提交
4
  attr_reader :first_note, :last_note, :notes
5 6 7 8 9 10 11 12 13 14

  delegate  :created_at,
            :project,
            :author,

            :noteable,
            :for_commit?,
            :for_merge_request?,

            :line_code,
15
            :original_line_code,
16 17 18 19 20 21
            :diff_file,
            :for_line?,
            :active?,

            to: :first_note

D
Douwe Maan 已提交
22 23 24
  delegate  :resolved_at,
            :resolved_by,

25 26
            to: :last_resolved_note,
            allow_nil: true
D
Douwe Maan 已提交
27

28 29 30 31 32 33 34 35 36 37 38 39
  delegate :blob, :highlighted_diff_lines, to: :diff_file, allow_nil: true

  def self.for_notes(notes)
    notes.group_by(&:discussion_id).values.map { |notes| new(notes) }
  end

  def self.for_diff_notes(notes)
    notes.group_by(&:line_code).values.map { |notes| new(notes) }
  end

  def initialize(notes)
    @first_note = notes.first
D
Douwe Maan 已提交
40
    @last_note = notes.last
41 42 43
    @notes = notes
  end

44 45 46 47 48 49
  def last_resolved_note
    return unless resolved?

    @last_resolved_note ||= resolved_notes.sort_by(&:resolved_at).last
  end

50 51 52 53 54 55 56 57
  def last_updated_at
    last_note.created_at
  end

  def last_updated_by
    last_note.author
  end

58 59 60
  def id
    first_note.discussion_id
  end
61

D
Douwe Maan 已提交
62
  alias_method :to_param, :id
63 64 65 66 67 68 69 70 71

  def diff_discussion?
    first_note.diff_note?
  end

  def legacy_diff_discussion?
    notes.any?(&:legacy_diff_note?)
  end

D
Douwe Maan 已提交
72
  def resolvable?
73 74 75
    return @resolvable if defined?(@resolvable)

    @resolvable = diff_discussion? && notes.any?(&:resolvable?)
D
Douwe Maan 已提交
76 77 78
  end

  def resolved?
79 80 81
    return @resolved if defined?(@resolved)

    @resolved = resolvable? && notes.none?(&:to_be_resolved?)
D
Douwe Maan 已提交
82 83
  end

84 85 86 87
  def resolved_notes
    notes.select(&:resolved?)
  end

D
Douwe Maan 已提交
88
  def to_be_resolved?
89
    resolvable? && !resolved?
D
Douwe Maan 已提交
90 91
  end

92 93 94 95 96
  def can_resolve?(current_user)
    return false unless current_user
    return false unless resolvable?

    current_user == self.noteable.author ||
97
      current_user.can?(:resolve_note, self.project)
98 99
  end

100
  def resolve!(current_user)
101 102
    return unless resolvable?

103 104 105 106 107 108
    notes.each do |note|
      note.resolve!(current_user) if note.resolvable?
    end
  end

  def unresolve!
109 110
    return unless resolvable?

111 112 113 114 115
    notes.each do |note|
      note.unresolve! if note.resolvable?
    end
  end

116 117 118 119
  def for_target?(target)
    self.noteable == target && !diff_discussion?
  end

120 121 122 123 124 125
  def active?
    return @active if defined?(@active)

    @active = first_note.active?
  end

D
Douwe Maan 已提交
126 127 128 129 130 131 132 133 134 135 136 137
  def collapsed?
    return false unless diff_discussion?

    if resolvable?
      # New diff discussions only disappear once they are marked resolved
      resolved?
    else
      # Old diff discussions disappear once they become outdated
      !active?
    end
  end

138
  def expanded?
D
Douwe Maan 已提交
139
    !collapsed?
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
  end

  def reply_attributes
    data = {
      noteable_type: first_note.noteable_type,
      noteable_id:   first_note.noteable_id,
      commit_id:     first_note.commit_id,
      discussion_id: self.id,
    }

    if diff_discussion?
      data[:note_type] = first_note.type

      data.merge!(first_note.diff_attributes)
    end

    data
  end

  # Returns an array of at most 16 highlighted lines above a diff note
  def truncated_diff_lines
    prev_lines = []

    highlighted_diff_lines.each do |line|
      if line.meta?
        prev_lines.clear
      else
        prev_lines << line

        break if for_line?(line)

        prev_lines.shift if prev_lines.length >= NUMBER_OF_TRUNCATED_DIFF_LINES
      end
    end

    prev_lines
  end
end