summaryrefslogtreecommitdiff
path: root/app/models/discussion.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/discussion.rb')
-rw-r--r--app/models/discussion.rb152
1 files changed, 71 insertions, 81 deletions
diff --git a/app/models/discussion.rb b/app/models/discussion.rb
index bbe813db823..314aea2c63a 100644
--- a/app/models/discussion.rb
+++ b/app/models/discussion.rb
@@ -1,5 +1,5 @@
class Discussion
- NUMBER_OF_TRUNCATED_DIFF_LINES = 16
+ MEMOIZED_VALUES = [] # rubocop:disable Style/MutableConstant
attr_reader :notes
@@ -11,12 +11,6 @@ class Discussion
:for_commit?,
:for_merge_request?,
- :line_code,
- :original_line_code,
- :diff_file,
- :for_line?,
- :active?,
-
to: :first_note
delegate :resolved_at,
@@ -25,29 +19,46 @@ class Discussion
to: :last_resolved_note,
allow_nil: true
- delegate :blob,
- :highlighted_diff_lines,
- :diff_lines,
+ def self.build(notes, noteable = nil)
+ notes.first.discussion_class(noteable).new(notes, noteable)
+ end
- to: :diff_file,
- allow_nil: true
+ def self.build_collection(notes, noteable = nil)
+ notes.group_by { |n| n.discussion_id(noteable) }.values.map { |notes| build(notes, noteable) }
+ end
- def self.for_notes(notes)
- notes.group_by(&:discussion_id).values.map { |notes| new(notes) }
+ def self.discussion_id(note)
+ Digest::SHA1.hexdigest(build_discussion_id(note).join("-"))
end
- def self.for_diff_notes(notes)
- notes.group_by(&:line_code).values.map { |notes| new(notes) }
+ # Optionally override the discussion ID at runtime depending on circumstances
+ def self.override_discussion_id(note)
+ nil
end
- def initialize(notes)
- @notes = notes
+ def self.build_discussion_id(note)
+ noteable_id = note.noteable_id || note.commit_id
+ [:discussion, note.noteable_type.try(:underscore), noteable_id]
end
- def last_resolved_note
- return unless resolved?
+ def self.original_discussion_id(note)
+ original_discussion_id = build_original_discussion_id(note)
+ if original_discussion_id
+ Digest::SHA1.hexdigest(original_discussion_id.join("-"))
+ else
+ note.discussion_id
+ end
+ end
- @last_resolved_note ||= resolved_notes.sort_by(&:resolved_at).last
+ # Optionally build a separate original discussion ID that will never change,
+ # if the main discussion ID _can_ change, like in the case of DiffDiscussion.
+ def self.build_original_discussion_id(note)
+ nil
+ end
+
+ def initialize(notes, noteable = nil)
+ @notes = notes
+ @noteable = noteable
end
def last_updated_at
@@ -59,42 +70,64 @@ class Discussion
end
def id
- first_note.discussion_id
+ first_note.discussion_id(noteable)
end
alias_method :to_param, :id
+ def original_id
+ first_note.original_discussion_id
+ end
+
def diff_discussion?
- first_note.diff_note?
+ false
+ end
+
+ def render_as_individual_notes?
+ false
end
- def legacy_diff_discussion?
- notes.any?(&:legacy_diff_note?)
+ def potentially_resolvable?
+ first_note.for_merge_request?
end
def resolvable?
return @resolvable if @resolvable.present?
- @resolvable = diff_discussion? && notes.any?(&:resolvable?)
+ @resolvable = potentially_resolvable? && notes.any?(&:resolvable?)
end
+ MEMOIZED_VALUES << :resolvable
def resolved?
return @resolved if @resolved.present?
@resolved = resolvable? && notes.none?(&:to_be_resolved?)
end
+ MEMOIZED_VALUES << :resolved
def first_note
- @first_note ||= @notes.first
+ @first_note ||= notes.first
end
+ MEMOIZED_VALUES << :first_note
def first_note_to_resolve
- @first_note_to_resolve ||= notes.detect(&:to_be_resolved?)
+ return unless resolvable?
+
+ @first_note_to_resolve ||= notes.find(&:to_be_resolved?)
end
+ MEMOIZED_VALUES << :first_note_to_resolve
+
+ def last_resolved_note
+ return unless resolved?
+
+ @last_resolved_note ||= resolved_notes.sort_by(&:resolved_at).last
+ end
+ MEMOIZED_VALUES << :last_resolved_note
def last_note
- @last_note ||= @notes.last
+ @last_note ||= notes.last
end
+ MEMOIZED_VALUES << :last_note
def resolved_notes
notes.select(&:resolved?)
@@ -124,25 +157,12 @@ class Discussion
update { |notes| notes.unresolve! }
end
- def for_target?(target)
- self.noteable == target && !diff_discussion?
- end
-
- def active?
- return @active if @active.present?
-
- @active = first_note.active?
- end
-
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?
+ false
end
end
@@ -151,52 +171,22 @@ class Discussion
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(highlight: true)
- lines = highlight ? highlighted_diff_lines : diff_lines
- prev_lines = []
-
- 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
+ first_note.slice(:type, :noteable_type, :noteable_id, :commit_id)
end
private
def update
- notes_relation = DiffNote.where(id: notes.map(&:id)).fresh
+ # Do not select `Note.resolvable`, so that system notes remain in the collection
+ notes_relation = Note.where(id: notes.map(&:id))
+
yield(notes_relation)
# Set the notes array to the updated notes
- @notes = notes_relation.to_a
+ @notes = notes_relation.fresh.to_a
- # Reset the memoized values
- @last_resolved_note = @resolvable = @resolved = @first_note = @last_note = nil
+ MEMOIZED_VALUES.each do |var|
+ instance_variable_set(:"@#{var}", nil)
+ end
end
end