581 lines
17 KiB
Ruby
581 lines
17 KiB
Ruby
|
require 'spec_helper_min'
|
||
|
require 'support/helpers'
|
||
|
require 'factories/carto_visualizations'
|
||
|
|
||
|
module Carto
|
||
|
module Api
|
||
|
describe Carto::Api::LegendsController do
|
||
|
include Carto::Factories::Visualizations, HelperMethods
|
||
|
|
||
|
let(:category_legend_payload) do
|
||
|
{
|
||
|
pre_html: "<h3>Es acaso</h3>",
|
||
|
post_html: "<h3>el mejor artista del mundo?</h3>",
|
||
|
title: "La verdad",
|
||
|
type: "category",
|
||
|
conf: {
|
||
|
columns: ['manolo', 'escobar']
|
||
|
},
|
||
|
definition: {}
|
||
|
}
|
||
|
end
|
||
|
|
||
|
let(:custom_legend_payload) do
|
||
|
{
|
||
|
pre_html: "<h3>Es acaso</h3>",
|
||
|
post_html: "<h3>el mejor artista del mundo?</h3>",
|
||
|
title: "La verdad",
|
||
|
type: "custom",
|
||
|
conf: {
|
||
|
columns: ['manolo', 'escobar']
|
||
|
},
|
||
|
definition: {
|
||
|
categories: [
|
||
|
{ title: 'Manolo Escobar' },
|
||
|
{ title: 'Manolo Escobar', color: '#fff' },
|
||
|
{ title: 'Manolo Escobar', icon: 'super.png' },
|
||
|
{ title: 'Manolo Escobar', icon: 'super.png', color: '#FFF' }
|
||
|
]
|
||
|
}
|
||
|
}
|
||
|
end
|
||
|
|
||
|
let(:bubble_legend_payload) do
|
||
|
{
|
||
|
pre_html: "<h3>Es acaso</h3>",
|
||
|
post_html: "<h3>el mejor artista del mundo?</h3>",
|
||
|
title: "La verdad",
|
||
|
type: "bubble",
|
||
|
conf: {
|
||
|
columns: ['manolo', 'escobar']
|
||
|
},
|
||
|
definition: {
|
||
|
color: '#fff'
|
||
|
}
|
||
|
}
|
||
|
end
|
||
|
|
||
|
let(:choropleth_legend_payload) do
|
||
|
{
|
||
|
pre_html: "<h3>Es acaso</h3>",
|
||
|
post_html: "<h3>el mejor artista del mundo?</h3>",
|
||
|
title: "La verdad",
|
||
|
type: "choropleth",
|
||
|
conf: {
|
||
|
columns: ['manolo', 'escobar']
|
||
|
},
|
||
|
definition: {
|
||
|
prefix: "123",
|
||
|
suffix: "foo"
|
||
|
}
|
||
|
}
|
||
|
end
|
||
|
|
||
|
let(:custom_choropleth_legend_payload) do
|
||
|
{
|
||
|
pre_html: "<h3>Es acaso</h3>",
|
||
|
post_html: "<h3>el mejor artista del mundo?</h3>",
|
||
|
title: "La verdad",
|
||
|
type: "custom_choropleth",
|
||
|
conf: {
|
||
|
columns: ['manolo', 'escobar']
|
||
|
},
|
||
|
definition: {
|
||
|
prefix: "123",
|
||
|
suffix: "foo",
|
||
|
colors: [
|
||
|
{ color: '#fff' },
|
||
|
{ color: '#fabada' },
|
||
|
{ color: '#CCC' }
|
||
|
]
|
||
|
}
|
||
|
}
|
||
|
end
|
||
|
|
||
|
let(:fake_uuid) { 'aaaaaaaa-0000-bbbb-1111-cccccccccccc' }
|
||
|
|
||
|
before(:all) do
|
||
|
@user = FactoryGirl.create(:carto_user)
|
||
|
@intruder = FactoryGirl.create(:carto_user)
|
||
|
@map, @table, @table_visualization, @visualization = create_full_visualization(@user)
|
||
|
@layer = @visualization.data_layers.first
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
destroy_full_visualization(@map, @table, @table_visualization, @visualization)
|
||
|
@user.destroy
|
||
|
@intruder.destroy
|
||
|
@layer = nil
|
||
|
end
|
||
|
|
||
|
before(:each) do
|
||
|
bypass_named_maps
|
||
|
end
|
||
|
|
||
|
def legend_is_correct(legend)
|
||
|
legend = legend.deep_symbolize_keys
|
||
|
saved_legend = LegendPresenter.new(Legend.find(legend[:id])).to_hash
|
||
|
|
||
|
pruned_legend = prune_legend(legend)
|
||
|
pruned_saved_legend = prune_legend(saved_legend)
|
||
|
|
||
|
legend_definition = legend[:definition].with_indifferent_access
|
||
|
saved_legend_definition = saved_legend[:definition]
|
||
|
.with_indifferent_access
|
||
|
|
||
|
conf = legend[:conf].with_indifferent_access
|
||
|
saved_conf = saved_legend[:conf].with_indifferent_access
|
||
|
|
||
|
pruned_legend.should eq pruned_saved_legend
|
||
|
legend_definition.should eq saved_legend_definition
|
||
|
conf.should eq saved_conf
|
||
|
end
|
||
|
|
||
|
def prune_legend(legend)
|
||
|
legend.except(:created_at, :updated_at, :definition, :conf)
|
||
|
end
|
||
|
|
||
|
describe '#create' do
|
||
|
after(:each) { @layer.reload.legends.map(&:destroy) }
|
||
|
|
||
|
def create_legend_url(user: @user, visualization: @visualization, layer: @layer)
|
||
|
legends_url(user_domain: user.subdomain,
|
||
|
visualization_id: visualization.id,
|
||
|
layer_id: layer.id,
|
||
|
api_key: user.api_key)
|
||
|
end
|
||
|
|
||
|
it 'should reject non visualization owners' do
|
||
|
post_json create_legend_url(user: @intruder), {} do |response|
|
||
|
response.status.should eq 403
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'should reject non data layers' do
|
||
|
base_layer = @visualization.layers.first
|
||
|
|
||
|
post_json create_legend_url(layer: base_layer), custom_legend_payload do |response|
|
||
|
response.status.should eq 422
|
||
|
|
||
|
response.body[:errors].should include("'#{base_layer.kind}' layers can't have legends")
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'should return a validation errors' do
|
||
|
post_json create_legend_url, {} do |response|
|
||
|
response.status.should eq 422
|
||
|
|
||
|
response.body[:errors].should_not be_nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe 'with valid definitions' do
|
||
|
after(:each) do
|
||
|
post_json create_legend_url, @payload do |response|
|
||
|
response.status.should eq 201
|
||
|
|
||
|
legend_is_correct(response.body)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
@payload = nil
|
||
|
end
|
||
|
|
||
|
it 'for category' do
|
||
|
@payload = category_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'for custom' do
|
||
|
@payload = custom_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'for bubble' do
|
||
|
@payload = bubble_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'for choropleth' do
|
||
|
@payload = choropleth_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'for custom_choropleth' do
|
||
|
@payload = custom_choropleth_legend_payload
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe 'with spammy definitions' do
|
||
|
after(:each) do
|
||
|
spammy_definition = @payload[:definition].merge(spam: 'hell')
|
||
|
@payload[:definition] = spammy_definition
|
||
|
|
||
|
post_json create_legend_url, @payload do |response|
|
||
|
response.status.should eq 422
|
||
|
end
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
@payload = nil
|
||
|
end
|
||
|
|
||
|
it 'banned for category' do
|
||
|
@payload = category_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for custom' do
|
||
|
@payload = custom_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for bubble' do
|
||
|
@payload = bubble_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for choropleth' do
|
||
|
@payload = choropleth_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for custom_choropleth' do
|
||
|
@payload = custom_choropleth_legend_payload
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe 'with spammy conf' do
|
||
|
after(:each) do
|
||
|
spammy_definition = @payload[:conf].merge(spam: 'hell')
|
||
|
@payload[:conf] = spammy_definition
|
||
|
|
||
|
post_json create_legend_url, @payload do |response|
|
||
|
response.status.should eq 422
|
||
|
end
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
@payload = nil
|
||
|
end
|
||
|
|
||
|
it 'banned for category' do
|
||
|
@payload = category_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for custom' do
|
||
|
@payload = custom_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for bubble' do
|
||
|
@payload = bubble_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for choropleth' do
|
||
|
@payload = choropleth_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for custom_choropleth' do
|
||
|
@payload = custom_choropleth_legend_payload
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe 'with wrong conf type' do
|
||
|
after(:each) do
|
||
|
@payload[:conf] = { columns: { not: 'an_array' } }
|
||
|
|
||
|
post_json create_legend_url, @payload do |response|
|
||
|
response.status.should eq 422
|
||
|
end
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
@payload = nil
|
||
|
end
|
||
|
|
||
|
it 'banned for category' do
|
||
|
@payload = category_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for custom' do
|
||
|
@payload = custom_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for bubble' do
|
||
|
@payload = bubble_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for choropleth' do
|
||
|
@payload = choropleth_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for custom_choropleth' do
|
||
|
@payload = custom_choropleth_legend_payload
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe 'with wrong conf columns type' do
|
||
|
after(:each) do
|
||
|
@payload[:conf] = ['manolo', 'escobar', 2]
|
||
|
|
||
|
post_json create_legend_url, @payload do |response|
|
||
|
response.status.should eq 422
|
||
|
end
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
@payload = nil
|
||
|
end
|
||
|
|
||
|
it 'banned for category' do
|
||
|
@payload = category_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for custom' do
|
||
|
@payload = custom_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for bubble' do
|
||
|
@payload = bubble_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for choropleth' do
|
||
|
@payload = choropleth_legend_payload
|
||
|
end
|
||
|
|
||
|
it 'banned for custom_choropleth' do
|
||
|
@payload = custom_choropleth_legend_payload
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'handles bad layer_id' do
|
||
|
url = legends_url(user_domain: @user.subdomain,
|
||
|
visualization_id: @visualization.id,
|
||
|
layer_id: fake_uuid,
|
||
|
api_key: @user.api_key)
|
||
|
post_json url, {} do |response|
|
||
|
response.status.should eq 404
|
||
|
response.body[:errors].should include('Layer not found')
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'handles bad visualization_id' do
|
||
|
url = legends_url(user_domain: @user.subdomain,
|
||
|
visualization_id: fake_uuid,
|
||
|
layer_id: @layer.id,
|
||
|
api_key: @user.api_key)
|
||
|
|
||
|
post_json url, {} do |response|
|
||
|
response.status.should eq 404
|
||
|
response.body[:errors].should include('Visualization not found')
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe 'multiple legends per layer' do
|
||
|
it 'can create a color layer and a size layer' do
|
||
|
post_json create_legend_url, category_legend_payload do |response|
|
||
|
response.status.should eq 201
|
||
|
end
|
||
|
|
||
|
post_json create_legend_url, bubble_legend_payload do |response|
|
||
|
response.status.should eq 201
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'cannot create two color layers' do
|
||
|
post_json create_legend_url, category_legend_payload do |response|
|
||
|
response.status.should eq 201
|
||
|
end
|
||
|
|
||
|
post_json create_legend_url, custom_legend_payload do |response|
|
||
|
response.status.should eq 422
|
||
|
|
||
|
response.body[:errors].should include('Only one color legend per layer allowed')
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'cannot create two size layers' do
|
||
|
post_json create_legend_url, bubble_legend_payload do |response|
|
||
|
response.status.should eq 201
|
||
|
end
|
||
|
|
||
|
post_json create_legend_url, bubble_legend_payload do |response|
|
||
|
response.status.should eq 422
|
||
|
|
||
|
response.body[:errors].should include('Only one size legend per layer allowed')
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe '#show' do
|
||
|
before (:all) { @legend = Legend.create!(custom_legend_payload.merge(layer_id: @layer.id)) }
|
||
|
after (:all) { @legend.destroy }
|
||
|
|
||
|
def show_legend_url(user: @user, visualization: @visualization, layer: @layer, legend: @legend)
|
||
|
legend_url(user_domain: user.subdomain,
|
||
|
visualization_id: visualization.id,
|
||
|
layer_id: layer.id,
|
||
|
id: legend.id,
|
||
|
api_key: user.api_key)
|
||
|
end
|
||
|
|
||
|
it 'should show a legend' do
|
||
|
get_json show_legend_url, {} do |response|
|
||
|
response.status.should eq 200
|
||
|
|
||
|
legend_is_correct(response.body)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'should not show a legend to others' do
|
||
|
get_json show_legend_url(user: @intruder), {} do |response|
|
||
|
response.status.should eq 403
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'handles bad legend_id' do
|
||
|
url = legend_url(user_domain: @user.subdomain,
|
||
|
visualization_id: @visualization.id,
|
||
|
layer_id: @layer.id,
|
||
|
id: fake_uuid,
|
||
|
api_key: @user.api_key)
|
||
|
|
||
|
get_json url, {} do |response|
|
||
|
response.status.should eq 404
|
||
|
response.body[:errors].should include('Legend not found')
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe '#update' do
|
||
|
before (:all) { @legend = Legend.create!(custom_legend_payload.merge(layer_id: @layer.id)) }
|
||
|
after (:all) { @legend.destroy }
|
||
|
|
||
|
def update_legend_url(user: @user, visualization: @visualization, layer: @layer, legend: @legend)
|
||
|
legend_url(user_domain: user.subdomain,
|
||
|
visualization_id: visualization.id,
|
||
|
layer_id: layer.id,
|
||
|
id: legend.id,
|
||
|
api_key: user.api_key)
|
||
|
end
|
||
|
|
||
|
it 'updates a legend' do
|
||
|
custom_legend_payload[:definition][:html] = '<p>modified</p>'
|
||
|
put_json update_legend_url, custom_legend_payload do |response|
|
||
|
response.status.should eq 200
|
||
|
|
||
|
legend_is_correct(response.body)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'updates a legend when max legends reached' do
|
||
|
Legend.create!(bubble_legend_payload.merge(layer_id: @layer.id))
|
||
|
|
||
|
custom_legend_payload[:definition][:html] = '<p>modified</p>'
|
||
|
put_json update_legend_url, custom_legend_payload do |response|
|
||
|
response.status.should eq 200
|
||
|
|
||
|
legend_is_correct(response.body)
|
||
|
end
|
||
|
|
||
|
@layer.reload.legends.map(&:destroy)
|
||
|
|
||
|
@legend = Legend.create!(custom_legend_payload.merge(layer_id: @layer.id))
|
||
|
end
|
||
|
|
||
|
it 'should let others update a legend' do
|
||
|
put_json update_legend_url(user: @intruder), {} do |response|
|
||
|
response.status.should eq 403
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'handles bad legend_id' do
|
||
|
url = legend_url(user_domain: @user.subdomain,
|
||
|
visualization_id: @visualization.id,
|
||
|
layer_id: @layer.id,
|
||
|
id: fake_uuid,
|
||
|
api_key: @user.api_key)
|
||
|
|
||
|
put_json url, {} do |response|
|
||
|
response.status.should eq 404
|
||
|
response.body[:errors].should include('Legend not found')
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe '#index' do
|
||
|
before(:all) do
|
||
|
@layer.reload.legends.map(&:destroy)
|
||
|
Legend.create!(custom_legend_payload.merge(layer_id: @layer.id))
|
||
|
Legend.create!(bubble_legend_payload.merge(layer_id: @layer.id))
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
@layer.reload.legends.map(&:destroy)
|
||
|
end
|
||
|
|
||
|
def index_legend_url(user: @user, visualization: @visualization, layer: @layer)
|
||
|
legends_url(user_domain: user.subdomain,
|
||
|
visualization_id: visualization.id,
|
||
|
layer_id: layer.id,
|
||
|
api_key: user.api_key)
|
||
|
end
|
||
|
|
||
|
it 'indexes legends' do
|
||
|
get_json index_legend_url, {} do |response|
|
||
|
response.status.should eq 200
|
||
|
|
||
|
response.body.each do |legend|
|
||
|
legend_is_correct(legend)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'should not index legends to others' do
|
||
|
get_json index_legend_url(user: @intruder), {} do |response|
|
||
|
response.status.should eq 403
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe '#delete' do
|
||
|
before (:each) { @legend = Legend.create!(custom_legend_payload.merge(layer_id: @layer.id)) }
|
||
|
after (:each) { @legend.destroy }
|
||
|
|
||
|
def delete_legend_url(user: @user, visualization: @visualization, layer: @layer, legend: @legend)
|
||
|
legend_url(user_domain: user.subdomain,
|
||
|
visualization_id: visualization.id,
|
||
|
layer_id: layer.id,
|
||
|
id: legend.id,
|
||
|
api_key: user.api_key)
|
||
|
end
|
||
|
|
||
|
it 'should delete a legend' do
|
||
|
delete_json delete_legend_url, {} do |response|
|
||
|
response.status.should eq 204
|
||
|
|
||
|
response.body.should be_empty
|
||
|
end
|
||
|
|
||
|
Legend.exists?(@legend.id).should be_false
|
||
|
end
|
||
|
|
||
|
it 'should not delete another user\'s legend' do
|
||
|
delete_json delete_legend_url(user: @intruder), {} do |response|
|
||
|
response.status.should eq 403
|
||
|
end
|
||
|
|
||
|
Legend.exists?(@legend.id).should be_true
|
||
|
end
|
||
|
|
||
|
it 'handles bad legend_id' do
|
||
|
url = legend_url(user_domain: @user.subdomain,
|
||
|
visualization_id: @visualization.id,
|
||
|
layer_id: @layer.id,
|
||
|
id: fake_uuid,
|
||
|
api_key: @user.api_key)
|
||
|
|
||
|
delete_json url, {} do |response|
|
||
|
response.status.should eq 404
|
||
|
response.body[:errors].should include('Legend not found')
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|