From ab23584d70832c4fa1574a73d7c1ba497cbdf675 Mon Sep 17 00:00:00 2001 From: Jaskowicz1 Date: Fri, 20 Oct 2023 17:40:33 +0100 Subject: [PATCH 1/7] feat: added application and following support for webhooks. --- include/dpp/webhook.h | 28 ++++++++++++++++---------- src/dpp/cluster/webhook.cpp | 21 +++++--------------- src/dpp/webhook.cpp | 39 +++++++++++++++---------------------- 3 files changed, 39 insertions(+), 49 deletions(-) diff --git a/include/dpp/webhook.h b/include/dpp/webhook.h index 808eb45227..82a692cd6b 100644 --- a/include/dpp/webhook.h +++ b/include/dpp/webhook.h @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include #include @@ -35,7 +38,8 @@ namespace dpp { */ enum webhook_type { w_incoming = 1, //!< Incoming webhook - w_channel_follower = 2 //!< Channel following webhook + w_channel_follower = 2, //!< Channel following webhook + w_application = 2 //!< Application webhooks for interactions. }; /** @@ -62,15 +66,19 @@ class DPP_EXPORT webhook : public managed, public json_interface { virtual json to_json_impl(bool with_id = false) const; public: - uint8_t type; //!< the type of the webhook - snowflake guild_id; //!< Optional: the guild id this webhook is for - snowflake channel_id; //!< the channel id this webhook is for - snowflake user_id; //!< Optional: the user this webhook was created by (not returned when getting a webhook with its token) - std::string name; //!< the default name of the webhook (may be empty) - std::string avatar; //!< the default avatar of the webhook (may be empty) - std::string token; //!< Optional: the secure token of the webhook (returned for Incoming Webhooks) - snowflake application_id; //!< the bot/OAuth2 application that created this webhook (may be empty) - std::string* image_data; //!< base64 encoded image data if uploading a new image + uint8_t type; //!< the type of the webhook + snowflake guild_id; //!< Optional: the guild id this webhook is for (may be empty) + snowflake channel_id; //!< the channel id this webhook is for (may be empty) + user user_obj; //!< Optional: the user this webhook was created by (not returned when getting a webhook with its token) + std::string name; //!< the default name of the webhook (may be empty) + utility::iconhash avatar; //!< the default avatar of the webhook (may be empty) + std::string token; //!< Optional: the secure token of the webhook (returned for Incoming Webhooks) + snowflake application_id; //!< the bot/OAuth2 application that created this webhook (may be empty) + guild source_guild; //!< the guild of the channel that this webhook is following (only for Channel Follower Webhooks) @note This will be absent if the webhook creator has since lost access to the guild where the followed channel resides! + channel source_channel; //!< the channel that this webhook is following (only for Channel Follower Webhooks) @note This will be absent if the webhook creator has since lost access to the guild where the followed channel resides! + std::string url; //!< the url used for executing the webhook (returned by the webhooks OAuth2 flow) + + std::string* image_data; //!< base64 encoded image data if uploading a new image /** * @brief Construct a new webhook object diff --git a/src/dpp/cluster/webhook.cpp b/src/dpp/cluster/webhook.cpp index f182012ec2..609db9ae1b 100644 --- a/src/dpp/cluster/webhook.cpp +++ b/src/dpp/cluster/webhook.cpp @@ -23,16 +23,14 @@ namespace dpp { -void cluster::create_webhook(const class webhook &w, command_completion_event_t callback) { - rest_request(this, API_PATH "/channels", std::to_string(w.channel_id), "webhooks", m_post, w.build_json(false), callback); +void cluster::create_webhook(const class webhook &wh, command_completion_event_t callback) { + rest_request(this, API_PATH "/channels", std::to_string(wh.channel_id), "webhooks", m_post, wh.build_json(false), callback); } - void cluster::delete_webhook(snowflake webhook_id, command_completion_event_t callback) { rest_request(this, API_PATH "/webhooks", std::to_string(webhook_id), "", m_delete, "", callback); } - void cluster::delete_webhook_message(const class webhook &wh, snowflake message_id, snowflake thread_id, command_completion_event_t callback) { std::string parameters = utility::make_url_parameters({ {"thread_id", thread_id}, @@ -40,17 +38,14 @@ void cluster::delete_webhook_message(const class webhook &wh, snowflake message_ rest_request(this, API_PATH "/webhooks", std::to_string(wh.id), utility::url_encode(!wh.token.empty() ? wh.token: token) + "/messages/" + std::to_string(message_id) + parameters, m_delete, "", callback); } - void cluster::delete_webhook_with_token(snowflake webhook_id, const std::string &token, command_completion_event_t callback) { rest_request(this, API_PATH "/webhooks", std::to_string(webhook_id), utility::url_encode(token), m_delete, "", callback); } - void cluster::edit_webhook(const class webhook& wh, command_completion_event_t callback) { rest_request(this, API_PATH "/webhooks", std::to_string(wh.id), "", m_patch, wh.build_json(false), callback); } - void cluster::edit_webhook_message(const class webhook &wh, const struct message& m, snowflake thread_id, command_completion_event_t callback) { std::string parameters = utility::make_url_parameters({ {"thread_id", thread_id}, @@ -62,7 +57,6 @@ void cluster::edit_webhook_message(const class webhook &wh, const struct message }, m.filename, m.filecontent, m.filemimetype); } - void cluster::edit_webhook_with_token(const class webhook& wh, command_completion_event_t callback) { json jwh = wh.to_json(true); if (jwh.find("channel_id") != jwh.end()) { @@ -71,20 +65,19 @@ void cluster::edit_webhook_with_token(const class webhook& wh, command_completio rest_request(this, API_PATH "/webhooks", std::to_string(wh.id), utility::url_encode(wh.token), m_patch, jwh.dump(), callback); } - void cluster::execute_webhook(const class webhook &wh, const struct message& m, bool wait, snowflake thread_id, const std::string& thread_name, command_completion_event_t callback) { std::string parameters = utility::make_url_parameters({ {"wait", wait}, {"thread_id", thread_id}, }); std::string body; - if (!thread_name.empty() || !wh.avatar.empty() || !wh.name.empty()) { // only use json::parse if thread_name is set + if (!thread_name.empty() || !wh.avatar.to_string().empty() || !wh.name.empty()) { // only use json::parse if thread_name is set json j = m.to_json(false); if (!thread_name.empty()) { j["thread_name"] = thread_name; } - if (!wh.avatar.empty()) { - j["avatar_url"] = wh.avatar; + if (!wh.avatar.to_string().empty()) { + j["avatar_url"] = wh.avatar.to_string(); } if (!wh.name.empty()) { j["username"] = wh.name; @@ -98,7 +91,6 @@ void cluster::execute_webhook(const class webhook &wh, const struct message& m, }, m.filename, m.filecontent, m.filemimetype); } - void cluster::get_channel_webhooks(snowflake channel_id, command_completion_event_t callback) { rest_request_list(this, API_PATH "/channels", std::to_string(channel_id), "webhooks", m_get, "", callback); } @@ -108,12 +100,10 @@ void cluster::get_guild_webhooks(snowflake guild_id, command_completion_event_t rest_request_list(this, API_PATH "/guilds", std::to_string(guild_id), "webhooks", m_get, "", callback); } - void cluster::get_webhook(snowflake webhook_id, command_completion_event_t callback) { rest_request(this, API_PATH "/webhooks", std::to_string(webhook_id), "", m_get, "", callback); } - void cluster::get_webhook_message(const class webhook &wh, snowflake message_id, snowflake thread_id, command_completion_event_t callback) { std::string parameters = utility::make_url_parameters({ {"thread_id", thread_id}, @@ -121,7 +111,6 @@ void cluster::get_webhook_message(const class webhook &wh, snowflake message_id, rest_request(this, API_PATH "/webhooks", std::to_string(wh.id), utility::url_encode(!wh.token.empty() ? wh.token: token) + "/messages/" + std::to_string(message_id) + parameters, m_get, "", callback); } - void cluster::get_webhook_with_token(snowflake webhook_id, const std::string &token, command_completion_event_t callback) { rest_request(this, API_PATH "/webhooks", std::to_string(webhook_id), utility::url_encode(token), m_get, "", callback); } diff --git a/src/dpp/webhook.cpp b/src/dpp/webhook.cpp index 9ef46d2df6..27adec2f33 100644 --- a/src/dpp/webhook.cpp +++ b/src/dpp/webhook.cpp @@ -61,44 +61,37 @@ webhook::~webhook() { } webhook& webhook::fill_from_json_impl(nlohmann::json* j) { - id = snowflake_not_null(j, "id"); - type = int8_not_null(j, "type"); - channel_id = snowflake_not_null(j, "channel_id"); - guild_id = snowflake_not_null(j, "guild_id"); + set_snowflake_not_null(j, "id", id); + set_int8_not_null(j, "type", type); + set_snowflake_not_null(j, "guild_id", guild_id); + set_snowflake_not_null(j, "channel_id", channel_id); if (j->contains("user")) { - json & user = (*j)["user"]; - user_id = snowflake_not_null(&user, "id"); + user_obj = user().fill_from_json(&((*j)["user"])); } - name = string_not_null(j, "name"); - avatar = string_not_null(j, "avatar"); - token = string_not_null(j, "token"); - application_id = snowflake_not_null(j, "application_id"); + set_string_not_null(j, "name", name); + set_iconhash_not_null(j, "avatar", avatar); + set_string_not_null(j, "token", token); + set_snowflake_not_null(j, "application_id", application_id); + if (j->contains("source_guild")) { + source_guild = guild().fill_from_json(&((*j)["source_guild"])); + } + if (j->contains("source_channel")) { + source_channel = channel().fill_from_json(&((*j)["source_channel"])); + } + set_string_not_null(j, "url", url); return *this; } json webhook::to_json_impl(bool with_id) const { json j; - if (with_id) { - j["id"] = std::to_string(id); - } j["name"] = name; - j["type"] = type; if (channel_id) { j["channel_id"] = channel_id; } - if (guild_id) { - j["guild_id"] = guild_id; - } - if (!name.empty()) { - j["name"] = name; - } if (image_data) { j["avatar"] = *image_data; } - if (application_id) { - j["application_id"] = application_id; - } return j; } From c498f89710d579ecd2f8eaeb9989222b0292342e Mon Sep 17 00:00:00 2001 From: Jaskowicz1 Date: Fri, 20 Oct 2023 17:41:54 +0100 Subject: [PATCH 2/7] fix: changed w_application to 3 --- include/dpp/webhook.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/dpp/webhook.h b/include/dpp/webhook.h index 82a692cd6b..8b0bce57e5 100644 --- a/include/dpp/webhook.h +++ b/include/dpp/webhook.h @@ -39,7 +39,7 @@ namespace dpp { enum webhook_type { w_incoming = 1, //!< Incoming webhook w_channel_follower = 2, //!< Channel following webhook - w_application = 2 //!< Application webhooks for interactions. + w_application = 3 //!< Application webhooks for interactions. }; /** From c530a98cc7868e81a90b07463b9ff09eebfdb35b Mon Sep 17 00:00:00 2001 From: Jaskowicz1 Date: Fri, 20 Oct 2023 20:05:44 +0100 Subject: [PATCH 3/7] fix: removed user_id from constructor, fixed comments --- include/dpp/webhook.h | 83 ++++++++++++++++++++++++++++++++++++------- src/dpp/webhook.cpp | 2 +- 2 files changed, 71 insertions(+), 14 deletions(-) diff --git a/include/dpp/webhook.h b/include/dpp/webhook.h index 8b0bce57e5..cc4630d64c 100644 --- a/include/dpp/webhook.h +++ b/include/dpp/webhook.h @@ -66,19 +66,76 @@ class DPP_EXPORT webhook : public managed, public json_interface { virtual json to_json_impl(bool with_id = false) const; public: - uint8_t type; //!< the type of the webhook - snowflake guild_id; //!< Optional: the guild id this webhook is for (may be empty) - snowflake channel_id; //!< the channel id this webhook is for (may be empty) - user user_obj; //!< Optional: the user this webhook was created by (not returned when getting a webhook with its token) - std::string name; //!< the default name of the webhook (may be empty) - utility::iconhash avatar; //!< the default avatar of the webhook (may be empty) - std::string token; //!< Optional: the secure token of the webhook (returned for Incoming Webhooks) - snowflake application_id; //!< the bot/OAuth2 application that created this webhook (may be empty) - guild source_guild; //!< the guild of the channel that this webhook is following (only for Channel Follower Webhooks) @note This will be absent if the webhook creator has since lost access to the guild where the followed channel resides! - channel source_channel; //!< the channel that this webhook is following (only for Channel Follower Webhooks) @note This will be absent if the webhook creator has since lost access to the guild where the followed channel resides! - std::string url; //!< the url used for executing the webhook (returned by the webhooks OAuth2 flow) - - std::string* image_data; //!< base64 encoded image data if uploading a new image + /** + * @brief Type of the webhook from dpp::webhook_type. + */ + uint8_t type; + + /** + * @brief The guild id this webhook is for. + * @note This field is optional, and may also be empty. + */ + snowflake guild_id; + + /** + * @brief The channel id this webhook is for. + * @note This may be empty. + */ + snowflake channel_id; + + /** + * @brief The user this webhook was created by. + * @note This field is optional. + * @warning This is not returned when getting a webhook with its token! + */ + user user_obj; + + /** + * @brief The default name of the webhook. + * @note This may be empty. + */ + std::string name; + + /** + * @brief The default avatar of the webhook + * @note This may be empty. + */ + utility::iconhash avatar; + + /** + * @brief The secure token of the webhook (returned for Incoming Webhooks). + * @note This field is optional. + */ + std::string token; + + /** + * @brief The bot/OAuth2 application that created this webhook. + * @note This may be empty. + */ + snowflake application_id; + + /** + * @brief The guild of the channel that this webhook is following (only for Channel Follower Webhooks). + * @warning This will be absent if the webhook creator has since lost access to the guild where the followed channel resides! + */ + guild source_guild; + + /** + * @brief The channel that this webhook is following (only for Channel Follower Webhooks). + * @warning This will be absent if the webhook creator has since lost access to the guild where the followed channel resides! + */ + channel source_channel; + + /** + * @brief The url used for executing the webhook (returned by the webhooks OAuth2 flow). + */ + std::string url; + + /** + * @brief base64 encoded image data if uploading a new image. + * @warning You should only ever read data from here. If you want to set the data, use dpp::webhook::load_image. + */ + std::string* image_data; /** * @brief Construct a new webhook object diff --git a/src/dpp/webhook.cpp b/src/dpp/webhook.cpp index 27adec2f33..9915a95eee 100644 --- a/src/dpp/webhook.cpp +++ b/src/dpp/webhook.cpp @@ -30,7 +30,7 @@ using json = nlohmann::json; const size_t MAX_ICON_SIZE = 256 * 1024; -webhook::webhook() : managed(), type(w_incoming), guild_id(0), channel_id(0), user_id(0), application_id(0), image_data(nullptr) +webhook::webhook() : managed(), type(w_incoming), guild_id(0), channel_id(0), application_id(0), image_data(nullptr) { } From dfb0b85d1accad8a064a6947c422e9f743b642d9 Mon Sep 17 00:00:00 2001 From: Jaskowicz1 Date: Fri, 20 Oct 2023 20:32:40 +0100 Subject: [PATCH 4/7] fix: webhook now uses utility::mime_type --- src/dpp/webhook.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/dpp/webhook.cpp b/src/dpp/webhook.cpp index 9915a95eee..97d34631e4 100644 --- a/src/dpp/webhook.cpp +++ b/src/dpp/webhook.cpp @@ -96,19 +96,13 @@ json webhook::to_json_impl(bool with_id) const { } webhook& webhook::load_image(const std::string &image_blob, const image_type type, bool is_base64_encoded) { - static const std::map mimetypes = { - { i_gif, "image/gif" }, - { i_jpg, "image/jpeg" }, - { i_png, "image/png" }, - { i_webp, "image/webp" }, - }; if (image_blob.size() > MAX_ICON_SIZE) { throw dpp::length_exception("Webhook icon file exceeds discord limit of 256 kilobytes"); } /* If there's already image data defined, free the old data, to prevent a memory leak */ delete image_data; - image_data = new std::string("data:" + mimetypes.find(type)->second + ";base64," + (is_base64_encoded ? image_blob : base64_encode((unsigned char const*)image_blob.data(), (unsigned int)image_blob.length()))); + image_data = new std::string("data:" + utility::mime_type(type) + ";base64," + (is_base64_encoded ? image_blob : base64_encode((unsigned char const*)image_blob.data(), (unsigned int)image_blob.length()))); return *this; } From f95d069156bd756d2abb82a61fe0e6ecb3075d7c Mon Sep 17 00:00:00 2001 From: Jaskowicz1 Date: Fri, 20 Oct 2023 21:20:06 +0100 Subject: [PATCH 5/7] fix: changed image_data to no longer be ptr, fixed casting --- include/dpp/webhook.h | 4 ++-- src/dpp/webhook.cpp | 12 +++--------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/include/dpp/webhook.h b/include/dpp/webhook.h index cc4630d64c..6c89306817 100644 --- a/include/dpp/webhook.h +++ b/include/dpp/webhook.h @@ -135,7 +135,7 @@ class DPP_EXPORT webhook : public managed, public json_interface { * @brief base64 encoded image data if uploading a new image. * @warning You should only ever read data from here. If you want to set the data, use dpp::webhook::load_image. */ - std::string* image_data; + std::string image_data; /** * @brief Construct a new webhook object @@ -161,7 +161,7 @@ class DPP_EXPORT webhook : public managed, public json_interface { /** * @brief Destroy the webhook object */ - ~webhook(); + virtual ~webhook() = default; /** * @brief Base64 encode image data and allocate it to image_data diff --git a/src/dpp/webhook.cpp b/src/dpp/webhook.cpp index 97d34631e4..c1141ccc1b 100644 --- a/src/dpp/webhook.cpp +++ b/src/dpp/webhook.cpp @@ -56,10 +56,6 @@ webhook::webhook(const snowflake webhook_id, const std::string& webhook_token) : id = webhook_id; } -webhook::~webhook() { - delete image_data; -} - webhook& webhook::fill_from_json_impl(nlohmann::json* j) { set_snowflake_not_null(j, "id", id); set_int8_not_null(j, "type", type); @@ -89,8 +85,8 @@ json webhook::to_json_impl(bool with_id) const { if (channel_id) { j["channel_id"] = channel_id; } - if (image_data) { - j["avatar"] = *image_data; + if (!image_data.empty()) { + j["avatar"] = image_data; } return j; } @@ -100,9 +96,7 @@ webhook& webhook::load_image(const std::string &image_blob, const image_type typ throw dpp::length_exception("Webhook icon file exceeds discord limit of 256 kilobytes"); } - /* If there's already image data defined, free the old data, to prevent a memory leak */ - delete image_data; - image_data = new std::string("data:" + utility::mime_type(type) + ";base64," + (is_base64_encoded ? image_blob : base64_encode((unsigned char const*)image_blob.data(), (unsigned int)image_blob.length()))); + image_data = "data:" + utility::mime_type(type) + ";base64," + (is_base64_encoded ? image_blob : base64_encode(reinterpret_cast(image_blob.data()), static_cast(image_blob.length()))); return *this; } From b7a3e4cc36c280906e3a4c736a74b526a555002f Mon Sep 17 00:00:00 2001 From: Jaskowicz1 Date: Fri, 20 Oct 2023 21:36:43 +0100 Subject: [PATCH 6/7] fix: no more ~webhook --- include/dpp/webhook.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/dpp/webhook.h b/include/dpp/webhook.h index 6c89306817..0593a9fcb4 100644 --- a/include/dpp/webhook.h +++ b/include/dpp/webhook.h @@ -158,11 +158,6 @@ class DPP_EXPORT webhook : public managed, public json_interface { */ webhook(const snowflake webhook_id, const std::string& webhook_token); - /** - * @brief Destroy the webhook object - */ - virtual ~webhook() = default; - /** * @brief Base64 encode image data and allocate it to image_data * From de20be159fa7108bbd2968e1b2ee9a705e9cbabb Mon Sep 17 00:00:00 2001 From: Jaskowicz1 Date: Sat, 21 Oct 2023 09:58:46 +0100 Subject: [PATCH 7/7] fix: fixed a compile issue --- src/dpp/webhook.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dpp/webhook.cpp b/src/dpp/webhook.cpp index c1141ccc1b..4b3c23a620 100644 --- a/src/dpp/webhook.cpp +++ b/src/dpp/webhook.cpp @@ -30,7 +30,7 @@ using json = nlohmann::json; const size_t MAX_ICON_SIZE = 256 * 1024; -webhook::webhook() : managed(), type(w_incoming), guild_id(0), channel_id(0), application_id(0), image_data(nullptr) +webhook::webhook() : managed(), type(w_incoming), guild_id(0), channel_id(0), application_id(0) { }