Initial commit
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
class Superadmin::AccountTypesController < Superadmin::SuperadminController
|
||||
respond_to :json
|
||||
|
||||
ssl_required :create, :update, :destroy
|
||||
|
||||
before_filter :get_account_type, only: [:update, :destroy]
|
||||
before_filter :get_rate_limit, only: [:create, :update]
|
||||
|
||||
def create
|
||||
if Carto::AccountType.exists?(params[:account_type][:account_type])
|
||||
@account_type = Carto::AccountType.find(params[:account_type][:account_type])
|
||||
else
|
||||
@account_type = Carto::AccountType.new
|
||||
@account_type.account_type = params[:account_type][:account_type]
|
||||
end
|
||||
|
||||
@account_type.rate_limit = @rate_limit
|
||||
@account_type.save!
|
||||
|
||||
render json: @account_type, status: 201
|
||||
end
|
||||
|
||||
def update
|
||||
if @account_type.rate_limit != @rate_limit
|
||||
@account_type.rate_limit.update_attributes!(@rate_limit.rate_limit_attributes)
|
||||
::Resque.enqueue(::Resque::UserJobs::RateLimitsJobs::SyncRedis, @account_type.account_type)
|
||||
end
|
||||
|
||||
render json: @account_type, status: 200
|
||||
end
|
||||
|
||||
def destroy
|
||||
@account_type.destroy
|
||||
|
||||
render nothing: true, status: 204
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_account_type
|
||||
@account_type = Carto::AccountType.find(params[:id])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render json: { error: 'ERROR. account_type not found' }, status: 404
|
||||
end
|
||||
|
||||
def get_rate_limit
|
||||
account_type_params = params[:account_type] || {}
|
||||
|
||||
@rate_limit = Carto::RateLimit.from_api_attributes(account_type_params[:rate_limit] || {})
|
||||
|
||||
render json: { error: 'ERROR. rate_limit object is not valid' }, status: 422 unless @rate_limit.valid?
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,38 @@
|
||||
class Superadmin::FeatureFlagsController < Superadmin::SuperadminController
|
||||
respond_to :json
|
||||
|
||||
ssl_required :create, :update, :destroy
|
||||
|
||||
before_filter :get_feature_flag, only: [:create, :update, :destroy]
|
||||
|
||||
def create
|
||||
@feature_flag.save
|
||||
render json: @feature_flag, status: 204
|
||||
end
|
||||
|
||||
def update
|
||||
@feature_flag.save
|
||||
render json: @feature_flag, status: 204
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @feature_flag.present?
|
||||
@feature_flag.destroy
|
||||
end
|
||||
render json: @feature_flag, status: 204
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_feature_flag
|
||||
feature_flag_params = params[:feature_flag]
|
||||
@feature_flag = FeatureFlag[feature_flag_params[:id]]
|
||||
if !@feature_flag.present?
|
||||
@feature_flag = FeatureFlag.new
|
||||
@feature_flag.id = feature_flag_params[:id]
|
||||
end
|
||||
@feature_flag.name = feature_flag_params[:name]
|
||||
@feature_flag.restricted = feature_flag_params[:restricted]
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,41 @@
|
||||
class Superadmin::OauthAppsController < Superadmin::SuperadminController
|
||||
respond_to :json
|
||||
|
||||
ssl_required
|
||||
|
||||
before_action :load_oauth_app, only: [:update, :destroy]
|
||||
|
||||
ALLOWED_SYNC_PARAMS = Carto::OauthApp::ALLOWED_SYNC_ATTRIBUTES + [:user_id, redirect_uris: []].freeze
|
||||
|
||||
def create
|
||||
@oauth_app = Carto::OauthApp.create!(oauth_params)
|
||||
|
||||
render json: @oauth_app, status: 201
|
||||
end
|
||||
|
||||
def update
|
||||
@oauth_app.update!(oauth_params)
|
||||
|
||||
render nothing: true, status: 204
|
||||
end
|
||||
|
||||
def destroy
|
||||
@oauth_app.avoid_sync_central = true
|
||||
@oauth_app.destroy!
|
||||
|
||||
render nothing: true, status: 204
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_oauth_app
|
||||
@oauth_app = Carto::OauthApp.find(params[:id])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render json: { error: 'ERROR. oauth_app not found' }, status: 404
|
||||
end
|
||||
|
||||
def oauth_params
|
||||
params[:oauth_app].permit(ALLOWED_SYNC_PARAMS)
|
||||
.merge(avoid_sync_central: true)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,60 @@
|
||||
class Superadmin::OrganizationsController < Superadmin::SuperadminController
|
||||
respond_to :json
|
||||
|
||||
ssl_required :show, :create, :update, :destroy, :index
|
||||
before_filter :get_organization, only: [:update, :destroy, :show]
|
||||
|
||||
layout 'application'
|
||||
|
||||
def show
|
||||
respond_with(@organization.data(:extended => true))
|
||||
end
|
||||
|
||||
def index
|
||||
@organizations = (params[:overquota].present? ? Organization.overquota(0.20) : Organization.all)
|
||||
|
||||
respond_with(:superadmin, @organizations.map(&:data))
|
||||
end
|
||||
|
||||
def create
|
||||
@organization = Organization.new
|
||||
@organization.set_fields_from_central(params[:organization], :create)
|
||||
if @organization.save && params[:organization][:owner_id].present? && @organization.owner.nil?
|
||||
# TODO: move this into a callback or a model method
|
||||
uo = CartoDB::UserOrganization.new(@organization.id, params[:organization][:owner_id])
|
||||
uo.promote_user_to_admin
|
||||
end
|
||||
respond_with(:superadmin, @organization)
|
||||
rescue => e
|
||||
begin
|
||||
@organization.delete if @organization && @organization.id
|
||||
rescue => ee
|
||||
# Avoid shadowing original error
|
||||
CartoDB.notify_error('Cleaning failed creation', error: ee.inspect, organization: @organization)
|
||||
end
|
||||
CartoDB.notify_error('Error creating organization', error: e.inspect, organization: @organization)
|
||||
respond_with(:superadmin, @organization, errors: [e.inspect], status: 500)
|
||||
end
|
||||
|
||||
def update
|
||||
@organization.set_fields_from_central(params[:organization], :update)
|
||||
@organization.save
|
||||
respond_with(:superadmin, @organization)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@organization.destroy_cascade(delete_in_central: false)
|
||||
respond_with(:superadmin, @organization)
|
||||
rescue => e
|
||||
CartoDB::Logger.error(exception: e, message: 'Error deleting organization', organization: @organization)
|
||||
render json: { errors: [e.inspect] }, status: 500
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_organization
|
||||
@organization = Organization[params[:id]]
|
||||
render json: { error: 'Organization not found' }, status: 404 unless @organization
|
||||
end # get_organization
|
||||
|
||||
end
|
||||
@@ -0,0 +1,86 @@
|
||||
require_dependency 'carto/db/database'
|
||||
require_dependency 'carto/db/connection'
|
||||
|
||||
class Superadmin::PlatformController < Superadmin::SuperadminController
|
||||
|
||||
respond_to :json
|
||||
ssl_required :databases_info
|
||||
layout 'application'
|
||||
|
||||
before_filter :check_for_database_host, only: [:database_validation]
|
||||
|
||||
def databases_info
|
||||
if params[:database_host]
|
||||
hosts = [params[:database_host]]
|
||||
else
|
||||
hosts = ::User.distinct(:database_host).select(:database_host).all.map(&:database_host)
|
||||
end
|
||||
dbs = {}
|
||||
hosts.each do |h|
|
||||
total_account_types = ::User.where(database_host: h).group_and_count(:account_type).order(Sequel.desc(:count)).all
|
||||
users_in_database = ::User.where(database_host: h).count
|
||||
dbs[h] = { count: users_in_database, total_account_types_percentages: {}, total_account_types_count: {} }
|
||||
total_account_types.each do |a|
|
||||
if users_in_database.to_i > 0
|
||||
percentage = (a[:count] * 100) / users_in_database
|
||||
dbs[h][:total_account_types_percentages][a[:account_type]] = percentage
|
||||
dbs[h][:total_account_types_count][a[:account_type]] = a[:count]
|
||||
end
|
||||
end
|
||||
end
|
||||
respond_with(dbs)
|
||||
end
|
||||
|
||||
def database_validation
|
||||
Carto::Db::Connection.connect(params[:database_host], 'postgres', as: :cluster_admin) do |database, _|
|
||||
db_users = database.roles
|
||||
non_carto_users = db_users.select { |r| !r.system_db_role? && !r.carto_db_role? }
|
||||
carto_users = db_users.select(&:carto_db_role?)
|
||||
connected_users = Carto::User.where(database_host: params[:database_host])
|
||||
.where(id: carto_users.map(&:id))
|
||||
.pluck(:username)
|
||||
return render json: { db_users: non_carto_users, carto_users: connected_users }
|
||||
end
|
||||
end
|
||||
|
||||
def total_users
|
||||
respond_with({:count => CartoDB::Stats::Platform.new.users})
|
||||
end
|
||||
|
||||
def total_pay_users
|
||||
respond_with({:count => CartoDB::Stats::Platform.new.pay_users})
|
||||
end
|
||||
|
||||
def total_datasets
|
||||
respond_with({:count => CartoDB::Stats::Platform.new.datasets})
|
||||
end
|
||||
|
||||
def total_seats_among_orgs
|
||||
respond_with(CartoDB::Stats::Platform.new.seats_among_orgs)
|
||||
end
|
||||
|
||||
def total_shared_objects_among_orgs
|
||||
respond_with(CartoDB::Stats::Platform.new.shared_objects_among_orgs)
|
||||
end
|
||||
|
||||
def total_visualizations
|
||||
respond_with({:count => CartoDB::Stats::Platform.new.visualizations})
|
||||
end
|
||||
|
||||
def total_maps
|
||||
respond_with({:count => CartoDB::Stats::Platform.new.maps})
|
||||
end
|
||||
|
||||
def total_active_users
|
||||
respond_with({:count => CartoDB::Stats::Platform.new.active_users})
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_for_database_host
|
||||
if !params[:database_host]
|
||||
render json: { error: "Database host parameter is mandatory" }, status: 400
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,35 @@
|
||||
class Superadmin::SuperadminController < ActionController::Base
|
||||
before_filter :authenticate
|
||||
|
||||
rescue_from StandardError, with: :rescue_from_superadmin_error
|
||||
|
||||
def self.ssl_required(*splat)
|
||||
if Rails.env.production? || Rails.env.staging?
|
||||
force_ssl only: splat
|
||||
end
|
||||
end
|
||||
|
||||
def self.ssl_allowed(*_splat)
|
||||
# noop
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def authenticate
|
||||
return true if Rails.env.development? || authenticated?(CartoDB.extract_subdomain(request)) && current_user.admin
|
||||
authenticate_or_request_with_http_basic do |username, password|
|
||||
username == Cartodb.config[:superadmin]["username"] && password == Cartodb.config[:superadmin]["password"]
|
||||
end
|
||||
end
|
||||
|
||||
def current_user
|
||||
super(CartoDB.extract_subdomain(request))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def rescue_from_superadmin_error(error)
|
||||
CartoDB::Logger.error(exception: error)
|
||||
render(json: { errors: { message: error.inspect, backtrace: error.backtrace.inspect } }, status: 500)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,30 @@
|
||||
require_relative '../../models/synchronization/member'
|
||||
require_relative '../../models/synchronization/collection'
|
||||
require_relative '../../../services/datasources/lib/datasources'
|
||||
|
||||
class Superadmin::SynchronizationsController < Superadmin::SuperadminController
|
||||
include CartoDB
|
||||
|
||||
respond_to :json
|
||||
|
||||
ssl_required :index
|
||||
|
||||
layout 'application'
|
||||
|
||||
def index
|
||||
collection = Synchronization::Collection.new.fetch(per_page:99999)
|
||||
if params[:pending_syncs].present?
|
||||
representation = collection.map { |sync|
|
||||
sync.should_auto_sync? ? sync.to_hash : nil
|
||||
}.compact
|
||||
else
|
||||
representation = collection.map(&:to_hash)
|
||||
end
|
||||
response = {
|
||||
synchronizations: representation,
|
||||
total_entries: collection.total_entries
|
||||
}
|
||||
respond_with(response)
|
||||
end #index
|
||||
|
||||
end # Superadmin::SynchronizationsController
|
||||
@@ -0,0 +1,226 @@
|
||||
require_relative '../../../lib/carto/http/client'
|
||||
require_dependency 'carto/uuidhelper'
|
||||
require_dependency 'carto/overquota_users_service'
|
||||
require_dependency 'carto/api/paged_searcher'
|
||||
|
||||
class Superadmin::UsersController < Superadmin::SuperadminController
|
||||
include Carto::UUIDHelper
|
||||
include Carto::Api::PagedSearcher
|
||||
include Carto::ControllerHelper
|
||||
|
||||
respond_to :json
|
||||
|
||||
ssl_required :show, :create, :update, :destroy, :index
|
||||
before_filter :get_user, only: [:update, :destroy, :show, :dump, :data_imports, :data_import]
|
||||
before_filter :get_carto_user, only: [:synchronizations, :synchronization, :geocodings, :geocoding]
|
||||
|
||||
rescue_from Carto::ParamInvalidError, with: :rescue_from_carto_error
|
||||
|
||||
layout 'application'
|
||||
|
||||
VALID_ORDER_PARAMS = [:updated_at].freeze
|
||||
|
||||
def show
|
||||
respond_with(@user.data({:extended => true}))
|
||||
end
|
||||
|
||||
def index
|
||||
if params[:overquota].present?
|
||||
users = Carto::OverquotaUsersService.new.get_stored_overquota_users
|
||||
respond_with(:superadmin, users)
|
||||
elsif params[:db_size_in_bytes_change].present?
|
||||
# This use case is specific: we only return cached db_size_in_bytes, which is
|
||||
# much faster and doesn't add load to the database.
|
||||
username_dbsize = Carto::UserDbSizeCache.new.db_size_in_bytes_change_users
|
||||
respond_with(:superadmin, username_dbsize.map do |username, db_size_in_bytes|
|
||||
{ 'username' => username, 'db_size_in_bytes' => db_size_in_bytes }
|
||||
end) and return
|
||||
elsif params[:account_type].present? && params[:state].present?
|
||||
users = ::User.where(account_type: params[:account_type], state: params[:state])
|
||||
respond_with(:superadmin, users.map(&:activity))
|
||||
else
|
||||
users = ::User.all
|
||||
respond_with(:superadmin, users.map(&:data))
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@user = ::User.new
|
||||
|
||||
user_param = params[:user]
|
||||
@user.set_fields_from_central(user_param, :create)
|
||||
@user.enabled = true
|
||||
|
||||
@user.rate_limit_id = create_rate_limits(user_param[:rate_limit]).id if user_param[:rate_limit].present?
|
||||
if @user.save
|
||||
@user.reload
|
||||
CartoDB::Visualization::CommonDataService.load_common_data(@user, self) if @user.should_load_common_data?
|
||||
@user.set_relationships_from_central(user_param)
|
||||
end
|
||||
CartoGearsApi::Events::EventManager.instance.notify(
|
||||
CartoGearsApi::Events::UserCreationEvent.new(
|
||||
CartoGearsApi::Events::UserCreationEvent::CREATED_VIA_SUPERADMIN, @user
|
||||
)
|
||||
)
|
||||
respond_with(:superadmin, @user)
|
||||
end
|
||||
|
||||
def update
|
||||
user_param = params[:user]
|
||||
@user.set_fields_from_central(user_param, :update)
|
||||
@user.set_relationships_from_central(user_param)
|
||||
@user.regenerate_api_key(user_param[:api_key]) if user_param[:api_key].present?
|
||||
|
||||
@user.update_rate_limits(user_param[:rate_limit])
|
||||
@user.save
|
||||
respond_with(:superadmin, @user)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@user.set_force_destroy if params[:force] == 'true'
|
||||
@user.destroy
|
||||
respond_with(:superadmin, @user)
|
||||
rescue CartoDB::SharedEntitiesError => e
|
||||
render json: { "error": "Error destroying user: #{e.message}", "errorCode": "userHasSharedEntities" }, status: 422
|
||||
rescue => e
|
||||
CartoDB::Logger.error(exception: e, message: 'Error destroying user', user: @user)
|
||||
render json: { "error": "Error destroying user: #{e.message}", "errorCode": "" }, status: 422
|
||||
end
|
||||
|
||||
def dump
|
||||
if Cartodb.config[:users_dumps].nil? || Cartodb.config[:users_dumps]["service"].nil? || Cartodb.config[:users_dumps]["service"]["port"].nil?
|
||||
raise "There is not a dump method configured"
|
||||
end
|
||||
json_data = {database: @user.database_name, username: @user.username}
|
||||
http_client = Carto::Http::Client.get(self.class.name, log_requests: true)
|
||||
response = http_client.request(
|
||||
"#{@user.database_host}:#{Cartodb.config[:users_dumps]["service"]["port"]}/scripts/db_dump",
|
||||
method: :post,
|
||||
headers: { "Content-Type" => "application/json" },
|
||||
body: json_data.to_json
|
||||
).run
|
||||
parsed_response = JSON.parse(response.body)
|
||||
if response.code == 200 &&
|
||||
parsed_response['retcode'] == 0 &&
|
||||
!parsed_response['return_values']['local_file'].nil? &&
|
||||
!parsed_response['return_values']['local_file'].empty? &&
|
||||
!parsed_response['return_values']['remote_file'].nil? &&
|
||||
!parsed_response['return_values']['remote_file'].empty?
|
||||
sa_response = {
|
||||
:dumper_response => parsed_response,
|
||||
:remote_file => parsed_response['remote_file'],
|
||||
:local_file => parsed_response['local_file'],
|
||||
:database_host => @user.database_host
|
||||
}
|
||||
render json: sa_response, status: 200
|
||||
else
|
||||
sa_response = {
|
||||
:dumper_response => parsed_response
|
||||
}
|
||||
render json: sa_response, status: 400
|
||||
end
|
||||
end
|
||||
|
||||
def data_imports
|
||||
page, per_page, order, _order_direction = page_per_page_order_params(VALID_ORDER_PARAMS)
|
||||
dataset = @user.data_imports_dataset.order(Sequel.desc(order)).paginate(page, per_page)
|
||||
|
||||
dataset = dataset.where(state: params[:status]) if params[:status].present?
|
||||
total_entries = dataset.pagination_record_count
|
||||
|
||||
data_imports_info = dataset.map do |entry|
|
||||
{
|
||||
id: entry.id,
|
||||
data_type: entry.data_type,
|
||||
date: entry.updated_at,
|
||||
status: entry.success.nil? ? false : entry.success,
|
||||
state: entry.state
|
||||
}
|
||||
end
|
||||
|
||||
respond_with({ total_entries: total_entries }.merge(data_imports: data_imports_info))
|
||||
end
|
||||
|
||||
def data_import
|
||||
data_import = DataImport[params[:data_import_id]]
|
||||
respond_with({
|
||||
data: data_import.to_hash,
|
||||
log: data_import.nil? ? nil : data_import.log.to_s
|
||||
})
|
||||
end
|
||||
|
||||
def geocodings
|
||||
page, per_page, order, _order_direction = page_per_page_order_params(VALID_ORDER_PARAMS)
|
||||
dataset = @user.geocodings.order("#{order} desc")
|
||||
|
||||
dataset = dataset.where(state: params[:status]) if params[:status].present?
|
||||
total_entries = dataset.count
|
||||
|
||||
geocodings_info = dataset.limit(per_page).offset((page - 1) * per_page).map do |entry|
|
||||
{
|
||||
id: entry.id,
|
||||
date: entry.updated_at,
|
||||
status: entry.state
|
||||
}
|
||||
end
|
||||
respond_with({ total_entries: total_entries }.merge(geocodings: geocodings_info))
|
||||
end
|
||||
|
||||
def geocoding
|
||||
geocoding = @user.geocodings.find(params[:geocoding_id])
|
||||
respond_with(data: geocoding.attributes, log: geocoding && geocoding.log.to_s)
|
||||
end
|
||||
|
||||
def synchronizations
|
||||
page, per_page, order, _order_direction = page_per_page_order_params(VALID_ORDER_PARAMS)
|
||||
dataset = @user.synchronizations.order("#{order} desc")
|
||||
|
||||
dataset = dataset.where(state: params[:status]) if params[:status].present?
|
||||
total_entries = dataset.count
|
||||
|
||||
synchronizations_info = dataset.limit(per_page).offset((page - 1) * per_page).map do |entry|
|
||||
{
|
||||
id: entry.id,
|
||||
data_type: entry.service_name,
|
||||
date: entry.updated_at,
|
||||
status: entry.success?,
|
||||
state: entry.state
|
||||
}
|
||||
end
|
||||
respond_with({ total_entries: total_entries }.merge(synchronizations: synchronizations_info))
|
||||
end
|
||||
|
||||
def synchronization
|
||||
synchronization = Carto::Synchronization.where(id: params[:synchronization_id]).first
|
||||
respond_with({
|
||||
data: synchronization.to_hash,
|
||||
log: synchronization.nil? ? nil : synchronization.log.try(:entries)
|
||||
})
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_user
|
||||
id = params[:id]
|
||||
|
||||
@user = if is_uuid?(id)
|
||||
::User[params[:id]]
|
||||
else
|
||||
::User.where(username: id).first
|
||||
end
|
||||
|
||||
render json: { error: 'User not found' }, status: 404 unless @user
|
||||
end
|
||||
|
||||
def get_carto_user
|
||||
@user = Carto::User.where(id: params[:id]).first
|
||||
render json: { error: 'User not found' }, status: 404 unless @user
|
||||
end
|
||||
|
||||
def create_rate_limits(rate_limit_attributes)
|
||||
rate_limit = Carto::RateLimit.from_api_attributes(rate_limit_attributes)
|
||||
rate_limit.save!
|
||||
rate_limit
|
||||
end
|
||||
|
||||
end # Superadmin::UsersController
|
||||
Reference in New Issue
Block a user