2017-03-30 20:38:21 -04:00
|
|
|
module ResolvableDiscussion
|
|
|
|
extend ActiveSupport::Concern
|
|
|
|
|
|
|
|
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?
|
|
|
|
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
|
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
|
|
|
|
@notes = notes_relation.fresh.to_a
|
|
|
|
|
|
|
|
self.class.memoized_values.each do |var|
|
|
|
|
instance_variable_set(:"@#{var}", nil)
|
|
|
|
end
|
|
|
|
end
|
2017-03-30 20:38:21 -04:00
|
|
|
end
|