BigW Consortium Gitlab

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

4
  attr_reader :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

22 23 24
  delegate  :resolved_at,
            :resolved_by,

25 26
            to: :last_resolved_note,
            allow_nil: true
27

28 29 30 31 32 33 34 35 36 37 38 39 40 41
  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)
    @notes = notes
  end

42 43 44 45 46 47
  def last_resolved_note
    return unless resolved?

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

48 49 50 51 52 53 54 55
  def last_updated_at
    last_note.created_at
  end

  def last_updated_by
    last_note.author
  end

56 57 58
  def id
    first_note.discussion_id
  end
59

Douwe Maan committed
60
  alias_method :to_param, :id
61 62 63 64 65 66 67 68 69

  def diff_discussion?
    first_note.diff_note?
  end

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

70
  def resolvable?
71
    return @resolvable if @resolvable.present?
72 73

    @resolvable = diff_discussion? && notes.any?(&:resolvable?)
74 75 76
  end

  def resolved?
77
    return @resolved if @resolved.present?
78 79

    @resolved = resolvable? && notes.none?(&:to_be_resolved?)
80 81
  end

82 83 84 85 86 87 88 89
  def first_note
    @first_note ||= @notes.first
  end

  def last_note
    @last_note ||= @notes.last
  end

90 91 92 93
  def resolved_notes
    notes.select(&:resolved?)
  end

94
  def to_be_resolved?
95
    resolvable? && !resolved?
96 97
  end

98 99 100 101 102
  def can_resolve?(current_user)
    return false unless current_user
    return false unless resolvable?

    current_user == self.noteable.author ||
103
      current_user.can?(:resolve_note, self.project)
104 105
  end

106
  def resolve!(current_user)
107 108
    return unless resolvable?

109
    update { |notes| notes.resolve!(current_user) }
110 111 112
  end

  def unresolve!
113 114
    return unless resolvable?

115
    update { |notes| notes.unresolve! }
116 117
  end

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

122
  def active?
123
    return @active if @active.present?
124 125 126 127

    @active = first_note.active?
  end

128 129 130 131 132 133 134 135 136 137 138 139
  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

140
  def expanded?
141
    !collapsed?
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 178
  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
179 180 181 182 183 184 185 186 187 188 189 190 191

  private

  def update
    notes_relation = DiffNote.where(id: notes.map(&:id)).fresh
    yield(notes_relation)

    # Set the notes array to the updated notes
    @notes = notes_relation.to_a

    # Reset the memoized values
    @last_resolved_note = @resolvable = @resolved = @first_note = @last_note = nil
  end
192
end