/** * @file Role.hpp * @author LiteLDev (https://github.com/LiteLDev) * @brief Role type for PermissionAPI * * @copyright Copyright (c) 2021-present LiteLoaderBDS developers and all contributors * */ #pragma once #include "Member.hpp" #include "Permission.hpp" namespace PERM { /** * @brief Role instance. * */ class Role { protected: Members members; ///< Members of the role. Permissions permissions; ///< Permissions of the role. public: /** * @brief The type of role. * */ enum class Type : char { None = 0, General = 1, Everyone = 2, Admin = 3, //Custom = 4, }; std::string name; ///< Name of the role. std::string displayName; ///< Display name of the role. int priority = 0; ///< Priority of the role. static constexpr std::string_view roleNameInvalidChars = "@#[]{}<>()/|\\$%^&*!~`\"\'+=?\n\t\r\f\v "; ///< Invalid characters for the role name. /** * @brief Destructor. * */ virtual ~Role() {}; /** * @brief Check whether the role has the permission. * * @param name The permission name to check. * @return bool True if the role has the permission, false otherwise. */ virtual bool hasPermission(const std::string& name) const { return this->permissions.contains(name) && this->permissions.at(name).enabled; } /** * @brief Set the permission of the role. * * @param name The name of the permission to set. * @param enabled Whether the permission is enabled. * @param extra Extra data for the permission. */ virtual void setPermission(const std::string& name, bool enabled = true, const nlohmann::json& extra = nlohmann::json()); /** * @brief Remove the permission of the role. * * @param name The name of the permission to remove. */ virtual void removePermission(const std::string& name) { this->permissions.remove(name); } /** * @brief Check whether the permission exists in the role. * * @param name The name of the permission to check. * @return bool True if the permission exists in the role, false otherwise. */ virtual bool permissionExists(const std::string& name) { return this->permissions.contains(name); } /** * @brief Check whether the role has the member. * * @param xuid The xuid of the member(player) to check. * @return bool True if the role has the member, false otherwise. */ virtual bool hasMember(const xuid_t& xuid) const = 0; /** * @brief Add the member to the role. * * @param xuid The xuid of the member(player) to add. */ virtual void addMember(const xuid_t& xuid) = 0; /** * @brief Remove the member from the role. * * @param xuid The xuid of the member(player) to remove. */ virtual void removeMember(const xuid_t& xuid) = 0; /** * @brief Get the permissions of the role(non-const). * * @return Permissions& The permissions of the role. */ virtual Permissions& getPermissions() { return this->permissions; } /** * @brief Get the permissions of the role(const). * * @return const Permissions& The permissions of the role. */ virtual const Permissions& getPermissions() const { return this->permissions; } /** * @brief Get the members of the role(non-const). * * @return Members& The members of the role. */ virtual Members& getMembers() { return this->members; } /** * @brief Get the members of the role(const). * * @return const Members& The members of the role. */ virtual const Members& getMembers() const { return this->members; } /** * @brief Get the type of the role. * * @return Type The type of the role. */ virtual Type getType() const = 0; /** * @brief Validate the role data * * @return bool True if changed, false otherwise. */ virtual bool validate() { if (this->name.find_first_of(Role::roleNameInvalidChars.data()) != std::string::npos) { for (auto& ch : this->name) { if (Role::roleNameInvalidChars.find(ch) != std::string::npos) { ch = '-'; } } return true; } return false; } /** * @brief Check whether the role name is valid. * * @param name The name to check. * @return bool True if the role name is valid, false otherwise. */ static bool isValidRoleName(const std::string& name) { return name.find_first_of(Role::roleNameInvalidChars.data()) == std::string::npos; } }; /** * @brief General role type. * */ class GeneralRole : public Role { using Base = Role; public: GeneralRole() = default; GeneralRole(const GeneralRole& other) = default; GeneralRole(GeneralRole&& other) = default; ~GeneralRole() = default; GeneralRole& operator=(const GeneralRole& other) = default; GeneralRole& operator=(GeneralRole&& other) = default; virtual bool hasMember(const xuid_t& xuid) const { return this->members.contains(xuid); } virtual void addMember(const xuid_t& xuid) { this->members.push_back(xuid); } virtual void removeMember(const xuid_t& xuid) { this->members.erase(std::remove(this->members.begin(), this->members.end(), xuid), this->members.end()); } virtual Type getType() const { return Type::General; } }; /** * @brief Everyone role type. * */ class EveryoneRole : public Role { using Base = Role; public: EveryoneRole() = default; EveryoneRole(const EveryoneRole& other) = default; EveryoneRole(EveryoneRole&& other) = default; ~EveryoneRole() = default; EveryoneRole& operator=(const EveryoneRole& other) = default; EveryoneRole& operator=(EveryoneRole&& other) = default; virtual bool hasMember(const xuid_t& xuid) const { return true; } virtual void addMember(const xuid_t& xuid) { throw std::runtime_error("You cannot add a member to a everyone permission role"); } virtual void removeMember(const xuid_t& xuid) { throw std::runtime_error("You cannot remove a member from a everyone permission role"); } virtual Type getType() const { return Type::Everyone; } }; /** * @brief Admin role type. * */ class AdminRole : public Role { using Base = Role; public: AdminRole() = default; AdminRole(const AdminRole& other) = default; AdminRole(AdminRole&& other) = default; ~AdminRole() = default; AdminRole& operator=(const AdminRole& other) = default; AdminRole& operator=(AdminRole&& other) = default; virtual bool hasPermission(const std::string& name) const { if (!this->permissions.contains(name)) { return true; } else { return this->permissions.at(name).enabled; } } virtual bool hasMember(const xuid_t& xuid) const { return this->members.contains(xuid); } virtual void addMember(const xuid_t& xuid) { this->members.push_back(xuid); } virtual void removeMember(const xuid_t& xuid) { this->members.erase(std::remove(this->members.begin(), this->members.end(), xuid), this->members.end()); } virtual Type getType() const { return Type::Admin; } }; /** * @brief Container to hold roles. * */ class Roles : public PermPtrContainer { using Base = PermPtrContainer; public: Roles() : Base() { } Roles(const Base& base) : Base(base) { } Roles(Base&& base) : Base(base) { } Roles(const Roles& other) = default; Roles(Roles&& other) = default; /** * @brief Sort the roles by priority. * * @param greater Greater or less. * @return Roles The sorted roles. */ Roles sortByPriority(bool greater = false) const { Roles result; for (auto& role : *this) { result.push_back(role); } std::sort(result.begin(), result.end(), [greater](const std::shared_ptr& a, const std::shared_ptr& b) { return greater ? a->priority > b->priority : a->priority < b->priority; }); return result; } std::shared_ptr& operator[](const std::string& name) { Role* ptr = nullptr; if (name == "everyone") ptr = new EveryoneRole; else if (name == "admin") ptr = new AdminRole; else ptr = new GeneralRole; auto def = std::shared_ptr(ptr); def->name = name; return this->getOrCreate(name, def); } Roles& operator=(const Roles& other) = default; Roles& operator=(Roles&& other) = default; Roles& operator=(const Base& other) { return (Roles&)((Base&)*this) = other; } }; } // namespace PERM