Skip to content

Commit

Permalink
#5710 created export service + plugged automatic backup before deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
Kartones committed Sep 28, 2015
1 parent de185cf commit 1a358e3
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
require 'active_record'

module Carto
module Visualization
class Backup < ActiveRecord::Base
class VisualizationBackup < ActiveRecord::Base

# @param String username
# @param Uuid visualization
Expand All @@ -13,6 +12,5 @@ class Backup < ActiveRecord::Base

validates :username, :visualization, :export_vizjson, presence: true

end
end
end
9 changes: 8 additions & 1 deletion app/models/visualization/member.rb
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,14 @@ def fetch
self
end

def delete(from_table_deletion=false)
def delete(from_table_deletion = false)
begin
Carto::VisualizationsExportService.new.export(id)
rescue => exception
# Don't break deletion flow
CartoDB.notify_exception(exception, user: user, visualization_id: id)
end

# Named map must be deleted before the map, or we lose the reference to it
begin
named_map = get_named_map
Expand Down
93 changes: 93 additions & 0 deletions app/services/carto/visualizations_export_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# encoding: utf-8

require_relative "../../controllers/carto/api/visualization_vizjson_adapter"

module Carto
class VisualizationsExportService

SERVICE_VERSION = 1


def export(visualization_id)
visualization = Carto::Visualization.where(id: visualization_id).first
raise "Visualization with id #{visualization_id} not found" unless visualization

vizjson_options = {
full: true,
user_name: visualization.user.username,
user_api_key: visualization.user.api_key,
user: visualization.user,
viewer_user: visualization.user,
export: true
}

data = CartoDB::Visualization::VizJSON.new(
Carto::Api::VisualizationVizJSONAdapter.new(visualization, $tables_metadata), vizjson_options, Cartodb.config)
.to_export_poro(SERVICE_VERSION)
.to_json

backup_entry = Carto::VisualizationBackup.new(
username: visualization.user.username,
visualization: visualization.id,
export_vizjson: data
)

backup_entry.save

true
end

def import(visualization_id)
# TODO: support partial restores
visualization = Carto::Visualization.where(id: visualization_id).first
raise "Visualization with id #{visualization_id} already exists!" if visualization

restore_data = Carto::VisualizationBackup.where(visualization: visualization_id).first
raise "Restore data not found for visualization id #{visualization_id}" unless restore_data

dump_data = ::JSON.parse(restore_data.export_vizjson)

user = ::User.where(id: dump_data["owner"]["id"]).first

# TODO: Import base layer instead of using default one if present
base_layer = CartoDB::Factories::LayerFactory.get_default_base_layer(user)
map = CartoDB::Factories::MapFactory.get_map(base_layer, user.id)
map.add_layer(base_layer)

dump_data["layers"].select { |layer| layer["type"] == "layergroup" }.each do |layergroup|
layergroup["options"]["layer_definition"]["layers"].each do |layer|
# TODO: new factory method to "get_data_layer"
data_layer = CartoDB::Factories::LayerFactory.get_default_data_layer(layer["options"]["table_name"], user)
map.add_layer(data_layer)
end
end

dump_data["layers"].select { |layer| ::Layer::DATA_LAYER_KINDS.include?(layer["type"]) }.each do |layer|
# TODO: new factory method to "get_data_layer"
data_layer = CartoDB::Factories::LayerFactory.get_default_data_layer(layer["options"]["table_name"], user)
map.add_layer(data_layer)
end

# TODO: Import labels layer instead of using default one if present
if base_layer.supports_labels_layer?
labels_layer = CartoDB::Factories::LayerFactory.get_default_labels_layer(base_layer)
map.add_layer(labels_layer)
end

visualization = CartoDB::Visualization::Member.new(
id: dump_data["id"],
name: dump_data["title"],
description: dump_data["description"],
type: CartoDB::Visualization::Member::TYPE_DERIVED,
privacy: CartoDB::Visualization::Member::PRIVACY_LINK,
user_id: dump_data["owner"]["id"],
map_id: map.id,
kind: CartoDB::Visualization::Member::KIND_GEOM
)

visualization.store

true
end
end
end
83 changes: 8 additions & 75 deletions lib/tasks/viz_maintenance.rake
Original file line number Diff line number Diff line change
Expand Up @@ -66,91 +66,24 @@ namespace :cartodb do

desc "Exports/Backups a visualization"
task :export_user_visualization, [:vis_id] => :environment do |_, args|
require_relative "../../app/controllers/carto/api/visualization_vizjson_adapter"

visualization = Carto::Visualization.where(id: args[:vis_id]).first
raise "Visualization with id #{args[:vis_id]} not found" unless visualization

vizjson_options = {
full: true,
user_name: visualization.user.username,
user_api_key: visualization.user.api_key,
user: visualization.user,
viewer_user: visualization.user,
export: true
}
vis_export_service = Carto::VisualizationsExportService.new

puts "Exporting visualization #{args[:vis_id]}..."

data = CartoDB::Visualization::VizJSON.new(
Carto::Api::VisualizationVizJSONAdapter.new(visualization, $tables_metadata), vizjson_options, Cartodb.config)
.to_export_poro(1)
.to_json

backup_entry = Carto::Visualization::Backup.new(
username: visualization.user.username,
visualization: visualization.id,
export_vizjson: ::JSON.dump(data)
)

backup_entry.save
vis_export_service.export(args[:vis_id])

puts "Export complete"
end

desc "Imports a visualization using a metadata file"
task :import_user_visualization, [:export_file] => :environment do |_, args|
raise "Export '#{args[:export_file]}' not found" unless File.file?(args[:export_file])

puts "Importing visualization data from #{args[:export_file]}"

dump_data = ::JSON.parse(IO.read(args[:export_file]))

# TODO: support partial restores
unless Carto::Visualization.where(id: dump_data["id"]).first.nil?
raise "Visualization #{dump_data['id']} already exists"
end

user = ::User.where(id: dump_data["owner"]["id"]).first

# TODO: Import base layer instead of using default one if present
base_layer = CartoDB::Factories::LayerFactory.get_default_base_layer(user)
map = CartoDB::Factories::MapFactory.get_map(base_layer, user.id)
map.add_layer(base_layer)

dump_data["layers"].select { |layer| layer["type"] == "layergroup" }.each do |layergroup|
layergroup["options"]["layer_definition"]["layers"].each do |layer|
# TODO: new factory method to "get_data_layer"
data_layer = CartoDB::Factories::LayerFactory.get_default_data_layer(layer["options"]["table_name"], user)
map.add_layer(data_layer)
end
end

dump_data["layers"].select { |layer| ::Layer::DATA_LAYER_KINDS.include?(layer["type"]) }.each do |layer|
# TODO: new factory method to "get_data_layer"
data_layer = CartoDB::Factories::LayerFactory.get_default_data_layer(layer["options"]["table_name"], user)
map.add_layer(data_layer)
end

# TODO: Import labels layer instead of using default one if present
if base_layer.supports_labels_layer?
labels_layer = CartoDB::Factories::LayerFactory.get_default_labels_layer(base_layer)
map.add_layer(labels_layer)
end
desc "Imports/Restores a visualization"
task :import_user_visualization, [:vis_id] => :environment do |_, args|
vis_export_service = Carto::VisualizationsExportService.new

visualization = CartoDB::Visualization::Member.new(
id: dump_data["id"],
name: dump_data["title"],
description: dump_data["description"],
type: CartoDB::Visualization::Member::TYPE_DERIVED,
privacy: CartoDB::Visualization::Member::PRIVACY_LINK,
user_id: dump_data["owner"]["id"],
map_id: map.id,
kind: CartoDB::Visualization::Member::KIND_GEOM)
puts "Importing visualization data for uuid #{args[:vis_id]}"

visualization.store
vis_export_service.import(args[:vis_id])

puts "Visualization #{visualization.id} imported"
puts "Visualization #{args[:vis_id]} imported"
end

private
Expand Down

0 comments on commit 1a358e3

Please sign in to comment.