115 lines
2.8 KiB
Ruby
115 lines
2.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module ResolvableDiscussion
|
|
extend ActiveSupport::Concern
|
|
include ::Gitlab::Utils::StrongMemoize
|
|
|
|
included do
|
|
# A number of properties of this `Discussion`, like `first_note` and `resolvable?`, are memoized.
|
|
# When this discussion is resolved or unresolved, the values of these properties potentially change.
|
|
# To make sure all memoized values are reset when this happens, `update` resets all instance variables with names in
|
|
# `memoized_variables`. If you add a memoized method in `ResolvableDiscussion` or any `Discussion` subclass,
|
|
# please make sure the instance variable name is added to `memoized_values`, like below.
|
|
cattr_accessor :memoized_values, instance_accessor: false do
|
|
[]
|
|
end
|
|
|
|
memoized_values.push(
|
|
:resolvable,
|
|
:resolved,
|
|
:first_note,
|
|
:first_note_to_resolve,
|
|
:last_resolved_note,
|
|
:last_note
|
|
)
|
|
|
|
delegate :potentially_resolvable?,
|
|
:noteable_id,
|
|
:noteable_type,
|
|
to: :first_note
|
|
|
|
delegate :resolved_at,
|
|
:resolved_by,
|
|
:resolved_by_push?,
|
|
to: :last_resolved_note,
|
|
allow_nil: true
|
|
end
|
|
|
|
def resolvable?
|
|
strong_memoize(:resolvable) do
|
|
potentially_resolvable? && notes.any?(&:resolvable?)
|
|
end
|
|
end
|
|
|
|
def resolved?
|
|
strong_memoize(:resolved) do
|
|
resolvable? && notes.none?(&:to_be_resolved?)
|
|
end
|
|
end
|
|
|
|
def first_note
|
|
strong_memoize(:first_note) do
|
|
notes.first
|
|
end
|
|
end
|
|
|
|
def first_note_to_resolve
|
|
return unless resolvable?
|
|
|
|
strong_memoize(:first_note_to_resolve) do
|
|
notes.find(&:to_be_resolved?)
|
|
end
|
|
end
|
|
|
|
def last_resolved_note
|
|
return unless resolved?
|
|
|
|
strong_memoize(:last_resolved_note) do
|
|
resolved_notes.max_by(&:resolved_at)
|
|
end
|
|
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.try(: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
|
|
|
|
private
|
|
|
|
def update
|
|
# 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.fresh.to_a # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
|
|
|
self.class.memoized_values.each do |name|
|
|
clear_memoization(name)
|
|
end
|
|
end
|
|
end
|