863 lines
33 KiB
C++
863 lines
33 KiB
C++
//
|
|
// Created by WolverinDEV on 08/03/2021.
|
|
//
|
|
#include <memory>
|
|
|
|
#include <bitset>
|
|
#include <algorithm>
|
|
#include <openssl/sha.h>
|
|
#include "../../build.h"
|
|
#include "../ConnectedClient.h"
|
|
#include "../InternalClient.h"
|
|
#include "../../server/VoiceServer.h"
|
|
#include "../voice/VoiceClient.h"
|
|
#include "../../InstanceHandler.h"
|
|
#include "../../server/QueryServer.h"
|
|
#include "../music/MusicClient.h"
|
|
#include "../query/QueryClient.h"
|
|
#include "../../manager/ConversationManager.h"
|
|
#include "../../manager/PermissionNameMapper.h"
|
|
#include "../../manager/ActionLogger.h"
|
|
#include "../../groups/GroupManager.h"
|
|
|
|
#include "helpers.h"
|
|
#include "./bulk_parsers.h"
|
|
|
|
#include <log/LogUtils.h>
|
|
#include <misc/base64.h>
|
|
#include <misc/digest.h>
|
|
#include <misc/rnd.h>
|
|
#include <misc/scope_guard.h>
|
|
#include <bbcode/bbcodes.h>
|
|
|
|
using namespace std::chrono;
|
|
using namespace std;
|
|
using namespace ts;
|
|
using namespace ts::server;
|
|
|
|
|
|
command_result ConnectedClient::handleCommandGroupAdd(Command &cmd, GroupTarget group_target) {
|
|
CMD_RESET_IDLE;
|
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
|
|
|
log::GroupTarget log_group_target;
|
|
switch(group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER:
|
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_create, 1);
|
|
log_group_target = log::GroupTarget::SERVER;
|
|
break;
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL:
|
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_create, 1);
|
|
log_group_target = log::GroupTarget::CHANNEL;
|
|
break;
|
|
|
|
default:
|
|
return ts::command_result{error::vs_critical, "internal invalid group target"};
|
|
}
|
|
|
|
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager();
|
|
log::GroupType log_group_type;
|
|
auto group_type = cmd[0].has("type") ? cmd["type"].as<groups::GroupType>() : groups::GroupType::GROUP_TYPE_NORMAL;
|
|
switch (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:
|
|
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"};
|
|
}
|
|
|
|
std::shared_ptr<groups::Group> group;
|
|
groups::GroupCreateResult result;
|
|
|
|
std::string notify_name;
|
|
std::string notify_id_key;
|
|
switch(group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER: {
|
|
std::shared_ptr<groups::ServerGroup> s_group;
|
|
result = group_manager->server_groups()->create_group(group_type, cmd["name"].string(), s_group);
|
|
group = s_group;
|
|
|
|
notify_name = this->notify_response_command("notifyservergroupadded");
|
|
notify_id_key = "sgid";
|
|
break;
|
|
}
|
|
case GroupTarget::GROUPTARGET_CHANNEL: {
|
|
std::shared_ptr<groups::ChannelGroup> c_group;
|
|
result = group_manager->channel_groups()->create_group(group_type, cmd["name"].string(), c_group);
|
|
group = c_group;
|
|
|
|
notify_name = this->notify_response_command("notifychannelgroupadded");
|
|
notify_id_key = "cgid";
|
|
break;
|
|
}
|
|
|
|
default:
|
|
assert(false);
|
|
result = groups::GroupCreateResult::DATABASE_ERROR;
|
|
break;
|
|
}
|
|
|
|
switch(result) {
|
|
case groups::GroupCreateResult::SUCCESS:
|
|
break;
|
|
|
|
case groups::GroupCreateResult::NAME_TOO_SHORT:
|
|
case groups::GroupCreateResult::NAME_TOO_LONG:
|
|
return command_result{error::parameter_invalid, "name"};
|
|
|
|
case groups::GroupCreateResult::NAME_ALREADY_IN_USED:
|
|
return command_result{error::group_name_inuse};
|
|
|
|
case groups::GroupCreateResult::DATABASE_ERROR:
|
|
default:
|
|
return command_result{error::vs_critical};
|
|
}
|
|
|
|
assert(group);
|
|
assert(!notify_id_key.empty());
|
|
serverInstance->action_logger()->group_logger.log_group_create(this->getServerId(), this->ref(), log_group_target, log_group_type, group->group_id(), group->display_name(), 0, "");
|
|
|
|
{
|
|
ts::command_builder notify{notify_name};
|
|
notify.put_unchecked(0, notify_id_key, group->group_id());
|
|
this->sendCommand(notify);
|
|
}
|
|
|
|
group->permissions()->set_permission(permission::b_group_is_permanent, {1, 0}, permission::v2::set_value, permission::v2::do_nothing);
|
|
if (this->server) {
|
|
switch(group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER:
|
|
this->server->enqueue_notify_server_group_list();
|
|
break;
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL:
|
|
this->server->enqueue_notify_channel_group_list();
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::deque<std::shared_ptr<VirtualServer>> server_updates{};
|
|
if(!this->server) {
|
|
server_updates = serverInstance->getVoiceServerManager()->serverInstances();
|
|
} else {
|
|
server_updates.push_back(this->server);
|
|
}
|
|
|
|
for(const auto& server : server_updates) {
|
|
if(!server) {
|
|
continue;
|
|
}
|
|
|
|
switch(group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER:
|
|
server->enqueue_notify_server_group_list();
|
|
break;
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL:
|
|
server->enqueue_notify_channel_group_list();
|
|
break;
|
|
}
|
|
}
|
|
|
|
return command_result{error::ok};
|
|
}
|
|
|
|
command_result ConnectedClient::handleCommandGroupCopy(Command &cmd, GroupTarget group_target) {
|
|
CMD_RESET_IDLE;
|
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
|
|
|
auto ref_server = this->server;
|
|
auto group_manager = ref_server ? ref_server->group_manager() : serverInstance->group_manager();
|
|
|
|
log::GroupTarget log_group_target;
|
|
GroupId source_group_id, target_group_id;
|
|
std::shared_ptr<groups::Group> source_group{}, target_group{};
|
|
bool target_group_global;
|
|
|
|
switch(group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER: {
|
|
std::shared_ptr<groups::ServerGroupManager> owning_manager{};
|
|
|
|
source_group_id = cmd["ssgid"].as<GroupId>();
|
|
target_group_id = cmd[0].has("tsgid") ? cmd["tsgid"].as<GroupId>() : 0;
|
|
|
|
source_group = group_manager->server_groups()->find_group(groups::GroupCalculateMode::GLOBAL, source_group_id);
|
|
target_group = group_manager->server_groups()->find_group_ext(owning_manager, groups::GroupCalculateMode::GLOBAL, target_group_id);
|
|
target_group_global = owning_manager != group_manager->server_groups();
|
|
|
|
log_group_target = log::GroupTarget::SERVER;
|
|
break;
|
|
}
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL: {
|
|
std::shared_ptr<groups::ChannelGroupManager> owning_manager{};
|
|
|
|
source_group_id = cmd["scgid"].as<GroupId>();
|
|
target_group_id = cmd[0].has("tcgid") ? cmd["tcgid"].as<GroupId>() : 0;
|
|
|
|
source_group = group_manager->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, source_group_id);
|
|
target_group = group_manager->channel_groups()->find_group_ext(owning_manager, groups::GroupCalculateMode::GLOBAL, target_group_id);
|
|
target_group_global = owning_manager != group_manager->channel_groups();
|
|
|
|
log_group_target = log::GroupTarget::CHANNEL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!source_group) {
|
|
return command_result{error::group_invalid_id, "invalid source group id"};
|
|
}
|
|
|
|
if (target_group_id > 0 && !target_group) {
|
|
return command_result{error::group_invalid_id, "invalid target group"};
|
|
}
|
|
|
|
const auto group_type_modifiable = [&](groups::GroupType type) {
|
|
switch (type) {
|
|
case groups::GroupType::GROUP_TYPE_TEMPLATE:
|
|
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_serverinstance_modify_templates, 0))) {
|
|
return permission::b_serverinstance_modify_templates;
|
|
}
|
|
|
|
break;
|
|
case groups::GroupType::GROUP_TYPE_QUERY:
|
|
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_serverinstance_modify_querygroup, 0))) {
|
|
return permission::b_serverinstance_modify_querygroup;
|
|
}
|
|
|
|
break;
|
|
|
|
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:
|
|
break;
|
|
}
|
|
return permission::undefined;
|
|
};
|
|
|
|
{
|
|
auto result = group_type_modifiable(source_group->group_type());
|
|
if (result != permission::undefined) {
|
|
return command_result{result};
|
|
}
|
|
}
|
|
|
|
auto global_update = false;
|
|
if (target_group) {
|
|
if(!target_group->permission_granted(permission::i_channel_group_needed_modify_power, this->calculate_permission(permission::i_channel_group_modify_power, 0), true)) {
|
|
return ts::command_result{permission::i_channel_group_needed_modify_power};
|
|
}
|
|
|
|
{
|
|
auto result = group_type_modifiable(target_group->group_type());
|
|
if (result != permission::undefined) {
|
|
return command_result{result};
|
|
}
|
|
}
|
|
|
|
groups::GroupCopyResult result;
|
|
switch(group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER:
|
|
result = group_manager->server_groups()->copy_group_permissions(source_group_id, target_group_id);
|
|
break;
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL:
|
|
result = group_manager->channel_groups()->copy_group_permissions(source_group_id, target_group_id);
|
|
break;
|
|
}
|
|
|
|
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};
|
|
|
|
case groups::GroupCopyResult::NAME_INVALID:
|
|
default:
|
|
return command_result{error::vs_critical};
|
|
}
|
|
|
|
log::GroupType log_group_type;
|
|
switch (target_group->group_type()) {
|
|
case groups::GroupType::GROUP_TYPE_QUERY:
|
|
log_group_type = log::GroupType::QUERY;
|
|
break;
|
|
|
|
case groups::GroupType::GROUP_TYPE_TEMPLATE:
|
|
log_group_type = log::GroupType::TEMPLATE;
|
|
break;
|
|
|
|
case groups::GroupType::GROUP_TYPE_NORMAL:
|
|
case groups::GroupType::GROUP_TYPE_UNKNOWN:
|
|
default:
|
|
log_group_type = log::GroupType::NORMAL;
|
|
break;
|
|
}
|
|
|
|
serverInstance->action_logger()->group_logger.log_group_permission_copy(target_group->group_type() != groups::GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId(),
|
|
this->ref(), log_group_target, log_group_type, target_group->group_id(), target_group->display_name(), source_group->group_id(), source_group->display_name());
|
|
|
|
global_update = !this->server || target_group_global;
|
|
} else {
|
|
//Copy to a new group
|
|
auto target_type = cmd["type"].as<groups::GroupType>();
|
|
|
|
log::GroupType log_group_type;
|
|
switch (target_type) {
|
|
case groups::GroupType::GROUP_TYPE_QUERY:
|
|
log_group_type = log::GroupType::QUERY;
|
|
break;
|
|
|
|
case groups::GroupType::GROUP_TYPE_TEMPLATE:
|
|
log_group_type = log::GroupType::TEMPLATE;
|
|
break;
|
|
|
|
case groups::GroupType::GROUP_TYPE_NORMAL:
|
|
log_group_type = log::GroupType::NORMAL;
|
|
break;
|
|
|
|
case groups::GroupType::GROUP_TYPE_UNKNOWN:
|
|
default:
|
|
return command_result{error::parameter_invalid, "type"};
|
|
}
|
|
|
|
{
|
|
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!"};
|
|
}
|
|
|
|
std::shared_ptr<groups::Group> created_group{};
|
|
std::string notify_name, notify_id_key;
|
|
groups::GroupCopyResult result;
|
|
|
|
switch(group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER: {
|
|
std::shared_ptr<groups::ServerGroup> s_group{};
|
|
result = group_manager->server_groups()->copy_group(source_group_id, target_type, cmd["name"].string(), s_group);
|
|
created_group = s_group;
|
|
|
|
notify_name = this->notify_response_command("notifyservergroupcopied");
|
|
notify_id_key = "sgid";
|
|
break;
|
|
}
|
|
case GroupTarget::GROUPTARGET_CHANNEL: {
|
|
std::shared_ptr<groups::ChannelGroup> c_group{};
|
|
result = group_manager->channel_groups()->copy_group(source_group_id, target_type, cmd["name"].string(), c_group);
|
|
created_group = c_group;
|
|
|
|
notify_name = this->notify_response_command("notifychannelgroupcopied");
|
|
notify_id_key = "cgid";
|
|
break;
|
|
}
|
|
default: {
|
|
result = groups::GroupCopyResult::DATABASE_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
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};
|
|
|
|
case groups::GroupCopyResult::NAME_INVALID:
|
|
return command_result{error::parameter_invalid, "name"};
|
|
|
|
default:
|
|
return command_result{error::vs_critical};
|
|
}
|
|
|
|
assert(!notify_name.empty());
|
|
assert(created_group);
|
|
serverInstance->action_logger()->group_logger.log_group_create(target_type != groups::GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId(),
|
|
this->ref(), log_group_target, log_group_type, created_group->group_id(), cmd["name"], source_group->group_id(), source_group->display_name());
|
|
|
|
{
|
|
ts::command_builder notify{notify_name};
|
|
notify.put_unchecked(0, notify_id_key, created_group->group_id());
|
|
this->sendCommand(notify);
|
|
}
|
|
|
|
global_update = !this->server;
|
|
}
|
|
|
|
std::deque<std::shared_ptr<VirtualServer>> server_updates{};
|
|
if(global_update) {
|
|
server_updates = serverInstance->getVoiceServerManager()->serverInstances();
|
|
} else {
|
|
server_updates.push_back(this->server);
|
|
}
|
|
|
|
for(const auto& server : server_updates) {
|
|
if(!server) {
|
|
continue;
|
|
}
|
|
|
|
switch(group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER:
|
|
server->enqueue_notify_server_group_list();
|
|
break;
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL:
|
|
server->enqueue_notify_channel_group_list();
|
|
break;
|
|
}
|
|
}
|
|
|
|
return command_result{error::ok};
|
|
}
|
|
|
|
command_result ConnectedClient::handleCommandGroupRename(Command &cmd, GroupTarget group_target) {
|
|
CMD_RESET_IDLE;
|
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
|
|
|
auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager();
|
|
|
|
log::GroupTarget log_group_target;
|
|
std::shared_ptr<groups::Group> group{};
|
|
GroupId group_id;
|
|
|
|
switch(group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER:
|
|
group_id = cmd["sgid"].as<GroupId>();
|
|
group = group_manager->server_groups()->find_group(groups::GroupCalculateMode::GLOBAL, group_id);
|
|
|
|
if(!group) {
|
|
return ts::command_result{error::group_invalid_id};
|
|
}
|
|
|
|
ACTION_REQUIRES_GROUP_PERMISSION(group, permission::i_server_group_needed_modify_power, permission::i_server_group_modify_power, true);
|
|
|
|
log_group_target = log::GroupTarget::SERVER;
|
|
break;
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL:
|
|
group_id = cmd["cgid"].as<GroupId>();
|
|
group = group_manager->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, group_id);
|
|
|
|
if(!group) {
|
|
return ts::command_result{error::group_invalid_id};
|
|
}
|
|
|
|
ACTION_REQUIRES_GROUP_PERMISSION(group, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true);
|
|
|
|
log_group_target = log::GroupTarget::CHANNEL;
|
|
break;
|
|
|
|
default:
|
|
return ts::command_result{error::vs_critical, "internal invalid group target"};
|
|
}
|
|
assert(group);
|
|
|
|
auto type = group->group_type();
|
|
log::GroupType log_group_type;
|
|
if (type == groups::GroupType::GROUP_TYPE_QUERY) {
|
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1);
|
|
log_group_type = log::GroupType::QUERY;
|
|
} else if (type == groups::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;
|
|
}
|
|
|
|
auto old_name = group->display_name();
|
|
groups::GroupRenameResult rename_result;
|
|
switch(group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER:
|
|
rename_result = group_manager->server_groups()->rename_group(group->group_id(), cmd["name"].string());
|
|
break;
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL:
|
|
rename_result = group_manager->channel_groups()->rename_group(group->group_id(), cmd["name"].string());
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
rename_result = groups::GroupRenameResult::DATABASE_ERROR;
|
|
break;
|
|
}
|
|
|
|
switch(rename_result) {
|
|
case groups::GroupRenameResult::SUCCESS:
|
|
break;
|
|
|
|
case groups::GroupRenameResult::INVALID_GROUP_ID:
|
|
return ts::command_result{error::vs_critical, "internal invalid group id"};
|
|
|
|
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_group_target, log_group_type, group->group_id(), group->display_name(), old_name);
|
|
std::deque<std::shared_ptr<VirtualServer>> server_updates{};
|
|
if(!this->server) {
|
|
server_updates = serverInstance->getVoiceServerManager()->serverInstances();
|
|
} else {
|
|
server_updates.push_back(this->server);
|
|
}
|
|
|
|
for(const auto& server : server_updates) {
|
|
if(!server) {
|
|
continue;
|
|
}
|
|
|
|
switch(group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER:
|
|
server->enqueue_notify_server_group_list();
|
|
break;
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL:
|
|
server->enqueue_notify_channel_group_list();
|
|
break;
|
|
}
|
|
}
|
|
|
|
return command_result{error::ok};
|
|
}
|
|
|
|
command_result ConnectedClient::handleCommandGroupDel(Command &cmd, GroupTarget group_target) {
|
|
CMD_RESET_IDLE;
|
|
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
|
|
|
auto ref_server = this->server;
|
|
auto group_manager = ref_server ? ref_server->group_manager() : serverInstance->group_manager();
|
|
|
|
log::GroupTarget log_group_target;
|
|
std::shared_ptr<groups::Group> group{};
|
|
GroupId group_id;
|
|
|
|
switch (group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER:
|
|
group_id = cmd["sgid"].as<GroupId>();
|
|
group = group_manager->server_groups()->find_group(groups::GroupCalculateMode::GLOBAL, group_id);
|
|
|
|
if(!group) {
|
|
return ts::command_result{error::group_invalid_id};
|
|
}
|
|
|
|
ACTION_REQUIRES_GROUP_PERMISSION(group, permission::i_server_group_needed_modify_power, permission::i_server_group_modify_power, true);
|
|
|
|
log_group_target = log::GroupTarget::SERVER;
|
|
break;
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL:
|
|
group_id = cmd["cgid"].as<GroupId>();
|
|
group = group_manager->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, group_id);
|
|
|
|
if(!group) {
|
|
return ts::command_result{error::group_invalid_id};
|
|
}
|
|
|
|
ACTION_REQUIRES_GROUP_PERMISSION(group, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true);
|
|
|
|
log_group_target = log::GroupTarget::CHANNEL;
|
|
break;
|
|
|
|
default:
|
|
return ts::command_result{error::vs_critical, "internal invalid group target"};
|
|
}
|
|
assert(group);
|
|
|
|
/* Test if the group is one of the default group */
|
|
switch (group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER:
|
|
if(this->server) {
|
|
if(this->server->properties()[property::VIRTUALSERVER_DEFAULT_SERVER_GROUP] == group->group_id()) {
|
|
return command_result{error::parameter_invalid, "Could not delete default server group!"};
|
|
}
|
|
}
|
|
|
|
if(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP] == group->group_id()) {
|
|
return command_result{error::parameter_invalid, "Could not delete instance default server admin group!"};
|
|
}
|
|
|
|
if(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP] == group->group_id()) {
|
|
return command_result{error::parameter_invalid, "Could not delete instance default server group!"};
|
|
}
|
|
|
|
if(serverInstance->properties()[property::SERVERINSTANCE_GUEST_SERVERQUERY_GROUP] == group->group_id()) {
|
|
return command_result{error::parameter_invalid, "Could not delete instance default guest server query group!"};
|
|
}
|
|
|
|
break;
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL:
|
|
if (this->server) {
|
|
if (this->server->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP] == group->group_id()) {
|
|
return command_result{error::parameter_invalid, "Could not delete default channel group!"};
|
|
}
|
|
if (this->server->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP] == group->group_id()) {
|
|
return command_result{error::parameter_invalid, "Could not delete default channel admin group!"};
|
|
}
|
|
}
|
|
|
|
if (serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP] == group->group_id()) {
|
|
return command_result{error::parameter_invalid, "Could not delete instance default channel group!"};
|
|
}
|
|
|
|
if(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP] == group->group_id()) {
|
|
return command_result{error::parameter_invalid, "Could not delete instance default channel admin group!"};
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
log::GroupType log_group_type;
|
|
switch (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:
|
|
switch(group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER:
|
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_delete, 1);
|
|
break;
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL:
|
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_delete, 1);
|
|
break;
|
|
}
|
|
|
|
log_group_type = log::GroupType::NORMAL;
|
|
break;
|
|
|
|
case groups::GroupType::GROUP_TYPE_UNKNOWN:
|
|
default:
|
|
return ts::command_result{error::vs_critical};
|
|
}
|
|
|
|
auto force_delete = cmd[0].has("force") ? cmd["force"].as<bool>() : false;
|
|
|
|
groups::GroupDeleteResult result;
|
|
switch (group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER:
|
|
if(!force_delete && !group_manager->assignments().is_server_group_empty(group->group_id())) {
|
|
result = groups::GroupDeleteResult::GROUP_NOT_EMPTY;
|
|
break;
|
|
}
|
|
|
|
result = group_manager->server_groups()->delete_group(group->group_id());
|
|
break;
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL:
|
|
if(!force_delete && !group_manager->assignments().is_channel_group_empty(group->group_id())) {
|
|
result = groups::GroupDeleteResult::GROUP_NOT_EMPTY;
|
|
break;
|
|
}
|
|
|
|
result = group_manager->channel_groups()->delete_group(group->group_id());
|
|
break;
|
|
}
|
|
|
|
switch(result) {
|
|
case groups::GroupDeleteResult::SUCCESS:
|
|
break;
|
|
|
|
case groups::GroupDeleteResult::GROUP_NOT_EMPTY:
|
|
return ts::command_result{error::group_not_empty};
|
|
|
|
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_group_target, log_group_type, group->group_id(), group->display_name());
|
|
|
|
std::deque<std::shared_ptr<VirtualServer>> server_updates{};
|
|
if(!this->server) {
|
|
server_updates = serverInstance->getVoiceServerManager()->serverInstances();
|
|
} else {
|
|
server_updates.push_back(this->server);
|
|
}
|
|
|
|
for(const auto& server : server_updates) {
|
|
if(!server) {
|
|
continue;
|
|
}
|
|
|
|
switch(group_target) {
|
|
case GroupTarget::GROUPTARGET_SERVER:
|
|
server->enqueue_notify_server_group_list();
|
|
server->group_manager()->assignments().handle_server_group_deleted(group->group_id());
|
|
server->tokenManager->handle_server_group_deleted(group->group_id());
|
|
break;
|
|
|
|
case GroupTarget::GROUPTARGET_CHANNEL:
|
|
server->enqueue_notify_channel_group_list();
|
|
server->group_manager()->assignments().handle_channel_group_deleted(group->group_id());
|
|
server->tokenManager->handle_channel_group_deleted(group->group_id());
|
|
break;
|
|
}
|
|
|
|
this->server->forEachClient([&](const std::shared_ptr<ConnectedClient>& client) {
|
|
bool groups_changed;
|
|
client->update_displayed_client_groups(groups_changed, groups_changed);
|
|
|
|
if(groups_changed) {
|
|
client->task_update_needed_permissions.enqueue();
|
|
client->task_update_channel_client_properties.enqueue();
|
|
}
|
|
});
|
|
}
|
|
|
|
return command_result{error::ok};
|
|
}
|
|
|
|
command_result ConnectedClient::executeGroupPermissionEdit(Command &cmd,
|
|
const std::vector<std::shared_ptr<groups::Group>> &groups,
|
|
const std::shared_ptr<VirtualServer> &target_server,
|
|
permission::v2::PermissionUpdateType mode) {
|
|
ts::command::bulk_parser::PermissionBulksParser pparser{cmd, mode == permission::v2::PermissionUpdateType::set_value};
|
|
if (!pparser.validate(this->ref(), 0)) {
|
|
return pparser.build_command_result();
|
|
}
|
|
|
|
bool update_channel_group_list{false}, update_server_group_list{false};
|
|
for(const auto& group : groups) {
|
|
bool* update_group_list;
|
|
log::PermissionTarget log_group_target;
|
|
|
|
if(dynamic_pointer_cast<groups::ServerGroup>(group)) {
|
|
update_group_list = &update_server_group_list;
|
|
log_group_target = log::PermissionTarget::SERVER_GROUP;
|
|
} else {
|
|
update_group_list = &update_channel_group_list;
|
|
log_group_target = log::PermissionTarget::CHANNEL_GROUP;
|
|
}
|
|
|
|
for (const auto &ppermission : pparser.iterate_valid_permissions()) {
|
|
ppermission.apply_to(group->permissions(), mode);
|
|
ppermission.log_update(serverInstance->action_logger()->permission_logger,
|
|
this->getServerId(),
|
|
this->ref(),
|
|
log_group_target,
|
|
mode,
|
|
0, "",
|
|
group->group_id(), group->display_name());
|
|
|
|
*update_group_list |= ppermission.is_group_property();
|
|
}
|
|
}
|
|
|
|
std::deque<std::shared_ptr<VirtualServer>> server_updates{};
|
|
if(target_server) {
|
|
server_updates.push_back(target_server);
|
|
} else {
|
|
server_updates = serverInstance->getVoiceServerManager()->serverInstances();
|
|
}
|
|
|
|
for(const auto& server : server_updates) {
|
|
if(!server) {
|
|
continue;
|
|
}
|
|
|
|
if(update_server_group_list) {
|
|
server->enqueue_notify_server_group_list();
|
|
}
|
|
|
|
if(update_channel_group_list) {
|
|
server->enqueue_notify_channel_group_list();
|
|
}
|
|
|
|
btree::set<ClientId> updated_clients{};
|
|
for(const auto& group : groups) {
|
|
if(auto s_group{dynamic_pointer_cast<groups::ServerGroup>(group)}; s_group) {
|
|
server->forEachClient([&](const std::shared_ptr<ConnectedClient> &client) {
|
|
if(updated_clients.count(client->getClientId()) > 0) {
|
|
return;
|
|
}
|
|
|
|
if(client->serverGroupAssigned(s_group)) {
|
|
updated_clients.emplace(client->getClientId());
|
|
client->task_update_channel_client_properties.enqueue();
|
|
client->task_update_needed_permissions.enqueue();
|
|
client->join_state_id++;
|
|
}
|
|
});
|
|
} else if(auto c_group{dynamic_pointer_cast<groups::ChannelGroup>(group)}; c_group) {
|
|
server->forEachClient([&](const std::shared_ptr<ConnectedClient> &client) {
|
|
if(updated_clients.count(client->getClientId()) > 0) {
|
|
return;
|
|
}
|
|
|
|
auto channel = client->getChannel();
|
|
if(client->channelGroupAssigned(c_group, channel)) {
|
|
updated_clients.emplace(client->getClientId());
|
|
client->task_update_channel_client_properties.enqueue();
|
|
client->task_update_needed_permissions.enqueue();
|
|
client->join_state_id++;
|
|
}
|
|
});
|
|
} else {
|
|
assert(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
return pparser.build_command_result();
|
|
}
|