188 lines
8.1 KiB
C++
188 lines
8.1 KiB
C++
#include <log/LogUtils.h>
|
|
#include <src/client/voice/VoiceClient.h>
|
|
#include <misc/sassert.h>
|
|
#include <misc/hex.h>
|
|
#include "DataClient.h"
|
|
#include "ConnectedClient.h"
|
|
#include "src/server/file/FileServer.h"
|
|
#include "src/InstanceHandler.h"
|
|
#include "misc/base64.h"
|
|
|
|
using namespace std;
|
|
using namespace ts;
|
|
using namespace ts::server;
|
|
using namespace ts::permission;
|
|
|
|
DataClient::DataClient(sql::SqlManager* database, const std::shared_ptr<TSServer>& server) : server(server), sql(database) {
|
|
assert(database);
|
|
this->_properties = DatabaseHelper::default_properties_client(nullptr, ClientType::CLIENT_INTERNAL);
|
|
}
|
|
|
|
DataClient::~DataClient() {
|
|
this->clientPermissions = nullptr;
|
|
this->_properties = nullptr;
|
|
}
|
|
|
|
bool DataClient::loadDataForCurrentServer() { //TODO for query
|
|
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_CREATED] = 0;
|
|
properties()[property::CLIENT_TOTALCONNECTIONS] = 0;
|
|
|
|
|
|
ClientDbId client_db_id = 0;
|
|
sql::command(this->sql, "SELECT `cldbid`,`firstConnect`,`connections` FROM `clients` WHERE `serverId` = :sid AND `clientUid` = :uid LIMIT 1",
|
|
variable{":sid", server_id},
|
|
variable{":uid", this->getUid()}
|
|
).query([&](DataClient* cl, int length, string* values, string* names){
|
|
for (int index = 0; index < length; index++) {
|
|
try {
|
|
if (names[index] == "cldbid") {
|
|
client_db_id = stoull(values[index]);
|
|
} else if (names[index] == "firstConnect") {
|
|
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;
|
|
}, 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
|
|
deque<ts::PropertyWrapper> copied;
|
|
for(const auto& prop : this->_properties->list_properties()){
|
|
if((prop.type().flags & property::FLAG_GLOBAL) == 0) continue;
|
|
if(prop.type().default_value == prop.value()) continue;
|
|
copied.push_back(prop);
|
|
}
|
|
|
|
if(!ref_server) {
|
|
if(this->getType() == ClientType::CLIENT_WEB || this->getType() == ClientType::CLIENT_TEAMSPEAK)
|
|
logCritical(LOG_INSTANCE, "Got a voice or web client, which is unbound to any server!");
|
|
return false;
|
|
}
|
|
|
|
auto client_type = this->getType();
|
|
if(client_type == CLIENT_TEAMSPEAK || ref_server) {
|
|
this->_properties = serverInstance->databaseHelper()->loadClientProperties(ref_server, this->getClientDatabaseId(), client_type);
|
|
} else {
|
|
this->_properties = DatabaseHelper::default_properties_client(nullptr, client_type);
|
|
|
|
this->_properties->registerNotifyHandler([&, server_id, client_db_id](Property& prop){
|
|
std::string query;
|
|
if(prop.type() == property::CLIENT_TOTALCONNECTIONS)
|
|
query = "UPDATE `clients` SET `connections` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid";
|
|
else if(prop.type() == property::CLIENT_NICKNAME)
|
|
query = "UPDATE `clients` SET `lastName` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid";
|
|
else if(prop.type() == property::CLIENT_LASTCONNECTED)
|
|
query = "UPDATE `clients` SET `lastConnect` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid";
|
|
else
|
|
return;
|
|
|
|
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"});
|
|
});
|
|
}
|
|
|
|
this->_properties->toggleSave(false);
|
|
for(const auto& e : copied) {
|
|
auto p = this->properties()->find(e.type().type_property, e.type().property_index);
|
|
p = e.value();
|
|
p.setModified(false);
|
|
}
|
|
this->_properties->toggleSave(true);
|
|
|
|
this->clientPermissions = serverInstance->databaseHelper()->loadClientPermissionManager(ref_server, this->getClientDatabaseId());
|
|
|
|
//Setup / fix stuff
|
|
if(!this->properties()[property::CLIENT_FLAG_AVATAR].as<string>().empty()){
|
|
if(
|
|
!ref_server ||
|
|
!serverInstance->getFileServer()->findFile("/avatar_" + this->getAvatarId(),serverInstance->getFileServer()->avatarDirectory(ref_server))) {
|
|
if(config::server::delete_missing_icon_permissions)
|
|
this->properties()[property::CLIENT_FLAG_AVATAR] = "";
|
|
}
|
|
}
|
|
|
|
if(ref_server)
|
|
this->properties()[property::CLIENT_UNREAD_MESSAGES] = ref_server->letters->unread_letter_count(this->getUid());
|
|
|
|
return true;
|
|
}
|
|
|
|
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> DataClient::calculate_permissions(
|
|
const std::deque<permission::PermissionType> &permissions,
|
|
ChannelId channel,
|
|
bool granted,
|
|
std::shared_ptr<CalculateCache> cache) {
|
|
if(permissions.empty()) return {};
|
|
|
|
if(!cache)
|
|
cache = std::make_shared<CalculateCache>();
|
|
if(!cache->client_permissions) /* so we don't have to load that shit later */
|
|
cache->client_permissions = this->clientPermissions;
|
|
if(channel == -1)
|
|
channel = this->currentChannel ? this->currentChannel->channelId() : 0;
|
|
|
|
auto ref_server = this->server;
|
|
if(ref_server)
|
|
return ref_server->calculate_permissions(permissions, this->getClientDatabaseId(), this->getType(), channel, granted, cache);
|
|
else
|
|
return serverInstance->calculate_permissions(permissions, this->getClientDatabaseId(), this->getType(), channel, granted, cache);
|
|
}
|
|
|
|
permission::v2::PermissionFlaggedValue DataClient::calculate_permission(
|
|
permission::PermissionType permission, ChannelId channel, bool granted, std::shared_ptr<CalculateCache> cache) {
|
|
auto result = this->calculate_permissions({permission}, channel, granted, cache);
|
|
if(result.empty()) return {0, false};
|
|
return result.back().second;
|
|
}
|
|
|
|
std::vector<std::shared_ptr<GroupAssignment>> DataClient::assignedServerGroups() {
|
|
if(!this->server) return serverInstance->getGroupManager()->getServerGroups(this->getClientDatabaseId(), this->getType());
|
|
return this->server->groups->getServerGroups(this->getClientDatabaseId(), this->getType());
|
|
}
|
|
|
|
std::shared_ptr<GroupAssignment> DataClient::assignedChannelGroup(const shared_ptr<BasicChannel> &channel) {
|
|
if(!this->server || !channel) return {};
|
|
return this->server->groups->getChannelGroup(this->getClientDatabaseId(), channel, true);
|
|
}
|
|
|
|
bool DataClient::serverGroupAssigned(const shared_ptr<Group> &group) {
|
|
for(const auto &gr : this->assignedServerGroups())
|
|
if(gr->group == group) return true;
|
|
return false;
|
|
}
|
|
|
|
bool DataClient::channelGroupAssigned(const shared_ptr<Group> &group, const shared_ptr<BasicChannel> &channel) {
|
|
if(!channel) return false;
|
|
auto gr = this->assignedChannelGroup(channel);
|
|
sassert(gr);
|
|
if(!gr) return false;
|
|
return gr->group == group;
|
|
}
|
|
|
|
std::string DataClient::getAvatarId() {
|
|
return hex::hex(base64::validate(this->getUid()) ? base64::decode(this->getUid()) : this->getUid(), 'a', 'q');
|
|
}
|