From d95c1f0335f7309114fcbb0d5413b28e1701a640 Mon Sep 17 00:00:00 2001 From: Jan Provaznik Date: Fri, 7 Sep 2018 13:39:20 +0000 Subject: Use ResourceLabelEvent for tracking label changes --- app/models/resource_label_event.rb | 101 ++++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 6 deletions(-) (limited to 'app/models/resource_label_event.rb') diff --git a/app/models/resource_label_event.rb b/app/models/resource_label_event.rb index 42c255fcd1e..3fd96b9dc18 100644 --- a/app/models/resource_label_event.rb +++ b/app/models/resource_label_event.rb @@ -3,33 +3,122 @@ # This model is not used yet, it will be used for: # https://gitlab.com/gitlab-org/gitlab-ce/issues/48483 class ResourceLabelEvent < ActiveRecord::Base + include Importable + include Gitlab::Utils::StrongMemoize + include CacheMarkdownField + + cache_markdown_field :reference + belongs_to :user belongs_to :issue belongs_to :merge_request belongs_to :label - validates :user, presence: true, on: :create - validates :label, presence: true, on: :create + scope :created_after, ->(time) { where('created_at > ?', time) } + + validates :user, presence: { unless: :importing? }, on: :create + validates :label, presence: { unless: :importing? }, on: :create validate :exactly_one_issuable + after_save :expire_etag_cache + after_destroy :expire_etag_cache + enum action: { add: 1, remove: 2 } - def self.issuable_columns - %i(issue_id merge_request_id).freeze + def self.issuable_attrs + %i(issue merge_request).freeze end def issuable issue || merge_request end + # create same discussion id for all actions with the same user and time + def discussion_id(resource = nil) + strong_memoize(:discussion_id) do + Digest::SHA1.hexdigest([self.class.name, created_at, user_id].join("-")) + 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 + private + 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 + def exactly_one_issuable - if self.class.issuable_columns.count { |attr| self[attr] } != 1 - errors.add(:base, "Exactly one of #{self.class.issuable_columns.join(', ')} is required") + 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 end + + 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 end end -- cgit v1.2.3