This commit is contained in:
WolverinDEV 2019-08-16 16:13:52 +02:00
parent bae6a56ed3
commit aa3de59652
14 changed files with 454 additions and 279 deletions

View File

@ -57,18 +57,18 @@ struct Group {
deque<permission::update::UpdatePermission> permissions; deque<permission::update::UpdatePermission> permissions;
}; };
map<Target, map<string, string>> property_mapping = { map<Target, map<string, vector<string>>> property_mapping = {
{TARGET_QUERY, { {TARGET_QUERY, {
{"Guest Server Query", "serverinstance_guest_serverquery_group"}, {"Guest Server Query", {"serverinstance_guest_serverquery_group"}},
{"Admin Server Query", "serverinstance_admin_serverquery_group"} {"Admin Server Query", {"serverinstance_admin_serverquery_group"}}
}}, }},
{TARGET_SERVER, { {TARGET_SERVER, {
{"Server Admin", "serverinstance_template_serveradmin_group"}, {"Server Admin", {"serverinstance_template_serveradmin_group"}},
{"Guest", "serverinstance_template_serverdefault_group"} {"Guest", {"serverinstance_template_serverdefault_group", "serverinstance_template_musicdefault_group"}}
}}, }},
{TARGET_CHANNEL, { {TARGET_CHANNEL, {
{"Channel Admin", "serverinstance_template_channeladmin_group"}, {"Channel Admin", {"serverinstance_template_channeladmin_group"}},
{"Guest", "serverinstance_template_channeldefault_group"} {"Guest", {"serverinstance_template_channeldefault_group"}}
}}, }},
}; };
@ -125,7 +125,7 @@ int main(int argc, char** argv) {
deque<Group> groups; deque<Group> groups;
{ {
ifstream file("../helpers/server_groups_new"); /* the new file is already mapped! */ ifstream file("../helpers/server_groups"); /* the new file is already mapped! */
string line; string line;
while (read_line(file, line)) while (read_line(file, line))
{ {
@ -242,7 +242,8 @@ int main(int argc, char** argv) {
of << "--start" << endl; of << "--start" << endl;
of << "name:" << group.name << endl; of << "name:" << group.name << endl;
of << "target:" << group.target << endl; of << "target:" << group.target << endl;
of << "property:" << property_mapping[group.target][group.name] << endl; for(const auto& property : property_mapping[group.target][group.name])
of << "property:" << property << endl;
for(const auto& perm : group.permissions) { for(const auto& perm : group.permissions) {
of << "permission:" << perm.name << "=" << perm.value << "," << perm.granted << "," << perm.skipped << "," << perm.negated << endl; of << "permission:" << perm.name << "=" << perm.value << "," << perm.granted << "," << perm.skipped << "," << perm.negated << endl;
} }

File diff suppressed because one or more lines are too long

View File

@ -1363,7 +1363,7 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
} }
{ {
CREATE_BINDING("unmute_message", 0); CREATE_BINDING("unmute_message", 0);
BIND_STRING(config::messages::mute_notify_message, "Hey!\nI unmuted you!"); BIND_STRING(config::messages::unmute_notify_message, "Hey!\nI unmuted you!");
} }
} }
{ {

View File

@ -616,7 +616,6 @@ void DatabaseHelper::saveChannelPermissions(const std::shared_ptr<ts::server::TS
} }
} }
#define DBSAVE_MUSIC_BOT (type == CLIENT_MUSIC ? PROP_DB_SAVE : 0)
void DatabaseHelper::assign_default_properties_client(Properties *properties, ClientType type){ void DatabaseHelper::assign_default_properties_client(Properties *properties, ClientType type){
Properties& _properties = *properties; Properties& _properties = *properties;
@ -624,91 +623,12 @@ void DatabaseHelper::assign_default_properties_client(Properties *properties, Cl
_properties.register_property_type<property::ConnectionProperties>(); _properties.register_property_type<property::ConnectionProperties>();
if(type == ClientType::CLIENT_MUSIC){ if(type == ClientType::CLIENT_MUSIC){
//_properties.registerProperty("channel_last", 0, PROP_DB_SAVE);
//_properties.registerProperty("bot_owner", 0, PROP_TEMP); //saved in bot table
//_properties.registerProperty("music_volume", 1.f, PROP_DB_SAVE);
//_properties.registerProperty("music_track_id", 0, PROP_CLIENT_VARIABLE | PROP_CLIENT_VIEW_INFO | PROP_NEW);
//_properties.registerProperty("music_player_state", 0, PROP_CLIENT_VARIABLE | PROP_CLIENT_VIEW_INFO | PROP_NEW);
_properties[property::CLIENT_INPUT_HARDWARE] = true; _properties[property::CLIENT_INPUT_HARDWARE] = true;
_properties[property::CLIENT_OUTPUT_HARDWARE] = true; _properties[property::CLIENT_OUTPUT_HARDWARE] = true;
} else if(type == ClientType::CLIENT_QUERY) { } else if(type == ClientType::CLIENT_QUERY) {
_properties[property::CLIENT_INPUT_HARDWARE] = true; _properties[property::CLIENT_INPUT_HARDWARE] = true;
_properties[property::CLIENT_OUTPUT_HARDWARE] = true; _properties[property::CLIENT_OUTPUT_HARDWARE] = true;
} }
/*
_properties.registerProperty("client_type", type, PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_type_exact", type, PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("clid", 0, PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO | PROP_CLIENT_VARIABLE);
_properties.registerProperty("client_database_id", 0, PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("hwid", "", PROP_PRIVATE | PROP_DB_SAVE);
_properties.registerProperty("connection_client_ip", "undefined", PROP_PRIVATE | PROP_DB_SAVE | PROP_SNAPSHOT);
_properties.registerProperty("client_version", "unknown", PROP_CLIENT_VARIABLE | PROP_CLIENT_VIEW_INFO | PROP_DB_SAVE | PROP_SNAPSHOT);
_properties.registerProperty("client_platform", "unknown", PROP_CLIENT_VARIABLE | PROP_CLIENT_VIEW_INFO | PROP_DB_SAVE | PROP_SNAPSHOT);
_properties.registerProperty("client_login_name", "", PROP_CLIENT_VARIABLE);
_properties.registerProperty("client_created", 0, PROP_SERVER_BOUND | PROP_CLIENT_VARIABLE | DBSAVE_MUSIC_BOT | PROP_SNAPSHOT);
_properties.registerProperty("client_lastconnected", 0, PROP_SERVER_BOUND | DBSAVE_MUSIC_BOT | PROP_CLIENT_VARIABLE | PROP_SNAPSHOT);
_properties.registerProperty("client_totalconnections", 0, PROP_SERVER_BOUND | PROP_CLIENT_VARIABLE | PROP_CLIENT_VIEW_INFO | PROP_SNAPSHOT);
_properties.registerProperty("client_month_bytes_uploaded", 0, PROP_SERVER_BOUND | PROP_CLIENT_VARIABLE);
_properties.registerProperty("client_month_bytes_downloaded", 0, PROP_SERVER_BOUND | PROP_CLIENT_VARIABLE);
_properties.registerProperty("client_total_bytes_uploaded", 0, PROP_SERVER_BOUND | PROP_CLIENT_VARIABLE);
_properties.registerProperty("client_total_bytes_downloaded", 0, PROP_SERVER_BOUND | PROP_CLIENT_VARIABLE);
_properties.registerProperty("connection_server2client_packetloss_keepalive", 0, PROP_SERVER_BOUND);
_properties.registerProperty("connection_server2client_packetloss_control", 0, PROP_SERVER_BOUND);
_properties.registerProperty("connection_server2client_packetloss_speech", 0, PROP_SERVER_BOUND);
_properties.registerProperty("connection_server2client_packetloss_total", 0, PROP_SERVER_BOUND);
_properties.registerProperty("client_unique_identifier", "", PROP_CLIENT_VIEW_INFO | PROP_SNAPSHOT);
_properties.registerProperty("client_nickname", "", PROP_CLIENT_VIEW_INFO | DBSAVE_MUSIC_BOT | PROP_SNAPSHOT);
_properties.registerProperty("client_nickname_phonetic", "", PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_input_muted", false, PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_output_muted", false, PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_outputonly_muted", false, PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_input_hardware", false, PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_output_hardware", false, PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_is_recording", false, PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_meta_data", "", PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO); //unused
_properties.registerProperty("client_channel_group_id", "0", PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_servergroups", "0", PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_away", false, PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_away_message", "", PROP_CLIENT_VIEW_INFO);CLIENT_DESCRIPTION
_properties.registerProperty("client_flag_avatar", "", PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO | PROP_DB_SAVE); //Some random uuid. File id or stuff like that?
_properties.registerProperty("client_description", ts::config::messages::defaultClientDescription, PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO | PROP_DB_SAVE | PROP_SNAPSHOT);
_properties.registerProperty("client_talk_power", 0, PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_talk_request", false, PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_talk_request_msg", "", PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_is_talker", false, PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_is_priority_speaker", false, PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_is_channel_commander", false, PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_unread_messages", 0, PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_needed_serverquery_view_power", 0, PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_icon_id", 0, PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO | PROP_DB_SAVE);
_properties.registerProperty("client_country", ts::config::geo::countryFlag, PROP_CLIENT_VIEW_INFO); //Country shortcuts
_properties.registerProperty("client_channel_group_inherited_channel_id", 0, PROP_SERVER_BOUND | PROP_CLIENT_VIEW_INFO);
_properties.registerProperty("client_badges", "", PROP_CLIENT_VIEW_INFO | PROP_DB_SAVE);
_properties.registerProperty("client_teaforum_id", 0, PROP_CLIENT_VIEW_INFO | PROP_NEW);
_properties.registerProperty("client_teaforum_name", "", PROP_CLIENT_VIEW_INFO | PROP_NEW);
//Client default channel settings
_properties.registerProperty("client_default_channel", "", PROP_PRIVATE);
_properties.registerProperty("client_default_channel_password", "", PROP_PRIVATE);
*/
} }
bool DatabaseHelper::assignDatabaseId(sql::SqlManager *sql, ServerId id, std::shared_ptr<DataClient> cl) { bool DatabaseHelper::assignDatabaseId(sql::SqlManager *sql, ServerId id, std::shared_ptr<DataClient> cl) {
@ -1073,7 +993,7 @@ std::shared_ptr<Properties> DatabaseHelper::loadClientProperties(const std::shar
weak_ptr<TSServer> weak_server = server; weak_ptr<TSServer> weak_server = server;
auto server_id = server ? server->getServerId() : 0; auto server_id = server ? server->getServerId() : 0;
props->registerNotifyHandler([&, weak_server, server_id, cldbid](Property& prop){ //General save props->registerNotifyHandler([&, weak_server, server_id, cldbid, type](Property& prop){ //General save
auto server = weak_server.lock(); auto server = weak_server.lock();
if(!server && server_id != 0) { if(!server && server_id != 0) {
logError(server_id, "Tried to update client permissions of a expired server!"); logError(server_id, "Tried to update client permissions of a expired server!");

View File

@ -97,7 +97,8 @@ InstanceHandler::InstanceHandler(SqlDataManager *sql) : sql(sql) {
sql::command(this->getSql(), sqlQuery, variable{":sid", 0}, variable{":type", property::PropertyType::PROP_TYPE_INSTANCE}, variable{":id", 0}, variable{":key", prop.type().name}, variable{":value", prop.value()}) sql::command(this->getSql(), sqlQuery, variable{":sid", 0}, variable{":type", property::PropertyType::PROP_TYPE_INSTANCE}, variable{":id", 0}, variable{":key", prop.type().name}, variable{":value", prop.value()})
.executeLater().waitAndGetLater(LOG_SQL_CMD, sql::result{1, "future failed"}); .executeLater().waitAndGetLater(LOG_SQL_CMD, sql::result{1, "future failed"});
}); });
this->properties()[property::SERVERINSTANCE_DATABASE_VERSION] = this->sql->getVersion(); this->properties()[property::SERVERINSTANCE_DATABASE_VERSION] = this->sql->get_database_version();
this->properties()[property::SERVERINSTANCE_PERMISSIONS_VERSION] = this->sql->get_permissions_version();
globalServerAdmin = std::make_shared<ts::server::InternalClient>(this->getSql(), nullptr, "serveradmin", true); globalServerAdmin = std::make_shared<ts::server::InternalClient>(this->getSql(), nullptr, "serveradmin", true);

View File

@ -23,7 +23,7 @@ struct GroupInfo {
* 2 = Channel * 2 = Channel
*/ */
int target; int target;
string propertyName; std::deque<string> properties;
string name; string name;
/* permission type, value, granted, skip, negate */ /* permission type, value, granted, skip, negate */
deque<tuple<permission::PermissionType, permission::PermissionValue, permission::PermissionValue, bool, bool>> permissions; deque<tuple<permission::PermissionType, permission::PermissionValue, permission::PermissionValue, bool, bool>> permissions;
@ -62,7 +62,7 @@ bool InstanceHandler::setupDefaultGroups() {
continue; continue;
} }
if(line.find("property:") == 0) { if(line.find("property:") == 0) {
group->propertyName = line.substr(9); group->properties.push_back(line.substr(9));
continue; continue;
} }
@ -132,10 +132,11 @@ bool InstanceHandler::setupDefaultGroups() {
for(auto perm : info->permissions) { for(auto perm : info->permissions) {
group->permissions()->set_permission(get<0>(perm), {get<1>(perm), get<2>(perm)}, permission::v2::set_value, permission::v2::set_value, get<3>(perm), get<4>(perm)); group->permissions()->set_permission(get<0>(perm), {get<1>(perm), get<2>(perm)}, permission::v2::set_value, permission::v2::set_value, get<3>(perm), get<4>(perm));
} }
if(!info->propertyName.empty()) {
const auto& prop = property::impl::info<property::InstanceProperties>(info->propertyName); for(const auto& property : info->properties) {
const auto& prop = property::impl::info<property::InstanceProperties>(property);
if(*prop == property::SERVERINSTANCE_UNDEFINED) { if(*prop == property::SERVERINSTANCE_UNDEFINED) {
logCritical(LOG_INSTANCE, "Invalid template property name: " + info->propertyName); logCritical(LOG_INSTANCE, "Invalid template property name: " + property);
} else { } else {
this->properties()[prop] = group->groupId(); this->properties()[prop] = group->groupId();
} }

View File

@ -209,8 +209,8 @@ void TSServer::testBanStateChange(const std::shared_ptr<ConnectedClient>& invoke
this->forEachClient([&](shared_ptr<ConnectedClient> client) { this->forEachClient([&](shared_ptr<ConnectedClient> client) {
auto ban = client->resolveActiveBan(client->getPeerIp()); auto ban = client->resolveActiveBan(client->getPeerIp());
if(ban) { if(ban) {
debugMessage(this->getServerId(), "Found online client with a active ban. ({})", CLIENT_STR_LOG_PREFIX_(client)); logMessage(this->getServerId(), "Client {} was online, but had an ban whcih effect him has been registered. Disconnecting client.", CLIENT_STR_LOG_PREFIX_(client));
auto entryTime = ban->until.time_since_epoch().count() > 0 ? (uint64_t) duration_cast<seconds>(ban->until - system_clock::now()).count() : 0UL; auto entryTime = ban->until.time_since_epoch().count() > 0 ? (uint64_t) chrono::ceil<seconds>(ban->until - system_clock::now()).count() : 0UL;
this->notify_client_ban(client, invoker, ban->reason, entryTime); this->notify_client_ban(client, invoker, ban->reason, entryTime);
client->closeConnection(system_clock::now() + seconds(1)); client->closeConnection(system_clock::now() + seconds(1));
} }

View File

@ -62,7 +62,7 @@ void TSServer::executeServerTick() {
size_t clientOnline = 0; size_t clientOnline = 0;
size_t queryOnline = 0; size_t queryOnline = 0;
for(const auto& conn : this->getClients()){ for(const auto& conn : client_list){
switch (conn->getType()){ switch (conn->getType()){
case ClientType::CLIENT_TEAMSPEAK: case ClientType::CLIENT_TEAMSPEAK:
case ClientType::CLIENT_TEASPEAK: case ClientType::CLIENT_TEASPEAK:
@ -98,7 +98,7 @@ void TSServer::executeServerTick() {
bool flag_update_spoken = this->spoken_time_timestamp + seconds(30) < system_clock::now(); bool flag_update_spoken = this->spoken_time_timestamp + seconds(30) < system_clock::now();
system_clock::time_point tick_client_begin, tick_client_end = system_clock::now(); system_clock::time_point tick_client_begin, tick_client_end = system_clock::now();
for(const auto& cl : this->getClients()) { for(const auto& cl : client_list) {
tick_client_begin = tick_client_end; tick_client_begin = tick_client_end;
if(cl->server != this) { if(cl->server != this) {
logError(this->getServerId(), "Got registered client, but client does not think hes bound to this server!"); logError(this->getServerId(), "Got registered client, but client does not think hes bound to this server!");

View File

@ -106,20 +106,36 @@ do { \
inline bool permission_require_granted_value(permission::PermissionType type) { inline bool permission_require_granted_value(permission::PermissionType type) {
switch (type) { switch (type) {
case permission::i_permission_modify_power: case permission::i_permission_modify_power:
case permission::i_channel_group_member_add_power: case permission::i_channel_group_member_add_power:
case permission::i_channel_group_member_remove_power: case permission::i_channel_group_member_remove_power:
case permission::i_channel_group_modify_power: case permission::i_channel_group_modify_power:
case permission::i_channel_group_needed_member_add_power:
case permission::i_channel_group_needed_member_remove_power:
case permission::i_channel_group_needed_modify_power:
case permission::i_server_group_member_add_power: case permission::i_server_group_member_add_power:
case permission::i_server_group_member_remove_power: case permission::i_server_group_member_remove_power:
case permission::i_server_group_modify_power: case permission::i_server_group_modify_power:
case permission::i_server_group_needed_member_add_power:
case permission::i_server_group_needed_member_remove_power:
case permission::i_server_group_needed_modify_power:
case permission::i_displayed_group_member_add_power: case permission::i_displayed_group_member_add_power:
case permission::i_displayed_group_member_remove_power: case permission::i_displayed_group_member_remove_power:
case permission::i_displayed_group_modify_power: case permission::i_displayed_group_modify_power:
case permission::i_displayed_group_needed_member_add_power:
case permission::i_displayed_group_needed_member_remove_power:
case permission::i_displayed_group_needed_modify_power:
case permission::i_channel_permission_modify_power: case permission::i_channel_permission_modify_power:
case permission::i_channel_needed_permission_modify_power:
case permission::i_client_permission_modify_power: case permission::i_client_permission_modify_power:
case permission::i_client_needed_permission_modify_power:
case permission::i_client_needed_kick_from_server_power: case permission::i_client_needed_kick_from_server_power:
case permission::i_client_needed_kick_from_channel_power: case permission::i_client_needed_kick_from_channel_power:
@ -1812,6 +1828,8 @@ CommandResult ConnectedClient::handleCommandChannelEdit(Command &cmd) {
} else { } else {
CHANNEL_PERM_TEST(permission::i_channel_create_modify_conversation_history_length, 1, true); CHANNEL_PERM_TEST(permission::i_channel_create_modify_conversation_history_length, 1, true);
} }
} else if (key == "channel_flag_conversation_private") {
CHANNEL_PERM_TEST(permission::b_channel_create_modify_conversation_private, 1, true);
} else { } else {
logCritical( logCritical(
this->getServerId(), this->getServerId(),
@ -2589,7 +2607,6 @@ CommandResult ConnectedClient::handleCommandServerGroupCopy(Command &cmd) {
return CommandResult::Success; return CommandResult::Success;
} }
//servergrouprename sgid=2 name=Operators
CommandResult ConnectedClient::handleCommandServerGroupRename(Command &cmd) { CommandResult ConnectedClient::handleCommandServerGroupRename(Command &cmd) {
CMD_RESET_IDLE; CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(5); CMD_CHK_AND_INC_FLOOD_POINTS(5);
@ -2961,20 +2978,22 @@ CommandResult ConnectedClient::handleCommandServerGroupDelPerm(Command &cmd) {
} }
CommandResult ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command& cmd) { CommandResult ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command& cmd) {
CMD_REQ_SERVER;
CMD_RESET_IDLE; CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(5); CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto ref_server = this->server;
auto group_manager = ref_server ? this->server->groups : &*serverInstance->getGroupManager();
deque<shared_ptr<Group>> groups; deque<shared_ptr<Group>> groups;
for(const auto& group : this->server->groups->availableGroups(false)) { for(const auto& group : group_manager->availableGroups(false)) {
if(group->updateType() == cmd["sgtype"].as<permission::PermissionValue>() && group->target() == GROUPTARGET_SERVER) { if(group->updateType() == cmd["sgtype"].as<permission::PermissionValue>() && group->target() == GROUPTARGET_SERVER) {
if(group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission_value(permission::i_server_group_modify_power, 0), true)) { if(group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission_value(permission::i_server_group_modify_power, 0), true)) {
auto type = group->type(); auto type = group->type();
if(type == GroupType::GROUP_TYPE_QUERY) { if(type == GroupType::GROUP_TYPE_QUERY) {
if(!this->permission_granted(this->cached_permission_value(permission::b_serverinstance_modify_querygroup), 1, true)) if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_serverinstance_modify_querygroup, 1))
continue; continue;
} else if(type == GroupType::GROUP_TYPE_TEMPLATE) { } else if(type == GroupType::GROUP_TYPE_TEMPLATE) {
if(!this->permission_granted(this->cached_permission_value(permission::b_serverinstance_modify_templates), 1, true)) if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_serverinstance_modify_templates, 1))
continue; continue;
} }
groups.push_back(group);//sgtype groups.push_back(group);//sgtype
@ -2986,7 +3005,8 @@ CommandResult ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command&
return CommandResult::Success; return CommandResult::Success;
auto maxValue = this->getPermissionGrantValue(permission::PERMTEST_ORDERED, permission::i_permission_modify_power, this->currentChannel); auto maxValue = this->getPermissionGrantValue(permission::PERMTEST_ORDERED, permission::i_permission_modify_power, this->currentChannel);
bool ignoreGrant = this->permission_granted(this->cached_permission_value(permission::b_permission_modify_power_ignore), 1);
bool ignoreGrant = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_permission_modify_power_ignore, 1);
bool conOnError = cmd[0].has("continueonerror"); bool conOnError = cmd[0].has("continueonerror");
bool checkTp = false; bool checkTp = false;
bool sgroupUpdate = false; bool sgroupUpdate = false;
@ -3029,13 +3049,13 @@ CommandResult ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command&
group->apply_properties_from_permissions(); group->apply_properties_from_permissions();
auto lock = this->_this.lock(); auto lock = this->_this.lock();
auto server = this->server; if(ref_server) {
threads::Thread([checkTp, sgroupUpdate, groups, lock, server]() { threads::Thread([checkTp, sgroupUpdate, groups, lock, ref_server]() {
if(sgroupUpdate) if(sgroupUpdate)
server->forEachClient([](shared_ptr<ConnectedClient> cl) { ref_server->forEachClient([](shared_ptr<ConnectedClient> cl) {
cl->notifyServerGroupList(); cl->notifyServerGroupList();
}); });
server->forEachClient([groups, checkTp](shared_ptr<ConnectedClient> cl) { ref_server->forEachClient([groups, checkTp](shared_ptr<ConnectedClient> cl) {
for(const auto& serverGroup : groups) { for(const auto& serverGroup : groups) {
if (cl->serverGroupAssigned(serverGroup)) { if (cl->serverGroupAssigned(serverGroup)) {
if(cl->update_cached_permissions()) {/* update cached calculated permissions */ if(cl->update_cached_permissions()) {/* update cached calculated permissions */
@ -3050,24 +3070,27 @@ CommandResult ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command&
} }
}); });
}).detach(); }).detach();
}
return CommandResult::Success; return CommandResult::Success;
} }
CommandResult ConnectedClient::handleCommandServerGroupAutoDelPerm(ts::Command& cmd) { CommandResult ConnectedClient::handleCommandServerGroupAutoDelPerm(ts::Command& cmd) {
CMD_REQ_SERVER;
CMD_RESET_IDLE; CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(5); CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto ref_server = this->server;
auto group_manager = ref_server ? this->server->groups : &*serverInstance->getGroupManager();
deque<shared_ptr<Group>> groups; deque<shared_ptr<Group>> groups;
for(const auto& group : this->server->groups->availableGroups(false)) { for(const auto& group : group_manager->availableGroups(false)) {
if(group->updateType() == cmd["sgtype"].as<permission::PermissionValue>() && group->target() == GROUPTARGET_SERVER) { if(group->updateType() == cmd["sgtype"].as<permission::PermissionValue>() && group->target() == GROUPTARGET_SERVER) {
if(group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission_value(permission::i_server_group_modify_power, 0), true)) { if(group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission_value(permission::i_server_group_modify_power, 0), true)) {
auto type = group->type(); auto type = group->type();
if(type == GroupType::GROUP_TYPE_QUERY) { if(type == GroupType::GROUP_TYPE_QUERY) {
if(!this->permission_granted(this->cached_permission_value(permission::b_serverinstance_modify_querygroup), 1, true)) if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_serverinstance_modify_querygroup, 1))
continue; continue;
} else if(type == GroupType::GROUP_TYPE_TEMPLATE) { } else if(type == GroupType::GROUP_TYPE_TEMPLATE) {
if(!this->permission_granted(this->cached_permission_value(permission::b_serverinstance_modify_templates), 1, true)) if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_serverinstance_modify_templates, 1))
continue; continue;
} }
groups.push_back(group);//sgtype groups.push_back(group);//sgtype
@ -3077,7 +3100,7 @@ CommandResult ConnectedClient::handleCommandServerGroupAutoDelPerm(ts::Command&
if(groups.empty()) return CommandResult::Success; if(groups.empty()) return CommandResult::Success;
bool ignoreGrant = this->permission_granted(this->cached_permission_value(permission::b_permission_modify_power_ignore), 1); bool ignoreGrant = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_permission_modify_power_ignore, 1);
bool conOnError = cmd[0].has("continueonerror"); bool conOnError = cmd[0].has("continueonerror");
bool checkTp = false; bool checkTp = false;
auto sgroupUpdate = false; auto sgroupUpdate = false;
@ -3106,18 +3129,19 @@ CommandResult ConnectedClient::handleCommandServerGroupAutoDelPerm(ts::Command&
} }
if(sgroupUpdate) if(sgroupUpdate) {
for(auto& group : groups) for(auto& group : groups)
group->apply_properties_from_permissions(); group->apply_properties_from_permissions();
}
if(ref_server) {
auto lock = this->_this.lock(); auto lock = this->_this.lock();
auto server = this->server; threads::Thread([checkTp, sgroupUpdate, groups, lock, ref_server]() {
threads::Thread([checkTp, sgroupUpdate, groups, lock, server]() {
if(sgroupUpdate) if(sgroupUpdate)
server->forEachClient([](shared_ptr<ConnectedClient> cl) { ref_server->forEachClient([](shared_ptr<ConnectedClient> cl) {
cl->notifyServerGroupList(); cl->notifyServerGroupList();
}); });
server->forEachClient([groups, checkTp](shared_ptr<ConnectedClient> cl) { ref_server->forEachClient([groups, checkTp](shared_ptr<ConnectedClient> cl) {
for(const auto& serverGroup : groups) { for(const auto& serverGroup : groups) {
if (cl->serverGroupAssigned(serverGroup)) { if (cl->serverGroupAssigned(serverGroup)) {
if(cl->update_cached_permissions()) /* update cached calculated permissions */ if(cl->update_cached_permissions()) /* update cached calculated permissions */
@ -3130,6 +3154,7 @@ CommandResult ConnectedClient::handleCommandServerGroupAutoDelPerm(ts::Command&
} }
}); });
}).detach(); }).detach();
}
return CommandResult::Success; return CommandResult::Success;
} }
@ -3267,7 +3292,12 @@ CommandResult ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_channel_textmessage_send, 1, channel, false)) if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_channel_textmessage_send, 1, channel, false))
return CommandResultPermissionError{permission::b_client_channel_textmessage_send}; return CommandResultPermissionError{permission::b_client_channel_textmessage_send};
bool conversation_private = channel->properties()[property::CHANNEL_FLAG_CONVERSATION_PRIVATE].as<bool>();
if(channel != this->currentChannel) { if(channel != this->currentChannel) {
if(conversation_private)
return {findError("conversation_is_private")};
if(!this->calculate_and_get_join_state(channel)) if(!this->calculate_and_get_join_state(channel))
return CommandResultPermissionError{permission::unknown}; /* You're not allowed to send messages :) */ return CommandResultPermissionError{permission::unknown}; /* You're not allowed to send messages :) */
} }
@ -3286,6 +3316,9 @@ CommandResult ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
continue; continue;
auto own_channel = client->currentChannel == this->currentChannel; auto own_channel = client->currentChannel == this->currentChannel;
if(conversation_private && !own_channel)
continue;
if(type != ClientType::CLIENT_TEAMSPEAK || own_channel) { if(type != ClientType::CLIENT_TEAMSPEAK || own_channel) {
if(!own_channel && &*client != this) { if(!own_channel && &*client != this) {
if(flag_password) if(flag_password)
@ -3297,16 +3330,32 @@ CommandResult ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
client->notifyTextMessage(ChatMessageMode::TEXTMODE_CHANNEL, _this, client_id, channel_id, message); client->notifyTextMessage(ChatMessageMode::TEXTMODE_CHANNEL, _this, client_id, channel_id, message);
} }
} }
if(!conversation_private) {
auto conversations = this->server->conversation_manager(); auto conversations = this->server->conversation_manager();
auto conversation = conversations->get_or_create(channel->channelId()); auto conversation = conversations->get_or_create(channel->channelId());
conversation->register_message(this->getClientDatabaseId(), this->getUid(), this->getDisplayName(), cmd["msg"].string()); conversation->register_message(this->getClientDatabaseId(), this->getUid(), this->getDisplayName(), cmd["msg"].string());
}
} else if (cmd["targetmode"] == ChatMessageMode::TEXTMODE_SERVER) { } else if (cmd["targetmode"] == ChatMessageMode::TEXTMODE_SERVER) {
CACHED_PERM_CHECK(permission::b_client_server_textmessage_send, 1); CACHED_PERM_CHECK(permission::b_client_server_textmessage_send, 1);
if(this->handleTextMessage(ChatMessageMode::TEXTMODE_SERVER, cmd["msg"], nullptr)) return CommandResult::Success; if(this->handleTextMessage(ChatMessageMode::TEXTMODE_SERVER, cmd["msg"], nullptr)) return CommandResult::Success;
this->server->forEachClient([&](shared_ptr<ConnectedClient> client) { for(const auto& client : this->server->getClients()) {
if (client->connectionState() != ConnectionState::CONNECTED)
continue;
auto type = client->getType();
if (type == ClientType::CLIENT_INTERNAL || type == ClientType::CLIENT_MUSIC)
continue;
client->notifyTextMessage(ChatMessageMode::TEXTMODE_SERVER, _this.lock(), this->getClientId(), 0, cmd["msg"].string()); client->notifyTextMessage(ChatMessageMode::TEXTMODE_SERVER, _this.lock(), this->getClientId(), 0, cmd["msg"].string());
}); }
{
auto conversations = this->server->conversation_manager();
auto conversation = conversations->get_or_create(0);
conversation->register_message(this->getClientDatabaseId(), this->getUid(), this->getDisplayName(), cmd["msg"].string());
}
} else return {findError("parameter_invalid"), "invalid target mode"}; } else return {findError("parameter_invalid"), "invalid target mode"};
return CommandResult::Success; return CommandResult::Success;
@ -4585,6 +4634,11 @@ CommandResult ConnectedClient::handleCommandClientEdit(Command &cmd, const std::
CACHED_PERM_CHECK(permission::b_client_music_modify_permanent, 1, true); CACHED_PERM_CHECK(permission::b_client_music_modify_permanent, 1, true);
} else } else
return {findError("parameter_invalid")}; return {findError("parameter_invalid")};
} else if(*info == property::CLIENT_AWAY_MESSAGE) {
if(!self) continue;
if(cmd["client_away_message"].string().length() > 256)
return {findError("parameter_invalid")};
} else if(!self) { /* dont edit random properties of other clients. For us self its allowed to edit the rest without permissions */ } else if(!self) { /* dont edit random properties of other clients. For us self its allowed to edit the rest without permissions */
continue; continue;
} }
@ -5115,13 +5169,13 @@ CommandResult ConnectedClient::handleCommandChannelClientAddPerm(Command &cmd) {
CMD_CHK_AND_INC_FLOOD_POINTS(5); CMD_CHK_AND_INC_FLOOD_POINTS(5);
if (!serverInstance->databaseHelper()->validClientDatabaseId(this->server, cmd["cldbid"])) return {findError("parameter_invalid"), "Invalid manager db id"}; if (!serverInstance->databaseHelper()->validClientDatabaseId(this->server, cmd["cldbid"])) return {findError("parameter_invalid"), "Invalid manager db id"};
auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, cmd["cldbid"]);
PERM_CHECKR(permission::i_client_permission_modify_power, this->server->calculatePermission(permission::PERMTEST_ORDERED, cmd["cldbid"], permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, nullptr), true);
RESOLVE_CHANNEL_R(cmd["cid"], true); RESOLVE_CHANNEL_R(cmd["cid"], true);
auto channel = dynamic_pointer_cast<ServerChannel>(l_channel->entry); auto channel = dynamic_pointer_cast<ServerChannel>(l_channel->entry);
if(!channel) return {ErrorType::VSError}; if(!channel) return {ErrorType::VSError};
auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, cmd["cldbid"]);
PERM_CHECK_CHANNELR(permission::i_client_permission_modify_power, this->server->calculatePermission(permission::PERMTEST_ORDERED, cmd["cldbid"], permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, channel), channel, true);
auto maxValue = this->getPermissionGrantValue(permission::PERMTEST_ORDERED, permission::i_permission_modify_power, this->currentChannel); auto maxValue = this->getPermissionGrantValue(permission::PERMTEST_ORDERED, permission::i_permission_modify_power, this->currentChannel);
bool ignoreGrant = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_permission_modify_power_ignore, 1, this->currentChannel); bool ignoreGrant = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_permission_modify_power_ignore, 1, this->currentChannel);
@ -7377,6 +7431,8 @@ CommandResult ConnectedClient::handleCommandConversationHistory(ts::Command &com
auto channel = this->channel_view()->find_channel(conversation_id); auto channel = this->channel_view()->find_channel(conversation_id);
if(!channel) if(!channel)
return {findError("conversation_invalid_id")}; return {findError("conversation_invalid_id")};
if(channel->channel()->properties()[property::CHANNEL_FLAG_CONVERSATION_PRIVATE].as<bool>())
return {findError("conversation_is_private")};
} }
/* test if there is a channel password or join power which denies that we see the conversation */ /* test if there is a channel password or join power which denies that we see the conversation */
@ -7497,6 +7553,12 @@ CommandResult ConnectedClient::handleCommandConversationFetch(ts::Command &cmd)
result_bulk["error_msg"] = error.message; result_bulk["error_msg"] = error.message;
continue; continue;
} }
if(channel->channel()->properties()[property::CHANNEL_FLAG_CONVERSATION_PRIVATE].as<bool>()) {
auto error = findError("conversation_is_private");
result_bulk["error_id"] = error.errorId;
result_bulk["error_msg"] = error.message;
continue;
}
} }
/* test if there is a channel password or join power which denies that we see the conversation */ /* test if there is a channel password or join power which denies that we see the conversation */

View File

@ -482,29 +482,30 @@ CommandResult SpeakingClient::handleCommandClientInit(Command& cmd) {
size_t clones_ip = 0; size_t clones_ip = 0;
size_t clones_hwid = 0; size_t clones_hwid = 0;
auto _own_hwid = this->getHardwareId();
this->server->forEachClient([&](shared_ptr<ConnectedClient> client) { this->server->forEachClient([&](shared_ptr<ConnectedClient> client) {
if(client->getExternalType() != CLIENT_TEAMSPEAK) return; if(client->getExternalType() != CLIENT_TEAMSPEAK) return;
if(client->getUid() == this->getUid()) if(client->getUid() == this->getUid())
clones_uid++; clones_uid++;
if(client->getPeerIp() == this->getPeerIp()) if(client->getPeerIp() == this->getPeerIp())
clones_ip++; clones_ip++;
if(client->getHardwareId() == this->getHardwareId()) if(client->getHardwareId() == _own_hwid)
clones_hwid++; clones_hwid++;
}); });
if(permissions[permission::i_client_max_clones_uid] > 0 && clones_uid >= permissions[permission::i_client_max_clones_uid]) { if(permissions[permission::i_client_max_clones_uid] > 0 && clones_uid >= permissions[permission::i_client_max_clones_uid]) {
logMessage(this->getServerId(), "{} Disconnecting because there are already {} uid clones connected. (Allowed: {})", CLIENT_STR_LOG_PREFIX, clones_uid, permissions[permission::i_client_max_clones_uid]); logMessage(this->getServerId(), "{} Disconnecting because there are already {} uid clones connected. (Allowed: {})", CLIENT_STR_LOG_PREFIX, clones_uid, permissions[permission::i_client_max_clones_uid]);
return {findError("client_too_many_clones_connected"), ""}; return {findError("client_too_many_clones_connected"), "too many clones connected (uid)"};
} }
if(permissions[permission::i_client_max_clones_ip] > 0 && clones_ip >= permissions[permission::i_client_max_clones_ip]) { if(permissions[permission::i_client_max_clones_ip] > 0 && clones_ip >= permissions[permission::i_client_max_clones_ip]) {
logMessage(this->getServerId(), "{} Disconnecting because there are already {} ip clones connected. (Allowed: {})", CLIENT_STR_LOG_PREFIX, clones_ip, permissions[permission::i_client_max_clones_ip]); logMessage(this->getServerId(), "{} Disconnecting because there are already {} ip clones connected. (Allowed: {})", CLIENT_STR_LOG_PREFIX, clones_ip, permissions[permission::i_client_max_clones_ip]);
return {findError("client_too_many_clones_connected"), ""}; return {findError("client_too_many_clones_connected"), "too many clones connected (ip)"};
} }
if(permissions[permission::i_client_max_clones_hwid] > 0 && clones_hwid >= permissions[permission::i_client_max_clones_hwid]) { if(permissions[permission::i_client_max_clones_hwid] > 0 && clones_hwid >= permissions[permission::i_client_max_clones_hwid] && !_own_hwid.empty()) {
logMessage(this->getServerId(), "{} Disconnecting because there are already {} hwid clones connected. (Allowed: {})", CLIENT_STR_LOG_PREFIX, clones_hwid, permissions[permission::i_client_max_clones_hwid]); logMessage(this->getServerId(), "{} Disconnecting because there are already {} hwid clones connected. (Allowed: {})", CLIENT_STR_LOG_PREFIX, clones_hwid, permissions[permission::i_client_max_clones_hwid]);
return {findError("client_too_many_clones_connected"), ""}; return {findError("client_too_many_clones_connected"), "too many clones connected (hwid)"};
} }
TIMING_STEP(timings, "max clones "); TIMING_STEP(timings, "max clones ");

View File

@ -124,6 +124,7 @@ void MusicClient::initialize_bot() {
if(this->_player_state == ReplayState::LOADING) if(this->_player_state == ReplayState::LOADING)
this->_player_state = ReplayState::PLAYING; this->_player_state = ReplayState::PLAYING;
if(!this->properties()->has(property::CLIENT_COUNTRY) || this->properties()[property::CLIENT_COUNTRY].value().empty())
this->properties()[property::CLIENT_COUNTRY] = config::geo::countryFlag; this->properties()[property::CLIENT_COUNTRY] = config::geo::countryFlag;
if(this->properties()[property::CLIENT_UPTIME_MODE].as<MusicClient::UptimeMode::value>() == MusicClient::UptimeMode::TIME_SINCE_SERVER_START) { if(this->properties()[property::CLIENT_UPTIME_MODE].as<MusicClient::UptimeMode::value>() == MusicClient::UptimeMode::TIME_SINCE_SERVER_START) {
this->properties()[property::CLIENT_LASTCONNECTED] = duration_cast<seconds>(this->server->start_timestamp().time_since_epoch()).count(); this->properties()[property::CLIENT_LASTCONNECTED] = duration_cast<seconds>(this->server->start_timestamp().time_since_epoch()).count();

View File

@ -123,11 +123,6 @@ CommandResult QueryClient::handleCommandExit(Command &) {
return CommandResult::Success; return CommandResult::Success;
} }
struct QuerySqlData {
std::string username;
std::string password;
std::string uniqueId;
};
//login client_login_name=andreas client_login_password=meinPW //login client_login_name=andreas client_login_password=meinPW
CommandResult QueryClient::handleCommandLogin(Command& cmd) { CommandResult QueryClient::handleCommandLogin(Command& cmd) {
CMD_RESET_IDLE; CMD_RESET_IDLE;
@ -172,11 +167,11 @@ CommandResult QueryClient::handleCommandLogin(Command& cmd) {
this->query_account = account; this->query_account = account;
auto joined = this->currentChannel; auto joined_channel = this->currentChannel;
if(this->server) { if(this->server) {
{ {
unique_lock tree_lock(this->server->channel_tree_lock); unique_lock tree_lock(this->server->channel_tree_lock);
if(joined) if(joined_channel)
this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock); this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
this->server->unregisterClient(_this.lock(), "login", tree_lock); this->server->unregisterClient(_this.lock(), "login", tree_lock);
} }
@ -192,6 +187,8 @@ CommandResult QueryClient::handleCommandLogin(Command& cmd) {
auto target_server = this->server; /* keep the server alive 'ill we've joined the server */ auto target_server = this->server; /* keep the server alive 'ill we've joined the server */
if(account->bound_server) { if(account->bound_server) {
target_server = serverInstance->getVoiceServerManager()->findServerById(account->bound_server); target_server = serverInstance->getVoiceServerManager()->findServerById(account->bound_server);
if(target_server != this->server)
joined_channel = nullptr;
if(!target_server) if(!target_server)
return {findError("server_invalid_id"), "server does not exists anymore"}; return {findError("server_invalid_id"), "server does not exists anymore"};
} }
@ -202,22 +199,30 @@ CommandResult QueryClient::handleCommandLogin(Command& cmd) {
target_server->groups->enableCache(_this.lock()); target_server->groups->enableCache(_this.lock());
target_server->registerClient(_this.lock()); target_server->registerClient(_this.lock());
{
shared_lock server_tree_lock(target_server->channel_tree_lock); shared_lock server_tree_lock(target_server->channel_tree_lock);
if(joined_channel) /* needs only notify if we were already on that server within a channel */
target_server->notifyClientPropertyUpdates(_this.lock(), deque<property::ClientProperties>{property::CLIENT_NICKNAME, property::CLIENT_UNIQUE_IDENTIFIER}); target_server->notifyClientPropertyUpdates(_this.lock(), deque<property::ClientProperties>{property::CLIENT_NICKNAME, property::CLIENT_UNIQUE_IDENTIFIER});
shared_lock client_tree_lock(this->channel_lock); unique_lock client_tree_lock(this->channel_lock);
this->channels->reset(); this->channels->reset();
this->channels->insert_channels(target_server->channelTree->tree_head(), true, false); this->channels->insert_channels(target_server->channelTree->tree_head(), true, false);
this->subscribeChannel(this->server->channelTree->channels(), false, false);
}
if(joined_channel) {
unique_lock tree_lock(this->server->channel_tree_lock);
if(joined_channel)
this->server->client_move(this->ref(), joined_channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
} else if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_virtualserver_select_godmode, 1))
this->server->assignDefaultChannel(this->ref(), true);
else
this->update_cached_permissions();
} else { } else {
serverInstance->getGroupManager()->enableCache(_this.lock()); serverInstance->getGroupManager()->enableCache(_this.lock());
this->update_cached_permissions(); this->update_cached_permissions();
} }
if(target_server) {
unique_lock tree_lock(target_server->channel_tree_lock);
if(joined)
this->server->client_move(this->ref(), joined, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
}
this->properties()[property::CLIENT_TOTALCONNECTIONS]++; this->properties()[property::CLIENT_TOTALCONNECTIONS]++;
this->updateChannelClientProperties(true, true); this->updateChannelClientProperties(true, true);
@ -249,19 +254,26 @@ CommandResult QueryClient::handleCommandLogout(Command &) {
this->server->groups->enableCache(_this.lock()); this->server->groups->enableCache(_this.lock());
this->server->registerClient(this->ref()); this->server->registerClient(this->ref());
{
shared_lock server_channel_r_lock(this->server->channel_tree_lock); shared_lock server_channel_r_lock(this->server->channel_tree_lock);
unique_lock client_channel_lock(this->channel_lock); unique_lock client_channel_lock(this->channel_lock);
this->channels->reset(); this->channels->reset();
this->channels->insert_channels(this->server->channelTree->tree_head(), true, false); this->channels->insert_channels(this->server->channelTree->tree_head(), true, false);
client_channel_lock.unlock(); this->subscribeChannel(this->server->channelTree->channels(), false, false);
server_channel_r_lock.unlock(); }
if(joined) { if(joined) {
unique_lock server_channel_w_lock(this->server->channel_tree_lock, defer_lock); unique_lock server_channel_w_lock(this->server->channel_tree_lock, defer_lock);
this->server->client_move(this->ref(), joined, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, server_channel_w_lock); this->server->client_move(this->ref(), joined, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, server_channel_w_lock);
} else if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_virtualserver_select_godmode, 1)) {
this->server->assignDefaultChannel(this->ref(), true);
} else {
this->update_cached_permissions();
} }
} else { } else {
serverInstance->getGroupManager()->enableCache(_this.lock()); serverInstance->getGroupManager()->enableCache(_this.lock());
this->update_cached_permissions();
} }
this->updateChannelClientProperties(true, true); this->updateChannelClientProperties(true, true);
@ -310,7 +322,8 @@ CommandResult QueryClient::handleCommandServerSelect(Command &cmd) {
} }
server_locked->groups->disableCache(_this.lock()); server_locked->groups->disableCache(_this.lock());
this->channels->reset(); this->channels->reset();
} else serverInstance->getGroupManager()->disableCache(_this.lock()); } else
serverInstance->getGroupManager()->disableCache(_this.lock());
} }
this->resetEventMask(); this->resetEventMask();
@ -331,11 +344,11 @@ CommandResult QueryClient::handleCommandServerSelect(Command &cmd) {
{ {
shared_lock server_channel_lock(target->channel_tree_lock); shared_lock server_channel_lock(target->channel_tree_lock);
unique_lock client_channel_lock(this->channel_lock); unique_lock client_channel_lock(this->channel_lock);
this->subscribeToAll = true; this->subscribeToAll = true;
this->channels->insert_channels(this->server->channelTree->tree_head(), true, false); this->channels->insert_channels(this->server->channelTree->tree_head(), true, false);
this->subscribeChannel(this->server->channelTree->channels(), false, true); this->subscribeChannel(this->server->channelTree->channels(), false, false);
} }
auto negated_enforce_join = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_virtualserver_select_godmode, 1); auto negated_enforce_join = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_virtualserver_select_godmode, 1);

View File

@ -44,7 +44,8 @@ if(!result && result.msg().find(ignore) == string::npos){
#define RESIZE_COLUMN(tblName, rowName, size) up vote EXECUTE("Could not change column size", "ALTER TABLE " tblName " ALTER COLUMN " rowName " varchar(" size ")"); #define RESIZE_COLUMN(tblName, rowName, size) up vote EXECUTE("Could not change column size", "ALTER TABLE " tblName " ALTER COLUMN " rowName " varchar(" size ")");
#define CURRENT_VERSION 11 #define CURRENT_DATABASE_VERSION 11
#define CURRENT_PERMISSION_VERSION 0
#define CLIENT_UID_LENGTH "64" #define CLIENT_UID_LENGTH "64"
#define CLIENT_NAME_LENGTH "128" #define CLIENT_NAME_LENGTH "128"
@ -62,6 +63,22 @@ struct alive_watch {
} }
}; };
#define db_version(new_version) \
do { \
if(!this->change_database_version(new_version)) { \
error = "failed to update database version"; \
return false; \
} \
} while(0)
#define perm_version(new_version) \
do { \
if(!this->change_permission_version(new_version)) { \
error = "failed to update permission version"; \
return false; \
} \
} while(0)
bool SqlDataManager::initialize(std::string& error) { bool SqlDataManager::initialize(std::string& error) {
if(ts::config::database::url.find("sqlite://") == 0) if(ts::config::database::url.find("sqlite://") == 0)
this->manager = new sql::sqlite::SqliteManager(); this->manager = new sql::sqlite::SqliteManager();
@ -77,11 +94,9 @@ bool SqlDataManager::initialize(std::string& error) {
return false; return false;
} }
string command_append_utf8;
if(manager->getType() == sql::TYPE_MYSQL) { if(manager->getType() == sql::TYPE_MYSQL) {
sql::command(this->manager, "SET NAMES utf8").execute(); sql::command(this->manager, "SET NAMES utf8").execute();
//sql::command(this->manager, "DEFAULT CHARSET=utf8").execute(); //sql::command(this->manager, "DEFAULT CHARSET=utf8").execute();
command_append_utf8 = " CHARACTER SET=utf8";
} else if(manager->getType() == sql::TYPE_SQLITE) { } else if(manager->getType() == sql::TYPE_SQLITE) {
if(!config::database::sqlite::journal_mode.empty()) if(!config::database::sqlite::journal_mode.empty())
sql::command(this->manager, "PRAGMA journal_mode=" + config::database::sqlite::journal_mode + ";").execute(); sql::command(this->manager, "PRAGMA journal_mode=" + config::database::sqlite::journal_mode + ";").execute();
@ -95,12 +110,7 @@ bool SqlDataManager::initialize(std::string& error) {
sql::command(this->manager, "PRAGMA encoding = \"UTF-8\";").execute(); sql::command(this->manager, "PRAGMA encoding = \"UTF-8\";").execute();
} }
this->detectVersion(); /* begin transaction, if available */
//general stuff
if(this->version != CURRENT_VERSION) {
auto timestamp_start = system_clock::now();
logMessage(LOG_GENERAL, "Upgrading database from version " + to_string(this->version) + " to " + to_string(CURRENT_VERSION) + ". This could take a moment!");
if(manager->getType() == sql::TYPE_SQLITE) { if(manager->getType() == sql::TYPE_SQLITE) {
result = sql::command(this->sql(),"BEGIN TRANSACTION;").execute(); result = sql::command(this->sql(),"BEGIN TRANSACTION;").execute();
if(!result) { if(!result) {
@ -119,9 +129,60 @@ bool SqlDataManager::initialize(std::string& error) {
} }
debugMessage(LOG_GENERAL, "Rollbacked database successfully."); debugMessage(LOG_GENERAL, "Rollbacked database successfully.");
} }
}); });
switch (this->version) {
if(!this->detect_versions()) {
error = "failed to detect database/permission version";
return false;
}
if(!this->update_database(error)) {
error = "failed to upgrade database: " + error;
return false;
}
//Advanced locked test
{
bool property_exists = false;
sql::command(this->sql(), "SELECT * FORM `general` WHERE `key` = :key", variable{":key", "lock_test"}).query([](bool& flag, int, string*, string*) { flag = true; }, property_exists);
sql::result res;
if(!property_exists) {
res = sql::command(this->sql(), "INSERT INTO `general` (`key`, `value`) VALUES (:key, :value);", variable{":key", "lock_test"}, variable{":value", "UPDATE ME!"}).execute();
} else {
res = sql::command(this->sql(), "UPDATE `general` SET `value`= :value WHERE `key`= :key;", variable{":key", "lock_test"}, variable{":value", "TeaSpeak created by WolverinDEV <3"}).execute();
}
if(!res) {
if(res.msg().find("database is locked") != string::npos) error = "database is locked";
else error = "Failed to execute lock test! Command result: " + res.fmtStr();
return false;
}
}
if(!this->update_permissions(error)) {
error = "failed to upgrade permissions: " + error;
return false;
}
rollback_watch.do_notify = false; /* transaction was successful */
if(manager->getType() == sql::TYPE_SQLITE) {
result = sql::command(this->sql(), "COMMIT;").execute();
if(!result) {
error = "failed to commit changes";
return false;
}
}
return true;
}
bool SqlDataManager::update_database(std::string &error) {
if(this->_database_version != CURRENT_DATABASE_VERSION) {
string command_append_utf8 = manager->getType() == sql::TYPE_MYSQL ? " CHARACTER SET=utf8" : "";
sql::result result;
auto timestamp_start = system_clock::now();
logMessage(LOG_GENERAL, "Upgrading database from version " + to_string(this->_database_version) + " to " + to_string(CURRENT_DATABASE_VERSION) + ". This could take a moment!");
switch (this->_database_version) {
case -1: case -1:
CREATE_TABLE("general", "`key` VARCHAR(" UNKNOWN_KEY_LENGTH "), `value` TEXT", command_append_utf8); CREATE_TABLE("general", "`key` VARCHAR(" UNKNOWN_KEY_LENGTH "), `value` TEXT", command_append_utf8);
CREATE_TABLE("servers", "`serverId` INT NOT NULL, `host` TEXT NOT NULL, `port` INT", command_append_utf8); CREATE_TABLE("servers", "`serverId` INT NOT NULL, `host` TEXT NOT NULL, `port` INT", command_append_utf8);
@ -143,8 +204,7 @@ bool SqlDataManager::initialize(std::string& error) {
CREATE_TABLE("letters", "`serverId` INT NOT NULL, `letterId` INTEGER NOT NULL PRIMARY KEY, `sender` VARCHAR(" CLIENT_UID_LENGTH "), `receiver` VARCHAR(" CLIENT_UID_LENGTH "), `created` INT, `subject` TEXT, `message` TEXT, `read` INT", command_append_utf8); CREATE_TABLE("letters", "`serverId` INT NOT NULL, `letterId` INTEGER NOT NULL PRIMARY KEY, `sender` VARCHAR(" CLIENT_UID_LENGTH "), `receiver` VARCHAR(" CLIENT_UID_LENGTH "), `created` INT, `subject` TEXT, `message` TEXT, `read` INT", command_append_utf8);
CREATE_TABLE("musicbots", "`serverId` INT, `botId` INT, `uniqueId` VARCHAR(" CLIENT_UID_LENGTH "), `owner` INT", command_append_utf8); CREATE_TABLE("musicbots", "`serverId` INT, `botId` INT, `uniqueId` VARCHAR(" CLIENT_UID_LENGTH "), `owner` INT", command_append_utf8);
this->changeVersion(0); db_version(0);
case 0: case 0:
CREATE_INDEX("general", "key"); CREATE_INDEX("general", "key");
CREATE_INDEX("servers", "serverId"); CREATE_INDEX("servers", "serverId");
@ -175,25 +235,25 @@ bool SqlDataManager::initialize(std::string& error) {
CREATE_INDEX("letters", "serverId"); CREATE_INDEX("letters", "serverId");
CREATE_INDEX("letters", "letterId"); CREATE_INDEX("letters", "letterId");
CREATE_INDEX("musicbots", "serverId"); CREATE_INDEX("musicbots", "serverId");
this->changeVersion(1); db_version(1);
case 1: case 1:
sql::command(this->sql(), "UPDATE `properties` SET `type` = :type WHERE `serverId` = 0 AND `id` = 0", variable{":type", property::PropertyType::PROP_TYPE_INSTANCE}).execute(); sql::command(this->sql(), "UPDATE `properties` SET `type` = :type WHERE `serverId` = 0 AND `id` = 0", variable{":type", property::PropertyType::PROP_TYPE_INSTANCE}).execute();
this->changeVersion(2); db_version(2);
case 2: case 2:
sql::command(this->sql(), "ALTER TABLE permissions ADD flag_skip BOOL;").execute(); sql::command(this->sql(), "ALTER TABLE permissions ADD flag_skip BOOL;").execute();
sql::command(this->sql(), "ALTER TABLE permissions ADD flag_negate BOOL;").execute(); sql::command(this->sql(), "ALTER TABLE permissions ADD flag_negate BOOL;").execute();
this->changeVersion(3); db_version(3);
case 3: case 3:
EXECUTE("Failed to update ban table", "ALTER TABLE `bannedClients` ADD COLUMN `triggered` INT DEFAULT 0;"); EXECUTE("Failed to update ban table", "ALTER TABLE `bannedClients` ADD COLUMN `triggered` INT DEFAULT 0;");
CREATE_TABLE("ban_trigger", "`server_id` INT, `ban_id` INT, `unique_id` VARCHAR(" CLIENT_UID_LENGTH "), `hardware_id` VARCHAR(" CLIENT_UID_LENGTH "), `name` VARCHAR(" CLIENT_NAME_LENGTH "), `ip` VARCHAR(128), `timestamp` BIGINT", command_append_utf8); CREATE_TABLE("ban_trigger", "`server_id` INT, `ban_id` INT, `unique_id` VARCHAR(" CLIENT_UID_LENGTH "), `hardware_id` VARCHAR(" CLIENT_UID_LENGTH "), `name` VARCHAR(" CLIENT_NAME_LENGTH "), `ip` VARCHAR(128), `timestamp` BIGINT", command_append_utf8);
CREATE_INDEX2R("ban_trigger", "server_id", "ban_id"); CREATE_INDEX2R("ban_trigger", "server_id", "ban_id");
this->changeVersion(4); db_version(4);
case 4: case 4:
sql::command(this->sql(), "ALTER TABLE queries ADD server INT;").execute(); sql::command(this->sql(), "ALTER TABLE queries ADD server INT;").execute();
this->changeVersion(5); db_version(5);
case 5: case 5:
CREATE_TABLE("playlists", "`serverId` INT NOT NULL, `playlist_id` INT", command_append_utf8); CREATE_TABLE("playlists", "`serverId` INT NOT NULL, `playlist_id` INT", command_append_utf8);
@ -201,7 +261,7 @@ bool SqlDataManager::initialize(std::string& error) {
CREATE_TABLE("playlist_songs", "`serverId` INT NOT NULL, `playlist_id` INT, `song_id` INT, `order_id` INT, `invoker_dbid` INT, `url` TEXT, `url_loader` TEXT", command_append_utf8); CREATE_TABLE("playlist_songs", "`serverId` INT NOT NULL, `playlist_id` INT, `song_id` INT, `order_id` INT, `invoker_dbid` INT, `url` TEXT, `url_loader` TEXT", command_append_utf8);
CREATE_INDEX2R("playlist_songs", "serverId", "playlist_id"); CREATE_INDEX2R("playlist_songs", "serverId", "playlist_id");
this->changeVersion(6); db_version(6);
sql::command(this->sql(), "UPDATE `permissions ` SET `permId` = `b_client_music_create_temporary` WHERE `permId` = `b_client_music_create`").execute(); sql::command(this->sql(), "UPDATE `permissions ` SET `permId` = `b_client_music_create_temporary` WHERE `permId` = `b_client_music_create`").execute();
@ -318,14 +378,14 @@ ROLLBACK;
sql::command(this->sql(), "DELETE FROM `properties` WHERE `type` = 1 AND NOT (`serverId` IN (SELECT `serverId` FROM servers) OR `serverId` = 0);").execute(); sql::command(this->sql(), "DELETE FROM `properties` WHERE `type` = 1 AND NOT (`serverId` IN (SELECT `serverId` FROM servers) OR `serverId` = 0);").execute();
} }
this->changeVersion(8); db_version(8);
case 8: case 8:
result = sql::command(this->sql(), "UPDATE `queries` SET `server` = 0 WHERE `server` IS NULL").execute(); result = sql::command(this->sql(), "UPDATE `queries` SET `server` = 0 WHERE `server` IS NULL").execute();
if(!result) { if(!result) {
error = "Failed to drop null query entries (" + result.fmtStr() + ")"; error = "Failed to drop null query entries (" + result.fmtStr() + ")";
return false; return false;
} }
this->changeVersion(9); db_version(9);
case 9: case 9:
// //
//"UPDATE `permissions` SET `id` = :id WHERE `type` = :channel_type" ;permission::SQL_PERM_CHANNEL //"UPDATE `permissions` SET `id` = :id WHERE `type` = :channel_type" ;permission::SQL_PERM_CHANNEL
@ -344,22 +404,14 @@ ROLLBACK;
return false; return false;
} }
} }
this->changeVersion(10); db_version(10);
case 10: case 10:
CREATE_TABLE("conversations", "`server_id` INT, `channel_id` INT, `conversation_id` INT, `file_path` TEXT", command_append_utf8); CREATE_TABLE("conversations", "`server_id` INT, `channel_id` INT, `conversation_id` INT, `file_path` TEXT", command_append_utf8);
CREATE_TABLE("conversation_blocks", "`server_id` INT, `conversation_id` INT, `begin_timestamp` INT, `end_timestamp` INT, `block_offset` INT, `flags` INT", command_append_utf8); CREATE_TABLE("conversation_blocks", "`server_id` INT, `conversation_id` INT, `begin_timestamp` INT, `end_timestamp` INT, `block_offset` INT, `flags` INT", command_append_utf8);
CREATE_INDEX("conversations", "server_id"); CREATE_INDEX("conversations", "server_id");
CREATE_INDEX2R("conversation_blocks", "server_id", "conversation_id"); CREATE_INDEX2R("conversation_blocks", "server_id", "conversation_id");
this->changeVersion(11); db_version(11);
default: default:
if(manager->getType() == sql::TYPE_SQLITE) {
result = sql::command(this->sql(), "COMMIT;").execute();
if(!result) {
error = "failed to commit changes";
return false;
}
}
rollback_watch.do_notify = false; /* transaction was successful */
break; break;
} }
@ -367,21 +419,106 @@ ROLLBACK;
logMessage(LOG_GENERAL, "Database upgrade took {}ms", duration_cast<milliseconds>(timestamp_end - timestamp_start).count()); logMessage(LOG_GENERAL, "Database upgrade took {}ms", duration_cast<milliseconds>(timestamp_end - timestamp_start).count());
} }
//Advanced locked test return true;
{
bool property_exists = false;
sql::command(this->sql(), "SELECT * FORM `general` WHERE `key` = :key", variable{":key", "lock_test"}).query([](bool& flag, int, string*, string*) { flag = true; }, property_exists);
sql::result res;
if(!property_exists) {
res = sql::command(this->sql(), "INSERT INTO `general` (`key`, `value`) VALUES (:key, :value);", variable{":key", "lock_test"}, variable{":value", "UPDATE ME!"}).execute();
} else {
res = sql::command(this->sql(), "UPDATE `general` SET `value`= :value WHERE `key`= :key;", variable{":key", "lock_test"}, variable{":value", "TeaSpeak created by WolverinDEV <3"}).execute();
} }
if(!res) {
if(res.msg().find("database is locked") != string::npos) error = "database is locked"; bool SqlDataManager::update_permissions(std::string &error) {
else error = "Failed to execute lock test! Command result: " + res.fmtStr(); if(this->_permissions_version != CURRENT_PERMISSION_VERSION) {
sql::result result;
auto timestamp_start = system_clock::now();
logMessage(LOG_GENERAL, "Upgrading permissions from version " + to_string(this->_permissions_version) + " to " + to_string(CURRENT_PERMISSION_VERSION) + ". This could take a moment!");
const auto auto_update = [&](permission::update::GroupUpdateType update_type, const std::string& permission, permission::v2::PermissionFlaggedValue value, bool skip, bool negate, permission::v2::PermissionFlaggedValue granted) {
/*
INSERT [OR IGNORE | IGNORE] INTO `perms` (serverId, type, id, channelId, permId, value, grant, flag_skip, flag_negate)
SELECT DISTINCT `permissions`.`serverId`, 0, `groupId`, 0, :name, :value, :grant, :skip, :negate FROM groups
INNER JOIN `permissions`
ON permissions.permId = 'i_group_auto_update_type' AND permissions.channelId = 0 AND permissions.id = groups.groupId AND permissions.serverId = groups.serverId AND permissions.value = :update_type;
*/
std::string query = "INSERT ";
if(this->sql()->getType() == sql::TYPE_MYSQL)
query += "IGNORE ";
else
query += "OR IGNORE ";
query += "INTO `permissions` (serverId, type, id, channelId, permId, value, grant, flag_skip, flag_negate) ";
query += string() + "SELECT DISTINCT `permissions`.`serverId`, 0, `groupId`, 0, "
+ "'" + permission + "', "
+ to_string(value.has_value ? value.value : -2) + ", "
+ to_string(granted.has_value ? granted.value : -2) + ", "
+ to_string(skip) + ", "
+ to_string(negate) + " FROM groups ";
query += "INNER JOIN `permissions` ";
query += "ON permissions.permId = 'i_group_auto_update_type' AND permissions.channelId = 0 AND permissions.id = groups.groupId AND permissions.serverId = groups.serverId AND permissions.value = " + to_string(update_type);
logTrace(LOG_GENERAL, "Executing sql update: {}", query);
auto result = sql::command(this->sql(), query).execute();
if(!result) {
error = "failed to auto update permission " + permission + " for type " + to_string(update_type) + ": " + result.fmtStr();
return false; return false;
} }
return true;
};
switch (this->_permissions_version) {
case -1:
/* initial setup, or first introduce of 1.4.0. Default stuff will be loaded from the template file so we only run updates here */
if(!auto_update(permission::update::QUERY_ADMIN, "b_client_is_priority_speaker", {-2, false}, false, false, {100, true}))
return false;
if(!auto_update(permission::update::QUERY_ADMIN, "b_virtualserver_modify_country_code", {1, true}, false, false, {100, true}))
return false;
if(!auto_update(permission::update::QUERY_ADMIN, "b_channel_ignore_subscribe_power", {1, true}, false, false, {100, true}))
return false;
if(!auto_update(permission::update::QUERY_ADMIN, "b_channel_ignore_description_view_power", {1, true}, false, false, {100, true}))
return false;
if(!auto_update(permission::update::QUERY_ADMIN, "i_max_playlist_size", {1, false}, false, false, {100, true}))
return false;
if(!auto_update(permission::update::QUERY_ADMIN, "i_max_playlists", {1, false}, false, false, {100, true}))
return false;
if(!auto_update(permission::update::QUERY_ADMIN, "i_channel_create_modify_conversation_history_length", {1, false}, false, false, {100, true}))
return false;
if(!auto_update(permission::update::QUERY_ADMIN, "b_channel_create_modify_conversation_history_unlimited", {1, true}, false, false, {100, true}))
return false;
if(!auto_update(permission::update::QUERY_ADMIN, "b_channel_create_modify_conversation_private", {1, true}, false, false, {100, true}))
return false;
if(!auto_update(permission::update::SERVER_ADMIN, "b_client_is_priority_speaker", {-2, false}, false, false, {75, true}))
return false;
if(!auto_update(permission::update::SERVER_ADMIN, "b_virtualserver_modify_country_code", {1, true}, false, false, {75, true}))
return false;
if(!auto_update(permission::update::SERVER_ADMIN, "b_channel_ignore_subscribe_power", {1, true}, false, false, {75, true}))
return false;
if(!auto_update(permission::update::SERVER_ADMIN, "b_channel_ignore_description_view_power", {1, true}, false, false, {75, true}))
return false;
if(!auto_update(permission::update::SERVER_ADMIN, "i_max_playlist_size", {1, false}, false, false, {75, true}))
return false;
if(!auto_update(permission::update::SERVER_ADMIN, "i_max_playlists", {1, false}, false, false, {75, true}))
return false;
if(!auto_update(permission::update::SERVER_ADMIN, "i_channel_create_modify_conversation_history_length", {1, false}, false, false, {75, true}))
return false;
if(!auto_update(permission::update::SERVER_ADMIN, "b_channel_create_modify_conversation_history_unlimited", {1, true}, false, false, {75, true}))
return false;
if(!auto_update(permission::update::SERVER_ADMIN, "b_channel_create_modify_conversation_private", {1, true}, false, false, {75, true}))
return false;
if(!auto_update(permission::update::SERVER_NORMAL, "i_max_playlist_size", {50, true}, false, false, {-2, false}))
return false;
if(!auto_update(permission::update::SERVER_NORMAL, "i_channel_create_modify_conversation_history_length", {15000, true}, false, false, {-2, false}))
return false;
if(!auto_update(permission::update::SERVER_GUEST, "i_max_playlist_size", {10, true}, false, false, {-2, false}))
return false;
perm_version(0);
default:
break;
}
auto timestamp_end = system_clock::now();
logMessage(LOG_GENERAL, "Permission upgrade took {}ms", duration_cast<milliseconds>(timestamp_end - timestamp_start).count());
} }
return true; return true;
} }
@ -392,23 +529,54 @@ void SqlDataManager::finalize() {
this->manager = nullptr; this->manager = nullptr;
} }
void SqlDataManager::detectVersion() { bool SqlDataManager::detect_versions() {
sql::command(this->manager, "SELECT `value` FROM `general` WHERE `key`= :key", variable{":key", "data_version"}).query([&](int length, char** values, char**){ auto result = sql::command(this->manager, "SELECT `value` FROM `general` WHERE `key`= :key", variable{":key", "data_version"}).query([&](int length, char** values, char**){
this->version = atoi(values[0]); this->_database_version = atoi(values[0]);
this->version_present = false; this->database_version_present = true;
return 0; return 0;
}); });
result = sql::command(this->manager, "SELECT `value` FROM `general` WHERE `key`= :key", variable{":key", "permissions_version"}).query([&](int length, char** values, char**){
this->_permissions_version = atoi(values[0]);
this->permissions_version_present = true;
return 0;
});
return true;
} }
void SqlDataManager::changeVersion(int version) { bool SqlDataManager::change_database_version(int version) {
string command; string command;
if(this->version_present) if(this->database_version_present)
command = "UPDATE `general` SET `value`= :version WHERE `key`= :key;"; command = "UPDATE `general` SET `value`= :version WHERE `key`= :key;";
else else
command = "INSERT INTO `general` (`key`, `value`) VALUES (:key, :version);"; command = "INSERT INTO `general` (`key`, `value`) VALUES (:key, :version);";
auto result = sql::command(this->manager, command, variable{":version", version}, variable{":key", "data_version"}).execute(); auto result = sql::command(this->manager, command, variable{":version", version}, variable{":key", "data_version"}).execute();
if(!result) logError("Could not update SQL version. (" + result.fmtStr() + ")"); if(!result) {
else this->version_present = true; logError(LOG_INSTANCE, "Could not update SQL database version. (" + result.fmtStr() + ")");
this->version = version; return false;
}
this->database_version_present = true;
this->_database_version = version;
return true;
}
bool SqlDataManager::change_permission_version(int version) {
string command;
if(this->permissions_version_present)
command = "UPDATE `general` SET `value`= :version WHERE `key`= :key;";
else
command = "INSERT INTO `general` (`key`, `value`) VALUES (:key, :version);";
auto result = sql::command(this->manager, command, variable{":version", version}, variable{":key", "permissions_version"}).execute();
if(!result) {
logError(LOG_INSTANCE, "Could not update SQL permissions version. (" + result.fmtStr() + ")");
return false;
}
this->permissions_version_present = true;
this->_permissions_version = version;
return true;
} }

View File

@ -9,18 +9,25 @@ namespace ts {
SqlDataManager(); SqlDataManager();
virtual ~SqlDataManager(); virtual ~SqlDataManager();
int getVersion() { return this->version; } inline int get_database_version() const { return this->_database_version; }
inline int get_permissions_version() const { return this->_database_version; }
bool initialize(std::string&); bool initialize(std::string&);
void finalize(); void finalize();
sql::SqlManager* sql() { return this->manager; } sql::SqlManager* sql() { return this->manager; }
private: private:
sql::SqlManager* manager = nullptr; sql::SqlManager* manager = nullptr;
int version = -1; int _database_version = -1;
bool version_present = false; int _permissions_version = -1;
bool database_version_present = false;
bool permissions_version_present = false;
void detectVersion(); bool detect_versions();
void changeVersion(int); bool change_database_version(int);
bool change_permission_version(int);
bool update_database(std::string& /* errror */);
bool update_permissions(std::string& /* errror */);
}; };
} }
} }