summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorouwou <26526779+ouwou@users.noreply.github.com>2023-08-28 21:47:04 -0400
committerouwou <26526779+ouwou@users.noreply.github.com>2023-08-28 21:47:04 -0400
commit36f2ec0996d937400e2fce028c3da729ad951f31 (patch)
tree5d0450c3bdae803ee9441c2bc8cea8131953ef7e /src
parent97240237585db9abac22eb214f1865694706af1e (diff)
downloadabaddon-portaudio-36f2ec0996d937400e2fce028c3da729ad951f31.tar.gz
abaddon-portaudio-36f2ec0996d937400e2fce028c3da729ad951f31.zip
fix webhook messages not using right username + avatar (fixes #209)
Diffstat (limited to 'src')
-rw-r--r--src/components/chatlist.cpp16
-rw-r--r--src/components/chatmessage.cpp40
-rw-r--r--src/discord/discord.cpp23
-rw-r--r--src/discord/discord.hpp1
-rw-r--r--src/discord/message.cpp8
-rw-r--r--src/discord/message.hpp4
-rw-r--r--src/discord/store.cpp69
-rw-r--r--src/discord/store.hpp6
-rw-r--r--src/discord/webhook.cpp4
-rw-r--r--src/discord/webhook.hpp9
10 files changed, 164 insertions, 16 deletions
diff --git a/src/components/chatlist.cpp b/src/components/chatlist.cpp
index ba18c0a..4dde8a3 100644
--- a/src/components/chatlist.cpp
+++ b/src/components/chatlist.cpp
@@ -67,8 +67,22 @@ void ChatList::ProcessNewMessage(const Message &data, bool prepend) {
if (last_row != nullptr) {
const uint64_t diff = std::max(data.ID, last_row->NewestID) - std::min(data.ID, last_row->NewestID);
- if (last_row->UserID == data.Author.ID && (prepend || (diff < SnowflakeSplitDifference * Snowflake::SecondsInterval)))
+ if (last_row->UserID == data.Author.ID && (prepend || (diff < SnowflakeSplitDifference * Snowflake::SecondsInterval))) {
should_attach = true;
+ }
+ // Separate webhooks if the usernames or avatar URLs are different
+ if (data.IsWebhook() && last_row->UserID == data.Author.ID) {
+ const auto last_message = discord.GetMessage(last_row->NewestID);
+ if (last_message.has_value() && last_message->IsWebhook()) {
+ const auto last_webhook_data = last_message->GetWebhookData();
+ const auto next_webhook_data = data.GetWebhookData();
+ if (last_webhook_data.has_value() && next_webhook_data.has_value()) {
+ if (last_webhook_data->Username != next_webhook_data->Username || last_webhook_data->Avatar != next_webhook_data->Avatar) {
+ should_attach = false;
+ }
+ }
+ }
+ }
}
}
diff --git a/src/components/chatmessage.cpp b/src/components/chatmessage.cpp
index d1d9f72..09083e3 100644
--- a/src/components/chatmessage.cpp
+++ b/src/components/chatmessage.cpp
@@ -918,11 +918,22 @@ ChatMessageHeader::ChatMessageHeader(const Message &data)
const auto author = Abaddon::Get().GetDiscordClient().GetUser(UserID);
auto &img = Abaddon::Get().GetImageManager();
+ std::string avatar_url;
+ if (data.IsWebhook()) {
+ const auto webhook_data = Abaddon::Get().GetDiscordClient().GetWebhookMessageData(data.ID);
+ if (webhook_data.has_value()) {
+ avatar_url = webhook_data->GetAvatarURL();
+ }
+ }
+ if (avatar_url.empty()) {
+ avatar_url = author->GetAvatarURL(data.GuildID);
+ }
+
auto cb = [this](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
m_static_avatar = pb->scale_simple(AvatarSize, AvatarSize, Gdk::INTERP_BILINEAR);
m_avatar.property_pixbuf() = m_static_avatar;
};
- img.LoadFromURL(author->GetAvatarURL(data.GuildID), sigc::track_obj(cb, *this));
+ img.LoadFromURL(avatar_url, sigc::track_obj(cb, *this));
if (author->HasAnimatedAvatar(data.GuildID)) {
auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
@@ -955,10 +966,11 @@ ChatMessageHeader::ChatMessageHeader(const Message &data)
m_extra->set_can_focus(false);
m_extra->set_use_markup(true);
}
- if (author->IsABot())
- m_extra->set_markup("<b>BOT</b>");
- else if (data.WebhookID.has_value())
+ if (data.IsWebhook()) {
m_extra->set_markup("<b>Webhook</b>");
+ } else if (author->IsABot()) {
+ m_extra->set_markup("<b>BOT</b>");
+ }
m_timestamp.set_text(data.ID.GetLocalTimestamp());
m_timestamp.set_hexpand(true);
@@ -1018,11 +1030,21 @@ ChatMessageHeader::ChatMessageHeader(const Message &data)
show_all();
auto &discord = Abaddon::Get().GetDiscordClient();
- auto role_update_cb = [this](...) { UpdateName(); };
- discord.signal_role_update().connect(sigc::track_obj(role_update_cb, *this));
- auto guild_member_update_cb = [this](const auto &, const auto &) { UpdateName(); };
- discord.signal_guild_member_update().connect(sigc::track_obj(guild_member_update_cb, *this));
- UpdateName();
+ if (data.IsWebhook()) {
+ const auto webhook_data = discord.GetWebhookMessageData(data.ID);
+ if (webhook_data.has_value()) {
+ const auto name = Glib::Markup::escape_text(webhook_data->Username);
+ m_author.set_markup("<span weight='bold'>" + name + "</span>");
+ } else {
+ UpdateName();
+ }
+ } else {
+ auto role_update_cb = [this](...) { UpdateName(); };
+ discord.signal_role_update().connect(sigc::track_obj(role_update_cb, *this));
+ auto guild_member_update_cb = [this](const auto &, const auto &) { UpdateName(); };
+ discord.signal_guild_member_update().connect(sigc::track_obj(guild_member_update_cb, *this));
+ UpdateName();
+ }
AttachUserMenuHandler(m_meta_ev);
AttachUserMenuHandler(m_avatar_ev);
}
diff --git a/src/discord/discord.cpp b/src/discord/discord.cpp
index 084e19f..ccc61b4 100644
--- a/src/discord/discord.cpp
+++ b/src/discord/discord.cpp
@@ -333,6 +333,10 @@ std::vector<Snowflake> DiscordClient::GetChildChannelIDs(Snowflake parent_id) co
return m_store.GetChannelIDsWithParentID(parent_id);
}
+std::optional<WebhookMessageData> DiscordClient::GetWebhookMessageData(Snowflake message_id) const {
+ return m_store.GetWebhookMessage(message_id);
+}
+
bool DiscordClient::IsThreadJoined(Snowflake thread_id) const {
return std::find(m_joined_threads.begin(), m_joined_threads.end(), thread_id) != m_joined_threads.end();
}
@@ -2735,15 +2739,18 @@ void DiscordClient::StoreMessageData(Message &msg) {
for (const auto &r : *msg.Reactions) {
if (!r.Emoji.ID.IsValid()) continue;
const auto cur = m_store.GetEmoji(r.Emoji.ID);
- if (!cur.has_value())
+ if (!cur.has_value()) {
m_store.SetEmoji(r.Emoji.ID, r.Emoji);
+ }
}
- for (const auto &user : msg.Mentions)
+ for (const auto &user : msg.Mentions) {
m_store.SetUser(user.ID, user);
+ }
- if (msg.Member.has_value())
+ if (msg.Member.has_value()) {
m_store.SetGuildMember(*msg.GuildID, msg.Author.ID, *msg.Member);
+ }
if (msg.Interaction.has_value()) {
m_store.SetUser(msg.Interaction->User.ID, msg.Interaction->User);
@@ -2752,11 +2759,17 @@ void DiscordClient::StoreMessageData(Message &msg) {
}
}
+ if (msg.IsWebhook()) {
+ m_store.SetWebhookMessage(msg);
+ }
+
m_store.EndTransaction();
- if (msg.ReferencedMessage.has_value() && msg.MessageReference.has_value() && msg.MessageReference->ChannelID.has_value())
- if (msg.ReferencedMessage.value() != nullptr)
+ if (msg.ReferencedMessage.has_value() && msg.MessageReference.has_value() && msg.MessageReference->ChannelID.has_value()) {
+ if (msg.ReferencedMessage.value() != nullptr) {
StoreMessageData(**msg.ReferencedMessage);
+ }
+ }
}
// some notes for myself
diff --git a/src/discord/discord.hpp b/src/discord/discord.hpp
index eba190a..ebbf5f9 100644
--- a/src/discord/discord.hpp
+++ b/src/discord/discord.hpp
@@ -63,6 +63,7 @@ public:
void GetArchivedPublicThreads(Snowflake channel_id, const sigc::slot<void(DiscordError, const ArchivedThreadsResponseData &)> &callback);
void GetArchivedPrivateThreads(Snowflake channel_id, const sigc::slot<void(DiscordError, const ArchivedThreadsResponseData &)> &callback);
std::vector<Snowflake> GetChildChannelIDs(Snowflake parent_id) const;
+ std::optional<WebhookMessageData> GetWebhookMessageData(Snowflake message_id) const;
// get ids of given list of members for who we do not have the member data
template<typename Iter>
diff --git a/src/discord/message.cpp b/src/discord/message.cpp
index 9adc7e6..bc4c6c8 100644
--- a/src/discord/message.cpp
+++ b/src/discord/message.cpp
@@ -283,3 +283,11 @@ bool Message::DoesMention(Snowflake id) const noexcept {
if (!member.has_value()) return false;
return std::find_first_of(MentionRoles.begin(), MentionRoles.end(), member->Roles.begin(), member->Roles.end()) != MentionRoles.end();
}
+
+bool Message::IsWebhook() const noexcept {
+ return WebhookID.has_value();
+}
+
+std::optional<WebhookMessageData> Message::GetWebhookData() const {
+ return Abaddon::Get().GetDiscordClient().GetWebhookMessageData(ID);
+}
diff --git a/src/discord/message.hpp b/src/discord/message.hpp
index fb11604..0f53021 100644
--- a/src/discord/message.hpp
+++ b/src/discord/message.hpp
@@ -8,6 +8,7 @@
#include "emoji.hpp"
#include "member.hpp"
#include "interactions.hpp"
+#include "webhook.hpp"
#include "misc/bitwise.hpp"
enum class MessageType {
@@ -226,6 +227,9 @@ struct Message {
bool DoesMentionEveryoneOrUser(Snowflake id) const noexcept;
bool DoesMention(Snowflake id) const noexcept;
+ bool IsWebhook() const noexcept;
+
+ std::optional<WebhookMessageData> GetWebhookData() const;
private:
bool m_deleted = false;
diff --git a/src/discord/store.cpp b/src/discord/store.cpp
index 7ee4d87..d8994c4 100644
--- a/src/discord/store.cpp
+++ b/src/discord/store.cpp
@@ -57,6 +57,20 @@ void Store::SetBan(Snowflake guild_id, Snowflake user_id, const BanData &ban) {
s->Reset();
}
+void Store::SetWebhookMessage(const Message &message) {
+ auto &s = m_stmt_set_webhook_msg;
+
+ s->Bind(1, message.ID);
+ s->Bind(2, message.WebhookID);
+ s->Bind(3, message.Author.Username);
+ s->Bind(4, message.Author.Avatar);
+
+ if (!s->Insert())
+ fprintf(stderr, "webhook message insert failed for %" PRIu64 ": %s\n", static_cast<uint64_t>(message.ID), m_db.ErrStr());
+
+ s->Reset();
+}
+
void Store::SetChannel(Snowflake id, const ChannelData &chan) {
auto &s = m_stmt_set_chan;
@@ -483,6 +497,29 @@ std::vector<BanData> Store::GetBans(Snowflake guild_id) const {
return ret;
}
+std::optional<WebhookMessageData> Store::GetWebhookMessage(Snowflake message_id) const {
+ auto &s = m_stmt_get_webhook_msg;
+
+ s->Bind(1, message_id);
+ if (!s->FetchOne()) {
+ if (m_db.Error() != SQLITE_DONE)
+ fprintf(stderr, "error while fetching webhook message %" PRIu64 ": %s\n", static_cast<uint64_t>(message_id), m_db.ErrStr());
+ s->Reset();
+ return {};
+ }
+
+ WebhookMessageData data;
+ s->Get(0, data.MessageID);
+ s->Get(1, data.WebhookID);
+ s->Get(2, data.Username);
+ s->Get(3, data.Avatar);
+
+ s->Reset();
+
+ return data;
+}
+
+
Snowflake Store::GetGuildOwner(Snowflake guild_id) const {
auto &s = m_stmt_get_guild_owner;
@@ -1503,6 +1540,15 @@ bool Store::CreateTables() {
)
)";
+ const char *create_webhook_messages = R"(
+ CREATE TABLE IF NOT EXISTS webhook_messages (
+ message_id INTEGER NOT NULL,
+ webhook_id INTEGER NOT NULL,
+ username TEXT,
+ avatar TEXT
+ )
+ )";
+
if (m_db.Execute(create_users) != SQLITE_OK) {
fprintf(stderr, "failed to create user table: %s\n", m_db.ErrStr());
return false;
@@ -1608,6 +1654,11 @@ bool Store::CreateTables() {
return false;
}
+ if (m_db.Execute(create_webhook_messages) != SQLITE_OK) {
+ fprintf(stderr, "failed to create webhook messages table: %s\n", m_db.ErrStr());
+ return false;
+ }
+
if (m_db.Execute(R"(
CREATE TRIGGER remove_zero_reactions AFTER UPDATE ON reactions WHEN new.count = 0
BEGIN
@@ -2288,6 +2339,24 @@ bool Store::CreateStatements() {
return false;
}
+ m_stmt_set_webhook_msg = std::make_unique<Statement>(m_db, R"(
+ REPLACE INTO webhook_messages VALUES (
+ ?, ?, ?, ?
+ )
+ )");
+ if (!m_stmt_set_webhook_msg->OK()) {
+ fprintf(stderr, "failed to prepare set webhook message statement: %s\n", m_db.ErrStr());
+ return false;
+ }
+
+ m_stmt_get_webhook_msg = std::make_unique<Statement>(m_db, R"(
+ SELECT * FROM webhook_messages WHERE message_id = ?
+ )");
+ if (!m_stmt_get_webhook_msg->OK()) {
+ fprintf(stderr, "failed to prepare get webhook message statement: %s\n", m_db.ErrStr());
+ return false;
+ }
+
return true;
}
diff --git a/src/discord/store.hpp b/src/discord/store.hpp
index 875a5af..b6979d0 100644
--- a/src/discord/store.hpp
+++ b/src/discord/store.hpp
@@ -7,7 +7,7 @@
#include <sqlite3.h>
#ifdef GetMessage // fuck you windows.h
- #undef GetMessage
+#undef GetMessage
#endif
class Store {
@@ -26,6 +26,7 @@ public:
void SetPermissionOverwrite(Snowflake channel_id, Snowflake id, const PermissionOverwrite &perm);
void SetEmoji(Snowflake id, const EmojiData &emoji);
void SetBan(Snowflake guild_id, Snowflake user_id, const BanData &ban);
+ void SetWebhookMessage(const Message &message);
std::optional<ChannelData> GetChannel(Snowflake id) const;
std::optional<EmojiData> GetEmoji(Snowflake id) const;
@@ -37,6 +38,7 @@ public:
std::optional<UserData> GetUser(Snowflake id) const;
std::optional<BanData> GetBan(Snowflake guild_id, Snowflake user_id) const;
std::vector<BanData> GetBans(Snowflake guild_id) const;
+ std::optional<WebhookMessageData> GetWebhookMessage(Snowflake message_id) const;
Snowflake GetGuildOwner(Snowflake guild_id) const;
std::vector<Snowflake> GetMemberRoles(Snowflake guild_id, Snowflake user_id) const;
@@ -313,5 +315,7 @@ private:
STMT(get_guild_member_ids);
STMT(clr_role);
STMT(get_guild_owner);
+ STMT(set_webhook_msg);
+ STMT(get_webhook_msg);
#undef STMT
};
diff --git a/src/discord/webhook.cpp b/src/discord/webhook.cpp
index 4e8b422..318f8c8 100644
--- a/src/discord/webhook.cpp
+++ b/src/discord/webhook.cpp
@@ -11,3 +11,7 @@ void from_json(const nlohmann::json &j, WebhookData &m) {
JS_O("token", m.Token);
JS_N("application_id", m.ApplicationID);
}
+
+std::string WebhookMessageData::GetAvatarURL() const {
+ return Avatar.empty() ? "" : "https://cdn.discordapp.com/avatars/" + std::to_string(WebhookID) + "/" + Avatar + ".png?size=32";
+}
diff --git a/src/discord/webhook.hpp b/src/discord/webhook.hpp
index f0214df..3b9eeb9 100644
--- a/src/discord/webhook.hpp
+++ b/src/discord/webhook.hpp
@@ -22,3 +22,12 @@ struct WebhookData {
friend void from_json(const nlohmann::json &j, WebhookData &m);
};
+
+struct WebhookMessageData {
+ Snowflake MessageID;
+ Snowflake WebhookID;
+ std::string Username;
+ std::string Avatar;
+
+ std::string GetAvatarURL() const;
+};