Initial commit

This commit is contained in:
zhongjin
2020-06-15 10:58:47 +08:00
commit 4f1dfe7564
8590 changed files with 1516878 additions and 0 deletions
@@ -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