469 lines
20 KiB
Ruby
469 lines
20 KiB
Ruby
require 'rspec/mocks'
|
|
require_relative '../../../spec_helper'
|
|
require_relative '../../../../app/controllers/carto/api/database_groups_controller'
|
|
require_relative '.././../../factories/visualization_creation_helpers'
|
|
|
|
# cURL samples:
|
|
# - Rename group: curl -v -H "Content-Type: application/json" -X PUT -d '{ "display_name": "Demo Group" }' "http://central-org-b-admin.localhost.lan:3000/api/v1/organization/95c2c425-5c8c-4b20-8999-d79cd20c2f2c/groups/c662f7ee-aefb-4f49-93ea-1f671a77bb36?api_key=665646f527c3006b124c15a308bb98f4ed1f52e4"
|
|
# - Add users: curl -v -H "Content-Type: application/json" -X POST -d '{ "users" : ["78ee570a-812d-4cce-928c-e5ebeb4708e8", "7e53c96c-1598-43e0-b23e-290daf633547"] }' "http://central-org-b-admin.localhost.lan:3000/api/v1/organization/95c2c425-5c8c-4b20-8999-d79cd20c2f2c/groups/c662f7ee-aefb-4f49-93ea-1f671a77bb36/users?api_key=665646f527c3006b124c15a308bb98f4ed1f52e4"
|
|
# - Remove users: curl -v -H "Content-Type: application/json" -X DELETE -d '{ "users" : ["78ee570a-812d-4cce-928c-e5ebeb4708e8", "7e53c96c-1598-43e0-b23e-290daf633547"] }' "http://central-org-b-admin.localhost.lan:3000/api/v1/organization/95c2c425-5c8c-4b20-8999-d79cd20c2f2c/groups/c662f7ee-aefb-4f49-93ea-1f671a77bb36/users?api_key=665646f527c3006b124c15a308bb98f4ed1f52e4"
|
|
|
|
describe Carto::Api::GroupsController do
|
|
include_context 'organization with users helper'
|
|
|
|
shared_examples_for 'Groups editor management' do
|
|
before(:all) do
|
|
@org_user_1_json = {
|
|
"id" => @org_user_1.id,
|
|
"name" => @org_user_1.name,
|
|
"last_name" => @org_user_1.last_name,
|
|
"username" => @org_user_1.username,
|
|
"avatar_url" => @org_user_1.avatar_url,
|
|
"base_url" => @org_user_1.public_url,
|
|
"disqus_shortname" => @org_user_1.disqus_shortname,
|
|
"viewer" => @org_user_1.viewer,
|
|
"org_admin" => false,
|
|
"org_user" => true,
|
|
"remove_logo" => @org_user_1.remove_logo?,
|
|
"google_maps_query_string" => @org_user_1.google_maps_query_string
|
|
}
|
|
|
|
@group_1 = FactoryGirl.create(:random_group, display_name: 'g_1', organization: @carto_organization)
|
|
@group_1_json = { 'id' => @group_1.id, 'organization_id' => @group_1.organization_id, 'name' => @group_1.name, 'display_name' => @group_1.display_name }
|
|
@group_2 = FactoryGirl.create(:random_group, display_name: 'g_2', organization: @carto_organization)
|
|
@group_2_json = { 'id' => @group_2.id, 'organization_id' => @group_2.organization_id, 'name' => @group_2.name, 'display_name' => @group_2.display_name }
|
|
@group_3 = FactoryGirl.create(:random_group, display_name: 'g_3', organization: @carto_organization)
|
|
@group_3_json = { 'id' => @group_3.id, 'organization_id' => @group_3.organization_id, 'name' => @group_3.name, 'display_name' => @group_3.display_name }
|
|
@headers = { 'CONTENT_TYPE' => 'application/json', :format => "json", 'Accept' => 'application/json' }
|
|
end
|
|
|
|
after(:all) do
|
|
@group_1.destroy
|
|
@group_2.destroy
|
|
@group_3.destroy
|
|
end
|
|
|
|
before(:each) do
|
|
@carto_organization.reload
|
|
end
|
|
|
|
describe '#index' do
|
|
|
|
it 'returns 401 without authentication' do
|
|
get_json api_v1_organization_groups_url(user_domain: @admin_user.username, organization_id: @carto_organization.id), {}, @headers do |response|
|
|
response.status.should == 401
|
|
end
|
|
end
|
|
|
|
it 'returns groups with pagination metadata' do
|
|
get_json api_v1_organization_groups_url(user_domain: @admin_user.username, organization_id: @carto_organization.id, api_key: @admin_user.api_key), {}, @headers do |response|
|
|
response.status.should == 200
|
|
expected_response = {
|
|
groups: [ @group_1_json, @group_2_json, @group_3_json ],
|
|
total_entries: 3
|
|
}
|
|
response.body.should == expected_response.deep_symbolize_keys
|
|
end
|
|
end
|
|
|
|
it 'returns paginated groups with pagination metadata' do
|
|
get_json api_v1_organization_groups_url(user_domain: @admin_user.username, organization_id: @carto_organization.id, api_key: @admin_user.api_key), { page: 2, per_page: 1, order: 'display_name' }, @headers do |response|
|
|
response.status.should == 200
|
|
expected_response = {
|
|
groups: [ @group_2_json ],
|
|
total_entries: 3
|
|
}
|
|
response.body.should == expected_response.deep_symbolize_keys
|
|
end
|
|
end
|
|
|
|
it 'can search by name' do
|
|
get_json api_v1_organization_groups_url(user_domain: @admin_user.username, organization_id: @carto_organization.id, api_key: @admin_user.api_key, q: @group_2.name), { page: 1, per_page: 1, order: 'display_name' }, @headers do |response|
|
|
response.status.should == 200
|
|
expected_response = {
|
|
groups: [ @group_2_json ],
|
|
total_entries: 1
|
|
}
|
|
response.body.should == expected_response.deep_symbolize_keys
|
|
end
|
|
end
|
|
|
|
it 'validates order param' do
|
|
[:id, :name, :display_name, :organization_id, :updated_at].each do |param|
|
|
get_json api_v1_organization_groups_url(
|
|
order: param,
|
|
user_domain: @admin_user.username,
|
|
organization_id: @carto_organization.id,
|
|
api_key: @admin_user.api_key
|
|
), {}, @headers do |response|
|
|
response.status.should == 200
|
|
end
|
|
end
|
|
|
|
get_json api_v1_organization_groups_url(
|
|
order: :invalid,
|
|
user_domain: @admin_user.username,
|
|
organization_id: @carto_organization.id,
|
|
api_key: @admin_user.api_key
|
|
), {}, @headers do |response|
|
|
response.status.should == 400
|
|
response.body.fetch(:errors).should_not be_nil
|
|
end
|
|
end
|
|
|
|
describe "users groups" do
|
|
|
|
before(:each) do
|
|
@group_1.add_user(@org_user_1.username)
|
|
end
|
|
|
|
after(:each) do
|
|
@group_1.remove_user(@org_user_1.username)
|
|
end
|
|
|
|
it 'returns user groups if user_id is requested' do
|
|
get_json api_v1_user_groups_url(user_domain: @org_user_1.username, user_id: @org_user_1.id, api_key: @org_user_1.api_key), {}, @headers do |response|
|
|
response.status.should == 200
|
|
expected_response = {
|
|
groups: [ @group_1_json ],
|
|
total_entries: 1
|
|
}
|
|
response.body.should == expected_response.deep_symbolize_keys
|
|
end
|
|
end
|
|
|
|
it 'optionally fetches number of shared tables, maps and users' do
|
|
get_json api_v1_user_groups_url(user_domain: @org_user_1.username, user_id: @org_user_1.id, api_key: @org_user_1.api_key), {}, @headers do |response|
|
|
response.status.should == 200
|
|
expected_response = {
|
|
groups: [
|
|
@group_1_json
|
|
],
|
|
total_entries: 1
|
|
}
|
|
response.body.should == expected_response.deep_symbolize_keys
|
|
end
|
|
|
|
get_json api_v1_user_groups_url(user_domain: @org_user_1.username, user_id: @org_user_1.id, api_key: @org_user_1.api_key, fetch_shared_tables_count: true, fetch_shared_maps_count: true, fetch_users: true), {}, @headers do |response|
|
|
response.status.should == 200
|
|
expected_response = {
|
|
groups: [
|
|
@group_1_json.merge({
|
|
'shared_tables_count' => 0,
|
|
'shared_maps_count' => 0,
|
|
'users' => [ @org_user_1_json ]
|
|
})
|
|
],
|
|
total_entries: 1
|
|
}
|
|
response.body.should == expected_response.deep_symbolize_keys
|
|
end
|
|
end
|
|
|
|
it 'can fetch number of shared tables, maps and users when a table is shared' do
|
|
bypass_named_maps
|
|
table_user_2 = create_table_with_options(@org_user_2)
|
|
permission = CartoDB::Permission[Carto::Visualization.find(table_user_2['table_visualization'][:id]).permission.id]
|
|
permission.set_group_permission(@group_1, Carto::Permission::ACCESS_READONLY)
|
|
permission.save
|
|
|
|
get_json api_v1_user_groups_url(user_domain: @org_user_1.username, user_id: @org_user_1.id, api_key: @org_user_1.api_key, fetch_shared_tables_count: true, fetch_shared_maps_count: true, fetch_users: true), {}, @headers do |response|
|
|
response.status.should == 200
|
|
expected_response = {
|
|
groups: [
|
|
@group_1_json.merge({
|
|
'shared_tables_count' => 1,
|
|
'shared_maps_count' => 0,
|
|
'users' => [ @org_user_1_json ]
|
|
})
|
|
],
|
|
total_entries: 1
|
|
}
|
|
response.body.should == expected_response.deep_symbolize_keys
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
it '#show returns a group' do
|
|
get_json api_v1_organization_groups_show_url(user_domain: @admin_user.username, organization_id: @carto_organization.id, group_id: @group_1.id, api_key: @admin_user.api_key), { }, @headers do |response|
|
|
response.status.should == 200
|
|
response.body.should == @group_1_json.symbolize_keys
|
|
end
|
|
end
|
|
|
|
it '#show support fetch_shared_maps_count, fetch_shared_tables_count and fetch_users' do
|
|
get_json api_v1_organization_groups_show_url(user_domain: @admin_user.username, organization_id: @carto_organization.id, group_id: @group_1.id, api_key: @admin_user.api_key, fetch_shared_tables_count: true, fetch_shared_maps_count: true, fetch_users: true), { }, @headers do |response|
|
|
response.status.should == 200
|
|
response.body[:shared_tables_count].should_not be_nil
|
|
response.body[:shared_maps_count].should_not be_nil
|
|
response.body[:users].should_not be_nil
|
|
end
|
|
end
|
|
|
|
it '#create fails if user is not owner' do
|
|
post_json api_v1_organization_groups_create_url(user_domain: @org_user_1.username, organization_id: @carto_organization.id, api_key: @org_user_1.api_key), { display_name: 'willfail' }, @headers do |response|
|
|
response.status.should == 400
|
|
end
|
|
end
|
|
|
|
it '#create triggers group creation' do
|
|
display_name = 'a new group'
|
|
name = 'a new group'
|
|
|
|
# Replacement for extension interaction
|
|
fake_database_role = 'fake_database_role'
|
|
fake_group_creation = Carto::Group.new_instance(@carto_organization.database_name, name, fake_database_role)
|
|
fake_group_creation.save
|
|
Carto::Group.expects(:create_group_extension_query).with(anything, name).returns(fake_group_creation)
|
|
|
|
post_json api_v1_organization_groups_create_url(user_domain: @admin_user.username, organization_id: @carto_organization.id, api_key: @admin_user.api_key), { display_name: display_name }, @headers do |response|
|
|
response.status.should == 200
|
|
response.body[:id].should_not be_nil
|
|
response.body[:organization_id].should == @carto_organization.id
|
|
response.body[:name].should == name
|
|
response.body[:display_name].should == display_name
|
|
|
|
# Also check database data because Group changes something after extension interaction
|
|
new_group = Carto::Group.find(response.body[:id])
|
|
new_group.organization_id.should == @carto_organization.id
|
|
new_group.name.should == name
|
|
new_group.display_name.should == display_name
|
|
new_group.database_role.should_not be_nil
|
|
end
|
|
end
|
|
|
|
it '#update triggers group renaming' do
|
|
group = @carto_organization.groups.first
|
|
new_display_name = 'A Group %Renamed'
|
|
expected_new_name = 'A Group _Renamed'
|
|
|
|
Carto::Group.expects(:rename_group_extension_query).with(anything, group.name, expected_new_name)
|
|
|
|
put_json api_v1_organization_groups_update_url(user_domain: @admin_user.username, organization_id: @carto_organization.id, group_id: group.id, api_key: @admin_user.api_key), { display_name: new_display_name }, @headers do |response|
|
|
response.status.should == 200
|
|
response.body[:id].should_not be_nil
|
|
response.body[:organization_id].should == @carto_organization.id
|
|
# INFO: since test doesn't actually trigger the extension we only check expectation on renaming call and display name
|
|
response.body[:display_name].should == new_display_name
|
|
response.body[:shared_tables_count].should_not be_nil
|
|
response.body[:shared_maps_count].should_not be_nil
|
|
response.body[:users].should_not be_nil
|
|
|
|
# Also check database data because Group changes something after extension interaction
|
|
new_group = Carto::Group.find(response.body[:id])
|
|
new_group.organization_id.should == @carto_organization.id
|
|
new_group.display_name.should == new_display_name
|
|
new_group.database_role.should_not be_nil
|
|
end
|
|
end
|
|
|
|
it '#update returns 409 and a meaningful error message if there is a group with the same name within the organization' do
|
|
group = @carto_organization.groups[0]
|
|
group_2 = @carto_organization.groups[1]
|
|
|
|
Carto::Group.expects(:rename_group_extension_query).with(anything, anything, anything).never
|
|
|
|
put_json api_v1_organization_groups_update_url(user_domain: @admin_user.username, organization_id: @carto_organization.id, group_id: group.id, api_key: @admin_user.api_key), { display_name: group_2.display_name }, @headers do |response|
|
|
response.status.should == 409
|
|
response.body[:errors][0].should match /A group with that name already exists/
|
|
end
|
|
end
|
|
|
|
it '#add_users triggers group inclusion' do
|
|
group = @carto_organization.groups.first
|
|
user = @org_user_1
|
|
|
|
Carto::Group.expects(:add_users_group_extension_query).with(anything, group.name, [user.username])
|
|
|
|
post_json api_v1_organization_groups_add_users_url(
|
|
user_domain: @admin_user.username,
|
|
organization_id: @carto_organization.id,
|
|
group_id: group.id,
|
|
api_key: @admin_user.api_key
|
|
), {
|
|
user_id: user.id,
|
|
password_confirmation: '00012345678'
|
|
}, @headers do |response|
|
|
response.status.should == 200
|
|
# INFO: since test doesn't actually trigger the extension we only check expectation on membership call
|
|
end
|
|
end
|
|
|
|
it 'fails to #add_users if wrong password_confirmation' do
|
|
group = @carto_organization.groups.first
|
|
user = @org_user_1
|
|
|
|
post_json api_v1_organization_groups_add_users_url(
|
|
user_domain: @admin_user.username,
|
|
organization_id: @carto_organization.id,
|
|
group_id: group.id,
|
|
api_key: @admin_user.api_key
|
|
), {
|
|
user_id: user.id,
|
|
password_confirmation: 'wrong'
|
|
}, @headers do |response|
|
|
response.status.should == 403
|
|
response.body[:errors].should include "Confirmation password sent does not match your current password"
|
|
end
|
|
end
|
|
|
|
it '#remove_users triggers group exclusion' do
|
|
group = @carto_organization.groups.first
|
|
user = @carto_org_user_1
|
|
group.users << user
|
|
group.save
|
|
group.reload
|
|
group.users.include?(user)
|
|
|
|
Carto::Group.expects(:remove_users_group_extension_query).with(anything, group.name, [user.username])
|
|
|
|
delete_json api_v1_organization_groups_remove_users_url(
|
|
user_domain: @admin_user.username,
|
|
organization_id: @carto_organization.id,
|
|
group_id: group.id,
|
|
api_key: @admin_user.api_key,
|
|
user_id: user.id
|
|
), {
|
|
password_confirmation: '00012345678'
|
|
}, @headers do |response|
|
|
response.status.should == 200
|
|
# INFO: since test doesn't actually trigger the extension we only check expectation on membership call
|
|
end
|
|
end
|
|
|
|
it 'fails #remove_users if wrong password_confirmation' do
|
|
group = @carto_organization.groups.first
|
|
user = @carto_org_user_1
|
|
group.users << user unless group.users.include?(user)
|
|
group.save
|
|
group.reload
|
|
group.users.include?(user)
|
|
|
|
delete_json api_v1_organization_groups_remove_users_url(
|
|
user_domain: @admin_user.username,
|
|
organization_id: @carto_organization.id,
|
|
group_id: group.id,
|
|
api_key: @admin_user.api_key,
|
|
user_id: user.id
|
|
), {
|
|
password_confirmation: 'wrong'
|
|
}, @headers do |response|
|
|
response.status.should == 403
|
|
response.body[:errors].should include "Confirmation password sent does not match your current password"
|
|
end
|
|
end
|
|
|
|
it '#add_users allows batches and triggers group inclusion' do
|
|
group = @carto_organization.groups.first
|
|
user_1 = @org_user_1
|
|
user_2 = @org_user_2
|
|
|
|
Carto::Group.expects(:add_users_group_extension_query)
|
|
.with(anything, group.name, [user_1.username, user_2.username])
|
|
|
|
post_json api_v1_organization_groups_add_users_url(
|
|
user_domain: @admin_user.username,
|
|
organization_id: @carto_organization.id,
|
|
group_id: group.id,
|
|
api_key: @admin_user.api_key
|
|
), {
|
|
users: [user_1.id, user_2.id],
|
|
password_confirmation: '00012345678'
|
|
}, @headers do |response|
|
|
response.status.should == 200
|
|
# INFO: since test doesn't actually trigger the extension we only check expectation on membership call
|
|
end
|
|
end
|
|
|
|
it '#remove_users allows batches and triggers group exclusion' do
|
|
group = @carto_organization.groups.first
|
|
user_1 = @carto_org_user_1
|
|
user_2 = @carto_org_user_2
|
|
group.users << user_2
|
|
group.save
|
|
group.reload
|
|
group.users.include?(user_1)
|
|
group.users.include?(user_2)
|
|
|
|
Carto::Group.expects(:remove_users_group_extension_query)
|
|
.with(anything, group.name, [user_1.username, user_2.username])
|
|
|
|
delete_json api_v1_organization_groups_remove_users_url(
|
|
user_domain: @admin_user.username,
|
|
organization_id: @carto_organization.id,
|
|
group_id: group.id,
|
|
api_key: @admin_user.api_key
|
|
), {
|
|
users: [user_1.id, user_2.id],
|
|
password_confirmation: '00012345678'
|
|
}, @headers do |response|
|
|
response.status.should == 200
|
|
# INFO: since test doesn't actually trigger the extension we only check expectation on membership call
|
|
end
|
|
end
|
|
|
|
it '#drops triggers deletion of existing groups' do
|
|
group = @carto_organization.groups.first
|
|
|
|
Carto::Group.expects(:destroy_group_extension_query).with(anything, group.name)
|
|
|
|
delete_json api_v1_organization_groups_destroy_url(
|
|
user_domain: @admin_user.username,
|
|
organization_id: @carto_organization.id,
|
|
group_id: group.id,
|
|
api_key: @admin_user.api_key
|
|
), {
|
|
password_confirmation: '00012345678'
|
|
}, @headers do |response|
|
|
response.status.should == 204
|
|
|
|
# Extension is simulated, so we delete the group manually
|
|
group.delete
|
|
end
|
|
end
|
|
|
|
it 'cannot destroy group if wrong password_confirmation' do
|
|
group = @carto_organization.groups.first
|
|
|
|
delete_json api_v1_organization_groups_destroy_url(
|
|
user_domain: @admin_user.username,
|
|
organization_id: @carto_organization.id,
|
|
group_id: group.id,
|
|
api_key: @admin_user.api_key
|
|
), {
|
|
password_confirmation: 'wrong'
|
|
}, @headers do |response|
|
|
response.status.should == 403
|
|
response.body[:errors].should include "Confirmation password sent does not match your current password"
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'with organization owner' do
|
|
it_behaves_like 'Groups editor management' do
|
|
before(:all) do
|
|
@admin_user = @organization.owner
|
|
@admin_user.password = '00012345678'
|
|
@admin_user.password_confirmation = '00012345678'
|
|
@admin_user.save
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'with organization admin' do
|
|
it_behaves_like 'Groups editor management' do
|
|
before(:all) do
|
|
@org_user_2.org_admin = true
|
|
@org_user_2.save
|
|
@admin_user = @org_user_2
|
|
@admin_user.password = '00012345678'
|
|
@admin_user.password_confirmation = '00012345678'
|
|
@admin_user.save
|
|
end
|
|
end
|
|
end
|
|
end
|