Teaspeak-Server/server/src/client/DataClient.cpp
2021-02-26 21:32:57 +01:00

206 lines
7.6 KiB
C++

#include <log/LogUtils.h>
#include <misc/sassert.h>
#include <misc/hex.h>
#include <misc/base64.h>
#include "./DataClient.h"
#include "../InstanceHandler.h"
using namespace std;
using namespace ts;
using namespace ts::server;
using namespace ts::permission;
DataClient::DataClient(sql::SqlManager* database, const std::shared_ptr<VirtualServer>& 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;
}
constexpr static std::string_view kClientLoadCommand{R"(
SELECT
`client_database_id`,
`client_created`,
`client_last_connected`,
`client_total_connections`,
`client_month_upload`,
`client_month_download`,
`client_total_upload`,
`client_total_download`
FROM `clients_server` WHERE `server_id` = :sid AND `client_unique_id` = :uid
)"};
bool DataClient::loadDataForCurrentServer() {
auto uniqueId = this->getUid();
if(uniqueId.empty()) {
return false;
}
auto ref_server = this->server;
auto server_id = ref_server ? ref_server->getServerId() : 0;
properties()[property::CLIENT_DATABASE_ID] = 0;
this->clientPermissions = std::make_shared<permission::v2::PermissionManager>();
auto properties = this->properties();
sql::command{this->sql, std::string{kClientLoadCommand}, variable{":uid", uniqueId}, variable{":sid", server_id}}.query([&](int length, std::string* values, std::string* names) {
auto index{0};
try {
assert(names[index] == "client_database_id");
properties[property::CLIENT_DATABASE_ID] = std::stoull(values[index++]);
assert(names[index] == "client_created");
properties[property::CLIENT_CREATED] = std::stoull(values[index++]);
assert(names[index] == "client_last_connected");
properties[property::CLIENT_LASTCONNECTED] = std::stoull(values[index++]);
assert(names[index] == "client_total_connections");
properties[property::CLIENT_TOTALCONNECTIONS] = std::stoull(values[index++]);
assert(names[index] == "client_month_upload");
properties[property::CLIENT_MONTH_BYTES_UPLOADED] = std::stoull(values[index++]);
assert(names[index] == "client_month_download");
properties[property::CLIENT_MONTH_BYTES_DOWNLOADED] = std::stoull(values[index++]);
assert(names[index] == "client_total_upload");
properties[property::CLIENT_TOTAL_BYTES_UPLOADED] = std::stoull(values[index++]);
assert(names[index] == "client_total_download");
properties[property::CLIENT_TOTAL_BYTES_DOWNLOADED] = std::stoull(values[index++]);
assert(index == length);
} catch (std::exception& ex) {
logError(server_id, "Failed to load client {} base properties from database: {} (Index {})",
this->getUid(),
ex.what(),
index - 1
);
properties[property::CLIENT_DATABASE_ID] = 0;
}
});
if(this->properties()[property::CLIENT_DATABASE_ID].as<ClientDbId>() == 0)
return false;
//Load general properties
std::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;
}
this->_properties = serverInstance->databaseHelper()->loadClientProperties(ref_server, this->getClientDatabaseId(), this->getType());
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 0
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] = "";
}
}
#endif
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) {
auto current_channel = this->currentChannel;
channel = current_channel ? current_channel->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->getOldGroupManager()->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');
}