2018-11-18 11:00:15 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
class ResourceLabelEvent < ApplicationRecord
|
2018-11-20 20:47:30 +05:30
|
|
|
include Importable
|
|
|
|
include Gitlab::Utils::StrongMemoize
|
|
|
|
include CacheMarkdownField
|
|
|
|
|
|
|
|
cache_markdown_field :reference
|
|
|
|
|
2018-11-18 11:00:15 +05:30
|
|
|
belongs_to :user
|
|
|
|
belongs_to :issue
|
|
|
|
belongs_to :merge_request
|
|
|
|
belongs_to :label
|
|
|
|
|
2018-11-20 20:47:30 +05:30
|
|
|
scope :created_after, ->(time) { where('created_at > ?', time) }
|
2019-09-30 23:59:55 +05:30
|
|
|
scope :inc_relations, -> { includes(:label, :user) }
|
2018-11-20 20:47:30 +05:30
|
|
|
|
|
|
|
validates :user, presence: { unless: :importing? }, on: :create
|
|
|
|
validates :label, presence: { unless: :importing? }, on: :create
|
2018-11-18 11:00:15 +05:30
|
|
|
validate :exactly_one_issuable
|
|
|
|
|
2018-11-20 20:47:30 +05:30
|
|
|
after_save :expire_etag_cache
|
|
|
|
after_destroy :expire_etag_cache
|
|
|
|
|
2018-11-18 11:00:15 +05:30
|
|
|
enum action: {
|
|
|
|
add: 1,
|
|
|
|
remove: 2
|
|
|
|
}
|
|
|
|
|
2018-11-20 20:47:30 +05:30
|
|
|
def self.issuable_attrs
|
|
|
|
%i(issue merge_request).freeze
|
2018-11-18 11:00:15 +05:30
|
|
|
end
|
|
|
|
|
2019-09-30 23:59:55 +05:30
|
|
|
def self.preload_label_subjects(events)
|
|
|
|
labels = events.map(&:label).compact
|
|
|
|
project_labels, group_labels = labels.partition { |label| label.is_a? ProjectLabel }
|
|
|
|
|
|
|
|
preloader = ActiveRecord::Associations::Preloader.new
|
|
|
|
preloader.preload(project_labels, { project: :project_feature })
|
|
|
|
preloader.preload(group_labels, :group)
|
|
|
|
end
|
|
|
|
|
2018-11-18 11:00:15 +05:30
|
|
|
def issuable
|
|
|
|
issue || merge_request
|
|
|
|
end
|
|
|
|
|
2018-11-20 20:47:30 +05:30
|
|
|
def discussion_id(resource = nil)
|
|
|
|
strong_memoize(:discussion_id) do
|
2019-09-30 21:07:59 +05:30
|
|
|
Digest::SHA1.hexdigest(discussion_id_key.join("-"))
|
2018-11-20 20:47:30 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def project
|
|
|
|
issuable.project
|
|
|
|
end
|
|
|
|
|
|
|
|
def group
|
|
|
|
issuable.group if issuable.respond_to?(:group)
|
|
|
|
end
|
|
|
|
|
|
|
|
def outdated_markdown?
|
|
|
|
return true if label_id.nil? && reference.present?
|
|
|
|
|
|
|
|
reference.nil? || latest_cached_markdown_version != cached_markdown_version
|
|
|
|
end
|
|
|
|
|
|
|
|
def banzai_render_context(field)
|
|
|
|
super.merge(pipeline: 'label', only_path: true)
|
|
|
|
end
|
|
|
|
|
|
|
|
def refresh_invalid_reference
|
|
|
|
# label_id could be nullified on label delete
|
|
|
|
self.reference = '' if label_id.nil?
|
|
|
|
|
|
|
|
# reference is not set for events which were not rendered yet
|
|
|
|
self.reference ||= label_reference
|
|
|
|
|
|
|
|
if changed?
|
|
|
|
save
|
|
|
|
elsif invalidated_markdown_cache?
|
|
|
|
refresh_markdown_cache!
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-11-18 11:00:15 +05:30
|
|
|
private
|
|
|
|
|
2018-11-20 20:47:30 +05:30
|
|
|
def label_reference
|
|
|
|
if local_label?
|
|
|
|
label.to_reference(format: :id)
|
|
|
|
elsif label.is_a?(GroupLabel)
|
|
|
|
label.to_reference(label.group, target_project: resource_parent, format: :id)
|
|
|
|
else
|
|
|
|
label.to_reference(resource_parent, format: :id)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-11-18 11:00:15 +05:30
|
|
|
def exactly_one_issuable
|
2018-11-20 20:47:30 +05:30
|
|
|
issuable_count = self.class.issuable_attrs.count { |attr| self["#{attr}_id"] }
|
|
|
|
|
|
|
|
return true if issuable_count == 1
|
|
|
|
|
|
|
|
# if none of issuable IDs is set, check explicitly if nested issuable
|
|
|
|
# object is set, this is used during project import
|
|
|
|
if issuable_count == 0 && importing?
|
|
|
|
issuable_count = self.class.issuable_attrs.count { |attr| self.public_send(attr) } # rubocop:disable GitlabSecurity/PublicSend
|
|
|
|
|
|
|
|
return true if issuable_count == 1
|
2018-11-18 11:00:15 +05:30
|
|
|
end
|
2018-11-20 20:47:30 +05:30
|
|
|
|
|
|
|
errors.add(:base, "Exactly one of #{self.class.issuable_attrs.join(', ')} is required")
|
|
|
|
end
|
|
|
|
|
|
|
|
def expire_etag_cache
|
|
|
|
issuable.expire_note_etag_cache
|
|
|
|
end
|
|
|
|
|
|
|
|
def local_label?
|
|
|
|
params = { include_ancestor_groups: true }
|
|
|
|
if resource_parent.is_a?(Project)
|
|
|
|
params[:project_id] = resource_parent.id
|
|
|
|
else
|
|
|
|
params[:group_id] = resource_parent.id
|
|
|
|
end
|
|
|
|
|
|
|
|
LabelsFinder.new(nil, params).execute(skip_authorization: true).where(id: label.id).any?
|
|
|
|
end
|
|
|
|
|
|
|
|
def resource_parent
|
|
|
|
issuable.project || issuable.group
|
2018-11-18 11:00:15 +05:30
|
|
|
end
|
2019-09-30 21:07:59 +05:30
|
|
|
|
|
|
|
def discussion_id_key
|
|
|
|
[self.class.name, created_at, user_id]
|
|
|
|
end
|
2018-11-18 11:00:15 +05:30
|
|
|
end
|
2019-12-04 20:38:33 +05:30
|
|
|
|
|
|
|
ResourceLabelEvent.prepend_if_ee('EE::ResourceLabelEvent')
|