100 lines
3.0 KiB
Ruby
100 lines
3.0 KiB
Ruby
|
require_relative './carto_json_serializer'
|
||
|
require_relative '../../controllers/carto/api/legend_presenter'
|
||
|
require_dependency 'carto/legend_definition_validator'
|
||
|
|
||
|
module Carto
|
||
|
class Legend < ActiveRecord::Base
|
||
|
self.inheritance_column = :_type
|
||
|
|
||
|
belongs_to :layer, class_name: Carto::Layer
|
||
|
|
||
|
VALID_LEGEND_TYPES = %w(category bubble choropleth custom custom_choropleth torque).freeze
|
||
|
LEGEND_TYPES_PER_ATTRIBUTE = {
|
||
|
color: %w(category choropleth custom custom_choropleth torque),
|
||
|
size: %w(bubble)
|
||
|
}.freeze
|
||
|
|
||
|
serialize :definition, ::Carto::CartoJsonSymbolizerSerializer
|
||
|
serialize :conf, ::Carto::CartoJsonSymbolizerSerializer
|
||
|
|
||
|
validates :definition, carto_json_symbolizer: true
|
||
|
serialize :conf, ::Carto::CartoJsonSymbolizerSerializer
|
||
|
validates :type, :layer, presence: true
|
||
|
validates :type, inclusion: { in: VALID_LEGEND_TYPES }, allow_nil: true
|
||
|
|
||
|
validate :on_data_layer,
|
||
|
:under_max_legends_per_layer,
|
||
|
:under_max_legends_per_layer_and_type,
|
||
|
:validate_definition_schema,
|
||
|
:validate_conf_schema
|
||
|
|
||
|
before_validation :ensure_definition, :ensure_conf
|
||
|
|
||
|
after_save :force_notify_layer_change
|
||
|
after_destroy :force_notify_layer_change
|
||
|
|
||
|
private
|
||
|
|
||
|
def ensure_definition
|
||
|
self.definition ||= Hash.new
|
||
|
end
|
||
|
|
||
|
def ensure_conf
|
||
|
self.conf ||= Hash.new
|
||
|
end
|
||
|
|
||
|
def on_data_layer
|
||
|
if layer && !layer.data_layer?
|
||
|
errors.add(:layer, "'#{layer.kind}' layers can't have legends")
|
||
|
end
|
||
|
end
|
||
|
|
||
|
MAX_LEGENDS_PER_LAYER = 2
|
||
|
|
||
|
def under_max_legends_per_layer
|
||
|
if layer
|
||
|
other_legends = layer.legends.select { |legend| legend.id != id }
|
||
|
|
||
|
unless other_legends.count < MAX_LEGENDS_PER_LAYER
|
||
|
errors.add(:layer, 'Maximum number of legends per layer reached')
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def under_max_legends_per_layer_and_type
|
||
|
return unless type
|
||
|
LEGEND_TYPES_PER_ATTRIBUTE.each do |attribute, legend_types|
|
||
|
next unless legend_types.include?(type)
|
||
|
|
||
|
other_legends_present = layer.legends.any? { |legend| legend.id != id && legend_types.include?(legend.type) }
|
||
|
errors.add(:layer, "Only one #{attribute} legend per layer allowed") if other_legends_present
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def validate_definition_schema
|
||
|
validator = Carto::LegendDefinitionValidator.new(type, definition)
|
||
|
definition_errors = validator.errors
|
||
|
|
||
|
if definition_errors.any?
|
||
|
errors.add(:definition, definition_errors.join(', '))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def validate_conf_schema
|
||
|
schema = Carto::Definition.instance
|
||
|
.load_from_file('lib/formats/legends/conf.json')
|
||
|
|
||
|
parsed_conf = conf.try(:is_a?, Hash) ? conf.with_indifferent_access : conf
|
||
|
conf_errors = JSON::Validator.fully_validate(schema, parsed_conf)
|
||
|
|
||
|
if conf_errors.any?
|
||
|
errors.add(:conf, conf_errors.join(', '))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def force_notify_layer_change
|
||
|
layer.force_notify_change
|
||
|
end
|
||
|
end
|
||
|
end
|