forked from OpenGamers/abaddon
add kick/ban
This commit is contained in:
@@ -7,6 +7,8 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
option(USE_PKGCONFIG "Use pkg-config" OFF)
|
||||
option(DISABLE_MBEDTLS "Disable mbedtls" OFF)
|
||||
|
||||
add_compile_definitions(NOMINMAX)
|
||||
|
||||
if(NOT USE_PKGCONFIG)
|
||||
find_path(GTKMM_INCLUDE_DIRS gtkmm.h REQUIRED)
|
||||
find_library(GTKMM_LIBRARY gtkmm)
|
||||
|
||||
25
abaddon.cpp
25
abaddon.cpp
@@ -71,6 +71,8 @@ int Abaddon::StartGTK() {
|
||||
m_main_window->GetChatWindow()->signal_action_insert_mention().connect(sigc::mem_fun(*this, &Abaddon::ActionInsertMention));
|
||||
|
||||
m_main_window->GetMemberList()->signal_action_insert_mention().connect(sigc::mem_fun(*this, &Abaddon::ActionInsertMention));
|
||||
m_main_window->GetMemberList()->signal_action_kick().connect(sigc::mem_fun(*this, &Abaddon::ActionKickMember));
|
||||
m_main_window->GetMemberList()->signal_action_ban().connect(sigc::mem_fun(*this, &Abaddon::ActionBanMember));
|
||||
|
||||
ActionReloadCSS();
|
||||
|
||||
@@ -316,11 +318,34 @@ void Abaddon::ActionInsertMention(Snowflake id) {
|
||||
|
||||
void Abaddon::ActionLeaveGuild(Snowflake id) {
|
||||
ConfirmDialog dlg(*m_main_window);
|
||||
const auto *guild = m_discord.GetGuild(id);
|
||||
if (guild != nullptr)
|
||||
dlg.SetConfirmText("Are you sure you want to leave " + guild->Name + "?");
|
||||
auto response = dlg.run();
|
||||
if (response == Gtk::RESPONSE_OK)
|
||||
m_discord.LeaveGuild(id);
|
||||
}
|
||||
|
||||
void Abaddon::ActionKickMember(Snowflake user_id, Snowflake guild_id) {
|
||||
ConfirmDialog dlg(*m_main_window);
|
||||
const auto *user = m_discord.GetUser(user_id);
|
||||
if (user != nullptr)
|
||||
dlg.SetConfirmText("Are you sure you want to kick " + user->Username + "#" + user->Discriminator + "?");
|
||||
auto response = dlg.run();
|
||||
if (response == Gtk::RESPONSE_OK)
|
||||
m_discord.KickUser(user_id, guild_id);
|
||||
}
|
||||
|
||||
void Abaddon::ActionBanMember(Snowflake user_id, Snowflake guild_id) {
|
||||
ConfirmDialog dlg(*m_main_window);
|
||||
const auto *user = m_discord.GetUser(user_id);
|
||||
if (user != nullptr)
|
||||
dlg.SetConfirmText("Are you sure you want to ban " + user->Username + "#" + user->Discriminator + "?");
|
||||
auto response = dlg.run();
|
||||
if (response == Gtk::RESPONSE_OK)
|
||||
m_discord.BanUser(user_id, guild_id);
|
||||
}
|
||||
|
||||
void Abaddon::ActionReloadCSS() {
|
||||
try {
|
||||
Gtk::StyleContext::remove_provider_for_screen(Gdk::Screen::get_default(), m_css_provider);
|
||||
|
||||
@@ -41,6 +41,8 @@ public:
|
||||
void ActionChatEditMessage(Snowflake channel_id, Snowflake id);
|
||||
void ActionInsertMention(Snowflake id);
|
||||
void ActionLeaveGuild(Snowflake id);
|
||||
void ActionKickMember(Snowflake user_id, Snowflake guild_id);
|
||||
void ActionBanMember(Snowflake user_id, Snowflake guild_id);
|
||||
|
||||
void ActionReloadCSS();
|
||||
|
||||
|
||||
@@ -61,6 +61,14 @@ MemberList::MemberList() {
|
||||
m_menu_insert_mention->signal_activate().connect(sigc::mem_fun(*this, &MemberList::on_insert_mention_activate));
|
||||
m_menu.append(*m_menu_insert_mention);
|
||||
|
||||
m_menu_kick = Gtk::manage(new Gtk::MenuItem("_Kick User", true));
|
||||
m_menu_kick->signal_activate().connect(sigc::mem_fun(*this, &MemberList::on_kick_activate));
|
||||
m_menu.append(*m_menu_kick);
|
||||
|
||||
m_menu_ban = Gtk::manage(new Gtk::MenuItem("_Ban User", true));
|
||||
m_menu_ban->signal_activate().connect(sigc::mem_fun(*this, &MemberList::on_ban_activate));
|
||||
m_menu.append(*m_menu_ban);
|
||||
|
||||
m_menu.show_all();
|
||||
|
||||
m_main->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
|
||||
@@ -230,10 +238,30 @@ void MemberList::on_insert_mention_activate() {
|
||||
m_signal_action_insert_mention.emit(row->ID);
|
||||
}
|
||||
|
||||
void MemberList::on_kick_activate() {
|
||||
auto *row = dynamic_cast<MemberListUserRow *>(m_row_menu_target);
|
||||
if (row == nullptr) return;
|
||||
m_signal_action_kick.emit(row->ID, m_guild_id);
|
||||
}
|
||||
|
||||
void MemberList::on_ban_activate() {
|
||||
auto *row = dynamic_cast<MemberListUserRow *>(m_row_menu_target);
|
||||
if (row == nullptr) return;
|
||||
m_signal_action_ban.emit(row->ID, m_guild_id);
|
||||
}
|
||||
|
||||
void MemberList::AttachUserMenuHandler(Gtk::ListBoxRow *row, Snowflake id) {
|
||||
row->signal_button_press_event().connect([&, row](GdkEventButton *e) -> bool {
|
||||
row->signal_button_press_event().connect([this, row, id](GdkEventButton *e) -> bool {
|
||||
if (e->type == GDK_BUTTON_PRESS && e->button == GDK_BUTTON_SECONDARY) {
|
||||
const auto &discord = Abaddon::Get().GetDiscordClient();
|
||||
const auto me = discord.GetUserData().ID;
|
||||
const bool has_kick = discord.HasGuildPermission(me, m_guild_id, Permission::KICK_MEMBERS);
|
||||
const bool has_ban = discord.HasGuildPermission(me, m_guild_id, Permission::BAN_MEMBERS);
|
||||
const bool can_manage = discord.CanManageMember(m_chan_id, discord.GetUserData().ID, id);
|
||||
|
||||
m_row_menu_target = row;
|
||||
m_menu_kick->set_sensitive(has_kick && can_manage);
|
||||
m_menu_ban->set_sensitive(has_ban && can_manage);
|
||||
m_menu.popup_at_pointer(reinterpret_cast<const GdkEvent *>(e));
|
||||
return true;
|
||||
}
|
||||
@@ -245,3 +273,11 @@ void MemberList::AttachUserMenuHandler(Gtk::ListBoxRow *row, Snowflake id) {
|
||||
MemberList::type_signal_action_insert_mention MemberList::signal_action_insert_mention() {
|
||||
return m_signal_action_insert_mention;
|
||||
}
|
||||
|
||||
MemberList::type_signal_action_kick MemberList::signal_action_kick() {
|
||||
return m_signal_action_kick;
|
||||
}
|
||||
|
||||
MemberList::type_signal_action_ban MemberList::signal_action_ban() {
|
||||
return m_signal_action_ban;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ public:
|
||||
private:
|
||||
void on_copy_id_activate();
|
||||
void on_insert_mention_activate();
|
||||
void on_kick_activate();
|
||||
void on_ban_activate();
|
||||
|
||||
void UpdateMemberListInternal();
|
||||
void AttachUserMenuHandler(Gtk::ListBoxRow *row, Snowflake id);
|
||||
@@ -37,6 +39,8 @@ private:
|
||||
Gtk::Menu m_menu;
|
||||
Gtk::MenuItem *m_menu_copy_id;
|
||||
Gtk::MenuItem *m_menu_insert_mention;
|
||||
Gtk::MenuItem *m_menu_kick;
|
||||
Gtk::MenuItem *m_menu_ban;
|
||||
Gtk::ListBoxRow *m_row_menu_target = nullptr; // maybe hacky
|
||||
|
||||
std::mutex m_mutex;
|
||||
@@ -52,9 +56,15 @@ private:
|
||||
|
||||
public:
|
||||
typedef sigc::signal<void, Snowflake> type_signal_action_insert_mention;
|
||||
typedef sigc::signal<void, Snowflake, Snowflake> type_signal_action_kick; // user_id, guild_id
|
||||
typedef sigc::signal<void, Snowflake, Snowflake> type_signal_action_ban; // ^
|
||||
|
||||
type_signal_action_insert_mention signal_action_insert_mention();
|
||||
type_signal_action_kick signal_action_kick();
|
||||
type_signal_action_ban signal_action_ban();
|
||||
|
||||
private:
|
||||
type_signal_action_insert_mention m_signal_action_insert_mention;
|
||||
type_signal_action_kick m_signal_action_kick;
|
||||
type_signal_action_ban m_signal_action_ban;
|
||||
};
|
||||
|
||||
@@ -28,3 +28,7 @@ ConfirmDialog::ConfirmDialog(Gtk::Window &parent)
|
||||
|
||||
show_all_children();
|
||||
}
|
||||
|
||||
void ConfirmDialog::SetConfirmText(const Glib::ustring &text) {
|
||||
m_label.set_text(text);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
class ConfirmDialog : public Gtk::Dialog {
|
||||
public:
|
||||
ConfirmDialog(Gtk::Window &parent);
|
||||
void SetConfirmText(const Glib::ustring &text);
|
||||
|
||||
protected:
|
||||
Gtk::Label m_label;
|
||||
|
||||
@@ -231,6 +231,21 @@ Snowflake DiscordClient::GetMemberHoistedRole(Snowflake guild_id, Snowflake user
|
||||
return roles[0]->ID;
|
||||
}
|
||||
|
||||
Snowflake DiscordClient::GetMemberHighestRole(Snowflake guild_id, Snowflake user_id) const {
|
||||
const auto *data = GetMember(user_id, guild_id);
|
||||
if (data == nullptr) return Snowflake::Invalid;
|
||||
|
||||
if (data->Roles.size() == 0) return Snowflake::Invalid;
|
||||
if (data->Roles.size() == 1) return data->Roles[0];
|
||||
|
||||
return *std::max(data->Roles.begin(), data->Roles.end(), [this](const auto &a, const auto &b) -> bool {
|
||||
const auto *role_a = GetRole(*a);
|
||||
const auto *role_b = GetRole(*b);
|
||||
if (role_a == nullptr || role_b == nullptr) return false; // for some reason a Snowflake(0) sneaks into here
|
||||
return role_a->Position < role_b->Position;
|
||||
});
|
||||
}
|
||||
|
||||
std::unordered_set<Snowflake> DiscordClient::GetUsersInGuild(Snowflake id) const {
|
||||
auto it = m_guild_to_users.find(id);
|
||||
if (it != m_guild_to_users.end())
|
||||
@@ -324,6 +339,20 @@ Permission DiscordClient::ComputeOverwrites(Permission base, Snowflake member_id
|
||||
return perms;
|
||||
}
|
||||
|
||||
bool DiscordClient::CanManageMember(Snowflake channel_id, Snowflake actor, Snowflake target) const {
|
||||
const auto *channel = GetChannel(channel_id);
|
||||
if (channel == nullptr) return false;
|
||||
const auto *guild = GetGuild(channel->GuildID);
|
||||
if (guild != nullptr && guild->OwnerID == target) return false;
|
||||
const auto actor_highest_id = GetMemberHighestRole(channel->GuildID, actor);
|
||||
const auto target_highest_id = GetMemberHighestRole(channel->GuildID, target);
|
||||
const auto *actor_highest = GetRole(actor_highest_id);
|
||||
const auto *target_highest = GetRole(target_highest_id);
|
||||
if (actor_highest == nullptr) return false;
|
||||
if (target_highest == nullptr) return true;
|
||||
return actor_highest->Position > target_highest->Position;
|
||||
}
|
||||
|
||||
void DiscordClient::SendChatMessage(std::string content, Snowflake channel) {
|
||||
// @([^@#]{1,32})#(\\d{4})
|
||||
CreateMessageObject obj;
|
||||
@@ -369,6 +398,14 @@ void DiscordClient::LeaveGuild(Snowflake id) {
|
||||
m_http.MakeDELETE("/users/@me/guilds/" + std::to_string(id), [](auto) {});
|
||||
}
|
||||
|
||||
void DiscordClient::KickUser(Snowflake user_id, Snowflake guild_id) {
|
||||
m_http.MakeDELETE("/guilds/" + std::to_string(guild_id) + "/members/" + std::to_string(user_id), [](auto) {});
|
||||
}
|
||||
|
||||
void DiscordClient::BanUser(Snowflake user_id, Snowflake guild_id) {
|
||||
m_http.MakePUT("/guilds/" + std::to_string(guild_id) + "/bans/" + std::to_string(user_id), "{}", [](auto) {});
|
||||
}
|
||||
|
||||
void DiscordClient::UpdateToken(std::string token) {
|
||||
if (!IsStarted()) {
|
||||
m_token = token;
|
||||
|
||||
@@ -84,6 +84,7 @@ public:
|
||||
const PermissionOverwrite *GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const;
|
||||
const Emoji *GetEmoji(Snowflake id) const;
|
||||
Snowflake GetMemberHoistedRole(Snowflake guild_id, Snowflake user_id, bool with_color = false) const;
|
||||
Snowflake GetMemberHighestRole(Snowflake guild_id, Snowflake user_id) const;
|
||||
std::unordered_set<Snowflake> GetUsersInGuild(Snowflake id) const;
|
||||
std::unordered_set<Snowflake> GetRolesInGuild(Snowflake id) const;
|
||||
|
||||
@@ -91,6 +92,7 @@ public:
|
||||
bool HasChannelPermission(Snowflake user_id, Snowflake channel_id, Permission perm) const;
|
||||
Permission ComputePermissions(Snowflake member_id, Snowflake guild_id) const;
|
||||
Permission ComputeOverwrites(Permission base, Snowflake member_id, Snowflake channel_id) const;
|
||||
bool CanManageMember(Snowflake channel_id, Snowflake actor, Snowflake target) const; // kick, ban, edit nickname (cant think of a better name)
|
||||
|
||||
void SendChatMessage(std::string content, Snowflake channel);
|
||||
void DeleteMessage(Snowflake channel_id, Snowflake id);
|
||||
@@ -98,6 +100,8 @@ public:
|
||||
void SendLazyLoad(Snowflake id);
|
||||
void JoinGuild(std::string code);
|
||||
void LeaveGuild(Snowflake id);
|
||||
void KickUser(Snowflake user_id, Snowflake guild_id);
|
||||
void BanUser(Snowflake user_id, Snowflake guild_id); // todo: reason, delete messages
|
||||
|
||||
void UpdateToken(std::string token);
|
||||
|
||||
|
||||
@@ -71,6 +71,27 @@ void HTTPClient::MakePOST(std::string path, std::string payload, std::function<v
|
||||
#endif
|
||||
}
|
||||
|
||||
void HTTPClient::MakePUT(std::string path, std::string payload, std::function<void(cpr::Response r)> cb) {
|
||||
printf("PUT %s\n", path.c_str());
|
||||
auto url = cpr::Url { m_api_base + path };
|
||||
auto headers = cpr::Header {
|
||||
{ "Authorization", m_authorization },
|
||||
{ "Content-Type", "application/json" },
|
||||
};
|
||||
auto body = cpr::Body { payload };
|
||||
#ifdef USE_LOCAL_PROXY
|
||||
m_futures.push_back(cpr::PutCallback(
|
||||
std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb),
|
||||
url, headers, body,
|
||||
cpr::Proxies { { "http", "127.0.0.1:8888" }, { "https", "127.0.0.1:8888" } },
|
||||
cpr::VerifySsl { false }));
|
||||
#else
|
||||
m_futures.push_back(cpr::PutCallback(
|
||||
std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb),
|
||||
url, headers, body));
|
||||
#endif
|
||||
}
|
||||
|
||||
void HTTPClient::MakeGET(std::string path, std::function<void(cpr::Response r)> cb) {
|
||||
printf("GET %s\n", path.c_str());
|
||||
auto url = cpr::Url { m_api_base + path };
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
void MakeGET(std::string path, std::function<void(cpr::Response r)> cb);
|
||||
void MakePATCH(std::string path, std::string payload, std::function<void(cpr::Response r)> cb);
|
||||
void MakePOST(std::string path, std::string payload, std::function<void(cpr::Response r)> cb);
|
||||
void MakePUT(std::string path, std::string payload, std::function<void(cpr::Response r)> cb);
|
||||
|
||||
private:
|
||||
void OnResponse(cpr::Response r, std::function<void(cpr::Response r)> cb);
|
||||
|
||||
Reference in New Issue
Block a user