Files
spark/src/lib/api/service_helpers/AdminServiceUtils.cpp
T

970 lines
50 KiB
C++

#include "lib/api/services/AdminService.server.pb.h"
#include "lib/api/service_helpers/AdminServiceUtils.h"
namespace bts{
namespace admin{
////////////////////////////////////////////
// connection accessors ////////////////////
////////////////////////////////////////////
uint32_t AdminServiceUtils::find_max_connection_id (const bts::api::admin::AdminData& data){
uint32_t rv = 0;
for(const auto &conn : data.connections())
if (conn.id() > rv)
rv = conn.id();
return rv;
}
const bts::api::admin::ExchangeConnection* AdminServiceUtils::find_connection(const bts::api::admin::AdminData& data,
const std::string& connection_name){
for(const auto& connection : data.connections())
if(connection.name()==connection_name)
return &connection;
return nullptr;
}
bool AdminServiceUtils::has_exchange(const bts::api::admin::ExchangeConnection& conn,
bts::api::Venue exchange){
bool rv = false;
switch(exchange)
{
case api::Venue::VENUE_GLBX:
rv = conn.has_cme_connection() &&
(conn.cme_connection().has_cgw_connection() || conn.cme_connection().has_msgw_connection());
break;
case api::Venue::VENUE_UNSET:
case api::Venue::VENUE_BTS:
case api::Venue::VENUE_CBOE:
case api::Venue::VENUE_CBOECFE:
case api::Venue::VENUE_ICE:
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
rv = false;
break;
}
return rv;
}
const bts::api::admin::ExchangeConnection* AdminServiceUtils::find_default_account_connection(const bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& account,
bts::api::Venue exchange){
//todo:get from parent accounts if not overridden
if(account.has_connections())
for (const std::string& conn_name : account.connections().exchange_connection_names()){
const bts::api::admin::ExchangeConnection* conn = find_connection(data, conn_name);
if (conn!=nullptr && has_exchange(*conn, exchange))
return conn;
}
return nullptr;
}
////////////////////////////////////////////
// connection mutators /////////////////////
////////////////////////////////////////////
bts::api::admin::ExchangeConnection* AdminServiceUtils::add_connection (bts::api::admin::AdminData& data,
const bts::api::admin::ExchangeConnection& new_connection){
auto new_connection_ptr = data.add_connections();
new_connection_ptr->CopyFrom(new_connection);
return new_connection_ptr;
}
void AdminServiceUtils::fill_connections_from_config(bts::api::admin::AdminData& admin_data){
admin_data.clear_connections();
auto &all_connections = config::get<config::JetFIX>().connection();
for (auto const &c : all_connections){
// TODO:(assumes all exchanges are CME)
bts::api::admin::ExchangeConnection connection;
uint32_t new_id = find_max_connection_id(admin_data)+1;
connection.set_id(new_id);
connection.set_name(c.name());
connection.mutable_cme_connection()->mutable_msgw_connection();
add_connection(admin_data,connection);
}
for(int i=0;i<admin_data.accounts_size();i++)
sync_account_connections(admin_data, *admin_data.mutable_accounts(i));
}
////////////////////////////////////////////
// account accessors ///////////////////////
////////////////////////////////////////////
bts::api::admin::BTSAccount* AdminServiceUtils::find_account (bts::api::admin::AdminData& data,
const std::string& name,
bool include_deleted){
auto account_ptrs = accounts_mutable(data, include_deleted);
for (auto account_ptr : account_ptrs)
if(name==account_ptr->name())
return account_ptr;
return nullptr;
}
const bts::api::admin::BTSAccount* AdminServiceUtils::find_account (const bts::api::admin::AdminData& data,
const std::string& name,
bool include_deleted){
auto account_ptrs = accounts(data, include_deleted);
for (auto account_ptr : account_ptrs)
if(name==account_ptr->name())
return account_ptr;
return nullptr;
}
bts::api::admin::BTSAccount* AdminServiceUtils::find_account (bts::api::admin::AdminData& data,
uint32_t id,
bool include_deleted){
auto account_ptrs = accounts_mutable(data, include_deleted);
for (auto account_ptr : account_ptrs)
if(id==account_ptr->id())
return account_ptr;
return nullptr;
}
const bts::api::admin::BTSAccount* AdminServiceUtils::find_account (const bts::api::admin::AdminData& data,
uint32_t id,
bool include_deleted){
auto account_ptrs = accounts(data, include_deleted);
for (auto account_ptr : account_ptrs)
if(id==account_ptr->id())
return account_ptr;
return nullptr;
}
std::vector<const bts::api::admin::BTSAccount*> AdminServiceUtils::accounts (const bts::api::admin::AdminData& data,
bool include_deleted){
std::vector<const bts::api::admin::BTSAccount*> rv;
for (const auto& account : data.accounts())
if (account.is_present() || include_deleted)
rv.push_back(&account);
return rv;
}
std::vector<bts::api::admin::BTSAccount*> AdminServiceUtils::accounts_mutable (bts::api::admin::AdminData& data,
bool include_deleted){
std::vector<bts::api::admin::BTSAccount*> rv;
for(int i=0; i<data.accounts_size(); i++){
bts::api::admin::BTSAccount* account_ptr = data.mutable_accounts(i);
if (account_ptr->is_present() || include_deleted)
rv.push_back(account_ptr);
}
return rv;
}
uint32_t AdminServiceUtils::find_max_acct_id (const bts::api::admin::AdminData& data){
uint32_t rv = 0;
for(const auto &acct : data.accounts())
if (acct.id() > rv)
rv = acct.id();
return rv;
}
const bts::api::admin::CMEAccountData* AdminServiceUtils::get_account_cme_data(const bts::api::admin::BTSAccount& account,
const bts::api::admin::AdminData& data){
if (account.has_exchange_account_data() && account.exchange_account_data().has_cme_account_data())
return &(account.exchange_account_data().cme_account_data());
else if (has_id(account.parent_account_id())){
const bts::api::admin::BTSAccount* parent_account = find_account(data, account.parent_account_id());
if (parent_account != nullptr)
return get_account_cme_data (*parent_account, data);
}
return nullptr;
}
bool AdminServiceUtils::account_has_connection(const bts::api::admin::BTSAccount& account,
const std::string& connection_name){
if(account.has_connections()){
for(int i=0; i<account.connections().exchange_connection_names_size();i++)
if(connection_name == account.connections().exchange_connection_names(i))
return true;
}
return false;
}
std::string AdminServiceUtils::find_account_exchange_account (const bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& account,
api::Venue exchange,
bts::api::admin::AdminServiceOperationResult& out_result){
out_result.set_is_success(true);
const api::admin::CMEAccountData* cme_account_data;
std::string rv = "";
switch(exchange)
{
case api::Venue::VENUE_GLBX:
cme_account_data = get_account_cme_data(account, data);
if (cme_account_data != nullptr)
rv = cme_account_data->clearing_account();
break;
case api::Venue::VENUE_UNSET:
case api::Venue::VENUE_BTS:
case api::Venue::VENUE_CBOE:
case api::Venue::VENUE_CBOECFE:
case api::Venue::VENUE_ICE:
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
out_result.set_is_success(false); out_result.set_error_text("Exchange not supported");
break;
}
return rv;
}
std::map<uint32_t,bool> AdminServiceUtils::accounts_map(const bts::api::admin::AdminData& admin_data){
std::map<uint32_t,bool> rv;
auto account_ptrs = accounts(admin_data, false);
for(const bts::api::admin::BTSAccount* account_ptr : account_ptrs)
rv.insert(std::pair<uint32_t,bool>(account_ptr->id(),account_ptr->is_active()));
return rv;
}
void AdminServiceUtils::validate_account_update (const bts::api::admin::AdminData& admin_data,
const bts::api::admin::BTSAccount& updated_account,
bts::api::admin::AdminServiceOperationResult& result){
result.set_is_success(true);
// validate id
if(find_account(admin_data, updated_account.id()) == nullptr){
result.set_is_success(false);
result.set_error_text("Could not find account id");
return;
}
// validate that name change doesnt collide
auto account_ptrs = accounts(admin_data, false);
for (const bts::api::admin::BTSAccount* account_ptr : account_ptrs)
if (account_ptr->id() != updated_account.id() && account_ptr->name() == updated_account.name()){
result.set_is_success(false);
result.set_error_text("Account by this name already exists");
return;
}
// validate account exchange changes
validate_account_exchange_data (updated_account, result);
}
void AdminServiceUtils::validate_account_exchange_data (const bts::api::admin::BTSAccount& account,
bts::api::admin::AdminServiceOperationResult& result){
result.set_is_success(true);
if (account.has_exchange_account_data()){
if (account.exchange_account_data().has_cme_account_data()){
const bts::api::admin::CMEAccountData& cme_account_data = account.exchange_account_data().cme_account_data();
if (cme_account_data.clearing_account().size() > 12){
result.set_is_success(false);
result.set_error_text("CME account can not be more 12 characters long");
}
}
}
}
bts::api::orderman::RoutingRecord AdminServiceUtils::get_routing_record(const bts::api::admin::AdminData& data,
const std::string& account_name,
const std::string& user_name,
const bts::api::Security& sec,
bts::api::admin::AdminServiceOperationResult& out_result){
bts::api::orderman::RoutingRecord rv;
const bts::api::admin::BTSAccount* account_ptr = find_account(data, account_name);
if (account_ptr == nullptr){
out_result.set_is_success(false);
out_result.set_error_text("Could not find account");
return rv;
}
const bts::api::admin::BTSUser* user_ptr = find_user(data, user_name);
if (user_ptr == nullptr){
out_result.set_is_success(false);
out_result.set_error_text("Could not find user");
return rv;
}
return get_routing_record(data, account_ptr->id(), user_ptr->id(), sec, out_result);
}
bts::api::orderman::RoutingRecord AdminServiceUtils::get_routing_record(const bts::api::admin::AdminData& data,
uint32_t account_id,
uint32_t user_id,
const bts::api::Security& sec,
bts::api::admin::AdminServiceOperationResult& out_result){
bts::api::orderman::RoutingRecord rv;
out_result.set_is_success(true);
const bts::api::admin::BTSAccount* account_ptr = find_account(data,account_id);
if (account_ptr == nullptr){
out_result.set_is_success(false);
out_result.set_error_text("Could not find account");
return rv;
}
const bts::api::admin::BTSUser* user_ptr = find_user(data, user_id);
if (user_ptr == nullptr){
out_result.set_is_success(false);
out_result.set_error_text("Could not find user");
return rv;
}
const bts::api::admin::ExchangeConnection* conn_ptr = find_default_account_connection(data, *account_ptr, sec.exchange());
if(conn_ptr == nullptr){
out_result.set_is_success(false);
out_result.set_error_text("Could not find connection");
return rv;
}
if(sec.exchange()==bts::api::Venue::VENUE_GLBX){
const bts::api::admin::CMEUserData* cme_user_data = get_user_cme_data(*user_ptr, data);
if(cme_user_data==nullptr){
out_result.set_is_success(false);
out_result.set_error_text("Could not find CME data for user");//CME or globex ?
return rv;
}
const bts::api::admin::CMEAccountData* cme_account_data = get_account_cme_data(*account_ptr, data);
if(cme_account_data==nullptr){
out_result.set_is_success(false);
out_result.set_error_text("Could not find CME data for account");
return rv;
}
rv.set_session(conn_ptr->name());
rv.set_operator_id(cme_user_data->operator_id());
rv.set_account(cme_account_data->clearing_account());
rv.set_cti_code(cme_account_data->cti());
rv.set_customer_or_firm(cme_account_data->origin());
return rv;
}
else{
out_result.set_is_success(false);
out_result.set_error_text("Only contracts at the CME are supported right now");
return rv;
}
}
////////////////////////////////////////////
// account mutators ////////////////////////
////////////////////////////////////////////
bts::api::admin::BTSAccount* AdminServiceUtils::create_account(bts::api::admin::AdminData& data,
uint32_t parent_account_id,
const std::string& account_name,
const std::string& description,
bool is_active,
bts::api::admin::AdminServiceCreateAccountResult& result){
result.set_is_success(true);
// the error conditions are checked first and returned immediatly
// i. account with the name already exists
// ii. parent account is set and does not exist
if (find_account(data, account_name, true) != nullptr){
result.set_is_success(false);
result.set_error_text("Account by this name already exists");
return nullptr;
}
if (has_id(parent_account_id)){
if (find_account(data, parent_account_id) == nullptr){
result.set_is_success(false);
result.set_error_text("Parent group does not exist");
return nullptr;
}
}
uint32_t new_id = find_max_acct_id(data)+1;
result.set_new_id(new_id);
bts::api::admin::BTSAccount* new_account_ptr = data.add_accounts();
new_account_ptr->set_is_present(true);
new_account_ptr->set_id(new_id);
new_account_ptr->set_parent_account_id(parent_account_id);
new_account_ptr->set_name(account_name);
new_account_ptr->set_description(description);
new_account_ptr->set_is_active(is_active);
return new_account_ptr;
}
void AdminServiceUtils::update_account(bts::api::admin::AdminData& admin_data,
const bts::api::admin::BTSAccount& updated_account,
bts::api::admin::AdminServiceOperationResult& result){
validate_account_update (admin_data, updated_account, result);
if (result.is_success()){
bts::api::admin::BTSAccount* account_ptr = find_account(admin_data, updated_account.id());
account_ptr->CopyFrom(updated_account);
}
}
void AdminServiceUtils::delete_account (bts::api::admin::AdminData& admin_data,
const bts::api::admin::IDAPIArgument& id,
bts::api::admin::AdminServiceOperationResult& result){
result.set_is_success(true);
api::admin::BTSAccount* account_ptr = AdminServiceUtils::find_account(admin_data, id.id());
if (account_ptr != nullptr)
{
std::string deleted_name;
int deleted_idx = 0;
do{
deleted_idx++;
deleted_name = deleted_idx == 1 ? fmt::format("DELETED_{}", account_ptr->name()) :
fmt::format("DELETED_{}_{}", deleted_idx, account_ptr->name());
}
while(AdminServiceUtils::find_account(admin_data, deleted_name, true) != nullptr);
account_ptr->set_is_present(false);
account_ptr->set_name(deleted_name);
}
else{
result.set_is_success(false);
result.set_error_text("Could not find account");
}
}
void AdminServiceUtils::set_account_exchange_data(bts::api::admin::BTSAccount* account,
const bts::api::admin::ExchangeAccountData& exchange_data){
account->mutable_exchange_account_data()->CopyFrom(exchange_data);
}
void AdminServiceUtils::sync_account_connections(const bts::api::admin::AdminData& data,
bts::api::admin::BTSAccount& account){
if(account.has_connections()){
std::map<std::string, bool> all_conn_names;
for(int i=0; i< data.connections_size(); i++)
all_conn_names[data.connections(i).name()]=true;
std::vector<std::string> cleaned_connections;
for(int i=0; i<account.connections().exchange_connection_names_size();i++){
const std::string& conn_name=account.connections().exchange_connection_names(i);
if(all_conn_names.find(conn_name)!=all_conn_names.end())
cleaned_connections.push_back(conn_name);
}
account.mutable_connections()->mutable_exchange_connection_names()->Clear();
for(auto it=cleaned_connections.begin(); it!= cleaned_connections.end(); it++)
account.mutable_connections()->add_exchange_connection_names(*it);
}
}
////////////////////////////////////////////
// group accessors /////////////////////////
////////////////////////////////////////////
bts::api::admin::BTSUserGroup* AdminServiceUtils::find_group (bts::api::admin::AdminData& data,
uint32_t id){
for(int i=0; i<data.user_groups_size();i++){
bts::api::admin::BTSUserGroup* group = data.mutable_user_groups(i);
if(id == group->id())
return group;
}
return nullptr;
}
const bts::api::admin::BTSUserGroup* const AdminServiceUtils::find_group (const bts::api::admin::AdminData& data,
uint32_t id){
for(const bts::api::admin::BTSUserGroup& group : data.user_groups())
if(id == group.id())
return &group;
return nullptr;
}
bts::api::admin::BTSUserGroup* AdminServiceUtils::find_group (bts::api::admin::AdminData& data,
const std::string& group_name){
for(int i=0; i<data.user_groups_size();i++){
bts::api::admin::BTSUserGroup* group = data.mutable_user_groups(i);
if(group_name == group->name())
return group;
}
return nullptr;
}
uint32_t AdminServiceUtils::find_max_group_id (const bts::api::admin::AdminData& data){
uint32_t rv = 0;
for(const bts::api::admin::BTSUserGroup& group : data.user_groups())
if (group.id() > rv)
rv = group.id();
return rv;
}
const bts::api::admin::CMEUserData* AdminServiceUtils::get_group_cme_data(const bts::api::admin::BTSUserGroup& group,
const bts::api::admin::AdminData& data){
if (group.has_user_data() && group.user_data().has_exchange_user_data() && group.user_data().exchange_user_data().has_cme_data())
return &(group.user_data().exchange_user_data().cme_data());
else if (has_id(group.parent_group_id())){
const bts::api::admin::BTSUserGroup* parent_group = find_group(data, group.parent_group_id());
if (parent_group != nullptr)
return get_group_cme_data(*parent_group, data);
}
return nullptr;
}
const bts::api::admin::UserAccountPermissions* const AdminServiceUtils::get_group_user_permissions (const bts::api::admin::AdminData& admin_data,
uint32_t group_id){
const bts::api::admin::BTSUserGroup* const group = find_group(admin_data, group_id);
if(group != nullptr){
if (group->has_user_data() && group->user_data().has_account_permissions())
return &group->user_data().account_permissions();
if (has_id(group->parent_group_id()))
return get_group_user_permissions(admin_data, group->parent_group_id());
}
return nullptr;
}
////////////////////////////////////////////
// group mutators //////////////////////////
////////////////////////////////////////////
bts::api::admin::BTSUserGroup* AdminServiceUtils::create_group(bts::api::admin::AdminData& data,
uint32_t parent_group_id,
const std::string& group_name,
bts::api::admin::AdminServiceOperationResult& result){
// the error conditions are checked first and returned immediatly
// i. account with the name already exists
// ii. parent account is set and does not exist
result.set_is_success(true);
if (find_group (data, group_name) != nullptr){
result.set_is_success(false);
result.set_error_text("Group by this name already exists");
return nullptr;
}
if (has_id(parent_group_id)){
if(find_group(data, parent_group_id) == nullptr){
result.set_is_success(false);
result.set_error_text("Parent group does not exist");
return nullptr;
}
}
uint32_t new_id = find_max_group_id(data)+1;
bts::api::admin::BTSUserGroup* new_group_ptr = data.add_user_groups();
new_group_ptr->set_id(new_id);
new_group_ptr->set_parent_group_id(parent_group_id);
new_group_ptr->set_name(group_name);
return new_group_ptr;
}
////////////////////////////////////////////
// user accessors //////////////////////////
////////////////////////////////////////////
bts::api::admin::BTSUser* AdminServiceUtils::find_user (bts::api::admin::AdminData& data, const std::string& user_name,
bool include_deleted){
auto user_ptrs = users_mutable(data,include_deleted);
for(auto user_ptr : user_ptrs){
if(user_name==user_ptr->name())
return user_ptr;
}
return nullptr;
}
const bts::api::admin::BTSUser* AdminServiceUtils::find_user (const bts::api::admin::AdminData& data, const std::string& user_name,
bool include_deleted){
auto user_ptrs = users(data,include_deleted);
for (auto user_ptr : user_ptrs)
if(user_name==user_ptr->name())
return user_ptr;
return nullptr;
}
bts::api::admin::BTSUser* AdminServiceUtils::find_user (bts::api::admin::AdminData& data, uint32_t id,
bool include_deleted){
auto user_ptrs = users_mutable(data,include_deleted);
for(auto user_ptr : user_ptrs){
if(id==user_ptr->id())
return user_ptr;
}
return nullptr;
}
const bts::api::admin::BTSUser* const AdminServiceUtils::find_user (const bts::api::admin::AdminData& data,uint32_t id,
bool include_deleted){
auto user_ptrs = users(data,include_deleted);
for (auto user_ptr : user_ptrs)
if(id==user_ptr->id())
return user_ptr;
return nullptr;
}
std::vector<const bts::api::admin::BTSUser*> AdminServiceUtils::users (const bts::api::admin::AdminData& data,
bool include_deleted){
std::vector<const bts::api::admin::BTSUser*> rv;
for (const bts::api::admin::BTSUser& user : data.users())
if (user.is_present() || include_deleted)
rv.push_back(&user);
return rv;
}
std::vector<bts::api::admin::BTSUser*> AdminServiceUtils::users_mutable (bts::api::admin::AdminData& data,
bool include_deleted){
std::vector<bts::api::admin::BTSUser*> rv;
for(int i=0; i<data.users_size(); i++){
auto user_ptr = data.mutable_users(i);
if (user_ptr->is_present() || include_deleted)
rv.push_back(user_ptr);
}
return rv;
}
uint32_t AdminServiceUtils::find_max_user_id (const bts::api::admin::AdminData& data){
uint32_t rv = 0;
auto user_ptrs = users(data,true);
for(auto user_ptr : user_ptrs)
if (user_ptr->id() > rv)
rv = user_ptr->id();
return rv;
}
const bts::api::admin::CMEUserData* AdminServiceUtils::get_user_cme_data(const bts::api::admin::BTSUser& user,
const bts::api::admin::AdminData& data){
if (user.has_user_data() && user.user_data().has_exchange_user_data() && user.user_data().exchange_user_data().has_cme_data())
return &(user.user_data().exchange_user_data().cme_data());
else{
const bts::api::admin::BTSUserGroup* parent_group = find_group(data, user.parent_group_id());
if (parent_group != nullptr)
return get_group_cme_data(*parent_group, data);
}
return nullptr;
}
// finds the "exchange user" (ex: "operator_id" at CME or "authorized_trader"
// at ICE) for a user
std::string AdminServiceUtils::find_user_exchange_id (const bts::api::admin::AdminData& data,
const bts::api::admin::BTSUser& user,
api::Venue exchange,
bts::api::admin::AdminServiceOperationResult& out_result){
const api::admin::CMEUserData* cme_user_data;
out_result.set_is_success(true);
std::string rv = "";
switch(exchange)
{
case api::Venue::VENUE_GLBX:
cme_user_data = get_user_cme_data(user, data);
if (cme_user_data != nullptr)
rv = cme_user_data->operator_id();
break;
case api::Venue::VENUE_UNSET:
case api::Venue::VENUE_BTS:
case api::Venue::VENUE_CBOE:
case api::Venue::VENUE_CBOECFE:
case api::Venue::VENUE_ICE:
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
out_result.set_is_success(false); out_result.set_error_text("Exchange not supported");
break;
}
return rv;
}
std::pair<const bts::api::admin::BTSAccount*, const bts::api::admin::BTSUser*>
AdminServiceUtils::find_user_account_matches (const bts::api::admin::AdminData& admin_data,
const std::string& connection, const std::string& exchange_account,
const std::string& exchange_user,
api::Venue exchange){
bts::api::admin::AdminServiceOperationResult find_account_result, find_user_result;
auto account_ptrs = accounts(admin_data, false);
auto user_ptrs = users(admin_data, false);
for(const bts::api::admin::BTSAccount* account_ptr : account_ptrs){
if (account_has_connection(*account_ptr, connection)){
if (exchange_account == find_account_exchange_account(admin_data,*account_ptr,exchange,find_account_result) && find_account_result.is_success()){
for(const bts::api::admin::BTSUser* user_ptr : user_ptrs){
if (exchange_user == find_user_exchange_id(admin_data,*user_ptr,exchange,find_user_result) && find_user_result.is_success())
return std::pair<const bts::api::admin::BTSAccount*, const bts::api::admin::BTSUser*>(account_ptr,user_ptr);
}
}
}
}
return std::pair<const bts::api::admin::BTSAccount*, const bts::api::admin::BTSUser*>(nullptr, nullptr);
}
// for a given user finds the account permissions (if permissions are
// derived from the group, it traverses the group hierarcy to find the
// correct permissions.
const bts::api::admin::UserAccountPermissions* AdminServiceUtils::get_user_permissions (const bts::api::admin::AdminData& admin_data,
uint32_t user_id){
const bts::api::admin::BTSUser* const user = find_user(admin_data, user_id);
if(user != nullptr){
if (user->has_user_data() && user->user_data().has_account_permissions())
return &user->user_data().account_permissions();
else
return get_group_user_permissions(admin_data, user->parent_group_id());
}
return nullptr;
}
// for a given user, fills in the associated_accounts ref arg
// with the accounts the user has permission to trade in
void AdminServiceUtils::find_user_trading_accounts (const bts::api::admin::AdminData& admin_data,
uint32_t user_id,
std::vector<const api::admin::BTSAccount*>& associated_accounts){
const bts::api::admin::UserAccountPermissions* user_perm_ptr = get_user_permissions (admin_data, user_id);
if (user_perm_ptr != nullptr)
for(auto it=user_perm_ptr->account_permissions().begin(); it!=user_perm_ptr->account_permissions().end(); it++)
if (it->second.has_trading_permission()){
const api::admin::BTSAccount* account_ptr = find_account(admin_data, it->first);
if (account_ptr != nullptr)
associated_accounts.push_back(account_ptr);
}
}
void AdminServiceUtils::validate_user_update (const bts::api::admin::AdminData& admin_data,
const bts::api::admin::BTSUser& updated_user,
bts::api::admin::AdminServiceOperationResult& result){
result.set_is_success(true);
// validate id
if(find_user(admin_data, updated_user.id()) == nullptr){
result.set_is_success(false);
result.set_error_text("Could not find user id");
return;
}
// validate that name change doesnt collide
auto user_ptrs = users(admin_data,true);
for (auto user_ptr : user_ptrs)
if (user_ptr->id() != updated_user.id() && user_ptr->name() == updated_user.name()){
result.set_is_success(false);
result.set_error_text("User by this name already exists");
return;
}
validate_user_exchange_data (updated_user, result);
}
void AdminServiceUtils::validate_user_exchange_data (const bts::api::admin::BTSUser& user,
bts::api::admin::AdminServiceOperationResult& result){
result.set_is_success(true);
// this is not right (should navigate to the group)
if (user.has_user_data() && user.user_data().has_exchange_user_data() && user.user_data().exchange_user_data().has_cme_data()){
const api::admin::CMEUserData& cme_user_data = user.user_data().exchange_user_data().cme_data();
if (cme_user_data.operator_id().size() > 18){
result.set_is_success(false);
result.set_error_text("CME operator id can not be more 12 characters long");
}
}
}
////////////////////////////////////////////
// user mutators ///////////////////////////
////////////////////////////////////////////
bts::api::admin::BTSUser* AdminServiceUtils::create_user (bts::api::admin::AdminData& data,
uint32_t parent_group_id,
const std::string& name,
const std::string& password,
bool is_active,
const bts::api::admin::LicenseData& license_data,
const bts::api::admin::LicenseEntitlements& license_entitlements,
bts::api::admin::AdminServiceCreateEntityResult& result){
result.set_is_success(true);
// the error conditions are checked first and returned immediatly
// i. user with the name already exists
// ii. parent group does not exist
if (find_user (data, name, true) != nullptr){
result.set_is_success(false);
result.set_error_text("User by this name already exists");
return nullptr;
}
if (find_group(data, parent_group_id) == nullptr){
result.set_is_success(false);
result.set_error_text("Parent group does not exist");
return nullptr;
}
uint32_t new_id = AdminServiceUtils::find_max_user_id(data)+1;
bts::api::admin::BTSUser* new_user_ptr = data.add_users();
new_user_ptr->set_is_present(true);
new_user_ptr->set_id(new_id);
new_user_ptr->set_parent_group_id(parent_group_id);
new_user_ptr->set_name(name);
new_user_ptr->set_password (password);
new_user_ptr->set_is_active(is_active);
new_user_ptr->mutable_license_data()->CopyFrom(license_data);
new_user_ptr->mutable_license_entitlements()->CopyFrom(license_entitlements);
result.set_new_id(new_id);
return new_user_ptr;
}
void AdminServiceUtils::set_user_exchange_data(bts::api::admin::BTSUser* user,
const bts::api::admin::ExchangeUserData& exchange_user_data){
if (!user->has_user_data())
user->mutable_user_data();
if (!user->user_data().has_exchange_user_data())
user->mutable_user_data()->mutable_exchange_user_data()->CopyFrom(exchange_user_data);
}
void AdminServiceUtils::set_user_md_entitlement_data(bts::api::admin::BTSUser* user,
const bts::api::admin::ExchangeUserMarketDataEntitlementData& exchange_user_md_entitelemnt_data){
if (!user->has_user_data())
user->mutable_user_data();
if (!user->user_data().has_exchange_md_entitlement_data())
user->mutable_user_data()->mutable_exchange_md_entitlement_data()->CopyFrom(exchange_user_md_entitelemnt_data);
}
void AdminServiceUtils::clear_user_accounts (bts::api::admin::BTSUser* user){
if(user->has_user_data() && user->user_data().has_account_permissions())
user->mutable_user_data()->clear_account_permissions();
}
void AdminServiceUtils::set_user_accounts (bts::api::admin::BTSUser* user, const bts::api::admin::UserAccountPermissions& user_account_permissions){
if(!user->has_user_data())
user->mutable_user_data();
user->mutable_user_data()->mutable_account_permissions()->CopyFrom(user_account_permissions);
}
bts::api::admin::BTSUser* AdminServiceUtils::update_user(bts::api::admin::AdminData& admin_data,
const bts::api::admin::BTSUser& updated_user,
bts::api::admin::AdminServiceOperationResult& result){
validate_user_update(admin_data, updated_user, result);
if (result.is_success()){
bts::api::admin::BTSUser* user_ptr = find_user(admin_data, updated_user.id());
user_ptr->CopyFrom(updated_user);
return user_ptr;
}
else
return nullptr;
}
void AdminServiceUtils::delete_user (bts::api::admin::AdminData& admin_data,
const bts::api::admin::IDAPIArgument& id,
bts::api::admin::AdminServiceOperationResult& result){
result.set_is_success(true);
api::admin::BTSUser* user_ptr = AdminServiceUtils::find_user(admin_data, id.id());
if (user_ptr != nullptr)
{
std::string deleted_name;
int deleted_idx = 0;
do{
// keep going until the modified name is not found,
// otherwise keep "incrementing" the modified name
deleted_idx++;
deleted_name = deleted_idx == 1 ? fmt::format("DELETED_{}", user_ptr->name()) :
fmt::format("DELETED_{}_{}", deleted_idx, user_ptr->name());
}
while(AdminServiceUtils::find_user(admin_data, deleted_name, true) != nullptr);
user_ptr->set_is_present(false);
user_ptr->set_name(deleted_name);
}
else{
result.set_is_success(false);
result.set_error_text("Could not find user");
}
}
////////////////////////////////////////////
//risk limits //////////////////////////////
////////////////////////////////////////////
bool AdminServiceUtils::_sort_security_scopes (const bts::api::admin::SecurityScope& a,
const bts::api::admin::SecurityScope& b){
if (has_id(a.security_id()))
return true;
if (has_id(b.security_id()))
return false;
if (a.security_symbol() != "*")
return true;
return false;
}
bool AdminServiceUtils::_sort_product_scopes (const bts::api::admin::ProductScope& a,
const bts::api::admin::ProductScope&){
if (a.security_symbol() != "*")
return true;
return false;
}
void AdminServiceUtils::sort_limits (bts::api::admin::BTSAccount& account){
std::sort (account.mutable_security_position_limits()->begin(),
account.mutable_security_position_limits()->end(),
[](const bts::api::admin::AccountSecurityPositionLimitUnit& a, const bts::api::admin::AccountSecurityPositionLimitUnit& b){
return _sort_security_scopes(a.security(), b.security());
});
std::sort (account.mutable_product_position_limits()->begin(),
account.mutable_product_position_limits()->end(),
[](const bts::api::admin::AccountProductPositionLimitUnit& a, const bts::api::admin::AccountProductPositionLimitUnit& b){
return _sort_product_scopes(a.product(), b.product());
});
if (account.has_security_clip_limits())
std::sort (account.mutable_security_clip_limits()->mutable_limit()->begin(),
account.mutable_security_clip_limits()->mutable_limit()->end(),
[](const bts::api::admin::AccountSecurityClipLimitUnit& a, const bts::api::admin::AccountSecurityClipLimitUnit& b){
return _sort_security_scopes(a.security(), b.security());
});
}
bts::api::admin::AdminData AdminServiceUtils::sort_limits (const bts::api::admin::AdminData& admin_data){
bts::api::admin::AdminData rv;
rv.CopyFrom(admin_data);
for(int i=0; i<rv.accounts_size();i++)
sort_limits(*rv.mutable_accounts(i));
return rv;
}
// find the clip size for a security, account
const uint32_t AdminServiceUtils::find_account_security_clip_size(const bts::api::admin::BTSAccount& account,
const api::Security& security){
uint32_t rv = 0;
if (account.has_security_clip_limits())
for(const auto& limit : account.security_clip_limits().limit()){
if(match_security_scope(limit.security(), security))
return limit.clip_size();
}
return rv;
}
// find the position limit for an account, security
const bts::api::admin::AccountSecurityPositionLimitUnit* AdminServiceUtils::find_account_security_position_limit(const bts::api::admin::BTSAccount& account,
const api::Security& security){
for(const auto& limit : account.security_position_limits())
if(match_security_scope(limit.security(), security))
return &limit;
return nullptr;
}
// find the position limit for an account, product
const bts::api::admin::AccountProductPositionLimitUnit* AdminServiceUtils::find_account_product_position_limit(const bts::api::admin::BTSAccount& account,
const api::Product& product){
for(const auto& limit : account.product_position_limits())
if(match_product_scope(limit.product(), product))
return &limit;
return nullptr;
}
bool AdminServiceUtils::match_security_scope (const bts::api::admin::SecurityScope& scope,
const bts::api::Security& security){
if(has_id(scope.security_id())){
if (scope.security_id() == security.id())
return true;
}
else if (security.exchange() == scope.exchange() &&
security_type(security) == scope.security_type() &&
_match_limit_rule_symbol(security.symbol(), scope.security_symbol()))
return true;
return false;
}
bool AdminServiceUtils::match_product_scope (const bts::api::admin::ProductScope& scope,
const bts::api::Product& product){
return product.exchange() == scope.exchange() &&
product.type() && scope.security_type() &&
_match_limit_rule_symbol(product.symbol(), scope.security_symbol());
}
bool AdminServiceUtils::match_product(const api::Security& security,
const api::Product& product){
return product.exchange() == security.exchange() &&
product.type() == security_type(security) &&
product.symbol() == security.symbol();
}
bool AdminServiceUtils::_match_limit_rule_symbol (const std::string& symbol,
const std::string& limit_symbol){
return limit_symbol=="*" || symbol==limit_symbol;
}
api::SecurityType AdminServiceUtils::security_type(const api::Security& security){
switch(security.Contract_case())
{
case api::Security::ContractCase::kFuture:
return api::SecurityType::SECURITYTYPE_FUTURE;
case api::Security::ContractCase::kOption:
return api::SecurityType::SECURITYTYPE_OPTION;
case api::Security::ContractCase::kSpread:
return api::SecurityType::SECURITYTYPE_SPREAD;
case api::Security::ContractCase::kSynthetic:
return api::SecurityType::SECURITYTYPE_SYNTHETIC;
case api::Security::ContractCase::CONTRACT_NOT_SET:
return api::SecurityType::SECURITYTYPE_UNSET;
}
return api::SecurityType::SECURITYTYPE_UNSET;
}
////////////////////////////////////////////
// boostrapping ////////////////////////////
////////////////////////////////////////////
void AdminServiceUtils::bootstrap_data (bts::api::admin::AdminData& data){
data.set_id(1);
bts::api::admin::AdminServiceOperationResult result;
bts::api::admin::AdminServiceCreateAccountResult account_result;
bts::api::admin::AdminServiceCreateEntityResult user_result;
// adding accounts
auto parent_account = create_account(data, 0, std::string("ACC A"), std::string("description"), true, account_result);
auto account_1 = create_account(data, parent_account->id(), std::string("ACC A1"), std::string("description"), true, account_result); account_1->set_is_active(true);
auto account_2 = create_account(data, parent_account->id(), std::string("ACC A2"), std::string("description"), true, account_result); account_2->set_is_active(true);
auto account_3 = create_account(data, parent_account->id(), std::string("ACC A3"), std::string("description"), true, account_result); account_3->set_is_active(true);
create_account(data, parent_account->id(), std::string("ACC A4"), std::string("description"), true, account_result);
// add group
auto def_group = create_group(data, 0, std::string("DEFAULT"), result);
// adding users to the group
bts::api::admin::LicenseData license_data;
bts::api::admin::LicenseEntitlements license_entitlements;
auto user_1 = create_user(data, def_group->id(), std::string("bts"), std::string(""), false, license_data, license_entitlements, user_result); user_1->set_is_active(true);
auto user_2 = create_user(data, def_group->id(), std::string("bts_2"), std::string("bts_2"), false, license_data, license_entitlements, user_result); user_2->set_is_active(true);
auto user_3 = create_user(data, def_group->id(), std::string("bts_3"), std::string("bts_3"), false, license_data, license_entitlements, user_result); user_3->set_is_active(true);
//associate users
bts::api::admin::UserAccountPermissionUnit permission_unit;
permission_unit.mutable_trading_permission()->set_submit_market_orders(true);
permission_unit.mutable_admin_permission()->set_has_permissions(true);
bts::api::admin::UserAccountPermissions account_permissions;
account_permissions.mutable_account_permissions()->insert(google::protobuf::MapPair<uint32_t, bts::api::admin::UserAccountPermissionUnit>(parent_account->id(), permission_unit));
account_permissions.mutable_account_permissions()->insert(google::protobuf::MapPair<uint32_t, bts::api::admin::UserAccountPermissionUnit>(account_1->id(), permission_unit));
account_permissions.mutable_account_permissions()->insert(google::protobuf::MapPair<uint32_t, bts::api::admin::UserAccountPermissionUnit>(account_2->id(), permission_unit));
account_permissions.mutable_account_permissions()->insert(google::protobuf::MapPair<uint32_t, bts::api::admin::UserAccountPermissionUnit>(account_3->id(), permission_unit));
set_user_accounts(user_1, account_permissions);
set_user_accounts(user_2, account_permissions);
set_user_accounts(user_3, account_permissions);
// add cme account data
bts::api::admin::ExchangeAccountData exchange_account_data;
exchange_account_data.mutable_cme_account_data()->set_cti(bts::api::orderman::CTICode::CTI_CODE_CTI_CODE1);
exchange_account_data.mutable_cme_account_data()->set_origin(bts::api::orderman::CustomerOrFirm::CUSTOMER_OR_FIRM_FIRM);
exchange_account_data.mutable_cme_account_data()->set_clearing_account("ca_" + parent_account->name());
set_account_exchange_data(parent_account, exchange_account_data);
exchange_account_data.mutable_cme_account_data()->set_clearing_account("ca_" + account_1->name());
set_account_exchange_data(account_1, exchange_account_data);
exchange_account_data.mutable_cme_account_data()->set_clearing_account("ca_" + account_2->name());
set_account_exchange_data(account_2, exchange_account_data);
exchange_account_data.mutable_cme_account_data()->set_clearing_account("ca_" + account_3->name());
set_account_exchange_data(account_3, exchange_account_data);
// add cme user data
bts::api::admin::ExchangeUserData exchange_user_data;
exchange_user_data.mutable_cme_data()->set_operator_id("op_id_" + user_1->name());
set_user_exchange_data(user_1, exchange_user_data);
exchange_user_data.mutable_cme_data()->set_operator_id("op_id_" + user_2->name());
set_user_exchange_data(user_2, exchange_user_data);
exchange_user_data.mutable_cme_data()->set_operator_id("op_id_" + user_3->name());
set_user_exchange_data(user_3, exchange_user_data);
// associate all connections to all accounts
for(int i=0; i<data.connections_size();i++){
std::string conn_name = data.connections(i).name();
for(int j=0; j<data.accounts_size();j++)
data.mutable_accounts(j)->mutable_connections()->add_exchange_connection_names(conn_name);
}
// add prod limit for ACC A
auto acct_a_prod_limit = parent_account->add_product_position_limits();
acct_a_prod_limit->mutable_product()->set_exchange(api::Venue::VENUE_GLBX);
acct_a_prod_limit->mutable_product()->set_security_type(api::SecurityType::SECURITYTYPE_FUTURE);
acct_a_prod_limit->mutable_product()->set_security_symbol("*");
acct_a_prod_limit->set_long_position_limit(500000);
acct_a_prod_limit->set_short_position_limit(500000);
// security clip sizes for ACC A
auto acct_a_clip_size = parent_account->mutable_security_clip_limits()->add_limit();
acct_a_clip_size->mutable_security()->set_exchange(api::Venue::VENUE_GLBX);
acct_a_clip_size->mutable_security()->set_security_type(api::SecurityType::SECURITYTYPE_FUTURE);
acct_a_clip_size->mutable_security()->set_security_symbol("*");
acct_a_clip_size->set_clip_size(50);
// add sec limit for ACC A1
auto acct_a1_sec_limit = account_1->add_security_position_limits();
acct_a1_sec_limit->mutable_security()->set_exchange(api::Venue::VENUE_GLBX);
acct_a1_sec_limit->mutable_security()->set_security_type(api::SecurityType::SECURITYTYPE_FUTURE);
acct_a1_sec_limit->mutable_security()->set_security_symbol("*");
acct_a1_sec_limit->set_long_position_limit (10000);
acct_a1_sec_limit->set_short_position_limit (10000);
// add prod limit for ACC A1
auto acct_a1_prod_limit = account_1->add_product_position_limits();
acct_a1_prod_limit->mutable_product()->set_exchange(api::Venue::VENUE_GLBX);
acct_a1_prod_limit->mutable_product()->set_security_type(api::SecurityType::SECURITYTYPE_FUTURE);
acct_a1_prod_limit->mutable_product()->set_security_symbol("*");
acct_a1_prod_limit->set_long_position_limit(1000000);
acct_a1_prod_limit->set_short_position_limit(1000000);
// security clip sizes for ACC A1
auto acct_a1_clip_size = account_1->mutable_security_clip_limits()->add_limit();
acct_a1_clip_size->mutable_security()->set_exchange(api::Venue::VENUE_GLBX);
acct_a1_clip_size->mutable_security()->set_security_type(api::SecurityType::SECURITYTYPE_FUTURE);
acct_a1_clip_size->mutable_security()->set_security_symbol("*");
acct_a1_clip_size->set_clip_size(100);
}
bool AdminServiceUtils::has_id (uint32_t id){return id>0;}
}}