forked from OpenGamers/abaddon
merge store
This commit is contained in:
commit
574cbc35d8
53
abaddon.cpp
53
abaddon.cpp
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <gtkmm.h>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include "../discord/discord.hpp"
|
||||
#include "discord/discord.hpp"
|
||||
#include "completer.hpp"
|
||||
|
||||
class ChatMessageHeader;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -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
|
||||
|
2661
discord/store.cpp
2661
discord/store.cpp
File diff suppressed because it is too large
Load Diff
@ -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));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "auditlogpane.hpp"
|
||||
#include "../../abaddon.hpp"
|
||||
#include "abaddon.hpp"
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include <gtkmm.h>
|
||||
#include "../../discord/objects.hpp"
|
||||
#include "discord/objects.hpp"
|
||||
|
||||
class GuildSettingsAuditLogPane : public Gtk::ScrolledWindow {
|
||||
public:
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user