Some more work for the new group manager
This commit is contained in:
parent
449df23a4b
commit
2d0b9da08d
@ -421,7 +421,7 @@ int main(int argc, char** argv) {
|
|||||||
{
|
{
|
||||||
rlimit rlimit{0, 0};
|
rlimit rlimit{0, 0};
|
||||||
//forum.teaspeak.de/index.php?threads/2570/
|
//forum.teaspeak.de/index.php?threads/2570/
|
||||||
constexpr auto seek_help_message = "Fore more help visit the forum and read this thread (https://forum.teaspeak.de/index.php?threads/2570/).";
|
constexpr auto seek_help_message = "For more help visit the forum and read this thread (https://forum.teaspeak.de/index.php?threads/2570/).";
|
||||||
if(getrlimit(RLIMIT_NOFILE, &rlimit) != 0) {
|
if(getrlimit(RLIMIT_NOFILE, &rlimit) != 0) {
|
||||||
//prlimit -n4096 -p pid_of_process
|
//prlimit -n4096 -p pid_of_process
|
||||||
logWarningFmt(true, LOG_INSTANCE, "Failed to get open file rlimit ({}). Please ensure its over 16384.", strerror(errno));
|
logWarningFmt(true, LOG_INSTANCE, "Failed to get open file rlimit ({}). Please ensure its over 16384.", strerror(errno));
|
||||||
|
@ -84,6 +84,16 @@ void ClientPermissionCalculator::initialize_client(DataClient* client) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PermissionFlaggedValue ClientPermissionCalculator::calculate_permission(permission::PermissionType permission,
|
||||||
|
bool granted) {
|
||||||
|
auto result = this->calculate_permissions({permission}, granted);
|
||||||
|
if(result.empty()) {
|
||||||
|
return { permNotGranted, false };
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.front().second;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionCalculator::calculate_permissions(
|
std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionCalculator::calculate_permissions(
|
||||||
const std::deque<permission::PermissionType> &permissions,
|
const std::deque<permission::PermissionType> &permissions,
|
||||||
bool calculate_granted
|
bool calculate_granted
|
||||||
@ -328,7 +338,8 @@ const std::shared_ptr<groups::ChannelGroup>& ClientPermissionCalculator::assigne
|
|||||||
return *this->assigned_channel_group_;
|
return *this->assigned_channel_group_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto channel_group_assignment = this->group_manager_->assignments().channel_group_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, this->client_database_id, this->channel_id_);
|
auto channel_group_assignment = this->group_manager_->assignments().exact_channel_group_of_client(
|
||||||
|
groups::GroupAssignmentCalculateMode::GLOBAL, this->client_database_id, this->channel_id_);
|
||||||
if(!channel_group_assignment.has_value()) {
|
if(!channel_group_assignment.has_value()) {
|
||||||
return *this->assigned_channel_group_;
|
return *this->assigned_channel_group_;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <misc/sassert.h>
|
#include <misc/sassert.h>
|
||||||
#include <src/manager/ActionLogger.h>
|
#include <src/manager/ActionLogger.h>
|
||||||
#include "InstanceHandler.h"
|
#include "InstanceHandler.h"
|
||||||
|
#include "./groups/GroupManager.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace ts::server;
|
using namespace ts::server;
|
||||||
@ -264,33 +265,6 @@ void VirtualServer::testBanStateChange(const std::shared_ptr<ConnectedClient>& i
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VirtualServer::could_default_create_channel() {
|
|
||||||
{
|
|
||||||
|
|
||||||
auto default_group = this->group_manager()->defaultGroup(GroupTarget::GROUPTARGET_SERVER);
|
|
||||||
if(default_group) {
|
|
||||||
auto flag = default_group->permissions()->permission_value_flagged(permission::b_channel_create_temporary).value == 1;
|
|
||||||
flag = flag ? flag : default_group->permissions()->permission_value_flagged(permission::b_channel_create_semi_permanent).value == 1;
|
|
||||||
flag = flag ? flag : default_group->permissions()->permission_value_flagged(permission::b_channel_create_permanent).value == 1;
|
|
||||||
if(flag)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
|
|
||||||
auto default_group = this->group_manager()->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL);
|
|
||||||
if(default_group) {
|
|
||||||
auto flag = default_group->permissions()->permission_value_flagged(permission::b_channel_create_temporary).value == 1;
|
|
||||||
flag = flag ? flag : default_group->permissions()->permission_value_flagged(permission::b_channel_create_semi_permanent).value == 1;
|
|
||||||
flag = flag ? flag : default_group->permissions()->permission_value_flagged(permission::b_channel_create_permanent).value == 1;
|
|
||||||
if(flag)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VirtualServer::notify_client_ban(const shared_ptr<ConnectedClient> &target, const std::shared_ptr<ts::server::ConnectedClient> &invoker, const std::string &reason, size_t time) {
|
void VirtualServer::notify_client_ban(const shared_ptr<ConnectedClient> &target, const std::shared_ptr<ts::server::ConnectedClient> &invoker, const std::string &reason, size_t time) {
|
||||||
/* the target is not allowed to execute anything; Must before channel tree lock because the target may waits for us to finish the channel stuff */
|
/* the target is not allowed to execute anything; Must before channel tree lock because the target may waits for us to finish the channel stuff */
|
||||||
lock_guard command_lock(target->command_lock);
|
lock_guard command_lock(target->command_lock);
|
||||||
@ -394,11 +368,13 @@ void VirtualServer::delete_channel(shared_ptr<ts::ServerChannel> channel, const
|
|||||||
command_locks.push_back(move(unique_lock(client->command_lock)));
|
command_locks.push_back(move(unique_lock(client->command_lock)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const auto& client : clients)
|
for(const auto& client : clients) {
|
||||||
this->client_move(client, default_channel, invoker, kick_message, ViewReasonId::VREASON_CHANNEL_KICK, true, tree_lock);
|
this->client_move(client, default_channel, invoker, kick_message, ViewReasonId::VREASON_CHANNEL_KICK, true, tree_lock);
|
||||||
|
}
|
||||||
|
|
||||||
if(!tree_lock.owns_lock())
|
if(!tree_lock.owns_lock()) {
|
||||||
tree_lock.lock(); /* no clients left within that tree */
|
tree_lock.lock(); /* no clients left within that tree */
|
||||||
|
}
|
||||||
command_locks.clear();
|
command_locks.clear();
|
||||||
|
|
||||||
auto deleted_channels = this->channelTree->delete_channel_root(channel);
|
auto deleted_channels = this->channelTree->delete_channel_root(channel);
|
||||||
@ -412,7 +388,25 @@ void VirtualServer::delete_channel(shared_ptr<ts::ServerChannel> channel, const
|
|||||||
client->notifyChannelDeleted(client->channels->delete_channel_root(channel), invoker);
|
client->notifyChannelDeleted(client->channels->delete_channel_root(channel), invoker);
|
||||||
});
|
});
|
||||||
|
|
||||||
this->tokenManager->handle_channel_deleted(channel->channelId());
|
{
|
||||||
|
std::vector<ChannelId> deleted_channel_ids{};
|
||||||
|
deleted_channel_ids.reserve(deleted_channels.size());
|
||||||
|
for(const auto& deleted_channel : deleted_channels) {
|
||||||
|
deleted_channel_ids.push_back(deleted_channel->channelId());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ref_self = this->ref();
|
||||||
|
task_id task_id{};
|
||||||
|
serverInstance->general_task_executor()->schedule(task_id, "database cleanup after channel delete", [ref_self, deleted_channel_ids]{
|
||||||
|
for(const auto& deleted_channel_id : deleted_channel_ids) {
|
||||||
|
ref_self->tokenManager->handle_channel_deleted(deleted_channel_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto& deleted_channel_id : deleted_channel_ids) {
|
||||||
|
ref_self->group_manager()->assignments().handle_channel_deleted(deleted_channel_id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualServer::client_move(
|
void VirtualServer::client_move(
|
||||||
@ -450,10 +444,6 @@ void VirtualServer::client_move(
|
|||||||
s_target_channel = dynamic_pointer_cast<ServerChannel>(target_channel);
|
s_target_channel = dynamic_pointer_cast<ServerChannel>(target_channel);
|
||||||
assert(s_target_channel);
|
assert(s_target_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update the group properties here already, so for all enter views we could just send the new props directly */
|
|
||||||
changed_groups = this->groups->update_server_group_property(target, true, s_target_channel);
|
|
||||||
client_updates.insert(client_updates.end(), changed_groups.begin(), changed_groups.end()); //TODO: Only update for clients which have no enter?
|
|
||||||
}
|
}
|
||||||
auto l_target_channel = s_target_channel ? this->channelTree->findLinkedChannel(s_target_channel->channelId()) : nullptr;
|
auto l_target_channel = s_target_channel ? this->channelTree->findLinkedChannel(s_target_channel->channelId()) : nullptr;
|
||||||
auto l_source_channel = s_source_channel ? this->channelTree->findLinkedChannel(s_source_channel->channelId()) : nullptr;
|
auto l_source_channel = s_source_channel ? this->channelTree->findLinkedChannel(s_source_channel->channelId()) : nullptr;
|
||||||
@ -560,12 +550,7 @@ void VirtualServer::client_move(
|
|||||||
|
|
||||||
if (s_source_channel) {
|
if (s_source_channel) {
|
||||||
s_source_channel->properties()[property::CHANNEL_LAST_LEFT] = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
|
s_source_channel->properties()[property::CHANNEL_LAST_LEFT] = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
|
||||||
auto source_channel_group = this->groups->getChannelGroupExact(target->getClientDatabaseId(), s_source_channel, false);
|
this->group_manager()->assignments().cleanup_channel_temporary_assignment(target->getClientDatabaseId(), s_source_channel->channelId());
|
||||||
if(source_channel_group) {
|
|
||||||
auto default_data = source_channel_group->group->permissions()->permission_value_flagged(permission::b_group_is_permanent);
|
|
||||||
if(!default_data.has_value || default_data.value != 1)
|
|
||||||
this->groups->setChannelGroup(target->getClientDatabaseId(), nullptr, s_source_channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto update = target->properties()[property::CLIENT_IS_TALKER].as_or<bool>(false) ||
|
auto update = target->properties()[property::CLIENT_IS_TALKER].as_or<bool>(false) ||
|
||||||
target->properties()[property::CLIENT_TALK_REQUEST].as_or<int64_t>(0) > 0;
|
target->properties()[property::CLIENT_TALK_REQUEST].as_or<int64_t>(0) > 0;
|
||||||
@ -582,15 +567,18 @@ void VirtualServer::client_move(
|
|||||||
|
|
||||||
if (s_target_channel) {
|
if (s_target_channel) {
|
||||||
target->task_update_needed_permissions.enqueue();
|
target->task_update_needed_permissions.enqueue();
|
||||||
|
target->task_update_displayed_groups.enqueue();
|
||||||
TIMING_STEP(timings, "perm gr upd");
|
TIMING_STEP(timings, "perm gr upd");
|
||||||
|
|
||||||
if(s_source_channel) {
|
if(s_source_channel) {
|
||||||
deque<ChannelId> deleted;
|
deque<ChannelId> deleted;
|
||||||
for(const auto& channel : target->channels->test_channel(l_source_channel, l_target_channel))
|
for(const auto& channel : target->channels->test_channel(l_source_channel, l_target_channel)) {
|
||||||
deleted.push_back(channel->channelId());
|
deleted.push_back(channel->channelId());
|
||||||
|
}
|
||||||
|
|
||||||
if(!deleted.empty())
|
if(!deleted.empty()) {
|
||||||
target->notifyChannelHide(deleted, false);
|
target->notifyChannelHide(deleted, false);
|
||||||
|
}
|
||||||
|
|
||||||
auto i_source_channel = s_source_channel->channelId();
|
auto i_source_channel = s_source_channel->channelId();
|
||||||
if(std::find(deleted.begin(), deleted.end(), i_source_channel) == deleted.end()) {
|
if(std::find(deleted.begin(), deleted.end(), i_source_channel) == deleted.end()) {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "VirtualServer.h"
|
#include "VirtualServer.h"
|
||||||
#include "./manager/ConversationManager.h"
|
#include "./manager/ConversationManager.h"
|
||||||
#include "./music/MusicBotManager.h"
|
#include "./music/MusicBotManager.h"
|
||||||
|
#include "./groups/GroupManager.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
@ -234,18 +235,7 @@ void VirtualServer::executeServerTick() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
BEGIN_TIMINGS();
|
BEGIN_TIMINGS();
|
||||||
|
this->group_manager()->save_permissions();
|
||||||
auto groups = this->group_manager()->availableGroups(false);
|
|
||||||
for(auto& group : groups) {
|
|
||||||
auto permissions = group->permissions();
|
|
||||||
if(permissions->require_db_updates()) {
|
|
||||||
auto begin = system_clock::now();
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
END_TIMINGS(timing_groups);
|
END_TIMINGS(timing_groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <protocol/buffers.h>
|
#include <protocol/buffers.h>
|
||||||
#include <openssl/sha.h>
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <tomcrypt.h>
|
#include <tomcrypt.h>
|
||||||
@ -28,6 +27,7 @@
|
|||||||
#include <misc/sassert.h>
|
#include <misc/sassert.h>
|
||||||
#include <src/manager/ActionLogger.h>
|
#include <src/manager/ActionLogger.h>
|
||||||
#include "./groups/GroupManager.h"
|
#include "./groups/GroupManager.h"
|
||||||
|
#include "./PermissionCalculator.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
@ -364,13 +364,35 @@ bool VirtualServer::initialize(bool test_properties) {
|
|||||||
|
|
||||||
/* lets cleanup the conversations for not existent channels */
|
/* lets cleanup the conversations for not existent channels */
|
||||||
this->conversation_manager_->synchronize_channels();
|
this->conversation_manager_->synchronize_channels();
|
||||||
|
|
||||||
|
{
|
||||||
|
auto ref_self = this->self;
|
||||||
|
this->task_notify_channel_group_list = multi_shot_task{serverInstance->general_task_executor(), "server notify channel group list", [ref_self]{
|
||||||
|
auto this_ = ref_self.lock();
|
||||||
|
if(this_) {
|
||||||
|
this_->forEachClient([](const std::shared_ptr<ConnectedClient>& client) {
|
||||||
|
std::optional<ts::command_builder> generated_notify{};
|
||||||
|
client->notifyChannelGroupList(generated_notify, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
this->task_notify_server_group_list = multi_shot_task{serverInstance->general_task_executor(), "server notify server group list", [ref_self]{
|
||||||
|
auto this_ = ref_self.lock();
|
||||||
|
if(this_) {
|
||||||
|
this_->forEachClient([](const std::shared_ptr<ConnectedClient>& client) {
|
||||||
|
std::optional<ts::command_builder> generated_notify{};
|
||||||
|
client->notifyServerGroupList(generated_notify, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualServer::~VirtualServer() {
|
VirtualServer::~VirtualServer() {
|
||||||
memtrack::freed<VirtualServer>(this);
|
memtrack::freed<VirtualServer>(this);
|
||||||
delete this->tokenManager;
|
delete this->tokenManager;
|
||||||
delete this->groups;
|
|
||||||
delete this->channelTree;
|
delete this->channelTree;
|
||||||
delete this->letters;
|
delete this->letters;
|
||||||
delete this->complains;
|
delete this->complains;
|
||||||
@ -653,10 +675,6 @@ void VirtualServer::stop(const std::string& reason, bool disconnect_query) {
|
|||||||
this->webControlServer = nullptr;
|
this->webControlServer = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(this->groups) {
|
|
||||||
this->groups->clearCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
properties()[property::VIRTUALSERVER_CLIENTS_ONLINE] = 0;
|
properties()[property::VIRTUALSERVER_CLIENTS_ONLINE] = 0;
|
||||||
properties()[property::VIRTUALSERVER_QUERYCLIENTS_ONLINE] = 0;
|
properties()[property::VIRTUALSERVER_QUERYCLIENTS_ONLINE] = 0;
|
||||||
properties()[property::VIRTUALSERVER_CHANNELS_ONLINE] = 0;
|
properties()[property::VIRTUALSERVER_CHANNELS_ONLINE] = 0;
|
||||||
@ -778,10 +796,12 @@ std::shared_ptr<ConnectedClient> VirtualServer::findClient(std::string name, boo
|
|||||||
bool VirtualServer::forEachClient(std::function<void(std::shared_ptr<ConnectedClient>)> function) {
|
bool VirtualServer::forEachClient(std::function<void(std::shared_ptr<ConnectedClient>)> function) {
|
||||||
for(const auto& elm : this->getClients()) {
|
for(const auto& elm : this->getClients()) {
|
||||||
shared_lock close_lock(elm->finalDisconnectLock, try_to_lock_t{});
|
shared_lock close_lock(elm->finalDisconnectLock, try_to_lock_t{});
|
||||||
if(close_lock.owns_lock()) //If not locked than client is on the way to disconnect
|
if(close_lock.owns_lock()) {
|
||||||
|
//If not locked than client is on the way to disconnect
|
||||||
if(elm->state == ConnectionState::CONNECTED && elm->getType() != ClientType::CLIENT_INTERNAL) {
|
if(elm->state == ConnectionState::CONNECTED && elm->getType() != ClientType::CLIENT_INTERNAL) {
|
||||||
function(elm);
|
function(elm);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -883,32 +903,6 @@ void VirtualServer::broadcastMessage(std::shared_ptr<ConnectedClient> invoker, s
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<GroupAssignment>> CalculateCache::getGroupAssignments(VirtualServer* server, ClientDbId cldbid, ClientType type) {
|
|
||||||
if(assignment_server_groups_set) return assignment_server_groups;
|
|
||||||
|
|
||||||
assignment_server_groups = server->group_manager()->getServerGroups(cldbid, type);
|
|
||||||
assignment_server_groups_set = true;
|
|
||||||
return assignment_server_groups;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<GroupAssignment> CalculateCache::getChannelAssignment(VirtualServer* server, ClientDbId client_dbid, ChannelId channel_id) {
|
|
||||||
if(this->assignment_channel_group_set && this->assignment_channel_group_channel == channel_id) return this->assignment_channel_group;
|
|
||||||
|
|
||||||
auto channel = this->getServerChannel(server, channel_id);
|
|
||||||
assignment_channel_group = channel ? server->group_manager()->getChannelGroup(client_dbid, channel, true) : nullptr;
|
|
||||||
assignment_channel_group_set = true;
|
|
||||||
assignment_channel_group_channel = channel_id;
|
|
||||||
return assignment_channel_group;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<BasicChannel> CalculateCache::getServerChannel(ts::server::VirtualServer *server, ts::ChannelId channel_id) {
|
|
||||||
if(this->last_server_channel == channel_id)
|
|
||||||
return this->server_channel;
|
|
||||||
this->last_server_channel = channel_id;
|
|
||||||
this->server_channel = server && channel_id > 0 ? server->getChannelTree()->findChannel(channel_id) : nullptr;
|
|
||||||
return this->server_channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
ts_always_inline bool channel_ignore_permission(ts::permission::PermissionType type) {
|
ts_always_inline bool channel_ignore_permission(ts::permission::PermissionType type) {
|
||||||
return permission::i_icon_id == type;
|
return permission::i_icon_id == type;
|
||||||
}
|
}
|
||||||
@ -920,207 +914,8 @@ vector<pair<ts::permission::PermissionType, ts::permission::v2::PermissionFlagge
|
|||||||
ChannelId channel_id,
|
ChannelId channel_id,
|
||||||
bool calculate_granted,
|
bool calculate_granted,
|
||||||
std::shared_ptr<CalculateCache> cache) {
|
std::shared_ptr<CalculateCache> cache) {
|
||||||
if(permissions.empty()) return {};
|
ClientPermissionCalculator calculator{this->ref(), client_dbid, client_type, channel_id};
|
||||||
|
return calculator.calculate_permissions(permissions, calculate_granted);
|
||||||
vector<pair<ts::permission::PermissionType, ts::permission::v2::PermissionFlaggedValue>> result;
|
|
||||||
result.reserve(permissions.size());
|
|
||||||
|
|
||||||
|
|
||||||
if(!cache) {
|
|
||||||
cache = make_shared<CalculateCache>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!cache->client_permissions) {
|
|
||||||
cache->client_permissions = serverInstance->databaseHelper()->loadClientPermissionManager(this->getServerId(), client_dbid);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool have_skip_permission = false;
|
|
||||||
int skip_permission_type = -1; /* -1 := unset | 0 := skip, not explicit | 1 := skip, explicit */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* server_group_data[0] := Server group id
|
|
||||||
* server_group_data[1] := Skip flag
|
|
||||||
* server_group_data[2] := Negate flag
|
|
||||||
* server_group_data[3] := Permission value
|
|
||||||
*/
|
|
||||||
typedef std::tuple<GroupId, bool, bool, permission::PermissionValue> GroupData;
|
|
||||||
bool server_group_data_initialized = false;
|
|
||||||
vector<GroupData> server_group_data;
|
|
||||||
GroupData* active_server_group;
|
|
||||||
|
|
||||||
/* function to calculate skip permission */
|
|
||||||
auto calculate_skip = [&]{
|
|
||||||
skip_permission_type = 0;
|
|
||||||
/* test for skip permission within the client permission manager */
|
|
||||||
{
|
|
||||||
auto skip_value = cache->client_permissions->permission_value_flagged(permission::b_client_skip_channelgroup_permissions);
|
|
||||||
if(skip_value.has_value) {
|
|
||||||
have_skip_permission = skip_value.value == 1;
|
|
||||||
skip_permission_type = 1;
|
|
||||||
logTrace(this->serverId, "[Permission] Found skip permission in client permissions. Value: {}", have_skip_permission);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* test for skip permission within all server groups */
|
|
||||||
if(skip_permission_type != 1) {
|
|
||||||
for(const auto& assignment : cache->getGroupAssignments(this, client_dbid, client_type)) {
|
|
||||||
auto group_permissions = assignment->group->permissions();
|
|
||||||
auto flagged_value = group_permissions->permission_value_flagged(permission::b_client_skip_channelgroup_permissions);
|
|
||||||
if(flagged_value.has_value) {
|
|
||||||
have_skip_permission |= flagged_value.value == 1;
|
|
||||||
if(have_skip_permission) {
|
|
||||||
logTrace(this->serverId, "[Permission] Found skip permission in client server group. Group: {} ({}), Value: {}", assignment->group->groupId(), assignment->group->name(), have_skip_permission);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto initialize_group_data = [&](const permission::PermissionType& permission_type) {
|
|
||||||
server_group_data_initialized = true;
|
|
||||||
active_server_group = nullptr;
|
|
||||||
|
|
||||||
auto assigned_groups = cache->getGroupAssignments(this, client_dbid, client_type);
|
|
||||||
server_group_data.resize(assigned_groups.size());
|
|
||||||
auto it = server_group_data.begin();
|
|
||||||
for(auto& group : assigned_groups) {
|
|
||||||
auto group_permissions = group->group->permissions();
|
|
||||||
auto permission_flags = group_permissions->permission_flags(permission_type);
|
|
||||||
|
|
||||||
auto flag_set = calculate_granted ? permission_flags.grant_set : permission_flags.value_set;
|
|
||||||
if(!flag_set)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//TODO: Test if there is may a group channel permissions
|
|
||||||
auto value = group_permissions->permission_values(permission_type);
|
|
||||||
*it = std::make_tuple(group->group->groupId(), (bool) permission_flags.skip, (bool) permission_flags.negate, calculate_granted ? value.grant : value.value);
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
if(it == server_group_data.begin())
|
|
||||||
return; /* no server group has that permission */
|
|
||||||
|
|
||||||
server_group_data.erase(it, server_group_data.end()); /* remove unneeded */
|
|
||||||
|
|
||||||
auto found_negate = false;
|
|
||||||
for(auto& group : server_group_data) {
|
|
||||||
if(std::get<2>(group)) {
|
|
||||||
found_negate = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(found_negate) {
|
|
||||||
server_group_data.erase(remove_if(server_group_data.begin(), server_group_data.end(), [](auto data) { return !std::get<2>(data); }), server_group_data.end());
|
|
||||||
logTrace(this->serverId, "[Permission] Found negate flag within server groups. Groups left: {}", server_group_data.size());
|
|
||||||
if(server_group_data.empty())
|
|
||||||
logTrace(this->serverId, "[Permission] After non negated groups have been kicked out the negated groups are empty! This should not happen! Permission: {}, Client ID: {}", permission_type, client_dbid);
|
|
||||||
permission::PermissionValue current_lowest = 0;
|
|
||||||
for(auto& group : server_group_data) {
|
|
||||||
if(!active_server_group || (std::get<3>(group) < current_lowest && std::get<3>(group) != -1)) {
|
|
||||||
current_lowest = std::get<3>(group);
|
|
||||||
active_server_group = &group;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
permission::PermissionValue current_highest = 0;
|
|
||||||
for(auto& group : server_group_data) {
|
|
||||||
if(!active_server_group || (std::get<3>(group) > current_highest || std::get<3>(group) == -1)) {
|
|
||||||
current_highest = std::get<3>(group);
|
|
||||||
active_server_group = &group;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for(const auto& permission : permissions) {
|
|
||||||
server_group_data_initialized = false; /* reset all group data */
|
|
||||||
auto client_permission_flags = cache->client_permissions->permission_flags(permission);
|
|
||||||
/* lets try to resolve the channel specific permission */
|
|
||||||
if(channel_id > 0 && client_permission_flags.channel_specific) {
|
|
||||||
auto data = cache->client_permissions->channel_permission(permission, channel_id);
|
|
||||||
if(calculate_granted ? data.flags.grant_set : data.flags.value_set) {
|
|
||||||
result.push_back({permission, {calculate_granted ? data.values.grant : data.values.value, true}});
|
|
||||||
logTrace(this->serverId, "[Permission] Calculation for client {} of permission {} returned {} (Client channel permission)", client_dbid, permission::resolvePermissionData(permission)->name, data.values.value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool skip_channel_permissions = channel_id == 0;
|
|
||||||
if(!skip_channel_permissions) {
|
|
||||||
/* look if somewhere is the skip permission flag set */
|
|
||||||
if(skip_permission_type == -1) {/* initialize skip flag */
|
|
||||||
calculate_skip();
|
|
||||||
}
|
|
||||||
skip_channel_permissions = have_skip_permission;
|
|
||||||
}
|
|
||||||
if(!skip_channel_permissions) {
|
|
||||||
/* okey we've no global skip. Then now lookup the groups and the client permissions */
|
|
||||||
if(calculate_granted ? client_permission_flags.grant_set : client_permission_flags.value_set) {
|
|
||||||
/* okey the client has the permission, this counts */
|
|
||||||
skip_channel_permissions = client_permission_flags.skip;
|
|
||||||
} else {
|
|
||||||
if(!server_group_data_initialized)
|
|
||||||
initialize_group_data(permission);
|
|
||||||
|
|
||||||
if(active_server_group)
|
|
||||||
skip_channel_permissions = std::get<1>(*active_server_group);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!skip_channel_permissions) {
|
|
||||||
/* lookup the channel group */
|
|
||||||
{
|
|
||||||
auto channel_assignment = cache->getChannelAssignment(this, client_dbid, channel_id);
|
|
||||||
if(channel_assignment) {
|
|
||||||
auto group_permissions = channel_assignment->group->permissions();
|
|
||||||
auto permission_flags = group_permissions->permission_flags(permission);
|
|
||||||
|
|
||||||
auto flag_set = calculate_granted ? permission_flags.grant_set : permission_flags.value_set;
|
|
||||||
if(flag_set) {
|
|
||||||
auto value = group_permissions->permission_values(permission);
|
|
||||||
result.push_back({permission, {calculate_granted ? value.grant : value.value, true}});
|
|
||||||
logTrace(this->serverId, "[Permission] Calculation for client {} of permission {} returned {} (Channel group permission)", client_dbid, permission::resolvePermissionData(permission)->name, calculate_granted ? value.grant : value.value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* lookup the channel permissions. Whyever? */
|
|
||||||
{
|
|
||||||
auto channel = cache->getServerChannel(this, channel_id);
|
|
||||||
if(channel) {
|
|
||||||
auto channel_permissions = channel->permissions();
|
|
||||||
auto data = calculate_granted ? channel_permissions->permission_granted_flagged(permission) : channel_permissions->permission_value_flagged(permission);
|
|
||||||
if(data.has_value) {
|
|
||||||
result.push_back({permission, {data.value, true}});
|
|
||||||
logTrace(this->serverId, "[Permission] Calculation for client {} of permission {} returned {} (Channel permission)", client_dbid, permission::resolvePermissionData(permission)->name, data.value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(calculate_granted ? client_permission_flags.grant_set : client_permission_flags.value_set) {
|
|
||||||
auto client_value = cache->client_permissions->permission_values(permission);
|
|
||||||
result.push_back({permission, {calculate_granted ? client_value.grant : client_value.value, true}});
|
|
||||||
logTrace(this->serverId, "[Permission] Calculation for client {} of permission {} returned {} (Client permission)", client_dbid, permission::resolvePermissionData(permission)->name, client_value.value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!server_group_data_initialized)
|
|
||||||
initialize_group_data(permission);
|
|
||||||
if(active_server_group) {
|
|
||||||
result.push_back({permission, {get<3>(*active_server_group), true}});
|
|
||||||
logTrace(this->serverId, "[Permission] Calculation for client {} of permission {} returned {} (Server group permission of group {})", client_dbid, permission::resolvePermissionData(permission)->name, get<3>(*active_server_group), get<0>(*active_server_group));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
logTrace(this->serverId, "[Permission] Calculation for client {} of permission {} returned in no permission.", client_dbid, permission::resolvePermissionData(permission)->name);
|
|
||||||
result.push_back({permission, {permNotGranted, false}});
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
permission::v2::PermissionFlaggedValue VirtualServer::calculate_permission(
|
permission::v2::PermissionFlaggedValue VirtualServer::calculate_permission(
|
||||||
@ -1137,13 +932,16 @@ permission::v2::PermissionFlaggedValue VirtualServer::calculate_permission(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool VirtualServer::verifyServerPassword(std::string password, bool hashed) {
|
bool VirtualServer::verifyServerPassword(std::string password, bool hashed) {
|
||||||
if(!this->properties()[property::VIRTUALSERVER_FLAG_PASSWORD].as_or<bool>(false)) return true;
|
if(!this->properties()[property::VIRTUALSERVER_FLAG_PASSWORD].as_or<bool>(false)) {
|
||||||
if(password.empty()) return false;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if(!hashed){
|
if(password.empty()) {
|
||||||
char buffer[SHA_DIGEST_LENGTH];
|
return false;
|
||||||
SHA1(reinterpret_cast<const unsigned char *>(password.data()), password.length(), reinterpret_cast<unsigned char *>(buffer));
|
}
|
||||||
password = base64_encode(string(buffer, SHA_DIGEST_LENGTH));
|
|
||||||
|
if(!hashed) {
|
||||||
|
password = base64::encode(digest::sha1(password));
|
||||||
}
|
}
|
||||||
|
|
||||||
return password == this->properties()[property::VIRTUALSERVER_PASSWORD].value();
|
return password == this->properties()[property::VIRTUALSERVER_PASSWORD].value();
|
||||||
@ -1175,105 +973,70 @@ VirtualServer::NetworkReport VirtualServer::generate_network_report() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool VirtualServer::resetPermissions(std::string& new_permission_token) {
|
bool VirtualServer::resetPermissions(std::string& new_permission_token) {
|
||||||
LOG_SQL_CMD(sql::command(this->sql, "DELETE FROM `permissions` WHERE `serverId` = :serverId AND `type` != :channel_type", variable{":serverId", this->serverId}, variable{":channel_type", permission::SQL_PERM_CHANNEL}).execute());
|
std::map<GroupId, GroupId> server_group_mapping{};
|
||||||
LOG_SQL_CMD(sql::command(this->sql, "DELETE FROM `assignedGroups` WHERE `serverId` = :serverId", variable{":serverId", this->serverId}).execute());
|
std::map<GroupId, GroupId> channel_group_mapping{};
|
||||||
LOG_SQL_CMD(sql::command(this->sql, "DELETE FROM `groups` WHERE `serverId` = :serverId", variable{":serverId", this->serverId}).execute());
|
{
|
||||||
|
this->group_manager()->server_groups()->reset_groups(serverInstance->group_manager(), server_group_mapping);
|
||||||
|
this->group_manager()->channel_groups()->reset_groups(serverInstance->group_manager(), channel_group_mapping);
|
||||||
|
this->group_manager()->assignments().reset_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assign the properties */
|
||||||
|
{
|
||||||
|
this->properties()[property::VIRTUALSERVER_DEFAULT_SERVER_GROUP] =
|
||||||
|
server_group_mapping[serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP].as_or<GroupId>(0)];
|
||||||
|
|
||||||
|
this->properties()[property::VIRTUALSERVER_DEFAULT_MUSIC_GROUP] =
|
||||||
|
server_group_mapping[serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP].as_or<GroupId>(0)];
|
||||||
|
|
||||||
|
this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP] =
|
||||||
|
channel_group_mapping[serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP].as_or<GroupId>(0)];
|
||||||
|
|
||||||
|
this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP] =
|
||||||
|
channel_group_mapping[serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP].as_or<GroupId>(0)];
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
threads::MutexLock lock(this->group_manager()->cacheLock);
|
this->properties()[property::VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY] = false;
|
||||||
this->group_manager()->deleteAllGroups();
|
|
||||||
deque<shared_ptr<Group>> saved_groups;
|
|
||||||
for(const auto& group : serverInstance->group_manager()->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());
|
auto admin_group_id = server_group_mapping[serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP].as_or<GroupId>(0)];
|
||||||
this->group_manager()->copyGroup(group, GroupType::GROUP_TYPE_NORMAL, group->name(), this->serverId);
|
auto admin_group = this->group_manager()->server_groups()->find_group(groups::GroupCalculateMode::GLOBAL, admin_group_id);
|
||||||
|
if(!admin_group) {
|
||||||
|
logCritical(this->getServerId(), "Missing default server admin group. Don't generate a new token.");
|
||||||
|
new_permission_token = "missing server admin group";
|
||||||
|
} else {
|
||||||
|
auto token = this->tokenManager->create_token(0, "default server admin token", 1, std::chrono::system_clock::time_point{});
|
||||||
|
if(!token) {
|
||||||
|
logCritical(this->serverId, "Failed to register the default server admin token.");
|
||||||
|
} else {
|
||||||
|
std::vector<token::TokenAction> actions{};
|
||||||
|
actions.push_back(token::TokenAction{
|
||||||
|
.id = 0,
|
||||||
|
.type = token::ActionType::AddServerGroup,
|
||||||
|
.id1 = admin_group->group_id(),
|
||||||
|
.id2 = 0
|
||||||
|
});
|
||||||
|
|
||||||
|
this->tokenManager->add_token_actions(token->id, actions);
|
||||||
|
new_permission_token = token->token;
|
||||||
|
|
||||||
|
this->properties()[property::VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY] = token->token;
|
||||||
|
this->properties()[property::VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Server admin
|
|
||||||
auto default_server_admin = serverInstance->group_manager()->findGroup(
|
|
||||||
serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP].as_or<GroupId>(0));
|
|
||||||
auto default_server_music = serverInstance->group_manager()->findGroup(
|
|
||||||
serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP].as_or<GroupId>(0));
|
|
||||||
auto default_server_guest = serverInstance->group_manager()->findGroup(
|
|
||||||
serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP].as_or<GroupId>(0));
|
|
||||||
|
|
||||||
auto default_channel_admin = serverInstance->group_manager()->findGroup(
|
|
||||||
serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP].as_or<GroupId>(0));
|
|
||||||
auto default_channel_guest = serverInstance->group_manager()->findGroup(
|
|
||||||
serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP].as_or<GroupId>(0));
|
|
||||||
|
|
||||||
if(!default_server_guest) {
|
|
||||||
logCritical(0, "Missing default server guest template group!");
|
|
||||||
assert(!serverInstance->group_manager()->availableChannelGroups().empty());
|
|
||||||
|
|
||||||
default_server_guest = serverInstance->group_manager()->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->group_manager()->availableChannelGroups().empty());
|
|
||||||
|
|
||||||
default_channel_admin = serverInstance->group_manager()->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->group_manager()->availableChannelGroups().empty());
|
|
||||||
|
|
||||||
default_server_music = serverInstance->group_manager()->availableChannelGroups().front();
|
|
||||||
logCritical(0, "Using group {} as channel server guest group for server {}.", default_server_music->name(), this->serverId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!default_server_admin) {
|
|
||||||
logCritical(0, "Missing default server admin template group! Using default guest group ({})", default_server_guest->name());
|
|
||||||
default_server_admin = default_server_guest;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!default_channel_admin) {
|
|
||||||
logCritical(0, "Missing default channel admin template group! Using default guest group ({})", default_channel_guest->name());
|
|
||||||
default_channel_admin = default_channel_guest;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->properties()[property::VIRTUALSERVER_DEFAULT_SERVER_GROUP] = this->group_manager()->findGroup(GroupTarget::GROUPTARGET_SERVER, default_server_guest->name()).front()->groupId();
|
|
||||||
this->properties()[property::VIRTUALSERVER_DEFAULT_MUSIC_GROUP] = this->group_manager()->findGroup(GroupTarget::GROUPTARGET_SERVER, default_server_music->name()).front()->groupId();
|
|
||||||
this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP] = this->group_manager()->findGroup(GroupTarget::GROUPTARGET_CHANNEL, default_channel_admin->name()).front()->groupId();
|
|
||||||
this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP] = this->group_manager()->findGroup(GroupTarget::GROUPTARGET_CHANNEL, default_channel_guest->name()).front()->groupId();
|
|
||||||
|
|
||||||
auto server_admin_group_id = this->group_manager()->findGroup(GroupTarget::GROUPTARGET_SERVER, default_server_admin->name()).front()->groupId();
|
|
||||||
auto token = this->tokenManager->create_token(0, "Default server admin token", 1, std::chrono::system_clock::time_point{});
|
|
||||||
if(!token) {
|
|
||||||
logCritical(this->serverId, "Failed to register the default server admin token.");
|
|
||||||
this->properties()[property::VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY] = false;
|
|
||||||
} else {
|
|
||||||
std::vector<token::TokenAction> actions{};
|
|
||||||
actions.push_back(token::TokenAction{
|
|
||||||
.id = 0,
|
|
||||||
.type = token::ActionType::AddServerGroup,
|
|
||||||
.id1 = server_admin_group_id,
|
|
||||||
.id2 = 0
|
|
||||||
});
|
|
||||||
|
|
||||||
this->tokenManager->add_token_actions(token->id, actions);
|
|
||||||
new_permission_token = token->token;
|
|
||||||
|
|
||||||
this->properties()[property::VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY] = token->token;
|
|
||||||
this->properties()[property::VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY] = true;
|
|
||||||
}
|
|
||||||
this->ensureValidDefaultGroups();
|
this->ensureValidDefaultGroups();
|
||||||
|
|
||||||
for(const auto& client : this->getClients()) {
|
for(const auto& client : this->getClients()) {
|
||||||
if(client->getType() != ClientType::CLIENT_QUERY) {
|
client->task_update_displayed_groups.enqueue();
|
||||||
client->notifyServerGroupList();
|
client->task_update_needed_permissions.enqueue();
|
||||||
client->notifyChannelGroupList();
|
|
||||||
}
|
|
||||||
if(this->notifyClientPropertyUpdates(client, this->group_manager()->update_server_group_property(client, true, client->getChannel()))) {
|
|
||||||
client->task_update_needed_permissions.enqueue();
|
|
||||||
}
|
|
||||||
client->task_update_channel_client_properties.enqueue();
|
client->task_update_channel_client_properties.enqueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->task_notify_channel_group_list.enqueue();
|
||||||
|
this->task_notify_server_group_list.enqueue();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1395,15 +1158,16 @@ void VirtualServer::update_channel_from_permissions(const std::shared_ptr<BasicC
|
|||||||
deleted.push_back(channel->channelId());
|
deleted.push_back(channel->channelId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!deleted.empty())
|
if(!deleted.empty()) {
|
||||||
cl->notifyChannelHide(deleted, false);
|
cl->notifyChannelHide(deleted, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<groups::ChannelGroup> VirtualServer::default_channel_group() {
|
std::shared_ptr<groups::ChannelGroup> VirtualServer::default_channel_group() {
|
||||||
auto group_id = this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP].as_save<GroupId>();
|
auto group_id = this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP].as_or<GroupId>(0);
|
||||||
auto group = this->group_manager()->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, group_id);
|
auto group = this->group_manager()->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, group_id);
|
||||||
if(!group) {
|
if(!group) {
|
||||||
auto groups = this->group_manager()->channel_groups()->available_groups(groups::GroupCalculateMode::GLOBAL);
|
auto groups = this->group_manager()->channel_groups()->available_groups(groups::GroupCalculateMode::GLOBAL);
|
||||||
|
@ -110,25 +110,7 @@ namespace ts {
|
|||||||
uint16_t bots = 0;
|
uint16_t bots = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CalculateCache {
|
struct CalculateCache {};
|
||||||
bool global_skip = false;
|
|
||||||
bool global_skip_set = false;
|
|
||||||
|
|
||||||
std::shared_ptr<permission::v2::PermissionManager> client_permissions;
|
|
||||||
std::vector<std::shared_ptr<GroupAssignment>> assignment_server_groups;
|
|
||||||
bool assignment_server_groups_set = false;
|
|
||||||
|
|
||||||
ChannelId assignment_channel_group_channel;
|
|
||||||
std::shared_ptr<GroupAssignment> assignment_channel_group;
|
|
||||||
bool assignment_channel_group_set = false;
|
|
||||||
|
|
||||||
std::shared_ptr<BasicChannel> server_channel;
|
|
||||||
ChannelId last_server_channel = 0;
|
|
||||||
|
|
||||||
inline std::vector<std::shared_ptr<GroupAssignment>> getGroupAssignments(VirtualServer* server, ClientDbId cldbid, ClientType type);
|
|
||||||
inline std::shared_ptr<GroupAssignment> getChannelAssignment(VirtualServer* server, ClientDbId client_dbid, ChannelId channel);
|
|
||||||
inline std::shared_ptr<BasicChannel> getServerChannel(VirtualServer*, ChannelId);
|
|
||||||
};
|
|
||||||
|
|
||||||
class VirtualServer {
|
class VirtualServer {
|
||||||
friend class WebClient;
|
friend class WebClient;
|
||||||
@ -258,8 +240,6 @@ namespace ts {
|
|||||||
|
|
||||||
ServerState::value getState() { return this->state; }
|
ServerState::value getState() { return this->state; }
|
||||||
|
|
||||||
bool could_default_create_channel();
|
|
||||||
|
|
||||||
inline std::shared_ptr<VirtualServer> ref() { return this->self.lock(); }
|
inline std::shared_ptr<VirtualServer> ref() { return this->self.lock(); }
|
||||||
inline bool disable_ip_saving() { return this->_disable_ip_saving; }
|
inline bool disable_ip_saving() { return this->_disable_ip_saving; }
|
||||||
inline std::chrono::system_clock::time_point start_timestamp() { return this->startTimestamp; };
|
inline std::chrono::system_clock::time_point start_timestamp() { return this->startTimestamp; };
|
||||||
@ -299,6 +279,9 @@ namespace ts {
|
|||||||
inline auto& get_channel_tree_lock() { return this->channel_tree_lock; }
|
inline auto& get_channel_tree_lock() { return this->channel_tree_lock; }
|
||||||
|
|
||||||
void update_channel_from_permissions(const std::shared_ptr<BasicChannel>& /* channel */, const std::shared_ptr<ConnectedClient>& /* issuer */);
|
void update_channel_from_permissions(const std::shared_ptr<BasicChannel>& /* channel */, const std::shared_ptr<ConnectedClient>& /* issuer */);
|
||||||
|
|
||||||
|
inline void enqueue_notify_channel_group_list() { this->task_notify_channel_group_list.enqueue(); }
|
||||||
|
inline void enqueue_notify_server_group_list() { this->task_notify_server_group_list.enqueue(); }
|
||||||
protected:
|
protected:
|
||||||
bool registerClient(std::shared_ptr<ConnectedClient>);
|
bool registerClient(std::shared_ptr<ConnectedClient>);
|
||||||
bool unregisterClient(std::shared_ptr<ConnectedClient>, std::string, std::unique_lock<std::shared_mutex>& channel_tree_lock);
|
bool unregisterClient(std::shared_ptr<ConnectedClient>, std::string, std::unique_lock<std::shared_mutex>& channel_tree_lock);
|
||||||
@ -363,6 +346,9 @@ namespace ts {
|
|||||||
std::chrono::milliseconds spoken_time{0};
|
std::chrono::milliseconds spoken_time{0};
|
||||||
std::chrono::system_clock::time_point spoken_time_timestamp;
|
std::chrono::system_clock::time_point spoken_time_timestamp;
|
||||||
|
|
||||||
|
multi_shot_task task_notify_channel_group_list{};
|
||||||
|
multi_shot_task task_notify_server_group_list{};
|
||||||
|
|
||||||
bool _disable_ip_saving = false;
|
bool _disable_ip_saving = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,13 @@ void ConnectedClient::initialize_weak_reference(const std::shared_ptr<ConnectedC
|
|||||||
self->updateChannelClientProperties(true, true);
|
self->updateChannelClientProperties(true, true);
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
this->task_update_displayed_groups = multi_shot_task{serverInstance->general_task_executor(), "update displayed groups for " + this->getLoggingPeerIp(), [weak_self]{
|
||||||
|
auto self = weak_self.lock();
|
||||||
|
if(self) {
|
||||||
|
self->update_displayed_client_groups();
|
||||||
|
}
|
||||||
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConnectedClient::loadDataForCurrentServer() {
|
bool ConnectedClient::loadDataForCurrentServer() {
|
||||||
@ -1012,6 +1019,63 @@ bool ConnectedClient::update_client_needed_permissions() {
|
|||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConnectedClient::update_displayed_client_groups(bool& server_groups_changed, bool& channel_group_changed) {
|
||||||
|
auto ref_server = this->server;
|
||||||
|
auto group_manager = ref_server ? ref_server->group_manager() : serverInstance->group_manager();
|
||||||
|
|
||||||
|
GroupId channel_group_id{0};
|
||||||
|
ChannelId channel_inherit_id{0};
|
||||||
|
std::string server_group_assignments{};
|
||||||
|
|
||||||
|
{
|
||||||
|
auto server_groups = group_manager->assignments().server_groups_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, this->getClientDatabaseId());
|
||||||
|
for(const auto& group_id : server_groups) {
|
||||||
|
server_group_assignments += ",";
|
||||||
|
server_group_assignments += std::to_string(group_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!server_group_assignments.empty()) {
|
||||||
|
server_group_assignments = server_group_assignments.substr(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::shared_ptr<BasicChannel> inherited_channel{this->currentChannel};
|
||||||
|
auto channel_group = group_manager->assignments().calculate_channel_group_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, this->getClientDatabaseId(), inherited_channel);
|
||||||
|
if(channel_group.has_value()) {
|
||||||
|
assert(inherited_channel);
|
||||||
|
channel_group_id = *channel_group;
|
||||||
|
channel_inherit_id = inherited_channel->channelId();
|
||||||
|
} else {
|
||||||
|
channel_group_id = 0;
|
||||||
|
channel_inherit_id = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server_groups_changed = false;
|
||||||
|
channel_group_changed = false;
|
||||||
|
|
||||||
|
std::deque<property::ClientProperties> updated_properties{};
|
||||||
|
if(this->properties()[property::CLIENT_SERVERGROUPS].update_value(server_group_assignments)) {
|
||||||
|
updated_properties.push_back(property::CLIENT_SERVERGROUPS);
|
||||||
|
server_groups_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this->properties()[property::CLIENT_CHANNEL_GROUP_ID].update_value(channel_group_id)) {
|
||||||
|
updated_properties.push_back(property::CLIENT_CHANNEL_GROUP_ID);
|
||||||
|
channel_group_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this->properties()[property::CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID].update_value(channel_inherit_id)) {
|
||||||
|
updated_properties.push_back(property::CLIENT_CHANNEL_GROUP_ID);
|
||||||
|
channel_group_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!updated_properties.empty() && ref_server) {
|
||||||
|
ref_server->notifyClientPropertyUpdates(this->ref(), updated_properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ConnectedClient::sendTSPermEditorWarning() {
|
void ConnectedClient::sendTSPermEditorWarning() {
|
||||||
if(config::voice::warn_on_permission_editor) {
|
if(config::voice::warn_on_permission_editor) {
|
||||||
if(system_clock::now() - this->command_times.servergrouplist > milliseconds(1000)) return;
|
if(system_clock::now() - this->command_times.servergrouplist > milliseconds(1000)) return;
|
||||||
@ -1192,11 +1256,7 @@ void ConnectedClient::useToken(token::TokenId token_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(tree_registered && (server_groups_changed || channel_group_changed)) {
|
if(tree_registered && (server_groups_changed || channel_group_changed)) {
|
||||||
/* TODO: Set "Update server groups" as task */
|
this->task_update_displayed_groups.enqueue();
|
||||||
auto updated_properties = this->getServer()->group_manager()->update_server_group_property(this->ref(), true, this->currentChannel);
|
|
||||||
if(!updated_properties.empty()) {
|
|
||||||
this->getServer()->notifyClientPropertyUpdates(this->ref(), updated_properties);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tree_registered && server_groups_changed) {
|
if(tree_registered && server_groups_changed) {
|
||||||
|
@ -57,6 +57,12 @@ namespace ts {
|
|||||||
class WebClient;
|
class WebClient;
|
||||||
class MusicClient;
|
class MusicClient;
|
||||||
|
|
||||||
|
namespace groups {
|
||||||
|
class Group;
|
||||||
|
class ServerGroup;
|
||||||
|
class ChannelGroup;
|
||||||
|
}
|
||||||
|
|
||||||
struct ConnectionInfoData {
|
struct ConnectionInfoData {
|
||||||
std::chrono::time_point<std::chrono::system_clock> timestamp;
|
std::chrono::time_point<std::chrono::system_clock> timestamp;
|
||||||
std::map<std::string, std::string> properties;
|
std::map<std::string, std::string> properties;
|
||||||
@ -74,7 +80,6 @@ namespace ts {
|
|||||||
friend class DataClient;
|
friend class DataClient;
|
||||||
friend class SpeakingClient;
|
friend class SpeakingClient;
|
||||||
friend class connection::VoiceClientConnection;
|
friend class connection::VoiceClientConnection;
|
||||||
friend class ts::GroupManager;
|
|
||||||
friend class VirtualServerManager;
|
friend class VirtualServerManager;
|
||||||
public:
|
public:
|
||||||
explicit ConnectedClient(sql::SqlManager*, const std::shared_ptr<VirtualServer>& server);
|
explicit ConnectedClient(sql::SqlManager*, const std::shared_ptr<VirtualServer>& server);
|
||||||
@ -129,14 +134,15 @@ namespace ts {
|
|||||||
/** Notifies (after request) */
|
/** Notifies (after request) */
|
||||||
bool sendNeededPermissions(bool /* force an update */); /* invoke this because it dosn't spam the client */
|
bool sendNeededPermissions(bool /* force an update */); /* invoke this because it dosn't spam the client */
|
||||||
virtual bool notifyClientNeededPermissions();
|
virtual bool notifyClientNeededPermissions();
|
||||||
virtual bool notifyServerGroupList(bool as_notify = true);
|
virtual bool notifyGroupPermList(const std::shared_ptr<groups::Group>&, bool);
|
||||||
virtual bool notifyGroupPermList(const std::shared_ptr<Group>&, bool);
|
|
||||||
virtual bool notifyClientPermList(ClientDbId, const std::shared_ptr<permission::v2::PermissionManager>&, bool);
|
virtual bool notifyClientPermList(ClientDbId, const std::shared_ptr<permission::v2::PermissionManager>&, bool);
|
||||||
virtual bool notifyChannelGroupList(bool as_notify = true);
|
|
||||||
virtual bool notifyConnectionInfo(const std::shared_ptr<ConnectedClient> &target, const std::shared_ptr<ConnectionInfoData> &info);
|
virtual bool notifyConnectionInfo(const std::shared_ptr<ConnectedClient> &target, const std::shared_ptr<ConnectionInfoData> &info);
|
||||||
virtual bool notifyChannelSubscribed(const std::deque<std::shared_ptr<BasicChannel>> &);
|
virtual bool notifyChannelSubscribed(const std::deque<std::shared_ptr<BasicChannel>> &);
|
||||||
virtual bool notifyChannelUnsubscribed(const std::deque<std::shared_ptr<BasicChannel>> &);
|
virtual bool notifyChannelUnsubscribed(const std::deque<std::shared_ptr<BasicChannel>> &);
|
||||||
|
|
||||||
|
virtual bool notifyServerGroupList(std::optional<ts::command_builder>& /* generated notify */, bool /* as notify */);
|
||||||
|
virtual bool notifyChannelGroupList(std::optional<ts::command_builder>& /* generated notify */, bool /* as notify */);
|
||||||
|
|
||||||
/** Notifies (without request) */
|
/** Notifies (without request) */
|
||||||
//Group server
|
//Group server
|
||||||
virtual bool notifyServerUpdated(std::shared_ptr<ConnectedClient>);
|
virtual bool notifyServerUpdated(std::shared_ptr<ConnectedClient>);
|
||||||
@ -299,6 +305,12 @@ namespace ts {
|
|||||||
*/
|
*/
|
||||||
bool update_client_needed_permissions();
|
bool update_client_needed_permissions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attention: This method should never be called directly!
|
||||||
|
* Use `task_update_displayed_groups` instead to schedule an update.
|
||||||
|
*/
|
||||||
|
void update_displayed_client_groups(bool& server_groups_changed, bool& channel_group_changed);
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> require_connected_state(bool blocking = false) {
|
std::shared_lock<std::shared_mutex> require_connected_state(bool blocking = false) {
|
||||||
//try_to_lock_t
|
//try_to_lock_t
|
||||||
std::shared_lock<std::shared_mutex> disconnect_lock{};
|
std::shared_lock<std::shared_mutex> disconnect_lock{};
|
||||||
@ -398,6 +410,7 @@ namespace ts {
|
|||||||
|
|
||||||
multi_shot_task task_update_needed_permissions{};
|
multi_shot_task task_update_needed_permissions{};
|
||||||
multi_shot_task task_update_channel_client_properties{};
|
multi_shot_task task_update_channel_client_properties{};
|
||||||
|
multi_shot_task task_update_displayed_groups{};
|
||||||
|
|
||||||
bool loadDataForCurrentServer() override;
|
bool loadDataForCurrentServer() override;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <misc/sassert.h>
|
#include <misc/sassert.h>
|
||||||
#include <log/LogUtils.h>
|
#include <log/LogUtils.h>
|
||||||
#include "./web/WebClient.h"
|
#include "./web/WebClient.h"
|
||||||
|
#include "../groups/GroupManager.h"
|
||||||
|
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -41,41 +42,83 @@ do { \
|
|||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
bool ConnectedClient::notifyServerGroupList(bool as_notify) {
|
template <typename T>
|
||||||
Command cmd(as_notify ? "notifyservergrouplist" : "");
|
inline void build_group_notify(ts::command_builder& notify, bool is_channel_groups, const std::vector<std::shared_ptr<T>>& available_groups) {
|
||||||
int index = 0;
|
std::string group_id_key{};
|
||||||
|
permission::PermissionType permission_modify{};
|
||||||
|
permission::PermissionType permission_add{};
|
||||||
|
permission::PermissionType permission_remove{};
|
||||||
|
|
||||||
for (const auto& group : (this->server ? this->server->group_manager() : serverInstance->group_manager().get())->availableServerGroups(true)) {
|
if(is_channel_groups) {
|
||||||
if(group->target() == GroupTarget::GROUPTARGET_CHANNEL) {
|
group_id_key = "cgid";
|
||||||
cmd[index]["cgid"] = group->groupId();
|
|
||||||
} else {
|
|
||||||
cmd[index]["sgid"] = group->groupId();
|
|
||||||
}
|
|
||||||
for (const auto &prop : group->properties().list_properties(property::FLAG_GROUP_VIEW, this->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0))
|
|
||||||
cmd[index][std::string{prop.type().name}] = prop.value();
|
|
||||||
|
|
||||||
|
permission_modify = permission::i_channel_group_needed_modify_power;
|
||||||
|
permission_add = permission::i_channel_group_needed_member_add_power;
|
||||||
|
permission_remove = permission::i_channel_group_needed_member_remove_power;
|
||||||
|
} else {
|
||||||
|
group_id_key = "sgid";
|
||||||
|
|
||||||
auto modify_power = group->permissions()->permission_value_flagged(permission::i_displayed_group_needed_modify_power);
|
permission_modify = permission::i_server_group_needed_modify_power;
|
||||||
auto add_power = group->permissions()->permission_value_flagged(permission::i_displayed_group_needed_member_add_power);
|
permission_add = permission::i_server_group_needed_member_add_power;
|
||||||
auto remove_power = group->permissions()->permission_value_flagged(permission::i_displayed_group_needed_member_remove_power);
|
permission_remove = permission::i_server_group_needed_member_remove_power;
|
||||||
cmd[index]["n_modifyp"] = modify_power.has_value ? modify_power.value : 0;
|
|
||||||
cmd[index]["n_member_addp"] = add_power.has_value ? add_power.value : 0;
|
|
||||||
cmd[index]["n_member_removep"] = remove_power.has_value ? remove_power.value : 0;
|
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->sendCommand(cmd);
|
size_t index{0};
|
||||||
|
for(const auto& group : available_groups) {
|
||||||
|
auto bulk = notify.bulk(index++);
|
||||||
|
bulk.put_unchecked(group_id_key, group->group_id());
|
||||||
|
bulk.put_unchecked("type", (uint8_t) group->group_type());
|
||||||
|
bulk.put_unchecked("name", group->display_name());
|
||||||
|
bulk.put_unchecked("sortid", group->sort_id());
|
||||||
|
bulk.put_unchecked("savedb", group->save_assignments());
|
||||||
|
bulk.put_unchecked("namemode", (uint8_t) group->name_mode());
|
||||||
|
bulk.put_unchecked("iconid", group->icon_id());
|
||||||
|
|
||||||
|
auto modify_power = group->permissions()->permission_value_flagged(permission_modify);
|
||||||
|
auto add_power = group->permissions()->permission_value_flagged(permission_add);
|
||||||
|
auto remove_power = group->permissions()->permission_value_flagged(permission_remove);
|
||||||
|
|
||||||
|
bulk.put_unchecked("n_modifyp", modify_power.has_value ? modify_power.value : 0);
|
||||||
|
bulk.put_unchecked("n_member_addp", add_power.has_value ? add_power.value : 0);
|
||||||
|
bulk.put_unchecked("n_member_removep", remove_power.has_value ? remove_power.value : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConnectedClient::notifyServerGroupList(std::optional<ts::command_builder> &generated_notify, bool as_notify) {
|
||||||
|
if(!generated_notify.has_value()) {
|
||||||
|
auto server_ref = this->server;
|
||||||
|
auto group_manager = server_ref ? server_ref->group_manager() : serverInstance->group_manager();
|
||||||
|
auto available_groups = group_manager->channel_groups()->available_groups(groups::GroupCalculateMode::GLOBAL);
|
||||||
|
|
||||||
|
build_group_notify(generated_notify.emplace(as_notify ? "notifyservergrouplist" : ""), false, available_groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->sendCommand(*generated_notify);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ConnectedClient::notifyChannelGroupList(std::optional<ts::command_builder>& generated_notify, bool as_notify) {
|
||||||
|
if(!generated_notify.has_value()) {
|
||||||
|
auto server_ref = this->server;
|
||||||
|
auto group_manager = server_ref ? server_ref->group_manager() : serverInstance->group_manager();
|
||||||
|
auto available_groups = group_manager->channel_groups()->available_groups(groups::GroupCalculateMode::GLOBAL);
|
||||||
|
|
||||||
bool ConnectedClient::notifyGroupPermList(const std::shared_ptr<Group>& group, bool as_sid) {
|
build_group_notify(generated_notify.emplace(as_notify ? "notifychannelgrouplist" : ""), true, available_groups);
|
||||||
ts::command_builder result{this->getExternalType() == CLIENT_TEAMSPEAK ? group->target() == GROUPTARGET_SERVER ? "notifyservergrouppermlist" : "notifychannelgrouppermlist" : ""};
|
}
|
||||||
|
|
||||||
if (group->target() == GROUPTARGET_SERVER)
|
this->sendCommand(*generated_notify);
|
||||||
result.put_unchecked(0, "sgid", group->groupId());
|
return true;
|
||||||
else
|
}
|
||||||
result.put_unchecked(0, "cgid", group->groupId());
|
|
||||||
|
bool ConnectedClient::notifyGroupPermList(const std::shared_ptr<groups::Group>& group, bool as_sid) {
|
||||||
|
auto is_channel_group = !!dynamic_pointer_cast<groups::ChannelGroup>(group);
|
||||||
|
ts::command_builder result{this->notify_response_command(is_channel_group ? "notifychannelgrouppermlist" : "notifyservergrouppermlist")};
|
||||||
|
|
||||||
|
if (!is_channel_group) {
|
||||||
|
result.put_unchecked(0, "sgid", group->group_id());
|
||||||
|
} else {
|
||||||
|
result.put_unchecked(0, "cgid", group->group_id());
|
||||||
|
}
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
@ -168,32 +211,6 @@ bool ConnectedClient::notifyClientPermList(ClientDbId cldbid, const std::shared_
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConnectedClient::notifyChannelGroupList(bool as_notify) {
|
|
||||||
Command cmd(as_notify ? "notifychannelgrouplist" : "");
|
|
||||||
int index = 0;
|
|
||||||
for (const auto &group : (this->server ? this->server->group_manager() : serverInstance->group_manager().get())->availableChannelGroups(true)) {
|
|
||||||
if(group->target() == GroupTarget::GROUPTARGET_CHANNEL) {
|
|
||||||
cmd[index]["cgid"] = group->groupId();
|
|
||||||
} else {
|
|
||||||
cmd[index]["sgid"] = group->groupId();
|
|
||||||
}
|
|
||||||
for (auto &prop : group->properties().list_properties(property::FLAG_GROUP_VIEW, this->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0))
|
|
||||||
cmd[index][std::string{prop.type().name}] = prop.value();
|
|
||||||
|
|
||||||
|
|
||||||
auto modify_power = group->permissions()->permission_value_flagged(permission::i_displayed_group_needed_modify_power);
|
|
||||||
auto add_power = group->permissions()->permission_value_flagged(permission::i_displayed_group_needed_member_add_power);
|
|
||||||
auto remove_power = group->permissions()->permission_value_flagged(permission::i_displayed_group_needed_member_remove_power);
|
|
||||||
cmd[index]["n_modifyp"] = modify_power.has_value ? modify_power.value : 0;
|
|
||||||
cmd[index]["n_member_addp"] = add_power.has_value ? add_power.value : 0;
|
|
||||||
cmd[index]["n_member_removep"] = remove_power.has_value ? remove_power.value : 0;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
if(index == 0) return false;
|
|
||||||
this->sendCommand(cmd);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ConnectedClient::notifyTextMessage(ChatMessageMode mode, const shared_ptr<ConnectedClient> &invoker, uint64_t targetId, ChannelId channel_id, const std::chrono::system_clock::time_point& timestamp, const string &textMessage) {
|
bool ConnectedClient::notifyTextMessage(ChatMessageMode mode, const shared_ptr<ConnectedClient> &invoker, uint64_t targetId, ChannelId channel_id, const std::chrono::system_clock::time_point& timestamp, const string &textMessage) {
|
||||||
//notifytextmessage targetmode=1 msg=asdasd target=2 invokerid=1 invokername=WolverinDEV invokeruid=xxjnc14LmvTk+Lyrm8OOeo4tOqw=
|
//notifytextmessage targetmode=1 msg=asdasd target=2 invokerid=1 invokername=WolverinDEV invokeruid=xxjnc14LmvTk+Lyrm8OOeo4tOqw=
|
||||||
Command cmd("notifytextmessage");
|
Command cmd("notifytextmessage");
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "./DataClient.h"
|
#include "./DataClient.h"
|
||||||
#include "../InstanceHandler.h"
|
#include "../InstanceHandler.h"
|
||||||
#include "../groups/GroupManager.h"
|
#include "../groups/GroupManager.h"
|
||||||
|
#include "../groups/GroupAssignmentManager.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace ts;
|
using namespace ts;
|
||||||
@ -196,22 +197,32 @@ std::vector<std::shared_ptr<groups::ServerGroup>> DataClient::assignedServerGrou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(result.empty() && ref_server) {
|
||||||
|
auto default_group_id = ref_server->properties()[property::VIRTUALSERVER_DEFAULT_SERVER_GROUP].as_or<GroupId>(0);
|
||||||
|
auto default_group = group_manager->server_groups()->find_group(groups::GroupCalculateMode::GLOBAL, default_group_id);
|
||||||
|
if(default_group) {
|
||||||
|
result.push_back(default_group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<groups::ChannelGroup> DataClient::assignedChannelGroup(const shared_ptr<BasicChannel> &channel) {
|
std::shared_ptr<groups::ChannelGroup> DataClient::assignedChannelGroup(const std::shared_ptr<BasicChannel> &channel) {
|
||||||
auto ref_server = this->server;
|
auto ref_server = this->server;
|
||||||
assert(channel);
|
assert(channel);
|
||||||
if(!channel || !ref_server) {
|
if(!channel || !ref_server) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<groups::ChannelGroup> result{};
|
std::shared_ptr<BasicChannel> inherited_channel{channel};
|
||||||
|
|
||||||
auto group_manager = ref_server ? ref_server->group_manager() : serverInstance->group_manager();
|
auto group_manager = ref_server ? ref_server->group_manager() : serverInstance->group_manager();
|
||||||
auto channel_group_assignment = group_manager->assignments().channel_group_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, this->getClientDatabaseId(), channel->channelId());
|
auto assigned_group_id = group_manager->assignments().calculate_channel_group_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, this->getClientDatabaseId(), inherited_channel);
|
||||||
if(channel_group_assignment.has_value()) {
|
|
||||||
result = group_manager->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, channel_group_assignment->group_id);
|
std::shared_ptr<groups::ChannelGroup> result{};
|
||||||
|
if(assigned_group_id.has_value()) {
|
||||||
|
result = group_manager->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, *assigned_group_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!result) {
|
if(!result) {
|
||||||
|
@ -517,8 +517,14 @@ void SpeakingClient::processJoin() {
|
|||||||
TIMING_STEP(timings, "join move ");
|
TIMING_STEP(timings, "join move ");
|
||||||
|
|
||||||
this->properties()->triggerAllModified();
|
this->properties()->triggerAllModified();
|
||||||
this->notifyServerGroupList();
|
{
|
||||||
this->notifyChannelGroupList();
|
std::optional<ts::command_builder> generated_notify{};
|
||||||
|
this->notifyServerGroupList(generated_notify, true);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::optional<ts::command_builder> generated_notify{};
|
||||||
|
this->notifyChannelGroupList(generated_notify, true);
|
||||||
|
}
|
||||||
TIMING_STEP(timings, "notify grou");
|
TIMING_STEP(timings, "notify grou");
|
||||||
logMessage(this->getServerId(), "Voice client {}/{} ({}) from {} joined.",
|
logMessage(this->getServerId(), "Voice client {}/{} ({}) from {} joined.",
|
||||||
this->getClientDatabaseId(),
|
this->getClientDatabaseId(),
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "../../manager/PermissionNameMapper.h"
|
#include "../../manager/PermissionNameMapper.h"
|
||||||
#include "../../server/QueryServer.h"
|
#include "../../server/QueryServer.h"
|
||||||
#include "../../server/VoiceServer.h"
|
#include "../../server/VoiceServer.h"
|
||||||
|
#include "../../groups/GroupManager.h"
|
||||||
#include "../ConnectedClient.h"
|
#include "../ConnectedClient.h"
|
||||||
#include "../InternalClient.h"
|
#include "../InternalClient.h"
|
||||||
#include "../music/MusicClient.h"
|
#include "../music/MusicClient.h"
|
||||||
@ -137,58 +138,63 @@ command_result ConnectedClient::handleCommandChannelGroupAdd(Command &cmd) {
|
|||||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_create, 1);
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_create, 1);
|
||||||
|
|
||||||
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get();
|
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager();
|
||||||
|
|
||||||
log::GroupType log_group_type;
|
log::GroupType log_group_type;
|
||||||
if (cmd["type"].as<GroupType>() == GroupType::GROUP_TYPE_QUERY) {
|
auto group_type = cmd["type"].as<groups::GroupType>();
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1);
|
switch (group_type) {
|
||||||
log_group_type = log::GroupType::QUERY;
|
case groups::GroupType::GROUP_TYPE_QUERY:
|
||||||
} else if (cmd["type"].as<GroupType>() == GroupType::GROUP_TYPE_TEMPLATE) {
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1);
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1);
|
log_group_type = log::GroupType::QUERY;
|
||||||
log_group_type = log::GroupType::TEMPLATE;
|
break;
|
||||||
} else {
|
|
||||||
if (!this->server) {
|
|
||||||
return command_result{error::parameter_invalid, "you cant create normal groups on the template server!"};
|
|
||||||
}
|
|
||||||
|
|
||||||
log_group_type = log::GroupType::NORMAL;
|
case groups::GroupType::GROUP_TYPE_TEMPLATE:
|
||||||
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1);
|
||||||
|
log_group_type = log::GroupType::TEMPLATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case groups::GroupType::GROUP_TYPE_NORMAL:
|
||||||
|
if (!this->server) {
|
||||||
|
return command_result{error::parameter_invalid, "you cant create normal groups on the template server!"};
|
||||||
|
}
|
||||||
|
log_group_type = log::GroupType::NORMAL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case groups::GroupType::GROUP_TYPE_UNKNOWN:
|
||||||
|
default:
|
||||||
|
return command_result{error::parameter_invalid, "type"};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd["name"].string().empty()) {
|
std::shared_ptr<groups::ChannelGroup> group{};
|
||||||
return command_result{error::parameter_invalid, "invalid group name"};
|
auto result = group_manager->channel_groups()->create_group(group_type, cmd["name"].string(), group);
|
||||||
}
|
switch(result) {
|
||||||
|
case groups::GroupCreateResult::SUCCESS:
|
||||||
|
break;
|
||||||
|
|
||||||
for (const auto &gr : group_manager->availableServerGroups(true)) {
|
case groups::GroupCreateResult::NAME_TOO_SHORT:
|
||||||
if (gr->name() == cmd["name"].string() && gr->target() == GroupTarget::GROUPTARGET_CHANNEL) {
|
case groups::GroupCreateResult::NAME_TOO_LONG:
|
||||||
return command_result{error::parameter_invalid, "Group already exists"};
|
return command_result{error::parameter_invalid, "name"};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto group = group_manager->createGroup(GroupTarget::GROUPTARGET_CHANNEL, cmd["type"].as<GroupType>(), cmd["name"].string());
|
case groups::GroupCreateResult::NAME_ALREADY_IN_USED:
|
||||||
serverInstance->action_logger()->group_logger.log_group_create(this->getServerId(), this->ref(), log::GroupTarget::CHANNEL, log_group_type, group->groupId(), group->name(), 0, "");
|
return command_result{error::group_name_inuse};
|
||||||
|
|
||||||
|
case groups::GroupCreateResult::DATABASE_ERROR:
|
||||||
|
default:
|
||||||
|
return command_result{error::vs_critical};
|
||||||
|
}
|
||||||
|
assert(group);
|
||||||
|
serverInstance->action_logger()->group_logger.log_group_create(this->getServerId(), this->ref(), log::GroupTarget::CHANNEL, log_group_type, group->group_id(), group->display_name(), 0, "");
|
||||||
|
|
||||||
{
|
{
|
||||||
ts::command_builder notify{this->notify_response_command("notifychannelgroupadded")};
|
ts::command_builder notify{this->notify_response_command("notifychannelgroupadded")};
|
||||||
notify.put_unchecked(0, "cgid", group->groupId());
|
notify.put_unchecked(0, "cgid", group->group_id());
|
||||||
this->sendCommand(notify);
|
this->sendCommand(notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group) {
|
if (group) {
|
||||||
group->permissions()->set_permission(permission::b_group_is_permanent, {1, 0}, permission::v2::set_value, permission::v2::do_nothing);
|
group->permissions()->set_permission(permission::b_group_is_permanent, {1, 0}, permission::v2::set_value, permission::v2::do_nothing);
|
||||||
if (this->server) {
|
if (this->server) {
|
||||||
if (this->getType() == ClientType::CLIENT_QUERY) {
|
this->server->enqueue_notify_channel_group_list();
|
||||||
this->server->forEachClient([&](const std::shared_ptr<ConnectedClient> &cl) {
|
|
||||||
if (cl == this) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cl->notifyChannelGroupList();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this->server->forEachClient([](const std::shared_ptr<ConnectedClient> &cl) {
|
|
||||||
cl->notifyChannelGroupList();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return command_result{error::group_invalid_id};
|
return command_result{error::group_invalid_id};
|
||||||
@ -200,30 +206,40 @@ command_result ConnectedClient::handleCommandChannelGroupAdd(Command &cmd) {
|
|||||||
command_result ConnectedClient::handleCommandChannelGroupCopy(Command &cmd) {
|
command_result ConnectedClient::handleCommandChannelGroupCopy(Command &cmd) {
|
||||||
CMD_RESET_IDLE;
|
CMD_RESET_IDLE;
|
||||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_create, 1);
|
|
||||||
|
|
||||||
auto ref_server = this->server;
|
auto ref_server = this->server;
|
||||||
|
|
||||||
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get();
|
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager();
|
||||||
|
|
||||||
auto source_group_id = cmd["scgid"].as<GroupId>();
|
auto source_group_id = cmd["scgid"].as<GroupId>();
|
||||||
auto source_group = group_manager->findGroup(source_group_id);
|
auto source_group = group_manager->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, source_group_id);
|
||||||
|
|
||||||
if (!source_group || source_group->target() != GROUPTARGET_CHANNEL)
|
if (!source_group) {
|
||||||
return command_result{error::group_invalid_id, "invalid source group"};
|
return command_result{error::group_invalid_id, "invalid source group id"};
|
||||||
|
}
|
||||||
|
|
||||||
const auto group_type_modificable = [&](GroupType type) {
|
const auto group_type_modifiable = [&](groups::GroupType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case GroupType::GROUP_TYPE_TEMPLATE:
|
case groups::GroupType::GROUP_TYPE_TEMPLATE:
|
||||||
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_serverinstance_modify_templates, 0)))
|
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_serverinstance_modify_templates, 0))) {
|
||||||
return permission::b_serverinstance_modify_templates;
|
return permission::b_serverinstance_modify_templates;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case GroupType::GROUP_TYPE_QUERY:
|
case groups::GroupType::GROUP_TYPE_QUERY:
|
||||||
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_serverinstance_modify_querygroup, 0)))
|
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_serverinstance_modify_querygroup, 0))) {
|
||||||
return permission::b_serverinstance_modify_querygroup;
|
return permission::b_serverinstance_modify_querygroup;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GroupType::GROUP_TYPE_NORMAL:
|
case groups::GroupType::GROUP_TYPE_NORMAL:
|
||||||
|
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_channelgroup_create, 0))) {
|
||||||
|
return permission::b_virtualserver_channelgroup_create;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case groups::GroupType::GROUP_TYPE_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -231,107 +247,149 @@ command_result ConnectedClient::handleCommandChannelGroupCopy(Command &cmd) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
auto result = group_type_modificable(source_group->type());
|
auto result = group_type_modifiable(source_group->group_type());
|
||||||
if (result != permission::undefined)
|
if (result != permission::undefined) {
|
||||||
return command_result{result};
|
return command_result{result};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto global_update = false;
|
auto global_update = false;
|
||||||
if (cmd[0].has("tcgid") && cmd["tcgid"].as<GroupId>() != 0) {
|
if (cmd[0].has("tcgid") && cmd["tcgid"].as<GroupId>() != 0) {
|
||||||
//Copy an existing group
|
//Copy an existing group
|
||||||
auto target_group = group_manager->findGroup(cmd["tcgid"]);
|
auto target_group_id = cmd["tcgid"].as<GroupId>();
|
||||||
if (!target_group || target_group->target() != GROUPTARGET_CHANNEL)
|
auto target_group = group_manager->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, target_group_id);
|
||||||
|
if (!target_group) {
|
||||||
return command_result{error::group_invalid_id, "invalid target group"};
|
return command_result{error::group_invalid_id, "invalid target group"};
|
||||||
|
|
||||||
{
|
|
||||||
auto result = group_type_modificable(target_group->type());
|
|
||||||
if (result != permission::undefined)
|
|
||||||
return command_result{result};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!target_group->permission_granted(permission::i_channel_group_needed_modify_power, this->calculate_permission(permission::i_channel_group_modify_power, 0), true))
|
if(!target_group->permission_granted(permission::i_channel_group_needed_modify_power, this->calculate_permission(permission::i_channel_group_modify_power, 0), true)) {
|
||||||
return command_result{permission::i_channel_group_modify_power};
|
return ts::command_result{permission::i_channel_group_needed_modify_power};
|
||||||
|
}
|
||||||
|
|
||||||
if (!group_manager->copyGroupPermissions(source_group, target_group))
|
{
|
||||||
return command_result{error::vs_critical, "failed to copy group permissions"};
|
auto result = group_type_modifiable(target_group->group_type());
|
||||||
|
if (result != permission::undefined) {
|
||||||
|
return command_result{result};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = group_manager->channel_groups()->copy_group_permissions(source_group_id, target_group_id);
|
||||||
|
switch(result) {
|
||||||
|
case groups::GroupCopyResult::SUCCESS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case groups::GroupCopyResult::UNKNOWN_SOURCE_GROUP:
|
||||||
|
return command_result{error::vs_critical, "internal unknown source group"};
|
||||||
|
|
||||||
|
case groups::GroupCopyResult::UNKNOWN_TARGET_GROUP:
|
||||||
|
return command_result{error::vs_critical, "internal unknown target group"};
|
||||||
|
|
||||||
|
case groups::GroupCopyResult::DATABASE_ERROR:
|
||||||
|
return command_result{error::vs_critical, "database error"};
|
||||||
|
|
||||||
|
case groups::GroupCopyResult::NAME_ALREADY_IN_USE:
|
||||||
|
return command_result{error::group_name_inuse};
|
||||||
|
|
||||||
|
default:
|
||||||
|
return command_result{error::vs_critical};
|
||||||
|
}
|
||||||
|
|
||||||
log::GroupType log_group_type;
|
log::GroupType log_group_type;
|
||||||
switch (target_group->type()) {
|
switch (target_group->group_type()) {
|
||||||
case GroupType::GROUP_TYPE_QUERY:
|
case groups::GroupType::GROUP_TYPE_QUERY:
|
||||||
log_group_type = log::GroupType::QUERY;
|
log_group_type = log::GroupType::QUERY;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GroupType::GROUP_TYPE_TEMPLATE:
|
case groups::GroupType::GROUP_TYPE_TEMPLATE:
|
||||||
log_group_type = log::GroupType::TEMPLATE;
|
log_group_type = log::GroupType::TEMPLATE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GroupType::GROUP_TYPE_NORMAL:
|
case groups::GroupType::GROUP_TYPE_NORMAL:
|
||||||
|
case groups::GroupType::GROUP_TYPE_UNKNOWN:
|
||||||
|
default:
|
||||||
log_group_type = log::GroupType::NORMAL;
|
log_group_type = log::GroupType::NORMAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
return command_result{error::parameter_invalid, "type"};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serverInstance->action_logger()->group_logger.log_group_permission_copy(target_group->type() != GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId(),
|
serverInstance->action_logger()->group_logger.log_group_permission_copy(target_group->group_type() != groups::GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId(),
|
||||||
this->ref(), log::GroupTarget::CHANNEL, log_group_type, target_group->groupId(), target_group->name(), source_group->groupId(), source_group->name());
|
this->ref(), log::GroupTarget::CHANNEL, log_group_type, target_group->group_id(), target_group->display_name(), source_group->group_id(), source_group->display_name());
|
||||||
|
|
||||||
|
|
||||||
global_update = !this->server || !group_manager->isLocalGroup(target_group);
|
global_update = !this->server || !group_manager->channel_groups()->find_group(groups::GroupCalculateMode::LOCAL, target_group_id);
|
||||||
} else {
|
} else {
|
||||||
//Copy a new group
|
//Copy a new group
|
||||||
auto target_type = cmd["type"].as<GroupType>();
|
auto target_type = cmd["type"].as<groups::GroupType>();
|
||||||
|
|
||||||
{
|
|
||||||
auto result = group_type_modificable(target_type);
|
|
||||||
if (result != permission::undefined)
|
|
||||||
return command_result{result};
|
|
||||||
}
|
|
||||||
|
|
||||||
log::GroupType log_group_type;
|
log::GroupType log_group_type;
|
||||||
switch (target_type) {
|
switch (target_type) {
|
||||||
case GroupType::GROUP_TYPE_QUERY:
|
case groups::GroupType::GROUP_TYPE_QUERY:
|
||||||
log_group_type = log::GroupType::QUERY;
|
log_group_type = log::GroupType::QUERY;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GroupType::GROUP_TYPE_TEMPLATE:
|
case groups::GroupType::GROUP_TYPE_TEMPLATE:
|
||||||
log_group_type = log::GroupType::TEMPLATE;
|
log_group_type = log::GroupType::TEMPLATE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GroupType::GROUP_TYPE_NORMAL:
|
case groups::GroupType::GROUP_TYPE_NORMAL:
|
||||||
log_group_type = log::GroupType::NORMAL;
|
log_group_type = log::GroupType::NORMAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case groups::GroupType::GROUP_TYPE_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
return command_result{error::parameter_invalid, "type"};
|
return command_result{error::parameter_invalid, "type"};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ref_server && target_type == GroupType::GROUP_TYPE_NORMAL)
|
{
|
||||||
|
auto result = group_type_modifiable(target_type);
|
||||||
|
if (result != permission::undefined) {
|
||||||
|
return command_result{result};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ref_server && target_type == groups::GroupType::GROUP_TYPE_NORMAL) {
|
||||||
return command_result{error::parameter_invalid, "You cant create normal groups on the template server!"};
|
return command_result{error::parameter_invalid, "You cant create normal groups on the template server!"};
|
||||||
|
}
|
||||||
|
|
||||||
if (!group_manager->findGroup(GroupTarget::GROUPTARGET_CHANNEL, cmd["name"].string()).empty())
|
std::shared_ptr<groups::ChannelGroup> created_group{};
|
||||||
return command_result{error::group_name_inuse, "You cant create normal groups on the template server!"};
|
auto result = group_manager->channel_groups()->copy_group(source_group_id, target_type, cmd["name"].string(), created_group);
|
||||||
|
switch(result) {
|
||||||
|
case groups::GroupCopyResult::SUCCESS:
|
||||||
|
break;
|
||||||
|
|
||||||
auto target_group_id = group_manager->copyGroup(source_group, target_type, cmd["name"], target_type != GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId());
|
case groups::GroupCopyResult::UNKNOWN_SOURCE_GROUP:
|
||||||
if (target_group_id == 0)
|
return command_result{error::vs_critical, "internal unknown source group"};
|
||||||
return command_result{error::vs_critical, "failed to copy group"};
|
|
||||||
serverInstance->action_logger()->group_logger.log_group_create(target_type != GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId(),
|
|
||||||
this->ref(), log::GroupTarget::CHANNEL, log_group_type, target_group_id, cmd["name"], source_group->groupId(), source_group->name());
|
|
||||||
|
|
||||||
if (this->getType() == ClientType::CLIENT_QUERY) {
|
case groups::GroupCopyResult::UNKNOWN_TARGET_GROUP:
|
||||||
Command notify("");
|
return command_result{error::vs_critical, "internal unknown target group"};
|
||||||
notify["cgid"] = target_group_id;
|
|
||||||
|
case groups::GroupCopyResult::DATABASE_ERROR:
|
||||||
|
return command_result{error::vs_critical, "database error"};
|
||||||
|
|
||||||
|
case groups::GroupCopyResult::NAME_ALREADY_IN_USE:
|
||||||
|
return command_result{error::group_name_inuse};
|
||||||
|
|
||||||
|
default:
|
||||||
|
return command_result{error::vs_critical};
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(created_group);
|
||||||
|
serverInstance->action_logger()->group_logger.log_group_create(target_type != groups::GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId(),
|
||||||
|
this->ref(), log::GroupTarget::CHANNEL, log_group_type, created_group->group_id(), cmd["name"], source_group->group_id(), source_group->display_name());
|
||||||
|
|
||||||
|
{
|
||||||
|
ts::command_builder notify{this->notify_response_command("notifychannelgroupcopied")};
|
||||||
|
notify.put_unchecked(0, "cgid", created_group->group_id());
|
||||||
this->sendCommand(notify);
|
this->sendCommand(notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
global_update = !this->server || !group_manager->isLocalGroup(group_manager->findGroup(target_group_id));
|
global_update = !this->server;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &server : (global_update ? serverInstance->getVoiceServerManager()->serverInstances() : deque<shared_ptr<VirtualServer>>{this->server}))
|
for (const auto &server : (global_update ? serverInstance->getVoiceServerManager()->serverInstances() : deque<shared_ptr<VirtualServer>>{this->server})) {
|
||||||
if (server)
|
if (server) {
|
||||||
server->forEachClient([](shared_ptr<ConnectedClient> cl) {
|
server->enqueue_notify_channel_group_list();
|
||||||
cl->notifyChannelGroupList();
|
}
|
||||||
});
|
}
|
||||||
return command_result{error::ok};
|
return command_result{error::ok};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,32 +397,50 @@ command_result ConnectedClient::handleCommandChannelGroupRename(Command &cmd) {
|
|||||||
CMD_RESET_IDLE;
|
CMD_RESET_IDLE;
|
||||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||||
|
|
||||||
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get();
|
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager();
|
||||||
auto channel_group = group_manager->findGroup(cmd["cgid"].as<GroupId>());
|
auto channel_group = group_manager->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, cmd["cgid"].as<GroupId>());
|
||||||
if (!channel_group || channel_group->target() != GROUPTARGET_CHANNEL)
|
if (!channel_group) {
|
||||||
return command_result{error::parameter_invalid, "invalid channel group id"};
|
return command_result{error::group_invalid_id};
|
||||||
|
}
|
||||||
|
|
||||||
ACTION_REQUIRES_GROUP_PERMISSION(channel_group, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true);
|
ACTION_REQUIRES_GROUP_PERMISSION(channel_group, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true);
|
||||||
|
|
||||||
auto type = channel_group->type();
|
auto type = channel_group->group_type();
|
||||||
log::GroupType log_group_type;
|
log::GroupType log_group_type;
|
||||||
if (type == GroupType::GROUP_TYPE_QUERY) {
|
if (type == groups::GroupType::GROUP_TYPE_QUERY) {
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1);
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1);
|
||||||
log_group_type = log::GroupType::QUERY;
|
log_group_type = log::GroupType::QUERY;
|
||||||
} else if (type == GroupType::GROUP_TYPE_TEMPLATE) {
|
} else if (type == groups::GroupType::GROUP_TYPE_TEMPLATE) {
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1);
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1);
|
||||||
log_group_type = log::GroupType::TEMPLATE;
|
log_group_type = log::GroupType::TEMPLATE;
|
||||||
} else {
|
} else {
|
||||||
log_group_type = log::GroupType::NORMAL;
|
log_group_type = log::GroupType::NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto old_name = channel_group->name();
|
auto old_name = channel_group->display_name();
|
||||||
group_manager->renameGroup(channel_group, cmd["name"].string());
|
auto result = group_manager->channel_groups()->rename_group(channel_group->group_id(), cmd["name"].string());
|
||||||
serverInstance->action_logger()->group_logger.log_group_rename(this->getServerId(), this->ref(), log::GroupTarget::CHANNEL, log_group_type, channel_group->groupId(), channel_group->name(), old_name);
|
switch(result) {
|
||||||
|
case groups::GroupRenameResult::SUCCESS:
|
||||||
|
break;
|
||||||
|
|
||||||
if (this->server)
|
case groups::GroupRenameResult::INVALID_GROUP_ID:
|
||||||
this->server->forEachClient([](shared_ptr<ConnectedClient> cl) {
|
return ts::command_result{error::vs_critical, "internal invalid group id"};
|
||||||
cl->notifyChannelGroupList();
|
|
||||||
});
|
case groups::GroupRenameResult::NAME_INVALID:
|
||||||
|
return ts::command_result{error::parameter_invalid, "name"};
|
||||||
|
|
||||||
|
case groups::GroupRenameResult::NAME_ALREADY_USED:
|
||||||
|
return ts::command_result{error::group_name_inuse};
|
||||||
|
|
||||||
|
case groups::GroupRenameResult::DATABASE_ERROR:
|
||||||
|
default:
|
||||||
|
return ts::command_result{error::vs_critical};
|
||||||
|
}
|
||||||
|
|
||||||
|
serverInstance->action_logger()->group_logger.log_group_rename(this->getServerId(), this->ref(), log::GroupTarget::CHANNEL, log_group_type, channel_group->group_id(), channel_group->display_name(), old_name);
|
||||||
|
if (this->server) {
|
||||||
|
this->server->enqueue_notify_channel_group_list();
|
||||||
|
}
|
||||||
|
|
||||||
return command_result{error::ok};
|
return command_result{error::ok};
|
||||||
}
|
}
|
||||||
@ -372,54 +448,101 @@ command_result ConnectedClient::handleCommandChannelGroupRename(Command &cmd) {
|
|||||||
command_result ConnectedClient::handleCommandChannelGroupDel(Command &cmd) {
|
command_result ConnectedClient::handleCommandChannelGroupDel(Command &cmd) {
|
||||||
CMD_RESET_IDLE;
|
CMD_RESET_IDLE;
|
||||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_delete, 1);
|
|
||||||
|
|
||||||
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get();
|
auto ref_server = this->server;
|
||||||
auto channel_group = group_manager->findGroup(cmd["cgid"].as<GroupId>());
|
auto group_manager = ref_server ? ref_server->group_manager() : serverInstance->group_manager();
|
||||||
if (!channel_group || channel_group->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"};
|
auto channel_group = group_manager->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, cmd["cgid"].as<GroupId>());
|
||||||
|
if (!channel_group) {
|
||||||
|
return command_result{error::group_invalid_id};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!channel_group->permission_granted(permission::i_channel_group_needed_modify_power, this->calculate_permission(permission::i_channel_group_modify_power, 0), true)) {
|
||||||
|
return command_result{permission::i_channel_group_needed_modify_power};
|
||||||
|
}
|
||||||
|
|
||||||
if (this->server) {
|
if (this->server) {
|
||||||
if (this->server->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP] == channel_group->groupId())
|
if (this->server->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP] == channel_group->group_id()) {
|
||||||
return command_result{error::parameter_invalid, "Could not delete default channel group!"};
|
return command_result{error::parameter_invalid, "Could not delete default channel group!"};
|
||||||
if (this->server->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP] == channel_group->groupId())
|
}
|
||||||
|
if (this->server->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP] == channel_group->group_id()) {
|
||||||
return command_result{error::parameter_invalid, "Could not delete default channel admin group!"};
|
return command_result{error::parameter_invalid, "Could not delete default channel admin group!"};
|
||||||
}
|
|
||||||
if (serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP] == channel_group->groupId())
|
|
||||||
return command_result{error::parameter_invalid, "Could not delete instance default channel group!"};
|
|
||||||
|
|
||||||
if (serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP] == channel_group->groupId())
|
|
||||||
return command_result{error::parameter_invalid, "Could not delete instance default channel admin group!"};
|
|
||||||
|
|
||||||
auto type = channel_group->type();
|
|
||||||
log::GroupType log_group_type;
|
|
||||||
if (type == GroupType::GROUP_TYPE_QUERY) {
|
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1);
|
|
||||||
log_group_type = log::GroupType::QUERY;
|
|
||||||
} else if (type == GroupType::GROUP_TYPE_TEMPLATE) {
|
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1);
|
|
||||||
log_group_type = log::GroupType::TEMPLATE;
|
|
||||||
} else {
|
|
||||||
log_group_type = log::GroupType::NORMAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cmd["force"].as<bool>())
|
|
||||||
if (!group_manager->listGroupMembers(channel_group, false).empty())
|
|
||||||
return command_result{error::database_empty_result, "group not empty!"};
|
|
||||||
|
|
||||||
if (group_manager->deleteGroup(channel_group)) {
|
|
||||||
serverInstance->action_logger()->group_logger.log_group_delete(this->getServerId(), this->ref(), log::GroupTarget::SERVER, log_group_type, channel_group->groupId(), channel_group->name());
|
|
||||||
if (this->server) {
|
|
||||||
this->server->forEachClient([&](shared_ptr<ConnectedClient> cl) {
|
|
||||||
if (this->server->notifyClientPropertyUpdates(cl, this->server->group_manager()->update_server_group_property(cl, true, cl->getChannel()))) {
|
|
||||||
cl->task_update_needed_permissions.enqueue();
|
|
||||||
}
|
|
||||||
cl->notifyChannelGroupList();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this->server) {
|
if (serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP] == channel_group->group_id()) {
|
||||||
this->server->tokenManager->handle_channel_group_deleted(channel_group->groupId());
|
return command_result{error::parameter_invalid, "Could not delete instance default channel group!"};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP] == channel_group->group_id()) {
|
||||||
|
return command_result{error::parameter_invalid, "Could not delete instance default channel admin group!"};
|
||||||
|
}
|
||||||
|
|
||||||
|
log::GroupType log_group_type;
|
||||||
|
switch (channel_group->group_type()) {
|
||||||
|
case groups::GroupType::GROUP_TYPE_QUERY:
|
||||||
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1);
|
||||||
|
log_group_type = log::GroupType::QUERY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case groups::GroupType::GROUP_TYPE_TEMPLATE:
|
||||||
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1);
|
||||||
|
log_group_type = log::GroupType::TEMPLATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case groups::GroupType::GROUP_TYPE_NORMAL:
|
||||||
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_delete, 1);
|
||||||
|
log_group_type = log::GroupType::NORMAL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case groups::GroupType::GROUP_TYPE_UNKNOWN:
|
||||||
|
default:
|
||||||
|
return ts::command_result{error::vs_critical};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cmd["force"].as<bool>()) {
|
||||||
|
if(!group_manager->assignments().is_channel_group_empty(channel_group->group_id())) {
|
||||||
|
return command_result{error::group_not_empty};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = group_manager->channel_groups()->delete_group(channel_group->group_id());
|
||||||
|
switch(result) {
|
||||||
|
case groups::GroupDeleteResult::SUCCESS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case groups::GroupDeleteResult::INVALID_GROUP_ID:
|
||||||
|
case groups::GroupDeleteResult::DATABASE_ERROR:
|
||||||
|
default:
|
||||||
|
return ts::command_result{error::vs_critical};
|
||||||
|
}
|
||||||
|
|
||||||
|
serverInstance->action_logger()->group_logger.log_group_delete(this->getServerId(), this->ref(), log::GroupTarget::SERVER, log_group_type, channel_group->group_id(), channel_group->display_name());
|
||||||
|
if(ref_server) {
|
||||||
|
auto channel_group_id = channel_group->group_id();
|
||||||
|
|
||||||
|
std::deque<std::shared_ptr<ConnectedClient>> affected_clients{};
|
||||||
|
this->server->forEachClient([&](std::shared_ptr<ConnectedClient> client) {
|
||||||
|
/* TODO: It might be faster to query all clients of the group and search within that list only */
|
||||||
|
auto assigned_group = group_manager->assignments().exact_channel_group_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, client->getClientDatabaseId(), client->getChannelId());
|
||||||
|
if(assigned_group.has_value() && assigned_group->group_id == channel_group_id) {
|
||||||
|
affected_clients.push_back(client);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ref_server->enqueue_notify_channel_group_list();
|
||||||
|
ref_server->group_manager()->assignments().handle_channel_group_deleted(channel_group_id);
|
||||||
|
|
||||||
|
for(const auto& client : affected_clients) {
|
||||||
|
/*
|
||||||
|
* Now we can enqueue all the updates since handle_channel_group_deleted has already been called.
|
||||||
|
* If not done in that order, the group might already got updated before we actiually deleted it from the group manager.
|
||||||
|
*/
|
||||||
|
client->task_update_displayed_groups.enqueue();
|
||||||
|
client->task_update_needed_permissions.enqueue();
|
||||||
|
client->task_update_channel_client_properties.enqueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
ref_server->tokenManager->handle_channel_group_deleted(channel_group_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return command_result{error::ok};
|
return command_result{error::ok};
|
||||||
@ -430,7 +553,9 @@ command_result ConnectedClient::handleCommandChannelGroupList(Command &) {
|
|||||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_list, 1);
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_list, 1);
|
||||||
|
|
||||||
this->notifyChannelGroupList(this->getType() != ClientType::CLIENT_QUERY);
|
std::optional<ts::command_builder> notify{};
|
||||||
|
this->notifyChannelGroupList(notify, this->getType() != ClientType::CLIENT_QUERY);
|
||||||
|
|
||||||
this->command_times.servergrouplist = system_clock::now();
|
this->command_times.servergrouplist = system_clock::now();
|
||||||
return command_result{error::ok};
|
return command_result{error::ok};
|
||||||
}
|
}
|
||||||
@ -439,69 +564,29 @@ command_result ConnectedClient::handleCommandChannelGroupClientList(Command &cmd
|
|||||||
CMD_REQ_SERVER;
|
CMD_REQ_SERVER;
|
||||||
CMD_RESET_IDLE;
|
CMD_RESET_IDLE;
|
||||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||||
|
|
||||||
auto target_channel_id = cmd[0].has("cid") ? cmd["cid"].as<ChannelId>() : 0;
|
auto target_channel_id = cmd[0].has("cid") ? cmd["cid"].as<ChannelId>() : 0;
|
||||||
if (target_channel_id > 0) {
|
auto target_client_database_id = cmd[0].has("cldbid") ? cmd["cldbid"].as<ClientDbId>() : 0;
|
||||||
ACTION_REQUIRES_PERMISSION(permission::b_virtualserver_channelgroup_client_list, 1, target_channel_id);
|
auto target_group_id = cmd[0].has("cgid") ? cmd["cgid"].as<GroupId>() : 0;
|
||||||
} else {
|
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_client_list, 1);
|
|
||||||
}
|
|
||||||
Command result(this->getExternalType() == ClientType::CLIENT_TEAMSPEAK ? "notifychannelgroupclientlist" : "");
|
|
||||||
|
|
||||||
deque<variable> variables{variable{":sid", this->getServerId()}};
|
ACTION_REQUIRES_PERMISSION(permission::b_virtualserver_channelgroup_client_list, 1, target_channel_id);
|
||||||
string query = "SELECT `groupId`, `cldbid`, `until`, `channelId` FROM `assignedGroups` WHERE `serverId` = :sid";
|
|
||||||
|
|
||||||
if (cmd[0].has("cgid") && cmd["cgid"].as<GroupId>() > 0) {
|
auto result = this->server->group_manager()->assignments().channel_group_list(target_group_id, target_channel_id, target_client_database_id);
|
||||||
auto group = this->server->group_manager()->findGroup(cmd["cgid"]);
|
if(result.empty()) {
|
||||||
if (!group || group->target() != GroupTarget::GROUPTARGET_CHANNEL)
|
return ts::command_result{error::database_empty_result};
|
||||||
return command_result{error::parameter_invalid, "invalid channel group id"};
|
|
||||||
query += " AND `groupId` = :groupId";
|
|
||||||
variables.push_back({":groupId", cmd["cgid"].as<GroupId>()});
|
|
||||||
} else {
|
|
||||||
query += " AND `groupId` IN (SELECT `groupId` FROM `groups` WHERE `serverId` = :sid AND `target` = :target)";
|
|
||||||
variables.push_back({":target", GroupTarget::GROUPTARGET_CHANNEL});
|
|
||||||
}
|
}
|
||||||
if (cmd[0].has("cldbid") && cmd["cldbid"].as<ClientDbId>() > 0) {
|
|
||||||
query += " AND `cldbid` = :cldbid";
|
|
||||||
variables.push_back({":cldbid", cmd["cldbid"].as<ClientDbId>()});
|
|
||||||
}
|
|
||||||
if (cmd[0].has("cid") && cmd["cid"].as<ChannelId>() > 0) {
|
|
||||||
auto channel = this->server->getChannelTree()->findChannel(cmd["cid"]);
|
|
||||||
if (!channel)
|
|
||||||
return command_result{error::parameter_invalid, "invalid channel id"};
|
|
||||||
query += " AND `channelId` = :cid";
|
|
||||||
variables.push_back({":cid", cmd["cid"].as<ChannelId>()});
|
|
||||||
}
|
|
||||||
debugMessage(this->getServerId(), "Command channelgroupclientlist sql: {}", query);
|
|
||||||
|
|
||||||
auto command = sql::command(this->sql, query);
|
|
||||||
for (const auto &variable : variables)
|
|
||||||
command.value(variable);
|
|
||||||
|
|
||||||
int index = 0;
|
size_t index{0};
|
||||||
command.query([&](Command &command, int &index, int length, string *values, string *names) {
|
ts::command_builder notify{this->notify_response_command("notifychannelgroupclientlist"), 64, result.size()};
|
||||||
GroupId group_id = 0;
|
for(const auto& entry : result) {
|
||||||
ChannelId channel_id = 0;
|
auto bulk = notify.bulk(index++);
|
||||||
ClientDbId cldbid = 0;
|
bulk.put_unchecked("cgid", std::get<0>(entry));
|
||||||
for (int i = 0; i < length; i++) {
|
bulk.put_unchecked("cid", std::get<1>(entry));
|
||||||
try {
|
bulk.put_unchecked("cldbid", std::get<2>(entry));
|
||||||
if (names[i] == "groupId")
|
}
|
||||||
group_id = stoll(values[i]);
|
this->sendCommand(notify);
|
||||||
else if (names[i] == "cldbid")
|
|
||||||
cldbid = stoll(values[i]);
|
|
||||||
else if (names[i] == "channelId")
|
|
||||||
channel_id = stoll(values[i]);
|
|
||||||
} catch (std::exception &ex) {
|
|
||||||
logError(this->getServerId(), "Failed to parse db field {}", names[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result[index]["cid"] = channel_id;
|
|
||||||
result[index]["cgid"] = group_id;
|
|
||||||
result[index]["cldbid"] = cldbid;
|
|
||||||
index++;
|
|
||||||
},
|
|
||||||
result, index);
|
|
||||||
if (index == 0) return command_result{error::database_empty_result};
|
|
||||||
this->sendCommand(result);
|
|
||||||
return command_result{error::ok};
|
return command_result{error::ok};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,9 +594,15 @@ command_result ConnectedClient::handleCommandChannelGroupPermList(Command &cmd)
|
|||||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_permission_list, 1);
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_permission_list, 1);
|
||||||
|
|
||||||
auto channelGroup = (this->server ? this->server->group_manager() : serverInstance->group_manager().get())->findGroup(cmd["cgid"].as<GroupId>());
|
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager();
|
||||||
if (!channelGroup || channelGroup->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"};
|
auto channelGroup = group_manager->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, cmd["cgid"].as<GroupId>());
|
||||||
if (!this->notifyGroupPermList(channelGroup, cmd.hasParm("permsid"))) return command_result{error::database_empty_result};
|
if (!channelGroup) {
|
||||||
|
return command_result{error::group_invalid_id};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->notifyGroupPermList(channelGroup, cmd.hasParm("permsid"))) {
|
||||||
|
return command_result{error::database_empty_result};
|
||||||
|
}
|
||||||
|
|
||||||
if (this->getType() == ClientType::CLIENT_TEAMSPEAK && this->command_times.last_notify + this->command_times.notify_timeout < system_clock::now()) {
|
if (this->getType() == ClientType::CLIENT_TEAMSPEAK && this->command_times.last_notify + this->command_times.notify_timeout < system_clock::now()) {
|
||||||
this->sendTSPermEditorWarning();
|
this->sendTSPermEditorWarning();
|
||||||
@ -523,9 +614,11 @@ command_result ConnectedClient::handleCommandChannelGroupPermList(Command &cmd)
|
|||||||
command_result ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) {
|
command_result ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) {
|
||||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||||
|
|
||||||
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get();
|
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager();
|
||||||
auto channelGroup = group_manager->findGroup(cmd["cgid"].as<GroupId>());
|
auto channelGroup = group_manager->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, cmd["cgid"].as<GroupId>());
|
||||||
if (!channelGroup || channelGroup->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"};
|
if (!channelGroup) {
|
||||||
|
return command_result{error::group_invalid_id};
|
||||||
|
}
|
||||||
ACTION_REQUIRES_GROUP_PERMISSION(channelGroup, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true);
|
ACTION_REQUIRES_GROUP_PERMISSION(channelGroup, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true);
|
||||||
|
|
||||||
ts::command::bulk_parser::PermissionBulksParser<true> pparser{cmd};
|
ts::command::bulk_parser::PermissionBulksParser<true> pparser{cmd};
|
||||||
@ -542,20 +635,14 @@ command_result ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) {
|
|||||||
log::PermissionTarget::CHANNEL_GROUP,
|
log::PermissionTarget::CHANNEL_GROUP,
|
||||||
permission::v2::PermissionUpdateType::set_value,
|
permission::v2::PermissionUpdateType::set_value,
|
||||||
0, "",
|
0, "",
|
||||||
channelGroup->groupId(), channelGroup->name());
|
channelGroup->group_id(), channelGroup->display_name());
|
||||||
|
|
||||||
updateList |= ppermission.is_group_property();
|
updateList |= ppermission.is_group_property();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateList) {
|
|
||||||
channelGroup->apply_properties_from_permissions();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->server) {
|
if (this->server) {
|
||||||
if (updateList) {
|
if (updateList) {
|
||||||
this->server->forEachClient([](shared_ptr<ConnectedClient> cl) {
|
this->server->enqueue_notify_channel_group_list();
|
||||||
cl->notifyChannelGroupList();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->server->forEachClient([channelGroup](shared_ptr<ConnectedClient> cl) {
|
this->server->forEachClient([channelGroup](shared_ptr<ConnectedClient> cl) {
|
||||||
@ -575,9 +662,12 @@ command_result ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) {
|
|||||||
|
|
||||||
command_result ConnectedClient::handleCommandChannelGroupDelPerm(Command &cmd) {
|
command_result ConnectedClient::handleCommandChannelGroupDelPerm(Command &cmd) {
|
||||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||||
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get();
|
|
||||||
auto channelGroup = group_manager->findGroup(cmd["cgid"].as<GroupId>());
|
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager();
|
||||||
if (!channelGroup || channelGroup->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"};
|
auto channelGroup = group_manager->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, cmd["cgid"].as<GroupId>());
|
||||||
|
if (!channelGroup) {
|
||||||
|
return command_result{error::group_invalid_id};
|
||||||
|
}
|
||||||
ACTION_REQUIRES_GROUP_PERMISSION(channelGroup, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true);
|
ACTION_REQUIRES_GROUP_PERMISSION(channelGroup, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true);
|
||||||
|
|
||||||
ts::command::bulk_parser::PermissionBulksParser<false> pparser{cmd};
|
ts::command::bulk_parser::PermissionBulksParser<false> pparser{cmd};
|
||||||
@ -593,18 +683,13 @@ command_result ConnectedClient::handleCommandChannelGroupDelPerm(Command &cmd) {
|
|||||||
log::PermissionTarget::CHANNEL_GROUP,
|
log::PermissionTarget::CHANNEL_GROUP,
|
||||||
permission::v2::PermissionUpdateType::delete_value,
|
permission::v2::PermissionUpdateType::delete_value,
|
||||||
0, "",
|
0, "",
|
||||||
channelGroup->groupId(), channelGroup->name());
|
channelGroup->group_id(), channelGroup->display_name());
|
||||||
updateList |= ppermission.is_group_property();
|
updateList |= ppermission.is_group_property();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateList)
|
|
||||||
channelGroup->apply_properties_from_permissions();
|
|
||||||
|
|
||||||
if (this->server) {
|
if (this->server) {
|
||||||
if (updateList)
|
if (updateList)
|
||||||
this->server->forEachClient([](shared_ptr<ConnectedClient> cl) {
|
this->server->enqueue_notify_channel_group_list();
|
||||||
cl->notifyChannelGroupList();
|
|
||||||
});
|
|
||||||
this->server->forEachClient([channelGroup](shared_ptr<ConnectedClient> cl) {
|
this->server->forEachClient([channelGroup](shared_ptr<ConnectedClient> cl) {
|
||||||
unique_lock client_channel_lock(cl->channel_lock); /* while we're updating groups we dont want to change anything! */
|
unique_lock client_channel_lock(cl->channel_lock); /* while we're updating groups we dont want to change anything! */
|
||||||
if (cl->channelGroupAssigned(channelGroup, cl->getChannel())) {
|
if (cl->channelGroupAssigned(channelGroup, cl->getChannel())) {
|
||||||
@ -632,7 +717,7 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
|
|||||||
|
|
||||||
#define test_permission(required, permission_type) \
|
#define test_permission(required, permission_type) \
|
||||||
do { \
|
do { \
|
||||||
if (!permission::v2::permission_granted(required, this->calculate_permission(permission_type, parent_channel_id, false))) \
|
if (!permission::v2::permission_granted(required, this->calculate_permission(permission_type, parent_channel_id, false))) \
|
||||||
return command_result{permission_type}; \
|
return command_result{permission_type}; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -842,22 +927,25 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
|
|||||||
max_channels = this->calculate_permission(permission::i_client_max_permanent_channels, parent_channel_id, false);
|
max_channels = this->calculate_permission(permission::i_client_max_permanent_channels, parent_channel_id, false);
|
||||||
|
|
||||||
if (max_channels.has_value) {
|
if (max_channels.has_value) {
|
||||||
if (!permission::v2::permission_granted(created_perm + 1, max_channels))
|
if (!permission::v2::permission_granted(created_perm + 1, max_channels)) {
|
||||||
return command_result{permission::i_client_max_permanent_channels};
|
return command_result{permission::i_client_max_permanent_channels};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (cmd[0]["channel_flag_semi_permanent"].as<bool>()) {
|
} else if (cmd[0]["channel_flag_semi_permanent"].as<bool>()) {
|
||||||
max_channels = this->calculate_permission(permission::i_client_max_semi_channels, parent_channel_id, false);
|
max_channels = this->calculate_permission(permission::i_client_max_semi_channels, parent_channel_id, false);
|
||||||
|
|
||||||
if (max_channels.has_value) {
|
if (max_channels.has_value) {
|
||||||
if (!permission::v2::permission_granted(created_semi + 1, max_channels))
|
if (!permission::v2::permission_granted(created_semi + 1, max_channels)) {
|
||||||
return command_result{permission::i_client_max_semi_channels};
|
return command_result{permission::i_client_max_semi_channels};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
max_channels = this->calculate_permission(permission::i_client_max_temporary_channels, parent_channel_id, false);
|
max_channels = this->calculate_permission(permission::i_client_max_temporary_channels, parent_channel_id, false);
|
||||||
|
|
||||||
if (max_channels.has_value) {
|
if (max_channels.has_value) {
|
||||||
if (!permission::v2::permission_granted(created_tmp + 1, max_channels))
|
if (!permission::v2::permission_granted(created_tmp + 1, max_channels)) {
|
||||||
return command_result{permission::i_client_max_temporary_channels};
|
return command_result{permission::i_client_max_temporary_channels};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -873,7 +961,9 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
|
|||||||
channel_deep++;
|
channel_deep++;
|
||||||
{
|
{
|
||||||
const auto typed_parent = dynamic_pointer_cast<ServerChannel>(local_parent->entry);
|
const auto typed_parent = dynamic_pointer_cast<ServerChannel>(local_parent->entry);
|
||||||
if (typed_parent->deleted) return command_result{error::channel_is_deleted, "One of the parents has been deleted"};
|
if (typed_parent->deleted) {
|
||||||
|
return command_result{error::channel_is_deleted, "One of the parents has been deleted"};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
local_parent = local_parent->parent.lock();
|
local_parent = local_parent->parent.lock();
|
||||||
}
|
}
|
||||||
@ -955,15 +1045,23 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
|
|||||||
if (this->server) {
|
if (this->server) {
|
||||||
const auto self_lock = this->ref();
|
const auto self_lock = this->ref();
|
||||||
|
|
||||||
GroupId adminGroup = this->server->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP];
|
auto admin_group_id = this->server->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP].as_or<GroupId>(0);
|
||||||
auto channel_admin_group = this->server->group_manager()->findGroup(adminGroup);
|
auto admin_group = this->server->group_manager()->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, admin_group_id);
|
||||||
if (!channel_admin_group) {
|
if(!admin_group) {
|
||||||
logError(this->getServerId(), "Missing server's default channel admin group! Using default channel group!");
|
logError(this->getServerId(), "Missing servers default channel admin group {}. Using the default channel gropup.", admin_group_id);
|
||||||
channel_admin_group = this->server->group_manager()->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL);
|
admin_group = this->server->default_channel_group();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: Log group assignment */
|
/* admin_group might still be null since default_channel_group() could return nullptr */
|
||||||
this->server->group_manager()->setChannelGroup(this->getClientDatabaseId(), channel_admin_group, created_channel);
|
if(admin_group) {
|
||||||
|
this->server->group_manager()->assignments().set_channel_group(this->getClientDatabaseId(), created_channel->channelId(), admin_group->group_id(), false);
|
||||||
|
serverInstance->action_logger()->group_assignment_logger.log_group_assignment_remove(
|
||||||
|
this->getServerId(), this->server->getServerRoot(),
|
||||||
|
log::GroupTarget::CHANNEL,
|
||||||
|
admin_group->group_id(), admin_group->display_name(),
|
||||||
|
this->getClientDatabaseId(), this->getDisplayName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (created_channel->channelType() == ChannelType::temporary && (this->getType() == ClientType::CLIENT_TEAMSPEAK || this->getType() == ClientType::CLIENT_WEB || this->getType() == ClientType::CLIENT_TEASPEAK)) {
|
if (created_channel->channelType() == ChannelType::temporary && (this->getType() == ClientType::CLIENT_TEAMSPEAK || this->getType() == ClientType::CLIENT_WEB || this->getType() == ClientType::CLIENT_TEASPEAK)) {
|
||||||
channel_tree_read_lock.unlock();
|
channel_tree_read_lock.unlock();
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
#include "../../manager/ConversationManager.h"
|
#include "../../manager/ConversationManager.h"
|
||||||
#include "../../manager/PermissionNameMapper.h"
|
#include "../../manager/PermissionNameMapper.h"
|
||||||
#include "../../manager/ActionLogger.h"
|
#include "../../manager/ActionLogger.h"
|
||||||
|
#include "../../groups/GroupManager.h"
|
||||||
|
#include "../../absl/btree/map.h"
|
||||||
#include <experimental/filesystem>
|
#include <experimental/filesystem>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <StringVariable.h>
|
#include <StringVariable.h>
|
||||||
@ -443,28 +445,41 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd)
|
|||||||
CMD_RESET_IDLE;
|
CMD_RESET_IDLE;
|
||||||
CMD_CHK_AND_INC_FLOOD_POINTS(25);
|
CMD_CHK_AND_INC_FLOOD_POINTS(25);
|
||||||
|
|
||||||
auto serverGroup = this->server->group_manager()->findGroup(cmd["cgid"].as<GroupId>());
|
auto target_channel_group_id = cmd["cgid"].as<GroupId>();
|
||||||
if (!serverGroup && cmd["cgid"].as<GroupId>() == 0)
|
std::shared_ptr<groups::ChannelGroup> target_channel_group{}, default_channel_group{};
|
||||||
serverGroup = this->server->group_manager()->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL);
|
|
||||||
|
|
||||||
if (!serverGroup || serverGroup->target() != GROUPTARGET_CHANNEL)
|
default_channel_group = this->server->default_channel_group();
|
||||||
return command_result{error::group_invalid_id};
|
if(target_channel_group_id == 0) {
|
||||||
|
target_channel_group = default_channel_group;
|
||||||
|
if(!target_channel_group) {
|
||||||
|
return command_result{error::vs_critical};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target_channel_group = this->server->group_manager()->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, cmd["cgid"].as<GroupId>());
|
||||||
|
if(!target_channel_group) {
|
||||||
|
return command_result{error::group_invalid_id};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
shared_lock server_channel_lock(this->server->channel_tree_lock); /* ensure we dont get moved or somebody could move us */
|
shared_lock server_channel_lock{this->server->channel_tree_lock}; /* ensure we dont get moved or somebody could move us */
|
||||||
auto channel_id = cmd["cid"].as<ChannelId>();
|
auto channel_id = cmd["cid"].as<ChannelId>();
|
||||||
auto channel = this->server->channelTree->findChannel(channel_id);
|
auto channel = this->server->channelTree->findChannel(channel_id);
|
||||||
if (!channel) return command_result{error::channel_invalid_id};
|
if (!channel) {
|
||||||
|
return command_result{error::channel_invalid_id};
|
||||||
|
}
|
||||||
|
|
||||||
auto target_cldbid = cmd["cldbid"].as<ClientDbId>();
|
auto target_cldbid = cmd["cldbid"].as<ClientDbId>();
|
||||||
{
|
{
|
||||||
auto channel_group_member_add_power = this->calculate_permission(permission::i_channel_group_member_add_power, channel_id);
|
auto channel_group_member_add_power = this->calculate_permission(permission::i_channel_group_member_add_power, channel_id);
|
||||||
if(!serverGroup->permission_granted(permission::i_channel_group_needed_member_add_power, channel_group_member_add_power, true)) {
|
if(!target_channel_group->permission_granted(permission::i_channel_group_needed_member_add_power, channel_group_member_add_power, true)) {
|
||||||
if(target_cldbid != this->getClientDatabaseId())
|
if(target_cldbid != this->getClientDatabaseId()) {
|
||||||
return command_result{permission::i_channel_group_member_add_power};
|
return command_result{permission::i_channel_group_member_add_power};
|
||||||
|
}
|
||||||
|
|
||||||
auto channel_group_self_add_power = this->calculate_permission(permission::i_channel_group_self_add_power, channel_id);
|
auto channel_group_self_add_power = this->calculate_permission(permission::i_channel_group_self_add_power, channel_id);
|
||||||
if(!serverGroup->permission_granted(permission::i_channel_group_needed_member_add_power, channel_group_self_add_power, true))
|
if(!target_channel_group->permission_granted(permission::i_channel_group_needed_member_add_power, channel_group_self_add_power, true)) {
|
||||||
return command_result{permission::i_channel_group_self_add_power};
|
return command_result{permission::i_channel_group_self_add_power};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -474,66 +489,68 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd)
|
|||||||
|
|
||||||
|
|
||||||
if(client_needed_permission_modify_power.has_value) {
|
if(client_needed_permission_modify_power.has_value) {
|
||||||
if(!permission::v2::permission_granted(client_needed_permission_modify_power, client_permission_modify_power))
|
if(!permission::v2::permission_granted(client_needed_permission_modify_power, client_permission_modify_power)) {
|
||||||
return command_result{permission::i_client_permission_modify_power};
|
return command_result{permission::i_client_permission_modify_power};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<GroupAssignment> old_group;
|
|
||||||
{
|
|
||||||
old_group = this->server->group_manager()->getChannelGroupExact(target_cldbid, channel, false);
|
|
||||||
if(old_group) {
|
|
||||||
auto channel_group_member_remove_power = this->calculate_permission(permission::i_channel_group_member_remove_power, channel_id);
|
|
||||||
if(!old_group->group->permission_granted(permission::i_channel_group_needed_member_remove_power, channel_group_member_remove_power, true)) {
|
|
||||||
if(target_cldbid != this->getClientDatabaseId())
|
|
||||||
return command_result{permission::i_channel_group_member_remove_power};
|
|
||||||
|
|
||||||
auto channel_group_self_remove_power = this->calculate_permission(permission::i_channel_group_self_remove_power, channel_id);
|
|
||||||
if(!old_group->group->permission_granted(permission::i_channel_group_needed_member_remove_power, channel_group_self_remove_power, true))
|
|
||||||
return command_result{permission::i_channel_group_self_remove_power};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->server->group_manager()->setChannelGroup(target_cldbid, serverGroup, channel);
|
auto old_group_id = this->server->group_manager()->assignments().exact_channel_group_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, target_cldbid, channel->channelId());
|
||||||
|
std::shared_ptr<groups::ChannelGroup> old_group{};
|
||||||
|
|
||||||
|
if(old_group_id.has_value()) {
|
||||||
|
old_group = this->server->group_manager()->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, old_group_id->group_id);
|
||||||
|
if(old_group) {
|
||||||
|
auto channel_group_member_remove_power = this->calculate_permission(permission::i_channel_group_member_remove_power, channel_id);
|
||||||
|
if(!old_group->permission_granted(permission::i_channel_group_needed_member_remove_power, channel_group_member_remove_power, true)) {
|
||||||
|
if(target_cldbid != this->getClientDatabaseId()) {
|
||||||
|
return command_result{permission::i_channel_group_member_remove_power};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto channel_group_self_remove_power = this->calculate_permission(permission::i_channel_group_self_remove_power, channel_id);
|
||||||
|
if(!old_group->permission_granted(permission::i_channel_group_needed_member_remove_power, channel_group_self_remove_power, true)) {
|
||||||
|
return command_result{permission::i_channel_group_self_remove_power};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->server->group_manager()->assignments().set_channel_group(target_cldbid, target_channel_group->group_id(), channel->channelId(), !target_channel_group->is_permanent());
|
||||||
|
|
||||||
std::shared_ptr<ConnectedClient> connected_client{};
|
std::shared_ptr<ConnectedClient> connected_client{};
|
||||||
for (const auto &targetClient : this->server->findClientsByCldbId(target_cldbid)) {
|
for (const auto &targetClient : this->server->findClientsByCldbId(target_cldbid)) {
|
||||||
connected_client = targetClient;
|
connected_client = targetClient;
|
||||||
|
|
||||||
unique_lock client_channel_lock_w(targetClient->channel_lock);
|
bool channel_group_changed, server_group_changed;
|
||||||
auto updates = this->server->group_manager()->update_server_group_property(targetClient, false, targetClient->getChannel()); /* needs a write lock */
|
targetClient->update_displayed_client_groups(server_group_changed, channel_group_changed);
|
||||||
client_channel_lock_w.unlock();
|
|
||||||
shared_lock client_channel_lock_r(targetClient->channel_lock);
|
|
||||||
auto result = this->server->notifyClientPropertyUpdates(targetClient, updates);
|
|
||||||
if (result) {
|
|
||||||
targetClient->task_update_needed_permissions.enqueue();
|
|
||||||
|
|
||||||
if(targetClient->properties()[property::CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID] == channel->channelId()) { //Only if group assigned over the channel
|
if(channel_group_changed) {
|
||||||
for (const auto &viewer : this->server->getClients()) {
|
targetClient->task_update_needed_permissions.enqueue();
|
||||||
/* if in view will be tested within that method */
|
targetClient->task_update_displayed_groups.enqueue();
|
||||||
shared_lock viewer_channel_lock(viewer->channel_lock, defer_lock);
|
|
||||||
if(viewer != targetClient)
|
for (const auto &viewer : this->server->getClients()) {
|
||||||
viewer_channel_lock.lock();
|
/* if in view will be tested within that method */
|
||||||
viewer->notifyClientChannelGroupChanged(this->ref(), targetClient, targetClient->getChannel(), channel, serverGroup, false);
|
std::shared_lock viewer_channel_lock{viewer->channel_lock, defer_lock};
|
||||||
|
if(viewer != targetClient) {
|
||||||
|
viewer_channel_lock.lock();
|
||||||
}
|
}
|
||||||
|
viewer->notifyClientChannelGroupChanged(this->ref(), targetClient, targetClient->getChannel(), channel, target_channel_group, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
targetClient->task_update_channel_client_properties.enqueue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(old_group) {
|
if(old_group) {
|
||||||
serverInstance->action_logger()->group_assignment_logger.log_group_assignment_remove(this->getServerId(),
|
serverInstance->action_logger()->group_assignment_logger.log_group_assignment_remove(this->getServerId(),
|
||||||
this->ref(), log::GroupTarget::CHANNEL,
|
this->ref(), log::GroupTarget::CHANNEL,
|
||||||
old_group->group->groupId(), old_group->group->name(),
|
old_group->group_id(), old_group->display_name(),
|
||||||
target_cldbid, connected_client ? connected_client->getDisplayName() : ""
|
target_cldbid, connected_client ? connected_client->getDisplayName() : ""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if(serverGroup != this->server->group_manager()->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL)) {
|
|
||||||
|
if(target_channel_group != default_channel_group) {
|
||||||
serverInstance->action_logger()->group_assignment_logger.log_group_assignment_add(this->getServerId(),
|
serverInstance->action_logger()->group_assignment_logger.log_group_assignment_add(this->getServerId(),
|
||||||
this->ref(), log::GroupTarget::CHANNEL,
|
this->ref(), log::GroupTarget::CHANNEL,
|
||||||
serverGroup->groupId(), serverGroup->name(),
|
target_channel_group->group_id(), target_channel_group->display_name(),
|
||||||
target_cldbid, connected_client ? connected_client->getDisplayName() : ""
|
target_cldbid, connected_client ? connected_client->getDisplayName() : ""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1241,8 +1258,8 @@ void check_token_action_permissions(const std::shared_ptr<ConnectedClient>& clie
|
|||||||
|
|
||||||
switch(action.type) {
|
switch(action.type) {
|
||||||
case ActionType::AddServerGroup: {
|
case ActionType::AddServerGroup: {
|
||||||
auto target_group = client->getServer()->group_manager()->findGroup(action.id1);
|
auto target_group = client->getServer()->group_manager()->server_groups()->find_group(groups::GroupCalculateMode::GLOBAL, action.id1);
|
||||||
if(!target_group || target_group->type() == GroupType::GROUP_TYPE_TEMPLATE || target_group->target() != GroupTarget::GROUPTARGET_SERVER) {
|
if(!target_group || target_group->group_type() == groups::GroupType::GROUP_TYPE_TEMPLATE) {
|
||||||
action.type = ActionType::ActionIgnore;
|
action.type = ActionType::ActionIgnore;
|
||||||
result.set_result(index, ts::command_result{error::group_invalid_id});
|
result.set_result(index, ts::command_result{error::group_invalid_id});
|
||||||
break;
|
break;
|
||||||
@ -1258,8 +1275,8 @@ void check_token_action_permissions(const std::shared_ptr<ConnectedClient>& clie
|
|||||||
}
|
}
|
||||||
|
|
||||||
case ActionType::RemoveServerGroup: {
|
case ActionType::RemoveServerGroup: {
|
||||||
auto target_group = client->getServer()->group_manager()->findGroup(action.id1);
|
auto target_group = client->getServer()->group_manager()->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, action.id1);
|
||||||
if(!target_group || target_group->type() == GroupType::GROUP_TYPE_TEMPLATE || target_group->target() != GroupTarget::GROUPTARGET_SERVER) {
|
if(!target_group || target_group->group_type() == groups::GroupType::GROUP_TYPE_TEMPLATE) {
|
||||||
action.type = ActionType::ActionIgnore;
|
action.type = ActionType::ActionIgnore;
|
||||||
result.set_result(index, ts::command_result{error::group_invalid_id});
|
result.set_result(index, ts::command_result{error::group_invalid_id});
|
||||||
break;
|
break;
|
||||||
@ -1275,8 +1292,8 @@ void check_token_action_permissions(const std::shared_ptr<ConnectedClient>& clie
|
|||||||
}
|
}
|
||||||
|
|
||||||
case ActionType::SetChannelGroup: {
|
case ActionType::SetChannelGroup: {
|
||||||
auto target_group = client->getServer()->group_manager()->findGroup(action.id1);
|
auto target_group = client->getServer()->group_manager()->server_groups()->find_group(groups::GroupCalculateMode::GLOBAL, action.id1);
|
||||||
if(!target_group || target_group->type() == GroupType::GROUP_TYPE_TEMPLATE || target_group->target() != GroupTarget::GROUPTARGET_CHANNEL) {
|
if(!target_group || target_group->group_type() == groups::GroupType::GROUP_TYPE_TEMPLATE) {
|
||||||
action.type = ActionType::ActionIgnore;
|
action.type = ActionType::ActionIgnore;
|
||||||
result.set_result(index, ts::command_result{error::group_invalid_id});
|
result.set_result(index, ts::command_result{error::group_invalid_id});
|
||||||
break;
|
break;
|
||||||
@ -2029,8 +2046,10 @@ command_result ConnectedClient::handleCommandPermFind(Command &cmd) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
if(entries.empty())
|
|
||||||
|
if(entries.empty()) {
|
||||||
return command_result{error::database_empty_result};
|
return command_result{error::database_empty_result};
|
||||||
|
}
|
||||||
|
|
||||||
struct CommandPerm {
|
struct CommandPerm {
|
||||||
permission::PermissionType p;
|
permission::PermissionType p;
|
||||||
@ -2044,7 +2063,16 @@ command_result ConnectedClient::handleCommandPermFind(Command &cmd) {
|
|||||||
perms.resize(entries.size());
|
perms.resize(entries.size());
|
||||||
|
|
||||||
size_t index{0};
|
size_t index{0};
|
||||||
auto all_groups = this->server->group_manager()->availableGroups(true);
|
|
||||||
|
/* 1 := Server | 2 := Channel */
|
||||||
|
btree::map<GroupId, int> group_types{};
|
||||||
|
for(const auto& s_group : this->server->group_manager()->server_groups()->available_groups(groups::GroupCalculateMode::GLOBAL)) {
|
||||||
|
group_types[s_group->group_id()] = 1;
|
||||||
|
}
|
||||||
|
for(const auto& c_group : this->server->group_manager()->channel_groups()->available_groups(groups::GroupCalculateMode::GLOBAL)) {
|
||||||
|
group_types[c_group->group_id()] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
for(const auto& entry : entries) {
|
for(const auto& entry : entries) {
|
||||||
auto& perm = perms[index++];
|
auto& perm = perms[index++];
|
||||||
|
|
||||||
@ -2090,19 +2118,24 @@ command_result ConnectedClient::handleCommandPermFind(Command &cmd) {
|
|||||||
perm.id2 = 0;
|
perm.id2 = 0;
|
||||||
perm.t = 2; /* channel permission */
|
perm.t = 2; /* channel permission */
|
||||||
} else if(entry->type == permission::SQL_PERM_GROUP) {
|
} else if(entry->type == permission::SQL_PERM_GROUP) {
|
||||||
auto group = std::find_if(all_groups.begin(), all_groups.end(), [&](const auto& group) { return group->groupId() == entry->group_id; });
|
auto group_type = group_types[entry->group_id];
|
||||||
if(group == all_groups.end()) {
|
switch(group_type) {
|
||||||
index--; /* unknown group */
|
case 1:
|
||||||
continue;
|
perm.id1 = entry->group_id;
|
||||||
}
|
perm.id2 = 0;
|
||||||
if((*group)->target() == GroupTarget::GROUPTARGET_CHANNEL) {
|
perm.t = 0; /* server group */
|
||||||
perm.id1 = 0;
|
break;
|
||||||
perm.id2 = entry->group_id;
|
|
||||||
perm.t = 3; /* channel group */
|
case 2:
|
||||||
} else {
|
perm.id1 = 0;
|
||||||
perm.id1 = entry->group_id;
|
perm.id2 = entry->group_id;
|
||||||
perm.id2 = 0;
|
perm.t = 3; /* channel group */
|
||||||
perm.t = 0; /* server group */
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
/* unknown group */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -2128,21 +2161,6 @@ command_result ConnectedClient::handleCommandPermFind(Command &cmd) {
|
|||||||
return &a > &b;
|
return &a > &b;
|
||||||
});
|
});
|
||||||
|
|
||||||
#if 0
|
|
||||||
Command result(this->notify_response_command("notifypermfind"));
|
|
||||||
index = 0;
|
|
||||||
|
|
||||||
// http://yat.qa/ressourcen/server-query-kommentare/#permfind
|
|
||||||
for(const auto& e : perms) {
|
|
||||||
result[index]["p"] = e.p;
|
|
||||||
result[index]["v"] = e.v;
|
|
||||||
result[index]["id1"] = e.id1;
|
|
||||||
result[index]["id2"] = e.id2;
|
|
||||||
result[index]["t"] = e.t;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
this->sendCommand(result);
|
|
||||||
#else
|
|
||||||
command_builder result{this->notify_response_command("notifypermfind"), 64, perms.size()};
|
command_builder result{this->notify_response_command("notifypermfind"), 64, perms.size()};
|
||||||
index = 0;
|
index = 0;
|
||||||
|
|
||||||
@ -2155,7 +2173,6 @@ command_result ConnectedClient::handleCommandPermFind(Command &cmd) {
|
|||||||
bulk.put("id2", e.id2);
|
bulk.put("id2", e.id2);
|
||||||
}
|
}
|
||||||
this->sendCommand(result);
|
this->sendCommand(result);
|
||||||
#endif
|
|
||||||
|
|
||||||
return command_result{error::ok};
|
return command_result{error::ok};
|
||||||
}
|
}
|
||||||
@ -2171,7 +2188,9 @@ command_result ConnectedClient::handleCommandPermOverview(Command &cmd) {
|
|||||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||||
|
|
||||||
auto client_dbid = cmd["cldbid"].as<ClientDbId>();
|
auto client_dbid = cmd["cldbid"].as<ClientDbId>();
|
||||||
if(!serverInstance->databaseHelper()->validClientDatabaseId(this->getServer(), client_dbid)) return command_result{error::client_invalid_id};
|
if(!serverInstance->databaseHelper()->validClientDatabaseId(this->getServer(), client_dbid)) {
|
||||||
|
return command_result{error::client_invalid_id};
|
||||||
|
}
|
||||||
|
|
||||||
if(client_dbid == this->getClientDatabaseId()) {
|
if(client_dbid == this->getClientDatabaseId()) {
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_client_permissionoverview_own, 1);
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_client_permissionoverview_own, 1);
|
||||||
@ -2182,26 +2201,28 @@ command_result ConnectedClient::handleCommandPermOverview(Command &cmd) {
|
|||||||
string channel_query, perm_query;
|
string channel_query, perm_query;
|
||||||
|
|
||||||
auto channel = this->server ? this->server->channelTree->findChannel(cmd["cid"]) : serverInstance->getChannelTree()->findChannel(cmd["cid"]);
|
auto channel = this->server ? this->server->channelTree->findChannel(cmd["cid"]) : serverInstance->getChannelTree()->findChannel(cmd["cid"]);
|
||||||
if(!channel) return command_result{error::channel_invalid_id};
|
if(!channel) {
|
||||||
|
return command_result{error::channel_invalid_id};
|
||||||
|
}
|
||||||
|
|
||||||
auto server_groups = this->server->group_manager()->getServerGroups(client_dbid, ClientType::CLIENT_TEAMSPEAK);
|
auto channel_group = this->assignedChannelGroup(channel);
|
||||||
auto channel_group = this->server->group_manager()->getChannelGroup(client_dbid, channel, true);
|
|
||||||
auto permission_manager = serverInstance->databaseHelper()->loadClientPermissionManager(this->getServerId(), client_dbid);
|
auto permission_manager = serverInstance->databaseHelper()->loadClientPermissionManager(this->getServerId(), client_dbid);
|
||||||
|
|
||||||
Command result(this->getExternalType() == ClientType::CLIENT_TEAMSPEAK ? "notifypermoverview" : "");
|
Command result(this->getExternalType() == ClientType::CLIENT_TEAMSPEAK ? "notifypermoverview" : "");
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
result["cldbid"] = client_dbid;
|
result["cldbid"] = client_dbid;
|
||||||
result["cid"] = channel->channelId();
|
result["cid"] = channel->channelId();
|
||||||
if(cmd["return_code"].size() > 0)
|
if(cmd["return_code"].size() > 0) {
|
||||||
result["return_code"] = cmd["return_code"].string();
|
result["return_code"] = cmd["return_code"].string();
|
||||||
|
}
|
||||||
|
|
||||||
for(const auto& server_group : server_groups) {
|
for(const auto& server_group : this->assignedServerGroups()) {
|
||||||
auto permission_manager = server_group->group->permissions();
|
auto permission_manager = server_group->permissions();
|
||||||
for(const auto& permission_data : permission_manager->permissions()) {
|
for(const auto& permission_data : permission_manager->permissions()) {
|
||||||
auto& permission = std::get<1>(permission_data);
|
auto& permission = std::get<1>(permission_data);
|
||||||
if(permission.flags.value_set) {
|
if(permission.flags.value_set) {
|
||||||
result[index]["t"] = 0; /* server group */
|
result[index]["t"] = 0; /* server group */
|
||||||
result[index]["id1"] = server_group->group->groupId();
|
result[index]["id1"] = server_group->group_id();
|
||||||
result[index]["id2"] = 0;
|
result[index]["id2"] = 0;
|
||||||
|
|
||||||
result[index]["p"] = std::get<0>(permission_data);
|
result[index]["p"] = std::get<0>(permission_data);
|
||||||
@ -2212,7 +2233,7 @@ command_result ConnectedClient::handleCommandPermOverview(Command &cmd) {
|
|||||||
}
|
}
|
||||||
if(permission.flags.grant_set) {
|
if(permission.flags.grant_set) {
|
||||||
result[index]["t"] = 0; /* server group */
|
result[index]["t"] = 0; /* server group */
|
||||||
result[index]["id1"] = server_group->group->groupId();
|
result[index]["id1"] = server_group->group_id();
|
||||||
result[index]["id2"] = 0;
|
result[index]["id2"] = 0;
|
||||||
|
|
||||||
result[index]["p"] = (std::get<0>(permission_data) | PERM_ID_GRANT);
|
result[index]["p"] = (std::get<0>(permission_data) | PERM_ID_GRANT);
|
||||||
|
@ -5,17 +5,17 @@
|
|||||||
|
|
||||||
namespace ts::server::groups {
|
namespace ts::server::groups {
|
||||||
enum GroupType {
|
enum GroupType {
|
||||||
GROUP_TYPE_QUERY,
|
GROUP_TYPE_TEMPLATE = 0x00,
|
||||||
GROUP_TYPE_TEMPLATE,
|
GROUP_TYPE_NORMAL = 0x01,
|
||||||
GROUP_TYPE_NORMAL,
|
GROUP_TYPE_QUERY = 0x02,
|
||||||
|
|
||||||
GROUP_TYPE_UNKNOWN = 0xFF
|
GROUP_TYPE_UNKNOWN = 0xFF
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GroupNameMode {
|
enum GroupNameMode {
|
||||||
GROUP_NAME_MODE_HIDDEN,
|
GROUP_NAME_MODE_HIDDEN = 0x00,
|
||||||
GROUP_NAME_MODE_BEFORE,
|
GROUP_NAME_MODE_BEFORE = 0x01,
|
||||||
GROUP_NAME_MODE_BEHIND
|
GROUP_NAME_MODE_BEHIND = 0x02
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef uint32_t GroupSortId;
|
typedef uint32_t GroupSortId;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <log/LogUtils.h>
|
#include <log/LogUtils.h>
|
||||||
#include "./GroupAssignmentManager.h"
|
#include "./GroupAssignmentManager.h"
|
||||||
#include "./GroupManager.h"
|
#include "./GroupManager.h"
|
||||||
|
#include "BasicChannel.h"
|
||||||
|
|
||||||
using namespace ts::server::groups;
|
using namespace ts::server::groups;
|
||||||
|
|
||||||
@ -217,7 +218,7 @@ std::vector<ts::GroupId> GroupAssignmentManager::server_groups_of_client(ts::ser
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ChannelGroupAssignment> GroupAssignmentManager::channel_groups_of_client(GroupAssignmentCalculateMode mode, ClientDbId cldbid) {
|
std::vector<ChannelGroupAssignment> GroupAssignmentManager::exact_channel_groups_of_client(GroupAssignmentCalculateMode mode, ClientDbId cldbid) {
|
||||||
std::vector<ChannelGroupAssignment> result{};
|
std::vector<ChannelGroupAssignment> result{};
|
||||||
bool cache_found{false};
|
bool cache_found{false};
|
||||||
{
|
{
|
||||||
@ -262,7 +263,7 @@ std::vector<ChannelGroupAssignment> GroupAssignmentManager::channel_groups_of_cl
|
|||||||
|
|
||||||
if(mode == GroupAssignmentCalculateMode::GLOBAL) {
|
if(mode == GroupAssignmentCalculateMode::GLOBAL) {
|
||||||
if(auto parent = this->manager_->parent_manager(); parent) {
|
if(auto parent = this->manager_->parent_manager(); parent) {
|
||||||
auto parent_groups = parent->assignments().channel_groups_of_client(mode, cldbid);
|
auto parent_groups = parent->assignments().exact_channel_groups_of_client(mode, cldbid);
|
||||||
result.reserve(result.size() + parent_groups.size());
|
result.reserve(result.size() + parent_groups.size());
|
||||||
result.insert(result.begin(), parent_groups.begin(), parent_groups.end());
|
result.insert(result.begin(), parent_groups.begin(), parent_groups.end());
|
||||||
}
|
}
|
||||||
@ -271,10 +272,10 @@ std::vector<ChannelGroupAssignment> GroupAssignmentManager::channel_groups_of_cl
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ChannelGroupAssignment> GroupAssignmentManager::channel_group_of_client(GroupAssignmentCalculateMode mode,
|
std::optional<ChannelGroupAssignment> GroupAssignmentManager::exact_channel_group_of_client(GroupAssignmentCalculateMode mode,
|
||||||
ClientDbId client_database_id, ChannelId channel_id) {
|
ClientDbId client_database_id, ChannelId channel_id) {
|
||||||
/* TODO: Improve performance by not querying all groups */
|
/* TODO: Improve performance by not querying all groups */
|
||||||
auto assignments = this->channel_groups_of_client(mode, client_database_id);
|
auto assignments = this->exact_channel_groups_of_client(mode, client_database_id);
|
||||||
for(const auto& assignment : assignments) {
|
for(const auto& assignment : assignments) {
|
||||||
if(assignment.channel_id != channel_id) {
|
if(assignment.channel_id != channel_id) {
|
||||||
continue;
|
continue;
|
||||||
@ -286,6 +287,29 @@ std::optional<ChannelGroupAssignment> GroupAssignmentManager::channel_group_of_c
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<ts::GroupId> GroupAssignmentManager::calculate_channel_group_of_client(GroupAssignmentCalculateMode mode,
|
||||||
|
ClientDbId client_database_id,
|
||||||
|
std::shared_ptr<BasicChannel> &channel) {
|
||||||
|
auto assignments = this->exact_channel_groups_of_client(mode, client_database_id);
|
||||||
|
while(channel) {
|
||||||
|
for(const auto& assignment : assignments) {
|
||||||
|
if(assignment.channel_id != channel->channelId()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_optional(assignment.group_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(permission::v2::permission_granted(1, channel->permissions()->permission_value_flagged(permission::b_channel_group_inheritance_end))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel = channel->parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
std::deque<ts::ClientDbId> GroupAssignmentManager::server_group_clients(GroupId group_id) {
|
std::deque<ts::ClientDbId> GroupAssignmentManager::server_group_clients(GroupId group_id) {
|
||||||
std::deque<ts::ClientDbId> result{};
|
std::deque<ts::ClientDbId> result{};
|
||||||
if constexpr(kCacheAllClients) {
|
if constexpr(kCacheAllClients) {
|
||||||
@ -330,6 +354,59 @@ std::deque<ts::ClientDbId> GroupAssignmentManager::server_group_clients(GroupId
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::deque<std::tuple<ts::GroupId, ts::ChannelId, ts::ClientDbId>> GroupAssignmentManager::channel_group_list(
|
||||||
|
GroupId group_id,
|
||||||
|
ChannelId channel_id,
|
||||||
|
ClientDbId client_database_id
|
||||||
|
) {
|
||||||
|
std::string sql_query{};
|
||||||
|
sql_query += "SELECT `groupId`, `cldbid`, `channelId` FROM `assignedGroups` WHERE `serverId` = :sid";
|
||||||
|
if(group_id > 0) {
|
||||||
|
sql_query += " AND `groupId` = :groupId";
|
||||||
|
}
|
||||||
|
if(channel_id > 0) {
|
||||||
|
sql_query += " AND `channelId` = :cid";
|
||||||
|
}
|
||||||
|
if(client_database_id > 0) {
|
||||||
|
sql_query += " AND `cldbid` = :cldbid";
|
||||||
|
}
|
||||||
|
sql::command sql{this->sql_manager(), sql_query};
|
||||||
|
sql.value(":groupId", group_id);
|
||||||
|
sql.value(":cid", channel_id);
|
||||||
|
sql.value(":cldbid", client_database_id);
|
||||||
|
|
||||||
|
std::deque<std::tuple<ts::GroupId, ts::ChannelId, ts::ClientDbId>> result{};
|
||||||
|
LOG_SQL_CMD(sql.query([&](int length, std::string* values, std::string* names) {
|
||||||
|
GroupId group_id;
|
||||||
|
ChannelId channel_id;
|
||||||
|
ClientDbId client_database_id;
|
||||||
|
|
||||||
|
int index{0};
|
||||||
|
try {
|
||||||
|
assert(names[index] == "groupId");
|
||||||
|
group_id = std::stoull(values[index++]);
|
||||||
|
|
||||||
|
assert(names[index] == "cldbid");
|
||||||
|
channel_id = std::stoull(values[index++]);
|
||||||
|
|
||||||
|
assert(names[index] == "channelId");
|
||||||
|
client_database_id = std::stoull(values[index++]);
|
||||||
|
|
||||||
|
assert(index == length);
|
||||||
|
} catch (std::exception& ex) {
|
||||||
|
logError(this->server_id(), "Failed to parse client group assignment at index {}: {}",
|
||||||
|
index - 1,
|
||||||
|
ex.what()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.emplace_back(group_id, channel_id, client_database_id);
|
||||||
|
}));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
GroupAssignmentResult GroupAssignmentManager::add_server_group(ClientDbId client, GroupId group) {
|
GroupAssignmentResult GroupAssignmentManager::add_server_group(ClientDbId client, GroupId group) {
|
||||||
bool cache_verified{false};
|
bool cache_verified{false};
|
||||||
{
|
{
|
||||||
@ -340,8 +417,9 @@ GroupAssignmentResult GroupAssignmentManager::add_server_group(ClientDbId client
|
|||||||
auto it = std::find_if(entry->server_group_assignments.begin(), entry->server_group_assignments.end(), [&](const ServerGroupAssignment& assignment) {
|
auto it = std::find_if(entry->server_group_assignments.begin(), entry->server_group_assignments.end(), [&](const ServerGroupAssignment& assignment) {
|
||||||
return assignment.group_id == group;
|
return assignment.group_id == group;
|
||||||
});
|
});
|
||||||
if(it != entry->server_group_assignments.end())
|
if(it != entry->server_group_assignments.end()) {
|
||||||
return GroupAssignmentResult::ADD_ALREADY_MEMBER_OF_GROUP;
|
return GroupAssignmentResult::ADD_ALREADY_MEMBER_OF_GROUP;
|
||||||
|
}
|
||||||
entry->server_group_assignments.emplace_back(group);
|
entry->server_group_assignments.emplace_back(group);
|
||||||
cache_verified = true;
|
cache_verified = true;
|
||||||
break;
|
break;
|
||||||
@ -384,8 +462,9 @@ GroupAssignmentResult GroupAssignmentManager::remove_server_group(ClientDbId cli
|
|||||||
auto it = std::find_if(entry->server_group_assignments.begin(), entry->server_group_assignments.end(), [&](const ServerGroupAssignment& assignment) {
|
auto it = std::find_if(entry->server_group_assignments.begin(), entry->server_group_assignments.end(), [&](const ServerGroupAssignment& assignment) {
|
||||||
return assignment.group_id == group;
|
return assignment.group_id == group;
|
||||||
});
|
});
|
||||||
if(it == entry->server_group_assignments.end())
|
if(it == entry->server_group_assignments.end()) {
|
||||||
return GroupAssignmentResult::REMOVE_NOT_MEMBER_OF_GROUP;
|
return GroupAssignmentResult::REMOVE_NOT_MEMBER_OF_GROUP;
|
||||||
|
}
|
||||||
entry->server_group_assignments.erase(it);
|
entry->server_group_assignments.erase(it);
|
||||||
cache_verified = true;
|
cache_verified = true;
|
||||||
break;
|
break;
|
||||||
@ -507,8 +586,14 @@ void GroupAssignmentManager::cleanup_channel_temporary_assignment(ClientDbId cli
|
|||||||
auto assignment = std::find_if(client->channel_group_assignments.begin(), client->channel_group_assignments.end(), [&](const ChannelGroupAssignment& assignment) {
|
auto assignment = std::find_if(client->channel_group_assignments.begin(), client->channel_group_assignments.end(), [&](const ChannelGroupAssignment& assignment) {
|
||||||
return assignment.channel_id == channel;
|
return assignment.channel_id == channel;
|
||||||
});
|
});
|
||||||
if(assignment->temporary_assignment)
|
|
||||||
|
if(assignment == client->channel_group_assignments.end()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(assignment->temporary_assignment) {
|
||||||
client->channel_group_assignments.erase(assignment);
|
client->channel_group_assignments.erase(assignment);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -12,6 +13,10 @@ namespace sql {
|
|||||||
class SqlManager;
|
class SqlManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace ts {
|
||||||
|
class BasicChannel;
|
||||||
|
}
|
||||||
|
|
||||||
namespace ts::server {
|
namespace ts::server {
|
||||||
class ConnectedClient;
|
class ConnectedClient;
|
||||||
|
|
||||||
@ -63,17 +68,30 @@ namespace ts::server {
|
|||||||
bool load_data(std::string& /* error */);
|
bool load_data(std::string& /* error */);
|
||||||
void unload_data();
|
void unload_data();
|
||||||
|
|
||||||
|
void reset_all();
|
||||||
|
|
||||||
/* client specific cache methods */
|
/* client specific cache methods */
|
||||||
void enable_cache_for_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
|
void enable_cache_for_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
|
||||||
void disable_cache_for_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
|
void disable_cache_for_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
|
||||||
|
|
||||||
/* info/query methods */
|
/* info/query methods */
|
||||||
[[nodiscard]] std::vector<GroupId> server_groups_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
|
[[nodiscard]] std::vector<GroupId> server_groups_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
|
||||||
[[nodiscard]] std::vector<ChannelGroupAssignment> channel_groups_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
|
[[nodiscard]] std::vector<ChannelGroupAssignment> exact_channel_groups_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
|
||||||
[[nodiscard]] std::optional<ChannelGroupAssignment> channel_group_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */, ChannelId /* channel id */);
|
[[nodiscard]] std::optional<ChannelGroupAssignment> exact_channel_group_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */, ChannelId /* channel id */);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the target channel group for the client.
|
||||||
|
* The parameters `target channel` will contain the channel where the group has been inherited from.
|
||||||
|
* Note: `target channel` will be altered if the resutl is empty.
|
||||||
|
* @return The target channel group id
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::optional<GroupId> calculate_channel_group_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */, std::shared_ptr<BasicChannel>& /* target channel */);
|
||||||
|
|
||||||
[[nodiscard]] std::deque<ClientDbId> server_group_clients(GroupId /* group id */);
|
[[nodiscard]] std::deque<ClientDbId> server_group_clients(GroupId /* group id */);
|
||||||
//[[nodiscard]] std::deque<ClientDbId> channel_group_clients(GroupId /* group id */, ChannelId /* channel id */);
|
[[nodiscard]] std::deque<std::tuple<GroupId, ChannelId, ClientDbId>> channel_group_list(GroupId /* group id */, ChannelId /* channel id */, ClientDbId /* client database id */);
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_server_group_empty(GroupId /* group id */);
|
||||||
|
[[nodiscard]] bool is_channel_group_empty(GroupId /* group id */);
|
||||||
|
|
||||||
/* change methods */
|
/* change methods */
|
||||||
GroupAssignmentResult add_server_group(ClientDbId /* client database id */, GroupId /* group id */);
|
GroupAssignmentResult add_server_group(ClientDbId /* client database id */, GroupId /* group id */);
|
||||||
@ -84,6 +102,10 @@ namespace ts::server {
|
|||||||
void cleanup_assignments();
|
void cleanup_assignments();
|
||||||
void cleanup_channel_assignments(ChannelId /* channel */);
|
void cleanup_channel_assignments(ChannelId /* channel */);
|
||||||
void cleanup_channel_temporary_assignment(ClientDbId /* client database id */, ChannelId /* channel */);
|
void cleanup_channel_temporary_assignment(ClientDbId /* client database id */, ChannelId /* channel */);
|
||||||
|
|
||||||
|
void handle_channel_deleted(ChannelId /* channel id */);
|
||||||
|
void handle_server_group_deleted(GroupId /* group id */);
|
||||||
|
void handle_channel_group_deleted(GroupId /* group id */);
|
||||||
private:
|
private:
|
||||||
struct ClientCache {
|
struct ClientCache {
|
||||||
ClientDbId client_database_id{0};
|
ClientDbId client_database_id{0};
|
||||||
|
@ -114,6 +114,27 @@ void AbstractGroupManager::unload_data() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AbstractGroupManager::reset_groups(const std::shared_ptr<GroupManager> &template_provider, std::map<GroupId, GroupId> &mapping) {
|
||||||
|
std::lock_guard manage_lock{this->group_manage_mutex_};
|
||||||
|
this->unload_data();
|
||||||
|
|
||||||
|
/* Delete all old groups */
|
||||||
|
{
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AbstractGroupManager::reset_groups(bool db_cleanup) {
|
void AbstractGroupManager::reset_groups(bool db_cleanup) {
|
||||||
std::lock_guard manage_lock{this->group_manage_mutex_};
|
std::lock_guard manage_lock{this->group_manage_mutex_};
|
||||||
this->unload_data();
|
this->unload_data();
|
||||||
@ -224,6 +245,12 @@ std::shared_ptr<Group> AbstractGroupManager::find_group_by_name_(GroupCalculateM
|
|||||||
}
|
}
|
||||||
|
|
||||||
GroupCreateResult AbstractGroupManager::create_group_(GroupType type, const std::string &name, std::shared_ptr<Group>& result) {
|
GroupCreateResult AbstractGroupManager::create_group_(GroupType type, const std::string &name, std::shared_ptr<Group>& result) {
|
||||||
|
if(name.empty()) {
|
||||||
|
return GroupCreateResult::NAME_TOO_SHORT;
|
||||||
|
} else if(name.length() > 30) {
|
||||||
|
return GroupCreateResult::NAME_TOO_LONG;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard manage_lock{this->group_manage_mutex_};
|
std::lock_guard manage_lock{this->group_manage_mutex_};
|
||||||
if(this->find_group_by_name_(GroupCalculateMode::LOCAL, name)) {
|
if(this->find_group_by_name_(GroupCalculateMode::LOCAL, name)) {
|
||||||
return GroupCreateResult::NAME_ALREADY_IN_USED;
|
return GroupCreateResult::NAME_ALREADY_IN_USED;
|
||||||
@ -264,9 +291,6 @@ GroupCopyResult AbstractGroupManager::copy_group_(GroupId source, GroupType targ
|
|||||||
|
|
||||||
case GroupCreateResult::NAME_ALREADY_IN_USED:
|
case GroupCreateResult::NAME_ALREADY_IN_USED:
|
||||||
return GroupCopyResult::NAME_ALREADY_IN_USE;
|
return GroupCopyResult::NAME_ALREADY_IN_USE;
|
||||||
|
|
||||||
case GroupCreateResult::FAILED_TO_GENERATE_ID:
|
|
||||||
return GroupCopyResult::FAILED_TO_GENERATE_ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(result);
|
assert(result);
|
||||||
@ -335,12 +359,17 @@ GroupDeleteResult AbstractGroupManager::delete_group_(GroupId group_id) {
|
|||||||
std::lock_guard manage_lock{this->group_manage_mutex_};
|
std::lock_guard manage_lock{this->group_manage_mutex_};
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard glock{this->group_mutex_};
|
std::unique_lock glock{this->group_mutex_};
|
||||||
auto it = std::find_if(this->groups_.begin(), this->groups_.begin(), [&](const std::shared_ptr<Group>& group) {
|
auto it = std::find_if(this->groups_.begin(), this->groups_.begin(), [&](const std::shared_ptr<Group>& group) {
|
||||||
return group->group_id() == group_id;
|
return group->group_id() == group_id;
|
||||||
});
|
});
|
||||||
|
|
||||||
if(it == this->groups_.end()) {
|
if(it == this->groups_.end()) {
|
||||||
|
if(this->parent_manager_) {
|
||||||
|
glock.unlock();
|
||||||
|
return this->parent_manager_->delete_group_(group_id);
|
||||||
|
}
|
||||||
|
|
||||||
return GroupDeleteResult::INVALID_GROUP_ID;
|
return GroupDeleteResult::INVALID_GROUP_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,6 +383,9 @@ GroupDeleteResult AbstractGroupManager::delete_group_(GroupId group_id) {
|
|||||||
return GroupDeleteResult::SUCCESS;
|
return GroupDeleteResult::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AbstractGroupManager::reset_groups_(const std::shared_ptr<GroupManager> &source, std::map<GroupId, GroupId> &mapping) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Server group manager */
|
/* Server group manager */
|
||||||
ServerGroupManager::ServerGroupManager(const std::shared_ptr<GroupManager> &handle, std::shared_ptr<ServerGroupManager> parent)
|
ServerGroupManager::ServerGroupManager(const std::shared_ptr<GroupManager> &handle, std::shared_ptr<ServerGroupManager> parent)
|
||||||
|
@ -24,7 +24,8 @@ namespace ts::server::groups {
|
|||||||
enum struct GroupCreateResult {
|
enum struct GroupCreateResult {
|
||||||
SUCCESS,
|
SUCCESS,
|
||||||
NAME_ALREADY_IN_USED,
|
NAME_ALREADY_IN_USED,
|
||||||
FAILED_TO_GENERATE_ID,
|
NAME_TOO_SHORT,
|
||||||
|
NAME_TOO_LONG,
|
||||||
DATABASE_ERROR
|
DATABASE_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -33,7 +34,6 @@ namespace ts::server::groups {
|
|||||||
UNKNOWN_SOURCE_GROUP,
|
UNKNOWN_SOURCE_GROUP,
|
||||||
UNKNOWN_TARGET_GROUP,
|
UNKNOWN_TARGET_GROUP,
|
||||||
NAME_ALREADY_IN_USE,
|
NAME_ALREADY_IN_USE,
|
||||||
FAILED_TO_GENERATE_ID,
|
|
||||||
DATABASE_ERROR
|
DATABASE_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,9 +73,14 @@ namespace ts::server::groups {
|
|||||||
bool initialize(std::string& /* error */);
|
bool initialize(std::string& /* error */);
|
||||||
GroupLoadResult load_data(bool /* initialize */ = false);
|
GroupLoadResult load_data(bool /* initialize */ = false);
|
||||||
void unload_data();
|
void unload_data();
|
||||||
void reset_groups(bool /* cleanup database */);
|
|
||||||
|
|
||||||
void save_permissions(size_t& /* total groups */, size_t& /* saved groups */);
|
void save_permissions(size_t& /* total groups */, size_t& /* saved groups */);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset all known groups.
|
||||||
|
* If the template group provider is empty no new groups will be created.
|
||||||
|
*/
|
||||||
|
void reset_groups(const std::shared_ptr<GroupManager>& /* template group provider */, std::map<GroupId, GroupId>& /* mapping */);
|
||||||
protected:
|
protected:
|
||||||
std::shared_ptr<AbstractGroupManager> parent_manager_;
|
std::shared_ptr<AbstractGroupManager> parent_manager_;
|
||||||
DatabaseGroupTarget database_target_;
|
DatabaseGroupTarget database_target_;
|
||||||
|
13
server/things_to_test
Normal file
13
server/things_to_test
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
permission calculation
|
||||||
|
channel group inheritance
|
||||||
|
general server & channel groups
|
||||||
|
- assignments
|
||||||
|
- removement
|
||||||
|
- temporary groups
|
||||||
|
|
||||||
|
Notified channel & server member add/remove powers
|
||||||
|
Group edit if the notify<server/channel> group triggers
|
||||||
|
|
||||||
|
channelgroupclientlist
|
||||||
|
|
||||||
|
TODO: Delete the group header
|
Loading…
Reference in New Issue
Block a user