cartodb/app/models/map/copier.rb
2020-06-15 10:58:47 +08:00

117 lines
3.3 KiB
Ruby

module CartoDB
module Map
class Copier
def copy(map, layers=true)
new_map = new_map_from(map).save
if layers
copy_layers(map, new_map)
end
new_map
end
def new_map_from(map)
@new_map ||= map.dup
# Explicit association assignment to make user itself available, beyond its id, for validations
if map.user
@new_map.user ||= map.user
end
# Default is to copy all attributes from the canonical map. This overrides it
@new_map.scrollwheel = true
@new_map.options[:scrollwheel] = true if @new_map.options
@new_map
end
def copy_layers(origin_map, destination_map)
layer_copies_from(origin_map).map do |layer|
link(destination_map, layer)
end
end
def copy_base_layer(origin_map, destination_map)
origin_map.user_layers.map do |layer|
link(destination_map, layer.dup)
end
end
# TL;DR: adds data layers between existing base layers.
#
# Stacks data layer on top of the last data layer and/or
# the first base layer found, and keeps any existing "top"
# base layers on top.
def copy_data_layers(origin_map, destination_map, user)
last_data = destination_map.layers.reverse.find(&:data_layer?)
order = if last_data
last_data.order + 1
else
first_base = destination_map.layers.find(&:base_layer?)
first_base ? (first_base.order + 1) : 0
end
modified_layers = []
data_layer_copies_from(origin_map, user).map do |layer|
# Push layers on top if needed
if(destination_map.layers.map(&:order).include?(order))
destination_map.layers.select { |l| l.order >= order }.each do |layer|
layer.order += 1
# layer must be saved later
modified_layers << layer
end
end
layer.order = order
link(destination_map, layer)
# link saves
modified_layers -= [layer]
order += 1
end
# this avoid extra saving (including validation) overhead
modified_layers.uniq.map(&:save)
end
private
attr_reader :map
def data_layer_copies_from(map, user)
map.data_layers.map do |layer|
new_layer = layer.dup
new_layer.qualify_for_organization(map.user.username) if user.id != map.user.id
user.builder_enabled? ? reset_layer_styles(layer, new_layer) : new_layer
end
end
def layer_copies_from(map)
map.layers.map(&:dup)
end
def link(map, layer)
layer.save
layer.add_map(map)
layer.save
end
def reset_layer_styles(old_layer, new_layer)
user_table = old_layer.user_tables.first
return new_layer unless user_table
geometry_type = user_table.service.geometry_types.first
return new_layer unless geometry_type
tile_style = ModelFactories::LayerFactory.builder_tile_style(geometry_type)
new_layer.options['tile_style'] = tile_style
style_properties = ModelFactories::LayerFactory.style_properties(geometry_type)
new_layer.options['style_properties'] = style_properties
new_layer
end
end
end
end