#pragma once #include #include #include #include #include #include "./helpers.h" namespace ts::command::bulk_parser { template class PermissionBulkParser { public: explicit PermissionBulkParser(ts::ParameterBulk& bulk) { if(bulk.has("permid")) { auto type = bulk["permid"].as(); if ((type & PERM_ID_GRANT) != 0) { type &= ~PERM_ID_GRANT; } this->permission_ = permission::resolvePermissionData(type); } else if(bulk.has("permsid")) { auto permission_name = bulk["permsid"].string(); this->permission_ = permission::resolvePermissionData(permission_name); this->grant_ = this->permission_->grantName() == permission_name;; } else { this->error_.reset(ts::command_result{error::parameter_missing, "permid"}); return; } if(this->permission_->is_invalid()) { this->error_.reset(ts::command_result{error::parameter_invalid}); return; } if(kParseValue) { if(!bulk.has("permvalue")) { this->error_.reset(ts::command_result{error::parameter_missing, "permvalue"}); return; } this->value_ = bulk["permvalue"].as(); this->flag_skip_ = bulk.has("permskip") && bulk["permskip"].as(); this->flag_negated_ = bulk.has("permnegated") && bulk["permnegated"].as(); } } PermissionBulkParser(const PermissionBulkParser&) = delete; PermissionBulkParser(PermissionBulkParser&&) = default; ~PermissionBulkParser() { this->error_.release_data(); } [[nodiscard]] inline bool has_error() const { assert(!this->error_released_); return this->error_.has_error(); } [[nodiscard]] inline bool has_value() const { return this->value_ != permission::undefined; } [[nodiscard]] inline bool is_grant_permission() const { return this->grant_; } [[nodiscard]] inline const auto& permission() const { return this->permission_; } [[nodiscard]] inline auto permission_type() const { return this->permission_->type; } [[nodiscard]] inline auto value() const { return this->value_; } [[nodiscard]] inline auto flag_skip() const { return this->flag_skip_; } [[nodiscard]] inline auto flag_negated() const { return this->flag_negated_; } [[nodiscard]] inline ts::command_result release_error() { assert(!std::exchange(this->error_released_, true)); return std::move(this->error_); } inline void emplace_custom_error(ts::command_result&& result) { assert(!this->error_released_); this->error_.reset(std::forward(result)); } inline void apply_to(const std::shared_ptr& manager, permission::v2::PermissionUpdateType mode) const { if(this->is_grant_permission()) { manager->set_permission(this->permission_type(), { this->value(), true }, permission::v2::PermissionUpdateType::do_nothing, mode); } else { manager->set_permission( this->permission_type(), { this->value(), true }, mode, permission::v2::PermissionUpdateType::do_nothing ); } } inline void apply_to_channel(const std::shared_ptr& manager, permission::v2::PermissionUpdateType mode, ChannelId channel_id) const { if(this->is_grant_permission()) { manager->set_channel_permission(this->permission_type(), channel_id, { this->value(), true }, permission::v2::PermissionUpdateType::do_nothing, mode); } else { manager->set_channel_permission( this->permission_type(), channel_id, { this->value(), true }, mode, permission::v2::PermissionUpdateType::do_nothing ); } } [[nodiscard]] inline bool is_group_property() const { return permission_is_group_property(this->permission_type()); } [[nodiscard]] inline bool is_client_view_property() const { return permission_is_client_property(this->permission_type()); } private: std::shared_ptr permission_{nullptr}; bool grant_{false}; bool flag_skip_{false}; bool flag_negated_{false}; permission::PermissionValue value_{0}; ts::command_result error_{error::ok}; #ifndef NDEBUG bool error_released_{false}; #endif }; template class PermissionBulksParser { public: PermissionBulksParser(const PermissionBulksParser&) = delete; PermissionBulksParser(PermissionBulksParser&&) = default; template struct FilteredPermissionIterator : public base_iterator { public: FilteredPermissionIterator() = default; explicit FilteredPermissionIterator(base_iterator position, base_iterator end = {}) : base_iterator{position}, end_{end} { if(*this != this->end_) { const auto& entry = **this; if(entry.has_error()) this->operator++(); } } FilteredPermissionIterator& operator++() { while(true) { base_iterator::operator++(); if(*this == this->end_) break; const auto& entry = **this; if(!entry.has_error()) break; } return *this; } [[nodiscard]] FilteredPermissionIterator operator++(int) const { FilteredPermissionIterator copy = *this; ++*this; return copy; } private: base_iterator end_; }; struct FilteredPermissionListIterable { typedef typename std::vector>::const_iterator const_iterator; public: FilteredPermissionListIterable(const_iterator begin, const_iterator end) noexcept : begin_{begin}, end_{end} {} FilteredPermissionIterator begin() const { return FilteredPermissionIterator{this->begin_, this->end_}; } FilteredPermissionIterator end() const { return FilteredPermissionIterator{this->end_, this->end_}; } private: const_iterator begin_; const_iterator end_; }; explicit PermissionBulksParser(ts::Command& command) { this->permissions_.reserve(command.bulkCount()); for(size_t index{0}; index < command.bulkCount(); index++) this->permissions_.emplace_back(command[index]); } [[nodiscard]] inline bool validate(const std::shared_ptr& issuer, ChannelId channel_id) { auto ignore_granted_values = permission::v2::permission_granted(1, issuer->calculate_permission(permission::b_permission_modify_power_ignore, channel_id)); if(!ignore_granted_values) { auto max_value = issuer->calculate_permission(permission::i_permission_modify_power, channel_id, false); if(!max_value.has_value) { for(PermissionBulkParser& permission : this->permissions_) { if(permission.has_error()) continue; permission.emplace_custom_error(ts::command_result{permission::i_permission_modify_power}); } return false; } for(size_t index{0}; index < this->permissions_.size(); index++) { PermissionBulkParser& permission = this->permissions_[index]; if(permission.has_error()) continue; if(kParseValue && permission_require_granted_value(permission.permission_type()) && !permission::v2::permission_granted(permission.value(), max_value)) { permission.emplace_custom_error(ts::command_result{permission::i_permission_modify_power}); continue; } if(!permission::v2::permission_granted(1, issuer->calculate_permission(permission.permission_type(), channel_id, true))) { permission.emplace_custom_error(ts::command_result{permission::i_permission_modify_power}); continue; } } } return true; } [[nodiscard]] inline FilteredPermissionListIterable iterate_valid_permissions() const { return FilteredPermissionListIterable{this->permissions_.begin(), this->permissions_.end()}; } [[nodiscard]] inline ts::command_result build_command_result() { assert(!std::exchange(this->result_created_, true)); ts::command_result_bulk result{}; for(auto& permission : this->permissions_) result.insert_result(std::forward(permission.release_error())); return ts::command_result{std::move(result)}; } private: std::vector> permissions_{}; #ifndef NDEBUG bool result_created_{false}; #endif }; }