Commit 2058e71e authored by Douwe Maan's avatar Douwe Maan Committed by Luke "Jared" Bennett

Extract commonalities between DiffDiscussion and LegacyDiffDiscussion

parent 874413cf
module DiscussionOnDiff
extend ActiveSupport::Concern
included do
NUMBER_OF_TRUNCATED_DIFF_LINES = 16
memoized_values << :active
delegate :line_code,
:original_line_code,
:diff_file,
:diff_line,
:for_line?,
:active?,
to: :first_note
delegate :file_path,
:blob,
:highlighted_diff_lines,
:diff_lines,
to: :diff_file,
allow_nil: true
end
def diff_discussion?
true
end
def active?
return @active if @active.present?
@active = first_note.active?
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
end
end
module ResolvableDiscussion
extend ActiveSupport::Concern
included do
memoized_values << :resolvable
memoized_values << :resolved
memoized_values << :first_note
memoized_values << :first_note_to_resolve
memoized_values << :last_resolved_note
memoized_values << :last_note
delegate :resolved_at,
:resolved_by,
to: :last_resolved_note,
allow_nil: true
end
# Keep this method in sync with the `potentially_resolvable` scope on `ResolvableNote`
def potentially_resolvable?
for_merge_request?
end
def resolvable?
return @resolvable if @resolvable.present?
@resolvable = potentially_resolvable? && notes.any?(&:resolvable?)
end
def resolved?
return @resolved if @resolved.present?
@resolved = resolvable? && notes.none?(&:to_be_resolved?)
end
def first_note
@first_note ||= notes.first
end
def first_note_to_resolve
return unless resolvable?
@first_note_to_resolve ||= notes.find(&:to_be_resolved?)
end
def last_resolved_note
return unless resolved?
@last_resolved_note ||= resolved_notes.sort_by(&:resolved_at).last
end
def resolved_notes
notes.select(&:resolved?)
end
def to_be_resolved?
resolvable? && !resolved?
end
def can_resolve?(current_user)
return false unless current_user
return false unless resolvable?
current_user == self.noteable.author ||
current_user.can?(:resolve_note, self.project)
end
def resolve!(current_user)
return unless resolvable?
update { |notes| notes.resolve!(current_user) }
end
def unresolve!
return unless resolvable?
update { |notes| notes.unresolve! }
end
end
class DiffDiscussion < Discussion
NUMBER_OF_TRUNCATED_DIFF_LINES = 16
include DiscussionOnDiff
delegate :line_code,
:original_line_code,
:diff_file,
:diff_line,
:for_line?,
:active?,
delegate :position,
:original_position,
to: :first_note
delegate :file_path,
:blob,
:highlighted_diff_lines,
:diff_lines,
to: :diff_file,
allow_nil: true
def self.build_discussion_id(note)
[*super(note), *unique_position_identifier(note)]
[*super(note), *note.position.key]
end
def self.build_original_discussion_id(note)
[*Discussion.build_discussion_id(note), *note.original_position.key]
end
def self.unique_position_identifier(note)
note.position.key
end
def diff_discussion?
true
end
def legacy_diff_discussion?
false
end
def active?
return @active if @active.present?
@active = first_note.active?
end
MEMOIZED_VALUES << :active
def reply_attributes
super.merge(first_note.diff_attributes)
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
super.merge(
original_position: original_position.to_json,
position: position.to_json,
)
end
end
......@@ -21,23 +21,12 @@ class DiffNote < Note
before_validation :set_discussion_id, if: :position_changed?
after_save :keep_around_commits
def new_diff_note?
true
end
def discussion_class(*)
DiffDiscussion
end
def diff_attributes
{
original_position: original_position.to_json,
position: position.to_json,
}
end
%i(original_position= position=).each do |meth|
define_method meth do |new_position|
%i(original_position position).each do |meth|
define_method "#{meth}=" do |new_position|
if new_position.is_a?(String)
new_position = JSON.parse(new_position) rescue nil
end
......
class Discussion
MEMOIZED_VALUES = [] # rubocop:disable Style/MutableConstant
cattr_accessor :memoized_values, instance_accessor: false do
[]
end
include ResolvableDiscussion
attr_reader :notes, :noteable
......@@ -13,12 +17,6 @@ class Discussion
to: :first_note
delegate :resolved_at,
:resolved_by,
to: :last_resolved_note,
allow_nil: true
def self.build(notes, noteable = nil)
notes.first.discussion_class(noteable).new(notes, noteable)
end
......@@ -98,76 +96,9 @@ class Discussion
notes.length == 1
end
# Keep this method in sync with the `potentially_resolvable` scope on `ResolvableNote`
def potentially_resolvable?
for_merge_request?
end
def resolvable?
return @resolvable if @resolvable.present?
@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
end
MEMOIZED_VALUES << :first_note
def first_note_to_resolve
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
end
MEMOIZED_VALUES << :last_note
def resolved_notes
notes.select(&:resolved?)
end
def to_be_resolved?
resolvable? && !resolved?
end
def can_resolve?(current_user)
return false unless current_user
return false unless resolvable?
current_user == self.noteable.author ||
current_user.can?(:resolve_note, self.project)
end
def resolve!(current_user)
return unless resolvable?
update { |notes| notes.resolve!(current_user) }
end
def unresolve!
return unless resolvable?
update { |notes| notes.unresolve! }
end
def collapsed?
resolved?
......@@ -192,7 +123,7 @@ class Discussion
# Set the notes array to the updated notes
@notes = notes_relation.fresh.to_a
MEMOIZED_VALUES.each do |var|
self.class.memoized_values.each do |var|
instance_variable_set(:"@#{var}", nil)
end
end
......
class LegacyDiffDiscussion < DiffDiscussion
def self.unique_position_identifier(note)
note.line_code
end
class LegacyDiffDiscussion < Discussion
include DiscussionOnDiff
def self.build_original_discussion_id(note)
Discussion.build_original_discussion_id(note)
def self.build_discussion_id(note)
[*super(note), note.line_code]
end
def legacy_diff_discussion?
......@@ -19,4 +17,8 @@ class LegacyDiffDiscussion < DiffDiscussion
def collapsed?
!active?
end
def reply_attributes
super.merge(line_code: line_code)
end
end
......@@ -11,14 +11,6 @@ class LegacyDiffNote < Note
LegacyDiffDiscussion
end
def legacy_diff_note?
true
end
def diff_attributes
{ line_code: line_code }
end
def project_repository
if RequestStore.active?
RequestStore.fetch("project:#{project_id}:repository") { self.project.repository }
......
......@@ -846,8 +846,8 @@ class MergeRequest < ActiveRecord::Base
return unless has_complete_diff_refs?
return if new_diff_refs == old_diff_refs
active_diff_notes = self.notes.diff_notes.select do |note|
note.new_diff_note? && note.active?(old_diff_refs)
active_diff_notes = self.notes.new_diff_notes.select do |note|
note.active?(old_diff_refs)
end
return if active_diff_notes.empty?
......
......@@ -75,6 +75,7 @@ class Note < ActiveRecord::Base
end
scope :diff_notes, ->{ where(type: %w(LegacyDiffNote DiffNote)) }
scope :new_diff_notes, ->{ where(type: 'DiffNote') }
scope :non_diff_notes, ->{ where(type: ['Note', 'DiscussionNote', nil]) }
scope :with_associations, -> do
......@@ -136,14 +137,6 @@ class Note < ActiveRecord::Base
false
end
def legacy_diff_note?
false
end
def new_diff_note?
false
end
def active?
true
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment