diff --git a/include/dpp/invite.h b/include/dpp/invite.h index cd5a045c97..e23592fae0 100644 --- a/include/dpp/invite.h +++ b/include/dpp/invite.h @@ -37,50 +37,54 @@ class DPP_EXPORT invite : public json_interface { */ std::string code; /** Readonly expiration timestamp of this invite or 0 if the invite doesn't expire + * @note Only returned from cluster::invite_get */ time_t expires_at; - /** Guild for the invite + /** Guild ID this invite is for */ snowflake guild_id; - /** Channel id for invite + /** Channel ID this invite is for */ snowflake channel_id; - /** User ID of invite creator + /** User ID who created this invite */ snowflake inviter_id; - /** Target user ID of invite, for invites sent via DM + /** The user ID whose stream to display for this voice channel stream invite */ snowflake target_user_id; - /** Target user type (generally this is always 1, "stream") + /** Target type */ - uint8_t target_user_type; + uint8_t target_type; /** Approximate number of online users + * @note Only returned from cluster::invite_get */ uint32_t approximate_presence_count; - /** Approximate total users online and offline + /** Approximate number of total users online and offline + * @note Only returned from cluster::invite_get */ uint32_t approximate_member_count; - /** Maximum age (in seconds) of invite + /** Duration (in seconds) after which the invite expires, or 0 for no expiration. Must be between 0 and 604800 (7 days). Defaults to 86400 (1 day) */ uint32_t max_age; - /** Maximum number of uses + /** Maximum number of uses, or 0 for unlimited. Must be between 0 and 100. Defaults to 0 */ uint32_t max_uses; - /** True if a temporary invite which grants access for a limited time + /** Whether this invite only grants temporary membership */ bool temporary; /** True if this invite should not replace or "attach to" similar invites */ bool unique; /** How many times this invite has been used - * - * @note Only set when using cluster::channel_invites_get */ uint32_t uses; /** The stage instance data if there is a public stage instance in the stage channel this invite is for * @deprecated Deprecated */ stage_instance stage; + /** Timestamp at which the invite was created + */ + time_t created_at; /** Constructor */ diff --git a/src/dpp/cluster/channel.cpp b/src/dpp/cluster/channel.cpp index 9db9995294..7faf3cba9c 100644 --- a/src/dpp/cluster/channel.cpp +++ b/src/dpp/cluster/channel.cpp @@ -76,7 +76,7 @@ void cluster::channel_get(snowflake c, command_completion_event_t callback) { } void cluster::channel_invite_create(const class channel &c, const class invite &i, command_completion_event_t callback) { - rest_request(this, API_PATH "/channels", std::to_string(c.id), "invites", m_post, i.build_json(), callback); + rest_request(this, API_PATH "/channels", std::to_string(c.id), "invites", m_post, i.build_json(), callback); } void cluster::channel_invites_get(const class channel &c, command_completion_event_t callback) { diff --git a/src/dpp/invite.cpp b/src/dpp/invite.cpp index ded29a84d7..640bf42b8f 100644 --- a/src/dpp/invite.cpp +++ b/src/dpp/invite.cpp @@ -28,18 +28,27 @@ namespace dpp { using json = nlohmann::json; -invite::invite() : expires_at(0), guild_id(0), channel_id(0), inviter_id(0), target_user_id(0), target_user_type(1), approximate_presence_count(0), approximate_member_count(0), uses(0) +invite::invite() : expires_at(0), guild_id(0), channel_id(0), inviter_id(0), target_user_id(0), target_type(0), approximate_presence_count(0), approximate_member_count(0), max_age(86400), max_uses(0), temporary(false), unique(false), uses(0), created_at(0) { } invite& invite::fill_from_json(nlohmann::json* j) { code = string_not_null(j, "code"); expires_at = (j->contains("expires_at")) ? ts_not_null(j, "expires_at") : 0; - guild_id = (j->contains("guild")) ? snowflake_not_null(&((*j)["guild"]), "id") : 0; - channel_id = (j->contains("channel")) ? snowflake_not_null(&((*j)["channel"]), "id") : 0; + created_at = (j->contains("created_at")) ? ts_not_null(j, "created_at") : 0; + if (j->contains("guild") && !j->at("guild").is_null()) { + guild_id = snowflake_not_null(&((*j)["guild"]), "id"); + } else if (j->contains("guild_id")) { // check ID for the invite create event + guild_id = snowflake_not_null(j, "guild_id"); + } + if (j->contains("channel") && !j->at("channel").is_null()) { + channel_id = snowflake_not_null(&((*j)["channel"]), "id"); + } else if (j->contains("channel_id")) { // check ID for the invite create event + channel_id = snowflake_not_null(j, "channel_id"); + } inviter_id = (j->contains("inviter")) ? snowflake_not_null(&((*j)["inviter"]), "id") : 0; target_user_id = (j->contains("target_user")) ? snowflake_not_null(&((*j)["target_user"]), "id") : 0; - target_user_type = int8_not_null(j, "target_user_type"); + target_type = int8_not_null(j, "target_type"); approximate_presence_count = int32_not_null(j, "approximate_presence_count"); approximate_member_count = int32_not_null(j, "approximate_member_count"); max_age = int32_not_null(j, "max_age"); @@ -55,14 +64,12 @@ invite& invite::fill_from_json(nlohmann::json* j) { std::string invite::build_json(bool with_id) const { json j; - if (max_age > 0) - j["max_age"] = max_age; - if (max_uses > 0) - j["max_uses"] = max_uses; + j["max_age"] = max_age; + j["max_uses"] = max_uses; if (target_user_id > 0) j["target_user"] = target_user_id; - if (target_user_type > 0) - j["target_user_type"] = target_user_type; + if (target_type > 0) + j["target_type"] = target_type; if (temporary) j["temporary"] = temporary; if (unique) diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp index 4a14bd346c..246cfbbace 100644 --- a/src/unittest/test.cpp +++ b/src/unittest/test.cpp @@ -658,6 +658,20 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b } }); + bot.on_invite_create([](const dpp::invite_create_t &event) { + auto &inv = event.created_invite; + if (!inv.code.empty() && inv.channel_id == TEST_TEXT_CHANNEL_ID && inv.guild_id == TEST_GUILD_ID && inv.created_at != 0 && inv.max_uses == 100) { + set_test("INVITE_CREATE_EVENT", true); + } + }); + + bot.on_invite_delete([](const dpp::invite_delete_t &event) { + auto &inv = event.deleted_invite; + if (!inv.code.empty() && inv.channel_id == TEST_TEXT_CHANNEL_ID && inv.guild_id == TEST_GUILD_ID) { + set_test("INVITE_DELETE_EVENT", true); + } + }); + bot.on_voice_buffer_send([&](const dpp::voice_buffer_send_t & event) { if (event.buffer_size == 0) { set_test("VOICESEND", true); @@ -963,6 +977,42 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b }); } + set_test("INVITE_CREATE", false); + set_test("INVITE_GET", false); + set_test("INVITE_DELETE", false); + if (!offline) { + dpp::channel channel; + channel.id = TEST_TEXT_CHANNEL_ID; + dpp::invite invite; + invite.max_age = 0; + invite.max_uses = 100; + set_test("INVITE_CREATE_EVENT", false); + bot.channel_invite_create(channel, invite, [&bot, invite](const dpp::confirmation_callback_t &event) { + if (event.is_error()) return; + + auto created = event.get(); + if (!created.code.empty() && created.channel_id == TEST_TEXT_CHANNEL_ID && created.guild_id == TEST_GUILD_ID && created.inviter_id != 0) { + set_test("INVITE_CREATE", true); + } + + bot.invite_get(created.code, [&bot, created](const dpp::confirmation_callback_t &event) { + if (event.is_error()) return; + + auto retrieved = event.get(); + if (retrieved.code == created.code && retrieved.expires_at == 0 && retrieved.guild_id == created.guild_id && retrieved.channel_id == created.channel_id && retrieved.inviter_id == created.inviter_id) { + set_test("INVITE_GET", true); + } + + set_test("INVITE_DELETE_EVENT", false); + bot.invite_delete(retrieved.code, [](const dpp::confirmation_callback_t &event) { + if (!event.is_error()) { + set_test("INVITE_DELETE", true); + } + }); + }); + }); + } + set_test("AUTOMOD_RULE_CREATE", false); set_test("AUTOMOD_RULE_GET", false); set_test("AUTOMOD_RULE_GET_ALL", false); diff --git a/src/unittest/unittest.cpp b/src/unittest/unittest.cpp index 15ef790a59..6313b33c37 100644 --- a/src/unittest/unittest.cpp +++ b/src/unittest/unittest.cpp @@ -142,6 +142,11 @@ std::map tests = { {"EMOJI_CREATE", {tt_online, "cluster::guild_emoji_create", false, false}}, {"EMOJI_GET", {tt_online, "cluster::guild_emoji_get", false, false}}, {"EMOJI_DELETE", {tt_online, "cluster::guild_emoji_delete", false, false}}, + {"INVITE_CREATE_EVENT", {tt_online, "cluster::on_invite_create", false, false}}, + {"INVITE_DELETE_EVENT", {tt_online, "cluster::on_invite_delete", false, false}}, + {"INVITE_CREATE", {tt_online, "cluster::channel_invite_create", false, false}}, + {"INVITE_GET", {tt_online, "cluster::invite_get", false, false}}, + {"INVITE_DELETE", {tt_online, "cluster::invite_delete", false, false}}, }; double start = dpp::utility::time_f();