Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace ContainerLabelTagMapping.controls_tag? with Tag.controlled_by_mapping scope #16449

Merged
merged 1 commit into from
Nov 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions app/models/container_label_tag_mapping.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
class ContainerLabelTagMapping < ApplicationRecord
belongs_to :tag

scope :any_value, -> { where(:label_value => nil) }
scope :specific_value, -> { where.not(:label_value => nil) }

require_nested :Mapper

# Return ContainerLabelTagMapping::Mapper instance that holds all current mappings,
Expand All @@ -31,24 +34,21 @@ def self.mapper

# Assigning/unassigning should be possible without Mapper instance, perhaps in another process.

# Checks whether a Tag record is under mapping control.
# TODO: expensive.
# Checks whether a Tag record is under mapping control. TODO: Remove? Only used by tests.
def self.controls_tag?(tag)
return false unless tag.classification.try(:read_only) # never touch user-assignable tags.
tag_ids = [tag.id, tag.category.tag_id].uniq
where(:tag_id => tag_ids).any?
Tag.controlled_by_mapping.where(:id => tag.id).exists?
end

# Assign/unassign mapping-controlled tags, preserving user-assigned tags.
# All tag references must have been resolved first by Mapper#find_or_create_tags.
def self.retag_entity(entity, tag_references)
mapped_tags = Mapper.references_to_tags(tag_references)
existing_tags = entity.tags
existing_tags = entity.tags.controlled_by_mapping
Tagging.transaction do
(mapped_tags - existing_tags).each do |tag|
Tagging.create!(:taggable => entity, :tag => tag)
end
(existing_tags - mapped_tags).select { |tag| controls_tag?(tag) }.tap do |tags|
(existing_tags - mapped_tags).tap do |tags|
Tagging.where(:taggable => entity, :tag => tags.collect(&:id)).destroy_all
end
end
Expand Down
25 changes: 24 additions & 1 deletion app/models/tag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ class Tag < ApplicationRecord
virtual_has_one :category, :class_name => "Classification"
virtual_has_one :categorization, :class_name => "Hash"

has_many :container_label_tag_mappings
has_many :container_label_tag_mappings # see also controlled_by_mapping scope

before_destroy :remove_from_managed_filters

# Note those scopes exclude Tags that don't have a Classification.
scope :visible, -> { joins(:classification).merge(Classification.visible) }
scope :read_only, -> { joins(:classification).merge(Classification.read_only) }
scope :writable, -> { joins(:classification).merge(Classification.writable) }

def self.list(object, options = {})
ns = get_namespace(options)
if ns[0..7] == "/virtual"
Expand Down Expand Up @@ -152,6 +157,24 @@ def categorization
end
end

# @return [ActiveRecord::Relation] Scope for tags controlled by ContainerLabelTagMapping.
# May include not only "entry" tags but also some parent "category" tags.
def self.controlled_by_mapping
# TODO: complex query, can we simply select by prefixes e.g. '/managed/kubernetes:%'?
# User can create categories with such prefix, but they won't be read_only.

# Entry tags from specific value->tag mappings.

mapped_specific_tags = read_only.where(:id => ContainerLabelTagMapping.specific_value.pluck(:tag_id))

# Entry tags for name->category mappings.
mapped_categories = Classification.where(:tag => ContainerLabelTagMapping.any_value.pluck(:tag_id))
mapped_entries = Classification.where(:parent => mapped_categories)
mapped_child_tags = read_only.where(:id => mapped_entries.select(:tag_id))

mapped_specific_tags.or(mapped_child_tags)
end

private

def remove_from_managed_filters
Expand Down