Fixed some subscribe issues

This commit is contained in:
WolverinDEV 2019-10-16 21:11:54 +02:00
parent b3347cfa8e
commit 46753d7a3f
11 changed files with 132 additions and 85 deletions

@ -1 +1 @@
Subproject commit d2b3e9bcadea5130b8ae906d9a1e656351f59936 Subproject commit ac79fda3b2d409e2fa023a5f38c380121cd7ee93

View File

@ -622,19 +622,19 @@ void DatabaseHelper::saveChannelPermissions(const std::shared_ptr<ts::server::TS
} }
} }
void DatabaseHelper::assign_default_properties_client(Properties *properties, ClientType type){ std::shared_ptr<Properties> DatabaseHelper::default_properties_client(std::shared_ptr<Properties> properties, ClientType type){
Properties& _properties = *properties; if(!properties)
properties = make_shared<Properties>();
_properties.register_property_type<property::ClientProperties>(); properties->register_property_type<property::ClientProperties>();
_properties.register_property_type<property::ConnectionProperties>(); properties->register_property_type<property::ConnectionProperties>();
if(type == ClientType::CLIENT_MUSIC){ if(type == ClientType::CLIENT_MUSIC || 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;
} else if(type == ClientType::CLIENT_QUERY) {
_properties[property::CLIENT_INPUT_HARDWARE] = true;
_properties[property::CLIENT_OUTPUT_HARDWARE] = true;
} }
return properties;
} }
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) {
@ -954,8 +954,7 @@ std::shared_ptr<Properties> DatabaseHelper::loadChannelProperties(const shared_p
} }
std::shared_ptr<Properties> DatabaseHelper::loadClientProperties(const std::shared_ptr<TSServer>& server, ClientDbId cldbid, ClientType type) { std::shared_ptr<Properties> DatabaseHelper::loadClientProperties(const std::shared_ptr<TSServer>& server, ClientDbId cldbid, ClientType type) {
auto props = std::make_shared<Properties>(); auto props = DatabaseHelper::default_properties_client(nullptr, type);
assign_default_properties_client(props.get(), type);
if(server) { if(server) {
props->operator[](property::CLIENT_DESCRIPTION) = server->properties()[property::VIRTUALSERVER_DEFAULT_CLIENT_DESCRIPTION].value(); props->operator[](property::CLIENT_DESCRIPTION) = server->properties()[property::VIRTUALSERVER_DEFAULT_CLIENT_DESCRIPTION].value();
} }

View File

@ -76,7 +76,7 @@ namespace ts {
class DatabaseHelper { class DatabaseHelper {
public: public:
static void assign_default_properties_client(Properties *, ClientType type); static std::shared_ptr<Properties> default_properties_client(std::shared_ptr<Properties> /* properties */, ClientType /* type */);
static bool assignDatabaseId(sql::SqlManager *, ServerId id, std::shared_ptr<DataClient>); static bool assignDatabaseId(sql::SqlManager *, ServerId id, std::shared_ptr<DataClient>);
explicit DatabaseHelper(sql::SqlManager*); explicit DatabaseHelper(sql::SqlManager*);

View File

@ -523,8 +523,20 @@ void TSServer::client_move(
if(!deleted.empty()) if(!deleted.empty())
target->notifyChannelHide(deleted, false); target->notifyChannelHide(deleted, false);
if(!s_source_channel->permission_granted(permission::i_channel_needed_subscribe_power, target->calculate_permission_value(permission::i_channel_subscribe_power, s_source_channel->channelId()), false)) auto i_source_channel = s_source_channel->channelId();
target->unsubscribeChannel({s_source_channel}, false); //Unsubscribe last channel (hasn't permissions) if(std::find(deleted.begin(), deleted.end(), i_source_channel) == deleted.end()) {
auto source_channel_sub_power = target->calculate_permission_value(permission::i_channel_subscribe_power, i_source_channel);
if(!s_source_channel->permission_granted(permission::i_channel_needed_subscribe_power, source_channel_sub_power, false)) {
auto source_channel_sub_power_ignore = target->calculate_permission_value(permission::b_channel_ignore_subscribe_power, i_source_channel);
if(!DataClient::permission_granted(source_channel_sub_power_ignore, 1, true)) {
logTrace(this->serverId, "Force unsubscribing of client {} for channel {}/{}. (Channel switch and no permissions)",
CLIENT_STR_LOG_PREFIX_(target), s_source_channel->name(),
i_source_channel
);
target->unsubscribeChannel({s_source_channel}, false); //Unsubscribe last channel (hasn't permissions)
}
}
}
TIMING_STEP(timings, "src hide ts"); TIMING_STEP(timings, "src hide ts");
} }
} }

View File

@ -246,9 +246,10 @@ std::deque<std::shared_ptr<BasicChannel>> ConnectedClient::subscribeChannel(cons
if(!general_granted && channel != this->currentChannel) { if(!general_granted && channel != this->currentChannel) {
auto granted_permission = this->calculate_permission_value(permission::i_channel_subscribe_power, channel->channelId()); auto granted_permission = this->calculate_permission_value(permission::i_channel_subscribe_power, channel->channelId());
if((granted_permission.has_value && granted_permission.value == -1) || !channel->permission_granted(permission::i_channel_needed_subscribe_power, granted_permission, false)) {
if(!channel->permission_granted(permission::i_channel_needed_subscribe_power, granted_permission, false)) {
auto ignore_power = this->calculate_permission_value(permission::b_channel_ignore_subscribe_power, channel->channelId()); auto ignore_power = this->calculate_permission_value(permission::b_channel_ignore_subscribe_power, channel->channelId());
if(!ignore_power.has_value && ignore_power.value < 1) if(!ignore_power.has_value || ignore_power.value < 1)
continue; continue;
} }
} }

View File

@ -5646,7 +5646,7 @@ CommandResult ConnectedClient::handleCommandMessageList(Command &cmd) {
CMD_CHK_AND_INC_FLOOD_POINTS(5); CMD_CHK_AND_INC_FLOOD_POINTS(5);
auto msgList = this->server->letters->avariableLetters(this->getUid()); auto msgList = this->server->letters->avariableLetters(this->getUid());
if (msgList.empty()) return {findError("database_empty_result"), "no letters avaraible"}; if (msgList.empty()) return {findError("database_empty_result"), "no letters available"};
Command notify(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifymessagelist" : ""); Command notify(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifymessagelist" : "");

View File

@ -13,12 +13,9 @@ using namespace ts;
using namespace ts::server; using namespace ts::server;
using namespace ts::permission; using namespace ts::permission;
extern ts::server::InstanceHandler* serverInstance;
DataClient::DataClient(sql::SqlManager* database, const std::shared_ptr<TSServer>& server) : server(server), sql(database) { DataClient::DataClient(sql::SqlManager* database, const std::shared_ptr<TSServer>& server) : server(server), sql(database) {
assert(database); assert(database);
this->_properties = std::make_shared<Properties>(); this->_properties = DatabaseHelper::default_properties_client(nullptr, ClientType::CLIENT_INTERNAL);
DatabaseHelper::assign_default_properties_client(this->_properties.get(), ClientType::CLIENT_INTERNAL);
} }
DataClient::~DataClient() { DataClient::~DataClient() {
@ -28,26 +25,48 @@ DataClient::~DataClient() {
bool DataClient::loadDataForCurrentServer() { //TODO for query bool DataClient::loadDataForCurrentServer() { //TODO for query
if(this->getUid().empty()) return false; if(this->getUid().empty()) return false;
auto ref_server = this->server;
auto server_id = ref_server ? ref_server->getServerId() : 0;
properties()[property::CLIENT_DATABASE_ID] = 0; properties()[property::CLIENT_DATABASE_ID] = 0;
properties()[property::CLIENT_CREATED] = 0; properties()[property::CLIENT_CREATED] = 0;
properties()[property::CLIENT_TOTALCONNECTIONS] = 0; properties()[property::CLIENT_TOTALCONNECTIONS] = 0;
sql::command(this->sql, "SELECT `cldbid`,`firstConnect`,`connections` FROM `clients` WHERE `serverId` = :sid AND `clientUid`=:uid LIMIT 1", variable{":sid", this->server ? this->server->getServerId() : 0}, variable{":uid", this->getUid()}).query([&](DataClient* cl, int length, string* values, string* names){ ClientDbId client_db_id = 0;
for (int index = 0; index < length; index++) { sql::command(this->sql, "SELECT `cldbid`,`firstConnect`,`connections` FROM `clients` WHERE `serverId` = :sid AND `clientUid` = :uid LIMIT 1",
logTrace(this->server ? this->server->getServerId() : 0, "Reading client (" + this->getUid() + ") property from client database table. (Key: " + names[index] + ", Value: " + values[index] + ")"); variable{":sid", server_id},
if (names[index] == "cldbid") { variable{":uid", this->getUid()}
cl->properties()[property::CLIENT_DATABASE_ID] = string(values[index]); ).query([&](DataClient* cl, int length, string* values, string* names){
} else if (names[index] == "firstConnect") { for (int index = 0; index < length; index++) {
cl->properties()[property::CLIENT_CREATED] = values[index]; try {
} else if (names[index] == "connections") { if (names[index] == "cldbid") {
cl->properties()[property::CLIENT_TOTALCONNECTIONS] = values[index]; client_db_id = stoull(values[index]);
} else { } else if (names[index] == "firstConnect") {
debugMessage(lstream << "Unknown row name '" << names[index] << "'" << endl); cl->properties()[property::CLIENT_CREATED] = values[index];
} } else if (names[index] == "connections") {
} cl->properties()[property::CLIENT_TOTALCONNECTIONS] = values[index];
} else {
logWarning(LOG_INSTANCE, "Received unknown column with name {} within client list", names[index]);
}
} catch(const std::exception& ex) {
logError(server_id, "Failed to load client {} base properties from database. Colum parsing for column {} failed. Value: {}. Message: {}",
this->getUid(),
names[index],
values[index],
ex.what()
);
return 0;
}
}
return 0; return 0;
}, this); }, this);
if(client_db_id == 0)
return false;
this->properties()[property::CLIENT_DATABASE_ID] = client_db_id; /* do this before the property saving (it saved the cldbid as well!)*/
//Load general properties //Load general properties
deque<ts::PropertyWrapper> copied; deque<ts::PropertyWrapper> copied;
for(const auto& prop : this->_properties->list_properties()){ for(const auto& prop : this->_properties->list_properties()){
@ -56,20 +75,19 @@ bool DataClient::loadDataForCurrentServer() { //TODO for query
copied.push_back(prop); copied.push_back(prop);
} }
if(this->getClientDatabaseId() == 0) return false; if(!ref_server) {
if(!this->server) {
if(this->getType() == ClientType::CLIENT_WEB || this->getType() == ClientType::CLIENT_TEAMSPEAK) if(this->getType() == ClientType::CLIENT_WEB || this->getType() == ClientType::CLIENT_TEAMSPEAK)
logCritical("Got a voice or web manager, which is unbound to any server!"); logCritical(LOG_INSTANCE, "Got a voice or web client, which is unbound to any server!");
return false; return false;
} }
auto clType = this->getType(); auto client_type = this->getType();
if(this->getType() == CLIENT_TEAMSPEAK || this->server) { if(client_type == CLIENT_TEAMSPEAK || ref_server) {
this->_properties = serverInstance->databaseHelper()->loadClientProperties(this->server, this->getClientDatabaseId(), clType); this->_properties = serverInstance->databaseHelper()->loadClientProperties(ref_server, this->getClientDatabaseId(), client_type);
} else { } else {
this->_properties = std::make_shared<Properties>(); this->_properties = DatabaseHelper::default_properties_client(nullptr, client_type);
DatabaseHelper::assign_default_properties_client(this->_properties.get(), clType);
this->_properties->registerNotifyHandler([&](Property& prop){ this->_properties->registerNotifyHandler([&, server_id, client_db_id](Property& prop){
std::string query; std::string query;
if(prop.type() == property::CLIENT_TOTALCONNECTIONS) if(prop.type() == property::CLIENT_TOTALCONNECTIONS)
query = "UPDATE `clients` SET `connections` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid"; query = "UPDATE `clients` SET `connections` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid";
@ -77,9 +95,12 @@ bool DataClient::loadDataForCurrentServer() { //TODO for query
query = "UPDATE `clients` SET `lastName` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid"; query = "UPDATE `clients` SET `lastName` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid";
else if(prop.type() == property::CLIENT_LASTCONNECTED) else if(prop.type() == property::CLIENT_LASTCONNECTED)
query = "UPDATE `clients` SET `lastConnect` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid"; query = "UPDATE `clients` SET `lastConnect` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid";
if(query.empty()) return; else
debugMessage("[SQL] " + query + " - " + to_string(0) + " - " + prop.value() + " - " + to_string(this->getClientDatabaseId())); return;
sql::command(this->sql, query, variable{":sid", 0}, variable{":cldbid", this->getClientDatabaseId()}, variable{":value", prop.value()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
debugMessage(server_id, "[Property] Updating general client table property for client {}. Key: {} Value: {}", client_db_id, prop.type().name, prop.value());
sql::command(this->sql, query, variable{":sid", 0}, variable{":cldbid", client_db_id}, variable{":value", prop.value()}).executeLater()
.waitAndGetLater(LOG_SQL_CMD, {1, "failed to update general client properties"});
}); });
} }
@ -91,35 +112,21 @@ bool DataClient::loadDataForCurrentServer() { //TODO for query
} }
this->_properties->toggleSave(true); this->_properties->toggleSave(true);
/* this->clientPermissions = serverInstance->databaseHelper()->loadClientPermissionManager(ref_server, this->getClientDatabaseId());
* //TODO What did this?
vector<string> updatedProps;
if(this->server) {
auto cclient = dynamic_cast<ConnectedClient*>(this);
if(cclient){
if(cclient->state == CONNECTED)
this->server->notifyClientPropertyUpdates(dynamic_cast<ConnectedClient*>(this)->_this.lock(), updatedProps);
}
}
*/
this->clientPermissions = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, this->getClientDatabaseId());
//Setup / fix stuff //Setup / fix stuff
if(!this->properties()[property::CLIENT_FLAG_AVATAR].as<string>().empty()){ if(!this->properties()[property::CLIENT_FLAG_AVATAR].as<string>().empty()){
if( if(
!this->server || !ref_server ||
!serverInstance->getFileServer()->findFile("/avatar_" + this->getAvatarId(),serverInstance->getFileServer()->avatarDirectory(this->server))) { !serverInstance->getFileServer()->findFile("/avatar_" + this->getAvatarId(),serverInstance->getFileServer()->avatarDirectory(ref_server))) {
if(config::server::delete_missing_icon_permissions) if(config::server::delete_missing_icon_permissions)
this->properties()[property::CLIENT_FLAG_AVATAR] = ""; this->properties()[property::CLIENT_FLAG_AVATAR] = "";
} }
} }
if(this->server){ if(ref_server)
int ureadMessages = 0; this->properties()[property::CLIENT_UNREAD_MESSAGES] = ref_server->letters->unread_letter_count(this->getUid());
for(const auto &elm : this->server->letters->avariableLetters(this->getUid()))
if(!elm->read) ureadMessages++;
this->properties()[property::CLIENT_UNREAD_MESSAGES] = ureadMessages;
}
return true; return true;
} }

View File

@ -90,24 +90,29 @@ namespace ts {
virtual permission::PermissionValue getPermissionGrantValue(permission::PermissionTestType test, permission::PermissionType, const std::shared_ptr<BasicChannel>& targetChannel = nullptr); virtual permission::PermissionValue getPermissionGrantValue(permission::PermissionTestType test, permission::PermissionType, const std::shared_ptr<BasicChannel>& targetChannel = nullptr);
virtual bool permissionGrantGranted(permission::PermissionTestType test, permission::PermissionType, permission::PermissionValue, const std::shared_ptr<BasicChannel>& targetChannel = nullptr, bool required = true); virtual bool permissionGrantGranted(permission::PermissionTestType test, permission::PermissionType, permission::PermissionValue, const std::shared_ptr<BasicChannel>& targetChannel = nullptr, bool required = true);
inline bool permission_granted(permission::PermissionType, permission::PermissionValue, bool = false) = delete; /* we dont accept permission type enums! */ template <typename T>
inline bool permission_granted(ts::permission::PermissionValue value, ts::permission::PermissionValue required, bool enforce_required = true) { inline bool permission_granted(T, permission::PermissionValue, bool = false) = delete; /* only permission values */
if(required == permNotGranted || required == 0) { [[deprecated]] __always_inline bool permission_granted(ts::permission::PermissionValue value, ts::permission::PermissionValue required, bool enforce_required = true) {
if(enforce_required) return DataClient::permission_granted({value, value != permNotGranted}, required, enforce_required);
return value == -1 || value > 0;
else
return true;
} else if(value == permNotGranted) {
return false;
} else {
if(value == -1)
return true;
else if(value >= required)
return true;
}
return false;
} }
static inline bool permission_granted(ts::permission::v2::PermissionFlaggedValue value, ts::permission::PermissionValue required, bool enforce_required = true) {
if(required == permNotGranted || required == 0) {
if(enforce_required)
return value.value == -1 || value.value > 0;
else
return true;
} else if(!value.has_value) {
return false;
} else {
if(value.value == -1)
return true;
else if(value.value >= required)
return true;
}
return false;
}
virtual std::vector<std::shared_ptr<GroupAssignment>> assignedServerGroups(); virtual std::vector<std::shared_ptr<GroupAssignment>> assignedServerGroups();
virtual std::shared_ptr<GroupAssignment> assignedChannelGroup(const std::shared_ptr<BasicChannel> &); virtual std::shared_ptr<GroupAssignment> assignedChannelGroup(const std::shared_ptr<BasicChannel> &);
virtual bool serverGroupAssigned(const std::shared_ptr<Group> &); virtual bool serverGroupAssigned(const std::shared_ptr<Group> &);

View File

@ -14,6 +14,28 @@ using namespace ts::server;
LetterManager::LetterManager(server::TSServer* server) : server(server) {} LetterManager::LetterManager(server::TSServer* server) : server(server) {}
LetterManager::~LetterManager() {} LetterManager::~LetterManager() {}
size_t LetterManager::unread_letter_count(const ts::ClientUid &client_unique_id) {
size_t result = 0;
auto res = sql::command(this->server->getSql(), "SELECT COUNT(*) FROM `letters` WHERE `serverId` = :sid AND `receiver` = :uid AND `read` = :false",
variable{":sid", this->server ? this->server->getServerId() : 0},
variable{":uid", client_unique_id},
variable{":false", 0}
).query([&](int length, std::string* values, std::string* columns) {
if(length != 1)
return 1;
try {
result = stoll(values[0]);
} catch(std::exception& ex) {
logError(this->server ? this->server->getServerId() : 0, "Failed to parse unread letter count: {}", ex.what());
return 1;
}
return 0;
});
(LOG_SQL_CMD)(res);
return result;
}
std::vector<std::shared_ptr<LetterHeader>> LetterManager::avariableLetters(ClientUid cluid) { std::vector<std::shared_ptr<LetterHeader>> LetterManager::avariableLetters(ClientUid cluid) {
vector<shared_ptr<LetterHeader>> result; vector<shared_ptr<LetterHeader>> result;

View File

@ -30,6 +30,7 @@ namespace ts {
~LetterManager(); ~LetterManager();
size_t unread_letter_count(const ClientUid&);
std::vector<std::shared_ptr<LetterHeader>> avariableLetters(ClientUid); std::vector<std::shared_ptr<LetterHeader>> avariableLetters(ClientUid);
std::shared_ptr<Letter> getFullLetter(LetterId); std::shared_ptr<Letter> getFullLetter(LetterId);

2
shared

@ -1 +1 @@
Subproject commit 3b3574d54df493a8a767e2c691c8769468b758dc Subproject commit 60ed95fb63463e71d423d555f316f071900d8fb6