From a51a54bc5979a2491f152abc47ad54e6b63f27c8 Mon Sep 17 00:00:00 2001 From: Dylam De La Torre Date: Tue, 23 Nov 2021 05:21:56 +0100 Subject: Restructure source and resource files (#46) importantly, res is now res/res and css is now res/css --- src/discord/guild.cpp | 221 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 src/discord/guild.cpp (limited to 'src/discord/guild.cpp') diff --git a/src/discord/guild.cpp b/src/discord/guild.cpp new file mode 100644 index 0000000..a02b896 --- /dev/null +++ b/src/discord/guild.cpp @@ -0,0 +1,221 @@ +#include "guild.hpp" +#include "abaddon.hpp" + +void from_json(const nlohmann::json &j, GuildData &m) { + JS_D("id", m.ID); + if (j.contains("unavailable")) { + m.IsUnavailable = true; + return; + } + + JS_D("name", m.Name); + JS_N("icon", m.Icon); + JS_N("splash", m.Splash); + JS_ON("discovery_splash", m.DiscoverySplash); + JS_O("owner", m.IsOwner); + JS_O("owner_id", m.OwnerID); + std::optional tmp; + JS_O("permissions", tmp); + if (tmp.has_value()) + m.Permissions = std::stoull(*tmp); + JS_O("region", m.VoiceRegion); + JS_ON("afk_channel_id", m.AFKChannelID); + JS_O("afk_timeout", m.AFKTimeout); + JS_O("embed_enabled", m.IsEmbedEnabled); + JS_ON("embed_channel_id", m.EmbedChannelID); + JS_O("verification_level", m.VerificationLevel); + JS_O("default_message_notifications", m.DefaultMessageNotifications); + JS_O("explicit_content_filter", m.ExplicitContentFilter); + JS_O("roles", m.Roles); + JS_O("emojis", m.Emojis); + JS_O("features", m.Features); + JS_O("mfa_level", m.MFALevel); + JS_ON("application_id", m.ApplicationID); + JS_O("widget_enabled", m.IsWidgetEnabled); + JS_ON("widget_channel_id", m.WidgetChannelID); + JS_ON("system_channel_id", m.SystemChannelID); + JS_O("system_channel_flags", m.SystemChannelFlags); + JS_ON("rules_channel_id", m.RulesChannelID); + JS_O("joined_at", m.JoinedAt); + JS_O("large", m.IsLarge); + JS_O("unavailable", m.IsUnavailable); + JS_O("member_count", m.MemberCount); + // JS_O("voice_states", m.VoiceStates); + // JS_O("members", m.Members); + JS_O("channels", m.Channels); + JS_O("threads", m.Threads); + // JS_O("presences", m.Presences); + JS_ON("max_presences", m.MaxPresences); + JS_O("max_members", m.MaxMembers); + JS_ON("vanity_url_code", m.VanityURL); + JS_ON("description", m.Description); + JS_ON("banner", m.BannerHash); + JS_O("premium_tier", m.PremiumTier); + JS_O("premium_subscription_count", m.PremiumSubscriptionCount); + JS_O("preferred_locale", m.PreferredLocale); + JS_ON("public_updates_channel_id", m.PublicUpdatesChannelID); + JS_O("max_video_channel_users", m.MaxVideoChannelUsers); + JS_O("approximate_member_count", tmp); + if (tmp.has_value()) + m.ApproximateMemberCount = std::stol(*tmp); + JS_O("approximate_presence_count", tmp); + if (tmp.has_value()) + m.ApproximatePresenceCount = std::stol(*tmp); +} + +void GuildData::update_from_json(const nlohmann::json &j) { + if (j.contains("unavailable")) { + IsUnavailable = true; + return; + } + + JS_RD("name", Name); + JS_RD("icon", Icon); + JS_RD("splash", Splash); + JS_RD("discovery_splash", DiscoverySplash); + JS_RD("owner", IsOwner); + JS_RD("owner_id", OwnerID); + std::string tmp; + JS_RD("permissions", tmp); + if (tmp != "") + Permissions = std::stoull(tmp); + JS_RD("region", VoiceRegion); + JS_RD("afk_channel_id", AFKChannelID); + JS_RD("afk_timeout", AFKTimeout); + JS_RD("embed_enabled", IsEmbedEnabled); + JS_RD("embed_channel_id", EmbedChannelID); + JS_RD("verification_level", VerificationLevel); + JS_RD("default_message_notifications", DefaultMessageNotifications); + JS_RD("explicit_content_filter", ExplicitContentFilter); + JS_RD("roles", Roles); + JS_RD("emojis", Emojis); + JS_RD("features", Features); + JS_RD("mfa_level", MFALevel); + JS_RD("application_id", ApplicationID); + JS_RD("widget_enabled", IsWidgetEnabled); + JS_RD("widget_channel_id", WidgetChannelID); + JS_RD("system_channel_id", SystemChannelID); + JS_RD("system_channel_flags", SystemChannelFlags); + JS_RD("rules_channel_id", RulesChannelID); + JS_RD("joined_at", JoinedAt); + JS_RD("large", IsLarge); + JS_RD("unavailable", IsUnavailable); + JS_RD("member_count", MemberCount); + // JS_O("voice_states", m.VoiceStates); + // JS_O("members", m.Members); + JS_RD("channels", Channels); + // JS_O("presences", m.Presences); + JS_RD("max_presences", MaxPresences); + JS_RD("max_members", MaxMembers); + JS_RD("vanity_url_code", VanityURL); + JS_RD("description", Description); + JS_RD("banner", BannerHash); + JS_RD("premium_tier", PremiumTier); + JS_RD("premium_subscription_count", PremiumSubscriptionCount); + JS_RD("preferred_locale", PreferredLocale); + JS_RD("public_updates_channel_id", PublicUpdatesChannelID); + JS_RD("max_video_channel_users", MaxVideoChannelUsers); + JS_RD("approximate_member_count", ApproximateMemberCount); + JS_RD("approximate_presence_count", ApproximatePresenceCount); +} + +bool GuildData::HasFeature(const std::string &search_feature) { + if (!Features.has_value()) return false; + for (const auto &feature : *Features) + if (search_feature == feature) + return true; + return false; +} + +bool GuildData::HasIcon() const { + return Icon != ""; +} + +bool GuildData::HasAnimatedIcon() const { + return HasIcon() && Icon[0] == 'a' && Icon[1] == '_'; +} + +std::string GuildData::GetIconURL(std::string ext, std::string size) const { + return "https://cdn.discordapp.com/icons/" + std::to_string(ID) + "/" + Icon + "." + ext + "?size=" + size; +} + +std::vector GuildData::GetSortedChannels(Snowflake ignore) const { + std::vector ret; + + const auto &discord = Abaddon::Get().GetDiscordClient(); + auto channels = discord.GetChannelsInGuild(ID); + + std::unordered_map> category_to_channels; + std::map> position_to_categories; + std::map> orphan_channels; + for (const auto &channel_id : channels) { + const auto data = discord.GetChannel(channel_id); + if (!data->ParentID.has_value() && (data->Type == ChannelType::GUILD_TEXT || data->Type == ChannelType::GUILD_NEWS)) + orphan_channels[*data->Position].push_back(*data); + else if (data->ParentID.has_value() && (data->Type == ChannelType::GUILD_TEXT || data->Type == ChannelType::GUILD_NEWS)) + category_to_channels[*data->ParentID].push_back(*data); + else if (data->Type == ChannelType::GUILD_CATEGORY) + position_to_categories[*data->Position].push_back(*data); + } + + for (auto &[pos, channels] : orphan_channels) { + std::sort(channels.begin(), channels.end(), [&](const ChannelData &a, const ChannelData &b) -> bool { + return a.ID < b.ID; + }); + for (const auto &chan : channels) + ret.push_back(chan.ID); + } + + for (auto &[pos, categories] : position_to_categories) { + std::sort(categories.begin(), categories.end(), [&](const ChannelData &a, const ChannelData &b) -> bool { + return a.ID < b.ID; + }); + for (const auto &category : categories) { + ret.push_back(category.ID); + if (ignore == category.ID) continue; // stupid hack to save me some time + auto it = category_to_channels.find(category.ID); + if (it == category_to_channels.end()) continue; + auto &channels = it->second; + std::sort(channels.begin(), channels.end(), [&](const ChannelData &a, const ChannelData &b) -> bool { + return a.Position < b.Position; + }); + for (auto &channel : channels) { + ret.push_back(channel.ID); + } + } + } + + return ret; +} + +std::vector GuildData::FetchRoles() const { + if (!Roles.has_value()) return {}; + std::vector ret; + ret.reserve(Roles->size()); + for (const auto thing : *Roles) { + auto r = Abaddon::Get().GetDiscordClient().GetRole(thing.ID); + if (r.has_value()) + ret.push_back(*r); + } + std::sort(ret.begin(), ret.end(), [](const RoleData &a, const RoleData &b) -> bool { + return a.Position > b.Position; + }); + 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(); + 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); +} -- cgit v1.2.3 From e02107feea8214a045e6faa969f00dcbc0d2b072 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sun, 28 Nov 2021 22:42:55 -0500 Subject: actually retrieve roles for guilds FetchRoles isnt needed anymore cuz full roles are fetched now --- src/discord/discord.cpp | 4 +++- src/discord/guild.cpp | 15 --------------- src/discord/guild.hpp | 3 +-- src/discord/store.cpp | 30 +++++++++++++++++++++++++++--- src/discord/store.hpp | 2 ++ src/windows/guildsettings/memberspane.cpp | 7 ++++--- src/windows/guildsettings/rolespane.cpp | 25 +++++++++++++------------ 7 files changed, 50 insertions(+), 36 deletions(-) (limited to 'src/discord/guild.cpp') diff --git a/src/discord/discord.cpp b/src/discord/discord.cpp index 83db97b..b678de0 100644 --- a/src/discord/discord.cpp +++ b/src/discord/discord.cpp @@ -720,7 +720,9 @@ void DiscordClient::ModifyRoleColor(Snowflake guild_id, Snowflake role_id, Gdk:: } void DiscordClient::ModifyRolePosition(Snowflake guild_id, Snowflake role_id, int position, sigc::slot callback) { - const auto roles = GetGuild(guild_id)->FetchRoles(); + const auto guild = GetGuild(guild_id); + if (!guild.has_value() || !guild->Roles.has_value()) return; + const auto &roles = *guild->Roles; if (static_cast(position) > roles.size()) return; // gay and makes you send every role in between new and old position constexpr auto IDX_MAX = ~size_t { 0 }; diff --git a/src/discord/guild.cpp b/src/discord/guild.cpp index a02b896..966bd44 100644 --- a/src/discord/guild.cpp +++ b/src/discord/guild.cpp @@ -188,21 +188,6 @@ std::vector GuildData::GetSortedChannels(Snowflake ignore) const { return ret; } -std::vector GuildData::FetchRoles() const { - if (!Roles.has_value()) return {}; - std::vector ret; - ret.reserve(Roles->size()); - for (const auto thing : *Roles) { - auto r = Abaddon::Get().GetDiscordClient().GetRole(thing.ID); - if (r.has_value()) - ret.push_back(*r); - } - std::sort(ret.begin(), ret.end(), [](const RoleData &a, const RoleData &b) -> bool { - return a.Position > b.Position; - }); - return ret; -} - void from_json(const nlohmann::json &j, GuildApplicationData &m) { JS_D("user_id", m.UserID); JS_D("guild_id", m.GuildID); diff --git a/src/discord/guild.hpp b/src/discord/guild.hpp index 3c3828d..51b5a01 100644 --- a/src/discord/guild.hpp +++ b/src/discord/guild.hpp @@ -50,7 +50,7 @@ struct GuildData { std::optional VerificationLevel; std::optional DefaultMessageNotifications; std::optional ExplicitContentFilter; - std::optional> Roles; // only access id + std::optional> Roles; std::optional> Emojis; // only access id std::optional> Features; std::optional MFALevel; @@ -96,5 +96,4 @@ struct GuildData { bool HasAnimatedIcon() const; std::string GetIconURL(std::string ext = "png", std::string size = "32") const; std::vector GetSortedChannels(Snowflake ignore = Snowflake::Invalid) const; - std::vector FetchRoles() const; // sorted }; diff --git a/src/discord/store.cpp b/src/discord/store.cpp index 63fb5f7..1cb7231 100644 --- a/src/discord/store.cpp +++ b/src/discord/store.cpp @@ -765,6 +765,16 @@ std::optional Store::GetGuild(Snowflake id) const { s->Reset(); } + { + auto &s = m_stmt_get_guild_roles; + s->Bind(1, id); + r.Roles.emplace(); + while (s->FetchOne()) { + r.Roles->push_back(GetRoleBound(s)); + } + s->Reset(); + } + return r; } @@ -961,9 +971,17 @@ std::optional Store::GetRole(Snowflake id) const { return {}; } + auto role = GetRoleBound(s); + + s->Reset(); + + return role; +} + +RoleData Store::GetRoleBound(std::unique_ptr &s) const { RoleData r; - r.ID = id; + s->Get(0, r.ID); //s->Get(1, guild id); s->Get(2, r.Name); s->Get(3, r.Color); @@ -973,8 +991,6 @@ std::optional Store::GetRole(Snowflake id) const { s->Get(7, r.IsManaged); s->Get(8, r.IsMentionable); - s->Reset(); - return r; } @@ -1726,6 +1742,14 @@ bool Store::CreateStatements() { return false; } + m_stmt_get_guild_roles = std::make_unique(m_db, R"( + SELECT * FROM roles WHERE guild = ? + )"); + if (!m_stmt_get_guild_roles->OK()) { + fprintf(stderr, "failed to prepare get guild roles statement: %s\n", m_db.ErrStr()); + return false; + } + m_stmt_set_emoji = std::make_unique(m_db, R"( REPLACE INTO emojis VALUES ( ?, ?, ?, ?, ?, ?, ? diff --git a/src/discord/store.hpp b/src/discord/store.hpp index 80e2407..715f280 100644 --- a/src/discord/store.hpp +++ b/src/discord/store.hpp @@ -235,6 +235,7 @@ private: }; Message GetMessageBound(std::unique_ptr &stmt) const; + RoleData GetRoleBound(std::unique_ptr &stmt) const; void SetMessageInteractionPair(Snowflake message_id, const MessageInteractionData &interaction); @@ -264,6 +265,7 @@ private: STMT(get_member); STMT(set_role); STMT(get_role); + STMT(get_guild_roles); STMT(set_emoji); STMT(get_emoji); STMT(set_perm); diff --git a/src/windows/guildsettings/memberspane.cpp b/src/windows/guildsettings/memberspane.cpp index 9dc76d3..bda92b4 100644 --- a/src/windows/guildsettings/memberspane.cpp +++ b/src/windows/guildsettings/memberspane.cpp @@ -238,9 +238,10 @@ GuildSettingsMembersPaneRoles::GuildSettingsMembersPaneRoles(Snowflake guild_id) discord.signal_role_delete().connect(sigc::mem_fun(*this, &GuildSettingsMembersPaneRoles::OnRoleDelete)); const auto guild = *discord.GetGuild(guild_id); - const auto roles = guild.FetchRoles(); - for (const auto &role : roles) { - CreateRow(can_modify, role, guild.OwnerID == self_id); + if (guild.Roles.has_value()) { + for (const auto &role : *guild.Roles) { + CreateRow(can_modify, role, guild.OwnerID == self_id); + } } m_list.set_sort_func([this](Gtk::ListBoxRow *a, Gtk::ListBoxRow *b) -> int { diff --git a/src/windows/guildsettings/rolespane.cpp b/src/windows/guildsettings/rolespane.cpp index 8d355ee..3567e95 100644 --- a/src/windows/guildsettings/rolespane.cpp +++ b/src/windows/guildsettings/rolespane.cpp @@ -79,19 +79,20 @@ GuildSettingsRolesPaneRoles::GuildSettingsRolesPaneRoles(Snowflake guild_id) discord.signal_role_delete().connect(sigc::mem_fun(*this, &GuildSettingsRolesPaneRoles::OnRoleDelete)); const auto guild = *discord.GetGuild(GuildID); - const auto roles = guild.FetchRoles(); const bool can_modify = discord.HasGuildPermission(discord.GetUserData().ID, GuildID, Permission::MANAGE_ROLES); - for (const auto &role : roles) { - auto *row = Gtk::manage(new GuildSettingsRolesPaneRolesListItem(guild, role)); - row->drag_source_set(g_target_entries, Gdk::BUTTON1_MASK, Gdk::ACTION_MOVE); - row->set_margin_start(5); - row->set_halign(Gtk::ALIGN_FILL); - row->show(); - m_rows[role.ID] = row; - if (can_modify) - m_list.add_draggable(row); - else - m_list.add(*row); + if (guild.Roles.has_value()) { + for (const auto &role : *guild.Roles) { + auto *row = Gtk::manage(new GuildSettingsRolesPaneRolesListItem(guild, role)); + row->drag_source_set(g_target_entries, Gdk::BUTTON1_MASK, Gdk::ACTION_MOVE); + row->set_margin_start(5); + row->set_halign(Gtk::ALIGN_FILL); + row->show(); + m_rows[role.ID] = row; + if (can_modify) + m_list.add_draggable(row); + else + m_list.add(*row); + } } m_list.set_sort_func([this](Gtk::ListBoxRow *rowa_, Gtk::ListBoxRow *rowb_) -> int { -- cgit v1.2.3