198 lines
8.0 KiB
Ruby
198 lines
8.0 KiB
Ruby
require_dependency 'cartodb/errors'
|
|
|
|
module Carto
|
|
module Api
|
|
|
|
# Group metadata registration. Exclusively for usage from PostgreSQL Extension, not from the Editor.
|
|
# It only registers metadata, actual group roles management must be done by the extension.
|
|
# Named "DatabaseGroups" because it receives _databases_, not organizations.
|
|
class DatabaseGroupsController < ::ApplicationController
|
|
|
|
respond_to :json
|
|
|
|
ssl_required :create, :update, :destroy, :add_users, :remove_users, :update_permission, :destroy_permission
|
|
|
|
# TODO: Make this controller inherit from ::Api::ApplicationController and remove skip_before_filter bellow
|
|
skip_before_filter :verify_authenticity_token
|
|
|
|
# Allow HTTPS on local/test as the calls from the groups API are done sending a https X-Forwarded-Proto,
|
|
# like simulating they come from https:
|
|
# @see https://github.com/CartoDB/cartodb-postgresql/blob/bce61c1e4359653134134097d269edae581e5660/scripts-available/CDB_Groups_API.sql#L170
|
|
# Without it, SSL is forbidden and a 302 to url "without HTTP" was returned so the API didn't work on testing
|
|
|
|
def ssl_allowed?
|
|
Rails.env.development? || Rails.env.test?
|
|
end
|
|
|
|
before_filter :authenticate_extension
|
|
before_filter :load_parameters
|
|
before_filter :load_mandatory_group, :only => [:destroy, :add_users, :remove_users, :update_permission, :destroy_permission]
|
|
before_filter :load_user_from_username, :only => [:load_table, :update_permission, :destroy_permission]
|
|
before_filter :load_users_from_username, :only => [:add_users, :remove_users]
|
|
before_filter :load_table, :only => [:update_permission, :destroy_permission]
|
|
|
|
def create
|
|
group = Group.new_instance(@database_name, @name, @database_role)
|
|
if group.save
|
|
render json: group.to_json
|
|
else
|
|
render json: { errors: "Error saving group: #{group.errors}" }, status: 400
|
|
end
|
|
rescue CartoDB::ModelAlreadyExistsError => e
|
|
CartoDB.notify_debug('Group already exists', { params: params })
|
|
render json: { errors: "A group with that data already exists" }, status: 409
|
|
rescue => e
|
|
CartoDB.notify_exception(e, { params: params , group: (group ? group : 'not created') })
|
|
render json: { errors: e.message }, status: 500
|
|
end
|
|
|
|
def update
|
|
new_name = params['name']
|
|
group = get_group_from_loaded_parameters
|
|
if group
|
|
group.rename(new_name, @database_role)
|
|
if group.save
|
|
render json: @group.to_json
|
|
else
|
|
raise "Error saving group: #{@group.errors}"
|
|
end
|
|
else
|
|
renamed_group = get_group(@database_name, new_name)
|
|
if renamed_group && renamed_group.database_role == @database_role
|
|
CartoDB.notify_debug('Group already renamed', { params: params })
|
|
render json: { errors: "That group has already been renamed" }, status: 409
|
|
else
|
|
raise "Group not found and no matching rename found"
|
|
end
|
|
end
|
|
rescue => e
|
|
CartoDB.notify_exception(e, { params: params , group: (@group ? @group : 'not loaded') })
|
|
render json: { errors: e.message }, status: 500
|
|
end
|
|
|
|
def destroy
|
|
@group.destroy
|
|
render json: {}, status: 204
|
|
rescue => e
|
|
CartoDB.notify_exception(e, { params: params , group: (@group ? @group : 'not loaded') })
|
|
render json: { errors: e.message }, status: 500
|
|
end
|
|
|
|
def add_users
|
|
added_usernames = []
|
|
@usernames.map { |username|
|
|
begin
|
|
added_usernames << @group.add_user(username).user.username
|
|
rescue CartoDB::ModelAlreadyExistsError => e
|
|
# This will provoke 409 response later
|
|
end
|
|
}
|
|
if added_usernames.length == @usernames.length
|
|
render json: { users: added_usernames }, status: 200
|
|
else
|
|
render json: { errors: "Some users were already in the group: #{@usernames - added_usernames }", users: added_usernames }, status: 409
|
|
end
|
|
rescue => e
|
|
CartoDB.notify_exception(e, { params: params , group: (@group ? @group : 'not loaded') })
|
|
render json: { errors: e.message }, status: 500
|
|
end
|
|
|
|
def remove_users
|
|
removed_usernames = []
|
|
@usernames.map { |username|
|
|
removed_user = @group.remove_user(username)
|
|
removed_usernames << removed_user.username if !removed_user.nil?
|
|
}
|
|
if removed_usernames.length == @usernames.length
|
|
render json: { users: removed_usernames }, status: 200
|
|
else
|
|
render json: { errors: "Some users (#{@usernames - removed_usernames}) were not in the group", users: removed_usernames }, status: 404
|
|
end
|
|
rescue => e
|
|
CartoDB.notify_exception(e, { params: params , group: (@group ? @group : 'not loaded') })
|
|
render json: { errors: e.message }, status: 500
|
|
end
|
|
|
|
def update_permission
|
|
permission = CartoDB::Permission[@table.permission.id]
|
|
permission.set_group_permission(@group, @access)
|
|
permission.save
|
|
render json: {}, status: 200
|
|
rescue CartoDB::ModelAlreadyExistsError => e
|
|
CartoDB.notify_debug('Permission already granted', { params: params })
|
|
render json: { errors: "That permission is already granted" }, status: 409
|
|
rescue => e
|
|
CartoDB.notify_exception(e, { params: params , group: (@group ? @group : 'not loaded') })
|
|
render json: { errors: e.message }, status: 500
|
|
end
|
|
|
|
def destroy_permission
|
|
permission = CartoDB::Permission[@table.permission.id]
|
|
permission.remove_group_permission(@group)
|
|
permission.save
|
|
render json: {}, status: 200
|
|
rescue CartoDB::ModelAlreadyExistsError => e
|
|
CartoDB.notify_debug('Permission already revoked', { params: params })
|
|
render json: { errors: "That permission is already revoked" }, status: 404
|
|
rescue => e
|
|
CartoDB.notify_exception(e, { params: params , group: (@group ? @group : 'not loaded') })
|
|
render json: { errors: e.message }, status: 500
|
|
end
|
|
|
|
private
|
|
|
|
def authenticate_extension
|
|
raise "missing org_metadata_api configuration" unless Cartodb.config[:org_metadata_api]
|
|
|
|
authenticate_or_request_with_http_basic do |username, password|
|
|
username == Cartodb.config[:org_metadata_api]["username"] && password == Cartodb.config[:org_metadata_api]["password"]
|
|
end
|
|
end
|
|
|
|
def load_parameters
|
|
@database_name = params[:database_name]
|
|
@name = [params[:old_name], params[:name]].compact.first
|
|
@database_role = params[:database_role]
|
|
@username = params[:username]
|
|
@usernames = @username.present? ? [ @username ] : params[:users]
|
|
@table_name = params[:table_name]
|
|
case params['access']
|
|
when nil
|
|
when 'r'
|
|
@access = CartoDB::Permission::ACCESS_READONLY
|
|
when 'w'
|
|
@access = CartoDB::Permission::ACCESS_READWRITE
|
|
else raise "Unknown access #{params['access']}"
|
|
end
|
|
end
|
|
|
|
def get_group_from_loaded_parameters
|
|
get_group(@database_name, @name)
|
|
end
|
|
|
|
def get_group(database_name, name)
|
|
Group.where(organization_id: Organization.find_by_database_name(database_name).id, name: name).first
|
|
end
|
|
|
|
def load_mandatory_group
|
|
@group = get_group_from_loaded_parameters
|
|
render json: { errors: "Group with database_name #{@database_name} and name #{@name} not found" }, status: 404 unless @group
|
|
end
|
|
|
|
def load_user_from_username
|
|
@user = Carto::User.where(username: @username).first
|
|
end
|
|
|
|
def load_users_from_username
|
|
@users = @usernames.map { |username| Carto::User.where(username: username).first }
|
|
end
|
|
|
|
def load_table
|
|
@table = Carto::Visualization.where(user_id: @user.id, type: 'table', name: @table_name).first
|
|
render json: { errors: "Table #{@username}.#{@table_name} not found" }, status: 404 unless @table
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|