summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--abaddon.cpp37
-rw-r--r--abaddon.hpp5
-rw-r--r--dialogs/verificationgate.cpp51
-rw-r--r--dialogs/verificationgate.hpp22
-rw-r--r--discord/channel.hpp3
-rw-r--r--discord/discord.cpp71
-rw-r--r--discord/discord.hpp23
-rw-r--r--discord/guild.cpp17
-rw-r--r--discord/guild.hpp22
-rw-r--r--discord/objects.cpp49
-rw-r--r--discord/objects.hpp42
-rw-r--r--discord/store.cpp2
12 files changed, 332 insertions, 12 deletions
diff --git a/abaddon.cpp b/abaddon.cpp
index 4a32b5d..233b22e 100644
--- a/abaddon.cpp
+++ b/abaddon.cpp
@@ -9,6 +9,7 @@
#include "dialogs/confirm.hpp"
#include "dialogs/setstatus.hpp"
#include "dialogs/friendpicker.hpp"
+#include "dialogs/verificationgate.hpp"
#include "abaddon.hpp"
#include "windows/guildsettingswindow.hpp"
#include "windows/profilewindow.hpp"
@@ -40,6 +41,7 @@ Abaddon::Abaddon()
m_discord.signal_guild_update().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnGuildUpdate));
m_discord.signal_reaction_add().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnReactionAdd));
m_discord.signal_reaction_remove().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnReactionRemove));
+ m_discord.signal_guild_join_request_create().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnGuildJoinRequestCreate));
m_discord.signal_disconnected().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnDisconnect));
if (m_settings.GetPrefetch())
m_discord.signal_message_create().connect([this](Snowflake id) {
@@ -185,8 +187,8 @@ void Abaddon::DiscordOnGuildMemberListUpdate(Snowflake guild_id) {
m_main_window->UpdateMembers();
}
-void Abaddon::DiscordOnGuildCreate(Snowflake guild_id) {
- m_main_window->UpdateChannelsNewGuild(guild_id);
+void Abaddon::DiscordOnGuildCreate(const GuildData &guild) {
+ m_main_window->UpdateChannelsNewGuild(guild.ID);
}
void Abaddon::DiscordOnGuildDelete(Snowflake guild_id) {
@@ -217,6 +219,13 @@ void Abaddon::DiscordOnReactionRemove(Snowflake message_id, const Glib::ustring
m_main_window->UpdateChatReactionAdd(message_id, param);
}
+// this will probably cause issues when actual applications are rolled out but that doesn't seem like it will happen for a while
+void Abaddon::DiscordOnGuildJoinRequestCreate(const GuildJoinRequestCreateData &data) {
+ if (data.Status == GuildApplicationStatus::STARTED) {
+ ShowGuildVerificationGateDialog(data.GuildID);
+ }
+}
+
void Abaddon::DiscordOnDisconnect(bool is_reconnecting, GatewayCloseCode close_code) {
m_main_window->UpdateComponents();
if (close_code == GatewayCloseCode::AuthenticationFailed) {
@@ -287,6 +296,19 @@ void Abaddon::ShowUserMenu(const GdkEvent *event, Snowflake id, Snowflake guild_
m_user_menu->popup_at_pointer(event);
}
+void Abaddon::ShowGuildVerificationGateDialog(Snowflake guild_id) {
+ VerificationGateDialog dlg(*m_main_window, guild_id);
+ if (dlg.run() == Gtk::RESPONSE_OK) {
+ const auto cb = [this](bool success) {
+ if (!success) {
+ Gtk::MessageDialog dlg(*m_main_window, "Failed to accept the verification gate.", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
+ dlg.run();
+ }
+ };
+ m_discord.AcceptVerificationGate(guild_id, dlg.GetVerificationGate(), cb);
+ }
+}
+
void Abaddon::SetupUserMenu() {
m_user_menu = Gtk::manage(new Gtk::Menu);
m_user_menu_insert_mention = Gtk::manage(new Gtk::MenuItem("Insert Mention"));
@@ -417,9 +439,6 @@ void Abaddon::ActionChannelOpened(Snowflake id) {
if (id == m_main_window->GetChatActiveChannel()) return;
const auto channel = m_discord.GetChannel(id);
- if (channel->Type != ChannelType::DM && channel->Type != ChannelType::GROUP_DM)
- m_discord.SendLazyLoad(id);
-
if (channel->Type == ChannelType::GUILD_TEXT || channel->Type == ChannelType::GUILD_NEWS)
m_main_window->set_title(std::string(APP_TITLE) + " - #" + *channel->Name);
else {
@@ -445,6 +464,14 @@ void Abaddon::ActionChannelOpened(Snowflake id) {
} else {
m_main_window->UpdateChatWindowContents();
}
+
+ if (channel->Type != ChannelType::DM && channel->Type != ChannelType::GROUP_DM) {
+ m_discord.SendLazyLoad(id);
+
+ const auto request = m_discord.GetGuildApplication(*channel->GuildID);
+ if (request.has_value() && request->ApplicationStatus == GuildApplicationStatus::STARTED)
+ ShowGuildVerificationGateDialog(*channel->GuildID);
+ }
}
void Abaddon::ActionChatLoadHistory(Snowflake id) {
diff --git a/abaddon.hpp b/abaddon.hpp
index 0799ed3..8415bb7 100644
--- a/abaddon.hpp
+++ b/abaddon.hpp
@@ -66,7 +66,7 @@ public:
void DiscordOnMessageDelete(Snowflake id, Snowflake channel_id);
void DiscordOnMessageUpdate(Snowflake id, Snowflake channel_id);
void DiscordOnGuildMemberListUpdate(Snowflake guild_id);
- void DiscordOnGuildCreate(Snowflake guild_id);
+ void DiscordOnGuildCreate(const GuildData &guild);
void DiscordOnGuildDelete(Snowflake guild_id);
void DiscordOnChannelDelete(Snowflake channel_id);
void DiscordOnChannelUpdate(Snowflake channel_id);
@@ -74,6 +74,7 @@ public:
void DiscordOnGuildUpdate(Snowflake guild_id);
void DiscordOnReactionAdd(Snowflake message_id, const Glib::ustring &param);
void DiscordOnReactionRemove(Snowflake message_id, const Glib::ustring &param);
+ void DiscordOnGuildJoinRequestCreate(const GuildJoinRequestCreateData &data);
void DiscordOnDisconnect(bool is_reconnecting, GatewayCloseCode close_code);
const SettingsManager &GetSettings() const;
@@ -83,6 +84,8 @@ public:
void ShowUserMenu(const GdkEvent *event, Snowflake id, Snowflake guild_id);
protected:
+ void ShowGuildVerificationGateDialog(Snowflake guild_id);
+
void SetupUserMenu();
void ManageHeapWindow(Gtk::Window *window);
diff --git a/dialogs/verificationgate.cpp b/dialogs/verificationgate.cpp
new file mode 100644
index 0000000..bd034f2
--- /dev/null
+++ b/dialogs/verificationgate.cpp
@@ -0,0 +1,51 @@
+#include "verificationgate.hpp"
+#include "../../abaddon.hpp"
+
+VerificationGateDialog::VerificationGateDialog(Gtk::Window &parent, Snowflake guild_id)
+ : Gtk::Dialog("Verification Required", parent, true)
+ , m_bbox(Gtk::ORIENTATION_HORIZONTAL) {
+ set_default_size(300, 300);
+ get_style_context()->add_class("app-window");
+ get_style_context()->add_class("app-popup");
+
+ m_ok_button = add_button("Accept", Gtk::RESPONSE_OK);
+
+ m_scroll_rules.set_vexpand(true);
+ m_scroll_rules.set_hexpand(true);
+
+ m_description.set_line_wrap(true);
+ m_description.set_line_wrap_mode(Pango::WRAP_WORD_CHAR);
+ m_description.set_halign(Gtk::ALIGN_CENTER);
+ m_description.set_margin_bottom(5);
+
+ m_scroll_rules.add(m_rules);
+ get_content_area()->add(m_description);
+ get_content_area()->add(m_scroll_rules);
+ show_all_children();
+
+ Abaddon::Get().GetDiscordClient().GetVerificationGateInfo(guild_id, sigc::mem_fun(*this, &VerificationGateDialog::OnVerificationGateFetch));
+}
+
+const VerificationGateInfoObject &VerificationGateDialog::GetVerificationGate() const {
+ return m_gate_info;
+}
+
+void VerificationGateDialog::OnVerificationGateFetch(const std::optional<VerificationGateInfoObject> &info) {
+ m_gate_info = *info;
+ if (m_gate_info.Description.has_value())
+ m_description.set_markup("<b>" + Glib::Markup::escape_text(*m_gate_info.Description) + "</b>");
+ else
+ m_description.hide();
+ for (const auto &field : *info->VerificationFields) {
+ if (field.Type == "TERMS") {
+ for (const auto &rule : field.Values) {
+ auto *lbl = Gtk::manage(new Gtk::Label(rule));
+ lbl->set_halign(Gtk::ALIGN_START);
+ lbl->set_ellipsize(Pango::ELLIPSIZE_END);
+ lbl->show();
+ m_rules.add(*lbl);
+ }
+ break;
+ }
+ }
+}
diff --git a/dialogs/verificationgate.hpp b/dialogs/verificationgate.hpp
new file mode 100644
index 0000000..31152b9
--- /dev/null
+++ b/dialogs/verificationgate.hpp
@@ -0,0 +1,22 @@
+#pragma once
+#include <gtkmm.h>
+#include <optional>
+#include "../../discord/objects.hpp"
+
+class VerificationGateDialog : public Gtk::Dialog {
+public:
+ VerificationGateDialog(Gtk::Window &parent, Snowflake guild_id);
+ const VerificationGateInfoObject &GetVerificationGate() const;
+
+protected:
+ void OnVerificationGateFetch(const std::optional<VerificationGateInfoObject> &info);
+
+ VerificationGateInfoObject m_gate_info;
+
+ Gtk::Label m_description;
+ Gtk::ScrolledWindow m_scroll_rules;
+ Gtk::ListBox m_rules;
+ Gtk::ButtonBox m_bbox;
+
+ Gtk::Button *m_ok_button;
+};
diff --git a/discord/channel.hpp b/discord/channel.hpp
index 7b0cf50..4f93569 100644
--- a/discord/channel.hpp
+++ b/discord/channel.hpp
@@ -14,6 +14,9 @@ enum class ChannelType : int {
GUILD_CATEGORY = 4,
GUILD_NEWS = 5,
GUILD_STORE = 6,
+ PUBLIC_THREAD = 11,
+ PRIVATE_THREAD = 12,
+ GUILD_STAGE_VOICE = 13,
};
struct ChannelData {
diff --git a/discord/discord.cpp b/discord/discord.cpp
index a16a119..6d481d2 100644
--- a/discord/discord.cpp
+++ b/discord/discord.cpp
@@ -631,6 +631,12 @@ void DiscordClient::DeleteEmoji(Snowflake guild_id, Snowflake emoji_id, sigc::sl
});
}
+std::optional<GuildApplicationData> DiscordClient::GetGuildApplication(Snowflake guild_id) const {
+ const auto it = m_guild_join_requests.find(guild_id);
+ if (it == m_guild_join_requests.end()) return std::nullopt;
+ return it->second;
+}
+
bool DiscordClient::CanModifyRole(Snowflake guild_id, Snowflake role_id, Snowflake user_id) const {
const auto guild = *GetGuild(guild_id);
if (guild.OwnerID == user_id) return true;
@@ -753,6 +759,23 @@ void DiscordClient::FetchUserRelationships(Snowflake user_id, sigc::slot<void(st
});
}
+void DiscordClient::GetVerificationGateInfo(Snowflake guild_id, sigc::slot<void(std::optional<VerificationGateInfoObject>)> callback) {
+ m_http.MakeGET("/guilds/" + std::to_string(guild_id) + "/member-verification", [this, callback](const http::response_type &response) {
+ if (!CheckCode(response)) return;
+ if (response.status_code == 204) callback(std::nullopt);
+ callback(nlohmann::json::parse(response.text).get<VerificationGateInfoObject>());
+ });
+}
+
+void DiscordClient::AcceptVerificationGate(Snowflake guild_id, VerificationGateInfoObject info, sigc::slot<void(bool success)> callback) {
+ if (info.VerificationFields.has_value())
+ for (auto &field : *info.VerificationFields)
+ field.Response = true;
+ m_http.MakePUT("/guilds/" + std::to_string(guild_id) + "/requests/@me", nlohmann::json(info).dump(), [this, callback](const http::response_type &response) {
+ callback(CheckCode(response));
+ });
+}
+
void DiscordClient::UpdateToken(std::string token) {
if (!IsStarted()) {
m_token = token;
@@ -949,6 +972,15 @@ void DiscordClient::HandleGatewayMessage(std::string str) {
case GatewayEvent::GUILD_EMOJIS_UPDATE: {
HandleGatewayGuildEmojisUpdate(m);
} break;
+ case GatewayEvent::GUILD_JOIN_REQUEST_CREATE: {
+ HandleGatewayGuildJoinRequestCreate(m);
+ } break;
+ case GatewayEvent::GUILD_JOIN_REQUEST_UPDATE: {
+ HandleGatewayGuildJoinRequestUpdate(m);
+ } break;
+ case GatewayEvent::GUILD_JOIN_REQUEST_DELETE: {
+ HandleGatewayGuildJoinRequestDelete(m);
+ } break;
}
} break;
default:
@@ -1033,6 +1065,10 @@ void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) {
for (const auto &relationship : *data.Relationships)
m_user_relationships[relationship.ID] = relationship.Type;
+ if (data.GuildJoinRequests.has_value())
+ for (const auto &request : *data.GuildJoinRequests)
+ m_guild_join_requests[request.GuildID] = request;
+
m_store.EndTransaction();
m_session_id = data.SessionID;
@@ -1361,6 +1397,24 @@ void DiscordClient::HandleGatewayGuildEmojisUpdate(const GatewayMessage &msg) {
FetchGuildEmojis(data.GuildID, cb);
}
+void DiscordClient::HandleGatewayGuildJoinRequestCreate(const GatewayMessage &msg) {
+ GuildJoinRequestCreateData data = msg.Data;
+ m_guild_join_requests[data.GuildID] = data.Request;
+ m_signal_guild_join_request_create.emit(data);
+}
+
+void DiscordClient::HandleGatewayGuildJoinRequestUpdate(const GatewayMessage &msg) {
+ GuildJoinRequestUpdateData data = msg.Data;
+ m_guild_join_requests[data.GuildID] = data.Request;
+ m_signal_guild_join_request_update.emit(data);
+}
+
+void DiscordClient::HandleGatewayGuildJoinRequestDelete(const GatewayMessage &msg) {
+ GuildJoinRequestDeleteData data = msg.Data;
+ m_guild_join_requests.erase(data.GuildID);
+ m_signal_guild_join_request_delete.emit(data);
+}
+
void DiscordClient::HandleGatewayReadySupplemental(const GatewayMessage &msg) {
ReadySupplementalData data = msg.Data;
for (const auto &p : data.MergedPresences.Friends) {
@@ -1478,7 +1532,7 @@ void DiscordClient::HandleGatewayGuildCreate(const GatewayMessage &msg) {
GuildData data = msg.Data;
ProcessNewGuild(data);
- m_signal_guild_create.emit(data.ID);
+ m_signal_guild_create.emit(data);
}
void DiscordClient::HandleGatewayGuildDelete(const GatewayMessage &msg) {
@@ -1682,6 +1736,9 @@ void DiscordClient::LoadEventMap() {
m_event_map["USER_NOTE_UPDATE"] = GatewayEvent::USER_NOTE_UPDATE;
m_event_map["READY_SUPPLEMENTAL"] = GatewayEvent::READY_SUPPLEMENTAL;
m_event_map["GUILD_EMOJIS_UPDATE"] = GatewayEvent::GUILD_EMOJIS_UPDATE;
+ m_event_map["GUILD_JOIN_REQUEST_CREATE"] = GatewayEvent::GUILD_JOIN_REQUEST_CREATE;
+ m_event_map["GUILD_JOIN_REQUEST_UPDATE"] = GatewayEvent::GUILD_JOIN_REQUEST_UPDATE;
+ m_event_map["GUILD_JOIN_REQUEST_DELETE"] = GatewayEvent::GUILD_JOIN_REQUEST_DELETE;
}
DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() {
@@ -1791,3 +1848,15 @@ DiscordClient::type_signal_note_update DiscordClient::signal_note_update() {
DiscordClient::type_signal_guild_emojis_update DiscordClient::signal_guild_emojis_update() {
return m_signal_guild_emojis_update;
}
+
+DiscordClient::type_signal_guild_join_request_create DiscordClient::signal_guild_join_request_create() {
+ return m_signal_guild_join_request_create;
+}
+
+DiscordClient::type_signal_guild_join_request_update DiscordClient::signal_guild_join_request_update() {
+ return m_signal_guild_join_request_update;
+}
+
+DiscordClient::type_signal_guild_join_request_delete DiscordClient::signal_guild_join_request_delete() {
+ return m_signal_guild_join_request_delete;
+}
diff --git a/discord/discord.hpp b/discord/discord.hpp
index 476adc8..fbcdb5f 100644
--- a/discord/discord.hpp
+++ b/discord/discord.hpp
@@ -131,6 +131,7 @@ public:
void ModifyRolePosition(Snowflake guild_id, Snowflake role_id, int position, sigc::slot<void(bool success)> callback);
void ModifyEmojiName(Snowflake guild_id, Snowflake emoji_id, const Glib::ustring &name, sigc::slot<void(bool success)> callback);
void DeleteEmoji(Snowflake guild_id, Snowflake emoji_id, sigc::slot<void(bool success)> callback);
+ std::optional<GuildApplicationData> GetGuildApplication(Snowflake guild_id) const;
bool CanModifyRole(Snowflake guild_id, Snowflake role_id) const;
bool CanModifyRole(Snowflake guild_id, Snowflake role_id, Snowflake user_id) const;
@@ -163,6 +164,9 @@ public:
void SetUserNote(Snowflake user_id, std::string note, sigc::slot<void(bool success)> callback);
void FetchUserRelationships(Snowflake user_id, sigc::slot<void(std::vector<UserData>)> callback);
+ void GetVerificationGateInfo(Snowflake guild_id, sigc::slot<void(std::optional<VerificationGateInfoObject>)> callback);
+ void AcceptVerificationGate(Snowflake guild_id, VerificationGateInfoObject info, sigc::slot<void(bool success)> callback);
+
void UpdateToken(std::string token);
void SetUserAgent(std::string agent);
@@ -209,6 +213,9 @@ private:
void HandleGatewayInviteDelete(const GatewayMessage &msg);
void HandleGatewayUserNoteUpdate(const GatewayMessage &msg);
void HandleGatewayGuildEmojisUpdate(const GatewayMessage &msg);
+ void HandleGatewayGuildJoinRequestCreate(const GatewayMessage &msg);
+ void HandleGatewayGuildJoinRequestUpdate(const GatewayMessage &msg);
+ void HandleGatewayGuildJoinRequestDelete(const GatewayMessage &msg);
void HandleGatewayReadySupplemental(const GatewayMessage &msg);
void HandleGatewayReconnect(const GatewayMessage &msg);
void HandleGatewayInvalidSession(const GatewayMessage &msg);
@@ -233,6 +240,7 @@ private:
std::unordered_map<Snowflake, std::unordered_set<Snowflake>> m_guild_to_users;
std::unordered_map<Snowflake, std::unordered_set<Snowflake>> m_guild_to_channels;
+ std::unordered_map<Snowflake, GuildApplicationData> m_guild_join_requests;
std::unordered_map<Snowflake, PresenceStatus> m_user_to_status;
@@ -275,7 +283,7 @@ public:
typedef sigc::signal<void, Snowflake, Snowflake> type_signal_message_delete;
typedef sigc::signal<void, Snowflake, Snowflake> type_signal_message_update;
typedef sigc::signal<void, Snowflake> type_signal_guild_member_list_update;
- typedef sigc::signal<void, Snowflake> type_signal_guild_create;
+ typedef sigc::signal<void, GuildData> type_signal_guild_create;
typedef sigc::signal<void, Snowflake> type_signal_guild_delete;
typedef sigc::signal<void, Snowflake> type_signal_channel_delete;
typedef sigc::signal<void, Snowflake> type_signal_channel_update;
@@ -295,7 +303,10 @@ public:
typedef sigc::signal<void, Snowflake, PresenceStatus> type_signal_presence_update;
typedef sigc::signal<void, Snowflake, std::string> type_signal_note_update;
typedef sigc::signal<void, Snowflake, std::vector<EmojiData>> type_signal_guild_emojis_update; // guild id
- typedef sigc::signal<void, bool, GatewayCloseCode> type_signal_disconnected; // bool true if reconnecting
+ typedef sigc::signal<void, GuildJoinRequestCreateData> type_signal_guild_join_request_create;
+ typedef sigc::signal<void, GuildJoinRequestUpdateData> type_signal_guild_join_request_update;
+ typedef sigc::signal<void, GuildJoinRequestDeleteData> type_signal_guild_join_request_delete;
+ typedef sigc::signal<void, bool, GatewayCloseCode> type_signal_disconnected; // bool true if reconnecting
typedef sigc::signal<void> type_signal_connected;
type_signal_gateway_ready signal_gateway_ready();
@@ -303,7 +314,7 @@ public:
type_signal_message_delete signal_message_delete();
type_signal_message_update signal_message_update();
type_signal_guild_member_list_update signal_guild_member_list_update();
- type_signal_guild_create signal_guild_create();
+ type_signal_guild_create signal_guild_create(); // structs are complete in this signal
type_signal_guild_delete signal_guild_delete();
type_signal_channel_delete signal_channel_delete();
type_signal_channel_update signal_channel_update();
@@ -323,6 +334,9 @@ public:
type_signal_presence_update signal_presence_update();
type_signal_note_update signal_note_update();
type_signal_guild_emojis_update signal_guild_emojis_update();
+ type_signal_guild_join_request_create signal_guild_join_request_create();
+ type_signal_guild_join_request_update signal_guild_join_request_update();
+ type_signal_guild_join_request_delete signal_guild_join_request_delete();
type_signal_disconnected signal_disconnected();
type_signal_connected signal_connected();
@@ -352,6 +366,9 @@ protected:
type_signal_presence_update m_signal_presence_update;
type_signal_note_update m_signal_note_update;
type_signal_guild_emojis_update m_signal_guild_emojis_update;
+ type_signal_guild_join_request_create m_signal_guild_join_request_create;
+ type_signal_guild_join_request_update m_signal_guild_join_request_update;
+ type_signal_guild_join_request_delete m_signal_guild_join_request_delete;
type_signal_disconnected m_signal_disconnected;
type_signal_connected m_signal_connected;
};
diff --git a/discord/guild.cpp b/discord/guild.cpp
index 5fb524e..d387729 100644
--- a/discord/guild.cpp
+++ b/discord/guild.cpp
@@ -197,3 +197,20 @@ std::vector<RoleData> GuildData::FetchRoles() const {
});
return ret;
}
+
+void from_json(const nlohmann::json &j, GuildApplicationData &m) {
+ JS_D("user_id", m.UserID);
+ JS_D("guild_id", m.GuildID);
+ auto tmp = j.at("application_status").get<std::string_view>();
+ if (tmp == "STARTED")
+ m.ApplicationStatus = GuildApplicationStatus::STARTED;
+ else if (tmp == "PENDING")
+ m.ApplicationStatus = GuildApplicationStatus::PENDING;
+ else if (tmp == "REJECTED")
+ m.ApplicationStatus = GuildApplicationStatus::REJECTED;
+ else if (tmp == "APPROVED")
+ m.ApplicationStatus = GuildApplicationStatus::APPROVED;
+ JS_N("rejection_reason", m.RejectionReason);
+ JS_N("last_seen", m.LastSeen);
+ JS_N("created_at", m.CreatedAt);
+}
diff --git a/discord/guild.hpp b/discord/guild.hpp
index c2d7333..a57bc15 100644
--- a/discord/guild.hpp
+++ b/discord/guild.hpp
@@ -6,6 +6,26 @@
#include "emoji.hpp"
#include <vector>
#include <string>
+#include <unordered_set>
+
+enum class GuildApplicationStatus {
+ STARTED,
+ PENDING,
+ REJECTED,
+ APPROVED,
+ UNKNOWN,
+};
+
+struct GuildApplicationData {
+ Snowflake UserID;
+ Snowflake GuildID;
+ GuildApplicationStatus ApplicationStatus;
+ std::optional<std::string> RejectionReason;
+ std::optional<std::string> LastSeen;
+ std::optional<std::string> CreatedAt;
+
+ friend void from_json(const nlohmann::json &j, GuildApplicationData &m);
+};
// a bot is apparently only supposed to receive the `id` and `unavailable` as false
// but user tokens seem to get the full objects (minus users)
@@ -32,7 +52,7 @@ struct GuildData {
std::optional<int> ExplicitContentFilter;
std::optional<std::vector<RoleData>> Roles; // only access id
std::optional<std::vector<EmojiData>> Emojis; // only access id
- std::optional<std::vector<std::string>> Features;
+ std::optional<std::unordered_set<std::string>> Features;
std::optional<int> MFALevel;
std::optional<Snowflake> ApplicationID; // null
std::optional<bool> IsWidgetEnabled;
diff --git a/discord/objects.cpp b/discord/objects.cpp
index 3aef9ee..7d44ece 100644
--- a/discord/objects.cpp
+++ b/discord/objects.cpp
@@ -125,6 +125,7 @@ void from_json(const nlohmann::json &j, ReadyEventData &m) {
JS_O("users", m.Users);
JS_ON("merged_members", m.MergedMembers);
JS_O("relationships", m.Relationships);
+ JS_O("guild_join_requests", m.GuildJoinRequests);
}
void from_json(const nlohmann::json &j, MergedPresence &m) {
@@ -394,3 +395,51 @@ void from_json(const nlohmann::json &j, GuildEmojisUpdateObject &m) {
void to_json(nlohmann::json &j, const ModifyGuildEmojiObject &m) {
JS_IF("name", m.Name);
}
+
+void from_json(const nlohmann::json &j, GuildJoinRequestCreateData &m) {
+ auto tmp = j.at("status").get<std::string_view>();
+ if (tmp == "STARTED")
+ m.Status = GuildApplicationStatus::STARTED;
+ else if (tmp == "PENDING")
+ m.Status = GuildApplicationStatus::PENDING;
+ else if (tmp == "REJECTED")
+ m.Status = GuildApplicationStatus::REJECTED;
+ else if (tmp == "APPROVED")
+ m.Status = GuildApplicationStatus::APPROVED;
+ JS_D("request", m.Request);
+ JS_D("guild_id", m.GuildID);
+}
+
+void from_json(const nlohmann::json &j, GuildJoinRequestDeleteData &m) {
+ JS_D("user_id", m.UserID);
+ JS_D("guild_id", m.GuildID);
+}
+
+void from_json(const nlohmann::json &j, VerificationFieldObject &m) {
+ JS_D("field_type", m.Type);
+ JS_D("label", m.Label);
+ JS_D("required", m.Required);
+ JS_D("values", m.Values);
+}
+
+void from_json(const nlohmann::json &j, VerificationGateInfoObject &m) {
+ JS_O("description", m.Description);
+ JS_O("form_fields", m.VerificationFields);
+ JS_O("version", m.Version);
+ JS_O("enabled", m.Enabled);
+}
+
+void to_json(nlohmann::json &j, const VerificationFieldObject &m) {
+ j["field_type"] = m.Type;
+ j["label"] = m.Label;
+ j["required"] = m.Required;
+ j["values"] = m.Values;
+ JS_IF("response", m.Response);
+}
+
+void to_json(nlohmann::json &j, const VerificationGateInfoObject &m) {
+ JS_IF("description", m.Description);
+ JS_IF("form_fields", m.VerificationFields);
+ JS_IF("version", m.Version);
+ JS_IF("enabled", m.Enabled);
+}
diff --git a/discord/objects.hpp b/discord/objects.hpp
index 88cac21..bad9fd4 100644
--- a/discord/objects.hpp
+++ b/discord/objects.hpp
@@ -65,6 +65,9 @@ enum class GatewayEvent : int {
USER_NOTE_UPDATE,
READY_SUPPLEMENTAL,
GUILD_EMOJIS_UPDATE,
+ GUILD_JOIN_REQUEST_CREATE,
+ GUILD_JOIN_REQUEST_UPDATE,
+ GUILD_JOIN_REQUEST_DELETE,
};
enum class GatewayCloseCode : uint16_t {
@@ -206,6 +209,7 @@ struct ReadyEventData {
UserSettings Settings;
std::optional<std::vector<std::vector<GuildMember>>> MergedMembers;
std::optional<std::vector<RelationshipData>> Relationships;
+ std::optional<std::vector<GuildApplicationData>> GuildJoinRequests;
// std::vector<Unknown> ConnectedAccounts; // opt
// std::map<std::string, Unknown> Consents; // opt
// std::vector<Unknown> Experiments; // opt
@@ -555,3 +559,41 @@ struct ModifyGuildEmojiObject {
friend void to_json(nlohmann::json &j, const ModifyGuildEmojiObject &m);
};
+
+struct GuildJoinRequestCreateData {
+ GuildApplicationStatus Status;
+ GuildApplicationData Request;
+ Snowflake GuildID;
+
+ friend void from_json(const nlohmann::json &j, GuildJoinRequestCreateData &m);
+};
+
+using GuildJoinRequestUpdateData = GuildJoinRequestCreateData;
+
+struct GuildJoinRequestDeleteData {
+ Snowflake UserID;
+ Snowflake GuildID;
+
+ friend void from_json(const nlohmann::json &j, GuildJoinRequestDeleteData &m);
+};
+
+struct VerificationFieldObject {
+ std::string Type;
+ std::string Label;
+ bool Required;
+ std::vector<std::string> Values;
+ std::optional<bool> Response; // present in client to server
+
+ friend void from_json(const nlohmann::json &j, VerificationFieldObject &m);
+ friend void to_json(nlohmann::json &j, const VerificationFieldObject &m);
+};
+
+struct VerificationGateInfoObject {
+ std::optional<std::string> Description;
+ std::optional<std::vector<VerificationFieldObject>> VerificationFields;
+ std::optional<std::string> Version;
+ std::optional<bool> Enabled; // present only in client to server in modify gate
+
+ friend void from_json(const nlohmann::json &j, VerificationGateInfoObject &m);
+ friend void to_json(nlohmann::json &j, const VerificationGateInfoObject &m);
+};
diff --git a/discord/store.cpp b/discord/store.cpp
index 44af4cd..6dcaabb 100644
--- a/discord/store.cpp
+++ b/discord/store.cpp
@@ -449,7 +449,7 @@ std::optional<GuildData> Store::GetGuild(Snowflake id) const {
for (const auto &id : nlohmann::json::parse(tmp).get<std::vector<Snowflake>>())
ret.Emojis->emplace_back().ID = id;
Get(m_get_guild_stmt, 14, tmp);
- ret.Features = nlohmann::json::parse(tmp).get<std::vector<std::string>>();
+ ret.Features = nlohmann::json::parse(tmp).get<std::unordered_set<std::string>>();
Get(m_get_guild_stmt, 15, ret.MFALevel);
Get(m_get_guild_stmt, 16, ret.ApplicationID);
Get(m_get_guild_stmt, 17, ret.IsWidgetEnabled);