merge store

This commit is contained in:
ouwou 2021-11-20 18:48:15 -05:00
commit 574cbc35d8
13 changed files with 2007 additions and 1210 deletions

View File

@ -82,9 +82,30 @@ int Abaddon::StartGTK() {
m_main_window = std::make_unique<MainWindow>();
m_main_window->set_title(APP_TITLE);
m_main_window->UpdateComponents();
m_main_window->set_position(Gtk::WIN_POS_CENTER);
if (!m_settings.IsValid()) {
Gtk::MessageDialog dlg(*m_main_window, "The settings file could not be created!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
dlg.set_position(Gtk::WIN_POS_CENTER);
dlg.run();
}
if (!m_emojis.Load()) {
Gtk::MessageDialog dlg(*m_main_window, "The emoji file couldn't be loaded!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
dlg.set_position(Gtk::WIN_POS_CENTER);
dlg.run();
}
if (!m_discord.IsStoreValid()) {
Gtk::MessageDialog dlg(*m_main_window, "The Discord cache could not be created!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
dlg.set_position(Gtk::WIN_POS_CENTER);
dlg.run();
return 1;
}
// store must be checked before this can be called
m_main_window->UpdateComponents();
// crashes for some stupid reason if i put it somewhere else
SetupUserMenu();
@ -114,25 +135,6 @@ int Abaddon::StartGTK() {
m_gtk_app->signal_shutdown().connect(sigc::mem_fun(*this, &Abaddon::StopDiscord), false);
if (!m_settings.IsValid()) {
Gtk::MessageDialog dlg(*m_main_window, "The settings file could not be created!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
dlg.set_position(Gtk::WIN_POS_CENTER);
dlg.run();
}
if (!m_emojis.Load()) {
Gtk::MessageDialog dlg(*m_main_window, "The emoji file couldn't be loaded!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
dlg.set_position(Gtk::WIN_POS_CENTER);
dlg.run();
}
if (!m_discord.IsStoreValid()) {
Gtk::MessageDialog dlg(*m_main_window, "The Discord cache could not be created!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
dlg.set_position(Gtk::WIN_POS_CENTER);
dlg.run();
return 1;
}
m_main_window->show();
return m_gtk_app->run(*m_main_window);
}
@ -552,16 +554,9 @@ void Abaddon::ActionChatLoadHistory(Snowflake id) {
return;
Snowflake before_id = m_main_window->GetChatOldestListedMessage();
auto knownset = m_discord.GetMessageIDsForChannel(id);
std::vector<Snowflake> knownvec(knownset.begin(), knownset.end());
std::sort(knownvec.begin(), knownvec.end());
auto latest = std::find_if(knownvec.begin(), knownvec.end(), [&before_id](Snowflake x) -> bool { return x == before_id; });
int distance = std::distance(knownvec.begin(), latest);
auto msgs = m_discord.GetMessagesBefore(id, before_id);
if (distance >= 50) {
std::vector<Message> msgs;
for (auto it = knownvec.begin() + distance - 50; it != knownvec.begin() + distance; it++)
msgs.push_back(*m_discord.GetMessage(*it));
if (msgs.size() >= 50) {
m_main_window->UpdateChatPrependHistory(msgs);
return;
}

View File

@ -231,11 +231,13 @@ void ChatMessageItemContainer::UpdateTextComponent(Gtk::TextView *tv) {
}
} break;
case MessageType::RECIPIENT_ADD: {
if (data->Mentions.size() == 0) break;
const auto &adder = Abaddon::Get().GetDiscordClient().GetUser(data->Author.ID);
const auto &added = data->Mentions[0];
b->insert_markup(s, "<i><span color='#999999'><span color='#eeeeee'>" + adder->Username + "</span> added <span color='#eeeeee'>" + added.Username + "</span></span></i>");
} break;
case MessageType::RECIPIENT_REMOVE: {
if (data->Mentions.size() == 0) break;
const auto &adder = Abaddon::Get().GetDiscordClient().GetUser(data->Author.ID);
const auto &added = data->Mentions[0];
if (adder->ID == added.ID)
@ -653,6 +655,14 @@ Gtk::Widget *ChatMessageItemContainer::CreateReplyComponent(const Message &data)
return author->GetEscapedBoldString<false>();
};
// if the message wasnt fetched from store it might have an un-fetched reference
std::optional<std::shared_ptr<Message>> referenced_message = data.ReferencedMessage;
if (data.MessageReference.has_value() && data.MessageReference->MessageID.has_value() && !referenced_message.has_value()) {
auto refd = discord.GetMessage(*data.MessageReference->MessageID);
if (refd.has_value())
referenced_message = std::make_shared<Message>(std::move(*refd));
}
if (data.Interaction.has_value()) {
const auto user = *discord.GetUser(data.Interaction->User.ID);
@ -664,16 +674,16 @@ Gtk::Widget *ChatMessageItemContainer::CreateReplyComponent(const Message &data)
} else {
lbl->set_markup(user.GetEscapedBoldString<false>());
}
} else if (data.ReferencedMessage.has_value()) {
if (data.ReferencedMessage.value().get() == nullptr) {
} else if (referenced_message.has_value()) {
if (referenced_message.value() == nullptr) {
lbl->set_markup("<i>deleted message</i>");
} else {
const auto &referenced = *data.ReferencedMessage.value().get();
const auto &referenced = *referenced_message.value();
Glib::ustring text;
if (referenced.Content == "") {
if (referenced.Attachments.size() > 0) {
if (referenced.Content.empty()) {
if (!referenced.Attachments.empty()) {
text = "<i>attachment</i>";
} else if (referenced.Embeds.size() > 0) {
} else if (!referenced.Embeds.empty()) {
text = "<i>embed</i>";
}
} else {

View File

@ -1,6 +1,6 @@
#include "chatwindow.hpp"
#include "chatmessage.hpp"
#include "../abaddon.hpp"
#include "abaddon.hpp"
#include "chatinputindicator.hpp"
#include "ratelimitindicator.hpp"
#include "chatinput.hpp"

View File

@ -2,7 +2,7 @@
#include <gtkmm.h>
#include <string>
#include <set>
#include "../discord/discord.hpp"
#include "discord/discord.hpp"
#include "completer.hpp"
class ChatMessageHeader;

View File

@ -109,8 +109,8 @@ std::vector<Message> DiscordClient::GetMessagesForChannel(Snowflake id, size_t l
return m_store.GetLastMessages(id, limit);
}
std::vector<Snowflake> DiscordClient::GetMessageIDsForChannel(Snowflake id) const {
return m_store.GetChannelMessageIDs(id);
std::vector<Message> DiscordClient::GetMessagesBefore(Snowflake channel_id, Snowflake message_id, size_t limit) const {
return m_store.GetMessagesBefore(channel_id, message_id, limit);
}
void DiscordClient::FetchInvite(std::string code, sigc::slot<void(std::optional<InviteData>)> callback) {
@ -1349,7 +1349,7 @@ void DiscordClient::ProcessNewGuild(GuildData &guild) {
}
for (auto &r : *guild.Roles)
m_store.SetRole(r.ID, r);
m_store.SetRole(guild.ID, r);
for (auto &e : *guild.Emojis)
m_store.SetEmoji(e.ID, e);
@ -1517,7 +1517,7 @@ void DiscordClient::HandleGatewayGuildUpdate(const GatewayMessage &msg) {
void DiscordClient::HandleGatewayGuildRoleUpdate(const GatewayMessage &msg) {
GuildRoleUpdateObject data = msg.Data;
m_store.SetRole(data.Role.ID, data.Role);
m_store.SetRole(data.GuildID, data.Role);
m_signal_role_update.emit(data.GuildID, data.Role.ID);
}
@ -1526,7 +1526,7 @@ void DiscordClient::HandleGatewayGuildRoleCreate(const GatewayMessage &msg) {
auto guild = *m_store.GetGuild(data.GuildID);
guild.Roles->push_back(data.Role);
m_store.BeginTransaction();
m_store.SetRole(data.Role.ID, data.Role);
m_store.SetRole(guild.ID, data.Role);
m_store.SetGuild(guild.ID, guild);
m_store.EndTransaction();
m_signal_role_create.emit(data.GuildID, data.Role.ID);
@ -1545,81 +1545,22 @@ void DiscordClient::HandleGatewayGuildRoleDelete(const GatewayMessage &msg) {
void DiscordClient::HandleGatewayMessageReactionAdd(const GatewayMessage &msg) {
MessageReactionAddObject data = msg.Data;
auto to = m_store.GetMessage(data.MessageID);
if (data.Emoji.ID.IsValid()) {
const auto cur_emoji = m_store.GetEmoji(data.Emoji.ID);
if (!cur_emoji.has_value())
m_store.SetEmoji(data.Emoji.ID, data.Emoji);
}
if (!to.has_value()) return;
if (!to->Reactions.has_value()) to->Reactions.emplace();
// add if present
bool stock;
auto it = std::find_if(to->Reactions->begin(), to->Reactions->end(), [&](const ReactionData &x) {
if (data.Emoji.ID.IsValid() && x.Emoji.ID.IsValid()) {
stock = false;
return data.Emoji.ID == x.Emoji.ID;
} else {
stock = true;
return data.Emoji.Name == x.Emoji.Name;
}
});
if (it != to->Reactions->end()) {
it->Count++;
if (data.UserID == GetUserData().ID)
it->HasReactedWith = true;
m_store.SetMessage(data.MessageID, *to);
if (stock)
m_signal_reaction_add.emit(data.MessageID, data.Emoji.Name);
else
m_signal_reaction_add.emit(data.MessageID, std::to_string(data.Emoji.ID));
return;
}
// create new
auto &rdata = to->Reactions->emplace_back();
rdata.Count = 1;
rdata.Emoji = data.Emoji;
rdata.HasReactedWith = data.UserID == GetUserData().ID;
m_store.SetMessage(data.MessageID, *to);
if (stock)
m_signal_reaction_add.emit(data.MessageID, data.Emoji.Name);
else
m_store.AddReaction(data, data.UserID == GetUserData().ID);
if (data.Emoji.ID.IsValid())
m_signal_reaction_add.emit(data.MessageID, std::to_string(data.Emoji.ID));
else
m_signal_reaction_add.emit(data.MessageID, data.Emoji.Name);
}
void DiscordClient::HandleGatewayMessageReactionRemove(const GatewayMessage &msg) {
MessageReactionRemoveObject data = msg.Data;
auto to = m_store.GetMessage(data.MessageID);
if (!to.has_value()) return;
if (!to->Reactions.has_value()) return;
bool stock;
auto it = std::find_if(to->Reactions->begin(), to->Reactions->end(), [&](const ReactionData &x) {
if (data.Emoji.ID.IsValid() && x.Emoji.ID.IsValid()) {
stock = false;
return data.Emoji.ID == x.Emoji.ID;
} else {
stock = true;
return data.Emoji.Name == x.Emoji.Name;
}
});
if (it == to->Reactions->end()) return;
if (it->Count == 1)
to->Reactions->erase(it);
else {
if (data.UserID == GetUserData().ID)
it->HasReactedWith = false;
it->Count--;
}
m_store.SetMessage(data.MessageID, *to);
if (stock)
m_signal_reaction_remove.emit(data.MessageID, data.Emoji.Name);
else
m_store.RemoveReaction(data, data.UserID == GetUserData().ID);
if (data.Emoji.ID.IsValid())
m_signal_reaction_remove.emit(data.MessageID, std::to_string(data.Emoji.ID));
else
m_signal_reaction_remove.emit(data.MessageID, data.Emoji.Name);
}
// todo: update channel list item and member list
@ -1635,10 +1576,7 @@ void DiscordClient::HandleGatewayChannelRecipientAdd(const GatewayMessage &msg)
void DiscordClient::HandleGatewayChannelRecipientRemove(const GatewayMessage &msg) {
ChannelRecipientRemove data = msg.Data;
auto cur = m_store.GetChannel(data.ChannelID);
if (!cur.has_value() || !cur->RecipientIDs.has_value()) return;
cur->RecipientIDs->erase(std::remove(cur->RecipientIDs->begin(), cur->RecipientIDs->end(), data.User.ID));
m_store.SetChannel(cur->ID, *cur);
m_store.ClearRecipient(data.ChannelID, data.User.ID);
}
void DiscordClient::HandleGatewayTypingStart(const GatewayMessage &msg) {

View File

@ -53,20 +53,12 @@ public:
bool IsStarted() const;
bool IsStoreValid() const;
using guilds_type = Store::guilds_type;
using channels_type = Store::channels_type;
using messages_type = Store::messages_type;
using users_type = Store::users_type;
using roles_type = Store::roles_type;
using members_type = Store::members_type;
using permission_overwrites_type = Store::permission_overwrites_type;
std::unordered_set<Snowflake> GetGuilds() const;
const UserData &GetUserData() const;
const UserSettings &GetUserSettings() const;
std::vector<Snowflake> GetUserSortedGuilds() const;
std::vector<Message> GetMessagesForChannel(Snowflake id, size_t limit = 50) const;
std::vector<Snowflake> GetMessageIDsForChannel(Snowflake id) const;
std::vector<Message> GetMessagesBefore(Snowflake channel_id, Snowflake message_id, size_t limit = 50) const;
std::set<Snowflake> GetPrivateChannels() const;
EPremiumType GetSelfPremiumType() const;

View File

@ -192,8 +192,11 @@ std::vector<RoleData> GuildData::FetchRoles() const {
if (!Roles.has_value()) return {};
std::vector<RoleData> ret;
ret.reserve(Roles->size());
for (const auto &thing : *Roles)
ret.push_back(*Abaddon::Get().GetDiscordClient().GetRole(thing.ID));
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;
});

View File

@ -4,7 +4,7 @@
#include "json.hpp"
#include "../util.hpp"
constexpr static uint64_t PERMISSION_MAX_BIT = 31;
constexpr static uint64_t PERMISSION_MAX_BIT = 36;
enum class Permission : uint64_t {
NONE = 0,
CREATE_INSTANT_INVITE = (1ULL << 0), // Allows creation of instant invites

File diff suppressed because it is too large Load Diff

View File

@ -21,15 +21,13 @@ public:
void SetUser(Snowflake id, const UserData &user);
void SetChannel(Snowflake id, const ChannelData &chan);
void SetGuild(Snowflake id, const GuildData &guild);
void SetRole(Snowflake id, const RoleData &role);
void SetRole(Snowflake guild_id, const RoleData &role);
void SetMessage(Snowflake id, const Message &message);
void SetGuildMember(Snowflake guild_id, Snowflake user_id, const GuildMember &data);
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);
// slap const on everything even tho its not *really* const
std::optional<ChannelData> GetChannel(Snowflake id) const;
std::optional<EmojiData> GetEmoji(Snowflake id) const;
std::optional<GuildData> GetGuild(Snowflake id) const;
@ -42,25 +40,20 @@ public:
std::vector<BanData> GetBans(Snowflake guild_id) const;
std::vector<Message> GetLastMessages(Snowflake id, size_t num) const;
std::vector<Snowflake> GetChannelMessageIDs(Snowflake id) const;
std::vector<Message> GetMessagesBefore(Snowflake channel_id, Snowflake message_id, size_t limit) const;
std::vector<Message> GetPinnedMessages(Snowflake channel_id) const;
std::vector<ChannelData> GetActiveThreads(Snowflake channel_id) const; // public
void AddReaction(const MessageReactionAddObject &data, bool byself);
void RemoveReaction(const MessageReactionRemoveObject &data, bool byself);
void ClearGuild(Snowflake id);
void ClearChannel(Snowflake id);
void ClearBan(Snowflake guild_id, Snowflake user_id);
void ClearRecipient(Snowflake channel_id, Snowflake user_id);
using users_type = std::unordered_map<Snowflake, UserData>;
using channels_type = std::unordered_map<Snowflake, ChannelData>;
using guilds_type = std::unordered_map<Snowflake, GuildData>;
using roles_type = std::unordered_map<Snowflake, RoleData>;
using messages_type = std::unordered_map<Snowflake, Message>;
using members_type = std::unordered_map<Snowflake, std::unordered_map<Snowflake, GuildMember>>; // [guild][user]
using permission_overwrites_type = std::unordered_map<Snowflake, std::unordered_map<Snowflake, PermissionOverwrite>>; // [channel][user/role]
using emojis_type = std::unordered_map<Snowflake, EmojiData>;
const std::unordered_set<Snowflake> &GetChannels() const;
const std::unordered_set<Snowflake> &GetGuilds() const;
std::unordered_set<Snowflake> GetChannels() const;
std::unordered_set<Snowflake> GetGuilds() const;
void ClearAll();
@ -68,105 +61,242 @@ public:
void EndTransaction();
private:
Message GetMessageBound(sqlite3_stmt *stmt) const;
class Statement;
class Database {
public:
Database(const char *path);
~Database();
int Close();
int StartTransaction();
int EndTransaction();
int Execute(const char *command);
int Error() const;
bool OK() const;
const char *ErrStr() const;
int SetError(int err);
sqlite3 *obj();
private:
sqlite3 *m_db;
int m_err = SQLITE_OK;
mutable char m_err_scratch[256] { 0 };
// stupid shit i dont like to allow closing properly
using type_signal_close = sigc::signal<void>;
type_signal_close m_signal_close;
public:
type_signal_close signal_close();
};
class Statement {
public:
Statement() = delete;
Statement(const Statement &other) = delete;
Statement(Database &db, const char *command);
~Statement();
Statement &operator=(Statement &other) = delete;
bool OK() const;
int Bind(int index, Snowflake id);
int Bind(int index, const char *str, size_t len = -1);
int Bind(int index, const std::string &str);
int Bind(int index);
template<typename T>
int Bind(int index, std::optional<T> opt) {
if (opt.has_value())
return Bind(index, opt.value());
else
return Bind(index);
}
template<typename Iter>
int BindIDsAsJSON(int index, Iter start, Iter end) {
std::vector<Snowflake> x;
for (Iter it = start; it != end; it++) {
x.push_back((*it).ID);
}
return Bind(index, nlohmann::json(x).dump());
}
template<typename T>
int BindAsJSONArray(int index, const std::optional<T> &obj) {
if (obj.has_value())
return Bind(index, nlohmann::json(obj.value()).dump());
else
return Bind(index, std::string("[]"));
}
template<typename T>
int BindAsJSON(int index, const T &obj) {
return Bind(index, nlohmann::json(obj).dump());
}
template<typename T>
inline typename std::enable_if<std::is_enum<T>::value, int>::type
Bind(int index, T val) {
return Bind(index, static_cast<typename std::underlying_type<T>::type>(val));
}
template<typename T>
typename std::enable_if<std::is_integral<T>::value, int>::type
Bind(int index, T val) {
return m_db->SetError(sqlite3_bind_int64(m_stmt, index, val));
}
template<typename T>
int BindAsJSON(int index, const std::optional<T> &obj) {
if (obj.has_value())
return Bind(index, nlohmann::json(obj.value()).dump());
else
return Bind(index);
}
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type
Get(int index, T &out) const {
out = static_cast<T>(sqlite3_column_int64(m_stmt, index));
}
void Get(int index, Snowflake &out) const;
void Get(int index, std::string &out) const;
template<typename T>
void GetJSON(int index, std::optional<T> &out) const {
if (IsNull(index))
out = std::nullopt;
else {
std::string stuff;
Get(index, stuff);
if (stuff == "")
out = std::nullopt;
else
out = nlohmann::json::parse(stuff).get<T>();
}
}
template<typename T>
void GetJSON(int index, T &out) const {
std::string stuff;
Get(index, stuff);
nlohmann::json::parse(stuff).get_to(out);
}
template<typename T>
void Get(int index, std::optional<T> &out) const {
if (IsNull(index))
out = std::nullopt;
else {
T tmp;
Get(index, tmp);
out = std::optional<T>(std::move(tmp));
}
}
template<typename T>
inline typename std::enable_if<std::is_enum<T>::value, void>::type
Get(int index, T &val) const {
typename std::underlying_type<T>::type tmp;
Get(index, tmp);
val = static_cast<T>(tmp);
}
template<typename T>
void GetIDOnlyStructs(int index, std::optional<std::vector<T>> &out) const {
out.emplace();
std::string str;
Get(index, str);
for (const auto &id : nlohmann::json::parse(str))
out->emplace_back().ID = id.get<Snowflake>();
}
template<typename T, typename OutputIt>
void GetArray(int index, OutputIt first) const {
std::string str;
Get(index, str);
for (const auto &id : nlohmann::json::parse(str))
*first++ = id.get<T>();
}
bool IsNull(int index) const;
int Step();
bool Insert();
bool FetchOne();
int Reset();
sqlite3_stmt *obj();
private:
Database *m_db;
sqlite3_stmt *m_stmt;
};
Message GetMessageBound(std::unique_ptr<Statement> &stmt) const;
void SetMessageInteractionPair(Snowflake message_id, const MessageInteractionData &interaction);
std::unordered_set<Snowflake> m_channels;
std::unordered_set<Snowflake> m_guilds;
bool CreateTables();
bool CreateStatements();
void Cleanup();
template<typename T>
void Bind(sqlite3_stmt *stmt, int index, const std::optional<T> &opt) const;
template<typename T>
typename std::enable_if<std::is_enum<T>::value, void>::type
Bind(sqlite3_stmt *stmt, int index, T val) const;
void Bind(sqlite3_stmt *stmt, int index, int num) const;
void Bind(sqlite3_stmt *stmt, int index, uint64_t num) const;
void Bind(sqlite3_stmt *stmt, int index, const std::string &str) const;
void Bind(sqlite3_stmt *stmt, int index, bool val) const;
void Bind(sqlite3_stmt *stmt, int index, std::nullptr_t) const;
bool RunInsert(sqlite3_stmt *stmt);
bool FetchOne(sqlite3_stmt *stmt) const;
template<typename T>
void Get(sqlite3_stmt *stmt, int index, std::optional<T> &out) const;
template<typename T>
typename std::enable_if<std::is_enum<T>::value, void>::type
Get(sqlite3_stmt *stmt, int index, T &out) const;
void Get(sqlite3_stmt *stmt, int index, int &out) const;
void Get(sqlite3_stmt *stmt, int index, uint64_t &out) const;
void Get(sqlite3_stmt *stmt, int index, std::string &out) const;
void Get(sqlite3_stmt *stmt, int index, bool &out) const;
void Get(sqlite3_stmt *stmt, int index, Snowflake &out) const;
bool IsNull(sqlite3_stmt *stmt, int index) const;
void Reset(sqlite3_stmt *stmt) const;
bool m_ok = true;
std::filesystem::path m_db_path;
mutable sqlite3 *m_db;
mutable int m_db_err;
mutable sqlite3_stmt *m_set_user_stmt;
mutable sqlite3_stmt *m_get_user_stmt;
mutable sqlite3_stmt *m_set_perm_stmt;
mutable sqlite3_stmt *m_get_perm_stmt;
mutable sqlite3_stmt *m_set_msg_stmt;
mutable sqlite3_stmt *m_get_msg_stmt;
mutable sqlite3_stmt *m_set_role_stmt;
mutable sqlite3_stmt *m_get_role_stmt;
mutable sqlite3_stmt *m_set_emote_stmt;
mutable sqlite3_stmt *m_get_emote_stmt;
mutable sqlite3_stmt *m_set_member_stmt;
mutable sqlite3_stmt *m_get_member_stmt;
mutable sqlite3_stmt *m_set_guild_stmt;
mutable sqlite3_stmt *m_get_guild_stmt;
mutable sqlite3_stmt *m_set_chan_stmt;
mutable sqlite3_stmt *m_get_chan_stmt;
mutable sqlite3_stmt *m_set_ban_stmt;
mutable sqlite3_stmt *m_get_ban_stmt;
mutable sqlite3_stmt *m_clear_ban_stmt;
mutable sqlite3_stmt *m_get_bans_stmt;
mutable sqlite3_stmt *m_set_msg_interaction_stmt;
mutable sqlite3_stmt *m_get_last_msgs_stmt;
mutable sqlite3_stmt *m_get_msg_ids_stmt;
mutable sqlite3_stmt *m_get_pins_stmt;
mutable sqlite3_stmt *m_get_threads_stmt;
mutable sqlite3_stmt *m_clear_chan_stmt;
Database m_db;
#define STMT(x) mutable std::unique_ptr<Statement> m_stmt_##x
STMT(set_guild);
STMT(get_guild);
STMT(get_guild_ids);
STMT(clr_guild);
STMT(set_chan);
STMT(get_chan);
STMT(get_chan_ids);
STMT(clr_chan);
STMT(set_msg);
STMT(get_msg);
STMT(set_msg_ref);
STMT(get_last_msgs);
STMT(set_user);
STMT(get_user);
STMT(set_member);
STMT(get_member);
STMT(set_role);
STMT(get_role);
STMT(set_emoji);
STMT(get_emoji);
STMT(set_perm);
STMT(get_perm);
STMT(set_ban);
STMT(get_ban);
STMT(get_bans);
STMT(clr_ban);
STMT(set_interaction);
STMT(set_member_roles);
STMT(get_member_roles);
STMT(set_guild_emoji);
STMT(get_guild_emojis);
STMT(clr_guild_emoji);
STMT(set_guild_feature);
STMT(get_guild_features);
STMT(get_guild_chans);
STMT(set_thread);
STMT(get_threads);
STMT(get_active_threads);
STMT(get_messages_before);
STMT(get_pins);
STMT(set_emoji_role);
STMT(get_emoji_roles);
STMT(set_mention);
STMT(get_mentions);
STMT(set_attachment);
STMT(get_attachments);
STMT(set_recipient);
STMT(get_recipients);
STMT(clr_recipient);
STMT(add_reaction);
STMT(sub_reaction);
STMT(get_reactions);
#undef STMT
};
template<typename T>
inline void Store::Bind(sqlite3_stmt *stmt, int index, const std::optional<T> &opt) const {
if (opt.has_value())
Bind(stmt, index, *opt);
else
sqlite3_bind_null(stmt, index);
}
template<typename T>
inline typename std::enable_if<std::is_enum<T>::value, void>::type
Store::Bind(sqlite3_stmt *stmt, int index, T val) const {
Bind(stmt, index, static_cast<typename std::underlying_type<T>::type>(val));
}
template<typename T>
inline void Store::Get(sqlite3_stmt *stmt, int index, std::optional<T> &out) const {
if (sqlite3_column_type(stmt, index) == SQLITE_NULL)
out = std::nullopt;
else {
T v;
Get(stmt, index, v);
out = std::optional<T>(v);
}
}
template<typename T>
inline typename std::enable_if<std::is_enum<T>::value, void>::type
Store::Get(sqlite3_stmt *stmt, int index, T &out) const {
out = static_cast<T>(sqlite3_column_int(stmt, index));
}

View File

@ -1,5 +1,5 @@
#include "auditlogpane.hpp"
#include "../../abaddon.hpp"
#include "abaddon.hpp"
using namespace std::string_literals;

View File

@ -1,6 +1,6 @@
#pragma once
#include <gtkmm.h>
#include "../../discord/objects.hpp"
#include "discord/objects.hpp"
class GuildSettingsAuditLogPane : public Gtk::ScrolledWindow {
public:

View File

@ -228,10 +228,12 @@ void MainWindow::UpdateChatReactionRemove(Snowflake id, const Glib::ustring &par
void MainWindow::OnDiscordSubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y) {
auto &discord = Abaddon::Get().GetDiscordClient();
auto channel_id = GetChatActiveChannel();
auto channel = discord.GetChannel(channel_id);
m_menu_discord_add_recipient.set_visible(false);
if (channel.has_value() && channel->GetDMRecipients().size() + 1 < 10)
m_menu_discord_add_recipient.set_visible(channel->Type == ChannelType::GROUP_DM);
if (channel_id.IsValid()) {
auto channel = discord.GetChannel(channel_id);
if (channel.has_value() && channel->GetDMRecipients().size() + 1 < 10)
m_menu_discord_add_recipient.set_visible(channel->Type == ChannelType::GROUP_DM);
}
const bool discord_active = Abaddon::Get().GetDiscordClient().IsStarted();
@ -246,12 +248,14 @@ void MainWindow::OnDiscordSubmenuPopup(const Gdk::Rectangle *flipped_rect, const
void MainWindow::OnViewSubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y) {
m_menu_view_friends.set_sensitive(Abaddon::Get().GetDiscordClient().IsStarted());
auto channel_id = GetChatActiveChannel();
auto channel = Abaddon::Get().GetDiscordClient().GetChannel(channel_id);
m_menu_view_pins.set_sensitive(false);
m_menu_view_threads.set_sensitive(false);
if (channel.has_value()) {
m_menu_view_threads.set_sensitive(channel->Type == ChannelType::GUILD_TEXT || channel->IsThread());
m_menu_view_pins.set_sensitive(channel->Type == ChannelType::GUILD_TEXT || channel->Type == ChannelType::DM || channel->Type == ChannelType::GROUP_DM || channel->IsThread());
if (channel_id.IsValid()) {
auto channel = Abaddon::Get().GetDiscordClient().GetChannel(channel_id);
if (channel.has_value()) {
m_menu_view_threads.set_sensitive(channel->Type == ChannelType::GUILD_TEXT || channel->IsThread());
m_menu_view_pins.set_sensitive(channel->Type == ChannelType::GUILD_TEXT || channel->Type == ChannelType::DM || channel->Type == ChannelType::GROUP_DM || channel->IsThread());
}
}
}