gitlab-org--gitlab-foss/app/models/discussion.rb

193 lines
4.0 KiB
Ruby
Raw Normal View History

class Discussion
MEMOIZED_VALUES = [] # rubocop:disable Style/MutableConstant
attr_reader :notes
delegate :created_at,
:project,
:author,
:noteable,
:for_commit?,
:for_merge_request?,
to: :first_note
2016-07-26 04:36:03 +00:00
delegate :resolved_at,
:resolved_by,
to: :last_resolved_note,
allow_nil: true
2016-07-26 04:36:03 +00:00
def self.build(notes, noteable = nil)
notes.first.discussion_class(noteable).new(notes, noteable)
end
def self.build_collection(notes, noteable = nil)
notes.group_by { |n| n.discussion_id(noteable) }.values.map { |notes| build(notes, noteable) }
end
def self.discussion_id(note)
Digest::SHA1.hexdigest(build_discussion_id(note).join("-"))
end
# Optionally override the discussion ID at runtime depending on circumstances
def self.override_discussion_id(note)
nil
end
def self.build_discussion_id(note)
noteable_id = note.noteable_id || note.commit_id
[:discussion, note.noteable_type.try(:underscore), noteable_id]
end
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
# 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
last_note.created_at
end
def last_updated_by
last_note.author
end
def id
first_note.discussion_id(noteable)
end
2016-08-15 23:45:23 +00:00
alias_method :to_param, :id
def original_id
first_note.original_discussion_id
end
def diff_discussion?
false
end
def render_as_individual_notes?
false
end
def potentially_resolvable?
first_note.for_merge_request?
end
2016-07-26 04:36:03 +00:00
def resolvable?
return @resolvable if @resolvable.present?
@resolvable = potentially_resolvable? && notes.any?(&:resolvable?)
2016-07-26 04:36:03 +00:00
end
MEMOIZED_VALUES << :resolvable
2016-07-26 04:36:03 +00:00
def resolved?
return @resolved if @resolved.present?
@resolved = resolvable? && notes.none?(&:to_be_resolved?)
2016-07-26 04:36:03 +00:00
end
MEMOIZED_VALUES << :resolved
2016-07-26 04:36:03 +00:00
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
2016-07-26 04:36:03 +00:00
def to_be_resolved?
resolvable? && !resolved?
2016-07-26 04:36:03 +00:00
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
2016-07-26 04:46:13 +00:00
def collapsed?
if resolvable?
# New diff discussions only disappear once they are marked resolved
resolved?
else
false
2016-07-26 04:46:13 +00:00
end
end
def expanded?
2016-07-26 04:46:13 +00:00
!collapsed?
end
def reply_attributes
first_note.slice(:type, :noteable_type, :noteable_id, :commit_id)
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
MEMOIZED_VALUES.each do |var|
instance_variable_set(:"@#{var}", nil)
end
end
end