Class: Discussion

Inherits:
Object
  • Object
show all
Includes:
GlobalID::Identification, ResolvableDiscussion
Defined in:
app/models/discussion.rb

Overview

A non-diff discussion on an issue, merge request, commit, or snippet, consisting of `DiscussionNote` notes.

A discussion of this type can be resolvable.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ResolvableDiscussion

#can_resolve?, #first_note, #first_note_to_resolve, #last_resolved_note, #resolvable?, #resolve!, #resolved?, #resolved_notes, #to_be_resolved?, #unresolve!

Methods included from Gitlab::Utils::StrongMemoize

#clear_memoization, #strong_memoize, #strong_memoized?

Constructor Details

#initialize(notes, context_noteable = nil) ⇒ Discussion

Returns a new instance of Discussion.


93
94
95
96
# File 'app/models/discussion.rb', line 93

def initialize(notes, context_noteable = nil)
  @notes = notes
  @context_noteable = context_noteable
end

Instance Attribute Details

#context_noteableObject (readonly)

Returns the value of attribute context_noteable


10
11
12
# File 'app/models/discussion.rb', line 10

def context_noteable
  @context_noteable
end

#notesObject (readonly)

Returns the value of attribute notes


10
11
12
# File 'app/models/discussion.rb', line 10

def notes
  @notes
end

Class Method Details

.base_discussion_id(note) ⇒ Object


67
68
69
70
# File 'app/models/discussion.rb', line 67

def self.base_discussion_id(note)
  noteable_id = note.noteable_id || note.commit_id
  [:discussion, note.noteable_type.try(:underscore), noteable_id]
end

.build(notes, context_noteable = nil) ⇒ Object


37
38
39
# File 'app/models/discussion.rb', line 37

def self.build(notes, context_noteable = nil)
  notes.first.discussion_class(context_noteable).new(notes, context_noteable)
end

.build_collection(notes, context_noteable = nil) ⇒ Object


41
42
43
44
# File 'app/models/discussion.rb', line 41

def self.build_collection(notes, context_noteable = nil)
  grouped_notes = notes.group_by { |n| n.discussion_id(context_noteable) }
  grouped_notes.values.map { |notes| build(notes, context_noteable) }
end

.build_discussion_id(note) ⇒ Object

Returns an array of discussion ID components


63
64
65
# File 'app/models/discussion.rb', line 63

def self.build_discussion_id(note)
  [*base_discussion_id(note), SecureRandom.hex]
end

.discussion_id(note) ⇒ Object

Returns an alphanumeric discussion ID based on `build_discussion_id`


58
59
60
# File 'app/models/discussion.rb', line 58

def self.discussion_id(note)
  Digest::SHA1.hexdigest(build_discussion_id(note).join("-"))
end

.lazy_find(discussion_id) ⇒ Object


46
47
48
49
50
51
52
53
54
55
# File 'app/models/discussion.rb', line 46

def self.lazy_find(discussion_id)
  BatchLoader.for(discussion_id).batch do |discussion_ids, loader|
    results = Note.where(discussion_id: discussion_ids).fresh.to_a.group_by(&:discussion_id)
    results.each do |discussion_id, notes|
      next if notes.empty?

      loader.call(discussion_id, Discussion.build(notes))
    end
  end
end

.note_classObject


89
90
91
# File 'app/models/discussion.rb', line 89

def self.note_class
  DiscussionNote
end

.override_discussion_id(note) ⇒ Object

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 turn a list of notes into a list of discussions, they are grouped by discussion ID, so 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`.


85
86
87
# File 'app/models/discussion.rb', line 85

def self.override_discussion_id(note)
  nil
end

Instance Method Details

#==(other) ⇒ Object


102
103
104
105
106
107
# File 'app/models/discussion.rb', line 102

def ==(other)
  other.class == self.class &&
    other.context_noteable == self.context_noteable &&
    other.id == self.id &&
    other.notes == self.notes
end

#can_convert_to_discussion?Boolean

Returns:

  • (Boolean)

141
142
143
# File 'app/models/discussion.rb', line 141

def can_convert_to_discussion?
  false
end

#collapsed?Boolean

Returns:

  • (Boolean)

149
150
151
# File 'app/models/discussion.rb', line 149

def collapsed?
  resolved?
end

#declarative_policy_delegateObject


29
30
31
# File 'app/models/discussion.rb', line 29

def declarative_policy_delegate
  first_note
end

#diff_discussion?Boolean

Returns:

  • (Boolean)

133
134
135
# File 'app/models/discussion.rb', line 133

def diff_discussion?
  false
end

#expanded?Boolean

Returns:

  • (Boolean)

153
154
155
# File 'app/models/discussion.rb', line 153

def expanded?
  !collapsed?
end

#idObject Also known as: to_param


121
122
123
# File 'app/models/discussion.rb', line 121

def id
  first_note.discussion_id(context_noteable)
end

#individual_note?Boolean

Returns:

  • (Boolean)

137
138
139
# File 'app/models/discussion.rb', line 137

def individual_note?
  false
end

#last_noteObject


145
146
147
# File 'app/models/discussion.rb', line 145

def last_note
  @last_note ||= notes.last
end

#last_updated_atObject


109
110
111
# File 'app/models/discussion.rb', line 109

def last_updated_at
  last_note.created_at
end

#last_updated_byObject


113
114
115
# File 'app/models/discussion.rb', line 113

def last_updated_by
  last_note.author
end

#on_image?Boolean

Returns:

  • (Boolean)

98
99
100
# File 'app/models/discussion.rb', line 98

def on_image?
  false
end

#project_idObject


33
34
35
# File 'app/models/discussion.rb', line 33

def project_id
  project&.id
end

#reply_attributesObject


157
158
159
# File 'app/models/discussion.rb', line 157

def reply_attributes
  first_note.slice(:type, :noteable_type, :noteable_id, :commit_id, :discussion_id)
end

#reply_idObject


125
126
127
128
129
# File 'app/models/discussion.rb', line 125

def reply_id
  # To reply to this discussion, we need the actual discussion_id from the database,
  # not the potentially overwritten one based on the noteable.
  first_note.discussion_id
end

#updated?Boolean

Returns:

  • (Boolean)

117
118
119
# File 'app/models/discussion.rb', line 117

def updated?
  last_updated_at != created_at
end