require 'sequel'
require 'rack/test'
require 'json'
require_relative '../../spec_helper'
require_relative '../../support/factories/organizations'
require_relative '../../../app/controllers/admin/visualizations_controller'
require 'helpers/unique_names_helper'

def app
  CartoDB::Application.new
end #app

describe Admin::VisualizationsController do
  include UniqueNamesHelper
  include Rack::Test::Methods
  include Warden::Test::Helpers
  include CacheHelper
  include Carto::Factories::Visualizations

  # Mock for a Rails context
  class ContextMock
    def initialize(global_context)
      @global_context = global_context
    end

    def request
      nil
    end

    def polymorphic_path(*args)
      @global_context.polymorphic_path(*args)
    end
  end

  before(:all) do
    @user = create(:valid_user, private_tables_enabled: true)

    @api_key = @user.api_key
    @user.stubs(:should_load_common_data?).returns(false)

    @headers = {
      'CONTENT_TYPE'  => 'application/json',
    }
    @mock_context = ContextMock.new(self)
  end

  after(:all) do
    @user.destroy
  end

  before(:each) do
    bypass_named_maps
    delete_user_data @user
    host! "#{@user.username}.localhost.lan"
  end

  describe 'GET /viz' do
    it 'returns a list of visualizations' do
      # we use this to avoid generating the static assets in CI
      Admin::VisualizationsController.any_instance.stubs(:render).returns('')
      login_as(@user, scope: @user.username)

      get "/viz", {}, @headers
      last_response.status.should == 200
    end

    it 'returns 403 if user not logged in' do
      get "/viz", {}, @headers
      last_response.status.should == 302
    end
  end # GET /viz

  describe 'GET /viz:id' do
    it 'returns a visualization' do
      id = factory.fetch('id')
      login_as(@user, scope: @user.username)

      get "/viz/#{id}", {}, @headers
      last_response.status.should == 200
    end

    it 'redirects to the public view if visualization private' do
      id = factory.fetch('id')

      get "/viz/#{id}", {}, @headers
      follow_redirect!
      last_request.path.should =~ %r{/viz/}
    end

    it 'keeps the base path (table|visualization) when redirecting' do
      id = table_factory.id

      get "/tables/#{id}", {}, @headers
      follow_redirect!
      last_request.path.should =~ %r{/tables/}
    end

    describe 'redirects to builder' do
      describe 'for tables' do
        before(:each) do
          @id = table_factory.id
        end
        it 'if forced' do
          @user.stubs(:builder_enabled).returns(true)
          @user.stubs(:builder_enabled?).returns(true)

          login_as(@user, scope: @user.username)
          get "/tables/#{@id}", {}, @headers
          last_response.status.should eq 302
          follow_redirect!
          last_request.path.should =~ %r{/dataset/}
        end

        it 'only if enabled' do
          @user.stubs(:builder_enabled).returns(true)
          @user.stubs(:builder_enabled?).returns(false)

          login_as(@user, scope: @user.username)
          get "/tables/#{@id}", {}, @headers
          last_response.status.should eq 200
        end

        it 'only if forced' do
          @user.stubs(:builder_enabled).returns(nil)
          @user.stubs(:builder_enabled?).returns(false)

          login_as(@user, scope: @user.username)
          get "/tables/#{@id}", {}, @headers
          last_response.status.should eq 200
        end
      end

      describe 'for visualizations' do
        before(:each) do
          @id = factory.fetch('id')
        end
        it 'if forced' do
          @user.stubs(:builder_enabled).returns(true)
          @user.stubs(:builder_enabled?).returns(true)

          login_as(@user, scope: @user.username)
          get "/viz/#{@id}", {}, @headers
          last_response.status.should eq 302
          follow_redirect!
          last_request.path.should =~ %r{/builder/}
        end

        it 'only if enabled' do
          @user.stubs(:builder_enabled).returns(true)
          @user.stubs(:builder_enabled?).returns(false)

          login_as(@user, scope: @user.username)
          get "/viz/#{@id}", {}, @headers
          last_response.status.should eq 200
        end

        it 'only if forced' do
          @user.stubs(:builder_enabled).returns(nil)
          @user.stubs(:builder_enabled?).returns(false)

          login_as(@user, scope: @user.username)
          get "/viz/#{@id}", {}, @headers
          last_response.status.should eq 200
        end

        it 'never for vizjson2 visualizations' do
          @user.stubs(:builder_enabled).returns(true)
          @user.stubs(:builder_enabled?).returns(true)
          Carto::Visualization::any_instance.stubs(:uses_vizjson2?).returns(true)

          login_as(@user, scope: @user.username)
          get public_visualizations_show_path(id: @id), {}, @headers
          last_response.status.should eq 200
        end

        it 'embed redirects to builder for v3 when needed' do
          # These two tests are in the same testcase to test proper embed cache invalidation
          @user.stubs(:builder_enabled).returns(false)
          @user.stubs(:builder_enabled?).returns(false)
          visualization = CartoDB::Visualization::Member.new(id: @id).fetch
          visualization.version = 2
          visualization.store

          login_as(@user, scope: @user.username)
          get public_visualizations_embed_map_path(id: @id), {}, @headers
          last_response.status.should eq 200

          visualization.version = 3
          visualization.store

          login_as(@user, scope: @user.username)
          get public_visualizations_embed_map_path(id: @id), {}, @headers
          last_response.status.should eq 302
        end
      end
    end
  end # GET /viz/:id

  describe 'GET /tables/:id/public/table' do
    it 'returns 404 for private tables' do
      id = table_factory(privacy: ::UserTable::PRIVACY_PRIVATE).id

      get "/tables/#{id}/public/table", {}, @headers
      last_response.status.should == 404
    end
  end

  describe 'GET /viz/:id/protected_public_map' do
    it 'returns 404 for private maps' do
      id = table_factory(privacy: ::UserTable::PRIVACY_PRIVATE).table_visualization.id

      get "/viz/#{id}/protected_public_map", {}, @headers
      last_response.status.should == 404
    end
  end

  describe 'GET /viz/:id/protected_embed_map' do
    it 'returns 404 for private maps' do
      id = table_factory(privacy: ::UserTable::PRIVACY_PRIVATE).table_visualization.id

      get "/viz/#{id}/protected_embed_map", {}, @headers
      last_response.status.should == 404
    end
  end

  describe 'GET /viz/:id/public_map' do
    it 'returns 403 for private maps' do
      id = table_factory(privacy: ::UserTable::PRIVACY_PRIVATE).table_visualization.id

      get "/viz/#{id}/public_map", {}, @headers
      last_response.status.should == 403
    end

    it 'go to password protected page if the viz is password protected' do
      id = factory.fetch('id')
      visualization = CartoDB::Visualization::Member.new(id: id).fetch
      visualization.version = 2
      visualization.password = 'foobar'
      visualization.privacy = Carto::Visualization::PRIVACY_PROTECTED
      visualization.store

      get "/viz/#{id}/public_map", {}, @headers
      last_response.status.should == 200
      last_response.body.scan(/Insert your password/).present?.should == true
    end

    it 'returns proper surrogate-keys' do
      id = table_factory(privacy: ::UserTable::PRIVACY_PUBLIC).table_visualization.id

      get "/viz/#{id}/public_map", {}, @headers
      last_response.status.should == 200
      last_response.headers["Surrogate-Key"].should_not be_empty
      last_response.headers["Surrogate-Key"].should include(CartoDB::SURROGATE_NAMESPACE_PUBLIC_PAGES)
    end

    it 'returns public map for org users' do
      org = OrganizationFactory.new.new_organization
      org.save

      user_a = create_user(quota_in_bytes: 123456789, table_quota: 400)
      user_org = CartoDB::UserOrganization.new(org.id, user_a.id)
      user_org.promote_user_to_admin

      vis_id = new_table({user_id: user_a.id, privacy: ::UserTable::PRIVACY_PUBLIC}).save.reload.table_visualization.id

      host! "#{org.name}.localhost.lan"
      get "/viz/#{vis_id}/public_map", @headers
      last_response.status.should == 200
    end

    it 'go to password protected page if the organization viz is password protected' do
      org = OrganizationFactory.new.new_organization
      org.save

      user_a = create_user(quota_in_bytes: 123456789, table_quota: 400)
      user_org = CartoDB::UserOrganization.new(org.id, user_a.id)
      user_org.promote_user_to_admin
      id = factory(owner=user_a).fetch('id')
      visualization = CartoDB::Visualization::Member.new(id: id).fetch
      visualization.version = 2
      visualization.password = 'foobar'
      visualization.privacy = Carto::Visualization::PRIVACY_PROTECTED
      visualization.store

      get "/viz/#{id}/public_map", {}, @headers

      last_response.status.should == 302
      follow_redirect!
      last_response.status.should == 200
      last_response.body.scan(/Insert your password/).present?.should == true
    end

    it 'does not load daily mapviews stats' do
      CartoDB::Visualization::Stats.expects(:mapviews).never
      CartoDB::Visualization::Stats.any_instance.expects(:to_poro).never
      CartoDB::Visualization.expects(:stats).never
      Carto::Visualization.expects(:stats).never

      id = table_factory(privacy: ::UserTable::PRIVACY_PUBLIC).table_visualization.id

      get public_visualizations_public_map_url(id: id), {}, @headers
      last_response.status.should == 200
    end

    it 'serves X-Frame-Options: DENY' do
      id = table_factory(privacy: ::UserTable::PRIVACY_PUBLIC).table_visualization.id

      get "/viz/#{id}/public_map", {}, @headers
      last_response.status.should == 200
      last_response.headers['X-Frame-Options'].should == 'DENY'
    end
  end

  describe 'public_visualizations_show_map' do

    it 'does not load daily mapviews stats' do
      CartoDB::Visualization::Stats.expects(:mapviews).never
      CartoDB::Visualization::Stats.any_instance.expects(:to_poro).never
      CartoDB::Stats::APICalls.any_instance.expects(:get_api_calls_from_redis_source).never

      CartoDB::Visualization.expects(:stats).never
      Carto::Visualization.expects(:stats).never

      id = table_factory(privacy: ::UserTable::PRIVACY_PUBLIC).table_visualization.id

      login_as(@user, scope: @user.username)
      get public_visualizations_show_map_url(id: id), {}, @headers
      last_response.status.should == 200
    end

  end

  describe 'GET /viz/:id/public' do
    it 'returns public data for a table visualization' do
      id = table_factory(privacy: ::UserTable::PRIVACY_PUBLIC).table_visualization.id

      get "/viz/#{id}/public", {}, @headers
      last_response.status.should == 200
    end

    it 'returns a 404 if table is private' do
      id = table_factory.table_visualization.id

      get "/viz/#{id}/public", {}, @headers
      last_response.status.should == 404
    end

    it "redirects to embed_map if visualization is 'derived'" do
      map = create(:map, user_id: @user.id)
      derived_visualization = create(:derived_visualization, user_id: @user.id, map_id: map.id)
      id = derived_visualization.id

      get "/viz/#{id}/public", {}, @headers
      last_response.status.should == 302
      follow_redirect!
      last_response.status.should == 200
      last_request.url.should =~ %r{.*#{id}/public_map.*}
    end
  end # GET /viz/:id/public

  describe 'GET /tables/:id/embed_map' do
    it 'returns 404 for nonexisting tables when table name is used' do
      get "/tables/tablethatdoesntexist/embed_map", {}, @headers
      last_response.status.should == 404
    end
  end

  describe 'GET /viz/:name/embed_map' do
    it 'renders the view by passing a visualization name' do
      table = table_factory(privacy: ::UserTable::PRIVACY_PUBLIC)
      name = table.table_visualization.name

      get "/viz/#{URI::encode(name)}/embed_map", {}, @headers
      last_response.status.should == 200
      last_response.headers["X-Cache-Channel"].should_not be_empty
      last_response.headers["X-Cache-Channel"].should include(table.name)
      last_response.headers["X-Cache-Channel"].should include(table.table_visualization.varnish_key)
      last_response.headers["Surrogate-Key"].should_not be_empty
      last_response.headers["Surrogate-Key"].should include(CartoDB::SURROGATE_NAMESPACE_PUBLIC_PAGES)
      last_response.headers["Surrogate-Key"].should include(table.table_visualization.surrogate_key)
    end

    it 'renders embed map error page if visualization private' do
      table = table_factory
      put "/api/v1/tables/#{table.id}?api_key=#{@api_key}",
        { privacy: 0 }.to_json, @headers

      name = table.table_visualization.name
      name = URI::encode(name)

      login_as(@user, scope: @user.username)

      get "/viz/#{name}/embed_map", {}, @headers
      last_response.status.should == 403
      last_response.body.should include("Map or dataset not found, or with restricted access.")
    end

    it 'renders embed map error when an exception is raised' do
      login_as(@user, scope: @user.username)

      get "/viz/220d2f46-b371-11e4-93f7-080027880ca6/embed_map", {}, @headers
      last_response.status.should == 404
    end

    it 'doesnt serve X-Frame-Options: DENY on embedded with name' do
      table = table_factory(privacy: ::UserTable::PRIVACY_PUBLIC)
      name = table.table_visualization.name

      get "/viz/#{URI::encode(name)}/embed_map", {}, @headers
      last_response.status.should == 200
      last_response.headers.include?('X-Frame-Options').should_not == true
    end

    it 'redirects to kuviz when needed' do
      kuviz = create(:kuviz_visualization, user_id: @user.id)

      get public_tables_embed_map_url(id: kuviz.id), {}, @headers
      last_response.status.should eq 302

      follow_redirect!

      uri = URI.parse(last_request.url)
      uri.host.should == "#{@user.username}.localhost.lan"
      uri.path.should == "/kuviz/#{kuviz.id}"
    end

    it 'redirects to app when needed' do
      app = create(:app_visualization, user_id: @user.id)

      get public_tables_embed_map_url(id: app.id), {}, @headers
      last_response.status.should eq 302

      follow_redirect!

      uri = URI.parse(last_request.url)
      uri.host.should == "#{@user.username}.localhost.lan"
      uri.path.should == "/app/#{app.id}"
    end
  end

  describe 'GET /viz/:id/embed_map' do
    it 'caches and serves public embed map successful responses' do
      id = table_factory(privacy: ::UserTable::PRIVACY_PUBLIC).table_visualization.id
      embed_redis_cache = EmbedRedisCache.new

      embed_redis_cache.get(id, https=false).should == nil
      get "/viz/#{id}/embed_map", {}, @headers
      last_response.status.should == 200

      # The https key/value pair should be differenent
      embed_redis_cache.get(id, https=true).should == nil
      last_response.status.should == 200

      # It should be cached after the first request
      embed_redis_cache.get(id, https=false).should_not be_nil
      first_response = last_response

      get "/viz/#{id}/embed_map", {}, @headers
      last_response.status.should == 200
      # Headers of both responses should be the same excluding some
      remove_changing = lambda {|h| h.reject {|k, v| ['X-Request-Id', 'X-Runtime'].include?(k)} }
      remove_changing.call(first_response.headers).should == remove_changing.call(last_response.headers)
      first_response.body.should == last_response.body
    end

    it 'doesnt serve X-Frame-Options: DENY on embedded' do
      id = table_factory(privacy: ::UserTable::PRIVACY_PUBLIC).table_visualization.id

      get "/viz/#{id}/embed_map", {}, @headers
      last_response.status.should == 200
      last_response.headers.include?('X-Frame-Options').should_not == true
    end
  end

  describe 'GET /viz/:name/track_embed' do
    it 'renders the view by passing a visualization name' do
      login_as(@user, scope: @user.username)

      get "/viz/track_embed", {}, @headers
      last_response.status.should == 200
    end

    it 'doesnt serve X-Frame-Options: DENY for track_embed' do
      login_as(@user, scope: @user.username)

      get "/viz/track_embed", {}, @headers
      last_response.status.should == 200
      last_response.headers.include?('X-Frame-Options').should_not == true
    end
  end

  describe 'non existent visualization' do
    it 'returns 404' do
      login_as(@user, scope: @user.username)

      get "/viz/220d2f46-b371-11e4-93f7-080027880ca6?api_key=#{@api_key}", {}, @headers
      last_response.status.should == 404

      get "/viz/220d2f46-b371-11e4-93f7-080027880ca6/public?api_key=#{@api_key}", {}, @headers
      last_response.status.should == 404

      get "/viz/220d2f46-b371-11e4-93f7-080027880ca6/embed_map?api_key=#{@api_key}", {}, @headers
      last_response.status.should == 404
    end
  end # non existent visualization

  describe 'org user visualization redirection' do
    it 'if A shares a (shared) vis link to B with A username, performs a redirect to B username' do
      Carto::ApiKey.any_instance.stubs(:save_cdb_conf_info)
      CartoDB::UserModule::DBService.any_instance.stubs(:move_to_own_schema).returns(nil)
      CartoDB::TablePrivacyManager.any_instance.stubs(
          :set_from_table_privacy => nil,
          :propagate_to_varnish => nil
      )

      ::User.any_instance.stubs(
        after_create: nil
      )

      CartoDB::UserModule::DBService.any_instance.stubs(
        grant_user_in_database: nil,
        grant_publicuser_in_database: nil,
        set_user_privileges_at_db: nil,
        set_statement_timeouts: nil,
        set_user_as_organization_member: nil,
        rebuild_quota_trigger: nil,
        setup_organization_user_schema: nil,
        set_database_search_path: nil,
        cartodb_extension_version_pre_mu?: false,
        load_cartodb_functions: nil,
        create_schema: nil,
        move_tables_to_schema: nil,
        create_public_db_user: nil,
        monitor_user_notification: nil,
        enable_remote_db_user: nil
      )

      Carto::NamedMaps::Api.any_instance.stubs(get: nil, create: true, update: true)

      Table.any_instance.stubs(perform_cartodb_function: nil,
                               update_cdb_tablemetadata: nil,
                               update_table_pg_stats: nil,
                               create_table_in_database!: nil,
                               get_table_id: 1,
                               grant_select_to_tiler_user: nil,
                               cartodbfy: nil,
                               set_the_geom_column!: nil)

      # --------TEST ITSELF-----------

      org = Carto::Organization.new
      org.name = 'vis-spec-org-2'
      org.quota_in_bytes = 1024 ** 3
      org.seats = 10
      org.builder_enabled = false
      org.save

      ::User.any_instance.stubs(:remaining_quota).returns(1000)
      user_a = create_user(username: 'user-a', quota_in_bytes: 123456789, table_quota: 400)
      user_org = CartoDB::UserOrganization.new(org.id, user_a.id)
      user_org.promote_user_to_admin
      org.reload
      user_a.reload

      user_b = create_user(username: 'user-b',
                           quota_in_bytes: 123456789,
                           table_quota: 400,
                           organization: org,
                           account_type: 'ORGANIZATION USER')

      # Needed because after_create is stubbed
      user_a.create_api_keys
      user_b.create_api_keys

      vis_id = factory(user_a).fetch('id')
      vis = CartoDB::Visualization::Member.new(id: vis_id).fetch
      vis.privacy = CartoDB::Visualization::Member::PRIVACY_PRIVATE
      vis.store

      login_host(user_b, org)

      get CartoDB.url(@mock_context, 'public_table', params: { id: vis.name }, user: user_a)
      last_response.status.should be(404)

      ['public_visualizations_public_map', 'public_tables_embed_map'].each do |forbidden_endpoint|
        get CartoDB.url(@mock_context, forbidden_endpoint, params: { id: vis.name }, user: user_a)
        follow_redirects
        last_response.status.should be(403), "#{forbidden_endpoint} is #{last_response.status}"
      end

      perm = vis.permission
      perm.set_user_permission(user_b, Carto::Permission::ACCESS_READONLY)
      perm.save

      get CartoDB.url(@mock_context, 'public_table', params: { id: vis.name }, user: user_a)
      last_response.status.should == 302
      # First we'll get redirected to the public map url
      follow_redirect!
      # Now url will get rewritten to current user
      last_response.status.should == 302
      url = CartoDB.base_url(org.name, user_b.username) +
            CartoDB.path(self, 'public_visualizations_show', id: "#{user_a.username}.#{vis.name}") + "?redirected=true"
      last_response.location.should eq url

      ['public_visualizations_public_map', 'public_tables_embed_map'].each do |forbidden_endpoint|
        get CartoDB.url(@mock_context, forbidden_endpoint, params: { id: vis.name }, user: user_a)
        follow_redirects
        last_response.status.should be(200), "#{forbidden_endpoint} is #{last_response.status}"
        last_response.length.should >= 100
      end
      org.destroy
    end

    # @see https://github.com/CartoDB/cartodb/issues/6081
    it 'If logged user navigates to legacy url from org user without org name, gets redirected properly' do
      Carto::ApiKey.any_instance.stubs(:save_cdb_conf_info)
      CartoDB::UserModule::DBService.any_instance.stubs(:move_to_own_schema).returns(nil)
      CartoDB::TablePrivacyManager.any_instance.stubs(
        set_from_table_privacy: nil,
        propagate_to_varnish: nil
      )

      ::User.any_instance.stubs(
        after_create: nil
      )

      CartoDB::UserModule::DBService.any_instance.stubs(
        grant_user_in_database: nil,
        grant_publicuser_in_database: nil,
        set_user_privileges_at_db: nil,
        set_statement_timeouts: nil,
        set_user_as_organization_member: nil,
        rebuild_quota_trigger: nil,
        setup_organization_user_schema: nil,
        set_database_search_path: nil,
        cartodb_extension_version_pre_mu?: false,
        load_cartodb_functions: nil,
        create_schema: nil,
        move_tables_to_schema: nil,
        create_public_db_user: nil,
        monitor_user_notification: nil,
        enable_remote_db_user: nil
      )

      Carto::NamedMaps::Api.any_instance.stubs(get: nil, create: true, update: true)
      Table.any_instance.stubs(
        perform_cartodb_function: nil,
        update_cdb_tablemetadata: nil,
        update_table_pg_stats: nil,
        create_table_in_database!: nil,
        get_table_id: 1,
        grant_select_to_tiler_user: nil,
        cartodbfy: nil,
        set_the_geom_column!: nil
      )

      # --------TEST ITSELF-----------

      org = Carto::Organization.new
      org.name = 'vis-spec-org'
      org.quota_in_bytes = 1024**3
      org.seats = 10
      org.builder_enabled = false
      org.save

      ::User.any_instance.stubs(:remaining_quota).returns(1000)
      user_a = create_user(quota_in_bytes: 123456789, table_quota: 400)
      user_org = CartoDB::UserOrganization.new(org.id, user_a.id)
      user_org.promote_user_to_admin
      org.reload
      user_a.reload

      user_b = create_user(quota_in_bytes: 123456789, table_quota: 400)

      # Needed because after_create is stubbed
      user_a.create_api_keys
      user_b.create_api_keys

      vis_id = factory(user_a).fetch('id')
      vis = CartoDB::Visualization::Member.new(id: vis_id).fetch
      vis.privacy = CartoDB::Visualization::Member::PRIVACY_PUBLIC
      vis.store

      login_host(user_b)

      # dirty but effective trick, generate the url as if were for a non-org user, then replace usernames
      # to respect format and just have no organization
      destination_url = CartoDB.url(@mock_context, 'public_visualizations_public_map',
                                    params: { id: vis.name }, user: user_b)
                               .sub(user_b.username, user_a.username)

      get destination_url
      last_response.status.should be(302)
      last_response.headers["Location"].should eq CartoDB.url(@mock_context, 'public_visualizations_public_map',
                                                              params: { id: vis.id, redirected: true }, user: user_a)
      follow_redirect!
      last_response.status.should be(200)

      org.destroy
    end
  end

  describe 'find visualizations by name' do
    before(:all) do
      @organization = create_organization_with_users(name: unique_name('organization'))
      @org_user = @organization.users.first
      bypass_named_maps
      @table = new_table(user_id: @org_user.id, privacy: ::UserTable::PRIVACY_PUBLIC).save.reload
      @faketable = new_table(user_id: @user.id, privacy: ::UserTable::PRIVACY_PUBLIC).save.reload
      @faketable_name = @faketable.table_visualization.name
    end

    it 'finds visualization by org and name' do
      url = CartoDB.url(@mock_context, 'public_table', params: { id: @table.table_visualization.name }, user: @org_user)
      url = url.sub("/u/#{@org_user.username}", '')

      get url
      last_response.status.should == 200
    end

    it 'does not find visualizations outside org' do
      url = CartoDB.url(@mock_context, 'public_table', params: { id: @faketable_name }, user: @org_user)
      url = url.sub("/u/#{@org_user.username}", '')

      get url
      last_response.status.should == 404
    end

    it 'finds visualization by user and public.name' do
      url = CartoDB.url(@mock_context, 'public_table',
                        params: { id: "public.#{@table.table_visualization.name}" }, user: @org_user)

      get url
      last_response.status.should == 200
    end

    it 'finds visualization by user and public.id' do
      url = CartoDB.url(@mock_context, 'public_table',
                        params: { id: "public.#{@table.table_visualization.id}" }, user: @org_user)

      get url
      last_response.status.should == 200
    end

    it 'does not find visualizations outside user with public schema' do
      url = CartoDB.url(@mock_context, 'public_table',
                        params: { id: "public.#{@faketable_name}" }, user: @org_user)
      url = url.sub("/u/#{@org_user.username}", '')

      get url
      last_response.status.should == 404
    end

    it 'does not try to search visualizations with invalid user/org' do
      url = CartoDB.url(@mock_context, 'public_table', params: { id: "public.#{@table.name}" }, user: @org_user)
      url = url.sub("/u/#{@org_user.username}", '/u/invalidus3r')

      get url
      last_response.status.should == 404
    end
  end

  def login_host(user, org = nil)
    login_as(user, scope: user.username)
    host! "#{org.nil? ? user.username : org.name}.localhost.lan"
  end

  def follow_redirects(limit = 10)
    while last_response.status == 302 && (limit -= 1) > 0 do
        follow_redirect!
    end
  end

  def factory(owner=nil)
    owner = @user if owner.nil?
    map     = Map.create(user_id: owner.id)
    payload = {
      name:         unique_name('viz'),
      tags:         ['foo', 'bar'],
      map_id:       map.id,
      description:  'bogus',
      type:         'derived'
    }

    with_host "#{owner.username}.localhost.lan" do
      post "/api/v1/viz?api_key=#{owner.api_key}", payload.to_json
    end


    JSON.parse(last_response.body)
  end

  def table_factory(attrs = {})
    new_table(attrs.merge(user_id: @user.id)).save.reload
  end

end # Admin::VisualizationsController
