/************************************************************************************ * * D++, A Lightweight C++ library for Discord * * 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 #include #include #include #include #include #include namespace dpp { /** * @brief Represents the type of a component */ enum component_type : uint8_t { /** * @brief Action row, a container for other components. */ cot_action_row = 1, /** * @brief Clickable button. */ cot_button = 2, /** * @brief Select menu for picking from defined text options. */ cot_selectmenu = 3, /** * @brief Text input. */ cot_text = 4, /** * @brief Select menu for users. */ cot_user_selectmenu = 5, /** * @brief Select menu for roles. */ cot_role_selectmenu = 6, /** * @brief Select menu for mentionables (users and roles). */ cot_mentionable_selectmenu = 7, /** * @brief Select menu for channels. */ cot_channel_selectmenu = 8, }; /** * @brief An emoji for a component (select menus included). * * To set an emoji on your button, you must set one of either the name or id fields. * The easiest way is to use the dpp::component::set_emoji method. * * @note This is a **very** scaled down version of dpp::emoji, we advise that you refrain from using this. */ struct component_emoji { /** * @brief The name of the emoji. * * For built in unicode emojis, set this to the * actual unicode value of the emoji e.g. "😄" * and not for example ":smile:" */ std::string name{""}; /** * @brief The emoji ID value for emojis that are custom * ones belonging to a guild. * * The same rules apply as with other emojis, * that the bot must be on the guild where the emoji resides * and it must be available for use * (e.g. not disabled due to lack of boosts, etc) */ dpp::snowflake id{0}; /** * @brief Is the emoji animated? * * @note Only applies to custom emojis. */ bool animated{false}; }; /** * @brief The data for a file attached to a message. * * @todo Change the naming of this and make stickers (and potentially anything else that has data like this) use this. */ struct message_file_data { /** * @brief Name of file to upload (for use server-side in discord's url). */ std::string name{}; /** * @brief File content to upload (raw binary) */ std::string content{}; /** * @brief Mime type of files to upload. * * @todo Look at turning this into an enum? This would allow people to easily compare mimetypes if they happen to change. */ std::string mimetype{}; }; /** * @brief Types of text input */ enum text_style_type : uint8_t { /** * @brief Intended for short single-line text. */ text_short = 1, /** * @brief Intended for much longer inputs. */ text_paragraph = 2, }; /** * @brief Represents the style of a button */ enum component_style : uint8_t { /** * @brief Blurple */ cos_primary = 1, /** * @brief Grey */ cos_secondary, /** * @brief Green */ cos_success, /** * @brief Red */ cos_danger, /** * @brief An external hyperlink to a website */ cos_link }; /** * Represents the type of a dpp::component_default_value * * @note They're different to discord's value types */ enum component_default_value_type: uint8_t { cdt_user = 0, cdt_role = 1, cdt_channel = 2, }; /** * @brief A Default value structure for components */ struct DPP_EXPORT component_default_value { /** * @brief The type this default value represents */ component_default_value_type type; /** * @brief Default value. ID of a user, role, or channel */ dpp::snowflake id; }; /** * @brief An option for a select component */ struct DPP_EXPORT select_option : 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 */ select_option& fill_from_json_impl(nlohmann::json* j); public: /** * @brief User-facing name of the option */ std::string label; /** * @brief Dev-defined value of the option */ std::string value; /** * @brief Additional description of the option */ std::string description; /** * @brief True if option is the default option */ bool is_default; /** * @brief The emoji for the select option. */ component_emoji emoji; /** * @brief Construct a new select option object */ select_option(); /** * @brief Destructs the select option object. */ virtual ~select_option() = default; /** * @brief Construct a new select option object * * @param label Label of option * @param value Value of option * @param description Description of option */ select_option(const std::string &label, const std::string &value, const std::string &description = ""); /** * @brief Set the label * * @param l the user-facing name of the option. It will be truncated to the maximum length of 100 UTF-8 characters. * @return select_option& reference to self for chaining */ select_option& set_label(const std::string &l); /** * @brief Set the value * * @param v value to set. It will be truncated to the maximum length of 100 UTF-8 characters. * @return select_option& reference to self for chaining */ select_option& set_value(const std::string &v); /** * @brief Set the description * * @param d description to set. It will be truncated to the maximum length of 100 UTF-8 characters. * @return select_option& reference to self for chaining */ select_option& set_description(const std::string &d); /** * @brief Set the emoji * * @param n emoji name * @param id emoji id for custom emojis * @param animated true if animated emoji * @return select_option& reference to self for chaining */ select_option& set_emoji(const std::string &n, dpp::snowflake id = 0, bool animated = false); /** * @brief Set the option as default * * @param def true to set the option as default * @return select_option& reference to self for chaining */ select_option& set_default(bool def); /** * @brief Set the emoji as animated * * @param anim true if animated * @return select_option& reference to self for chaining */ select_option& set_animated(bool anim); }; /** * @brief Represents the component object. * A component is a clickable button or drop down list * within a discord message, where the buttons emit * on_button_click events when the user interacts with * them. * * You should generally define one component object and * then insert one or more additional components into it * using component::add_component(), so that the parent * object is an action row and the child objects are buttons. */ class DPP_EXPORT component : 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 */ component& fill_from_json_impl(nlohmann::json* j); public: /** * @brief Component type, either a button or action row */ component_type type; /** * @brief Sub components, buttons on an action row */ std::vector components; /** * @brief Component label (for buttons, text inputs). * Maximum of 80 characters. */ std::string label; /** * @brief Component style (for buttons). */ component_style style; /** * @brief Text style (for text inputs). */ text_style_type text_style; /** * @brief Component id (for buttons, menus, text inputs). * Maximum of 100 characters. */ std::string custom_id; /** * @brief URL for link types (dpp::cos_link). * Maximum of 512 characters. */ std::string url; /** * @brief Placeholder text for select menus and text inputs (max 150 characters) */ std::string placeholder; /** * @brief Minimum number of items that must be chosen for a select menu (0-25). * * @note Use -1 to not set this. This is done by default. */ int32_t min_values; /** * @brief Maximum number of items that can be chosen for a select menu (0-25). * * @note Use -1 to not set this. This is done by default. */ int32_t max_values; /** * @brief Minimum length for text input (0-4000) */ int32_t min_length; /** * @brief Maximum length for text input (1-4000) */ int32_t max_length; /** * @brief Select options for select menus. * * @warning Only required and available for select menus of type dpp::cot_selectmenu */ std::vector options; /** * @brief List of channel types (dpp::channel_type) to include in the channel select component (dpp::cot_channel_selectmenu) */ std::vector channel_types; /** * @brief List of default values for auto-populated select menu components. * * @note The amount of default values must be in the range defined by dpp::component::min_values and dpp::component::max_values. * * @warning Only available for auto-populated select menu components, which include dpp::cot_user_selectmenu, dpp::cot_role_selectmenu, dpp::cot_mentionable_selectmenu, and dpp::cot_channel_selectmenu components. */ std::vector default_values; /** * @brief Disabled flag (for buttons) */ bool disabled; /** * @brief Whether the text input is required to be filled */ bool required; /** * @brief Value of the modal. * Filled or valid when populated from an on_form_submit event, or from the set_value function. */ std::variant value; /** * @brief The emoji for this component. */ component_emoji emoji; /** * @brief Constructor */ component(); /** * @brief Destructor */ virtual ~component() = default; /** * @brief Add a channel type to include in the channel select component (dpp::cot_channel_selectmenu) * * @param ct The dpp::channel_type * @return component& reference to self */ component& add_channel_type(uint8_t ct); /** * @brief Set the type of the component. Button components * (type dpp::cot_button) should always be contained within * an action row (type dpp::cot_action_row). As described * below, many of the other methods automatically set this * to the correct type so usually you should not need to * manually call component::set_type(). * * @param ct The component type * @return component& reference to self */ component& set_type(component_type ct); /** * @brief Set the text style of a text component * @note Sets type to `cot_text` * * @param ts Text style type to set * @return component& reference to self */ component& set_text_style(text_style_type ts); /** * @brief Set the label of the component, e.g. button text. * For action rows, this field is ignored. Setting the * label will auto-set the type to dpp::cot_button. * * @param label Label text to set. It will be truncated to the maximum length of 80 UTF-8 characters. * @return component& Reference to self */ component& set_label(const std::string &label); /** * @brief Set the default value of the text input component. * For action rows, this field is ignored. Setting the * value will auto-set the type to dpp::cot_text. * * @param val Value text to set. It will be truncated to the maximum length of 4000 UTF-8 characters. * @return component& Reference to self */ component& set_default_value(const std::string &val); /** * @brief Set the url for dpp::cos_link types. * Calling this function sets the style to dpp::cos_link * and the type to dpp::cot_button. * * @param url URL to set. It will be truncated to the maximum length of 512 UTF-8 characters. * @return component& reference to self. */ component& set_url(const std::string &url); /** * @brief Set the style of the component, e.g. button colour. * For action rows, this field is ignored. Setting the * style will auto-set the type to dpp::cot_button. * * @param cs Component style to set * @return component& reference to self */ component& set_style(component_style cs); /** * @brief Set the id of the component. * For action rows, this field is ignored. Setting the * id will auto-set the type to dpp::cot_button. * * @param id Custom ID string to set. This ID will be sent * for any on_button_click events related to the button. * @note The maximum length of the Custom ID is 100 UTF-8 codepoints. * If your Custom ID is longer than this, it will be truncated. * @return component& Reference to self */ component& set_id(const std::string &id); /** * @brief Set the component to disabled. * Defaults to false on all created components. * * @param disable True to disable, false to disable. * @return component& Reference to self */ component& set_disabled(bool disable); /** * @brief Set if this component is required. * Defaults to false on all created components. * * @param require True to require this, false to make it optional. * @return component& Reference to self */ component& set_required(bool require); /** * @brief Set the placeholder * * @param placeholder placeholder string. It will be truncated to the * maximum length of 150 UTF-8 characters for select menus, and 100 UTF-8 * characters for modals. * @return component& Reference to self */ component& set_placeholder(const std::string &placeholder); /** * @brief Set the minimum number of items that must be chosen for a select menu * * @param min_values min value to set (0-25) * @return component& Reference to self */ component& set_min_values(uint32_t min_values); /** * @brief Set the maximum number of items that can be chosen for a select menu * * @param max_values max value to set (0-25) * @return component& Reference to self */ component& set_max_values(uint32_t max_values); /** * @brief Set the minimum input length for a text input * * @param min_l min length to set (0-4000) * @return component& Reference to self */ component& set_min_length(uint32_t min_l); /** * @brief Set the maximum input length for a text input * * @param max_l max length to set (1-4000) * @return component& Reference to self */ component& set_max_length(uint32_t max_l); /** * @brief Add a select option * * @param option option to add * @return component& Reference to self */ component& add_select_option(const select_option &option); /** * @brief Add a sub-component, only valid for action rows. * Adding subcomponents to a component will automatically * set this component's type to dpp::cot_action_row. * * @param c The sub-component to add * @return component& reference to self */ 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 */ component& add_default_value(const snowflake id, const component_default_value_type type); /** * @brief Set the emoji of the current sub-component. * Only valid for buttons. Adding an emoji to a component * will automatically set this components type to * dpp::cot_button. One or both of name and id must be set. * For a built in unicode emoji, you only need set name, * and should set it to a unicode character e.g. "😄". * For custom emojis, set the name to the name of the emoji * on the guild, and the id to the emoji's ID. * Setting the animated boolean is only valid for custom * emojis. * * @param name Emoji name, or unicode character to use * @param id Emoji id, for custom emojis only. * @param animated True if the custom emoji is animated. * @return component& Reference to self */ component& set_emoji(const std::string& name, dpp::snowflake id = 0, bool animated = false); }; /** * @brief A footer in a dpp::embed */ struct DPP_EXPORT embed_footer { /** * @brief Footer text */ std::string text; /** * @brief Footer icon url. * * @warning Only supports http(s) and attachments. */ std::string icon_url; /** * @brief Proxied icon url. */ std::string proxy_url; /** * @brief Set footer's text. * @param t string to set as footer text. It will be truncated to the maximum length of 2048 UTF-8 characters. * @return A reference to self so this method may be "chained". */ embed_footer& set_text(const std::string& t); /** * @brief Set footer's icon url. * @param i url to set as footer icon url * @return A reference to self so this method may be "chained". */ embed_footer& set_icon(const std::string& i); /** * @brief Set footer's proxied icon url. * @param p url to set as footer proxied icon url * @return A reference to self so this method may be "chained". */ embed_footer& set_proxy(const std::string& p); }; /** * @brief An video, image or thumbnail in a dpp::embed */ struct DPP_EXPORT embed_image { /** * @brief URL to image or video. */ std::string url; /** * @brief Proxied image url. */ std::string proxy_url; /** * @brief Height (calculated by discord). */ std::string height; /** * @brief Width (calculated by discord). */ std::string width; }; /** * @brief Embed provider in a dpp::embed. Received from discord but cannot be sent */ struct DPP_EXPORT embed_provider { /** * @brief Provider name. */ std::string name; /** * @brief Provider URL. */ std::string url; }; /** * @brief Author within a dpp::embed object */ struct DPP_EXPORT embed_author { /** * @brief Author name. */ std::string name; /** * @brief Author url. * * @warning Only supports http(s). */ std::string url; /** * @brief Author icon url. * * @warning Only supports http(s) and attachments. */ std::string icon_url; /** * @brief Proxied icon url. */ std::string proxy_icon_url; }; /** * @brief A dpp::embed may contain zero or more fields. */ struct DPP_EXPORT embed_field { /** * @brief Name of field (max length 256). */ std::string name; /** * @brief Value of field (max length 1024). */ std::string value; /** * @brief True if the field is to be displayed inline. */ bool is_inline; }; /** * @brief A rich embed for display within a dpp::message. */ struct DPP_EXPORT embed { /** * @brief Optional: Title of embed. */ std::string title; /** * @brief Optional: Type of embed. * * @note Always "rich" for webhook embeds. */ std::string type; /** * @brief Optional: Description of embed. */ std::string description; /** * @brief Optional: URL of embed. */ std::string url; /** * @brief Optional: Timestamp of embed content. */ time_t timestamp; /** * @brief Optional: Color code of the embed. */ std::optional color; /** * @brief Optional: Footer information. */ std::optional footer; /** * @brief Optional: Image information. */ std::optional image; /** * @brief Optional: Thumbnail information. */ std::optional thumbnail; /** * @brief Optional: Video information * * @warning Can't send this. */ std::optional video; /** * @brief Optional: Provider information. * * @warning Can't send this. */ std::optional provider; /** * @brief Optional: Author information. */ std::optional author; /** * @brief Optional: Fields information. */ std::vector fields; /** * @brief Constructor */ embed(); /** * @brief Constructor to build embed from json object * @param j JSON to read content from */ embed(nlohmann::json* j); /** * @brief Destructor */ ~embed(); /** * @brief Set embed title. * @param text The text of the title. It will be truncated to the maximum length of 256 UTF-8 characters. * @return A reference to self so this method may be "chained". */ embed& set_title(const std::string &text); /** * @brief Set embed description. * @param text The text of the title. It will be truncated to the maximum length of 4096 UTF-8 characters. * @return A reference to self so this method may be "chained". */ embed& set_description(const std::string &text); /** * @brief Set the footer of the embed. * @param f the footer to set * @return A reference to self so this method may be "chained". */ embed& set_footer(const embed_footer& f); /** * @brief Set the footer of the embed. * @param text string to set as footer text. It will be truncated to the maximum length of 2048 UTF-8 characters. * @param icon_url an url to set as footer icon url (only supports http(s) and attachments) * @return A reference to self so this method may be "chained". */ embed& set_footer(const std::string& text, const std::string& icon_url); /** * @brief Set embed colour. * @param col The colour of the embed * @return A reference to self so this method may be "chained". */ embed& set_color(uint32_t col); /** * @brief Set embed colour. * @param col The colour of the embed * @return A reference to self so this method may be "chained". */ embed& set_colour(uint32_t col); /** * @brief Set embed timestamp. * @param tstamp The timestamp to show in the footer, should be in UTC * @return A reference to self so this method may be "chained". */ embed& set_timestamp(time_t tstamp); /** * @brief Set embed url. * @param url the url of the embed * @return A reference to self so this method may be "chained". */ embed& set_url(const std::string &url); /** * @brief Add an embed field. * @param name The name of the field. It will be truncated to the maximum length of 256 UTF-8 characters. * @param value The value of the field. It will be truncated to the maximum length of 1024 UTF-8 characters. * @param is_inline Whether or not to display the field 'inline' or on its own line * @return A reference to self so this method may be "chained". */ embed& add_field(const std::string& name, const std::string &value, bool is_inline = false); /** * @brief Set embed author. * @param a The author to set * @return A reference to self so this method may be "chained". */ embed& set_author(const dpp::embed_author& a); /** * @brief Set embed author. * @param name The name of the author. It will be truncated to the maximum length of 256 UTF-8 characters. * @param url The url of the author (only supports http(s)) * @param icon_url The icon URL of the author (only supports http(s) and attachments) * @return A reference to self so this method may be "chained". */ embed& set_author(const std::string& name, const std::string& url, const std::string& icon_url); /** * @brief Set embed provider. * @param name The provider name. It will be truncated to the maximum length of 256 UTF-8 characters. * @param url The provider url * @return A reference to self so this method may be "chained". */ embed& set_provider(const std::string& name, const std::string& url); /** * @brief Set embed image. * @param url The embed image URL (only supports http(s) and attachments) * @return A reference to self so this method may be "chained". */ embed& set_image(const std::string& url); /** * @brief Set embed video. * @param url The embed video url * @return A reference to self so this method may be "chained". */ embed& set_video(const std::string& url); /** * @brief Set embed thumbnail. * @param url The embed thumbnail url (only supports http(s) and attachments) * @return A reference to self so this method may be "chained". */ embed& set_thumbnail(const std::string& url); }; /** * @brief Represents a reaction to a dpp::message. */ struct DPP_EXPORT reaction { /** * @brief Total number of times this emoji has been used to react (including super reacts) */ uint32_t count; /** * @brief Count of super reactions */ uint32_t count_burst; /** * @brief Count of normal reactions */ uint32_t count_normal; /** * @brief ID of emoji for reaction */ snowflake emoji_id; /** * @brief Name of emoji, if applicable */ std::string emoji_name; /** * @brief Whether your bot reacted using this emoji */ bool me; /** * @brief Whether your bot super-reacted using this emoji */ bool me_burst; /** * @brief HEX colors used for super reaction. * * @note Stored as integers. */ std::vector burst_colors; /** * @brief Constructs a new reaction object. */ reaction(); /** * @brief Constructs a new reaction object from a JSON object. * @param j The JSON to read data from */ reaction(nlohmann::json* j); /** * @brief Destructs the reaction object. */ ~reaction() = default; }; /** * @brief Bitmask flags for a dpp::attachment */ enum attachment_flags : uint8_t { /** * @brief This attachment has been edited using the remix feature on mobile. */ a_is_remix = 1 << 2, }; /** * @brief Represents an attachment in a dpp::message */ struct DPP_EXPORT attachment { /** * @brief ID of attachment. */ snowflake id; /** * @brief Size of the attachment in bytes. */ uint32_t size; /** * @brief File name of the attachment. */ std::string filename; /** * @brief Optional: Description of the attachment. * Max 1024 characters. */ std::string description; /** * @brief URL which points to the attachment. */ std::string url; /** * @brief Proxied URL which points to the attachment. */ std::string proxy_url; /** * @brief Width of the attachment, if applicable. */ uint32_t width; /** * @brief Height of the attachment, if applicable. */ uint32_t height; /** * @brief MIME type of the attachment, if applicable. */ std::string content_type; /** * @brief Whether this attachment is ephemeral, if applicable. */ bool ephemeral; /** * @brief The duration of the audio file. * * @note Currently for voice messages. */ double duration_secs; /** * @brief Base64 encoded bytearray representing a sampled waveform. * * @note Currently for voice messages. */ std::string waveform; /** * @brief Flags made from dpp::attachment_flags. */ uint8_t flags; /** * @brief Owning message */ struct message* owner; /** * @brief Constructs a new attachment object. * @param o Owning dpp::message object */ attachment(struct message* o); /** * @brief Constructs a new attachment object from a JSON object. * @param o Owning dpp::message object * @param j JSON to read information from */ attachment(struct message* o, nlohmann::json* j); /** * @brief Destructs the attachment object. */ ~attachment() = default; /** * @brief Download this attachment * * @param callback A callback which is called when the download completes. * @note The content of the file will be in the http_info.body parameter of the * callback parameter. * @throw dpp::logic_exception If there is no owner associated with this attachment that * itself has an owning cluster, this method will throw a dpp::logic_exception when called. */ void download(http_completion_event callback) const; /** * @brief Returns true if remixed * * @return true if remixed */ bool is_remix() const; }; /** * @brief Represents the type of a sticker */ enum sticker_type : uint8_t { /** * @brief An official sticker in a pack. */ st_standard = 1, /** * @brief Guild sticker. */ st_guild = 2 }; /** * @brief The file format (png, apng, lottie) of a sticker */ enum sticker_format : uint8_t { sf_png = 1, sf_apng = 2, sf_lottie = 3, sf_gif = 4, }; /** * @brief Represents stickers received in messages */ struct DPP_EXPORT sticker : public managed, 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 */ sticker& fill_from_json_impl(nlohmann::json* j); /** Build JSON from this object. * @param with_id True if the ID is to be set in the JSON structure * @return The JSON of the invite */ virtual json to_json_impl(bool with_id = true) const; public: /** * @brief Optional: for standard stickers, id of the pack the sticker is from */ snowflake pack_id; /** * @brief The name of the sticker. */ std::string name; /** * @brief Description of the sticker * * @note This may be empty. */ std::string description; /** * @brief The sticker's (or related) expressions. * * @note If it's a guild sticker, this will be the Discord name of * a unicode emoji representing the sticker's expression. * Otherwise, this will be a comma-separated list of related expressions. */ std::string tags; /** * @brief Asset ID * * @deprecated now an empty string but still sent by discord. * While discord still send this empty string value, * we will still have this field here in the library. */ std::string asset; /** * @brief The type of sticker. */ sticker_type type; /** * @brief type of sticker format. */ sticker_format format_type; /** * @brief Optional: Whether this guild sticker can be used. * * @note May be false due to loss of Server Boosts. */ bool available; /** * @brief Optional: ID of the guild that owns this sticker. */ snowflake guild_id; /** * @brief Optional: The user that uploaded the guild sticker. */ user sticker_user; /** * @brief Optional: The standard sticker's sort order within its pack. */ uint8_t sort_value; /** * @brief Name of file to upload (when adding or editing a sticker). */ std::string filename; /** * @brief File content to upload (raw binary). */ std::string filecontent; /** * @brief Construct a new sticker object */ sticker(); virtual ~sticker() = default; /** * @brief Get the sticker url. * * @return std::string The sticker url or an empty string, if the id is empty */ std::string get_url() const; /** * @brief Set the filename * * @param fn filename * @return message& reference to self */ sticker& set_filename(const std::string &fn); /** * @brief Set the file content * * @param fc raw file content contained in std::string * @return message& reference to self */ sticker& set_file_content(const std::string &fc); }; /** * @brief Represents a sticker pack (the built in groups of stickers that all nitro users get to use) */ struct DPP_EXPORT sticker_pack : public managed, 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 */ sticker_pack& fill_from_json_impl(nlohmann::json* j); /** Build JSON from this object. * @param with_id True if the ID is to be set in the JSON structure * @return The JSON of the invite */ virtual json to_json_impl(bool with_id = true) const; public: /** * @brief The stickers in the pack. */ std::map stickers; /** * @brief Name of the sticker pack. */ std::string name; /** * @brief ID of the pack's SKU. */ snowflake sku_id; /** * @brief Optional: ID of a sticker in the pack which is shown as the pack's icon. */ snowflake cover_sticker_id; /** * @brief Description of the sticker pack. */ std::string description; /** * @brief ID of the sticker pack's banner image. */ snowflake banner_asset_id; /** * @brief Construct a new sticker pack object */ sticker_pack(); virtual ~sticker_pack() = default; }; /** * @brief Bitmask flags for a dpp::message */ enum message_flags : uint16_t { /** * @brief This message has been published to subscribed channels (via Channel Following). */ m_crossposted = 1 << 0, /** * @brief This message originated from a message in another channel (via Channel Following). */ m_is_crosspost = 1 << 1, /** * @brief Do not include any embeds when serializing this message. */ m_suppress_embeds = 1 << 2, /** * @brief The source message for this crosspost has been deleted (via Channel Following). */ m_source_message_deleted = 1 << 3, /** * @brief This message came from the urgent message system. */ m_urgent = 1 << 4, /** * @brief This message has an associated thread, with the same id as the message. */ m_has_thread = 1 << 5, /** * @brief This message is only visible to the user who invoked the Interaction. */ m_ephemeral = 1 << 6, /** * @brief This message is an Interaction Response and the bot is "thinking". */ m_loading = 1 << 7, /** * @brief This message failed to mention some roles and add their members to the thread. */ m_thread_mention_failed = 1 << 8, /** * @brief This message will not trigger push and desktop notifications. */ m_suppress_notifications = 1 << 12, /** * @brief This message is a voice message. */ m_is_voice_message = 1 << 13, }; /** * @brief Represents possible values for the dpp::embed type field. * These are loosely defined by the API docs and do not influence how the client renders embeds. * * @note The only type a bot can send is dpp::embed_type::emt_rich. */ namespace embed_type { /** * @brief Rich text */ const std::string emt_rich = "rich"; /** * @brief Image */ const std::string emt_image = "image"; /** * @brief Video link */ const std::string emt_video = "video"; /** * @brief Animated gif */ const std::string emt_gifv = "gifv"; /** * @brief Article */ const std::string emt_article = "article"; /** * @brief Link URL */ const std::string emt_link = "link"; /** * @brief Auto moderation filter */ const std::string emt_automod = "auto_moderation_message"; } // namespace embed_type /** * @brief Message types for dpp::message::type */ enum message_type { /** * @brief Default */ mt_default = 0, /** * @brief Add recipient */ mt_recipient_add = 1, /** * @brief Remove recipient */ mt_recipient_remove = 2, /** * @brief Call */ mt_call = 3, /** * @brief Channel name change */ mt_channel_name_change = 4, /** * @brief Channel icon change */ mt_channel_icon_change = 5, /** * @brief Message pinned */ mt_channel_pinned_message = 6, /** * @brief Member joined */ mt_guild_member_join = 7, /** * @brief Boost */ mt_user_premium_guild_subscription = 8, /** * @brief Boost level 1 */ mt_user_premium_guild_subscription_tier_1 = 9, /** * @brief Boost level 2 */ mt_user_premium_guild_subscription_tier_2 = 10, /** * @brief Boost level 3 */ mt_user_premium_guild_subscription_tier_3 = 11, /** * @brief Follow channel */ mt_channel_follow_add = 12, /** * @brief Disqualified from discovery */ mt_guild_discovery_disqualified = 14, /** * @brief Re-qualified for discovery */ mt_guild_discovery_requalified = 15, /** * @brief Discovery grace period warning 1 */ mt_guild_discovery_grace_period_initial_warning = 16, /** * @brief Discovery grace period warning 2 */ mt_guild_discovery_grace_period_final_warning = 17, /** * @brief Thread Created */ mt_thread_created = 18, /** * @brief Reply */ mt_reply = 19, /** * @brief Application command */ mt_application_command = 20, /** * @brief Thread starter message */ mt_thread_starter_message = 21, /** * @brief Invite reminder */ mt_guild_invite_reminder = 22, /** * @brief Context Menu Command */ mt_context_menu_command = 23, /** * @brief Auto moderation action */ mt_auto_moderation_action = 24, /** * @brief Role subscription purchase */ mt_role_subscription_purchase = 25, /** * @brief Interaction premium upsell */ mt_interaction_premium_upsell = 26, /** * @brief Stage start */ mt_stage_start = 27, /** * @brief Stage end */ mt_stage_end = 28, /** * @brief Stage speaker */ mt_stage_speaker = 29, /** * @brief Stage topic */ mt_stage_topic = 31, /** * @brief Guild application premium subscription */ mt_application_premium_subscription = 32, }; /** * @brief Represents the caching policy of a cache in the library. */ enum cache_policy_setting_t { /** * @brief request aggressively on seeing new guilds, and also store missing data from messages. * This is the default behaviour and the least memory-efficient option. Memory usage will increase * over time, initially quite rapidly, and then linearly over time. It is the least cpu-intensive * setting. */ cp_aggressive = 0, /** * @brief only cache when there is relevant activity, e.g. a message to the bot. * This is a good middle-ground, memory usage will increase linearly over time. */ cp_lazy = 1, /** * @brief Don't cache anything. Fill details when we see them. * This is the most memory-efficient option but consumes more CPU time */ cp_none = 2 }; /** * @brief Represents the caching policy of the cluster. * * Channels and guilds are always cached as these caches are used * internally by the library. The memory usage of these is minimal. * * All default to 'aggressive' which means to actively attempt to cache, * going out of the way to fill the caches completely. On large bots this * can take a LOT of RAM. */ struct DPP_EXPORT cache_policy_t { /** * @brief Caching policy for users and guild members */ cache_policy_setting_t user_policy = cp_aggressive; /** * @brief Caching policy for emojis */ cache_policy_setting_t emoji_policy = cp_aggressive; /** * @brief Caching policy for roles */ cache_policy_setting_t role_policy = cp_aggressive; /** * @brief Caching policy for roles */ cache_policy_setting_t channel_policy = cp_aggressive; /** * @brief Caching policy for roles */ cache_policy_setting_t guild_policy = cp_aggressive; }; /** * @brief Contains a set of predefined cache policies for use when constructing a dpp::cluster */ namespace cache_policy { /** * @brief A shortcut constant for all caching enabled for use in dpp::cluster constructor */ inline constexpr cache_policy_t cpol_default = { cp_aggressive, cp_aggressive, cp_aggressive, cp_aggressive, cp_aggressive }; /** * @brief A shortcut constant for a more balanced caching policy for use in dpp::cluster constructor */ inline constexpr cache_policy_t cpol_balanced = { cp_lazy, cp_lazy, cp_lazy, cp_aggressive, cp_aggressive }; /** * @brief A shortcut constant for all caching disabled for use in dpp::cluster constructor */ inline constexpr cache_policy_t cpol_none = { cp_none, cp_none, cp_none, cp_none, cp_none }; }; /** * @brief Represents messages sent and received on Discord */ struct DPP_EXPORT message : public managed, 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 */ inline message& fill_from_json_impl(nlohmann::json *j) { return fill_from_json(j, {cp_aggressive, cp_aggressive, cp_aggressive}); } /** Build a JSON from this object. * @param with_id True if an ID is to be included in the JSON * @return JSON */ inline json to_json_impl(bool with_id = false) const { return to_json(with_id, false); } public: /** * @brief ID of the channel the message was sent in. */ snowflake channel_id; /** * @brief Optional: ID of the guild the message was sent in. */ snowflake guild_id; /** * @brief The author of this message. * * @warning This is not guaranteed to be a valid user. */ user author; /** * @brief Optional: member properties for this message's author */ guild_member member; /** * @brief Contents of the message. */ std::string content; /** * @brief Message components. */ std::vector components; /** * @brief When this message was sent. */ time_t sent; /** * @brief When this message was edited. * * @note This may be 0 if never edited. */ time_t edited; /** * @brief Users specifically mentioned in the message. */ std::vector> mentions; /** * @brief Roles specifically mentioned in this message (only IDs currently). */ std::vector mention_roles; /** * @brief Channels mentioned in the message. * * @warning Not all types supported. * * @note Discord: Only textual channels that are visible to everyone in a lurkable guild will ever be included. * Only crossposted messages (via Channel Following) currently include mention_channels at all. (includes ID, Guild ID, Type, Name). */ std::vector mention_channels; /** * @brief Any attached files. */ std::vector attachments; /** * @brief Up to 10 dpp::embed objects. */ std::vector embeds; /** * @brief Optional: reactions to the message. */ std::vector reactions; /** * @brief Optional: Used for validating a message was sent. */ std::string nonce; /** * @brief Optional: Webhook ID. * * @note If the message is generated by a webhook, its ID will be here. Otherwise, the field will be 0. */ snowflake webhook_id; /** * @brief Stickers. */ std::vector stickers; /** * @brief An array of file data to use for uploading files. * * @note You should use dpp::message::add_file to add data to this! */ std::vector file_data; /** * @brief Reference to another message, e.g. a reply */ struct message_ref { /** * @brief ID of the originating message. */ snowflake message_id; /** * @brief ID of the originating message's channel. */ snowflake channel_id; /** * @brief ID of the originating message's guild. */ snowflake guild_id; /** * @brief when sending, whether to error if the referenced message doesn't exist instead of sending as a normal (non-reply) message. * Default true. */ bool fail_if_not_exists; } message_reference; /** * @brief Reference to an interaction */ struct message_interaction_struct{ /** * @brief ID of the interaction. */ snowflake id; /** * @brief Type of interaction. */ uint8_t type; /** * @brief Name of the application command. */ std::string name; /** * @brief The user who invoked the interaction. */ user usr; } interaction; /** * @brief Allowed mentions details */ struct allowed_ref { /** * @brief Set to true to parse user mentions in the text. Default is false */ bool parse_users; /** * @brief Set to true to at-everyone and at-here mentions in the text. Default is false */ bool parse_everyone; /** * @brief Set to true to parse role mentions in the text. Default is false */ bool parse_roles; /** * @brief Set to true to mention the user who sent the message this one is replying to. Default is false */ bool replied_user; /** * @brief List of users to allow pings for */ std::vector users; /** * @brief List of roles to allow pings for */ std::vector roles; } allowed_mentions; /** * @brief The cluster which created this message object. */ class cluster* owner; /** * @brief Message type. */ message_type type; /** * @brief Flags made from dpp::message_flags */ uint16_t flags; /** * @brief Whether this message is pinned. */ bool pinned; /** * @brief Whether this was a TTS message. */ bool tts; /** * @brief Whether this message mentions everyone. */ bool mention_everyone; /** * @brief Construct a new message object */ 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. * Owning cluster is optional (can be nullptr) and if nulled, will prevent some functions * such as attachment::download from functioning (they will throw, if used) */ message(class cluster* o); /** * @brief Construct a new message object with a channel and content * * @param channel_id The channel to send the message to * @param content The content of the message. It will be truncated to the maximum length of 4000 UTF-8 characters. * @param type The message type to create */ message(snowflake channel_id, const std::string &content, message_type type = mt_default); /** * @brief Construct a new message object with a channel and content * * @param channel_id The channel to send the message to * @param _embed An embed to send */ message(snowflake channel_id, const embed & _embed); /** * @brief Construct a new message object with content * * @param content The content of the message. It will be truncated to the maximum length of 4000 UTF-8 characters. * @param type The message type to create */ 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 * * @param _message_id message id to reply to * @param _guild_id guild id to reply to (optional) * @param _channel_id channel id to reply to (optional) * @param fail_if_not_exists true if the message send should fail if these values are invalid (optional) * @return message& reference to self */ message& set_reference(snowflake _message_id, snowflake _guild_id = 0, snowflake _channel_id = 0, bool fail_if_not_exists = false); /** * @brief Set the allowed mentions object for pings on the message * * @param _parse_users whether or not to parse users in the message content or embeds * @param _parse_roles whether or not to parse roles in the message content or embeds * @param _parse_everyone whether or not to parse everyone/here in the message content or embeds * @param _replied_user if set to true and this is a reply, then ping the user we reply to * @param users list of user ids to allow pings for * @param roles list of role ids to allow pings for * @return message& reference to self */ message& set_allowed_mentions(bool _parse_users, bool _parse_roles, bool _parse_everyone, bool _replied_user, const std::vector &users, const std::vector &roles); using json_interface::fill_from_json; using json_interface::to_json; /** Fill this object from json. * @param j JSON object to fill from * @param cp Cache policy for user records, whether or not we cache users when a message is received * @return A reference to self */ message& fill_from_json(nlohmann::json* j, cache_policy_t cp); /** Build JSON from this object. * @param with_id True if the ID is to be included in the built JSON * @param is_interaction_response Set to true if this message is intended to be included in an interaction response. * This will exclude some fields that are not valid in interactions at this time. * @return The JSON text of the message */ virtual json to_json(bool with_id, bool is_interaction_response) const; /** * @brief Returns true if the message was crossposted to other servers * * @return true if crossposted */ bool is_crossposted() const; /** * @brief Returns true if posted from other servers announcement channel via webhook * * @return true if posted from other server */ bool is_crosspost() const; /** * @brief True if embeds have been removed * * @return true if embeds removed */ bool suppress_embeds() const; /** * @brief True if source message was deleted * * @return true if source message deleted */ bool is_source_message_deleted() const; /** * @brief True if urgent * * @return true if urgent */ bool is_urgent() const; /** * @brief True if has thread attached * * @return true if has thread attached */ bool has_thread() const; /** * @brief True if ephemeral (visible only to issuer of a slash command) * * @return true if ephemeral */ bool is_ephemeral() const; /** * @brief True if loading * * @return true if loading */ bool is_loading() const; /** * @brief Returns true if this message failed to mention some roles and add their members to the thread * * @return true if this message failed to mention some roles and add their members to the thread */ bool is_thread_mention_failed() const; /** * @brief True if the message will not trigger push and desktop notifications * * @return True if notifications suppressed */ bool suppress_notifications() const; /** * @brief True if the message is a voice message * * @return True if voice message */ bool is_voice_message() const; /** * @brief Add a component (button) to message * * @param c component to add * @return message& reference to self */ message& add_component(const component& c); /** * @brief Add an embed to message * * @param e embed to add * @return message& reference to self */ message& add_embed(const embed& e); /** * @brief Set the flags * * @param f flags to set from dpp::message_flags * @return message& reference to self */ message& set_flags(uint16_t f); /** * @brief Set the message type * * @param t type to set * @return message& reference to self */ message& set_type(message_type t); /** * @brief Set the filename of the last file in list * * @param fn filename * @return message& reference to self * @deprecated Use message::add_file instead */ message& set_filename(const std::string &fn); /** * @brief Set the file content of the last file in list * * @param fc raw file content contained in std::string * @return message& reference to self * @deprecated Use message::add_file instead */ message& set_file_content(const std::string &fc); /** * @brief Add a file to the message * * @param filename filename * @param filecontent raw file content contained in std::string * @param filemimetype optional mime type of the file * @return message& reference to self */ message& add_file(const std::string &filename, const std::string &filecontent, const std::string &filemimetype = ""); /** * @brief Set the message content * * @param c message content. It will be truncated to the maximum length of 4000 UTF-8 characters. * @return message& reference to self */ message& set_content(const std::string &c); /** * @brief Set the channel id * * @param _channel_id channel id * @return message& reference to self */ message& set_channel_id(snowflake _channel_id); /** * @brief Set the channel id * * @param _guild_id channel id * @return message& reference to self */ message& set_guild_id(snowflake _guild_id); /** * @brief Returns true if the message is from a DM * * @return true if message is a DM */ bool is_dm() const; /** * @brief Returns true if message has remixed attachment * * @return true if message has remixed attachment */ bool has_remix_attachment() const; /** * @brief Returns URL to message * * @return string of URL to message */ std::string get_url() const; }; /** * @brief A group of messages */ typedef std::unordered_map message_map; /** * @brief A group of stickers */ typedef std::unordered_map sticker_map; /** * @brief A group of sticker packs */ typedef std::unordered_map sticker_pack_map; } // namespace dpp