331 lines
14 KiB
C++
331 lines
14 KiB
C++
#pragma once
|
|
|
|
#include <mutex>
|
|
#include <deque>
|
|
#include <string>
|
|
#include <memory>
|
|
#include <Definitions.h>
|
|
#include <sql/SqlQuery.h>
|
|
#include "./GroupAssignmentManager.h"
|
|
#include "./Group.h"
|
|
|
|
namespace ts::server::groups {
|
|
enum struct GroupCalculateMode {
|
|
LOCAL, /* only calculate clients groups for the local server */
|
|
GLOBAL /* use the parent group manager as well, if existing */
|
|
};
|
|
|
|
enum struct GroupLoadResult {
|
|
SUCCESS,
|
|
NO_GROUPS,
|
|
DATABASE_ERROR
|
|
};
|
|
|
|
enum struct GroupCreateResult {
|
|
SUCCESS,
|
|
NAME_ALREADY_IN_USED,
|
|
NAME_TOO_SHORT,
|
|
NAME_TOO_LONG,
|
|
DATABASE_ERROR
|
|
};
|
|
|
|
enum struct GroupCopyResult {
|
|
SUCCESS,
|
|
UNKNOWN_SOURCE_GROUP,
|
|
UNKNOWN_TARGET_GROUP,
|
|
NAME_ALREADY_IN_USE,
|
|
NAME_INVALID,
|
|
DATABASE_ERROR
|
|
};
|
|
|
|
enum struct GroupRenameResult {
|
|
SUCCESS,
|
|
INVALID_GROUP_ID,
|
|
NAME_ALREADY_USED,
|
|
NAME_INVALID,
|
|
DATABASE_ERROR
|
|
};
|
|
|
|
enum struct GroupDeleteResult {
|
|
SUCCESS,
|
|
INVALID_GROUP_ID,
|
|
/* Artificial result, not used by the delete method but needed */
|
|
GROUP_NOT_EMPTY,
|
|
DATABASE_ERROR
|
|
};
|
|
|
|
class GroupManager;
|
|
class AbstractGroupManager : public std::enable_shared_from_this<AbstractGroupManager> {
|
|
friend class Group;
|
|
friend class GroupAssignmentManager;
|
|
public:
|
|
enum struct DatabaseGroupTarget : uint8_t {
|
|
SERVER = 0x00,
|
|
CHANNEL = 0x01
|
|
};
|
|
|
|
AbstractGroupManager(
|
|
sql::SqlManager* /* database */,
|
|
DatabaseGroupTarget /* database group target */,
|
|
ServerId /* virtual server id */,
|
|
std::shared_ptr<AbstractGroupManager> /* parent */
|
|
);
|
|
|
|
virtual ~AbstractGroupManager() = default;
|
|
|
|
bool initialize(std::string& /* error */);
|
|
GroupLoadResult load_data(bool /* initialize */ = false);
|
|
void unload_data();
|
|
|
|
void save_permissions(size_t& /* total groups */, size_t& /* saved groups */);
|
|
|
|
/**
|
|
* Reset all known groups and copy the template groups from our group parent (if it isn't null)
|
|
*/
|
|
void reset_groups(std::map<GroupId, GroupId>& /* mapping */);
|
|
protected:
|
|
std::shared_ptr<AbstractGroupManager> parent_manager_;
|
|
DatabaseGroupTarget database_target_;
|
|
|
|
sql::SqlManager* database_;
|
|
ServerId virtual_server_id_;
|
|
|
|
/* recursive_mutex due to the copy group methods */
|
|
std::recursive_mutex group_manage_mutex_{};
|
|
std::mutex group_mutex_{};
|
|
|
|
/* I think std::vector is better here because we will iterate more often than add groups */
|
|
std::vector<std::shared_ptr<Group>> groups_{};
|
|
|
|
[[nodiscard]] sql::SqlManager* sql_manager();
|
|
[[nodiscard]] ServerId server_id();
|
|
|
|
[[nodiscard]] std::shared_ptr<Group> find_group_(std::shared_ptr<AbstractGroupManager>& /* owning manager */, GroupCalculateMode /* mode */, GroupId /* group id */);
|
|
[[nodiscard]] std::shared_ptr<Group> find_group_by_name_(GroupCalculateMode /* mode */, const std::string& /* group name */);
|
|
[[nodiscard]] GroupCreateResult create_group_(GroupType type, const std::string& /* group name */, std::shared_ptr<Group>& /* result */);
|
|
[[nodiscard]] GroupCopyResult copy_group_(GroupId /* group id */, GroupType /* target group type */, const std::string& /* target group name */, std::shared_ptr<Group>& /* result */);
|
|
[[nodiscard]] GroupCopyResult copy_group_permissions_(GroupId /* group id */, GroupId /* target group */);
|
|
[[nodiscard]] GroupRenameResult rename_group_(GroupId /* group id */, const std::string& /* target group name */);
|
|
[[nodiscard]] GroupDeleteResult delete_group_(GroupId /* group id */);
|
|
|
|
int insert_group_from_sql(int /* length */, std::string* /* values */, std::string* /* columns */);
|
|
|
|
virtual std::shared_ptr<Group> allocate_group(
|
|
GroupId /* id */,
|
|
GroupType /* type */,
|
|
std::string /* name */,
|
|
std::shared_ptr<permission::v2::PermissionManager> /* permissions */
|
|
) = 0;
|
|
};
|
|
|
|
class ServerGroupManager : public AbstractGroupManager {
|
|
public:
|
|
ServerGroupManager(const std::shared_ptr<GroupManager>& /* owner */, std::shared_ptr<ServerGroupManager> /* parent */);
|
|
|
|
[[nodiscard]] inline std::vector<std::shared_ptr<ServerGroup>> available_groups(GroupCalculateMode mode) {
|
|
std::vector<std::shared_ptr<ServerGroup>> result{};
|
|
if(auto manager{std::dynamic_pointer_cast<ServerGroupManager>(this->parent_manager_)}; manager && mode != GroupCalculateMode::LOCAL) {
|
|
auto result_ = manager->available_groups(mode);
|
|
result.reserve(result_.size());
|
|
result.insert(result.end(), result_.begin(), result_.end());
|
|
}
|
|
|
|
{
|
|
std::lock_guard group_lock{this->group_mutex_};
|
|
result.reserve(this->groups_.size());
|
|
for(const auto& group : this->groups_) {
|
|
result.push_back(this->cast_result(group));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
[[nodiscard]] inline std::shared_ptr<ServerGroup> find_group(GroupCalculateMode mode, GroupId group_id) {
|
|
std::shared_ptr<AbstractGroupManager> owning_manager{};
|
|
return this->cast_result(this->find_group_(owning_manager, mode, group_id));
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param owning_manager
|
|
* @param mode
|
|
* @param group_id
|
|
* @return the group if found. `owning_manager` will be set to the owning manager.
|
|
*/
|
|
[[nodiscard]] inline std::shared_ptr<ServerGroup> find_group_ext(std::shared_ptr<ServerGroupManager>& owning_manager, GroupCalculateMode mode, GroupId group_id) {
|
|
std::shared_ptr<AbstractGroupManager> owning_manager_;
|
|
auto result = this->cast_result(this->find_group_(owning_manager_, mode, group_id));
|
|
if(owning_manager_) {
|
|
owning_manager = std::dynamic_pointer_cast<ServerGroupManager>(owning_manager_);
|
|
assert(owning_manager);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
[[nodiscard]] inline std::shared_ptr<ServerGroup> find_group_by_name(GroupCalculateMode mode, const std::string& group_name) {
|
|
return this->cast_result(this->find_group_by_name_(mode, group_name));
|
|
}
|
|
|
|
[[nodiscard]] inline GroupCreateResult create_group(GroupType type, const std::string& group_name, std::shared_ptr<ServerGroup>& result) {
|
|
std::shared_ptr<Group> result_;
|
|
auto r = this->create_group_(type, group_name, result_);
|
|
result = this->cast_result(result_);
|
|
return r;
|
|
}
|
|
|
|
[[nodiscard]] inline GroupCopyResult copy_group(GroupId group_id, GroupType target_group_type, const std::string& target_group_name, std::shared_ptr<ServerGroup>& result) {
|
|
std::shared_ptr<Group> result_;
|
|
auto r = this->copy_group_(group_id, target_group_type, target_group_name, result_);
|
|
result = this->cast_result(result_);
|
|
return r;
|
|
}
|
|
|
|
[[nodiscard]] inline GroupCopyResult copy_group_permissions(GroupId group_id, GroupId target_group) {
|
|
return this->copy_group_permissions_(group_id, target_group);
|
|
}
|
|
|
|
[[nodiscard]] inline GroupRenameResult rename_group(GroupId group_id, const std::string& target_group_name) {
|
|
return this->rename_group_(group_id, target_group_name);
|
|
}
|
|
|
|
[[nodiscard]] inline GroupDeleteResult delete_group(GroupId group_id) {
|
|
return this->delete_group_(group_id);
|
|
}
|
|
|
|
protected:
|
|
[[nodiscard]] std::shared_ptr<Group> allocate_group(GroupId, GroupType, std::string,
|
|
std::shared_ptr<permission::v2::PermissionManager>) override;
|
|
|
|
[[nodiscard]] inline std::shared_ptr<ServerGroup> cast_result(std::shared_ptr<Group> result) {
|
|
if(!result) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto casted = std::dynamic_pointer_cast<ServerGroup>(result);
|
|
assert(casted);
|
|
return casted;
|
|
}
|
|
};
|
|
|
|
class ChannelGroupManager : public AbstractGroupManager {
|
|
public:
|
|
ChannelGroupManager(const std::shared_ptr<GroupManager>& /* owner */, std::shared_ptr<ChannelGroupManager> /* parent */);
|
|
|
|
[[nodiscard]] inline std::vector<std::shared_ptr<ChannelGroup>> available_groups(GroupCalculateMode mode) {
|
|
std::vector<std::shared_ptr<ChannelGroup>> result{};
|
|
if(auto manager{std::dynamic_pointer_cast<ChannelGroupManager>(this->parent_manager_)}; manager && mode != GroupCalculateMode::LOCAL) {
|
|
auto result_ = manager->available_groups(mode);
|
|
result.reserve(result_.size());
|
|
result.insert(result.end(), result_.begin(), result_.end());
|
|
}
|
|
|
|
{
|
|
std::lock_guard group_lock{this->group_mutex_};
|
|
result.reserve(this->groups_.size());
|
|
for(const auto& group : this->groups_) {
|
|
result.push_back(this->cast_result(group));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
[[nodiscard]] inline std::shared_ptr<ChannelGroup> find_group(GroupCalculateMode mode, GroupId group_id) {
|
|
std::shared_ptr<AbstractGroupManager> owning_manager{};
|
|
return this->cast_result(this->find_group_(owning_manager, mode, group_id));
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param owning_manager
|
|
* @param mode
|
|
* @param group_id
|
|
* @return the group if found. `owning_manager` will be set to the owning manager.
|
|
*/
|
|
[[nodiscard]] inline std::shared_ptr<ChannelGroup> find_group_ext(std::shared_ptr<ChannelGroupManager>& owning_manager, GroupCalculateMode mode, GroupId group_id) {
|
|
std::shared_ptr<AbstractGroupManager> owning_manager_;
|
|
auto result = this->cast_result(this->find_group_(owning_manager_, mode, group_id));
|
|
if(owning_manager_) {
|
|
owning_manager = std::dynamic_pointer_cast<ChannelGroupManager>(owning_manager_);
|
|
assert(owning_manager);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
[[nodiscard]] inline std::shared_ptr<ChannelGroup> find_group_by_name(GroupCalculateMode mode, const std::string& group_name) {
|
|
return this->cast_result(this->find_group_by_name_(mode, group_name));
|
|
}
|
|
|
|
[[nodiscard]] inline GroupCreateResult create_group(GroupType type, const std::string& group_name, std::shared_ptr<ChannelGroup>& result) {
|
|
std::shared_ptr<Group> result_;
|
|
auto r = this->create_group_(type, group_name, result_);
|
|
result = this->cast_result(result_);
|
|
return r;
|
|
}
|
|
|
|
[[nodiscard]] inline GroupCopyResult copy_group(GroupId group_id, GroupType target_group_type, const std::string& target_group_name, std::shared_ptr<ChannelGroup>& result) {
|
|
std::shared_ptr<Group> result_;
|
|
auto r = this->copy_group_(group_id, target_group_type, target_group_name, result_);
|
|
result = this->cast_result(result_);
|
|
return r;
|
|
}
|
|
|
|
[[nodiscard]] inline GroupCopyResult copy_group_permissions(GroupId group_id, GroupId target_group) {
|
|
return this->copy_group_permissions_(group_id, target_group);
|
|
}
|
|
|
|
[[nodiscard]] inline GroupRenameResult rename_group(GroupId group_id, const std::string& target_group_name) {
|
|
return this->rename_group_(group_id, target_group_name);
|
|
}
|
|
|
|
[[nodiscard]] inline GroupDeleteResult delete_group(GroupId group_id) {
|
|
return this->delete_group_(group_id);
|
|
}
|
|
private:
|
|
std::shared_ptr<Group> allocate_group(GroupId, GroupType, std::string,
|
|
std::shared_ptr<permission::v2::PermissionManager>) override;
|
|
|
|
[[nodiscard]] inline std::shared_ptr<ChannelGroup> cast_result(std::shared_ptr<Group> result) {
|
|
if(!result) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto casted = std::dynamic_pointer_cast<ChannelGroup>(result);
|
|
assert(casted);
|
|
return casted;
|
|
}
|
|
};
|
|
|
|
class GroupManager {
|
|
friend class Group;
|
|
friend class ServerGroupManager;
|
|
friend class ChannelGroupManager;
|
|
friend class GroupAssignmentManager;
|
|
public:
|
|
GroupManager(sql::SqlManager* /* database */, ServerId /* virtual server id */, std::shared_ptr<GroupManager> /* parent */);
|
|
~GroupManager();
|
|
|
|
bool initialize(const std::shared_ptr<GroupManager>& /* self ref, */, std::string& /* error */);
|
|
|
|
[[nodiscard]] inline const std::shared_ptr<GroupManager>& parent_manager() { return this->parent_manager_; }
|
|
void save_permissions();
|
|
|
|
[[nodiscard]] inline GroupAssignmentManager& assignments() { return this->assignment_manager_; }
|
|
[[nodiscard]] inline const std::shared_ptr<ServerGroupManager>& server_groups() { return this->server_groups_; }
|
|
[[nodiscard]] inline const std::shared_ptr<ChannelGroupManager>& channel_groups() { return this->channel_groups_; }
|
|
private:
|
|
sql::SqlManager* database_;
|
|
ServerId virtual_server_id_;
|
|
|
|
std::shared_ptr<GroupManager> parent_manager_;
|
|
|
|
std::shared_ptr<ServerGroupManager> server_groups_{};
|
|
std::shared_ptr<ChannelGroupManager> channel_groups_{};
|
|
|
|
GroupAssignmentManager assignment_manager_;
|
|
|
|
[[nodiscard]] sql::SqlManager* sql_manager();
|
|
[[nodiscard]] ServerId server_id();
|
|
};
|
|
} |