diff options
Diffstat (limited to 'app/models/discussion.rb')
-rw-r--r-- | app/models/discussion.rb | 152 |
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 |