Initial commit
This commit is contained in:
17
app/api/v2/admin/abilities.rb
Normal file
17
app/api/v2/admin/abilities.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Abilities < Grape::API
|
||||
namespace :abilities do
|
||||
desc 'Get all roles and permissions.'
|
||||
get do
|
||||
Ability.admin_permissions[current_user.role] || {}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
155
app/api/v2/admin/adjustments.rb
Normal file
155
app/api/v2/admin/adjustments.rb
Normal file
@@ -0,0 +1,155 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Adjustments < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
namespace :adjustments do
|
||||
desc 'Get all adjustments, result is paginated.',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::Adjustment
|
||||
params do
|
||||
use :currency
|
||||
use :date_picker
|
||||
use :pagination
|
||||
use :ordering
|
||||
optional :state,
|
||||
type: String,
|
||||
values: { value: -> { Adjustment.aasm.states.map(&:name).map(&:to_s) }, message: 'admin.adjustment.invalid_action' },
|
||||
desc: -> { API::V2::Admin::Entities::Adjustment.documentation[:state][:desc] }
|
||||
optional :category,
|
||||
type: String,
|
||||
values: { value: -> { ::Adjustment::CATEGORIES }, message: 'admin.adjustment.invalid_category' },
|
||||
desc: -> { API::V2::Admin::Entities::Adjustment.documentation[:category][:desc] }
|
||||
end
|
||||
get do
|
||||
admin_authorize! :read, Adjustment
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(:state, :category)
|
||||
.translate(currency: :currency_id)
|
||||
.with_daterange
|
||||
.build
|
||||
|
||||
search = Adjustment.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
present paginate(search.result), with: API::V2::Admin::Entities::Adjustment
|
||||
end
|
||||
|
||||
desc 'Get adjustment by ID',
|
||||
success: API::V2::Admin::Entities::Adjustment
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'account.adjustment.non_integer_id' },
|
||||
desc: 'Adjsustment Identifier in Database'
|
||||
end
|
||||
get ':id' do
|
||||
admin_authorize! :read, Adjustment
|
||||
|
||||
present ::Adjustment.find(params[:id]), with: API::V2::Admin::Entities::Adjustment
|
||||
end
|
||||
|
||||
desc 'Create new adjustment.',
|
||||
success: API::V2::Admin::Entities::Adjustment
|
||||
params do
|
||||
requires :reason,
|
||||
type: String,
|
||||
desc: -> { API::V2::Admin::Entities::Adjustment.documentation[:reason][:desc] }
|
||||
requires :description,
|
||||
type: String,
|
||||
desc: -> { API::V2::Admin::Entities::Adjustment.documentation[:description][:desc] }
|
||||
requires :category,
|
||||
type: String,
|
||||
values: { value: -> { ::Adjustment::CATEGORIES }, message: 'admin.adjustment.invalid_category' },
|
||||
desc: -> { API::V2::Admin::Entities::Adjustment.documentation[:category][:desc] }
|
||||
requires :amount,
|
||||
type: { value: BigDecimal, message: 'admin.adjustment.non_decimal_amount' },
|
||||
desc: -> { API::V2::Admin::Entities::Adjustment.documentation[:amount][:desc] }
|
||||
requires :currency_id,
|
||||
type: String,
|
||||
values: { value: -> { ::Currency.codes }, message: 'admin.adjustment.currency_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Adjustment.documentation[:currency][:desc] }
|
||||
requires :asset_account_code,
|
||||
type: { value: Integer, message: 'admin.adjustment.non_integer_asset_account_code' },
|
||||
values: { value: -> { ::Operations::Account.where(type: :asset).pluck(:code) }, message: 'admin.adjustment.invalid_asset_account_code' },
|
||||
desc: -> { API::V2::Admin::Entities::Adjustment.documentation[:asset_account_code][:desc] }
|
||||
requires :receiving_account_code,
|
||||
type: { value: Integer, message: 'admin.adjustment.non_integer_receiving_account_code' },
|
||||
values: { value: -> { ::Operations::Account.where.not(type: :asset).pluck(:code) }, message: 'admin.adjustment.invalid_receiving_account_code' },
|
||||
desc: -> { API::V2::Admin::Entities::Adjustment.documentation[:receiving_account_code][:desc] }
|
||||
optional :receiving_member_uid,
|
||||
type: String,
|
||||
desc: -> { API::V2::Admin::Entities::Adjustment.documentation[:receiving_account_code][:desc] }
|
||||
end
|
||||
post '/new' do
|
||||
admin_authorize! :create, Adjustment
|
||||
|
||||
# Do not accept member_uid if account code is not Liability or Revenue
|
||||
# Raise error if there is no :receiving_member_uid for Liability
|
||||
operation_klass = ::Operations.klass_for(code: params[:receiving_account_code])
|
||||
if operation_klass == ::Operations::Liability && params[:receiving_member_uid].blank?
|
||||
error!({ errors: ['admin.adjustment.missing_receiving_member_uid'] }, 422)
|
||||
elsif operation_klass == ::Operations::Expense && params[:receiving_member_uid].present?
|
||||
error!({ errors: ['admin.adjustment.redundant_receiving_member_uid'] }, 422)
|
||||
end
|
||||
|
||||
receiving = ::Operations.build_account_number(currency_id: params[:currency_id],
|
||||
account_code: params[:receiving_account_code],
|
||||
member_uid: params[:receiving_member_uid])
|
||||
|
||||
adjustment = Adjustment.new(declared(params)
|
||||
.except(:receiving_account_code, :receiving_member_uid)
|
||||
.merge(receiving_account_number: receiving,
|
||||
creator: current_user))
|
||||
if adjustment.save
|
||||
present adjustment, with: API::V2::Admin::Entities::Adjustment
|
||||
status 201
|
||||
else
|
||||
body errors: adjustment.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Accepts adjustment and creates operations or reject adjustment.',
|
||||
success: API::V2::Admin::Entities::Adjustment
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.adjustment.non_integer_id' },
|
||||
desc: -> { API::V2::Admin::Entities::Adjustment.documentation[:id][:desc] }
|
||||
requires :action,
|
||||
type: String,
|
||||
values: { value: -> { Adjustment.aasm.events.map(&:name).map(&:to_s) }, message: 'admin.adjustment.invalid_action' },
|
||||
desc: "Adjustment action all available actions: #{Adjustment.aasm.events.map(&:name)}"
|
||||
end
|
||||
post '/action' do
|
||||
admin_authorize! :update, Adjustment
|
||||
adjustment = Adjustment.find(params[:id])
|
||||
|
||||
if adjustment.amount < 0
|
||||
account_number_hash = ::Operations.split_account_number(account_number: adjustment.receiving_account_number)
|
||||
member = Member.find_by(uid: account_number_hash[:member_uid])
|
||||
balance = member.get_account(account_number_hash[:currency_id]).balance
|
||||
|
||||
if adjustment.amount.abs() > balance
|
||||
error!({ errors: ['admin.adjustment.user_insufficient_balance'] }, 422)
|
||||
end
|
||||
end
|
||||
|
||||
if adjustment.public_send("may_#{params[:action]}?")
|
||||
# TODO: Add behaviour in case of errors on action.
|
||||
adjustment.public_send("#{params[:action]}!", validator: current_user)
|
||||
present adjustment, with: API::V2::Admin::Entities::Adjustment
|
||||
else
|
||||
body errors: ["admin.adjustment.cannot_perform_#{params[:action]}_action"]
|
||||
status 422
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
23
app/api/v2/admin/airdrops.rb
Normal file
23
app/api/v2/admin/airdrops.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'peatio/airdrop'
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Airdrops < Grape::API
|
||||
|
||||
desc 'Process user airdrop'
|
||||
params do
|
||||
requires :file,
|
||||
type: File
|
||||
end
|
||||
post '/airdrops' do
|
||||
Peatio::Airdrop.new.process(current_user, params)
|
||||
present(result: 'Airdrop processing started')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
77
app/api/v2/admin/beneficiaries.rb
Normal file
77
app/api/v2/admin/beneficiaries.rb
Normal file
@@ -0,0 +1,77 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Beneficiaries < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
namespace :beneficiaries do
|
||||
desc 'Get list of beneficiaries',
|
||||
success: API::V2::Admin::Entities::Beneficiary
|
||||
params do
|
||||
use :uid
|
||||
use :ordering
|
||||
use :pagination
|
||||
optional :id,
|
||||
type: Integer,
|
||||
desc: -> { API::V2::Entities::Beneficiary.documentation[:id][:desc] }
|
||||
optional :currency,
|
||||
values: { value: ->(v) { (Array.wrap(v) - ::Currency.codes).blank? }, message: 'account.currency.doesnt_exist' },
|
||||
desc: 'Beneficiary currency code'
|
||||
optional :state,
|
||||
type: Array[Integer],
|
||||
values: { value: ->(v) { (Array.wrap(v) - ::Beneficiary::STATES_MAPPING.values).blank? }, message: 'account.beneficiary.invalid_state' },
|
||||
desc: 'Beneficiary state',
|
||||
coerce_with: lambda { |val|
|
||||
val.map { |s| Beneficiary::STATES_MAPPING[s.to_sym] }
|
||||
}
|
||||
end
|
||||
|
||||
get do
|
||||
admin_authorize! :read, Beneficiary
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(:id)
|
||||
.in(:state)
|
||||
.translate_in(currency: :currency_id)
|
||||
.translate(uid: :member_uid)
|
||||
.build
|
||||
|
||||
search = Beneficiary.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
present paginate(search.result), with: API::V2::Admin::Entities::Beneficiary
|
||||
end
|
||||
|
||||
desc 'Take an action on the beneficiary',
|
||||
success: API::V2::Admin::Entities::Beneficiary
|
||||
|
||||
params do
|
||||
requires :id,
|
||||
type: Integer,
|
||||
desc: -> { API::V2::Admin::Entities::Beneficiary.documentation[:id][:desc] }
|
||||
requires :action,
|
||||
type: String,
|
||||
values: { value: -> { ::Beneficiary.aasm.events.map(&:name).map(&:to_s) }, message: 'admin.beneficiary.invalid_action' },
|
||||
desc: "Valid actions are #{::Beneficiary.aasm.events.map(&:name)}."
|
||||
end
|
||||
|
||||
post '/actions' do
|
||||
admin_authorize! :update, Beneficiary
|
||||
|
||||
beneficiary = Beneficiary.find(params[:id])
|
||||
|
||||
if beneficiary.public_send("may_#{params[:action]}?")
|
||||
beneficiary.public_send("#{params[:action]}!")
|
||||
present beneficiary, with: API::V2::Admin::Entities::Beneficiary
|
||||
else
|
||||
body errors: ["admin.beneficiary.cannot_#{params[:action]}"]
|
||||
status 422
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
201
app/api/v2/admin/blockchains.rb
Normal file
201
app/api/v2/admin/blockchains.rb
Normal file
@@ -0,0 +1,201 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Blockchains < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
namespace :blockchains do
|
||||
desc 'Get all blockchains, result is paginated.',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::Blockchain
|
||||
params do
|
||||
optional :key,
|
||||
values: { value: -> { ::Blockchain.pluck(:key) }, message: 'admin.blockchain.blockchain_key_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:key][:desc] }
|
||||
optional :client,
|
||||
values: { value: -> { ::Blockchain.clients.map(&:to_s) }, message: 'admin.blockchain.blockchain_client_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:client][:desc] }
|
||||
optional :status,
|
||||
values: { value: -> { %w[active disabled] }, message: 'admin.blockchain.blockchain_status_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:status][:desc] }
|
||||
optional :name,
|
||||
values: { value: -> { ::Blockchain.pluck(:name) }, message: 'admin.blockchain.blockchain_name_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:name][:desc] }
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get do
|
||||
admin_authorize! :read, Blockchain
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(:key, :client, :status, :name)
|
||||
.build
|
||||
|
||||
search = ::Blockchain.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
present paginate(search.result), with: API::V2::Admin::Entities::Blockchain
|
||||
end
|
||||
|
||||
desc 'Get available blockchain clients.',
|
||||
is_array: true
|
||||
get '/clients' do
|
||||
Blockchain.clients
|
||||
end
|
||||
|
||||
desc 'Get a blockchain.' do
|
||||
success API::V2::Admin::Entities::Blockchain
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.blockchain.non_integer_id' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:id][:desc] }
|
||||
end
|
||||
get '/:id' do
|
||||
admin_authorize! :read, Blockchain
|
||||
|
||||
present Blockchain.find(params[:id]), with: API::V2::Admin::Entities::Blockchain
|
||||
end
|
||||
|
||||
desc 'Get a latest blockchain block.'
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.blockchain.non_integer_id' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:id][:desc] }
|
||||
end
|
||||
get '/:id/latest_block' do
|
||||
admin_authorize! :read, Blockchain
|
||||
|
||||
Blockchain.find(params[:id])&.blockchain_api.latest_block_number
|
||||
rescue
|
||||
error!({ errors: ['admin.blockchain.latest_block'] }, 422)
|
||||
end
|
||||
|
||||
desc 'Create new blockchain.' do
|
||||
success API::V2::Admin::Entities::Blockchain
|
||||
end
|
||||
params do
|
||||
requires :key,
|
||||
values: { value: -> (v){ v && v.length < 255 }, message: 'admin.blockchain.key_too_long' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:key][:desc] }
|
||||
requires :name,
|
||||
values: { value: -> (v){ v && v.length < 255 }, message: 'admin.blockchain.name_too_long' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:name][:desc] }
|
||||
requires :client,
|
||||
values: { value: -> { ::Blockchain.clients.map(&:to_s) }, message: 'admin.blockchain.invalid_client' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:client][:desc] }
|
||||
requires :height,
|
||||
type: { value: Integer, message: 'admin.blockchain.non_integer_height' },
|
||||
values: { value: -> (p){ p.try(:positive?) }, message: 'admin.blockchain.non_positive_height' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:height][:desc] }
|
||||
optional :explorer_transaction,
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:explorer_transaction][:desc] }
|
||||
optional :explorer_address,
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:explorer_address][:desc] }
|
||||
optional :server,
|
||||
regexp: { value: URI::regexp, message: 'admin.blockchain.invalid_server' },
|
||||
desc: -> { 'Blockchain server url' }
|
||||
optional :status,
|
||||
values: { value: %w(active disabled), message: 'admin.blockchain.invalid_status' },
|
||||
default: 'active',
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:status][:desc] }
|
||||
optional :min_confirmations,
|
||||
type: { value: Integer, message: 'admin.blockchain.non_integer_min_confirmations' },
|
||||
values: { value: -> (p){ p.try(:positive?) }, message: 'admin.blockchain.non_positive_min_confirmations' },
|
||||
default: 6,
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:min_confirmations][:desc] }
|
||||
end
|
||||
post '/new' do
|
||||
admin_authorize! :create, Blockchain
|
||||
|
||||
blockchain = Blockchain.new(declared(params))
|
||||
if blockchain.save
|
||||
present blockchain, with: API::V2::Admin::Entities::Blockchain
|
||||
status 201
|
||||
else
|
||||
body errors: blockchain.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Update blockchain.' do
|
||||
success API::V2::Admin::Entities::Blockchain
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.blockchain.non_integer_id' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:id][:desc] }
|
||||
optional :key,
|
||||
type: String,
|
||||
values: { value: -> (v){ v.length < 255 }, message: 'admin.blockchain.key_too_long' },
|
||||
coerce_with: ->(v) { v.strip.downcase },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:key][:desc] }
|
||||
optional :name,
|
||||
values: { value: -> (v){ v.length < 255 }, message: 'admin.blockchain.name_too_long' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:name][:desc] }
|
||||
optional :client,
|
||||
values: { value: -> { ::Blockchain.clients.map(&:to_s) }, message: 'admin.blockchain.invalid_client' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:client][:desc] }
|
||||
optional :server,
|
||||
regexp: { value: URI::regexp, message: 'admin.blockchain.invalid_server' },
|
||||
desc: -> { 'Blockchain server url' }
|
||||
optional :height,
|
||||
type: { value: Integer, message: 'admin.blockchain.non_integer_height' },
|
||||
values: { value: -> (p){ p.try(:positive?) }, message: 'admin.blockchain.non_positive_height' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:height][:desc] }
|
||||
optional :explorer_transaction,
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:explorer_transaction][:desc] }
|
||||
optional :explorer_address,
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:explorer_address][:desc] }
|
||||
optional :status,
|
||||
values: { value: %w(active disabled), message: 'admin.blockchain.invalid_status' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:status][:desc] }
|
||||
optional :min_confirmations,
|
||||
type: { value: Integer, message: 'admin.blockchain.non_integer_min_confirmations' },
|
||||
values: { value: -> (p){ p.try(:positive?) }, message: 'admin.blockchain.non_positive_min_confirmations' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:min_confirmations][:desc] }
|
||||
end
|
||||
post '/update' do
|
||||
admin_authorize! :update, Blockchain, params.except(:id)
|
||||
|
||||
blockchain = Blockchain.find(params[:id])
|
||||
if blockchain.update(declared(params, include_missing: false))
|
||||
present blockchain, with: API::V2::Admin::Entities::Blockchain
|
||||
else
|
||||
body errors: blockchain.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Process blockchain\'s block.' do
|
||||
success API::V2::Admin::Entities::Blockchain
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.blockchain.non_integer_id' },
|
||||
desc: -> { API::V2::Admin::Entities::Blockchain.documentation[:id][:desc] }
|
||||
requires :block_number,
|
||||
type: { value: Integer, message: 'admin.blockchain.non_integer_block_number' },
|
||||
values: { value: -> (p){ p.try(:positive?) }, message: 'admin.blockchain.non_positive_block_number' },
|
||||
desc: -> { 'The id of a particular block on blockchain' }
|
||||
end
|
||||
post '/process_block' do
|
||||
admin_authorize! :update, Blockchain
|
||||
|
||||
blockchain = Blockchain.find(params[:id])
|
||||
begin
|
||||
blockchain.blockchain_api.process_block(params[:block_number])
|
||||
present blockchain, with: API::V2::Admin::Entities::Blockchain
|
||||
status 201
|
||||
rescue StandardError => e
|
||||
Rails.logger.error { "Error: #{e} while processing block #{params[:block_number]} of blockchain id: #{params[:id]}" }
|
||||
error!({ errors: ['admin.blockchain.process_block'] }, 422)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
234
app/api/v2/admin/currencies.rb
Normal file
234
app/api/v2/admin/currencies.rb
Normal file
@@ -0,0 +1,234 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Currencies < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
helpers do
|
||||
# Collection of shared params, used to
|
||||
# generate required/optional Grape params.
|
||||
OPTIONAL_CURRENCY_PARAMS ||= {
|
||||
name: { desc: -> { API::V2::Admin::Entities::Currency.documentation[:name][:desc] } },
|
||||
deposit_fee: {
|
||||
type: { value: BigDecimal, message: 'admin.currency.non_decimal_deposit_fee' },
|
||||
values: { value: -> (p){ p >= 0 }, message: 'admin.currency.invalid_deposit_fee' },
|
||||
default: 0.0,
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:deposit_fee][:desc] }
|
||||
},
|
||||
min_deposit_amount: {
|
||||
type: { value: BigDecimal, message: 'admin.currency.min_deposit_amount' },
|
||||
values: { value: -> (p){ p >= 0 }, message: 'admin.currency.min_deposit_amount' },
|
||||
default: 0.0,
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:min_deposit_amount][:desc] }
|
||||
},
|
||||
min_collection_amount: {
|
||||
type: { value: BigDecimal, message: 'admin.currency.non_decimal_min_collection_amount' },
|
||||
values: { value: -> (p){ p >= 0 }, message: 'admin.currency.invalid_min_collection_amount' },
|
||||
default: 0.0,
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:min_collection_amount][:desc] }
|
||||
},
|
||||
withdraw_fee: {
|
||||
type: { value: BigDecimal, message: 'admin.currency.non_decimal_withdraw_fee' },
|
||||
values: { value: -> (p){ p >= 0 }, message: 'admin.currency.ivalid_withdraw_fee' },
|
||||
default: 0.0,
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:withdraw_fee][:desc] }
|
||||
},
|
||||
min_withdraw_amount: {
|
||||
type: { value: BigDecimal, message: 'admin.currency.non_decimal_min_withdraw_amount' },
|
||||
values: { value: -> (p){ p >= 0 }, message: 'admin.currency.invalid_min_withdraw_amount' },
|
||||
default: 0.0,
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:min_withdraw_amount][:desc] }
|
||||
},
|
||||
withdraw_limit_24h: {
|
||||
type: { value: BigDecimal, message: 'admin.currency.non_decimal_withdraw_limit_24h' },
|
||||
values: { value: -> (p){ p >= 0 }, message: 'admin.currency.invalid_withdraw_limit_24h' },
|
||||
default: 0.0,
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:withdraw_limit_24h][:desc] }
|
||||
},
|
||||
withdraw_limit_72h: {
|
||||
type: { value: BigDecimal, message: 'admin.currency.non_decimal_withdraw_limit_72h' },
|
||||
values: { value: -> (p){ p >= 0 }, message: 'admin.currency.invalid_withdraw_limit_72h' },
|
||||
default: 0.0,
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:withdraw_limit_72h][:desc] }
|
||||
},
|
||||
options: {
|
||||
type: { value: JSON, message: 'admin.currency.non_json_options' },
|
||||
default: {},
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:options][:desc] }
|
||||
},
|
||||
visible: {
|
||||
type: { value: Boolean, message: 'admin.currency.non_boolean_visible' },
|
||||
default: true,
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:visible][:desc] }
|
||||
},
|
||||
deposit_enabled: {
|
||||
type: { value: Boolean, message: 'admin.currency.non_boolean_deposit_enabled' },
|
||||
default: true,
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:deposit_enabled][:desc] }
|
||||
},
|
||||
withdrawal_enabled: {
|
||||
type: { value: Boolean, message: 'admin.currency.non_boolean_withdrawal_enabled' },
|
||||
default: true,
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:withdrawal_enabled][:desc] }
|
||||
},
|
||||
precision: {
|
||||
type: { value: Integer, message: 'admin.currency.non_integer_base_precision' },
|
||||
default: 8,
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:precision][:desc] }
|
||||
},
|
||||
price: {
|
||||
type: { value: BigDecimal, message: 'admin.currency.non_decimal_price' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:price][:desc] }
|
||||
},
|
||||
icon_url: { desc: -> { API::V2::Admin::Entities::Currency.documentation[:icon_url][:desc] } },
|
||||
description: { desc: -> { API::V2::Admin::Entities::Currency.documentation[:description][:desc] } },
|
||||
homepage: { desc: -> { API::V2::Admin::Entities::Currency.documentation[:homepage][:desc] } },
|
||||
}
|
||||
|
||||
params :create_currency_params do
|
||||
OPTIONAL_CURRENCY_PARAMS.each do |key, params|
|
||||
optional key, params
|
||||
end
|
||||
end
|
||||
|
||||
params :update_currency_params do
|
||||
OPTIONAL_CURRENCY_PARAMS.each do |key, params|
|
||||
optional key, params.except(:default)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Get list of currencies',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::Currency
|
||||
params do
|
||||
use :currency_type
|
||||
use :pagination
|
||||
optional :ordering,
|
||||
values: { value: %w(asc desc), message: 'admin.pagination.invalid_ordering' },
|
||||
default: 'asc',
|
||||
desc: 'If set, returned values will be sorted in specific order, defaults to \'asc\'.'
|
||||
optional :order_by,
|
||||
default: 'position',
|
||||
desc: 'Name of the field, which result will be ordered by.'
|
||||
optional :deposit_enabled,
|
||||
type: { value: Boolean, message: 'admin.currency.non_boolean_deposit_enabled' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:deposit_enabled][:desc] }
|
||||
optional :withdrawal_enabled,
|
||||
type: { value: Boolean, message: 'admin.currency.non_boolean_withdrawal_enabled' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:withdrawal_enabled][:desc] }
|
||||
optional :visible,
|
||||
type: { value: Boolean, message: 'admin.currency.non_boolean_visible' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:visible][:desc] }
|
||||
end
|
||||
get '/currencies' do
|
||||
admin_authorize! :read, Currency
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(:type, :deposit_enabled, :withdrawal_enabled, :visible)
|
||||
.with_daterange
|
||||
.build
|
||||
|
||||
search = Currency.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
present paginate(search.result), with: API::V2::Admin::Entities::Currency
|
||||
end
|
||||
|
||||
desc 'Get a currency.' do
|
||||
success API::V2::Admin::Entities::Currency
|
||||
end
|
||||
params do
|
||||
requires :code,
|
||||
type: String,
|
||||
values: { value: -> { Currency.codes(bothcase: true) }, message: 'admin.currency.doesnt_exist'},
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:code][:desc] }
|
||||
end
|
||||
get '/currencies/:code', requirements: { code: /[\w\.\-]+/ } do
|
||||
admin_authorize! :read, Currency
|
||||
|
||||
present Currency.find(params[:code]), with: API::V2::Admin::Entities::Currency
|
||||
end
|
||||
|
||||
desc 'Create new currency.' do
|
||||
success API::V2::Admin::Entities::Currency
|
||||
end
|
||||
params do
|
||||
use :create_currency_params
|
||||
requires :code,
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:code][:desc] }
|
||||
optional :type,
|
||||
values: { value: ::Currency.types.map(&:to_s), message: 'admin.currency.invalid_type' },
|
||||
default: 'coin',
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:type][:desc] }
|
||||
optional :base_factor,
|
||||
type: { value: Integer, message: 'admin.currency.non_integer_base_factor' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:base_factor][:desc] }
|
||||
optional :position,
|
||||
type: { value: Integer, message: 'admin.currency.non_integer_position' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:position][:desc] }
|
||||
optional :subunits,
|
||||
type: { value: Integer, message: 'admin.currency.non_integer_subunits' },
|
||||
values: { value: (0..18), message: 'admin.currency.invalid_subunits' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:subunits][:desc] }
|
||||
given type: ->(val) { val == 'coin' } do
|
||||
optional :blockchain_key,
|
||||
values: { value: -> { ::Blockchain.pluck(:key) }, message: 'admin.currency.blockchain_key_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:blockchain_key][:desc] }
|
||||
optional :parent_id,
|
||||
values: { value: -> { Currency.coins_without_tokens.pluck(:id).map(&:to_s) }, message: 'admin.currency.parent_id_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:parent_id][:desc] }
|
||||
end
|
||||
mutually_exclusive :base_factor, :subunits, message: 'admin.currency.one_of_base_factor_subunits_fields'
|
||||
end
|
||||
post '/currencies/new' do
|
||||
admin_authorize! :create, Currency
|
||||
|
||||
currency = Currency.new(declared(params, include_missing: false))
|
||||
if currency.save
|
||||
present currency, with: API::V2::Admin::Entities::Currency
|
||||
status 201
|
||||
else
|
||||
body errors: currency.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Update currency.' do
|
||||
success API::V2::Admin::Entities::Currency
|
||||
end
|
||||
params do
|
||||
use :update_currency_params
|
||||
requires :code,
|
||||
values: { value: -> { ::Currency.codes }, message: 'admin.currency.doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:code][:desc] }
|
||||
optional :position,
|
||||
type: { value: Integer, message: 'admin.currency.non_integer_position' },
|
||||
values: { value: -> (p){ p >= ::Currency::TOP_POSITION }, message: 'admin.currency.invalid_position' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:position][:desc] }
|
||||
optional :blockchain_key,
|
||||
values: { value: -> { ::Blockchain.pluck(:key) }, message: 'admin.currency.blockchain_key_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:blockchain_key][:desc] }
|
||||
given code: -> (val) { val.in?(Currency.coins.pluck(:code).map(&:to_s)) } do
|
||||
optional :parent_id,
|
||||
values: { value: -> { Currency.coins_without_tokens.pluck(:id).map(&:to_s) }, message: 'admin.currency.parent_id_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:parent_id][:desc] }
|
||||
end
|
||||
end
|
||||
post '/currencies/update' do
|
||||
admin_authorize! :update, Currency, params.except(:code)
|
||||
|
||||
currency = Currency.find(params[:code])
|
||||
if currency.update(declared(params, include_missing: false))
|
||||
present currency, with: API::V2::Admin::Entities::Currency
|
||||
else
|
||||
body errors: currency.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
133
app/api/v2/admin/deposit_limits.rb
Normal file
133
app/api/v2/admin/deposit_limits.rb
Normal file
@@ -0,0 +1,133 @@
|
||||
# frozen_string_literal: true
|
||||
#
|
||||
# this file follow withdraw_limits.rb
|
||||
#
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class DepositLimits < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
# list of deposit limits
|
||||
desc 'Returns deposit limits table as paginated collection',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::DepositLimit
|
||||
params do
|
||||
optional :group,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:group][:desc] },
|
||||
coerce_with: ->(c) { c.strip.downcase }
|
||||
optional :kyc_level,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:kyc_level][:desc] }
|
||||
optional :kind,
|
||||
values: { value: ->(v) { (Array.wrap(v) - DepositLimit.kind.values).blank? }, message: 'limit.kind.invalid' },
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:kind][:desc] }
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/deposit_limits' do
|
||||
admin_authorize! :read, DepositLimit
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(:group, :kyc_level, :kind)
|
||||
.build
|
||||
|
||||
search = DepositLimit.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
present paginate(search.result), with: API::V2::Entities::DepositLimit
|
||||
end
|
||||
|
||||
# create deposit limit
|
||||
desc 'It creates deposit limits record',
|
||||
success: API::V2::Entities::DepositLimit
|
||||
params do
|
||||
requires :limit_24_hour,
|
||||
type: { value: BigDecimal, message: 'admin.deposit_limit.non_decimal_limit_24_hour' },
|
||||
values: { value: ->(p) { p && p >= 0 }, message: 'admin.deposit_limit.invalid_limit_24_hour' },
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:limit_24_hour][:desc] }
|
||||
requires :limit_1_month,
|
||||
type: { value: BigDecimal, message: 'admin.deposit_limit.non_decimal_limit_1_month' },
|
||||
values: { value: ->(p) { p && p >= 0 }, message: 'admin.deposit_limit.invalid_limit_1_month' },
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:limit_1_month][:desc] }
|
||||
requires :kind,
|
||||
values: { value: ->(v) { (Array.wrap(v) - DepositLimit.kind.values).blank? }, message: 'limit.kind.invalid' },
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:kind][:desc] }
|
||||
optional :group,
|
||||
type: String,
|
||||
default: ::DepositLimit::ANY,
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:group][:desc] }
|
||||
optional :kyc_level,
|
||||
type: String,
|
||||
default: ::DepositLimit::ANY,
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:kyc_level][:desc] }
|
||||
end
|
||||
post '/deposit_limits' do
|
||||
admin_authorize! :create, DepositLimit
|
||||
|
||||
deposit_limit = ::DepositLimit.new(declared(params))
|
||||
if deposit_limit.save
|
||||
present deposit_limit, with: API::V2::Entities::DepositLimit
|
||||
status 201
|
||||
else
|
||||
body errors: deposit_limit.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
# update deposit limit
|
||||
desc 'It updates deposit limits record',
|
||||
success: API::V2::Entities::DepositLimit
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.deposit_limit.non_integer_id' },
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:id][:desc] }
|
||||
optional :limit_24_hour,
|
||||
type: { value: BigDecimal, message: 'admin.deposit_limit.non_decimal_limit_24_hour' },
|
||||
values: { value: ->(p) { p && p >= 0 }, message: 'admin.deposit_limit.invalid_limit_24_hour' },
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:limit_24_hour][:desc] }
|
||||
optional :limit_1_month,
|
||||
type: { value: BigDecimal, message: 'admin.deposit_limit.non_decimal_limit_1_month' },
|
||||
values: { value: ->(p) { p && p >= 0 }, message: 'admin.deposit_limit.invalid_limit_1_month' },
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:limit_1_month][:desc] }
|
||||
optional :kind,
|
||||
values: { value: ->(v) { (Array.wrap(v) - DepositLimit.kind.values).blank? }, message: 'limit.kind.invalid' },
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:kind][:desc] }
|
||||
optional :kyc_level,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:kyc_level][:desc] }
|
||||
optional :group,
|
||||
type: String,
|
||||
coerce_with: ->(c) { c.strip.downcase },
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:group][:desc] }
|
||||
end
|
||||
put '/deposit_limits' do
|
||||
admin_authorize! :update, DepositLimit
|
||||
|
||||
deposit_limit = ::DepositLimit.find(params[:id])
|
||||
if deposit_limit.update(declared(params, include_missing: false))
|
||||
present deposit_limit, with: API::V2::Entities::DepositLimit
|
||||
else
|
||||
body errors: deposit_limit.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
# delete deposit limit
|
||||
desc 'It deletes deposit limits record',
|
||||
success: API::V2::Entities::DepositLimit
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.deposit_limit.non_integer_id' },
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:id][:desc] }
|
||||
end
|
||||
delete '/deposit_limits/:id' do
|
||||
admin_authorize! :delete, DepositLimit
|
||||
|
||||
present DepositLimit.destroy(params[:id]), with: API::V2::Entities::DepositLimit
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
180
app/api/v2/admin/deposits.rb
Normal file
180
app/api/v2/admin/deposits.rb
Normal file
@@ -0,0 +1,180 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Deposits < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
desc 'Get all deposits, result is paginated.',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::Deposit
|
||||
params do
|
||||
optional :state,
|
||||
values: { value: -> { ::Deposit.aasm.states.map(&:name).map(&:to_s) }, message: 'admin.deposit.invalid_state' },
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:state][:desc] }
|
||||
optional :id,
|
||||
type: Integer,
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:id][:desc] }
|
||||
optional :txid,
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:txid][:desc] }
|
||||
optional :address,
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:address][:desc] }
|
||||
optional :tid,
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:tid][:desc] }
|
||||
optional :email,
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:email][:desc] }
|
||||
use :uid
|
||||
use :currency
|
||||
use :currency_type
|
||||
use :date_picker
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/deposits' do
|
||||
admin_authorize! :read, Deposit
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(:id, :txid, :tid, :address)
|
||||
.translate(state: :aasm_state, uid: :member_uid, currency: :currency_id, email: :member_email)
|
||||
.with_daterange
|
||||
.merge(type_eq: params[:type].present? ? "Deposits::#{params[:type].capitalize}" : nil)
|
||||
.build
|
||||
|
||||
search = Deposit.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
present paginate(search.result), with: API::V2::Admin::Entities::Deposit
|
||||
end
|
||||
|
||||
desc 'Take an action on the deposit.',
|
||||
success: API::V2::Admin::Entities::Deposit
|
||||
params do
|
||||
requires :id,
|
||||
type: Integer,
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:id][:desc] }
|
||||
requires :action,
|
||||
type: String,
|
||||
values: { value: -> { ::Deposit.aasm.events.map(&:name).map(&:to_s) }, message: 'admin.deposit.invalid_action' },
|
||||
desc: "Valid actions are #{::Deposit.aasm.events.map(&:name)}."
|
||||
given action: ->(val) { val == 'process' } do
|
||||
optional :fees,
|
||||
type: Boolean,
|
||||
default: false,
|
||||
desc: 'Process deposit collection with collecting fees or not'
|
||||
end
|
||||
end
|
||||
post '/deposits/actions' do
|
||||
admin_authorize! :update, Deposit
|
||||
|
||||
deposit = Deposit.find(params[:id])
|
||||
|
||||
if deposit.public_send("may_#{params[:action]}?")
|
||||
deposit.public_send("#{params[:action]}!")
|
||||
present deposit, with: API::V2::Admin::Entities::Deposit
|
||||
else
|
||||
body errors: ["admin.depodit.cannot_#{params[:action]}"]
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Creates new fiat deposit .',
|
||||
success: API::V2::Admin::Entities::Deposit
|
||||
params do
|
||||
requires :uid,
|
||||
values: { value: -> (v) { Member.exists?(uid: v) }, message: 'admin.deposit.user_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:uid][:desc] }
|
||||
requires :currency,
|
||||
values: { value: -> { Currency.fiats.codes(bothcase: true) }, message: 'admin.deposit.currency_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:currency][:desc] }
|
||||
requires :amount,
|
||||
type: { value: BigDecimal, message: 'admin.deposit.non_decimal_amount' },
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:amount][:desc] }
|
||||
optional :tid,
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:tid][:desc] }
|
||||
end
|
||||
post '/deposits/new' do
|
||||
admin_authorize! :create, ::Deposits::Fiat
|
||||
|
||||
declared_params = declared(params, include_missing: false)
|
||||
member = Member.find_by(uid: declared_params[:uid])
|
||||
currency = Currency.find(declared_params[:currency])
|
||||
data = { member: member, currency: currency }.merge!(declared_params.slice(:amount, :tid))
|
||||
deposit = ::Deposits::Fiat.new(data)
|
||||
|
||||
if deposit.save
|
||||
present deposit, with: API::V2::Admin::Entities::Deposit
|
||||
status 201
|
||||
else
|
||||
body errors: deposit.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Creates new crypto refund',
|
||||
success: API::V2::Admin::Entities::Refund
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.deposit.non_integer_type' },
|
||||
desc: -> { 'Deposit id' }
|
||||
requires :address,
|
||||
desc: -> { API::V2::Admin::Entities::Refund.documentation[:address][:desc] }
|
||||
end
|
||||
post '/deposits/:id/refund' do
|
||||
admin_authorize! :wrrie, Deposit
|
||||
|
||||
deposit = Deposit.find(params[:id])
|
||||
|
||||
refund = ::Refund.new(deposit: deposit, address: params[:address])
|
||||
|
||||
if refund.save
|
||||
present refund, with: API::V2::Admin::Entities::Refund
|
||||
else
|
||||
body errors: refund.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Returns deposit address for account you want to deposit to by currency and uid.',
|
||||
success: API::V2::Admin::Entities::Deposit
|
||||
params do
|
||||
requires :uid,
|
||||
values: { value: -> (v) { Member.exists?(uid: v) }, message: 'admin.deposit.user_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:uid][:desc] }
|
||||
requires :currency,
|
||||
values: { value: -> { Currency.codes }, message: 'admin.deposit.currency_doesnt_exist' },
|
||||
as: :currency_id,
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:currency][:desc] }
|
||||
given :currency_id do
|
||||
optional :address_format,
|
||||
type: String,
|
||||
values: { value: -> { %w[legacy cash] }, message: 'admin.deposit.invalid_address_format' },
|
||||
validate_currency_address_format: { value: true, prefix: 'admin.deposit' },
|
||||
desc: 'Address format legacy/cash'
|
||||
end
|
||||
end
|
||||
post '/deposit_address' do
|
||||
admin_authorize! :create, PaymentAddress
|
||||
|
||||
member = Member.find_by!(uid: params[:uid])
|
||||
currency = Currency.find_by!(id: params[:currency_id])
|
||||
wallet = Wallet.deposit_wallet(currency.id)
|
||||
|
||||
unless wallet.present?
|
||||
error!({ errors: ['admin.deposit.wallet_not_found'] }, 422)
|
||||
end
|
||||
|
||||
if currency.deposit_enabled
|
||||
payment_address = member.payment_address(wallet.id)
|
||||
present payment_address, with: API::V2::Entities::PaymentAddress, address_format: params[:address_format]
|
||||
status 201
|
||||
else
|
||||
body errors: ["admin.deposit.deposit_disabled"]
|
||||
status 422
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
101
app/api/v2/admin/engines.rb
Normal file
101
app/api/v2/admin/engines.rb
Normal file
@@ -0,0 +1,101 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Engines < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
desc 'Get all engine, result is paginated.',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::Engine
|
||||
params do
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/engines' do
|
||||
admin_authorize! :read, ::Engine
|
||||
|
||||
result = ::Engine.order(params[:order_by] => params[:ordering])
|
||||
present paginate(result), with: API::V2::Admin::Entities::Engine
|
||||
end
|
||||
|
||||
desc 'Get engine.' do
|
||||
success API::V2::Admin::Entities::Engine
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: String,
|
||||
desc: -> { API::V2::Admin::Entities::Engine.documentation[:id][:desc] }
|
||||
end
|
||||
get '/engines/:id' do
|
||||
admin_authorize! :read, ::Engine
|
||||
|
||||
present ::Engine.find(params[:id]), with: API::V2::Admin::Entities::Engine
|
||||
end
|
||||
|
||||
desc 'Create new engine.' do
|
||||
success API::V2::Admin::Entities::Engine
|
||||
end
|
||||
params do
|
||||
requires :name,
|
||||
desc: -> { API::V2::Admin::Entities::Engine.documentation[:name][:desc] },
|
||||
values: { value: ->(v) { !v.in?(::Engine.pluck(:name)) }, message: 'admin.engine.duplicate_name' }
|
||||
requires :driver,
|
||||
desc: -> { API::V2::Admin::Entities::Engine.documentation[:driver][:desc] }
|
||||
optional :uid,
|
||||
desc: -> { API::V2::Admin::Entities::Engine.documentation[:uid][:desc] }
|
||||
optional :key,
|
||||
desc: -> { 'Credentials for remote engine' }
|
||||
optional :secret,
|
||||
desc: -> { 'Credentials for remote engine' }
|
||||
optional :data,
|
||||
desc: -> { 'Metadata for engine' }
|
||||
end
|
||||
post '/engines/new' do
|
||||
admin_authorize! :create, ::Engine
|
||||
|
||||
engine = ::Engine.new(declared(params))
|
||||
if engine.save
|
||||
present engine, with: API::V2::Admin::Entities::Engine
|
||||
status 201
|
||||
else
|
||||
body errors: engine.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Update engine' do
|
||||
success API::V2::Admin::Entities::Engine
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
desc: -> { API::V2::Admin::Entities::Engine.documentation[:id][:desc] }
|
||||
optional :name,
|
||||
desc: -> { API::V2::Admin::Entities::Engine.documentation[:name][:desc] }
|
||||
optional :driver,
|
||||
desc: -> { API::V2::Admin::Entities::Engine.documentation[:driver][:desc] }
|
||||
optional :key,
|
||||
desc: -> { 'Credentials for remote engine' }
|
||||
optional :secret,
|
||||
desc: -> { 'Credentials for remote engine' }
|
||||
optional :state,
|
||||
values: { value: ::Engine::STATES.values, message: 'admin.engine.invalid_state' },
|
||||
default: 1,
|
||||
desc: -> { API::V2::Admin::Entities::Engine.documentation[:state][:desc] }
|
||||
end
|
||||
post '/engines/update' do
|
||||
admin_authorize! :update, ::Engine
|
||||
|
||||
engine = ::Engine.find(params[:id])
|
||||
if engine.update(declared(params, include_missing: false))
|
||||
present engine, with: API::V2::Admin::Entities::Engine
|
||||
else
|
||||
body errors: engine.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
169
app/api/v2/admin/entities/adjustment.rb
Normal file
169
app/api/v2/admin/entities/adjustment.rb
Normal file
@@ -0,0 +1,169 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Adjustment < API::V2::Entities::Base
|
||||
expose(
|
||||
:id,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Unique adjustment identifier in database.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:reason,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Adjustment reason.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:description,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Adjustment description.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:category,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Adjustment category'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:amount,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Adjustment amount.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:validator_uid,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Unique adjustment validator identifier in database.'
|
||||
},
|
||||
if: ->(adjustment, _options) { adjustment.validator }
|
||||
) do |adjustment, _options|
|
||||
adjustment.validator.uid
|
||||
end
|
||||
|
||||
expose(
|
||||
:creator_uid,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Unique adjustment creator identifier in database.'
|
||||
},
|
||||
) do |adjustment, _options|
|
||||
adjustment.creator.uid
|
||||
end
|
||||
|
||||
expose(
|
||||
:currency_id,
|
||||
as: :currency,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Adjustment currency ID.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:asset,
|
||||
using: API::V2::Admin::Entities::Operation,
|
||||
if: ->(adjustment, _options) { adjustment.fetch_asset }
|
||||
) do |adjustment, _options|
|
||||
adjustment.fetch_asset
|
||||
end
|
||||
|
||||
expose(
|
||||
:liability,
|
||||
using: API::V2::Admin::Entities::Operation,
|
||||
if: ->(adjustment, _options) { adjustment.fetch_liability }
|
||||
) do |adjustment, _options|
|
||||
adjustment.fetch_liability
|
||||
end
|
||||
|
||||
expose(
|
||||
:revenue,
|
||||
using: API::V2::Admin::Entities::Operation,
|
||||
if: ->(adjustment, _options) { adjustment.fetch_revenue }
|
||||
) do |adjustment, _options|
|
||||
adjustment.fetch_revenue
|
||||
end
|
||||
|
||||
expose(
|
||||
:expense,
|
||||
using: API::V2::Admin::Entities::Operation,
|
||||
if: ->(adjustment, _options) { adjustment.fetch_expense }
|
||||
) do |adjustment, _options|
|
||||
adjustment.fetch_expense
|
||||
end
|
||||
|
||||
expose(
|
||||
:state,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Adjustment\'s state.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:asset_account_code,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Adjustment asset account code.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:receiving_account_code,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Adjustment receiving account code.'
|
||||
}
|
||||
) do |adjustment, _options|
|
||||
::Operations.split_account_number(account_number: adjustment.receiving_account_number)[:code]
|
||||
end
|
||||
|
||||
expose(
|
||||
:receiving_member_uid,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Adjustment receiving member uid.'
|
||||
},
|
||||
if: ->(adjustment, _options) { adjustment.fetch_liability.present? }
|
||||
) do |adjustment, _options|
|
||||
::Operations.split_account_number(account_number: adjustment.receiving_account_number)[:member_uid]
|
||||
end
|
||||
|
||||
expose(
|
||||
:created_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The datetime when operation was created.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:updated_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The datetime when operation was updated.'
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
20
app/api/v2/admin/entities/beneficiary.rb
Normal file
20
app/api/v2/admin/entities/beneficiary.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Beneficiary < API::V2::Entities::Beneficiary
|
||||
expose(
|
||||
:data,
|
||||
documentation: {
|
||||
desc: 'Bank Account details for fiat Beneficiary in JSON format.'\
|
||||
'For crypto it\'s blockchain address.',
|
||||
type: JSON
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
102
app/api/v2/admin/entities/blockchain.rb
Normal file
102
app/api/v2/admin/entities/blockchain.rb
Normal file
@@ -0,0 +1,102 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Blockchain < API::V2::Entities::Base
|
||||
expose(
|
||||
:id,
|
||||
documentation:{
|
||||
type: Integer,
|
||||
desc: 'Unique blockchain identifier in database.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:key,
|
||||
documentation:{
|
||||
type: String,
|
||||
desc: 'Unique key to identify blockchain.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:name,
|
||||
documentation:{
|
||||
type: String,
|
||||
desc: 'A name to identify blockchain.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:client,
|
||||
documentation:{
|
||||
type: String,
|
||||
desc: 'Integrated blockchain client.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:height,
|
||||
documentation:{
|
||||
type: Integer,
|
||||
desc: 'The number of blocks preceding a particular block on blockchain.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:explorer_address,
|
||||
documentation:{
|
||||
type: String,
|
||||
desc: 'Blockchain explorer address template.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:explorer_transaction,
|
||||
documentation:{
|
||||
type: String,
|
||||
desc: 'Blockchain explorer transaction template.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:min_confirmations,
|
||||
documentation:{
|
||||
type: Integer,
|
||||
desc: 'Minimum number of confirmations.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:status,
|
||||
documentation:{
|
||||
type: String,
|
||||
desc: 'Blockchain status (active/disabled).'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:created_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Blockchain created time in iso8601 format.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:updated_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Blockchain updated time in iso8601 format.'
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
123
app/api/v2/admin/entities/currency.rb
Normal file
123
app/api/v2/admin/entities/currency.rb
Normal file
@@ -0,0 +1,123 @@
|
||||
# enco ding: UTF-8
|
||||
# froz en_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Currency < API::V2::Entities::Currency
|
||||
unexpose(:id)
|
||||
|
||||
expose(
|
||||
:code,
|
||||
documentation: {
|
||||
desc: 'Unique currency code.',
|
||||
type: String
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:blockchain_key,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Associated blockchain key which will perform transactions synchronization for currency.'
|
||||
},
|
||||
if: -> (currency){ currency.coin? }
|
||||
)
|
||||
|
||||
expose(
|
||||
:parent_id,
|
||||
documentation: {
|
||||
desc: 'Parent currency id.',
|
||||
type: String
|
||||
},
|
||||
if: -> (currency){ currency.token? }
|
||||
)
|
||||
|
||||
expose(
|
||||
:min_collection_amount,
|
||||
documentation: {
|
||||
type: BigDecimal,
|
||||
desc: 'Minimal collection amount.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:position,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Currency position.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:visible,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Currency display status (true/false).'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:base_factor,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Currency base factor.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:subunits,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Fraction of the basic monetary unit.'
|
||||
}
|
||||
) { |currency| currency.subunits }
|
||||
|
||||
expose(
|
||||
:options,
|
||||
documentation: {
|
||||
type: JSON,
|
||||
desc: 'Currency options.'
|
||||
},
|
||||
if: -> (currency){ currency.coin? }
|
||||
)
|
||||
|
||||
expose(
|
||||
:precision,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Currency precision.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:price,
|
||||
documentation: {
|
||||
type: BigDecimal,
|
||||
desc: 'Currency price.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:created_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Currency created time in iso8601 format.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:updated_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Currency updated time in iso8601 format.'
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
108
app/api/v2/admin/entities/deposit.rb
Normal file
108
app/api/v2/admin/entities/deposit.rb
Normal file
@@ -0,0 +1,108 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Deposit < API::V2::Entities::Deposit
|
||||
expose(
|
||||
:member_id,
|
||||
as: :member,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The member id.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:uid,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Deposit member uid.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:email,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The deposit member email.'
|
||||
}
|
||||
) { |d| d.member.email }
|
||||
|
||||
expose(
|
||||
:address,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Deposit blockchain address.'
|
||||
},
|
||||
if: ->(deposit) { deposit.currency.coin? }
|
||||
)
|
||||
|
||||
expose(
|
||||
:txout,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Deposit blockchain transaction output.'
|
||||
},
|
||||
if: ->(deposit) { deposit.currency.coin? }
|
||||
)
|
||||
|
||||
expose(
|
||||
:block_number,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Deposit blockchain block number.'
|
||||
},
|
||||
if: ->(deposit) { deposit.currency.coin? }
|
||||
)
|
||||
|
||||
expose(
|
||||
:type,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Deposit type (fiat or coin).'
|
||||
}
|
||||
) { |d| d.currency.fiat? ? :fiat : :coin }
|
||||
|
||||
expose(
|
||||
:tid,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Deposit tid.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:spread,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Deposit collection spread.'
|
||||
},
|
||||
if: -> (deposit) { !deposit.spread.empty? }
|
||||
)
|
||||
|
||||
expose(
|
||||
:updated_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The datetime when deposit was updated.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:completed_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The datetime when deposit was completed.'
|
||||
},
|
||||
if: ->(deposit) { deposit.completed? }
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
51
app/api/v2/admin/entities/engine.rb
Normal file
51
app/api/v2/admin/entities/engine.rb
Normal file
@@ -0,0 +1,51 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Engine < API::V2::Entities::Base
|
||||
expose(
|
||||
:id,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Engine uniq id'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:name,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Engine name'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:driver,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Engine driver'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:uid,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Owner of a engine'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:state,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Engine state'
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
20
app/api/v2/admin/entities/internal_transfer.rb
Normal file
20
app/api/v2/admin/entities/internal_transfer.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class InternalTransfer < API::V2::Entities::InternalTransfer
|
||||
expose(
|
||||
:id,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Internal transfer uniq id'
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
54
app/api/v2/admin/entities/market.rb
Normal file
54
app/api/v2/admin/entities/market.rb
Normal file
@@ -0,0 +1,54 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Market < API::V2::Entities::Market
|
||||
expose(
|
||||
:engine_id,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Engine id for this market.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:position,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Market position.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:data,
|
||||
documentation: {
|
||||
type: JSON,
|
||||
desc: 'Market additional data.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:created_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Market created time in iso8601 format.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:updated_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Market updated time in iso8601 format.'
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
104
app/api/v2/admin/entities/member.rb
Normal file
104
app/api/v2/admin/entities/member.rb
Normal file
@@ -0,0 +1,104 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Member < API::V2::Entities::Member
|
||||
expose(
|
||||
:id,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Unique member identifier in database.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:level,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Member\'s level.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:role,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Member\'s role.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:group,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Member\'s group.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:state,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Member\'s state.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:created_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Member created time in iso8601 format.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:updated_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Member updated time in iso8601 format.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:beneficiaries,
|
||||
using: API::V2::Admin::Entities::Beneficiary,
|
||||
documentation: {
|
||||
type: 'API::V2::Admin::Entities::Beneficiary',
|
||||
is_array: true,
|
||||
desc: 'Member Beneficiary.'
|
||||
}
|
||||
) do |m|
|
||||
m.beneficiaries
|
||||
end
|
||||
|
||||
expose(
|
||||
:accounts,
|
||||
using: API::V2::Entities::Account,
|
||||
documentation: {
|
||||
type: 'API::V2::Entities::Account',
|
||||
is_array: true,
|
||||
desc: 'Member accounts.'
|
||||
}
|
||||
) do |m|
|
||||
m.accounts.includes(:currency)
|
||||
end
|
||||
|
||||
expose(
|
||||
:payment_addresses,
|
||||
as: :deposit_addresses,
|
||||
using: API::V2::Entities::PaymentAddress,
|
||||
documentation: {
|
||||
type: 'API::V2::Entities::PaymentAddress',
|
||||
is_array: true,
|
||||
desc: 'Member deposits addresses'
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
94
app/api/v2/admin/entities/operation.rb
Normal file
94
app/api/v2/admin/entities/operation.rb
Normal file
@@ -0,0 +1,94 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Operation < API::V2::Entities::Base
|
||||
expose(
|
||||
:id,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Unique operation identifier in database.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:code,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The Account code which this operation related to.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:currency_id,
|
||||
as: :currency,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Operation currency ID.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:credit,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Operation credit amount.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:debit,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Operation debit amount.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:uid,
|
||||
if: ->(operation) { operation.try(:member).try(:uid) },
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The shared user ID.'
|
||||
}) { |operation| operation.try(:member).try(:uid) }
|
||||
|
||||
expose(
|
||||
:account_kind,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Operation\'s account kind (locked or main).'
|
||||
}
|
||||
) { |operation| operation.account.kind }
|
||||
|
||||
expose(
|
||||
:reference_id,
|
||||
as: :rid,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The id of operation reference.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:reference_type,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The type of operations.'
|
||||
}) { |operation| operation.reference_type.downcase if operation.reference_type.present? }
|
||||
|
||||
expose(
|
||||
:created_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The datetime when operation was created.'
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
30
app/api/v2/admin/entities/order.rb
Normal file
30
app/api/v2/admin/entities/order.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Order < API::V2::Entities::Order
|
||||
unexpose(:trades)
|
||||
|
||||
expose(
|
||||
:email,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The shared user email.'
|
||||
}
|
||||
) { |w| w.member.email }
|
||||
|
||||
expose(
|
||||
:uid,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The shared user ID.'
|
||||
}
|
||||
) { |w| w.member.uid }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
33
app/api/v2/admin/entities/refund.rb
Normal file
33
app/api/v2/admin/entities/refund.rb
Normal file
@@ -0,0 +1,33 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Refund < API::V2::Entities::Base
|
||||
expose(
|
||||
:id,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'The refund id'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:address,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Refund address'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:deposit,
|
||||
using: API::V2::Admin::Entities::Deposit
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
112
app/api/v2/admin/entities/trade.rb
Normal file
112
app/api/v2/admin/entities/trade.rb
Normal file
@@ -0,0 +1,112 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Trade < API::V2::Entities::Trade
|
||||
unexpose(:side)
|
||||
unexpose(:order_id)
|
||||
unexpose(:fee_currency)
|
||||
unexpose(:fee)
|
||||
unexpose(:fee_amount)
|
||||
|
||||
expose(
|
||||
:maker_order_email,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Trade maker member email.'
|
||||
}
|
||||
) { |trade| trade.maker.email }
|
||||
|
||||
expose(
|
||||
:maker_uid,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Trade maker member uid.'
|
||||
}
|
||||
) { |trade| trade.maker.uid }
|
||||
|
||||
expose(
|
||||
:maker_fee,
|
||||
documentation: {
|
||||
type: BigDecimal,
|
||||
desc: 'Trade maker fee percentage.',
|
||||
},
|
||||
if: ->(object, options) { options[:extended] }
|
||||
) { |trade| trade.maker_order.maker_fee }
|
||||
|
||||
expose(
|
||||
:maker_fee_amount,
|
||||
documentation: {
|
||||
type: BigDecimal,
|
||||
desc: 'Trade maker fee amount.',
|
||||
}
|
||||
) { |trade| fee_amount(trade, trade.maker_order) }
|
||||
|
||||
expose(
|
||||
:maker_fee_currency,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Trade maker fee currency code.'
|
||||
}
|
||||
) { |trade| fee_currency(trade.maker_order) }
|
||||
|
||||
expose(
|
||||
:maker_order,
|
||||
using: API::V2::Admin::Entities::Order,
|
||||
if: ->(object, options) { options[:extended] }
|
||||
)
|
||||
|
||||
expose(
|
||||
:taker_order_email,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Trade taker member email.'
|
||||
}
|
||||
) { |trade| trade.taker.email }
|
||||
|
||||
expose(
|
||||
:taker_uid,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Trade taker member uid.'
|
||||
}
|
||||
) { |trade| trade.taker.uid }
|
||||
|
||||
expose(
|
||||
:taker_fee_currency,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Trade taker fee currency code.'
|
||||
}
|
||||
) { |trade| fee_currency(trade.taker_order) }
|
||||
|
||||
expose(
|
||||
:taker_fee,
|
||||
documentation: {
|
||||
type: BigDecimal,
|
||||
desc: 'Trade taker fee percentage.',
|
||||
},
|
||||
if: ->(object, options) { options[:extended] }
|
||||
) { |trade| trade.taker_order.taker_fee }
|
||||
|
||||
expose(
|
||||
:taker_fee_amount,
|
||||
documentation: {
|
||||
type: BigDecimal,
|
||||
desc: 'Trade taker fee amount.',
|
||||
}
|
||||
) { |trade| fee_amount(trade, trade.taker_order) }
|
||||
|
||||
expose(
|
||||
:taker_order,
|
||||
using: API::V2::Admin::Entities::Order,
|
||||
if: ->(object, options) { options[:extended] }
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
112
app/api/v2/admin/entities/wallet.rb
Normal file
112
app/api/v2/admin/entities/wallet.rb
Normal file
@@ -0,0 +1,112 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Wallet < API::V2::Entities::Base
|
||||
expose(
|
||||
:id,
|
||||
documentation:{
|
||||
type: Integer,
|
||||
desc: 'Unique wallet identifier in database.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:name,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Wallet name.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:kind,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: "Kind of wallet 'deposit','fee','hot','warm' or 'cold'."
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:currency_ids,
|
||||
as: :currencies,
|
||||
documentation: {
|
||||
is_array: true,
|
||||
desc: 'Wallet currency code.',
|
||||
example: -> { ::Currency.visible.codes }
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:address,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Wallet address.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:gateway,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Wallet gateway.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:max_balance,
|
||||
documentation: {
|
||||
type: BigDecimal,
|
||||
desc: 'Wallet max balance.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:balance,
|
||||
documentation: {
|
||||
type: BigDecimal,
|
||||
desc: 'Wallet balance'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:blockchain_key,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Wallet blockchain key.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:status,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Wallet status (active/disabled).'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:created_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Wallet created time in iso8601 format.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:updated_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Wallet updated time in iso8601 format.'
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
69
app/api/v2/admin/entities/whitelisted_smart_contract.rb
Normal file
69
app/api/v2/admin/entities/whitelisted_smart_contract.rb
Normal file
@@ -0,0 +1,69 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class WhitelistedSmartContract < API::V2::Entities::Base
|
||||
expose(
|
||||
:id,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'Unique whitelisted smart contract identifier in database.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:address,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Whitelisted smart contract address.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:description,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Whitelisted smart contract description.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:blockchain_key,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Whitelisted smart contract blockchain key.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:state,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Whitelisted smart contract status (active/disabled).'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:created_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Whitelisted smart contract created time in iso8601 format.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:updated_at,
|
||||
format_with: :iso8601,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Whitelisted smart contract updated time in iso8601 format.'
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
87
app/api/v2/admin/entities/withdraw.rb
Normal file
87
app/api/v2/admin/entities/withdraw.rb
Normal file
@@ -0,0 +1,87 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Entities
|
||||
class Withdraw < API::V2::Entities::Withdraw
|
||||
expose(
|
||||
:member_id,
|
||||
as: :member,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The member id.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:beneficiary,
|
||||
using: API::V2::Entities::Beneficiary,
|
||||
if: ->(withdraw, options) do
|
||||
options[:with_beneficiary] && withdraw.beneficiary.present?
|
||||
end
|
||||
)
|
||||
|
||||
expose(
|
||||
:uid,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The withdrawal member uid.'
|
||||
}
|
||||
) { |w| w.member.uid }
|
||||
|
||||
expose(
|
||||
:email,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The withdrawal member email.'
|
||||
}
|
||||
) { |w| w.member.email }
|
||||
|
||||
expose(
|
||||
:account,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'The account code.'
|
||||
}
|
||||
) { |w| w.account.id }
|
||||
|
||||
expose(
|
||||
:block_number,
|
||||
documentation: {
|
||||
type: Integer,
|
||||
desc: 'The withdrawal block_number.'
|
||||
},
|
||||
if: ->(w) { w.currency.coin? }
|
||||
)
|
||||
|
||||
expose(
|
||||
:tid,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Withdraw tid.'
|
||||
}
|
||||
)
|
||||
|
||||
expose(
|
||||
:error,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Withdraw error.'
|
||||
},
|
||||
unless: ->(w) { w.succeed? }
|
||||
)
|
||||
|
||||
expose(
|
||||
:metadata,
|
||||
documentation: {
|
||||
type: String,
|
||||
desc: 'Optional metadata to be applied to the transaction.'
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
115
app/api/v2/admin/helpers.rb
Normal file
115
app/api/v2/admin/helpers.rb
Normal file
@@ -0,0 +1,115 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
module Helpers
|
||||
extend ::Grape::API::Helpers
|
||||
|
||||
class RansackBuilder
|
||||
# RansackBuilder creates a hash in a format ransack accepts
|
||||
# eq(:column) generetes a pair column_eq: params[:column]
|
||||
# translate(:column1 => :column2) generates a pair column2_eq: params[:column1]
|
||||
# merge allows to append additional selectors in
|
||||
# build returns prepared hash
|
||||
|
||||
attr_reader :build
|
||||
|
||||
def initialize(params)
|
||||
@params = params
|
||||
@build = {}
|
||||
end
|
||||
|
||||
def merge(opt)
|
||||
@build.merge!(opt)
|
||||
self
|
||||
end
|
||||
|
||||
def with_daterange
|
||||
@build.merge!("#{@params[:range]}_at_gteq" => @params[:from])
|
||||
@build.merge!("#{@params[:range]}_at_lteq" => @params[:to])
|
||||
self
|
||||
end
|
||||
|
||||
def translate(opt)
|
||||
opt.each { |k, v| @build.merge!("#{v}_eq" => @params[k]) }
|
||||
self
|
||||
end
|
||||
|
||||
def translate_in(opt)
|
||||
opt.each { |k, v| @build.merge!("#{v}_in" => @params[k]) }
|
||||
self
|
||||
end
|
||||
|
||||
def in(*keys)
|
||||
keys.each { |k| @build.merge!("#{k}_in" => @params[k]) }
|
||||
self
|
||||
end
|
||||
|
||||
def eq(*keys)
|
||||
keys.each { |k| @build.merge!("#{k}_eq" => @params[k]) }
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
params :currency_type do
|
||||
optional :type,
|
||||
type: String,
|
||||
values: { value: ::Currency.types.map(&:to_s), message: 'admin.currency.invalid_type' },
|
||||
desc: -> { API::V2::Admin::Entities::Currency.documentation[:type][:desc] }
|
||||
end
|
||||
|
||||
params :currency do
|
||||
optional :currency,
|
||||
values: { value: -> { Currency.codes(bothcase: true) }, message: 'admin.currency.doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Deposit.documentation[:currency][:desc] }
|
||||
end
|
||||
|
||||
params :uid do
|
||||
optional :uid,
|
||||
values: { value: -> (v) { Member.exists?(uid: v) }, message: 'admin.user.doesnt_exist' },
|
||||
desc: -> { API::V2::Entities::Member.documentation[:uid][:desc] }
|
||||
end
|
||||
|
||||
params :pagination do
|
||||
optional :limit,
|
||||
type: { value: Integer, message: 'admin.pagination.non_integer_limit' },
|
||||
values: { value: 1..1000, message: 'admin.pagination.invalid_limit' },
|
||||
default: 100,
|
||||
desc: 'Limit the number of returned paginations. Defaults to 100.'
|
||||
optional :page,
|
||||
type: { value: Integer, message: 'admin.pagination.non_integer_page' },
|
||||
allow_blank: false,
|
||||
default: 1,
|
||||
desc: 'Specify the page of paginated results.'
|
||||
end
|
||||
|
||||
params :ordering do
|
||||
optional :ordering,
|
||||
values: { value: %w(asc desc), message: 'admin.pagination.invalid_ordering' },
|
||||
default: 'asc',
|
||||
desc: 'If set, returned values will be sorted in specific order, defaults to \'asc\'.'
|
||||
optional :order_by,
|
||||
default: 'id',
|
||||
desc: 'Name of the field, which result will be ordered by.'
|
||||
end
|
||||
|
||||
params :date_picker do
|
||||
optional :range,
|
||||
default: 'created',
|
||||
values: { value: -> { %w[created updated completed] } },
|
||||
desc: 'Date range picker, defaults to \'created\'.'
|
||||
optional :from,
|
||||
type: { value: Time, message: 'admin.filter.range_from_invalid' },
|
||||
desc: 'An integer represents the seconds elapsed since Unix epoch.'\
|
||||
'If set, only entities FROM the time will be retrieved.'
|
||||
optional :to,
|
||||
type: { value: Time, message: 'admin.filter.range_to_invalid' },
|
||||
desc: 'An integer represents the seconds elapsed since Unix epoch.'\
|
||||
'If set, only entities BEFORE the time will be retrieved.'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
51
app/api/v2/admin/internal_transfers.rb
Normal file
51
app/api/v2/admin/internal_transfers.rb
Normal file
@@ -0,0 +1,51 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class InternalTransfers < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
desc 'Get all internal transfers.',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::InternalTransfer
|
||||
params do
|
||||
optional :sender,
|
||||
values: { value: -> (v) { Member.where('uid = ? OR username = ?', v, v).present? }, message: 'admin.receiver.doesnt_exist' },
|
||||
desc: 'Sender uid or username.'
|
||||
optional :receiver,
|
||||
values: { value: -> (v) { Member.where('uid = ? OR username = ?', v, v).present? }, message: 'admin.receiver.doesnt_exist' },
|
||||
desc: 'Receiver uid or username.'
|
||||
use :currency
|
||||
use :pagination
|
||||
use :date_picker
|
||||
use :ordering
|
||||
end
|
||||
get '/internal_transfers' do
|
||||
admin_authorize! :read, InternalTransfer
|
||||
|
||||
if params[:sender].present?
|
||||
sender = Member.find_by('uid = ? OR username = ?', params[:sender], params[:sender])
|
||||
params.except!(:sender).merge!(sender_id: sender.id) if sender.present?
|
||||
end
|
||||
|
||||
if params[:receiver].present?
|
||||
receiver = Member.find_by('uid = ? OR username = ?', params[:receiver], params[:receiver])
|
||||
params.except!(:receiver).merge!(receiver_id: receiver.id) if receiver.present?
|
||||
end
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(:sender_id, :receiver_id)
|
||||
.translate_in(currency: :currency_id)
|
||||
.with_daterange
|
||||
.build
|
||||
|
||||
search = ::InternalTransfer.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
present paginate(search.result), with: API::V2::Admin::Entities::InternalTransfer
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
171
app/api/v2/admin/markets.rb
Normal file
171
app/api/v2/admin/markets.rb
Normal file
@@ -0,0 +1,171 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Markets < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
helpers do
|
||||
# Collection of shared params, used to
|
||||
# generate required/optional Grape params.
|
||||
OPTIONAL_MARKET_PARAMS ||= {
|
||||
amount_precision: {
|
||||
type: { value: Integer, message: 'admin.market.non_integer_amount_precision' },
|
||||
values: { value: -> (p){ p && p >= 0 }, message: 'admin.market.invalid_amount_precision' },
|
||||
default: 4,
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:amount_precision][:desc] }
|
||||
},
|
||||
price_precision: {
|
||||
type: { value: Integer, message: 'admin.market.non_integer_price_precision' },
|
||||
values: { value: -> (p){ p && p >= 0 }, message: 'admin.market.invalid_price_precision' },
|
||||
default: 4,
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:price_precision][:desc] }
|
||||
},
|
||||
max_price: {
|
||||
type: { value: BigDecimal, message: 'admin.market.non_decimal_max_price' },
|
||||
values: { value: -> (p){ p >= 0 }, message: 'admin.market.invalid_max_price' },
|
||||
default: 0.0,
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:max_price][:desc] }
|
||||
},
|
||||
data: {
|
||||
type: { value: JSON, message: 'admin.market.invalid_data' },
|
||||
default: {},
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:data][:desc] }
|
||||
},
|
||||
state: {
|
||||
values: { value: ::Market::STATES, message: 'admin.market.invalid_state' },
|
||||
default: 'enabled',
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:state][:desc] }
|
||||
},
|
||||
}
|
||||
|
||||
params :create_market_params do
|
||||
OPTIONAL_MARKET_PARAMS.each do |key, params|
|
||||
optional key, params
|
||||
end
|
||||
end
|
||||
|
||||
params :update_market_params do
|
||||
OPTIONAL_MARKET_PARAMS.each do |key, params|
|
||||
optional key, params.except(:default)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Get all markets, result is paginated.',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::Market
|
||||
params do
|
||||
use :pagination
|
||||
optional :ordering,
|
||||
values: { value: %w(asc desc), message: 'admin.pagination.invalid_ordering' },
|
||||
default: 'asc',
|
||||
desc: 'If set, returned values will be sorted in specific order, defaults to \'asc\'.'
|
||||
optional :order_by,
|
||||
default: 'position',
|
||||
desc: 'Name of the field, which result will be ordered by.'
|
||||
end
|
||||
get '/markets' do
|
||||
admin_authorize! :read, ::Market
|
||||
|
||||
result = ::Market.order(params[:order_by] => params[:ordering])
|
||||
present paginate(result), with: API::V2::Admin::Entities::Market
|
||||
end
|
||||
|
||||
desc 'Get market.' do
|
||||
success API::V2::Admin::Entities::Market
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: String,
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:id][:desc] }
|
||||
end
|
||||
get '/markets/:id', requirements: { id: /[\w\.\-]+/ } do
|
||||
admin_authorize! :read, ::Market
|
||||
|
||||
present ::Market.find(params[:id]), with: API::V2::Admin::Entities::Market
|
||||
end
|
||||
|
||||
desc 'Create new market.' do
|
||||
success API::V2::Admin::Entities::Market
|
||||
end
|
||||
params do
|
||||
use :create_market_params
|
||||
requires :base_currency,
|
||||
values: { value: -> { ::Currency.ids }, message: 'admin.market.currency_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:base_unit][:desc] }
|
||||
requires :quote_currency,
|
||||
values: { value: -> { ::Currency.ids }, message: 'admin.market.currency_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:quote_unit][:desc] }
|
||||
requires :min_price,
|
||||
type: { value: BigDecimal, message: 'admin.market.non_decimal_min_price' },
|
||||
values: { value: -> (p){ p && p >= 0 }, message: 'admin.market.invalid_min_price' },
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:min_price][:desc] }
|
||||
requires :min_amount,
|
||||
type: { value: BigDecimal, message: 'admin.market.non_decimal_min_amount' },
|
||||
values: { value: -> (p){ p && p >= 0 }, message: 'admin.market.invalid_min_amount' },
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:min_amount][:desc] }
|
||||
optional :engine_id,
|
||||
type: { value: Integer, message: 'admin.market.non_integer_engine_id' },
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:engine_id][:desc] }
|
||||
optional :position,
|
||||
type: { value: Integer, message: 'admin.market.non_integer_position' },
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:position][:desc] }
|
||||
optional :engine_name,
|
||||
values: { value: -> { ::Engine.pluck(:name) }, message: 'admin.market.engine_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Engine.documentation[:name][:desc] }
|
||||
exactly_one_of :engine_id, :engine_name, message: 'admin.market.one_of_engine_id_engine_name_fields'
|
||||
end
|
||||
post '/markets/new' do
|
||||
admin_authorize! :create, ::Market
|
||||
|
||||
market = ::Market.new(declared(params, include_missing: false))
|
||||
if market.save
|
||||
present market, with: API::V2::Admin::Entities::Market
|
||||
status 201
|
||||
else
|
||||
body errors: market.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Update market.' do
|
||||
success API::V2::Admin::Entities::Market
|
||||
end
|
||||
params do
|
||||
use :update_market_params
|
||||
requires :id,
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:id][:desc] }
|
||||
optional :engine_id,
|
||||
type: { value: Integer, message: 'admin.market.non_integer_engine_id' },
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:engine_id][:desc] }
|
||||
optional :position,
|
||||
type: { value: Integer, message: 'admin.market.non_integer_position' },
|
||||
values: { value: -> (p){ p >= ::Market::TOP_POSITION }, message: 'admin.market.invalid_position' },
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:position][:desc] }
|
||||
optional :min_price,
|
||||
type: { value: BigDecimal, message: 'admin.market.non_decimal_min_price' },
|
||||
values: { value: -> (p){ p >= 0 }, message: 'admin.market.invalid_min_price' },
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:min_price][:desc] }
|
||||
optional :min_amount,
|
||||
type: { value: BigDecimal, message: 'admin.market.non_decimal_min_amount' },
|
||||
values: { value: -> (p){ p >= 0 }, message: 'admin.market.invalid_min_amount' },
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:min_amount][:desc] }
|
||||
|
||||
end
|
||||
post '/markets/update' do
|
||||
admin_authorize! :update, ::Market
|
||||
|
||||
market = ::Market.find(params[:id])
|
||||
if market.update(declared(params, include_missing: false))
|
||||
present market, with: API::V2::Admin::Entities::Market
|
||||
else
|
||||
body errors: market.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
90
app/api/v2/admin/members.rb
Normal file
90
app/api/v2/admin/members.rb
Normal file
@@ -0,0 +1,90 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Members < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
desc 'Get all members, result is paginated.',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::Member
|
||||
params do
|
||||
optional :state,
|
||||
desc: 'Filter order by state.'
|
||||
optional :role,
|
||||
values: { value: -> { ::Ability.roles }, message: 'admin.member.invalid_role' }
|
||||
optional :group,
|
||||
values: { value: -> { ::Member.groups }, message: 'admin.member.invalid_group' }
|
||||
optional :email,
|
||||
desc: -> { API::V2::Entities::Member.documentation[:email][:desc] }
|
||||
use :uid
|
||||
use :date_picker
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/members' do
|
||||
admin_authorize! :read, Member
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(:uid, :email, :state, :role, :group)
|
||||
.with_daterange
|
||||
.build
|
||||
|
||||
search = Member.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
present paginate(search.result), with: API::V2::Admin::Entities::Member
|
||||
end
|
||||
|
||||
desc 'Get available members groups.',
|
||||
is_array: true
|
||||
get '/members/groups' do
|
||||
admin_authorize! :read, Member
|
||||
|
||||
Member.groups
|
||||
end
|
||||
|
||||
desc 'Get a member.' do
|
||||
success API::V2::Admin::Entities::Member
|
||||
end
|
||||
params do
|
||||
requires :uid,
|
||||
type: String,
|
||||
desc: 'The shared user ID.'
|
||||
end
|
||||
get '/members/:uid' do
|
||||
admin_authorize! :read, Member
|
||||
|
||||
present Member.find_by!(uid: params[:uid]), with: API::V2::Admin::Entities::Member
|
||||
end
|
||||
|
||||
desc 'Set user group.' do
|
||||
success API::V2::Admin::Entities::Member
|
||||
end
|
||||
params do
|
||||
requires :uid,
|
||||
type: String,
|
||||
desc: 'The shared user ID.'
|
||||
requires :group,
|
||||
type: String,
|
||||
coerce_with: ->(v) { v.strip.downcase },
|
||||
desc: 'User gruop'
|
||||
end
|
||||
put '/members/:uid' do
|
||||
admin_authorize! :update, Member
|
||||
declared_params = declared(params)
|
||||
|
||||
member = Member.find_by!(uid: declared_params[:uid])
|
||||
if member.update(group: declared_params[:group])
|
||||
present member, with: API::V2::Admin::Entities::Member
|
||||
status 201
|
||||
else
|
||||
body errors: member.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
67
app/api/v2/admin/mount.rb
Normal file
67
app/api/v2/admin/mount.rb
Normal file
@@ -0,0 +1,67 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Mount < Grape::API
|
||||
PREFIX = '/admin'
|
||||
|
||||
before { authenticate! unless request.path == '/api/v2/admin/swagger' }
|
||||
|
||||
formatter :csv, CSVFormatter
|
||||
|
||||
mount Admin::Orders
|
||||
mount Admin::Blockchains
|
||||
mount Admin::Currencies
|
||||
mount Admin::Markets
|
||||
mount Admin::Wallets
|
||||
mount Admin::Deposits
|
||||
mount Admin::Withdraws
|
||||
mount Admin::Trades
|
||||
mount Admin::Operations
|
||||
mount Admin::Members
|
||||
mount Admin::TradingFees
|
||||
mount Admin::Adjustments
|
||||
mount Admin::Engines
|
||||
mount Admin::Beneficiaries
|
||||
mount Admin::Abilities
|
||||
mount Admin::WithdrawLimits
|
||||
mount Admin::DepositLimits
|
||||
mount Admin::Airdrops
|
||||
mount Admin::InternalTransfers
|
||||
mount Admin::WhitelistedSmartContracts
|
||||
|
||||
# The documentation is accessible at http://localhost:3000/swagger?url=/api/v2/admin/swagger
|
||||
# Add swagger documentation for Peatio Admin API
|
||||
add_swagger_documentation base_path: File.join(API::Mount::PREFIX, API::V2::Mount::API_VERSION, PREFIX, 'peatio'),
|
||||
add_base_path: true,
|
||||
mount_path: '/swagger',
|
||||
api_version: API::V2::Mount::API_VERSION,
|
||||
doc_version: Peatio::Application::VERSION,
|
||||
info: {
|
||||
title: "Peatio Admin API #{API::V2::Mount::API_VERSION}",
|
||||
description: 'Admin API high privileged API with RBAC.',
|
||||
contact_name: 'openware.com',
|
||||
contact_email: 'hello@openware.com',
|
||||
contact_url: 'https://www.openware.com',
|
||||
licence: 'MIT',
|
||||
license_url: 'https://github.com/openware/peatio/blob/master/LICENSE.md'
|
||||
},
|
||||
models: [
|
||||
API::V2::Admin::Entities::Blockchain,
|
||||
API::V2::Admin::Entities::Currency,
|
||||
API::V2::Admin::Entities::Deposit,
|
||||
API::V2::Admin::Entities::Market,
|
||||
API::V2::Admin::Entities::Member,
|
||||
API::V2::Admin::Entities::Operation,
|
||||
API::V2::Admin::Entities::Order,
|
||||
API::V2::Admin::Entities::Trade,
|
||||
API::V2::Admin::Entities::Wallet,
|
||||
API::V2::Admin::Entities::Withdraw,
|
||||
API::V2::Admin::Entities::InternalTransfer,
|
||||
API::V2::Admin::Entities::WhitelistedSmartContract
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
84
app/api/v2/admin/operations.rb
Normal file
84
app/api/v2/admin/operations.rb
Normal file
@@ -0,0 +1,84 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Operations < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
helpers do
|
||||
params :get_operations_params do
|
||||
optional :reference_type,
|
||||
desc: 'The reference type for which operation was created.'
|
||||
optional :rid,
|
||||
type: Integer,
|
||||
desc: 'The unique id of operation\'s reference, for which operation was created.'
|
||||
optional :code,
|
||||
type: Integer,
|
||||
desc: 'Opeartion\'s code.'
|
||||
use :currency
|
||||
use :date_picker
|
||||
end
|
||||
|
||||
def ransack_params
|
||||
Helpers::RansackBuilder.new(params)
|
||||
.eq(:code, :reference_type)
|
||||
.translate(currency: :currency_id, rid: :reference_id)
|
||||
.with_daterange
|
||||
.build
|
||||
end
|
||||
end
|
||||
|
||||
# GET: api/v2/admin/assets
|
||||
# GET: api/v2/admin/expenses
|
||||
# GET: api/v2/admin/revenues
|
||||
::Operations::Account::PLATFORM_TYPES.each do |op_type|
|
||||
op_type_plural = op_type.to_s.pluralize
|
||||
|
||||
desc "Returns #{op_type_plural} as a paginated collection." do
|
||||
success API::V2::Admin::Entities::Operation
|
||||
end
|
||||
params do
|
||||
use :get_operations_params
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get op_type_plural do
|
||||
klass = ::Operations.const_get(op_type.capitalize)
|
||||
admin_authorize! :read, klass
|
||||
|
||||
search = klass.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
present paginate(search.result, false), with: API::V2::Admin::Entities::Operation
|
||||
end
|
||||
end
|
||||
|
||||
# Get: api/v2/admin/liabilities
|
||||
::Operations::Account::MEMBER_TYPES.each do |op_type|
|
||||
op_type_plural = op_type.to_s.pluralize
|
||||
|
||||
desc "Returns #{op_type_plural} as a paginated collection." do
|
||||
success API::V2::Admin::Entities::Operation
|
||||
end
|
||||
params do
|
||||
use :uid
|
||||
use :get_operations_params
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get op_type_plural do
|
||||
klass = ::Operations.const_get(op_type.capitalize)
|
||||
admin_authorize! :read, klass
|
||||
|
||||
member = Member.find_by(uid: params[:uid]) if params[:uid].present?
|
||||
search = klass.ransack(ransack_params.merge(member_id_eq: member&.id))
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
present paginate(search.result, false), with: API::V2::Admin::Entities::Operation
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
122
app/api/v2/admin/orders.rb
Normal file
122
app/api/v2/admin/orders.rb
Normal file
@@ -0,0 +1,122 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Orders < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
helpers ::API::V2::OrderHelpers
|
||||
|
||||
content_type :csv, 'text/csv'
|
||||
|
||||
desc 'Get all orders, result is paginated.',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::Order
|
||||
params do
|
||||
optional :market,
|
||||
values: { value: -> { ::Market.ids }, message: 'admin.market.doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:id][:desc] }
|
||||
optional :state,
|
||||
values: { value: -> { ::Order.state.values }, message: 'admin.order.invalid_state' },
|
||||
desc: 'Filter order by state.'
|
||||
optional :ord_type,
|
||||
values: { value: ::Order::TYPES, message: 'admin.order.invalid_ord_type' },
|
||||
desc: 'Filter order by ord_type.'
|
||||
optional :price,
|
||||
type: { value: BigDecimal, message: 'admin.order.non_decimal_price' },
|
||||
values: { value: -> (p){ p.try(:positive?) }, message: 'admin.order.non_positive_price' },
|
||||
desc: -> { API::V2::Admin::Entities::Order.documentation[:price][:desc] }
|
||||
optional :origin_volume,
|
||||
type: { value: BigDecimal, message: 'admin.order.non_decimal_price' },
|
||||
values: { value: -> (p){ p.try(:positive?) }, message: 'admin.order.non_positive_origin_volume' },
|
||||
desc: -> { API::V2::Admin::Entities::Order.documentation[:origin_volume][:desc] }
|
||||
optional :type,
|
||||
values: { value: %w(sell buy), message: 'admin.order.invalid_type' },
|
||||
desc: 'Filter order by type.'
|
||||
optional :email,
|
||||
desc: -> { API::V2::Entities::Member.documentation[:email][:desc] }
|
||||
use :uid
|
||||
use :date_picker
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/orders' do
|
||||
admin_authorize! :read, Order
|
||||
|
||||
if params[:uid].present? || params[:email].present?
|
||||
member = Member.find_by('uid = ? OR email = ?', params[:uid], params[:email])
|
||||
params.except!(:uid, :email).merge!(member_id: member.id) if member.present?
|
||||
end
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(:price, :origin_volume, :ord_type, :state, :member_id)
|
||||
.translate(market: :market_id)
|
||||
.with_daterange
|
||||
.merge({
|
||||
type_eq: params[:type].present? ? params[:type] == 'buy' ? 'OrderBid' : 'OrderAsk' : nil
|
||||
}).build
|
||||
|
||||
search = Order.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
if params[:format] == 'csv'
|
||||
search.result
|
||||
else
|
||||
present paginate(search.result, false), with: API::V2::Admin::Entities::Order
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Cancel an order.'
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.order.non_integer_id' },
|
||||
allow_blank: false,
|
||||
desc: -> { API::V2::Admin::Entities::Order.documentation[:id][:desc] }
|
||||
end
|
||||
post '/orders/:id/cancel' do
|
||||
admin_authorize! :update, ::Order
|
||||
|
||||
begin
|
||||
order = Order.find(params[:id])
|
||||
order.trigger_cancellation
|
||||
present order, with: API::V2::Admin::Entities::Order
|
||||
rescue ActiveRecord::RecordNotFound => e
|
||||
# RecordNotFound in rescued by ExceptionsHandler.
|
||||
raise(e)
|
||||
rescue
|
||||
error!({ errors: ['admin.order.cancel_error'] }, 422)
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Cancel all orders.'
|
||||
params do
|
||||
requires :market,
|
||||
values: { value: -> { ::Market.active.ids }, message: 'admin.order.market_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Order.documentation[:id][:desc] }
|
||||
optional :side,
|
||||
values: { value: %w(sell buy), message: 'admin.order.invalid_side' },
|
||||
desc: 'If present, only sell orders (asks) or buy orders (bids) will be cancelled.'
|
||||
end
|
||||
post '/orders/cancel' do
|
||||
admin_authorize! :update, ::Order
|
||||
|
||||
begin
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(state: 'wait')
|
||||
.translate(market: :market_id)
|
||||
.merge({
|
||||
type_eq: params[:side].present? ? params[:side] == 'buy' ? 'OrderBid' : 'OrderAsk' : nil,
|
||||
}).build
|
||||
|
||||
orders = Order.ransack(ransack_params)
|
||||
orders.result.map(&:trigger_cancellation)
|
||||
present orders.result, with: API::V2::Entities::Order
|
||||
rescue
|
||||
error!({ errors: ['admin.order.cancel_error'] }, 422)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
68
app/api/v2/admin/trades.rb
Normal file
68
app/api/v2/admin/trades.rb
Normal file
@@ -0,0 +1,68 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'csv'
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Trades < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
content_type :csv, 'text/csv'
|
||||
|
||||
desc 'Get all trades, result is paginated.',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::Trade
|
||||
params do
|
||||
optional :market,
|
||||
values: { value: -> { ::Market.ids }, message: 'admin.market.doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Market.documentation[:id][:desc] }
|
||||
optional :order_id,
|
||||
type: Integer,
|
||||
desc: -> { API::V2::Entities::Order.documentation[:id][:desc] }
|
||||
use :uid
|
||||
use :date_picker
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/trades' do
|
||||
admin_authorize! :read, Trade
|
||||
|
||||
member = Member.find_by(uid: params[:uid]) if params[:uid].present?
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params.except!(:uid))
|
||||
.translate(market: :market_id)
|
||||
.with_daterange
|
||||
.merge(g: [
|
||||
{ maker_id_eq: member&.id, taker_id_eq: member&.id, m: 'or' },
|
||||
{ maker_order_id_eq: params[:order_id], taker_order_id_eq: params[:order_id], m: 'or' },
|
||||
]).build
|
||||
|
||||
search = Trade.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
if params[:format] == 'csv'
|
||||
search.result
|
||||
else
|
||||
present paginate(search.result, false), with: API::V2::Admin::Entities::Trade
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Get a trade with detailed information.' do
|
||||
success API::V2::Admin::Entities::Blockchain
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.trade.non_integer_id' },
|
||||
desc: -> { API::V2::Admin::Entities::Trade.documentation[:id][:desc] }
|
||||
end
|
||||
get '/trades/:id' do
|
||||
admin_authorize! :read, Trade
|
||||
|
||||
present Trade.find(params[:id]), with: API::V2::Admin::Entities::Trade, extended: true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
125
app/api/v2/admin/trading_fees.rb
Normal file
125
app/api/v2/admin/trading_fees.rb
Normal file
@@ -0,0 +1,125 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class TradingFees < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
desc 'Returns trading_fees table as paginated collection',
|
||||
is_array: true,
|
||||
success: API::V2::Entities::TradingFee
|
||||
params do
|
||||
optional :group,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:group][:desc] },
|
||||
coerce_with: ->(c) { c.strip.downcase }
|
||||
optional :market_id,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:market_id][:desc] },
|
||||
values: { value: -> { ::Market.ids.append(::TradingFee::ANY) },
|
||||
message: 'admin.trading_fee.market_doesnt_exist' }
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/trading_fees' do
|
||||
admin_authorize! :read, TradingFee
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(:group, :market_id)
|
||||
.build
|
||||
|
||||
search = TradingFee.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
present paginate(search.result), with: API::V2::Entities::TradingFee
|
||||
end
|
||||
|
||||
desc 'It creates trading fees record',
|
||||
success: API::V2::Entities::TradingFee
|
||||
params do
|
||||
requires :maker,
|
||||
type: { value: BigDecimal, message: 'admin.trading_fee.non_decimal_maker' },
|
||||
values: { value: -> (p){ p && p >= 0 }, message: 'admin.trading_fee.invalid_maker' },
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:maker][:desc] }
|
||||
requires :taker,
|
||||
type: { value: BigDecimal, message: 'admin.trading_fee.non_decimal_taker' },
|
||||
values: { value: -> (p){ p && p >= 0 }, message: 'admin.trading_fee.invalid_taker' },
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:taker][:desc] }
|
||||
optional :group,
|
||||
type: String,
|
||||
default: ::TradingFee::ANY,
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:group][:desc] }
|
||||
optional :market_id,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:market_id][:desc] },
|
||||
default: ::TradingFee::ANY,
|
||||
values: { value: -> { ::Market.ids.append(::TradingFee::ANY) },
|
||||
message: 'admin.trading_fee.market_doesnt_exist' }
|
||||
end
|
||||
post '/trading_fees/new' do
|
||||
admin_authorize! :create, TradingFee
|
||||
|
||||
trading_fee = ::TradingFee.new(declared(params))
|
||||
if trading_fee.save
|
||||
present trading_fee, with: API::V2::Entities::TradingFee
|
||||
status 201
|
||||
else
|
||||
body errors: trading_fee.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'It updates trading fees record',
|
||||
success: API::V2::Entities::TradingFee
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.trading_fee.non_integer_id' },
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:id][:desc] }
|
||||
optional :maker,
|
||||
type: { value: BigDecimal, message: 'admin.trading_fee.non_decimal_maker' },
|
||||
values: { value: -> (p){ p && p >= 0 }, message: 'admin.trading_fee.invalid_maker' },
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:maker][:desc] }
|
||||
optional :taker,
|
||||
type: { value: BigDecimal, message: 'admin.trading_fee.non_decimal_taker' },
|
||||
values: { value: -> (p){ p && p >= 0 }, message: 'admin.trading_fee.invalid_taker' },
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:taker][:desc] }
|
||||
optional :group,
|
||||
type: String,
|
||||
coerce_with: ->(c) { c.strip.downcase },
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:group][:desc] }
|
||||
optional :market_id,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:market_id][:desc] },
|
||||
values: { value: -> { ::Market.ids.append(::TradingFee::ANY) },
|
||||
message: 'admin.trading_fee.market_doesnt_exist' }
|
||||
end
|
||||
post '/trading_fees/update' do
|
||||
admin_authorize! :update, TradingFee
|
||||
|
||||
trading_fee = ::TradingFee.find(params[:id])
|
||||
if trading_fee.update(declared(params, include_missing: false))
|
||||
present trading_fee, with: API::V2::Entities::TradingFee
|
||||
else
|
||||
body errors: trading_fee.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'It deletes trading fees record',
|
||||
success: API::V2::Entities::TradingFee
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.trading_fee.non_integer_id' },
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:id][:desc] }
|
||||
end
|
||||
post '/trading_fees/delete' do
|
||||
admin_authorize! :delete, TradingFee
|
||||
|
||||
present TradingFee.destroy(params[:id]), with: API::V2::Entities::TradingFee
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
249
app/api/v2/admin/wallets.rb
Normal file
249
app/api/v2/admin/wallets.rb
Normal file
@@ -0,0 +1,249 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Wallets < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
helpers do
|
||||
# Collection of shared params, used to
|
||||
# generate required/optional Grape params.
|
||||
OPTIONAL_WALLET_PARAMS ||= {
|
||||
max_balance: {
|
||||
type: { value: BigDecimal, message: 'admin.blockchain.non_decimal_max_balance' },
|
||||
values: { value: -> (p){ p >= 0 }, message: 'admin.wallet.invalid_max_balance' },
|
||||
default: 0.0,
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:max_balance][:desc] }
|
||||
},
|
||||
status: {
|
||||
values: { value: %w(active disabled), message: 'admin.wallet.invalid_status' },
|
||||
default: 'active',
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:status][:desc] }
|
||||
},
|
||||
}
|
||||
|
||||
params :create_wallet_params do
|
||||
OPTIONAL_WALLET_PARAMS.each do |key, params|
|
||||
optional key, params
|
||||
end
|
||||
end
|
||||
|
||||
params :update_wallet_params do
|
||||
OPTIONAL_WALLET_PARAMS.each do |key, params|
|
||||
optional key, params.except(:default)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Get all wallets, result is paginated.',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::Wallet
|
||||
params do
|
||||
optional :blockchain_key,
|
||||
values: { value: -> { ::Blockchain.pluck(:key) }, message: 'admin.currency.blockchain_key_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:blockchain_key][:desc] }
|
||||
optional :kind,
|
||||
values: { value: -> { Wallet.kind.values }, message: 'admin.wallet.invalid_kind' },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:kind][:desc] }
|
||||
optional :currencies,
|
||||
values: { value: ->(v) { (Array.wrap(v) - ::Currency.codes).blank? }, message: 'admin.wallet.currency_doesnt_exist' },
|
||||
types: [String, Array], coerce_with: ->(c) { Array.wrap(c) },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:currencies][:desc] }
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/wallets' do
|
||||
admin_authorize! :read, Wallet
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(:blockchain_key)
|
||||
.translate_in(currencies: :currencies_id)
|
||||
.merge(kind_eq: params[:kind].present? ? Wallet.kinds[params[:kind].to_sym] : nil)
|
||||
.build
|
||||
|
||||
search = ::Wallet.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
present paginate(search.result.includes(:currencies).distinct), with: API::V2::Admin::Entities::Wallet
|
||||
end
|
||||
|
||||
desc 'List wallet kinds.'
|
||||
get '/wallets/kinds' do
|
||||
::Wallet.kind.values
|
||||
end
|
||||
|
||||
desc 'List wallet gateways.'
|
||||
get '/wallets/gateways' do
|
||||
::Wallet.gateways.map(&:to_s)
|
||||
end
|
||||
|
||||
desc 'Get a wallet.' do
|
||||
success API::V2::Admin::Entities::Wallet
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.wallet.non_integer_id' },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:id][:desc] }
|
||||
end
|
||||
get '/wallets/:id' do
|
||||
admin_authorize! :read, Wallet
|
||||
|
||||
present ::Wallet.find(params[:id]), with: API::V2::Admin::Entities::Wallet
|
||||
end
|
||||
|
||||
desc 'Creates new wallet.' do
|
||||
success API::V2::Admin::Entities::Wallet
|
||||
end
|
||||
params do
|
||||
use :create_wallet_params
|
||||
requires :blockchain_key,
|
||||
values: { value: -> { ::Blockchain.pluck(:key) }, message: 'admin.wallet.blockchain_key_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:blockchain_key][:desc] }
|
||||
requires :name,
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:name][:desc] }
|
||||
optional :address,
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:address][:desc] }
|
||||
optional :currencies,
|
||||
values: { value: ->(v) { (Array.wrap(v) - ::Currency.codes).blank? }, message: 'admin.wallet.currency_doesnt_exist' },
|
||||
types: [String, Array], coerce_with: ->(c) { Array.wrap(c) },
|
||||
as: :currency_ids,
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:currencies][:desc] }
|
||||
# @deprecated Please use `currencies` field
|
||||
optional :currency,
|
||||
values: { value: -> { ::Currency.codes }, message: 'admin.wallet.currency_doesnt_exist' },
|
||||
as: :currency_ids,
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:currencies][:desc] }
|
||||
requires :kind,
|
||||
values: { value: ::Wallet.kind.values, message: 'admin.wallet.invalid_kind' },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:kind][:desc] }
|
||||
requires :gateway,
|
||||
values: { value: -> { ::Wallet.gateways.map(&:to_s) }, message: 'admin.wallet.gateway_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:gateway][:desc] }
|
||||
optional :settings, type: JSON,
|
||||
default: {},
|
||||
desc: -> { 'Wallet settings (uri, secret)' } do
|
||||
optional :uri,
|
||||
values: { value: ->(v) { URI.parse(v).is_a?(URI::HTTP) || URI.parse(v).is_a?(URI::HTTPS) }, message: 'admin.wallet.invalid_uri_setting' },
|
||||
desc: -> { 'Wallet uri setting' }
|
||||
optional :secret,
|
||||
desc: -> { 'Wallet secret setting' }
|
||||
end
|
||||
exactly_one_of :currencies, :currency, message: 'admin.wallet.currencies_field_is_missing'
|
||||
end
|
||||
post '/wallets/new' do
|
||||
admin_authorize! :create, Wallet
|
||||
|
||||
wallet = ::Wallet.new(declared(params))
|
||||
if wallet.save
|
||||
present wallet, with: API::V2::Admin::Entities::Wallet
|
||||
status 201
|
||||
else
|
||||
body errors: wallet.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Update wallet.' do
|
||||
success API::V2::Admin::Entities::Wallet
|
||||
end
|
||||
params do
|
||||
use :update_wallet_params
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.wallet.non_integer_id' },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:id][:desc] }
|
||||
optional :blockchain_key,
|
||||
values: { value: -> { ::Blockchain.pluck(:key) }, message: 'admin.wallet.blockchain_key_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:blockchain_key][:desc] }
|
||||
optional :name,
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:name][:desc] }
|
||||
optional :address,
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:address][:desc] }
|
||||
optional :kind,
|
||||
values: { value: ::Wallet.kind.values, message: 'admin.wallet.invalid_kind' },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:kind][:desc] }
|
||||
optional :gateway,
|
||||
values: { value: -> { ::Wallet.gateways.map(&:to_s) }, message: 'admin.wallet.gateway_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:gateway][:desc] }
|
||||
optional :currencies,
|
||||
values: { value: ->(v) { (Array.wrap(v) - ::Currency.codes).blank? }, message: 'admin.wallet.currency_doesnt_exist' },
|
||||
types: [String, Array], coerce_with: ->(c) { Array.wrap(c) },
|
||||
as: :currency_ids,
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:currencies][:desc] }
|
||||
optional :settings, type: JSON,
|
||||
desc: -> { 'Wallet settings' } do
|
||||
optional :uri,
|
||||
values: { value: ->(v) { URI.parse(v).is_a?(URI::HTTP) || URI.parse(v).is_a?(URI::HTTPS) }, message: 'admin.wallet.invalid_uri_setting' },
|
||||
desc: -> { 'Wallet uri setting' }
|
||||
optional :secret,
|
||||
desc: -> { 'Wallet secret setting' }
|
||||
end
|
||||
end
|
||||
post '/wallets/update' do
|
||||
admin_authorize! :update, Wallet
|
||||
wallet = ::Wallet.find(params[:id])
|
||||
|
||||
declared_params = declared(params, include_missing: false)
|
||||
declared_params.merge!(settings: params[:settings]) if params[:settings].present?
|
||||
if wallet.update(declared_params)
|
||||
present wallet, with: API::V2::Admin::Entities::Wallet
|
||||
else
|
||||
body errors: wallet.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Add currency to the wallet' do
|
||||
success API::V2::Admin::Entities::Wallet
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.wallet.non_integer_id' },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:id][:desc] }
|
||||
requires :currencies,
|
||||
values: { value: ->(v) { (Array.wrap(v) - ::Currency.codes).blank? }, message: 'admin.wallet.currency_doesnt_exist' },
|
||||
types: [String, Array], coerce_with: ->(c) { Array.wrap(c) },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:currencies][:desc] }
|
||||
end
|
||||
post '/wallets/currencies' do
|
||||
wallet = Wallet.find(params[:id])
|
||||
|
||||
wallet.transaction do
|
||||
params[:currencies].each do |c_id|
|
||||
c_w = CurrencyWallet.new(currency_id: c_id, wallet_id: params[:id])
|
||||
error!({ errors: c_w.errors.full_messages }, 422) unless c_w.save
|
||||
end
|
||||
end
|
||||
|
||||
present wallet, with: API::V2::Admin::Entities::Wallet
|
||||
status 201
|
||||
end
|
||||
|
||||
desc 'Delete currency from the wallet' do
|
||||
success API::V2::Admin::Entities::Wallet
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.wallet.non_integer_id' },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:id][:desc] }
|
||||
requires :currencies,
|
||||
values: { value: ->(v) { (Array.wrap(v) - ::Currency.codes).blank? }, message: 'admin.wallet.currency_doesnt_exist' },
|
||||
types: [String, Array], coerce_with: ->(c) { Array.wrap(c) },
|
||||
desc: -> { API::V2::Admin::Entities::Wallet.documentation[:currencies][:desc] }
|
||||
end
|
||||
delete '/wallets/currencies' do
|
||||
wallet = Wallet.find(params[:id])
|
||||
wallet.transaction do
|
||||
params[:currencies].each do |c_id|
|
||||
# Check if exist (will return error)
|
||||
CurrencyWallet.find_by!(currency_id: c_id, wallet_id: params[:id])
|
||||
# Delete relation
|
||||
CurrencyWallet.where(currency_id: c_id, wallet_id: params[:id]).delete_all
|
||||
end
|
||||
end
|
||||
|
||||
present wallet, with: API::V2::Admin::Entities::Wallet
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
137
app/api/v2/admin/whitelisted_smart_contracts.rb
Normal file
137
app/api/v2/admin/whitelisted_smart_contracts.rb
Normal file
@@ -0,0 +1,137 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class WhitelistedSmartContracts < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
content_type :csv, 'text/csv'
|
||||
|
||||
desc 'Get all whitelisted addresses, result is paginated.',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::WhitelistedSmartContract
|
||||
params do
|
||||
optional :blockchain_key,
|
||||
values: { value: -> { ::Blockchain.pluck(:key) }, message: 'admin.whitelistedsmartcontract.blockchain_key_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::WhitelistedSmartContract.documentation[:blockchain_key][:desc] }
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/whitelisted_smart_contracts' do
|
||||
admin_authorize! :read, WhitelistedSmartContract
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params).eq(:blockchain_key).build
|
||||
|
||||
search = ::WhitelistedSmartContract.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
if params[:format] == 'csv'
|
||||
search.result
|
||||
else
|
||||
present paginate(search.result), with: API::V2::Admin::Entities::WhitelistedSmartContract
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Get a whitelisted address.' do
|
||||
success API::V2::Admin::Entities::WhitelistedSmartContract
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.whitelistedsmartcontract.non_integer_id' },
|
||||
desc: -> { API::V2::Admin::Entities::WhitelistedSmartContract.documentation[:id][:desc] }
|
||||
end
|
||||
get '/whitelisted_smart_contract/:id' do
|
||||
admin_authorize! :read, WhitelistedSmartContract
|
||||
|
||||
present ::WhitelistedSmartContract.find(params[:id]), with: API::V2::Admin::Entities::WhitelistedSmartContract
|
||||
end
|
||||
|
||||
desc 'Creates new whitelisted address.' do
|
||||
success API::V2::Admin::Entities::WhitelistedSmartContract
|
||||
end
|
||||
params do
|
||||
requires :blockchain_key,
|
||||
values: { value: -> { ::Blockchain.pluck(:key) }, message: 'admin.whitelistedsmartcontract.blockchain_key_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::WhitelistedSmartContract.documentation[:blockchain_key][:desc] }
|
||||
requires :address,
|
||||
desc: -> { API::V2::Admin::Entities::WhitelistedSmartContract.documentation[:address][:desc] }
|
||||
optional :description,
|
||||
desc: -> { API::V2::Admin::Entities::WhitelistedSmartContract.documentation[:description][:desc] }
|
||||
optional :state,
|
||||
values: { value: %w[active disabled], message: 'admin.whitelistedsmartcontract.invalid_state' },
|
||||
default: 'active',
|
||||
desc: -> { API::V2::Admin::Entities::WhitelistedSmartContract.documentation[:state][:desc] }
|
||||
end
|
||||
post '/whitelisted_smart_contracts' do
|
||||
admin_authorize! :create, WhitelistedSmartContract
|
||||
|
||||
whitelisted_address = ::WhitelistedSmartContract.new(declared(params))
|
||||
if whitelisted_address.save
|
||||
present whitelisted_address, with: API::V2::Admin::Entities::WhitelistedSmartContract
|
||||
else
|
||||
body errors: whitelisted_address.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Update whitelisted_smart_contract.' do
|
||||
success API::V2::Admin::Entities::WhitelistedSmartContract
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.whitelistedsmartcontract.non_integer_id' },
|
||||
desc: -> { API::V2::Admin::Entities::WhitelistedSmartContract.documentation[:id][:desc] }
|
||||
optional :blockchain_key,
|
||||
values: { value: -> { ::Blockchain.pluck(:key) }, message: 'admin.whitelistedsmartcontract.blockchain_key_doesnt_exist' },
|
||||
desc: -> { API::V2::Admin::Entities::WhitelistedSmartContract.documentation[:blockchain_key][:desc] }
|
||||
optional :description,
|
||||
desc: -> { API::V2::Admin::Entities::WhitelistedSmartContract.documentation[:description][:desc] }
|
||||
optional :address,
|
||||
desc: -> { API::V2::Admin::Entities::WhitelistedSmartContract.documentation[:address][:desc] }
|
||||
optional :state,
|
||||
values: { value: %w[active disabled], message: 'admin.whitelistedsmartcontract.invalid_state' },
|
||||
desc: -> { API::V2::Admin::Entities::WhitelistedSmartContract.documentation[:state][:desc] }
|
||||
end
|
||||
put '/whitelisted_smart_contracts' do
|
||||
admin_authorize! :update, WhitelistedSmartContract
|
||||
whitelisted_address = ::WhitelistedSmartContract.find(params[:id])
|
||||
declared_params = declared(params, include_missing: false)
|
||||
|
||||
if whitelisted_address.update(declared_params)
|
||||
present whitelisted_address, with: API::V2::Admin::Entities::WhitelistedSmartContract
|
||||
else
|
||||
body errors: whitelisted_address.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Process whitelisted smart contracts from csv' do
|
||||
success API::V2::Admin::Entities::WhitelistedSmartContract
|
||||
end
|
||||
params do
|
||||
requires :file,
|
||||
type: File,
|
||||
desc: -> {'CSV file with whitelisted smart contracts data'}
|
||||
end
|
||||
post '/whitelisted_smart_contracts/csv' do
|
||||
admin_authorize! :create, WhitelistedSmartContract
|
||||
count = 0
|
||||
|
||||
CSV.parse(params[:file][:tempfile], headers: true, quote_empty: false).each do |row|
|
||||
row = row.to_h.compact.symbolize_keys!
|
||||
address = row[:address]
|
||||
blockchain_key = row[:blockchain_key]
|
||||
description = row[:description]
|
||||
next if address.blank? || blockchain_key.blank? || ::Blockchain.pluck(:key).exclude?(blockchain_key)
|
||||
|
||||
::WhitelistedSmartContract.create!(description: description, address: address,
|
||||
blockchain_key: blockchain_key, state: 'active')
|
||||
count += 1
|
||||
end
|
||||
|
||||
present ::WhitelistedSmartContract.last(count), with: API::V2::Admin::Entities::WhitelistedSmartContract
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
127
app/api/v2/admin/withdraw_limits.rb
Normal file
127
app/api/v2/admin/withdraw_limits.rb
Normal file
@@ -0,0 +1,127 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class WithdrawLimits < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
desc 'Returns withdraw limits table as paginated collection',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::WithdrawLimit
|
||||
params do
|
||||
optional :group,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:group][:desc] },
|
||||
coerce_with: ->(c) { c.strip.downcase }
|
||||
optional :kyc_level,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:kyc_level][:desc] }
|
||||
optional :kind,
|
||||
values: { value: ->(v) { (Array.wrap(v) - WithdrawLimit.kind.values).blank? }, message: 'limit.kind.invalid' },
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:kind][:desc] }
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/withdraw_limits' do
|
||||
admin_authorize! :read, WithdrawLimit
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(:group, :kyc_level, :kind)
|
||||
.build
|
||||
|
||||
search = WithdrawLimit.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
present paginate(search.result), with: API::V2::Entities::WithdrawLimit
|
||||
end
|
||||
|
||||
desc 'It creates withdraw limits record',
|
||||
success: API::V2::Entities::WithdrawLimit
|
||||
params do
|
||||
requires :limit_24_hour,
|
||||
type: { value: BigDecimal, message: 'admin.withdraw_limit.non_decimal_limit_24_hour' },
|
||||
values: { value: ->(p) { p && p >= 0 }, message: 'admin.withdraw_limit.invalid_limit_24_hour' },
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:limit_24_hour][:desc] }
|
||||
requires :limit_1_month,
|
||||
type: { value: BigDecimal, message: 'admin.withdraw_limit.non_decimal_limit_1_month' },
|
||||
values: { value: ->(p) { p && p >= 0 }, message: 'admin.withdraw_limit.invalid_limit_1_month' },
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:limit_1_month][:desc] }
|
||||
requires :kind,
|
||||
values: { value: ->(v) { (Array.wrap(v) - WithdrawLimit.kind.values).blank? }, message: 'limit.kind.invalid' },
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:kind][:desc] }
|
||||
optional :group,
|
||||
type: String,
|
||||
default: ::WithdrawLimit::ANY,
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:group][:desc] }
|
||||
optional :kyc_level,
|
||||
type: String,
|
||||
default: ::WithdrawLimit::ANY,
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:kyc_level][:desc] }
|
||||
end
|
||||
post '/withdraw_limits' do
|
||||
admin_authorize! :create, WithdrawLimit
|
||||
|
||||
withdraw_limit = ::WithdrawLimit.new(declared(params))
|
||||
if withdraw_limit.save
|
||||
present withdraw_limit, with: API::V2::Entities::WithdrawLimit
|
||||
status 201
|
||||
else
|
||||
body errors: withdraw_limit.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'It updates withdraw limits record',
|
||||
success: API::V2::Entities::WithdrawLimit
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.withdraw_limit.non_integer_id' },
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:id][:desc] }
|
||||
optional :limit_24_hour,
|
||||
type: { value: BigDecimal, message: 'admin.withdraw_limit.non_decimal_limit_24_hour' },
|
||||
values: { value: ->(p) { p && p >= 0 }, message: 'admin.withdraw_limit.invalid_limit_24_hour' },
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:limit_24_hour][:desc] }
|
||||
optional :limit_1_month,
|
||||
type: { value: BigDecimal, message: 'admin.withdraw_limit.non_decimal_limit_1_month' },
|
||||
values: { value: ->(p) { p && p >= 0 }, message: 'admin.withdraw_limit.invalid_limit_1_month' },
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:limit_1_month][:desc] }
|
||||
optional :kind,
|
||||
values: { value: ->(v) { (Array.wrap(v) - WithdrawLimit.kind.values).blank? }, message: 'limit.kind.invalid' },
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:kind][:desc] }
|
||||
optional :kyc_level,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:kyc_level][:desc] }
|
||||
optional :group,
|
||||
type: String,
|
||||
coerce_with: ->(c) { c.strip.downcase },
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:group][:desc] }
|
||||
end
|
||||
put '/withdraw_limits' do
|
||||
admin_authorize! :update, WithdrawLimit
|
||||
|
||||
withdraw_limit = ::WithdrawLimit.find(params[:id])
|
||||
if withdraw_limit.update(declared(params, include_missing: false))
|
||||
present withdraw_limit, with: API::V2::Entities::WithdrawLimit
|
||||
else
|
||||
body errors: withdraw_limit.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'It deletes withdraw limits record',
|
||||
success: API::V2::Entities::WithdrawLimit
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.withdraw_limit.non_integer_id' },
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:id][:desc] }
|
||||
end
|
||||
delete '/withdraw_limits/:id' do
|
||||
admin_authorize! :delete, WithdrawLimit
|
||||
|
||||
present WithdrawLimit.destroy(params[:id]), with: API::V2::Entities::WithdrawLimit
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
149
app/api/v2/admin/withdraws.rb
Normal file
149
app/api/v2/admin/withdraws.rb
Normal file
@@ -0,0 +1,149 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Admin
|
||||
class Withdraws < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
desc 'Get all withdraws, result is paginated.',
|
||||
is_array: true,
|
||||
success: API::V2::Admin::Entities::Withdraw
|
||||
params do
|
||||
optional :state,
|
||||
values: { value: ->(v) { (Array.wrap(v) - Withdraw::STATES.map(&:to_s)).blank? }, message: 'admin.withdraw.invalid_state' },
|
||||
desc: -> { API::V2::Admin::Entities::Withdraw.documentation[:state][:desc] }
|
||||
optional :id,
|
||||
type: Integer,
|
||||
desc: -> { API::V2::Admin::Entities::Withdraw.documentation[:id][:desc] }
|
||||
optional :txid,
|
||||
desc: -> { API::V2::Admin::Entities::Withdraw.documentation[:blockchain_txid][:desc] }
|
||||
optional :tid,
|
||||
desc: -> { API::V2::Admin::Entities::Withdraw.documentation[:tid][:desc] }
|
||||
optional :confirmations,
|
||||
type: Integer,
|
||||
desc: -> { API::V2::Admin::Entities::Withdraw.documentation[:confirmations][:desc] }
|
||||
optional :rid,
|
||||
desc: -> { API::V2::Admin::Entities::Withdraw.documentation[:rid][:desc] }
|
||||
optional :wallet_type,
|
||||
values: { value: ->(v) { (Array.wrap(v.to_sym) - Wallet.gateways).blank? }, message: 'admin.withdraw.invalid_wallet_type' },
|
||||
desc: -> { 'Select withdraw that can be processed from wallets with given type e.g. patiry' }
|
||||
use :uid
|
||||
use :currency
|
||||
use :currency_type
|
||||
use :date_picker
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/withdraws' do
|
||||
admin_authorize! :read, Withdraw
|
||||
|
||||
ransack_params = Helpers::RansackBuilder.new(params)
|
||||
.eq(:id, :txid, :rid, :tid)
|
||||
.translate(uid: :member_uid, currency: :currency_id)
|
||||
.with_daterange
|
||||
.merge(type_eq: params[:type].present? ? "Withdraws::#{params[:type].capitalize}" : nil)
|
||||
.merge(aasm_state_in: params[:state])
|
||||
.build
|
||||
|
||||
search = Withdraw.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
if params[:wallet_type].present?
|
||||
present paginate(search.result
|
||||
.where(currency: Currency.joins(:wallets)
|
||||
.where(wallets: { id: Wallet.where(gateway: params[:wallet_type]) }))),
|
||||
with: API::V2::Admin::Entities::Withdraw
|
||||
else
|
||||
present paginate(search.result), with: API::V2::Admin::Entities::Withdraw
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Get withdraw by ID.',
|
||||
success: API::V2::Admin::Entities::Withdraw
|
||||
params do
|
||||
requires :id,
|
||||
type: { value: Integer, message: 'admin.withdraw.non_integer_id' },
|
||||
desc: -> { API::V2::Admin::Entities::Withdraw.documentation[:id][:desc] }
|
||||
end
|
||||
get '/withdraws/:id' do
|
||||
admin_authorize! :read, Withdraw
|
||||
|
||||
withdraw = Withdraw.find_by!(id: params[:id])
|
||||
present withdraw,
|
||||
with: API::V2::Admin::Entities::Withdraw,
|
||||
with_beneficiary: true
|
||||
end
|
||||
|
||||
desc 'Take an action on the withdrawal.',
|
||||
success: API::V2::Admin::Entities::Withdraw
|
||||
params do
|
||||
requires :id,
|
||||
type: Integer,
|
||||
desc: -> { API::V2::Admin::Entities::Withdraw.documentation[:id][:desc] }
|
||||
requires :action,
|
||||
type: String,
|
||||
values: { value: -> { ::Withdraw.aasm.events.map(&:name).map(&:to_s) }, message: 'admin.withdraw.invalid_action' },
|
||||
desc: "Valid actions are #{::Withdraw.aasm.events.map(&:name)}."
|
||||
given action: ->(action) { %w[load dispatch success].include?(action) } do
|
||||
optional :txid,
|
||||
type: String,
|
||||
desc: -> { API::V2::Admin::Entities::Withdraw.documentation[:blockchain_txid][:desc] }
|
||||
end
|
||||
end
|
||||
post '/withdraws/actions' do
|
||||
admin_authorize! :update, Withdraw
|
||||
|
||||
declared_params = declared(params, include_missing: false)
|
||||
|
||||
withdraw = Withdraw.find(declared_params[:id])
|
||||
|
||||
if withdraw.currency.fiat? && declared_params[:txid].present?
|
||||
error!({ errors: ['admin.withdraw.redundant_txid'] }, 422)
|
||||
end
|
||||
|
||||
transited = withdraw.transaction do
|
||||
withdraw.update!(txid: declared_params[:txid]) if declared_params[:txid].present?
|
||||
withdraw.public_send("#{declared_params[:action]}!").tap do |success|
|
||||
raise ActiveRecord::Rollback unless success
|
||||
end
|
||||
rescue StandardError
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
if transited
|
||||
present withdraw, with: API::V2::Admin::Entities::Withdraw
|
||||
else
|
||||
body errors: ["admin.withdraw.cannot_#{declared_params[:action]}"]
|
||||
status 422
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Update withdraw request',
|
||||
success: API::V2::Admin::Entities::Withdraw
|
||||
params do
|
||||
requires :id,
|
||||
type: Integer,
|
||||
desc: -> { API::V2::Admin::Entities::Withdraw.documentation[:id][:desc] }
|
||||
optional :metadata,
|
||||
type: JSON,
|
||||
desc: 'Optional metadata to be applied to the transaction.'
|
||||
end
|
||||
put '/withdraws' do
|
||||
admin_authorize! :update, Withdraw
|
||||
|
||||
declared_params = declared(params, include_missing: false)
|
||||
withdraw = Withdraw.find(declared_params[:id])
|
||||
|
||||
declared_params[:metadata] = withdraw.metadata.merge(declared_params[:metadata]) if declared_params[:metadata].present?
|
||||
if withdraw.update(declared_params)
|
||||
present withdraw, with: API::V2::Admin::Entities::Withdraw
|
||||
else
|
||||
body errors: withdraw.errors.full_messages
|
||||
status 422
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user