Introduced the new group manager
This commit is contained in:
parent
ee52f4b8d9
commit
6f2d8ab6e4
@ -134,6 +134,10 @@ set(SERVER_SOURCE_FILES
|
||||
src/snapshots/music.cpp
|
||||
src/snapshots/parser.cpp
|
||||
|
||||
src/groups/Group.cpp
|
||||
src/groups/GroupManager.cpp
|
||||
src/groups/GroupAssignmentManager.cpp
|
||||
|
||||
src/manager/ActionLogger.cpp
|
||||
src/manager/ActionLoggerImpl.cpp
|
||||
|
||||
|
@ -167,14 +167,13 @@ void DatabaseHelper::deleteClient(const std::shared_ptr<VirtualServer>& server,
|
||||
}
|
||||
|
||||
inline sql::result load_permissions_v2(
|
||||
const std::shared_ptr<VirtualServer>& server,
|
||||
const ServerId& server_id,
|
||||
v2::PermissionManager* manager,
|
||||
sql::command& command,
|
||||
bool test_channel, /* only used for client permissions (client channel permissions) */
|
||||
bool is_channel) {
|
||||
auto start = system_clock::now();
|
||||
|
||||
auto server_id = server ? server->getServerId() : 0;
|
||||
return command.query([&](int length, char** values, char** names){
|
||||
permission::PermissionType key = permission::PermissionType::undefined;
|
||||
permission::PermissionValue value = permNotGranted, granted = permNotGranted;
|
||||
@ -209,16 +208,6 @@ inline sql::result load_permissions_v2(
|
||||
logError(server_id, "[SQL] Cant load permissions! Failed to parse value! Command: {} Message: {} Key: {} Value: {}", command.sqlCommand(), ex.what(),names[index], values[index]);
|
||||
return 0;
|
||||
}
|
||||
if(channel_id > 0 && test_channel) {
|
||||
if(!server)
|
||||
logError(server_id, "[SQL] Cant find channel for channel bound permission (No server given)! Command: {} ChannelID: {}", command.sqlCommand(), values[index]);
|
||||
else {
|
||||
auto channel = server->getChannelTree()->findChannel(channel_id);
|
||||
if(!channel)
|
||||
logError(server_id, "[SQL] Cant find channel for channel bound permission! Command: {} ChannelID: {}", command.sqlCommand(), values[index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(key == permission::undefined) {
|
||||
debugMessage(server_id, "[SQL] Permission entry misses permission type! Command: {}", command.sqlCommand());
|
||||
@ -306,7 +295,7 @@ std::shared_ptr<v2::PermissionManager> DatabaseHelper::loadClientPermissionManag
|
||||
variable{":serverId", server ? server->getServerId() : 0},
|
||||
variable{":type", permission::SQL_PERM_USER},
|
||||
variable{":id", cldbid});
|
||||
LOG_SQL_CMD(load_permissions_v2(server, permission_manager.get(), command, true, false));
|
||||
LOG_SQL_CMD(load_permissions_v2(server_id, permission_manager.get(), command, true, false));
|
||||
}
|
||||
|
||||
|
||||
@ -368,14 +357,14 @@ void DatabaseHelper::saveClientPermissions(const std::shared_ptr<ts::server::Vir
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadGroupPermissions(const std::shared_ptr<VirtualServer>& server, ts::GroupId group_id) {
|
||||
std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadGroupPermissions(const ServerId& server_id, ts::GroupId group_id, uint8_t /* target */) {
|
||||
auto result = std::make_shared<v2::PermissionManager>();
|
||||
if(this->use_startup_cache && server) {
|
||||
if(this->use_startup_cache && server_id > 0) {
|
||||
shared_ptr<StartupCacheEntry> entry;
|
||||
{
|
||||
threads::MutexLock lock(this->startup_lock);
|
||||
for(const auto& entries : this->startup_entries) {
|
||||
if(entries->sid == server->getServerId()) {
|
||||
if(entries->sid == server_id) {
|
||||
entry = entries;
|
||||
break;
|
||||
}
|
||||
@ -393,19 +382,18 @@ std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadGroupPerm
|
||||
|
||||
//7931
|
||||
auto command = sql::command(this->sql, "SELECT `channelId`, `permId`, `value`, `grant`, `flag_skip`, `flag_negate` FROM `permissions` WHERE `serverId` = :serverId AND `type` = :type AND `id` = :id",
|
||||
variable{":serverId", server ? server->getServerId() : 0},
|
||||
variable{":serverId", server_id},
|
||||
variable{":type", permission::SQL_PERM_GROUP},
|
||||
variable{":id", group_id});
|
||||
LOG_SQL_CMD(load_permissions_v2(server, result.get(), command, false, false));
|
||||
LOG_SQL_CMD(load_permissions_v2(server_id, result.get(), command, false, false));
|
||||
return result;
|
||||
}
|
||||
|
||||
void DatabaseHelper::saveGroupPermissions(const std::shared_ptr<ts::server::VirtualServer> &server, ts::GroupId group_id, const std::shared_ptr<ts::permission::v2::PermissionManager> &permissions) {
|
||||
void DatabaseHelper::saveGroupPermissions(const ServerId &server_id, ts::GroupId group_id, uint8_t /* target */, const std::shared_ptr<ts::permission::v2::PermissionManager> &permissions) {
|
||||
const auto updates = permissions->flush_db_updates();
|
||||
if(updates.empty())
|
||||
return;
|
||||
|
||||
auto server_id = server ? server->getServerId() : 0;
|
||||
for(auto& update : updates) {
|
||||
std::string query{update.flag_delete ? kPermissionDeleteCommand : (update.flag_db ? kPermissionUpdateCommand : kPermissionInsertCommand)};
|
||||
|
||||
@ -420,7 +408,7 @@ void DatabaseHelper::saveGroupPermissions(const std::shared_ptr<ts::server::Virt
|
||||
query
|
||||
);
|
||||
sql::command(this->sql, query,
|
||||
variable{":serverId", server ? server->getServerId() : 0},
|
||||
variable{":serverId", server_id},
|
||||
variable{":id", group_id},
|
||||
variable{":chId", 0},
|
||||
variable{":type", permission::SQL_PERM_GROUP},
|
||||
@ -468,7 +456,7 @@ std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadPlaylistP
|
||||
variable{":serverId", server ? server->getServerId() : 0},
|
||||
variable{":type", permission::SQL_PERM_PLAYLIST},
|
||||
variable{":id", playlist_id});
|
||||
LOG_SQL_CMD(load_permissions_v2(server, result.get(), command, false, false));
|
||||
LOG_SQL_CMD(load_permissions_v2(server ? server->getServerId() : 0, result.get(), command, false, false));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -534,7 +522,7 @@ std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadChannelPe
|
||||
variable{":chid", channel},
|
||||
variable{":id", 0},
|
||||
variable{":type", permission::SQL_PERM_CHANNEL});
|
||||
LOG_SQL_CMD(load_permissions_v2(server, result.get(), command, false, true));
|
||||
LOG_SQL_CMD(load_permissions_v2(server ? server->getServerId() : 0, result.get(), command, false, true));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -98,8 +98,8 @@ namespace ts::server {
|
||||
std::shared_ptr<permission::v2::PermissionManager> loadChannelPermissions(const std::shared_ptr<VirtualServer>&, ChannelId);
|
||||
void saveChannelPermissions(const std::shared_ptr<VirtualServer>&, ChannelId, const std::shared_ptr<permission::v2::PermissionManager>& /* permission manager */);
|
||||
|
||||
std::shared_ptr<permission::v2::PermissionManager> loadGroupPermissions(const std::shared_ptr<VirtualServer>&, GroupId);
|
||||
void saveGroupPermissions(const std::shared_ptr<VirtualServer>&, GroupId, const std::shared_ptr<permission::v2::PermissionManager>& /* permission manager */);
|
||||
std::shared_ptr<permission::v2::PermissionManager> loadGroupPermissions(const ServerId& server_id, GroupId, uint8_t /* target */);
|
||||
void saveGroupPermissions(const ServerId&, GroupId, uint8_t /* target */, const std::shared_ptr<permission::v2::PermissionManager>& /* permission manager */);
|
||||
|
||||
std::shared_ptr<permission::v2::PermissionManager> loadPlaylistPermissions(const std::shared_ptr<VirtualServer>&, PlaylistId /* playlist id */);
|
||||
void savePlaylistPermissions(const std::shared_ptr<VirtualServer>&, PlaylistId, const std::shared_ptr<permission::v2::PermissionManager>& /* permission manager */);
|
||||
|
@ -224,7 +224,7 @@ int GroupManager::insertGroupFromDb(int count, char **values, char **column) {
|
||||
|
||||
group->properties()[property::GROUP_NAME] = targetName;
|
||||
|
||||
group->setPermissionManager(serverInstance->databaseHelper()->loadGroupPermissions(this->server.lock(), group->groupId()));
|
||||
group->setPermissionManager(serverInstance->databaseHelper()->loadGroupPermissions(this->getServerId(), group->groupId(), 0));
|
||||
|
||||
debugMessage(this->getServerId(), "Push back group -> " + to_string(group->groupId()) + " - " + group->name());
|
||||
this->groups.push_back(group);
|
||||
@ -326,7 +326,7 @@ std::shared_ptr<Group> GroupManager::createGroup(GroupTarget target, GroupType t
|
||||
|
||||
std::shared_ptr<Group> group = std::make_shared<Group>(this, target, type, groupId);
|
||||
group->properties()[property::GROUP_NAME] = name;
|
||||
group->setPermissionManager(serverInstance->databaseHelper()->loadGroupPermissions(this->server.lock(), group->groupId()));
|
||||
group->setPermissionManager(serverInstance->databaseHelper()->loadGroupPermissions(this->getServerId(), group->groupId(), 0));
|
||||
|
||||
std::lock_guard glock{this->group_lock};
|
||||
this->groups.push_back(group);
|
||||
@ -368,7 +368,7 @@ bool GroupManager::copyGroupPermissions(const shared_ptr<Group> &source, const s
|
||||
res = sql::command(this->sql, "INSERT INTO `permissions` (`serverId`, `type`, `id`, `channelId`, `permId`, `value`, `grant`) SELECT :tsid AS `serverId`, `type`, :target AS `id`, 0 AS `channelId`, `permId`, `value`,`grant` FROM `permissions` WHERE `serverId` = :ssid AND `type` = :type AND `id` = :source",
|
||||
variable{":ssid", sourceServer}, variable{":tsid", targetServer}, variable{":type", SQL_PERM_GROUP}, variable{":source", source->groupId()}, variable{":target", target->groupId()}).execute();
|
||||
|
||||
target->setPermissionManager(serverInstance->databaseHelper()->loadGroupPermissions(target->handle->server.lock(), target->groupId()));
|
||||
target->setPermissionManager(serverInstance->databaseHelper()->loadGroupPermissions(target->handle->getServerId(), target->groupId(), 0));
|
||||
LOG_SQL_CMD(res);
|
||||
return true;
|
||||
}
|
||||
@ -379,7 +379,7 @@ bool GroupManager::reloadGroupPermissions(std::shared_ptr<Group> group) {
|
||||
return false;
|
||||
}
|
||||
|
||||
group->setPermissionManager(serverInstance->databaseHelper()->loadGroupPermissions(this->server.lock(), group->groupId()));
|
||||
group->setPermissionManager(serverInstance->databaseHelper()->loadGroupPermissions(this->getServerId(), group->groupId(), 0));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -128,10 +128,10 @@ InstanceHandler::InstanceHandler(SqlDataManager *sql) : sql(sql) {
|
||||
dynamic_pointer_cast<InternalClient>(this->_musicRoot)->initialize_weak_reference(this->_musicRoot);
|
||||
|
||||
{
|
||||
this->groupManager = std::make_shared<GroupManager>(nullptr, this->getSql());
|
||||
this->groupManager->loadGroupFormDatabase();
|
||||
this->__old__groupManager = std::make_shared<GroupManager>(nullptr, this->getSql());
|
||||
this->__old__groupManager->loadGroupFormDatabase();
|
||||
|
||||
if (this->groupManager->availableServerGroups(false).empty()) {
|
||||
if (this->__old__groupManager->availableServerGroups(false).empty()) {
|
||||
if(!this->setupDefaultGroups()){
|
||||
logCritical(LOG_INSTANCE, "Could not setup server instance! Stopping...");
|
||||
mainThreadActive = false;
|
||||
@ -140,24 +140,24 @@ InstanceHandler::InstanceHandler(SqlDataManager *sql) : sql(sql) {
|
||||
}
|
||||
|
||||
debugMessage(LOG_INSTANCE, "Instance admin group id " + to_string(this->properties()[property::SERVERINSTANCE_ADMIN_SERVERQUERY_GROUP].as<GroupId>()));
|
||||
auto instance_server_admin = this->groupManager->findGroup(this->properties()[property::SERVERINSTANCE_ADMIN_SERVERQUERY_GROUP].as<GroupId>());
|
||||
auto instance_server_admin = this->__old__groupManager->findGroup(this->properties()[property::SERVERINSTANCE_ADMIN_SERVERQUERY_GROUP].as<GroupId>());
|
||||
if (!instance_server_admin) {
|
||||
instance_server_admin = this->groupManager->availableServerGroups(false).front();
|
||||
instance_server_admin = this->__old__groupManager->availableServerGroups(false).front();
|
||||
logCritical(LOG_INSTANCE, "Missing instance server admin group! Using first available (" + (instance_server_admin ? instance_server_admin->name() : "nil") + ")");
|
||||
}
|
||||
if(this->groupManager->listGroupAssignments(this->globalServerAdmin->getClientDatabaseId()).empty())
|
||||
this->groupManager->addServerGroup(this->globalServerAdmin->getClientDatabaseId(), instance_server_admin);
|
||||
if(this->__old__groupManager->listGroupAssignments(this->globalServerAdmin->getClientDatabaseId()).empty())
|
||||
this->__old__groupManager->addServerGroup(this->globalServerAdmin->getClientDatabaseId(), instance_server_admin);
|
||||
|
||||
debugMessage(LOG_INSTANCE, "Server guest group id " + to_string(this->properties()[property::SERVERINSTANCE_GUEST_SERVERQUERY_GROUP].as<GroupId>()));
|
||||
auto instance_server_guest = this->groupManager->findGroup(this->properties()[property::SERVERINSTANCE_GUEST_SERVERQUERY_GROUP].as_save<GroupId>());
|
||||
auto instance_server_guest = this->__old__groupManager->findGroup(this->properties()[property::SERVERINSTANCE_GUEST_SERVERQUERY_GROUP].as_save<GroupId>());
|
||||
if (!instance_server_guest) {
|
||||
instance_server_guest = this->groupManager->availableServerGroups(false).front();
|
||||
instance_server_guest = this->__old__groupManager->availableServerGroups(false).front();
|
||||
logCritical(LOG_INSTANCE, "Missing instance server guest group! Using first available (" + (instance_server_guest ? instance_server_guest->name() : "nil") + ")");
|
||||
}
|
||||
this->properties()[property::SERVERINSTANCE_GUEST_SERVERQUERY_GROUP] = instance_server_guest->groupId();
|
||||
|
||||
debugMessage(LOG_INSTANCE, "Server music group id " + to_string(this->properties()[property::SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP].as<GroupId>()));
|
||||
auto instance_server_music = this->groupManager->findGroup(this->properties()[property::SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP].as_save<GroupId>());
|
||||
auto instance_server_music = this->__old__groupManager->findGroup(this->properties()[property::SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP].as_save<GroupId>());
|
||||
if (!instance_server_music) {
|
||||
instance_server_music = instance_server_guest;
|
||||
logCritical(LOG_INSTANCE, "Missing instance server music group! Using serverguest (" + (instance_server_music ? instance_server_music->name() : "nil") + ")");
|
||||
@ -214,7 +214,7 @@ InstanceHandler::~InstanceHandler() {
|
||||
delete this->banMgr;
|
||||
delete this->dbHelper;
|
||||
|
||||
groupManager = nullptr;
|
||||
__old__groupManager = nullptr;
|
||||
globalServerAdmin = nullptr;
|
||||
_musicRoot = nullptr;
|
||||
|
||||
@ -554,12 +554,12 @@ void InstanceHandler::tickInstance() {
|
||||
}
|
||||
|
||||
void InstanceHandler::save_group_permissions() {
|
||||
auto groups = this->getGroupManager()->availableGroups(false);
|
||||
auto groups = this->getOldGroupManager()->availableGroups(false);
|
||||
for(auto& group : groups) {
|
||||
auto permissions = group->permissions();
|
||||
if(permissions->require_db_updates()) {
|
||||
auto begin = system_clock::now();
|
||||
serverInstance->databaseHelper()->saveGroupPermissions(nullptr, group->groupId(), permissions);
|
||||
serverInstance->databaseHelper()->saveGroupPermissions(0, group->groupId(), 0, permissions);
|
||||
auto end = system_clock::now();
|
||||
debugMessage(0, "Saved instance group permissions for group {} ({}) in {}ms", group->groupId(), group->name(), duration_cast<milliseconds>(end - begin).count());
|
||||
}
|
||||
@ -899,7 +899,7 @@ std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlag
|
||||
//TODO: Negate?
|
||||
//TODO: May move this part to the instance?
|
||||
|
||||
auto server_groups = this->getGroupManager()->getServerGroups(cldbid, type);
|
||||
auto server_groups = this->getOldGroupManager()->getServerGroups(cldbid, type);
|
||||
for(const auto& permission : permissions) {
|
||||
permission::v2::PermissionFlaggedValue value{0, false};
|
||||
|
||||
|
@ -47,7 +47,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
std::shared_ptr<ts::server::InternalClient> getInitialServerAdmin(){ return globalServerAdmin; }
|
||||
std::shared_ptr<ts::GroupManager> getGroupManager(){ return groupManager; }
|
||||
std::shared_ptr<ts::GroupManager> getOldGroupManager(){ return __old__groupManager; }
|
||||
|
||||
std::shared_ptr<ts::ServerChannelTree> getChannelTree() { return this->default_tree; }
|
||||
std::shared_mutex& getChannelTreeLock() { return this->default_tree_lock; }
|
||||
@ -143,7 +143,7 @@ namespace ts {
|
||||
std::shared_ptr<ts::Properties> default_server_properties = nullptr;
|
||||
std::shared_ptr<ts::ServerChannelTree> default_tree = nullptr;
|
||||
std::shared_mutex default_tree_lock;
|
||||
std::shared_ptr<ts::GroupManager> groupManager = nullptr;
|
||||
std::shared_ptr<ts::GroupManager> __old__groupManager = nullptr;
|
||||
|
||||
std::shared_ptr<ts::server::InternalClient> globalServerAdmin = nullptr;
|
||||
std::shared_ptr<ConnectedClient> _musicRoot = nullptr;
|
||||
|
@ -123,7 +123,7 @@ bool InstanceHandler::setupDefaultGroups() {
|
||||
for(const auto& info : groups) {
|
||||
debugMessage(LOG_INSTANCE, "Creating default group {} with type {}", info->name, to_string(info->target));
|
||||
//Query groups
|
||||
auto group = this->groupManager->createGroup(
|
||||
auto group = this->__old__groupManager->createGroup(
|
||||
info->target != 2 ? GroupTarget::GROUPTARGET_SERVER : GroupTarget::GROUPTARGET_CHANNEL,
|
||||
info->target == 0 ? GroupType::GROUP_TYPE_QUERY : GroupType::GROUP_TYPE_TEMPLATE,
|
||||
info->name
|
||||
|
@ -241,7 +241,7 @@ void VirtualServer::executeServerTick() {
|
||||
auto permissions = group->permissions();
|
||||
if(permissions->require_db_updates()) {
|
||||
auto begin = system_clock::now();
|
||||
serverInstance->databaseHelper()->saveGroupPermissions(this->ref(), group->groupId(), permissions);
|
||||
serverInstance->databaseHelper()->saveGroupPermissions(this->getServerId(), group->groupId(), 0, permissions);
|
||||
auto end = system_clock::now();
|
||||
debugMessage(this->serverId, "Saved group permissions for group {} ({}) in {}ms", group->groupId(), group->name(), duration_cast<milliseconds>(end - begin).count());
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ bool VirtualServer::initialize(bool test_properties) {
|
||||
channelTree = new ServerChannelTree(self.lock(), this->sql);
|
||||
channelTree->loadChannelsFromDatabase();
|
||||
|
||||
this->groups = new GroupManager(self.lock(), this->sql, serverInstance->getGroupManager());
|
||||
this->groups = new GroupManager(self.lock(), this->sql, serverInstance->getOldGroupManager());
|
||||
if(!this->groups->loadGroupFormDatabase()){ //TODO exception etc
|
||||
logCritical(this->serverId, "Cant setup group manager!");
|
||||
return false;
|
||||
@ -1137,7 +1137,7 @@ bool VirtualServer::resetPermissions(std::string& new_permission_token) {
|
||||
threads::MutexLock lock(this->getGroupManager()->cacheLock);
|
||||
this->getGroupManager()->deleteAllGroups();
|
||||
deque<shared_ptr<Group>> saved_groups;
|
||||
for(const auto& group : serverInstance->getGroupManager()->availableGroups(false)){
|
||||
for(const auto& group : serverInstance->getOldGroupManager()->availableGroups(false)){
|
||||
if(group->type() != GroupType::GROUP_TYPE_TEMPLATE) continue;
|
||||
|
||||
debugMessage(this->serverId, "Copy default group {{Id: {}, Type: {}, Target: {}, Name: {}}} to server", group->groupId(), group->type(), group->target(), group->name());
|
||||
@ -1146,32 +1146,32 @@ bool VirtualServer::resetPermissions(std::string& new_permission_token) {
|
||||
}
|
||||
|
||||
//Server admin
|
||||
auto default_server_admin = serverInstance->getGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP].as<GroupId>());
|
||||
auto default_server_music = serverInstance->getGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP].as<GroupId>());
|
||||
auto default_server_guest = serverInstance->getGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP].as<GroupId>());
|
||||
auto default_server_admin = serverInstance->getOldGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP].as<GroupId>());
|
||||
auto default_server_music = serverInstance->getOldGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP].as<GroupId>());
|
||||
auto default_server_guest = serverInstance->getOldGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP].as<GroupId>());
|
||||
|
||||
auto default_channel_admin = serverInstance->getGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP].as<GroupId>());
|
||||
auto default_channel_guest = serverInstance->getGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP].as<GroupId>());
|
||||
auto default_channel_admin = serverInstance->getOldGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP].as<GroupId>());
|
||||
auto default_channel_guest = serverInstance->getOldGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP].as<GroupId>());
|
||||
|
||||
if(!default_server_guest) {
|
||||
logCritical(0, "Missing default server guest template group!");
|
||||
assert(!serverInstance->getGroupManager()->availableChannelGroups().empty());
|
||||
assert(!serverInstance->getOldGroupManager()->availableChannelGroups().empty());
|
||||
|
||||
default_server_guest = serverInstance->getGroupManager()->availableServerGroups().front();
|
||||
default_server_guest = serverInstance->getOldGroupManager()->availableServerGroups().front();
|
||||
logCritical(0, "Using group {} as default server guest group for server {}.", default_server_guest->name(), this->serverId);
|
||||
}
|
||||
if(!default_channel_admin) {
|
||||
logCritical(0, "Missing default channel guest template group!");
|
||||
assert(!serverInstance->getGroupManager()->availableChannelGroups().empty());
|
||||
assert(!serverInstance->getOldGroupManager()->availableChannelGroups().empty());
|
||||
|
||||
default_channel_admin = serverInstance->getGroupManager()->availableChannelGroups().front();
|
||||
default_channel_admin = serverInstance->getOldGroupManager()->availableChannelGroups().front();
|
||||
logCritical(0, "Using group {} as channel server guest group for server {}.", default_channel_admin->name(), this->serverId);
|
||||
}
|
||||
if(!default_server_music) {
|
||||
logCritical(0, "Missing default channel guest template group!");
|
||||
assert(!serverInstance->getGroupManager()->availableChannelGroups().empty());
|
||||
assert(!serverInstance->getOldGroupManager()->availableChannelGroups().empty());
|
||||
|
||||
default_server_music = serverInstance->getGroupManager()->availableChannelGroups().front();
|
||||
default_server_music = serverInstance->getOldGroupManager()->availableChannelGroups().front();
|
||||
logCritical(0, "Using group {} as channel server guest group for server {}.", default_server_music->name(), this->serverId);
|
||||
}
|
||||
|
||||
|
@ -578,7 +578,7 @@ void ServerChannelTree::on_channel_entry_deleted(const shared_ptr<BasicChannel>
|
||||
server->conversation_manager()->delete_conversation(channel->channelId());
|
||||
server->rtc_server().destroy_channel(server_channel->rtc_channel_id);
|
||||
} else {
|
||||
serverInstance->getGroupManager()->handleChannelDeleted(channel->channelId());
|
||||
serverInstance->getOldGroupManager()->handleChannelDeleted(channel->channelId());
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,7 +45,7 @@ bool ConnectedClient::notifyServerGroupList(bool as_notify) {
|
||||
Command cmd(as_notify ? "notifyservergrouplist" : "");
|
||||
int index = 0;
|
||||
|
||||
for (const auto& group : (this->server ? this->server->groups : serverInstance->getGroupManager().get())->availableServerGroups(true)) {
|
||||
for (const auto& group : (this->server ? this->server->groups : serverInstance->getOldGroupManager().get())->availableServerGroups(true)) {
|
||||
if(group->target() == GroupTarget::GROUPTARGET_CHANNEL) {
|
||||
cmd[index]["cgid"] = group->groupId();
|
||||
} else {
|
||||
@ -171,7 +171,7 @@ bool ConnectedClient::notifyClientPermList(ClientDbId cldbid, const std::shared_
|
||||
bool ConnectedClient::notifyChannelGroupList(bool as_notify) {
|
||||
Command cmd(as_notify ? "notifychannelgrouplist" : "");
|
||||
int index = 0;
|
||||
for (const auto &group : (this->server ? this->server->groups : serverInstance->getGroupManager().get())->availableChannelGroups(true)) {
|
||||
for (const auto &group : (this->server ? this->server->groups : serverInstance->getOldGroupManager().get())->availableChannelGroups(true)) {
|
||||
if(group->target() == GroupTarget::GROUPTARGET_CHANNEL) {
|
||||
cmd[index]["cgid"] = group->groupId();
|
||||
} else {
|
||||
|
@ -177,7 +177,7 @@ permission::v2::PermissionFlaggedValue DataClient::calculate_permission(
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<GroupAssignment>> DataClient::assignedServerGroups() {
|
||||
if(!this->server) return serverInstance->getGroupManager()->getServerGroups(this->getClientDatabaseId(), this->getType());
|
||||
if(!this->server) return serverInstance->getOldGroupManager()->getServerGroups(this->getClientDatabaseId(), this->getType());
|
||||
return this->server->groups->getServerGroups(this->getClientDatabaseId(), this->getType());
|
||||
}
|
||||
|
||||
|
@ -136,7 +136,7 @@ command_result ConnectedClient::handleCommandChannelGroupAdd(Command &cmd) {
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_create, 1);
|
||||
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get();
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get();
|
||||
|
||||
log::GroupType log_group_type;
|
||||
if (cmd["type"].as<GroupType>() == GroupType::GROUP_TYPE_QUERY) {
|
||||
@ -203,7 +203,7 @@ command_result ConnectedClient::handleCommandChannelGroupCopy(Command &cmd) {
|
||||
|
||||
auto ref_server = this->server;
|
||||
|
||||
auto group_manager = this->server ? this->server->groups : serverInstance->getGroupManager().get();
|
||||
auto group_manager = this->server ? this->server->groups : serverInstance->getOldGroupManager().get();
|
||||
|
||||
auto source_group_id = cmd["scgid"].as<GroupId>();
|
||||
auto source_group = group_manager->findGroup(source_group_id);
|
||||
@ -338,7 +338,7 @@ command_result ConnectedClient::handleCommandChannelGroupRename(Command &cmd) {
|
||||
CMD_RESET_IDLE;
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get();
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get();
|
||||
auto channel_group = group_manager->findGroup(cmd["cgid"].as<GroupId>());
|
||||
if (!channel_group || channel_group->target() != GROUPTARGET_CHANNEL)
|
||||
return command_result{error::parameter_invalid, "invalid channel group id"};
|
||||
@ -373,7 +373,7 @@ command_result ConnectedClient::handleCommandChannelGroupDel(Command &cmd) {
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_delete, 1);
|
||||
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get();
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get();
|
||||
auto channel_group = group_manager->findGroup(cmd["cgid"].as<GroupId>());
|
||||
if (!channel_group || channel_group->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"};
|
||||
|
||||
@ -508,7 +508,7 @@ command_result ConnectedClient::handleCommandChannelGroupPermList(Command &cmd)
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_permission_list, 1);
|
||||
|
||||
auto channelGroup = (this->server ? this->server->groups : serverInstance->getGroupManager().get())->findGroup(cmd["cgid"].as<GroupId>());
|
||||
auto channelGroup = (this->server ? this->server->groups : serverInstance->getOldGroupManager().get())->findGroup(cmd["cgid"].as<GroupId>());
|
||||
if (!channelGroup || channelGroup->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"};
|
||||
if (!this->notifyGroupPermList(channelGroup, cmd.hasParm("permsid"))) return command_result{error::database_empty_result};
|
||||
|
||||
@ -522,7 +522,7 @@ command_result ConnectedClient::handleCommandChannelGroupPermList(Command &cmd)
|
||||
command_result ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) {
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get();
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get();
|
||||
auto channelGroup = group_manager->findGroup(cmd["cgid"].as<GroupId>());
|
||||
if (!channelGroup || channelGroup->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"};
|
||||
ACTION_REQUIRES_GROUP_PERMISSION(channelGroup, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true);
|
||||
@ -574,7 +574,7 @@ command_result ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) {
|
||||
|
||||
command_result ConnectedClient::handleCommandChannelGroupDelPerm(Command &cmd) {
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get();
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get();
|
||||
auto channelGroup = group_manager->findGroup(cmd["cgid"].as<GroupId>());
|
||||
if (!channelGroup || channelGroup->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"};
|
||||
ACTION_REQUIRES_GROUP_PERMISSION(channelGroup, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true);
|
||||
|
@ -314,7 +314,7 @@ command_result ConnectedClient::handleCommandServerGroupAdd(Command &cmd) {
|
||||
log_group_type = log::GroupType::NORMAL;
|
||||
}
|
||||
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get();
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get();
|
||||
for(const auto& gr : group_manager->availableServerGroups(true)) {
|
||||
if(gr->name() == cmd["name"].string() && gr->target() == GroupTarget::GROUPTARGET_SERVER) {
|
||||
return command_result{error::parameter_invalid, "Group already exists"};
|
||||
@ -360,7 +360,7 @@ command_result ConnectedClient::handleCommandServerGroupCopy(Command &cmd) {
|
||||
auto ref_server = this->server;
|
||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_create, 1);
|
||||
|
||||
auto group_manager = this->server ? this->server->groups : serverInstance->getGroupManager().get();
|
||||
auto group_manager = this->server ? this->server->groups : serverInstance->getOldGroupManager().get();
|
||||
|
||||
auto source_group_id = cmd["ssgid"].as<GroupId>();
|
||||
auto source_group = group_manager->findGroup(source_group_id);
|
||||
@ -494,7 +494,7 @@ command_result ConnectedClient::handleCommandServerGroupRename(Command &cmd) {
|
||||
CMD_RESET_IDLE;
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get();
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get();
|
||||
|
||||
auto serverGroup = group_manager->findGroup(cmd["sgid"].as<GroupId>());
|
||||
if (!serverGroup || serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::group_invalid_id};
|
||||
@ -529,7 +529,7 @@ command_result ConnectedClient::handleCommandServerGroupDel(Command &cmd) {
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_delete, 1);
|
||||
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get();
|
||||
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get();
|
||||
auto serverGroup = group_manager->findGroup(cmd["sgid"].as<GroupId>());
|
||||
if (!serverGroup || serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::group_invalid_id};
|
||||
ACTION_REQUIRES_GROUP_PERMISSION(serverGroup, permission::i_server_group_needed_modify_power, permission::i_server_group_modify_power, true);
|
||||
@ -589,7 +589,7 @@ command_result ConnectedClient::handleCommandServerGroupClientList(Command &cmd)
|
||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_client_list, 1);
|
||||
|
||||
auto server = cmd[0].has("sid") && cmd["sid"] == 0 ? nullptr : this->server;
|
||||
auto groupManager = server ? this->server->groups : serverInstance->getGroupManager().get();
|
||||
auto groupManager = server ? this->server->groups : serverInstance->getOldGroupManager().get();
|
||||
|
||||
auto serverGroup = groupManager->findGroup(cmd["sgid"].as<GroupId>());
|
||||
if (!serverGroup || serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::group_invalid_id};
|
||||
@ -617,7 +617,7 @@ command_result ConnectedClient::handleCommandServerGroupAddClient(Command &cmd)
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(25);
|
||||
|
||||
auto target_server = cmd[0].has("sid") && cmd["sid"] == 0 ? nullptr : this->server;
|
||||
auto group_manager = target_server ? this->server->groups : serverInstance->getGroupManager().get();
|
||||
auto group_manager = target_server ? this->server->groups : serverInstance->getOldGroupManager().get();
|
||||
|
||||
auto target_cldbid = cmd["cldbid"].as<ClientDbId>();
|
||||
if (!serverInstance->databaseHelper()->validClientDatabaseId(target_server, cmd["cldbid"])) return command_result{error::client_invalid_id, "invalid cldbid"};
|
||||
@ -741,7 +741,7 @@ command_result ConnectedClient::handleCommandServerGroupDelClient(Command &cmd)
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(25);
|
||||
|
||||
auto target_server = cmd[0].has("sid") && cmd["sid"] == 0 ? nullptr : this->server;
|
||||
auto group_manager = target_server ? this->server->groups : serverInstance->getGroupManager().get();
|
||||
auto group_manager = target_server ? this->server->groups : serverInstance->getOldGroupManager().get();
|
||||
|
||||
auto target_cldbid = cmd["cldbid"].as<ClientDbId>();
|
||||
if (!serverInstance->databaseHelper()->validClientDatabaseId(target_server, cmd["cldbid"])) return command_result{error::client_invalid_id, "invalid cldbid"};
|
||||
@ -879,7 +879,7 @@ command_result ConnectedClient::handleCommandServerGroupPermList(Command &cmd) {
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_permission_list, 1);
|
||||
|
||||
auto serverGroup = (this->server ? this->server->groups : serverInstance->getGroupManager().get())->findGroup(cmd["sgid"].as<GroupId>());
|
||||
auto serverGroup = (this->server ? this->server->groups : serverInstance->getOldGroupManager().get())->findGroup(cmd["sgid"].as<GroupId>());
|
||||
if (!serverGroup) return command_result{error::group_invalid_id};
|
||||
|
||||
if(this->getType() == ClientType::CLIENT_TEAMSPEAK && this->command_times.last_notify + this->command_times.notify_timeout < system_clock::now()) {
|
||||
@ -894,7 +894,7 @@ command_result ConnectedClient::handleCommandServerGroupAddPerm(Command &cmd) {
|
||||
CMD_RESET_IDLE;
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||
|
||||
auto serverGroup = (this->server ? this->server->groups : serverInstance->getGroupManager().get())->findGroup(cmd["sgid"].as<GroupId>());
|
||||
auto serverGroup = (this->server ? this->server->groups : serverInstance->getOldGroupManager().get())->findGroup(cmd["sgid"].as<GroupId>());
|
||||
if (!serverGroup) return command_result{error::group_invalid_id};
|
||||
if (serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::parameter_invalid};
|
||||
ACTION_REQUIRES_GROUP_PERMISSION(serverGroup, permission::i_server_group_needed_modify_power, permission::i_server_group_modify_power, 1);
|
||||
@ -959,7 +959,7 @@ command_result ConnectedClient::handleCommandServerGroupDelPerm(Command &cmd) {
|
||||
CMD_RESET_IDLE;
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||
|
||||
auto serverGroup = (this->server ? this->server->groups : serverInstance->getGroupManager().get())->findGroup(cmd["sgid"].as<GroupId>());
|
||||
auto serverGroup = (this->server ? this->server->groups : serverInstance->getOldGroupManager().get())->findGroup(cmd["sgid"].as<GroupId>());
|
||||
if (!serverGroup) return command_result{error::group_invalid_id};
|
||||
if (serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::parameter_invalid};
|
||||
ACTION_REQUIRES_GROUP_PERMISSION(serverGroup, permission::i_server_group_needed_modify_power, permission::i_server_group_modify_power, 1);
|
||||
@ -1024,7 +1024,7 @@ command_result ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command&
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(25);
|
||||
|
||||
auto ref_server = this->server;
|
||||
auto group_manager = ref_server ? this->server->groups : &*serverInstance->getGroupManager();
|
||||
auto group_manager = ref_server ? this->server->groups : &*serverInstance->getOldGroupManager();
|
||||
|
||||
deque<shared_ptr<Group>> groups;
|
||||
for(const auto& group : group_manager->availableGroups(false)) {
|
||||
@ -1102,7 +1102,7 @@ command_result ConnectedClient::handleCommandServerGroupAutoDelPerm(ts::Command&
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(25);
|
||||
|
||||
auto ref_server = this->server;
|
||||
auto group_manager = ref_server ? this->server->groups : &*serverInstance->getGroupManager();
|
||||
auto group_manager = ref_server ? this->server->groups : &*serverInstance->getOldGroupManager();
|
||||
|
||||
deque<shared_ptr<Group>> groups;
|
||||
for(const auto& group : group_manager->availableGroups(false)) {
|
||||
@ -1191,7 +1191,7 @@ command_result ConnectedClient::handleCommandServerGroupsByClientId(Command &cmd
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
for (const auto &group : serverInstance->getGroupManager()->getAssignedServerGroups(cldbid)) {
|
||||
for (const auto &group : serverInstance->getOldGroupManager()->getAssignedServerGroups(cldbid)) {
|
||||
result[index]["name"] = group->group->name();
|
||||
result[index]["sgid"] = group->group->groupId();
|
||||
result[index]["cldbid"] = cldbid;
|
||||
|
@ -635,5 +635,5 @@ void QueryClient::disconnect_from_virtual_server(const std::string& reason) {
|
||||
this->loadDataForCurrentServer();
|
||||
}
|
||||
|
||||
serverInstance->getGroupManager()->enableCache(this->getClientDatabaseId());
|
||||
serverInstance->getOldGroupManager()->enableCache(this->getClientDatabaseId());
|
||||
}
|
@ -248,7 +248,7 @@ command_result QueryClient::handleCommandLogin(Command& cmd) {
|
||||
this->server->unregisterClient(this->ref(), "login", tree_lock);
|
||||
}
|
||||
this->server->groups->disableCache(this->getClientDatabaseId());
|
||||
} else serverInstance->getGroupManager()->disableCache(this->getClientDatabaseId());
|
||||
} else serverInstance->getOldGroupManager()->disableCache(this->getClientDatabaseId());
|
||||
|
||||
logMessage(LOG_QUERY, "Got new authenticated client. Username: {}, Unique-ID: {}, Bounded Server: {}", account->username, account->unique_id, account->bound_server);
|
||||
|
||||
@ -292,7 +292,7 @@ command_result QueryClient::handleCommandLogin(Command& cmd) {
|
||||
this->task_update_needed_permissions.enqueue();
|
||||
}
|
||||
} else {
|
||||
serverInstance->getGroupManager()->enableCache(this->getClientDatabaseId());
|
||||
serverInstance->getOldGroupManager()->enableCache(this->getClientDatabaseId());
|
||||
this->task_update_needed_permissions.enqueue();
|
||||
}
|
||||
|
||||
@ -318,7 +318,7 @@ command_result QueryClient::handleCommandLogout(Command &) {
|
||||
this->server->unregisterClient(this->ref(), "logout", tree_lock);
|
||||
}
|
||||
this->server->groups->disableCache(this->getClientDatabaseId());
|
||||
} else serverInstance->getGroupManager()->disableCache(this->getClientDatabaseId());
|
||||
} else serverInstance->getOldGroupManager()->disableCache(this->getClientDatabaseId());
|
||||
|
||||
this->properties()[property::CLIENT_UNIQUE_IDENTIFIER] = "UnknownQuery"; //TODO load from table
|
||||
this->properties()[property::CLIENT_NICKNAME] = string() + "ServerQuery#" + this->getLoggingPeerIp() + "/" + to_string(ntohs(this->getPeerPort()));
|
||||
@ -346,7 +346,7 @@ command_result QueryClient::handleCommandLogout(Command &) {
|
||||
this->task_update_needed_permissions.enqueue();
|
||||
}
|
||||
} else {
|
||||
serverInstance->getGroupManager()->enableCache(this->getClientDatabaseId());
|
||||
serverInstance->getOldGroupManager()->enableCache(this->getClientDatabaseId());
|
||||
this->task_update_needed_permissions.enqueue();
|
||||
}
|
||||
|
||||
@ -419,7 +419,7 @@ command_result QueryClient::handleCommandServerSelect(Command &cmd) {
|
||||
this->task_update_needed_permissions.enqueue();
|
||||
}
|
||||
} else {
|
||||
serverInstance->getGroupManager()->enableCache(this->getClientDatabaseId());
|
||||
serverInstance->getOldGroupManager()->enableCache(this->getClientDatabaseId());
|
||||
this->task_update_needed_permissions.enqueue();
|
||||
}
|
||||
|
||||
|
30
server/src/groups/Group.cpp
Normal file
30
server/src/groups/Group.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
//
|
||||
// Created by WolverinDEV on 03/03/2020.
|
||||
//
|
||||
|
||||
#include "Group.h"
|
||||
#include "./GroupManager.h"
|
||||
|
||||
using namespace ts::server::groups;
|
||||
|
||||
Group::Group(ServerId sid, ts::GroupId id, ts::server::groups::GroupType type, std::string name,
|
||||
std::shared_ptr<permission::v2::PermissionManager> permissions) : virtual_server_id_{sid}, group_id_{id}, type_{type}, name_{std::move(name)}, permissions_{std::move(permissions)} { }
|
||||
|
||||
void Group::set_permissions(const std::shared_ptr<permission::v2::PermissionManager> &permissions) {
|
||||
assert(permissions);
|
||||
this->permissions_ = permissions;
|
||||
}
|
||||
|
||||
ServerGroup::ServerGroup(ServerId sid, GroupId id, GroupType type, std::string name,
|
||||
std::shared_ptr<permission::v2::PermissionManager> permissions)
|
||||
: Group{sid, id, type, std::move(name), std::move(permissions)}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ChannelGroup::ChannelGroup(ServerId sid, GroupId id, GroupType type, std::string name,
|
||||
std::shared_ptr<permission::v2::PermissionManager> permissions)
|
||||
: Group{sid, id, type, std::move(name), std::move(permissions)}
|
||||
{
|
||||
|
||||
}
|
86
server/src/groups/Group.h
Normal file
86
server/src/groups/Group.h
Normal file
@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <PermissionManager.h>
|
||||
|
||||
namespace ts::server::groups {
|
||||
enum GroupType {
|
||||
GROUP_TYPE_QUERY,
|
||||
GROUP_TYPE_TEMPLATE,
|
||||
GROUP_TYPE_NORMAL,
|
||||
|
||||
GROUP_TYPE_UNKNOWN = 0xFF
|
||||
};
|
||||
|
||||
enum GroupNameMode {
|
||||
GROUP_NAME_MODE_HIDDEN,
|
||||
GROUP_NAME_MODE_BEFORE,
|
||||
GROUP_NAME_MODE_BEHIND
|
||||
};
|
||||
|
||||
typedef uint32_t GroupSortId;
|
||||
typedef uint32_t GroupIconId;
|
||||
|
||||
class AbstractGroupManager;
|
||||
class Group {
|
||||
friend class AbstractGroupManager;
|
||||
public:
|
||||
Group(ServerId /* server id */, GroupId /* id */, GroupType /* type */, std::string /* name */, std::shared_ptr<permission::v2::PermissionManager> /* permissions */);
|
||||
virtual ~Group() = default;
|
||||
|
||||
/* information getters */
|
||||
[[nodiscard]] inline ServerId virtual_server_id() const { return this->virtual_server_id_; }
|
||||
[[nodiscard]] inline GroupId group_id() const { return this->group_id_; }
|
||||
[[nodiscard]] inline GroupType group_type() const { return this->type_; }
|
||||
[[nodiscard]] inline const std::string& display_name() const { return this->name_; }
|
||||
|
||||
/* we're not returning a cr here because the permissions might get reloaded */
|
||||
[[nodiscard]] inline std::shared_ptr<permission::v2::PermissionManager> permissions() { return this->permissions_; }
|
||||
|
||||
[[nodiscard]] inline bool save_assignments() const {
|
||||
assert(this->permissions_);
|
||||
auto value = this->permissions_->permission_value_flagged(permission::b_group_is_permanent);
|
||||
return value.has_value ? permission::v2::permission_granted(1, value) : true;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline GroupNameMode name_mode() const {
|
||||
assert(this->permissions_);
|
||||
auto value = this->permissions_->permission_value_flagged(permission::i_group_show_name_in_tree);
|
||||
return value.has_value ? (GroupNameMode) value.value : GroupNameMode::GROUP_NAME_MODE_HIDDEN;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline GroupSortId sort_id() const {
|
||||
assert(this->permissions_);
|
||||
auto value = this->permissions_->permission_value_flagged(permission::i_group_sort_id);
|
||||
return value.has_value ? value.value : 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline GroupIconId icon_id() const {
|
||||
assert(this->permissions_);
|
||||
auto value = this->permissions_->permission_value_flagged(permission::i_icon_id);
|
||||
return value.has_value ? value.value : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
const ServerId virtual_server_id_;
|
||||
const GroupId group_id_;
|
||||
const GroupType type_;
|
||||
std::string name_;
|
||||
|
||||
std::shared_ptr<permission::v2::PermissionManager> permissions_;
|
||||
|
||||
void set_permissions(const std::shared_ptr<permission::v2::PermissionManager>& /* permissions */);
|
||||
};
|
||||
|
||||
class ServerGroup : public Group {
|
||||
public:
|
||||
ServerGroup(ServerId /* server id */, GroupId /* id */, GroupType /* type */, std::string /* name */, std::shared_ptr<permission::v2::PermissionManager> /* permissions */);
|
||||
};
|
||||
|
||||
class ChannelGroup : public Group {
|
||||
public:
|
||||
ChannelGroup(ServerId /* server id */, GroupId /* id */, GroupType /* type */, std::string /* name */, std::shared_ptr<permission::v2::PermissionManager> /* permissions */);
|
||||
};
|
||||
}
|
||||
DEFINE_TRANSFORMS(ts::server::groups::GroupType, uint8_t);
|
||||
DEFINE_TRANSFORMS(ts::server::groups::GroupNameMode, uint8_t);
|
497
server/src/groups/GroupAssignmentManager.cpp
Normal file
497
server/src/groups/GroupAssignmentManager.cpp
Normal file
@ -0,0 +1,497 @@
|
||||
//
|
||||
// Created by WolverinDEV on 03/03/2020.
|
||||
//
|
||||
#include <log/LogUtils.h>
|
||||
#include "./GroupAssignmentManager.h"
|
||||
#include "./GroupManager.h"
|
||||
|
||||
using namespace ts::server::groups;
|
||||
|
||||
GroupAssignmentManager::GroupAssignmentManager(GroupManager* handle) : manager_{handle} { }
|
||||
GroupAssignmentManager::~GroupAssignmentManager() = default;
|
||||
|
||||
bool GroupAssignmentManager::initialize(std::string &error) {
|
||||
return true;
|
||||
}
|
||||
|
||||
sql::SqlManager* GroupAssignmentManager::sql_manager() {
|
||||
return this->manager_->sql_manager();
|
||||
}
|
||||
|
||||
ts::ServerId GroupAssignmentManager::server_id() {
|
||||
return this->manager_->server_id();
|
||||
}
|
||||
|
||||
bool GroupAssignmentManager::load_data(std::string &error) {
|
||||
if constexpr(kCacheAllClients) {
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
std::unique_ptr<ClientCache> current_entry{nullptr};
|
||||
|
||||
auto res = sql::command(this->sql_manager(), "SELECT `groupId`, `cldbid`, `channelId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid ORDER BY `cldbid`", variable{":sid", this->server_id()})
|
||||
.query([&](int length, std::string* value, std::string* column) {
|
||||
ChannelId channel_id{0};
|
||||
GroupId group_id{0};
|
||||
ClientDbId client_dbid{0};
|
||||
|
||||
for(int index = 0; index < length; index++){
|
||||
try {
|
||||
if(column[index] == "groupId"){
|
||||
group_id = stoll(value[index]);
|
||||
} else if(column[index] == "until"){
|
||||
} else if(column[index] == "channelId"){
|
||||
channel_id = stoll(value[index]);
|
||||
} else if(column[index] == "cldbid"){
|
||||
client_dbid = stoll(value[index]);
|
||||
}
|
||||
} catch(std::exception& ex) {
|
||||
logError(this->server_id(), "Failed to load group assignment from database. Column {} contains an invalid value: {}", column[index], value[index]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(current_entry)
|
||||
if(current_entry->client_database_id != client_dbid)
|
||||
this->client_cache.push_back(std::move(current_entry));
|
||||
|
||||
if(!current_entry) {
|
||||
current_entry = std::make_unique<ClientCache>();
|
||||
current_entry->client_database_id = client_dbid;
|
||||
}
|
||||
|
||||
if(channel_id)
|
||||
current_entry->channel_group_assignments.emplace_back(channel_id, group_id, false);
|
||||
else
|
||||
current_entry->server_group_assignments.emplace_back(group_id);
|
||||
return 0;
|
||||
});
|
||||
|
||||
if(!res) {
|
||||
error = "failed to query database (" + res.fmtStr() + ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(current_entry) {
|
||||
this->client_cache.push_back(std::move(current_entry));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GroupAssignmentManager::unload_data() {
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
this->client_cache.clear();
|
||||
}
|
||||
|
||||
void GroupAssignmentManager::enable_cache_for_client(GroupAssignmentCalculateMode mode, ClientDbId cldbid) {
|
||||
if constexpr(!kCacheAllClients) {
|
||||
bool cache_exists{false};
|
||||
{
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
for(auto& client : this->client_cache)
|
||||
if(client->client_database_id == cldbid) {
|
||||
client->use_count++;
|
||||
cache_exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!cache_exists) {
|
||||
auto cache = std::make_unique<ClientCache>();
|
||||
cache->client_database_id = cldbid;
|
||||
cache->use_count++;
|
||||
|
||||
auto res = sql::command(this->sql_manager(), "SELECT `groupId`, `channelId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid", variable{":sid", this->server_id()}, variable{":cldbid", cldbid})
|
||||
.query([&](int length, std::string* value, std::string* column) {
|
||||
ChannelId channel_id{0};
|
||||
GroupId group_id{0};
|
||||
|
||||
for(int index = 0; index < length; index++){
|
||||
try {
|
||||
if(column[index] == "groupId"){
|
||||
group_id = stoll(value[index]);
|
||||
} else if(column[index] == "until"){
|
||||
} else if(column[index] == "channelId"){
|
||||
channel_id = stoll(value[index]);
|
||||
}
|
||||
} catch(std::exception& ex) {
|
||||
logError(this->server_id(), "Failed to load group assignment from database for client {}. Column {} contains an invalid value: {}", cldbid, column[index], value[index]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(!group_id)
|
||||
return 0;
|
||||
|
||||
if(channel_id)
|
||||
cache->channel_group_assignments.emplace_back(channel_id, group_id, false);
|
||||
else
|
||||
cache->server_group_assignments.emplace_back(group_id);
|
||||
return 0;
|
||||
});
|
||||
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
#if 0 /* lets have some performance over double entries :D */
|
||||
for(auto& client : this->client_cache)
|
||||
if(client->client_database_id == cldbid) {
|
||||
/* somebody already inserted that client while we've loaded him */
|
||||
cache_exists = true;
|
||||
break;
|
||||
}
|
||||
if(!cache_exists)
|
||||
#endif
|
||||
this->client_cache.push_back(std::move(cache));
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == GroupAssignmentCalculateMode::GLOBAL) {
|
||||
if(auto parent = this->manager_->parent_manager(); parent) {
|
||||
parent->assignments().enable_cache_for_client(mode, cldbid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GroupAssignmentManager::disable_cache_for_client(GroupAssignmentCalculateMode mode, ClientDbId cldbid) {
|
||||
if constexpr(!kCacheAllClients) {
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
this->client_cache.erase(std::remove_if(this->client_cache.begin(), this->client_cache.end(), [cldbid](const std::unique_ptr<ClientCache>& client) {
|
||||
return client->client_database_id == cldbid;
|
||||
}), this->client_cache.end());
|
||||
}
|
||||
|
||||
if(mode == GroupAssignmentCalculateMode::GLOBAL)
|
||||
if(auto parent = this->manager_->parent_manager(); parent)
|
||||
parent->assignments().disable_cache_for_client(mode, cldbid);
|
||||
}
|
||||
|
||||
|
||||
std::vector<ts::GroupId> GroupAssignmentManager::server_groups_of_client(ts::server::groups::GroupAssignmentCalculateMode mode,
|
||||
ts::ClientDbId cldbid) {
|
||||
std::vector<ts::GroupId> result{};
|
||||
bool cache_found{false};
|
||||
{
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
for(auto& entry : this->client_cache) {
|
||||
if(entry->client_database_id != cldbid) continue;
|
||||
|
||||
result.reserve(entry->server_group_assignments.size());
|
||||
for(auto& assignment : entry->server_group_assignments)
|
||||
result.push_back(assignment.group_id);
|
||||
|
||||
cache_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!cache_found && !kCacheAllClients) {
|
||||
debugMessage(this->server_id(), "Query client groups for client {} on server {}.", cldbid, this->server_id());
|
||||
|
||||
result.reserve(64);
|
||||
auto res = sql::command(this->sql_manager(), "SELECT `groupId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = 0", variable{":sid", this->server_id()}, variable{":cldbid", cldbid})
|
||||
.query([&](int length, std::string* value, std::string* column) {
|
||||
GroupId group_id{0};
|
||||
try {
|
||||
for(int index = 0; index < length; index++) {
|
||||
if(column[index] == "groupId") {
|
||||
group_id = std::stoull(value[index]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch(std::exception& ex) {
|
||||
logWarning(this->server_id(), "Invalid data found in group assignment table. Failed to parse group id.");
|
||||
return 0;
|
||||
}
|
||||
if(!group_id) return 0;
|
||||
|
||||
result.push_back(group_id);
|
||||
return 0;
|
||||
});
|
||||
LOG_SQL_CMD(res);
|
||||
}
|
||||
|
||||
if(mode == GroupAssignmentCalculateMode::GLOBAL)
|
||||
if(auto parent = this->manager_->parent_manager(); parent) {
|
||||
auto parent_groups = parent->assignments().server_groups_of_client(mode, cldbid);
|
||||
result.reserve(result.size() + parent_groups.size());
|
||||
result.insert(result.begin(), parent_groups.begin(), parent_groups.end());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<ChannelGroupAssignment> GroupAssignmentManager::channel_group_of_client(GroupAssignmentCalculateMode mode, ClientDbId cldbid) {
|
||||
std::vector<ChannelGroupAssignment> result{};
|
||||
bool cache_found{false};
|
||||
{
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
for(auto& entry : this->client_cache) {
|
||||
if(entry->client_database_id != cldbid) continue;
|
||||
|
||||
result.reserve(entry->channel_group_assignments.size());
|
||||
result.insert(result.begin(), entry->channel_group_assignments.begin(), entry->channel_group_assignments.end());
|
||||
cache_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!cache_found && !kCacheAllClients) {
|
||||
debugMessage(this->server_id(), "Query client groups for client {} on server {}.", cldbid, this->server_id());
|
||||
|
||||
result.reserve(64);
|
||||
auto res = sql::command(this->sql_manager(), "SELECT `groupId`, `channelId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` != 0", variable{":sid", this->server_id()}, variable{":cldbid", cldbid})
|
||||
.query([&](int length, std::string* value, std::string* column) {
|
||||
GroupId group_id{0};
|
||||
ChannelId channel_id{0};
|
||||
try {
|
||||
for(int index = 0; index < length; index++) {
|
||||
if(column[index] == "groupId") {
|
||||
group_id = std::stoull(value[index]);
|
||||
} else if(column[index] == "channelId") {
|
||||
channel_id = std::stoull(value[index]);
|
||||
}
|
||||
}
|
||||
} catch(std::exception& ex) {
|
||||
logWarning(this->server_id(), "Invalid data found in group assignment table. Failed to parse group or channel id.");
|
||||
return 0;
|
||||
}
|
||||
if(!group_id || !channel_id) return 0;
|
||||
|
||||
result.emplace_back(channel_id, group_id, false);
|
||||
return 0;
|
||||
});
|
||||
LOG_SQL_CMD(res);
|
||||
}
|
||||
|
||||
if(mode == GroupAssignmentCalculateMode::GLOBAL) {
|
||||
if(auto parent = this->manager_->parent_manager(); parent) {
|
||||
auto parent_groups = parent->assignments().channel_group_of_client(mode, cldbid);
|
||||
result.reserve(result.size() + parent_groups.size());
|
||||
result.insert(result.begin(), parent_groups.begin(), parent_groups.end());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::deque<ts::ClientDbId> GroupAssignmentManager::server_group_clients(GroupId group_id) {
|
||||
std::deque<ts::ClientDbId> result{};
|
||||
if constexpr(kCacheAllClients) {
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
for(auto& client : this->client_cache) {
|
||||
auto it = std::find_if(client->server_group_assignments.begin(), client->server_group_assignments.end(), [&](const ServerGroupAssignment& assignment) {
|
||||
return assignment.group_id == group_id;
|
||||
});
|
||||
if(it == client->server_group_assignments.end())
|
||||
continue;
|
||||
result.push_back(client->client_database_id);
|
||||
}
|
||||
} else {
|
||||
auto res = sql::command(this->sql_manager(), "SELECT `cldbid` FROM `assignedGroups` WHERE `serverId` = :sid AND `channelId` = 0 AND `groupId` = :gid", variable{":sid", this->server_id()}, variable{":gid", group_id})
|
||||
.query([&](int length, std::string* value, std::string* column) {
|
||||
ClientDbId cldbid{0};
|
||||
try {
|
||||
for(int index = 0; index < length; index++) {
|
||||
if(column[index] == "cldbid") {
|
||||
cldbid = std::stoull(value[index]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch(std::exception& ex) {
|
||||
logWarning(this->server_id(), "Invalid data found in group assignment table. Failed to parse client database id.");
|
||||
return 0;
|
||||
}
|
||||
if(!cldbid) return 0;
|
||||
|
||||
result.push_back(cldbid);
|
||||
return 0;
|
||||
});
|
||||
LOG_SQL_CMD(res);
|
||||
}
|
||||
|
||||
if(auto parent = this->manager_->parent_manager(); parent) {
|
||||
auto parent_clients = parent->assignments().server_group_clients(group_id);
|
||||
result.insert(result.begin(), parent_clients.begin(), parent_clients.end());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GroupAssignmentResult GroupAssignmentManager::add_server_group(ClientDbId client, GroupId group) {
|
||||
bool cache_verified{false};
|
||||
{
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
for(auto& entry : this->client_cache) {
|
||||
if(entry->client_database_id != client) continue;
|
||||
|
||||
auto it = std::find_if(entry->server_group_assignments.begin(), entry->server_group_assignments.end(), [&](const ServerGroupAssignment& assignment) {
|
||||
return assignment.group_id == group;
|
||||
});
|
||||
if(it != entry->server_group_assignments.end())
|
||||
return GroupAssignmentResult::ADD_ALREADY_MEMBER_OF_GROUP;
|
||||
entry->server_group_assignments.emplace_back(group);
|
||||
cache_verified = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!cache_verified && kCacheAllClients) {
|
||||
/* add the client to the cache */
|
||||
auto cache = std::make_unique<ClientCache>();
|
||||
cache->client_database_id = client;
|
||||
cache->server_group_assignments.emplace_back(group);
|
||||
this->client_cache.push_back(std::move(cache));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
auto command = sql::command(this->sql_manager(), "INSERT INTO `assignedGroups` (`serverId`, `cldbid`, `groupId`, `channelId`, `until`) VALUES (:sid, :cldbid, :gid, :chid, :until)",
|
||||
variable{":sid", this->server_id()},
|
||||
variable{":cldbid", client},
|
||||
variable{":gid", group},
|
||||
variable{":chid", 0},
|
||||
variable{":until", 0});
|
||||
if(cache_verified)
|
||||
command.executeLater().waitAndGetLater(LOG_SQL_CMD, {-1, "failed to insert group assignment into the database"});
|
||||
else {
|
||||
auto result = command.execute();
|
||||
if(!result) return GroupAssignmentResult::ADD_ALREADY_MEMBER_OF_GROUP; //TODO: Parse error from database?
|
||||
}
|
||||
}
|
||||
return GroupAssignmentResult::SUCCESS;
|
||||
}
|
||||
|
||||
GroupAssignmentResult GroupAssignmentManager::remove_server_group(ClientDbId client, GroupId group) {
|
||||
bool cache_verified{false};
|
||||
{
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
for(auto& entry : this->client_cache) {
|
||||
if(entry->client_database_id != client) continue;
|
||||
|
||||
auto it = std::find_if(entry->server_group_assignments.begin(), entry->server_group_assignments.end(), [&](const ServerGroupAssignment& assignment) {
|
||||
return assignment.group_id == group;
|
||||
});
|
||||
if(it == entry->server_group_assignments.end())
|
||||
return GroupAssignmentResult::REMOVE_NOT_MEMBER_OF_GROUP;
|
||||
entry->server_group_assignments.erase(it);
|
||||
cache_verified = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!cache_verified && kCacheAllClients)
|
||||
return GroupAssignmentResult::REMOVE_NOT_MEMBER_OF_GROUP;
|
||||
}
|
||||
|
||||
{
|
||||
auto command = sql::command(this->sql_manager(), "DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `groupId` = :gid AND `channelId` = :chid",
|
||||
variable{":sid", this->server_id()},
|
||||
variable{":cldbid", client},
|
||||
variable{":gid", group},
|
||||
variable{":chid", 0});
|
||||
if(cache_verified)
|
||||
command.executeLater().waitAndGetLater(LOG_SQL_CMD, {-1, "failed to remove group assignment from database"});
|
||||
else {
|
||||
auto result = command.execute();
|
||||
if(!result) {
|
||||
return GroupAssignmentResult::REMOVE_NOT_MEMBER_OF_GROUP; //TODO: Parse error from database?
|
||||
}
|
||||
}
|
||||
}
|
||||
return GroupAssignmentResult::SUCCESS;
|
||||
}
|
||||
|
||||
GroupAssignmentResult GroupAssignmentManager::set_channel_group(ClientDbId client, GroupId group, ChannelId channel_id, bool temporary) {
|
||||
bool cache_verified{false};
|
||||
{
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
for(auto& entry : this->client_cache) {
|
||||
if(entry->client_database_id != client) continue;
|
||||
|
||||
auto it = std::find_if(entry->channel_group_assignments.begin(), entry->channel_group_assignments.end(), [&](const ChannelGroupAssignment& assignment) {
|
||||
return assignment.channel_id == channel_id;
|
||||
});
|
||||
if(it != entry->channel_group_assignments.end()) {
|
||||
if(group) {
|
||||
if(it->group_id == group)
|
||||
return GroupAssignmentResult::SET_ALREADY_MEMBER_OF_GROUP;
|
||||
it->group_id = group;
|
||||
} else {
|
||||
entry->channel_group_assignments.erase(it);
|
||||
}
|
||||
} else {
|
||||
if(group) {
|
||||
entry->channel_group_assignments.emplace_back(channel_id, group, temporary);
|
||||
}
|
||||
}
|
||||
cache_verified = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!cache_verified && kCacheAllClients) {
|
||||
if(group) {
|
||||
/* add the client to the cache */
|
||||
auto cache = std::make_unique<ClientCache>();
|
||||
cache->client_database_id = client;
|
||||
cache->channel_group_assignments.emplace_back(channel_id, group, temporary);
|
||||
this->client_cache.push_back(std::move(cache));
|
||||
} else {
|
||||
return GroupAssignmentResult::SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(temporary)
|
||||
return GroupAssignmentResult::SUCCESS;
|
||||
|
||||
sql::command(this->sql_manager(), "DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = :chid",
|
||||
variable{":sid", this->server_id()},
|
||||
variable{":cldbid", client},
|
||||
variable{":chid", channel_id})
|
||||
.executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "failed to delete old channel group assignment"});
|
||||
|
||||
if(group) {
|
||||
sql::command(this->sql_manager(), "INSERT INTO `assignedGroups` (`serverId`, `cldbid`, `groupId`, `channelId`, `until`) VALUES (:sid, :cldbid, :gid, :chid, :until)",
|
||||
variable{":sid", this->server_id()},
|
||||
variable{":cldbid", client},
|
||||
variable{":gid", group},
|
||||
variable{":chid", channel_id},
|
||||
variable{":until", 0})
|
||||
.executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "failed to insert channel group assignment"});
|
||||
}
|
||||
return GroupAssignmentResult::SUCCESS;
|
||||
}
|
||||
|
||||
void GroupAssignmentManager::cleanup_channel_assignments(ChannelId channel_id) {
|
||||
{
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
for(auto& client : this->client_cache) {
|
||||
client->channel_group_assignments.erase(std::find_if(client->channel_group_assignments.begin(), client->channel_group_assignments.end(), [&](const ChannelGroupAssignment& assignment) {
|
||||
return assignment.channel_id == channel_id;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
sql::command(this->sql_manager(), "DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `channelId` = :cid", variable{":sid", this->server_id()}, variable{":cid", channel_id})
|
||||
.executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
|
||||
}
|
||||
|
||||
void GroupAssignmentManager::cleanup_assignments() {
|
||||
{
|
||||
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
this->client_cache.clear();
|
||||
}
|
||||
|
||||
sql::command(this->sql_manager(), "DELETE FROM `assignedGroups` WHERE `serverId` = :sid", variable{":sid", this->server_id()})
|
||||
.executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
|
||||
}
|
||||
|
||||
void GroupAssignmentManager::cleanup_channel_temporary_assignment(ClientDbId client_dbid, ChannelId channel) {
|
||||
std::lock_guard cache_lock{this->client_cache_lock};
|
||||
for(auto& client : this->client_cache) {
|
||||
if(client->client_database_id == client_dbid) {
|
||||
auto assignment = std::find_if(client->channel_group_assignments.begin(), client->channel_group_assignments.end(), [&](const ChannelGroupAssignment& assignment) {
|
||||
return assignment.channel_id == channel;
|
||||
});
|
||||
if(assignment->temporary_assignment)
|
||||
client->channel_group_assignments.erase(assignment);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
106
server/src/groups/GroupAssignmentManager.h
Normal file
106
server/src/groups/GroupAssignmentManager.h
Normal file
@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <Definitions.h>
|
||||
#include <Properties.h>
|
||||
|
||||
namespace sql {
|
||||
class SqlManager;
|
||||
}
|
||||
|
||||
namespace ts::server {
|
||||
class ConnectedClient;
|
||||
|
||||
namespace groups {
|
||||
enum struct GroupAssignmentCalculateMode {
|
||||
LOCAL, /* only calculate clients groups for the local server */
|
||||
GLOBAL /* use the parent group manager as well, if existing */
|
||||
};
|
||||
|
||||
class ServerGroup;
|
||||
class ChannelGroup;
|
||||
class GroupManager;
|
||||
|
||||
struct ChannelGroupAssignment {
|
||||
ChannelGroupAssignment(ChannelId channel_id, GroupId group_id, bool t) : channel_id{channel_id}, group_id{group_id}, temporary_assignment{t} { }
|
||||
ChannelGroupAssignment(const ChannelGroupAssignment& other) = default;
|
||||
ChannelGroupAssignment(ChannelGroupAssignment&&) = default;
|
||||
ChannelGroupAssignment&operator=(const ChannelGroupAssignment&) = default;
|
||||
|
||||
ChannelId channel_id;
|
||||
GroupId group_id;
|
||||
bool temporary_assignment;
|
||||
};
|
||||
|
||||
struct ServerGroupAssignment {
|
||||
explicit ServerGroupAssignment(GroupId group_id) : group_id{group_id} { }
|
||||
ServerGroupAssignment(const ServerGroupAssignment& other) = default;
|
||||
ServerGroupAssignment(ServerGroupAssignment&&) = default;
|
||||
ServerGroupAssignment&operator=(const ServerGroupAssignment&) = default;
|
||||
|
||||
GroupId group_id;
|
||||
};
|
||||
|
||||
enum struct GroupAssignmentResult {
|
||||
SUCCESS,
|
||||
ADD_ALREADY_MEMBER_OF_GROUP,
|
||||
REMOVE_NOT_MEMBER_OF_GROUP,
|
||||
SET_ALREADY_MEMBER_OF_GROUP
|
||||
};
|
||||
|
||||
class GroupAssignmentManager {
|
||||
constexpr static bool kCacheAllClients{true};
|
||||
public:
|
||||
explicit GroupAssignmentManager(GroupManager* /* manager */);
|
||||
~GroupAssignmentManager();
|
||||
|
||||
/* general load/initialize methods */
|
||||
bool initialize(std::string& /* error */);
|
||||
bool load_data(std::string& /* error */);
|
||||
void unload_data();
|
||||
|
||||
/* client specific cache methods */
|
||||
void enable_cache_for_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
|
||||
void disable_cache_for_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
|
||||
|
||||
/* info/query methods */
|
||||
[[nodiscard]] std::vector<GroupId> server_groups_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
|
||||
[[nodiscard]] std::vector<ChannelGroupAssignment> channel_group_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
|
||||
|
||||
[[nodiscard]] std::deque<ClientDbId> server_group_clients(GroupId /* group id */);
|
||||
//[[nodiscard]] std::deque<ClientDbId> channel_group_clients(GroupId /* group id */, ChannelId /* channel id */);
|
||||
|
||||
/* change methods */
|
||||
GroupAssignmentResult add_server_group(ClientDbId /* client database id */, GroupId /* group id */);
|
||||
GroupAssignmentResult remove_server_group(ClientDbId /* client database id */, GroupId /* group id */);
|
||||
|
||||
GroupAssignmentResult set_channel_group(ClientDbId /* client database id */, GroupId /* group id */, ChannelId /* channel id */, bool /* temporary assignment */);
|
||||
|
||||
void cleanup_assignments();
|
||||
void cleanup_channel_assignments(ChannelId /* channel */);
|
||||
void cleanup_channel_temporary_assignment(ClientDbId /* client database id */, ChannelId /* channel */);
|
||||
private:
|
||||
struct ClientCache {
|
||||
ClientDbId client_database_id{0};
|
||||
size_t use_count{0};
|
||||
|
||||
std::deque<ChannelGroupAssignment> channel_group_assignments{};
|
||||
std::deque<ServerGroupAssignment> server_group_assignments{};
|
||||
};
|
||||
|
||||
GroupManager* manager_;
|
||||
|
||||
std::mutex client_cache_lock;
|
||||
std::deque<std::unique_ptr<ClientCache>> client_cache{};
|
||||
|
||||
|
||||
[[nodiscard]] sql::SqlManager* sql_manager();
|
||||
[[nodiscard]] ServerId server_id();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
346
server/src/groups/GroupManager.cpp
Normal file
346
server/src/groups/GroupManager.cpp
Normal file
@ -0,0 +1,346 @@
|
||||
//
|
||||
// Created by WolverinDEV on 03/03/2020.
|
||||
//
|
||||
#include <string>
|
||||
#include <log/LogUtils.h>
|
||||
#include "./GroupManager.h"
|
||||
#include "../InstanceHandler.h"
|
||||
|
||||
using namespace ts::server::groups;
|
||||
|
||||
GroupManager::GroupManager(sql::SqlManager *sql, ServerId server_id, std::shared_ptr<GroupManager> parent)
|
||||
: virtual_server_id_{server_id}, database_{sql}, parent_manager_{std::move(parent)}, assignment_manager_{this}
|
||||
{
|
||||
assert(sql);
|
||||
}
|
||||
|
||||
GroupManager::~GroupManager() = default;
|
||||
|
||||
ts::ServerId GroupManager::server_id() {
|
||||
return this->virtual_server_id_;
|
||||
}
|
||||
|
||||
sql::SqlManager* GroupManager::sql_manager() {
|
||||
return this->database_;
|
||||
}
|
||||
|
||||
bool GroupManager::initialize(const std::shared_ptr<GroupManager>& self, std::string &error) {
|
||||
assert(&*self == this);
|
||||
|
||||
if(this->parent_manager_) {
|
||||
this->server_groups_ = std::make_shared<ServerGroupManager>(self, this->parent_manager_->server_groups_);
|
||||
this->channel_groups_ = std::make_shared<ChannelGroupManager>(self, this->parent_manager_->channel_groups_);
|
||||
} else {
|
||||
this->server_groups_ = std::make_shared<ServerGroupManager>(self, nullptr);
|
||||
this->channel_groups_ = std::make_shared<ChannelGroupManager>(self, nullptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Abstract group manager */
|
||||
AbstractGroupManager::AbstractGroupManager(
|
||||
sql::SqlManager* database,
|
||||
DatabaseGroupTarget database_target_,
|
||||
ServerId virtual_server_id,
|
||||
std::shared_ptr<AbstractGroupManager> parent
|
||||
) : database_{database}, database_target_{database_target_}, virtual_server_id_{virtual_server_id}, parent_manager_{std::move(parent)} { }
|
||||
|
||||
ts::ServerId AbstractGroupManager::server_id() {
|
||||
return this->virtual_server_id_;
|
||||
}
|
||||
|
||||
sql::SqlManager *AbstractGroupManager::sql_manager() {
|
||||
return this->database_;
|
||||
}
|
||||
|
||||
bool AbstractGroupManager::initialize(std::string &) {
|
||||
return true;
|
||||
}
|
||||
|
||||
GroupLoadResult AbstractGroupManager::load_data(bool initialize) {
|
||||
std::lock_guard manage_lock{this->group_manage_mutex_};
|
||||
{
|
||||
std::lock_guard list_lock{this->group_mutex_};
|
||||
this->groups_.clear();
|
||||
}
|
||||
|
||||
{
|
||||
auto command = sql::command{this->sql_manager(), "SELECT * FROM `groups` WHERE `serverId` = :sid AND `target` = :target"};
|
||||
command.value(":sid", this->server_id());
|
||||
command.value(":target", (uint8_t) this->database_target_);
|
||||
auto result = command.query(&AbstractGroupManager::insert_group_from_sql, this);
|
||||
if(!result) {
|
||||
LOG_SQL_CMD(result);
|
||||
return GroupLoadResult::DATABASE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard list_lock{this->group_mutex_};
|
||||
if(this->groups_.empty()) {
|
||||
return GroupLoadResult::NO_GROUPS;
|
||||
}
|
||||
}
|
||||
|
||||
return GroupLoadResult::SUCCESS;
|
||||
}
|
||||
|
||||
void AbstractGroupManager::unload_data() {
|
||||
std::lock_guard manage_lock{this->group_manage_mutex_};
|
||||
{
|
||||
std::lock_guard list_lock{this->group_mutex_};
|
||||
this->groups_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractGroupManager::reset_groups(bool db_cleanup) {
|
||||
std::lock_guard manage_lock{this->group_manage_mutex_};
|
||||
this->unload_data();
|
||||
|
||||
if(db_cleanup) {
|
||||
/* FIXME: Only delete groups with our database target! */
|
||||
LOG_SQL_CMD(sql::command(this->sql_manager(), "DELETE FROM `permissions` WHERE `serverId` = :serverId AND `type` = :type",
|
||||
variable{":serverId", this->server_id()},
|
||||
variable{":type", ts::permission::SQL_PERM_GROUP}).execute());
|
||||
LOG_SQL_CMD(sql::command(this->sql_manager(), "DELETE FROM `assignedGroups` WHERE `serverId` = :serverId",
|
||||
variable{":serverId", this->server_id()}).execute());
|
||||
LOG_SQL_CMD(sql::command(this->sql_manager(), "DELETE FROM `groups` WHERE `serverId` = :serverId",
|
||||
variable{":serverId", this->server_id()}).execute());
|
||||
}
|
||||
|
||||
if(auto error = this->load_data(true); error != GroupLoadResult::SUCCESS) {
|
||||
logCritical(this->server_id(), "Failed to load groups after group unload ({}). There might be no groups loaded now!", (int) error);
|
||||
}
|
||||
}
|
||||
|
||||
int AbstractGroupManager::insert_group_from_sql(int length, std::string *values, std::string *names) {
|
||||
GroupId group_id{0};
|
||||
GroupType group_type{GroupType::GROUP_TYPE_UNKNOWN};
|
||||
std::string group_name{};
|
||||
|
||||
for(size_t index = 0; index < length; index++) {
|
||||
try {
|
||||
if(names[index] == "groupId") {
|
||||
group_id = std::stoull(values[index]);
|
||||
} else if(names[index] == "target") {
|
||||
/* group_target = (GroupTarget) std::stoull(values[index]); */
|
||||
} else if(names[index] == "type") {
|
||||
group_type = (GroupType) std::stoull(values[index]);
|
||||
} else if(names[index] == "displayName") {
|
||||
group_name = names[index];
|
||||
}
|
||||
} catch(std::exception& ex) {
|
||||
logWarning(this->server_id(), "Failed to parse group from database. Failed to parse column {} (value: {})", names[index], values[index]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(!group_id) {
|
||||
logWarning(this->server_id(), "Failed to query group from database. Invalid values found.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto permissions = serverInstance->databaseHelper()->loadGroupPermissions(this->server_id(), group_id, (uint8_t) this->database_target_);
|
||||
auto group = this->allocate_group(group_id, group_type, group_name, permissions);
|
||||
|
||||
std::lock_guard lock{this->group_mutex_};
|
||||
this->groups_.push_back(group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<Group> AbstractGroupManager::find_group_(GroupCalculateMode mode, GroupId group_id) {
|
||||
{
|
||||
std::lock_guard glock{this->group_mutex_};
|
||||
auto it = std::find_if(this->groups_.begin(), this->groups_.end(), [&](const std::shared_ptr<Group>& group) {
|
||||
return group->group_id() == group_id;
|
||||
});
|
||||
|
||||
if(it != this->groups_.end()) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
if(mode == GroupCalculateMode::GLOBAL && this->parent_manager_) {
|
||||
return this->parent_manager_->find_group_(mode, group_id);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Group> AbstractGroupManager::find_group_by_name_(GroupCalculateMode mode, const std::string &name) {
|
||||
{
|
||||
std::string lname{name};
|
||||
std::transform(lname.begin(), lname.end(), lname.begin(), ::tolower);
|
||||
|
||||
std::lock_guard glock{this->group_mutex_};
|
||||
auto it = std::find_if(this->groups_.begin(), this->groups_.end(),
|
||||
[&](const std::shared_ptr<Group> &group) {
|
||||
std::string lgroup_name{group->display_name()};
|
||||
std::transform(lgroup_name.begin(), lgroup_name.end(), lgroup_name.begin(), ::tolower);
|
||||
return lname == lgroup_name;
|
||||
});
|
||||
|
||||
if(it != this->groups_.end()) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == GroupCalculateMode::GLOBAL && this->parent_manager_) {
|
||||
return this->parent_manager_->find_group_by_name_(mode, name);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GroupCreateResult AbstractGroupManager::create_group_(GroupType type, const std::string &name, std::shared_ptr<Group>& result) {
|
||||
std::lock_guard manage_lock{this->group_manage_mutex_};
|
||||
if(this->find_group_by_name_(GroupCalculateMode::LOCAL, name)) {
|
||||
return GroupCreateResult::NAME_ALREADY_IN_USED;
|
||||
}
|
||||
|
||||
auto res = sql::command(this->sql_manager(), "INSERT INTO `groups` (`serverId`, `target`, `type`, `displayName`) VALUES (:sid, :target, :type, :name)",
|
||||
variable{":sid", this->server_id()},
|
||||
variable{":target", (uint8_t) this->database_target_},
|
||||
variable{":type", type},
|
||||
variable{":name", name}).execute();
|
||||
|
||||
if(!res) {
|
||||
LOG_SQL_CMD(res);
|
||||
return GroupCreateResult::DATABASE_ERROR;
|
||||
}
|
||||
|
||||
auto group_id = res.last_insert_rowid();
|
||||
auto permissions = serverInstance->databaseHelper()->loadGroupPermissions(this->server_id(), group_id, (uint8_t) this->database_target_);
|
||||
auto group = std::make_shared<ServerGroup>(this->server_id(), group_id, type, name, permissions);
|
||||
{
|
||||
std::lock_guard glock{this->group_mutex_};
|
||||
this->groups_.push_back(group);
|
||||
}
|
||||
result = group;
|
||||
return GroupCreateResult::SUCCESS;
|
||||
}
|
||||
|
||||
GroupCopyResult AbstractGroupManager::copy_group_(GroupId source, GroupType target_type, const std::string &display_name, std::shared_ptr<Group>& result) {
|
||||
std::lock_guard manage_lock{this->group_manage_mutex_};
|
||||
|
||||
auto create_result = this->create_group_(target_type, display_name, result);
|
||||
switch(create_result) {
|
||||
case GroupCreateResult::SUCCESS:
|
||||
break;
|
||||
|
||||
case GroupCreateResult::DATABASE_ERROR:
|
||||
return GroupCopyResult::DATABASE_ERROR;
|
||||
|
||||
case GroupCreateResult::NAME_ALREADY_IN_USED:
|
||||
return GroupCopyResult::NAME_ALREADY_IN_USE;
|
||||
|
||||
case GroupCreateResult::FAILED_TO_GENERATE_ID:
|
||||
return GroupCopyResult::FAILED_TO_GENERATE_ID;
|
||||
}
|
||||
|
||||
assert(result);
|
||||
return this->copy_group_permissions_(source, result->group_id());
|
||||
}
|
||||
|
||||
GroupCopyResult AbstractGroupManager::copy_group_permissions_(GroupId source, GroupId target) {
|
||||
std::lock_guard manage_lock{this->group_manage_mutex_};
|
||||
|
||||
auto source_group = this->find_group_(groups::GroupCalculateMode::GLOBAL, source);
|
||||
if(!source_group) {
|
||||
return GroupCopyResult::UNKNOWN_SOURCE_GROUP;
|
||||
}
|
||||
|
||||
auto target_group = this->find_group_(groups::GroupCalculateMode::GLOBAL, target);
|
||||
if(!target_group) {
|
||||
return GroupCopyResult::UNKNOWN_TARGET_GROUP;
|
||||
}
|
||||
|
||||
auto res = sql::command(this->sql_manager(), "DELETE FROM `permissions` WHERE `serverId` = :sid AND `type` = :type AND `id` = :id",
|
||||
variable{":sid", this->server_id()},
|
||||
variable{":type", ts::permission::SQL_PERM_GROUP},
|
||||
variable{":id", target}).execute();
|
||||
if(!res) {
|
||||
LOG_SQL_CMD(res);
|
||||
return GroupCopyResult::DATABASE_ERROR;
|
||||
}
|
||||
|
||||
res = sql::command(this->sql_manager(), "INSERT INTO `permissions` (`serverId`, `type`, `id`, `channelId`, `permId`, `value`, `grant`, `flag_skip`, `flag_negate`) SELECT :tsid AS `serverId`, `type`, :target AS `id`, 0 AS `channelId`, `permId`, `value`,`grant`,`flag_skip`, `flag_negate` FROM `permissions` WHERE `serverId` = :ssid AND `type` = :type AND `id` = :source",
|
||||
variable{":ssid", source_group->virtual_server_id()},
|
||||
variable{":tsid", target_group->virtual_server_id()},
|
||||
variable{":type", ts::permission::SQL_PERM_GROUP},
|
||||
variable{":source", source},
|
||||
variable{":target", target}).execute();
|
||||
|
||||
target_group->set_permissions(serverInstance->databaseHelper()->loadGroupPermissions(this->server_id(), target, (uint8_t) this->database_target_));
|
||||
LOG_SQL_CMD(res);
|
||||
|
||||
return GroupCopyResult::SUCCESS;
|
||||
}
|
||||
|
||||
GroupRenameResult AbstractGroupManager::rename_group_(GroupId group_id, const std::string &name) {
|
||||
std::lock_guard manage_lock{this->group_manage_mutex_};
|
||||
if(name.empty() || name.length() > 40) {
|
||||
return GroupRenameResult::NAME_INVALID;
|
||||
}
|
||||
|
||||
auto group = this->find_group_(groups::GroupCalculateMode::GLOBAL, group_id);
|
||||
if(!group) {
|
||||
return GroupRenameResult::INVALID_GROUP_ID;
|
||||
}
|
||||
|
||||
if(this->find_group_by_name_(GroupCalculateMode::LOCAL, name)) {
|
||||
return GroupRenameResult::NAME_ALREADY_USED;
|
||||
}
|
||||
|
||||
sql::command(this->sql_manager(), "UPDATE `groups` SET `displayName` = :name WHERE `serverId` = :server AND `groupId` = :group_id AND `target` = :target",
|
||||
variable{":server", this->server_id()},
|
||||
variable{":target", (uint8_t) this->database_target_},
|
||||
variable{":group_id", group_id}).executeLater().waitAndGetLater(LOG_SQL_CMD, {-1, "future failed"});
|
||||
group->name_ = name;
|
||||
return GroupRenameResult::SUCCESS;
|
||||
}
|
||||
|
||||
GroupDeleteResult AbstractGroupManager::delete_group_(GroupId group_id) {
|
||||
std::lock_guard manage_lock{this->group_manage_mutex_};
|
||||
|
||||
{
|
||||
std::lock_guard glock{this->group_mutex_};
|
||||
auto it = std::find_if(this->groups_.begin(), this->groups_.begin(), [&](const std::shared_ptr<Group>& group) {
|
||||
return group->group_id() == group_id;
|
||||
});
|
||||
|
||||
if(it == this->groups_.end()) {
|
||||
return GroupDeleteResult::INVALID_GROUP_ID;
|
||||
}
|
||||
|
||||
this->groups_.erase(it);
|
||||
}
|
||||
|
||||
sql::command(this->sql_manager(), "DELETE FROM WHERE `serverId` = :server AND `groupId` = :group_id AND `target` = :target",
|
||||
variable{":server", this->server_id()},
|
||||
variable{":target", (uint8_t) this->database_target_},
|
||||
variable{":group_id", group_id}).executeLater().waitAndGetLater(LOG_SQL_CMD, {-1, "future failed"});
|
||||
return GroupDeleteResult::SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Server group manager */
|
||||
ServerGroupManager::ServerGroupManager(const std::shared_ptr<GroupManager> &handle, std::shared_ptr<ServerGroupManager> parent)
|
||||
: AbstractGroupManager{handle->sql_manager(), DatabaseGroupTarget::SERVER, handle->server_id(), parent}
|
||||
{
|
||||
|
||||
}
|
||||
std::shared_ptr<Group> ServerGroupManager::allocate_group(GroupId id, GroupType type, std::string name,
|
||||
std::shared_ptr<permission::v2::PermissionManager> permissions) {
|
||||
return std::make_shared<ServerGroup>(this->server_id(), id, type, name, permissions);
|
||||
}
|
||||
|
||||
|
||||
/* Channel group manager */
|
||||
ChannelGroupManager::ChannelGroupManager(const std::shared_ptr<GroupManager> &handle, std::shared_ptr<ChannelGroupManager> parent)
|
||||
: AbstractGroupManager{handle->sql_manager(), DatabaseGroupTarget::SERVER, handle->server_id(), parent}
|
||||
{
|
||||
|
||||
}
|
||||
std::shared_ptr<Group> ChannelGroupManager::allocate_group(GroupId id, GroupType type, std::string name,
|
||||
std::shared_ptr<permission::v2::PermissionManager> permissions) {
|
||||
return std::make_shared<ChannelGroup>(this->server_id(), id, type, name, permissions);
|
||||
}
|
247
server/src/groups/GroupManager.h
Normal file
247
server/src/groups/GroupManager.h
Normal file
@ -0,0 +1,247 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <Definitions.h>
|
||||
#include <sql/SqlQuery.h>
|
||||
#include "./GroupAssignmentManager.h"
|
||||
#include "./Group.h"
|
||||
|
||||
namespace ts::server::groups {
|
||||
enum struct GroupCalculateMode {
|
||||
LOCAL, /* only calculate clients groups for the local server */
|
||||
GLOBAL /* use the parent group manager as well, if existing */
|
||||
};
|
||||
|
||||
enum struct GroupLoadResult {
|
||||
SUCCESS,
|
||||
NO_GROUPS,
|
||||
DATABASE_ERROR
|
||||
};
|
||||
|
||||
enum struct GroupCreateResult {
|
||||
SUCCESS,
|
||||
NAME_ALREADY_IN_USED,
|
||||
FAILED_TO_GENERATE_ID,
|
||||
DATABASE_ERROR
|
||||
};
|
||||
|
||||
enum struct GroupCopyResult {
|
||||
SUCCESS,
|
||||
UNKNOWN_SOURCE_GROUP,
|
||||
UNKNOWN_TARGET_GROUP,
|
||||
NAME_ALREADY_IN_USE,
|
||||
FAILED_TO_GENERATE_ID,
|
||||
DATABASE_ERROR
|
||||
};
|
||||
|
||||
enum struct GroupRenameResult {
|
||||
SUCCESS,
|
||||
INVALID_GROUP_ID,
|
||||
NAME_ALREADY_USED,
|
||||
NAME_INVALID,
|
||||
DATABASE_ERROR
|
||||
};
|
||||
|
||||
enum struct GroupDeleteResult {
|
||||
SUCCESS,
|
||||
INVALID_GROUP_ID,
|
||||
DATABASE_ERROR
|
||||
};
|
||||
|
||||
class GroupManager;
|
||||
class AbstractGroupManager {
|
||||
friend class Group;
|
||||
friend class GroupAssignmentManager;
|
||||
public:
|
||||
enum struct DatabaseGroupTarget : uint8_t {
|
||||
SERVER = 0x00,
|
||||
CHANNEL = 0x01
|
||||
};
|
||||
|
||||
AbstractGroupManager(
|
||||
sql::SqlManager* /* database */,
|
||||
DatabaseGroupTarget /* database group target */,
|
||||
ServerId /* virtual server id */,
|
||||
std::shared_ptr<AbstractGroupManager> /* parent */
|
||||
);
|
||||
|
||||
virtual ~AbstractGroupManager() = default;
|
||||
|
||||
bool initialize(std::string& /* error */);
|
||||
GroupLoadResult load_data(bool /* initialize */ = false);
|
||||
void unload_data();
|
||||
void reset_groups(bool /* cleanup database */);
|
||||
protected:
|
||||
std::shared_ptr<AbstractGroupManager> parent_manager_;
|
||||
DatabaseGroupTarget database_target_;
|
||||
|
||||
sql::SqlManager* database_;
|
||||
ServerId virtual_server_id_;
|
||||
|
||||
/* recursive_mutex due to the copy group methods */
|
||||
std::recursive_mutex group_manage_mutex_{};
|
||||
std::mutex group_mutex_{};
|
||||
|
||||
/* I think std::vector is better here because we will iterate more often than add groups */
|
||||
std::vector<std::shared_ptr<Group>> groups_{};
|
||||
|
||||
[[nodiscard]] sql::SqlManager* sql_manager();
|
||||
[[nodiscard]] ServerId server_id();
|
||||
|
||||
[[nodiscard]] std::shared_ptr<Group> find_group_(GroupCalculateMode /* mode */, GroupId /* group id */);
|
||||
[[nodiscard]] std::shared_ptr<Group> find_group_by_name_(GroupCalculateMode /* mode */, const std::string& /* group name */);
|
||||
[[nodiscard]] GroupCreateResult create_group_(GroupType type, const std::string& /* group name */, std::shared_ptr<Group>& /* result */);
|
||||
[[nodiscard]] GroupCopyResult copy_group_(GroupId /* group id */, GroupType /* target group type */, const std::string& /* target group name */, std::shared_ptr<Group>& /* result */);
|
||||
[[nodiscard]] GroupCopyResult copy_group_permissions_(GroupId /* group id */, GroupId /* target group */);
|
||||
[[nodiscard]] GroupRenameResult rename_group_(GroupId /* group id */, const std::string& /* target group name */);
|
||||
[[nodiscard]] GroupDeleteResult delete_group_(GroupId /* group id */);
|
||||
|
||||
int insert_group_from_sql(int /* length */, std::string* /* values */, std::string* /* columns */);
|
||||
|
||||
virtual std::shared_ptr<Group> allocate_group(
|
||||
GroupId /* id */,
|
||||
GroupType /* type */,
|
||||
std::string /* name */,
|
||||
std::shared_ptr<permission::v2::PermissionManager> /* permissions */
|
||||
) = 0;
|
||||
};
|
||||
|
||||
class ServerGroupManager : public AbstractGroupManager {
|
||||
public:
|
||||
ServerGroupManager(const std::shared_ptr<GroupManager>& /* owner */, std::shared_ptr<ServerGroupManager> /* parent */);
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ServerGroup> find_group(GroupCalculateMode mode, GroupId group_id) {
|
||||
return this->cast_result(this->find_group_(mode, group_id));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ServerGroup> find_group_by_name(GroupCalculateMode mode, const std::string& group_name) {
|
||||
return this->cast_result(this->find_group_by_name_(mode, group_name));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline GroupCreateResult create_group(GroupType type, const std::string& group_name, std::shared_ptr<ServerGroup>& result) {
|
||||
std::shared_ptr<Group> result_;
|
||||
auto r = this->create_group_(type, group_name, result_);
|
||||
result = this->cast_result(result_);
|
||||
return r;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline GroupCopyResult copy_group(GroupId group_id, GroupType target_group_type, const std::string& target_group_name, std::shared_ptr<ServerGroup>& result) {
|
||||
std::shared_ptr<Group> result_;
|
||||
auto r = this->copy_group_(group_id, target_group_type, target_group_name, result_);
|
||||
result = this->cast_result(result_);
|
||||
return r;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline GroupCopyResult copy_group_permissions(GroupId group_id, GroupId target_group) {
|
||||
return this->copy_group_permissions_(group_id, target_group);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline GroupRenameResult rename_group(GroupId group_id, const std::string& target_group_name) {
|
||||
return this->rename_group_(group_id, target_group_name);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline GroupDeleteResult delete_group(GroupId group_id) {
|
||||
return this->delete_group_(group_id);
|
||||
}
|
||||
|
||||
protected:
|
||||
[[nodiscard]] std::shared_ptr<Group> allocate_group(GroupId, GroupType, std::string,
|
||||
std::shared_ptr<permission::v2::PermissionManager>) override;
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ServerGroup> cast_result(std::shared_ptr<Group> result) {
|
||||
if(!result) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto casted = std::dynamic_pointer_cast<ServerGroup>(result);
|
||||
assert(casted);
|
||||
return casted;
|
||||
}
|
||||
};
|
||||
|
||||
class ChannelGroupManager : public AbstractGroupManager {
|
||||
public:
|
||||
ChannelGroupManager(const std::shared_ptr<GroupManager>& /* owner */, std::shared_ptr<ChannelGroupManager> /* parent */);
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ChannelGroup> find_group(GroupCalculateMode mode, GroupId group_id) {
|
||||
return this->cast_result(this->find_group_(mode, group_id));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ChannelGroup> find_group_by_name(GroupCalculateMode mode, const std::string& group_name) {
|
||||
return this->cast_result(this->find_group_by_name_(mode, group_name));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline GroupCreateResult create_group(GroupType type, const std::string& group_name, std::shared_ptr<ChannelGroup>& result) {
|
||||
std::shared_ptr<Group> result_;
|
||||
auto r = this->create_group_(type, group_name, result_);
|
||||
result = this->cast_result(result_);
|
||||
return r;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline GroupCopyResult copy_group(GroupId group_id, GroupType target_group_type, const std::string& target_group_name, std::shared_ptr<ChannelGroup>& result) {
|
||||
std::shared_ptr<Group> result_;
|
||||
auto r = this->copy_group_(group_id, target_group_type, target_group_name, result_);
|
||||
result = this->cast_result(result_);
|
||||
return r;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline GroupCopyResult copy_group_permissions(GroupId group_id, GroupId target_group) {
|
||||
return this->copy_group_permissions_(group_id, target_group);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline GroupRenameResult rename_group(GroupId group_id, const std::string& target_group_name) {
|
||||
return this->rename_group_(group_id, target_group_name);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline GroupDeleteResult delete_group(GroupId group_id) {
|
||||
return this->delete_group_(group_id);
|
||||
}
|
||||
private:
|
||||
std::shared_ptr<Group> allocate_group(GroupId, GroupType, std::string,
|
||||
std::shared_ptr<permission::v2::PermissionManager>) override;
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ChannelGroup> cast_result(std::shared_ptr<Group> result) {
|
||||
if(!result) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto casted = std::dynamic_pointer_cast<ChannelGroup>(result);
|
||||
assert(casted);
|
||||
return casted;
|
||||
}
|
||||
};
|
||||
|
||||
class GroupManager {
|
||||
friend class Group;
|
||||
friend class ServerGroupManager;
|
||||
friend class ChannelGroupManager;
|
||||
friend class GroupAssignmentManager;
|
||||
public:
|
||||
GroupManager(sql::SqlManager* /* database */, ServerId /* virtual server id */, std::shared_ptr<GroupManager> /* parent */);
|
||||
~GroupManager();
|
||||
|
||||
bool initialize(const std::shared_ptr<GroupManager>& /* self ref, */, std::string& /* error */);
|
||||
|
||||
[[nodiscard]] inline const std::shared_ptr<GroupManager>& parent_manager() { return this->parent_manager_; }
|
||||
|
||||
[[nodiscard]] inline GroupAssignmentManager& assignments() { return this->assignment_manager_; }
|
||||
[[nodiscard]] inline const std::shared_ptr<ServerGroupManager>& server_groups() { return this->server_groups_; }
|
||||
[[nodiscard]] inline const std::shared_ptr<ChannelGroupManager>& channel_groups() { return this->channel_groups_; }
|
||||
private:
|
||||
sql::SqlManager* database_;
|
||||
ServerId virtual_server_id_;
|
||||
|
||||
std::shared_ptr<GroupManager> parent_manager_;
|
||||
|
||||
std::shared_ptr<ServerGroupManager> server_groups_{};
|
||||
std::shared_ptr<ChannelGroupManager> channel_groups_{};
|
||||
|
||||
GroupAssignmentManager assignment_manager_;
|
||||
|
||||
[[nodiscard]] sql::SqlManager* sql_manager();
|
||||
[[nodiscard]] ServerId server_id();
|
||||
};
|
||||
}
|
@ -44,7 +44,7 @@ void QueryServer::unregisterConnection(const shared_ptr<QueryClient> &client) {
|
||||
if(client->server) {
|
||||
client->server->getGroupManager()->disableCache(client->getClientDatabaseId());
|
||||
} else {
|
||||
serverInstance->getGroupManager()->disableCache(client->getClientDatabaseId());
|
||||
serverInstance->getOldGroupManager()->disableCache(client->getClientDatabaseId());
|
||||
}
|
||||
/* client->handle = nullptr; */
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user