2018-08-03 13:22:24 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-03-30 20:38:21 -04:00
|
|
|
module ResolvableDiscussion
|
|
|
|
extend ActiveSupport::Concern
|
2018-01-09 12:30:04 -05:00
|
|
|
include ::Gitlab::Utils::StrongMemoize
|
2017-03-30 20:38:21 -04:00
|
|
|
|
|
|
|
included do
|
2017-04-04 18:27:23 -04:00
|
|
|
# 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
|
|
|
|
|
2017-03-30 23:06:09 -04:00
|
|
|
memoized_values.push(
|
|
|
|
:resolvable,
|
|
|
|
:resolved,
|
|
|
|
:first_note,
|
|
|
|
:first_note_to_resolve,
|
|
|
|
:last_resolved_note,
|
|
|
|
:last_note
|
|
|
|
)
|
2017-03-30 20:38:21 -04:00
|
|
|
|
2017-04-06 11:05:57 -04:00
|
|
|
delegate :potentially_resolvable?, to: :first_note
|
|
|
|
|
2017-03-30 20:38:21 -04:00
|
|
|
delegate :resolved_at,
|
|
|
|
:resolved_by,
|
2017-09-05 11:49:05 -04:00
|
|
|
:resolved_by_push?,
|
2017-03-30 20:38:21 -04:00
|
|
|
|
|
|
|
to: :last_resolved_note,
|
|
|
|
allow_nil: true
|
|
|
|
end
|
|
|
|
|
|
|
|
def resolvable?
|
2018-01-09 12:30:04 -05:00
|
|
|
strong_memoize(:resolvable) do
|
|
|
|
potentially_resolvable? && notes.any?(&:resolvable?)
|
|
|
|
end
|
2017-03-30 20:38:21 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def resolved?
|
2018-01-09 12:30:04 -05:00
|
|
|
strong_memoize(:resolved) do
|
|
|
|
resolvable? && notes.none?(&:to_be_resolved?)
|
|
|
|
end
|
2017-03-30 20:38:21 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def first_note
|
2018-01-10 05:09:00 -05:00
|
|
|
strong_memoize(:first_note) do
|
|
|
|
notes.first
|
|
|
|
end
|
2017-03-30 20:38:21 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def first_note_to_resolve
|
|
|
|
return unless resolvable?
|
|
|
|
|
2018-01-09 12:30:04 -05:00
|
|
|
strong_memoize(:first_note_to_resolve) do
|
|
|
|
notes.find(&:to_be_resolved?)
|
|
|
|
end
|
2017-03-30 20:38:21 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def last_resolved_note
|
|
|
|
return unless resolved?
|
|
|
|
|
2018-01-09 12:30:04 -05:00
|
|
|
strong_memoize(:last_resolved_note) do
|
|
|
|
resolved_notes.sort_by(&:resolved_at).last
|
|
|
|
end
|
2017-03-30 20:38:21 -04:00
|
|
|
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
|
2017-04-04 18:27:23 -04:00
|
|
|
|
|
|
|
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
|
2018-04-18 09:41:42 -04:00
|
|
|
@notes = notes_relation.fresh.to_a # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
2017-04-04 18:27:23 -04:00
|
|
|
|
2018-01-10 05:09:00 -05:00
|
|
|
self.class.memoized_values.each do |name|
|
|
|
|
clear_memoization(name)
|
2017-04-04 18:27:23 -04:00
|
|
|
end
|
|
|
|
end
|
2017-03-30 20:38:21 -04:00
|
|
|
end
|