281 lines
11 KiB
Ruby
281 lines
11 KiB
Ruby
require_relative 'external_source_presenter'
|
|
require_relative 'permission_presenter'
|
|
require_relative 'user_table_presenter'
|
|
|
|
module Carto
|
|
module Api
|
|
class VisualizationPresenter
|
|
|
|
def initialize(visualization, current_viewer, context,
|
|
related: true, related_canonical_visualizations: false, show_user: false,
|
|
show_stats: true, show_table: true, show_liked: true,
|
|
show_permission: true, show_synchronization: true, show_uses_builder_features: true,
|
|
show_table_size_and_row_count: true, show_auth_tokens: true, show_user_basemaps: false,
|
|
password: nil, with_dependent_visualizations: 0)
|
|
@visualization = visualization
|
|
@current_viewer = current_viewer
|
|
@context = context
|
|
|
|
@related = related
|
|
@load_related_canonical_visualizations = related_canonical_visualizations
|
|
@show_user = show_user
|
|
@show_stats = show_stats
|
|
@show_liked = show_liked
|
|
@show_table = show_table
|
|
@show_permission = show_permission
|
|
@show_synchronization = show_synchronization
|
|
@show_uses_builder_features = show_uses_builder_features
|
|
@show_table_size_and_row_count = show_table_size_and_row_count
|
|
@show_auth_tokens = show_auth_tokens
|
|
@show_user_basemaps = show_user_basemaps
|
|
@password = password
|
|
@with_dependent_visualizations = with_dependent_visualizations
|
|
|
|
@presenter_cache = Carto::Api::PresenterCache.new
|
|
end
|
|
|
|
def with_presenter_cache(presenter_cache)
|
|
@presenter_cache = presenter_cache
|
|
self
|
|
end
|
|
|
|
def to_poro
|
|
return_private_poro = @visualization.can_view_private_info?(@current_viewer)
|
|
|
|
poro = return_private_poro ? to_private_poro : to_public_poro
|
|
|
|
poro[:user] = user if show_user
|
|
|
|
if load_related_canonical_visualizations
|
|
poro[:related_canonical_visualizations] = related_canonicals
|
|
# The count doesn't take into account privacy concerns
|
|
poro[:related_canonical_visualizations_count] = @visualization.related_canonical_visualizations.count
|
|
end
|
|
|
|
if with_dependent_visualizations > 0
|
|
dependencies = @visualization.dependent_visualizations
|
|
poro[:dependent_visualizations_count] = dependencies.count
|
|
limited_dependencies = most_recent_dependencies(dependencies, with_dependent_visualizations)
|
|
poro[:dependent_visualizations] = limited_dependencies.map do |dependent_visualization|
|
|
VisualizationPresenter.new(dependent_visualization, @current_viewer, @context).to_summarized_poro
|
|
end
|
|
end
|
|
|
|
poro[:liked] = @current_viewer ? @visualization.liked_by?(@current_viewer) : false if show_liked
|
|
poro[:permission] = permission if show_permission
|
|
poro[:stats] = show_stats ? @visualization.stats : {}
|
|
|
|
if show_auth_tokens
|
|
poro[:auth_tokens] = auth_tokens
|
|
elsif return_private_poro || @visualization.is_accessible_with_password?(@current_viewer, @password)
|
|
poro[:auth_tokens] = auth_tokens
|
|
end
|
|
|
|
poro[:table] = user_table_presentation if show_table
|
|
|
|
poro
|
|
end
|
|
|
|
def to_private_poro
|
|
poro = {
|
|
id: @visualization.id,
|
|
name: @visualization.name,
|
|
display_name: @visualization.display_name,
|
|
map_id: @visualization.map_id,
|
|
active_layer_id: @visualization.active_layer_id,
|
|
type: @visualization.type,
|
|
tags: @visualization.tags,
|
|
description: @visualization.description,
|
|
privacy: @visualization.privacy.upcase,
|
|
created_at: @visualization.created_at,
|
|
updated_at: @visualization.updated_at,
|
|
locked: @visualization.locked,
|
|
source: @visualization.source,
|
|
title: @visualization.title,
|
|
license: @visualization.license,
|
|
attributions: @visualization.attributions,
|
|
kind: @visualization.kind,
|
|
external_source: Carto::Api::ExternalSourcePresenter.new(@visualization.external_source).to_poro,
|
|
url: url,
|
|
version: @visualization.version || 2,
|
|
# TODO: The following are Odyssey fields and could be removed
|
|
# They are kept here for now for compatibility with the old presenter and JS code
|
|
# `children` is hardcoded to avoid a performance impact (an extra query)
|
|
prev_id: @visualization.prev_id,
|
|
next_id: @visualization.next_id,
|
|
parent_id: @visualization.parent_id,
|
|
transition_options: @visualization.transition_options,
|
|
active_child: nil,
|
|
children: []
|
|
}
|
|
|
|
poro[:related_tables] = related_tables if related
|
|
poro[:synchronization] = synchronization if show_synchronization
|
|
poro[:uses_builder_features] = @visualization.uses_builder_features? if show_uses_builder_features
|
|
|
|
poro
|
|
end
|
|
|
|
def to_public_poro
|
|
{
|
|
id: @visualization.id,
|
|
name: @visualization.name,
|
|
display_name: @visualization.display_name,
|
|
attributions: @visualization.attributions,
|
|
source: @visualization.source,
|
|
license: @visualization.license,
|
|
type: @visualization.type,
|
|
tags: @visualization.tags,
|
|
description: @visualization.description,
|
|
created_at: @visualization.created_at,
|
|
updated_at: @visualization.updated_at,
|
|
title: @visualization.title,
|
|
kind: @visualization.kind,
|
|
privacy: @visualization.privacy.upcase,
|
|
}
|
|
end
|
|
|
|
# For dependent visualizations
|
|
def to_summarized_poro
|
|
{
|
|
id: @visualization.id,
|
|
name: @visualization.name,
|
|
updated_at: @visualization.updated_at,
|
|
permission: permission.slice(:id, :owner),
|
|
auth_tokens: auth_tokens
|
|
}
|
|
end
|
|
|
|
def to_search_preview_poro
|
|
{
|
|
type: @visualization.type,
|
|
name: @visualization.name,
|
|
url: url
|
|
}
|
|
end
|
|
|
|
# Ideally this should go at a lower level, as relates to url generation, but at least centralize logic here
|
|
# INFO: For now, no support for non-org users, as intended use is for sharing urls
|
|
def privacy_aware_map_url(additional_params = {}, action = 'public_visualizations_show_map')
|
|
organization = @visualization.user.organization
|
|
|
|
return unless organization
|
|
|
|
# When a visualization is private, checks of permissions need not only the Id but also the vis owner database schema
|
|
# Logic on public_map route will handle permissions so here we only "namespace the id" when proceeds
|
|
if @visualization.is_privacy_private?
|
|
# Final url will be like ORG.carto.com/u/VIEWER/viz/OWNER_SCHEMA.VIS_ID/public_map
|
|
base_url_username = @current_viewer.username
|
|
vis_id_schema = @visualization.user.database_schema
|
|
else
|
|
# Final url will be like ORG.carto.com/u/VIEWER/viz/VIS_ID/public_map
|
|
base_url_username = @visualization.user.username
|
|
vis_id_schema = nil
|
|
end
|
|
# this builds only the fragment /viz/xxxxx/public_map
|
|
path = CartoDB.path(@context, action, additional_params.merge(id: qualified_visualization_id(vis_id_schema)))
|
|
"#{CartoDB.base_url(organization.name, base_url_username)}#{path}"
|
|
end
|
|
|
|
def qualified_visualization_id(schema = nil)
|
|
schema.nil? ? @visualization.id : "#{schema}.#{@visualization.id}"
|
|
end
|
|
|
|
private
|
|
|
|
attr_reader :related, :load_related_canonical_visualizations, :show_user,
|
|
:show_stats, :show_table, :show_liked,
|
|
:show_permission, :show_synchronization, :show_uses_builder_features,
|
|
:show_table_size_and_row_count, :show_auth_tokens,
|
|
:show_user_basemaps, :with_dependent_visualizations
|
|
|
|
def user_table_presentation
|
|
Carto::Api::UserTablePresenter.new(@visualization.user_table, @current_viewer,
|
|
show_size_and_row_count: show_table_size_and_row_count)
|
|
.with_presenter_cache(@presenter_cache).to_poro
|
|
end
|
|
|
|
def synchronization
|
|
Carto::Api::SynchronizationPresenter.new(@visualization.synchronization).to_poro
|
|
end
|
|
|
|
def permission
|
|
unless @visualization.permission.nil?
|
|
Carto::Api::PermissionPresenter.new(@visualization.permission, current_viewer: @current_viewer)
|
|
.with_presenter_cache(@presenter_cache).to_poro
|
|
end
|
|
end
|
|
|
|
def auth_tokens
|
|
if @visualization.password_protected? && (@visualization.user.id == @current_viewer.try(:id) || @visualization.password_valid?(@password))
|
|
@visualization.get_auth_tokens
|
|
elsif @visualization.is_privacy_private?
|
|
@current_viewer.get_auth_tokens
|
|
else
|
|
[]
|
|
end
|
|
end
|
|
|
|
def related_tables
|
|
related = if @visualization.user_table
|
|
@visualization.related_tables.select { |table| table.id != @visualization.user_table.id }
|
|
else
|
|
@visualization.related_tables
|
|
end
|
|
|
|
related.map do |table|
|
|
Carto::Api::UserTablePresenter.new(table, @current_viewer).with_presenter_cache(@presenter_cache).to_poro
|
|
end
|
|
end
|
|
|
|
def related_canonicals
|
|
@visualization
|
|
.related_canonical_visualizations
|
|
.select { |v| v.is_viewable_by_user?(@current_viewer) }
|
|
.map { |v| self.class.new(v, @current_viewer, @context).to_poro }
|
|
end
|
|
|
|
def children_poro(visualization)
|
|
{
|
|
id: visualization.id,
|
|
prev_id: visualization.prev_id,
|
|
type: visualization.type,
|
|
next_id: visualization.next_id,
|
|
transition_options: visualization.transition_options,
|
|
map_id: visualization.map_id
|
|
}
|
|
end
|
|
|
|
def url
|
|
if @visualization.canonical?
|
|
dataset_name = @visualization.qualified_name(@current_viewer).tr('"', '')
|
|
CartoDB.url(@context, 'public_tables_show_bis',
|
|
params: { id: dataset_name },
|
|
user: @current_viewer)
|
|
elsif @visualization.kuviz?
|
|
CartoDB.url(@context, 'kuviz_show',
|
|
params: { id: @visualization.id },
|
|
user: @current_viewer)
|
|
else
|
|
CartoDB.url(@context, 'public_visualizations_show_map',
|
|
params: { id: @visualization.id },
|
|
user: @current_viewer)
|
|
end
|
|
end
|
|
|
|
def user
|
|
Carto::Api::UserPresenter.new(@visualization.user,
|
|
current_viewer: @current_viewer,
|
|
fetch_db_size: false,
|
|
fetch_basemaps: show_user_basemaps,
|
|
fetch_profile: false).to_poro
|
|
end
|
|
|
|
def most_recent_dependencies(dependencies, limit)
|
|
sorted_dependencies = dependencies.sort_by(&:updated_at).reverse
|
|
sorted_dependencies.first(limit)
|
|
end
|
|
end
|
|
end
|
|
end
|