diff --git a/include/dpp/channel.h b/include/dpp/channel.h index 59080ee0df..6b97b9e23a 100644 --- a/include/dpp/channel.h +++ b/include/dpp/channel.h @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -243,38 +242,6 @@ struct DPP_EXPORT permission_overwrite { permission_overwrite(snowflake id, uint64_t allow, uint64_t deny, overwrite_type type); }; - -/** - * @brief metadata for threads - */ -struct DPP_EXPORT thread_metadata { - /** - * @brief Timestamp when the thread's archive status was last changed, used for calculating recent activity. - */ - time_t archive_timestamp; - - /** - * @brief The duration in minutes to automatically archive the thread after recent activity (60, 1440, 4320, 10080). - */ - uint16_t auto_archive_duration; - - /** - * @brief Whether a thread is archived - */ - bool archived; - - /** - * @brief Whether a thread is locked. When a thread is locked, - * only users with `MANAGE_THREADS` can un-archive it. - */ - bool locked; - - /** - * @brief Whether non-moderators can add other non-moderators. Only for private threads. - */ - bool invitable; -}; - /** * @brief Auto archive duration of threads which will stop showing in the channel list after the specified period of inactivity. * Defined as an enum to fit into 1 byte. Internally it'll be translated to minutes to match the API @@ -301,42 +268,6 @@ enum auto_archive_duration_t : uint8_t { arc_1_week = 4, }; -/** - * @brief represents membership of a user with a thread - */ -struct DPP_EXPORT thread_member : public json_interface { -protected: - friend struct json_interface; - - /** - * @brief Read struct values from a json object - * @param j json to read values from - * @return A reference to self - */ - thread_member& fill_from_json_impl(nlohmann::json* j); - -public: - /** - * @brief ID of the thread member is part of. - */ - snowflake thread_id; - - /** - * @brief ID of the member. - */ - snowflake user_id; - - /** - * @brief The time when user last joined the thread. - */ - time_t joined; - - /** - * @brief Any user-thread settings, currently only used for notifications. - */ - uint32_t flags; -}; - /** * @brief Represents a tag that is able to be applied to a thread in a forum or media channel */ @@ -401,11 +332,6 @@ struct DPP_EXPORT forum_tag : public managed, public json_interface { forum_tag& set_name(const std::string& name); }; -/** - * @brief A group of thread member objects. the key is the user_id of the dpp::thread_member - */ -typedef std::unordered_map thread_member_map; - /** * @brief A definition of a discord channel. * There are one of these for every channel type except threads. Threads are @@ -429,6 +355,8 @@ class DPP_EXPORT channel : public managed, public json_interface { */ virtual json to_json_impl(bool with_id = false) const; + static constexpr uint16_t CHANNEL_TYPE_MASK = 0b0000000000001111; + public: /** * @brief Channel name (1-100 characters). @@ -937,111 +865,6 @@ class DPP_EXPORT channel : public managed, public json_interface { }; -/** @brief A definition of a discord thread. - * A thread is a superset of a channel. Not to be confused with `std::thread`! - */ -class DPP_EXPORT thread : public channel, public json_interface { -protected: - friend struct json_interface; - - /** Read class values from json object - * @param j A json object to read from - * @return A reference to self - */ - thread& fill_from_json_impl(nlohmann::json* j); - - /** - * @brief Build json for this thread object - * - * @param with_id include the ID in the json - * @return std::string JSON string - */ - json to_json_impl(bool with_id = false) const override; - -public: - using json_interface::fill_from_json; - using json_interface::build_json; - using json_interface::to_json; - - /** - * @brief Thread member of current user if joined to the thread. - * Note this is only set by certain api calls otherwise contains default data - */ - thread_member member; - - /** - * @brief Thread metadata (threads) - */ - thread_metadata metadata; - - /** - * @brief Created message. Only filled within the cluster::thread_create_in_forum() method - */ - message msg; - - /** - * @brief A list of dpp::forum_tag IDs that have been applied to a thread in a forum or media channel. - */ - std::vector applied_tags; - - /** - * @brief Number of messages ever sent in the thread. - * It's similar to thread::message_count on message creation, but will not decrement the number when a message is deleted - */ - uint32_t total_messages_sent; - - /** - * @brief Number of messages (not including the initial message or deleted messages) of the thread. - * For threads created before July 1, 2022, the message count is inaccurate when it's greater than 50. - */ - uint8_t message_count; - - /** - * @brief Approximate count of members in a thread (stops counting at 50) - */ - uint8_t member_count; - - /** - * @brief Construct a new thread object - */ - thread(); - - /** - * @brief Returns true if the thread is within an announcement channel - * - * @return true if announcement thread - */ - bool is_news_thread() const; - - /** - * @brief Returns true if the channel is a public thread - * - * @return true if public thread - */ - bool is_public_thread() const; - - /** - * @brief Returns true if the channel is a private thread - * - * @return true if private thread - */ - bool is_private_thread() const; - - /** - * @brief Destroy the thread object - */ - virtual ~thread() = default; -}; - - -/** - * @brief Serialize a thread_metadata object to json - * - * @param j JSON object to serialize to - * @param tmdata object to serialize - */ -void to_json(nlohmann::json& j, const thread_metadata& tmdata); - /** * @brief Serialize a permission_overwrite object to json * @@ -1055,30 +878,5 @@ void to_json(nlohmann::json& j, const permission_overwrite& po); */ typedef std::unordered_map channel_map; -/** - * @brief A group of threads - */ -typedef std::unordered_map thread_map; - -/** - * @brief A thread alongside the bot's optional thread_member object tied to it - */ -struct active_thread_info { - /** - * @brief The thread object - */ - thread active_thread; - - /** - * @brief The bot as a thread member, only present if the bot is in the thread - */ - std::optional bot_member; -}; - -/** - * @brief A map of threads alongside optionally the thread_member tied to the bot if it is in the thread. The map's key is the thread id. Returned from the cluster::threads_get_active method - */ -using active_threads = std::map; - } // namespace dpp diff --git a/include/dpp/dispatcher.h b/include/dpp/dispatcher.h index 4c41ab69ae..18d07b807d 100644 --- a/include/dpp/dispatcher.h +++ b/include/dpp/dispatcher.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/include/dpp/dpp.h b/include/dpp/dpp.h index cade039ee4..9e60093b47 100644 --- a/include/dpp/dpp.h +++ b/include/dpp/dpp.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include diff --git a/include/dpp/message.h b/include/dpp/message.h index ac9ca0716f..f2b1d1b7e6 100644 --- a/include/dpp/message.h +++ b/include/dpp/message.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -622,11 +623,11 @@ class DPP_EXPORT component : public json_interface { component& add_component(const component& c); /** - * @brief Add a default value. - * - * @param id Default value. ID of a user, role, or channel - * @param type The type this default value represents - */ + * @brief Add a default value. + * + * @param id Default value. ID of a user, role, or channel + * @param type The type this default value represents + */ component& add_default_value(const snowflake id, const component_default_value_type type); /** @@ -1979,6 +1980,18 @@ struct DPP_EXPORT message : public managed, json_interface { */ message(); + /* + * @brief Construct a new message object + * @param m Message to copy + */ + message(const message& m) = default; + + /* + * @brief Construct a new message object + * @param m Message to move + */ + message(message&& m) = default; + /** * @brief Construct a new message object * @param o Owning cluster, passed down to various things such as dpp::attachment. @@ -1987,11 +2000,6 @@ struct DPP_EXPORT message : public managed, json_interface { */ message(class cluster* o); - /** - * @brief Destroy the message object - */ - virtual ~message(); - /** * @brief Construct a new message object with a channel and content * @@ -2017,6 +2025,27 @@ struct DPP_EXPORT message : public managed, json_interface { */ message(const std::string &content, message_type type = mt_default); + /** + * @brief Destroy the message object + */ + ~message() override = default; + + /** + * @brief Copy a message object + * + * @param m Message to copy + * @return message& Reference to self + */ + message &operator=(const message& m) = default; + + /** + * @brief Move a message object + * + * @param m Message to move + * @return message& Reference to self + */ + message &operator=(message&& m) = default; + /** * @brief Set the original message reference for replies/crossposts * diff --git a/include/dpp/thread.h b/include/dpp/thread.h new file mode 100644 index 0000000000..2dee940be0 --- /dev/null +++ b/include/dpp/thread.h @@ -0,0 +1,230 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#pragma once +#include +#include +#include +#include +#include + +namespace dpp { + +/** + * @brief represents membership of a user with a thread + */ +struct DPP_EXPORT thread_member : public json_interface { +protected: + friend struct json_interface; + + /** + * @brief Read struct values from a json object + * @param j json to read values from + * @return A reference to self + */ + thread_member& fill_from_json_impl(nlohmann::json* j); + +public: + /** + * @brief ID of the thread member is part of. + */ + snowflake thread_id = {}; + + /** + * @brief ID of the member. + */ + snowflake user_id = {}; + + /** + * @brief The time when user last joined the thread. + */ + time_t joined = 0; + + /** + * @brief Any user-thread settings, currently only used for notifications. + */ + uint32_t flags = 0; +}; + +/** + * @brief A group of thread member objects. the key is the user_id of the dpp::thread_member + */ +typedef std::unordered_map thread_member_map; + +/** + * @brief metadata for threads + */ +struct DPP_EXPORT thread_metadata { + /** + * @brief Timestamp when the thread's archive status was last changed, used for calculating recent activity. + */ + time_t archive_timestamp; + + /** + * @brief The duration in minutes to automatically archive the thread after recent activity (60, 1440, 4320, 10080). + */ + uint16_t auto_archive_duration; + + /** + * @brief Whether a thread is archived + */ + bool archived; + + /** + * @brief Whether a thread is locked. When a thread is locked, + * only users with `MANAGE_THREADS` can un-archive it. + */ + bool locked; + + /** + * @brief Whether non-moderators can add other non-moderators. Only for private threads. + */ + bool invitable; +}; + +/** @brief A definition of a discord thread. + * A thread is a superset of a channel. Not to be confused with `std::thread`! + */ +class DPP_EXPORT thread : public channel, public json_interface { +protected: + friend struct json_interface; + + /** Read class values from json object + * @param j A json object to read from + * @return A reference to self + */ + thread& fill_from_json_impl(nlohmann::json* j); + + /** + * @brief Build json for this thread object + * + * @param with_id include the ID in the json + * @return std::string JSON string + */ + json to_json_impl(bool with_id = false) const override; + +public: + using json_interface::fill_from_json; + using json_interface::build_json; + using json_interface::to_json; + + /** + * @brief Thread member of current user if joined to the thread. + * Note this is only set by certain api calls otherwise contains default data + */ + thread_member member = {}; + + /** + * @brief Thread metadata (threads) + */ + thread_metadata metadata = {}; + + /** + * @brief Created message. Only filled within the cluster::thread_create_in_forum() method + */ + message msg = {}; + + /** + * @brief A list of dpp::forum_tag IDs that have been applied to a thread in a forum or media channel. + */ + std::vector applied_tags = {}; + + /** + * @brief Number of messages ever sent in the thread. + * It's similar to thread::message_count on message creation, but will not decrement the number when a message is deleted + */ + uint32_t total_messages_sent = 0; + + /** + * @brief Number of messages (not including the initial message or deleted messages) of the thread. + * For threads created before July 1, 2022, the message count is inaccurate when it's greater than 50. + */ + uint8_t message_count = 0; + + /** + * @brief Approximate count of members in a thread (stops counting at 50) + */ + uint8_t member_count = 0; + + /** + * @brief Returns true if the thread is within an announcement channel + * + * @return true if announcement thread + */ + constexpr bool is_news_thread() const noexcept { + return (flags & channel::CHANNEL_TYPE_MASK) == CHANNEL_ANNOUNCEMENT_THREAD; + } + + /** + * @brief Returns true if the channel is a public thread + * + * @return true if public thread + */ + constexpr bool is_public_thread() const noexcept { + return (flags & channel::CHANNEL_TYPE_MASK) == CHANNEL_PUBLIC_THREAD; + } + + /** + * @brief Returns true if the channel is a private thread + * + * @return true if private thread + */ + constexpr bool is_private_thread() const noexcept { + return (flags & channel::CHANNEL_TYPE_MASK) == CHANNEL_PRIVATE_THREAD; + } +}; + + +/** + * @brief Serialize a thread_metadata object to json + * + * @param j JSON object to serialize to + * @param tmdata object to serialize + */ +void to_json(nlohmann::json& j, const thread_metadata& tmdata); + +/** + * @brief A group of threads + */ +typedef std::unordered_map thread_map; + +/** + * @brief A thread alongside the bot's optional thread_member object tied to it + */ +struct active_thread_info { + /** + * @brief The thread object + */ + thread active_thread; + + /** + * @brief The bot as a thread member, only present if the bot is in the thread + */ + std::optional bot_member; +}; + +/** + * @brief A map of threads alongside optionally the thread_member tied to the bot if it is in the thread. The map's key is the thread id. Returned from the cluster::threads_get_active method + */ +using active_threads = std::map; + +} diff --git a/src/dpp/channel.cpp b/src/dpp/channel.cpp index e5d77acd71..4903b60f81 100644 --- a/src/dpp/channel.cpp +++ b/src/dpp/channel.cpp @@ -85,24 +85,8 @@ forum_tag &forum_tag::set_name(const std::string &name) { return *this; } -const uint16_t CHANNEL_TYPE_MASK = 0b0000000000001111; const uint16_t DEFAULT_FORUM_LAYOUT_MASK = 0b0000011000000000; -thread_member& thread_member::fill_from_json_impl(nlohmann::json* j) { - set_snowflake_not_null(j, "id", this->thread_id); - set_snowflake_not_null(j, "user_id", this->user_id); - set_ts_not_null(j, "join_timestamp", this->joined); - set_int32_not_null(j, "flags", this->flags); - return *this; -} - -void to_json(nlohmann::json& j, const thread_metadata& tmdata) { - j["archived"] = tmdata.archived; - j["auto_archive_duration"] = tmdata.auto_archive_duration; - j["locked"] = tmdata.locked; - j["invitable"] = tmdata.invitable; -} - void to_json(nlohmann::json& j, const permission_overwrite& po) { j["id"] = std::to_string(po.id); j["allow"] = std::to_string(po.allow); @@ -332,46 +316,6 @@ bool channel::is_download_options_hidden() const { return flags & dpp::c_hide_media_download_options; } -bool thread::is_news_thread() const { - return (flags & CHANNEL_TYPE_MASK) == CHANNEL_ANNOUNCEMENT_THREAD; -} - -bool thread::is_public_thread() const { - return (flags & CHANNEL_TYPE_MASK) == CHANNEL_PUBLIC_THREAD; -} - -bool thread::is_private_thread() const { - return (flags & CHANNEL_TYPE_MASK) == CHANNEL_PRIVATE_THREAD; -} - -thread& thread::fill_from_json_impl(json* j) { - channel::fill_from_json(j); - - uint8_t type = int8_not_null(j, "type"); - this->flags |= (type & CHANNEL_TYPE_MASK); - - set_snowflake_array_not_null(j, "applied_tags", this->applied_tags); - - set_int32_not_null(j, "total_message_sent", this->total_messages_sent); - set_int8_not_null(j, "message_count", this->message_count); - set_int8_not_null(j, "member_count", this->member_count); - auto json_metadata = (*j)["thread_metadata"]; - metadata.archived = bool_not_null(&json_metadata, "archived"); - metadata.archive_timestamp = ts_not_null(&json_metadata, "archive_timestamp"); - metadata.auto_archive_duration = int16_not_null(&json_metadata, "auto_archive_duration"); - metadata.locked = bool_not_null(&json_metadata, "locked"); - metadata.invitable = bool_not_null(&json_metadata, "invitable"); - - /* Only certain events set this */ - if (j->contains("member")) { - member.fill_from_json(&((*j)["member"])); - } - return *this; -} - -thread::thread() : channel(), total_messages_sent(0), message_count(0), member_count(0) { -} - channel& channel::fill_from_json_impl(json* j) { this->id = snowflake_not_null(j, "id"); set_snowflake_not_null(j, "guild_id", this->guild_id); @@ -472,30 +416,8 @@ channel& channel::fill_from_json_impl(json* j) { } set_string_not_null(j, "rtc_region", rtc_region); - - return *this; -} -json thread::to_json_impl(bool with_id) const { - json j = channel::to_json_impl(with_id); - j["type"] = (flags & CHANNEL_TYPE_MASK); - j["archived"] = this->metadata.archived; - j["auto_archive_duration"] = this->metadata.auto_archive_duration; - j["locked"] = this->metadata.locked; - - if(this->get_type() == dpp::channel_type::CHANNEL_PRIVATE_THREAD) { - j["invitable"] = this->metadata.invitable; - } - - if (!this->applied_tags.empty()) { - j["applied_tags"] = json::array(); - for (auto &tag_id: this->applied_tags) { - if (tag_id) { - j["applied_tags"].push_back(tag_id); - } - } - } - return j; + return *this; } json channel::to_json_impl(bool with_id) const { diff --git a/src/dpp/message.cpp b/src/dpp/message.cpp index abb2d5f8af..61d3bb582c 100644 --- a/src/dpp/message.cpp +++ b/src/dpp/message.cpp @@ -1056,8 +1056,6 @@ bool message::is_voice_message() const { return flags & m_is_voice_message; } -message::~message() = default; - message& message::fill_from_json(json* d, cache_policy_t cp) { this->id = snowflake_not_null(d, "id"); diff --git a/src/dpp/thread.cpp b/src/dpp/thread.cpp new file mode 100644 index 0000000000..9c95954c23 --- /dev/null +++ b/src/dpp/thread.cpp @@ -0,0 +1,90 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ +#include +#include + + +namespace dpp { + +thread_member& thread_member::fill_from_json_impl(nlohmann::json* j) { + set_snowflake_not_null(j, "id", this->thread_id); + set_snowflake_not_null(j, "user_id", this->user_id); + set_ts_not_null(j, "join_timestamp", this->joined); + set_int32_not_null(j, "flags", this->flags); + return *this; +} + +thread& thread::fill_from_json_impl(json* j) { + channel::fill_from_json(j); + + uint8_t type = int8_not_null(j, "type"); + this->flags |= (type & channel::CHANNEL_TYPE_MASK); + + set_snowflake_array_not_null(j, "applied_tags", this->applied_tags); + + set_int32_not_null(j, "total_message_sent", this->total_messages_sent); + set_int8_not_null(j, "message_count", this->message_count); + set_int8_not_null(j, "member_count", this->member_count); + auto json_metadata = (*j)["thread_metadata"]; + metadata.archived = bool_not_null(&json_metadata, "archived"); + metadata.archive_timestamp = ts_not_null(&json_metadata, "archive_timestamp"); + metadata.auto_archive_duration = int16_not_null(&json_metadata, "auto_archive_duration"); + metadata.locked = bool_not_null(&json_metadata, "locked"); + metadata.invitable = bool_not_null(&json_metadata, "invitable"); + + /* Only certain events set this */ + if (j->contains("member")) { + member.fill_from_json(&((*j)["member"])); + } + return *this; +} + +json thread::to_json_impl(bool with_id) const { + json j = channel::to_json_impl(with_id); + j["type"] = (flags & CHANNEL_TYPE_MASK); + j["archived"] = this->metadata.archived; + j["auto_archive_duration"] = this->metadata.auto_archive_duration; + j["locked"] = this->metadata.locked; + + if(this->get_type() == dpp::channel_type::CHANNEL_PRIVATE_THREAD) { + j["invitable"] = this->metadata.invitable; + } + + if (!this->applied_tags.empty()) { + j["applied_tags"] = json::array(); + for (auto &tag_id: this->applied_tags) { + if (tag_id) { + j["applied_tags"].push_back(tag_id); + } + } + } + return j; +} + +void to_json(nlohmann::json& j, const thread_metadata& tmdata) { + j["archived"] = tmdata.archived; + j["auto_archive_duration"] = tmdata.auto_archive_duration; + j["locked"] = tmdata.locked; + j["invitable"] = tmdata.invitable; +} + +}