discussion.rb 2.9 KB
Newer Older
D
Douwe Maan 已提交
1
# A non-diff discussion on an issue, merge request, commit, or snippet, consisting of `DiscussionNote` notes.
2
class Discussion
3
  include ResolvableDiscussion
4

D
Douwe Maan 已提交
5
  attr_reader :notes, :noteable
6 7 8 9 10 11 12 13 14 15 16

  delegate  :created_at,
            :project,
            :author,

            :noteable,
            :for_commit?,
            :for_merge_request?,

            to: :first_note

17 18 19
  def self.build(notes, noteable = nil)
    notes.first.discussion_class(noteable).new(notes, noteable)
  end
20

21 22 23
  def self.build_collection(notes, noteable = nil)
    notes.group_by { |n| n.discussion_id(noteable) }.values.map { |notes| build(notes, noteable) }
  end
24

D
Douwe Maan 已提交
25
  # Returns an alphanumeric discussion ID based on `build_discussion_id`
26 27
  def self.discussion_id(note)
    Digest::SHA1.hexdigest(build_discussion_id(note).join("-"))
28 29
  end

D
Douwe Maan 已提交
30 31 32
  # Returns an array of discussion ID components
  def self.build_discussion_id(note)
    [*base_discussion_id(note), SecureRandom.hex]
33 34
  end

D
Douwe Maan 已提交
35
  def self.base_discussion_id(note)
36 37
    noteable_id = note.noteable_id || note.commit_id
    [:discussion, note.noteable_type.try(:underscore), noteable_id]
38 39
  end

D
Douwe Maan 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52
  # To turn a list of notes into a list of discussions, they are grouped by discussion ID.
  # When notes on a commit are displayed in context of a merge request that contains that commit,
  # these notes are to be displayed as if they were part of one discussion, even though they were actually
  # individual notes on the commit with different discussion IDs, so that it's clear that these are not
  # notes on the merge request itself.
  # To get these out-of-context notes to end up in the same discussion, we need to get them to return the same
  # `discussion_id` when this grouping happens. To enable this, `Note#discussion_id` calls out
  # to the `override_discussion_id` method on the appropriate `Discussion` subclass, as determined by
  # the `discussion_class` method on `Note` or a subclass of `Note`.
  # If no override is necessary, return `nil`.
  # For the case described above, see `OutOfContextDiscussion.override_discussion_id`.
  def self.override_discussion_id(note)
    nil
53 54 55 56 57
  end

  def initialize(notes, noteable = nil)
    @notes = notes
    @noteable = noteable
58 59
  end

D
Douwe Maan 已提交
60 61 62 63 64 65 66
  def ==(other)
    other.class == self.class &&
      other.noteable == self.noteable &&
      other.id == self.id &&
      other.notes == self.notes
  end

67 68 69 70 71 72 73 74
  def last_updated_at
    last_note.created_at
  end

  def last_updated_by
    last_note.author
  end

75
  def id
76
    first_note.discussion_id(noteable)
77
  end
78

D
Douwe Maan 已提交
79
  alias_method :to_param, :id
80 81

  def diff_discussion?
82 83 84
    false
  end

D
Douwe Maan 已提交
85
  def individual_note?
86
    false
87 88
  end

89 90 91 92
  def new_discussion?
    notes.length == 1
  end

93
  def last_note
94
    @last_note ||= notes.last
95
  end
96

D
Douwe Maan 已提交
97
  def collapsed?
D
Douwe Maan 已提交
98
    resolved?
D
Douwe Maan 已提交
99 100
  end

101
  def expanded?
D
Douwe Maan 已提交
102
    !collapsed?
103 104 105
  end

  def reply_attributes
D
Douwe Maan 已提交
106
    first_note.slice(:type, :noteable_type, :noteable_id, :commit_id, :discussion_id)
107 108
  end
end