Skip to content

Commit e1f8325

Browse files
committed
add permission overwrites for channels
1 parent 4832c9e commit e1f8325

File tree

7 files changed

+138
-21
lines changed

7 files changed

+138
-21
lines changed

Discord.C++/Channel.cpp

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "Channel.h"
22

3+
#include "Permissions.h"
34
#include "static.h"
45

56
/** @param[in] data JSON data
@@ -9,9 +10,14 @@ DiscordCPP::Channel::Channel(const json& data, const std::string& token)
910
: DiscordCPP::DiscordObject(token, data["id"].get<std::string>()),
1011
type(static_cast<Type>(data["type"].get<int>())) {
1112
position = get_or_else<int>(data, "position", 0);
12-
// permission_overwrites
1313
name = get_or_else<std::string>(data, "name", "");
1414
icon = get_or_else<std::string>(data, "icon", "");
15+
16+
if (has_value(data, "permission_overwrites")) {
17+
for (auto d : data.at("permission_overwrites")) {
18+
permission_overwrites.push_back(PermissionOverwrites(d));
19+
}
20+
}
1521
}
1622

1723
/** @param[in] id the channel's id
@@ -35,3 +41,21 @@ void DiscordCPP::Channel::delete_channel() {
3541

3642
api_call(url, "DELETE");
3743
}
44+
45+
DiscordCPP::Permissions DiscordCPP::Channel::merge_permission_overwrites(const Permissions& permissions, const std::string& id) {
46+
if (permissions.has_permission(Permissions::ADMINISTRATOR)) {
47+
return Permissions::All();
48+
}
49+
50+
Permissions result;
51+
result.add(permissions);
52+
53+
for (auto overwrite : permission_overwrites) {
54+
if (overwrite.get_id() == id) {
55+
result.add(overwrite.get_allowed_permissions());
56+
result.remove(overwrite.get_denied_permissions());
57+
}
58+
}
59+
60+
return result;
61+
}

Discord.C++/Channel.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#pragma once
22

3+
#include <vector>
4+
35
#include "DiscordObject.h"
6+
#include "Permissions.h"
47
#include "static.h"
58

69
namespace DiscordCPP {
@@ -30,7 +33,8 @@ class Channel : public DiscordObject {
3033
Type type;
3134
/// the sorting position
3235
int32_t position;
33-
// vector<Overwrite *> permission_overwrites;
36+
/// explicit permission overwrites for members and roles
37+
std::vector<PermissionOverwrites> permission_overwrites;
3438
/// the channel's name
3539
std::string name;
3640
/// the channel's icon hash
@@ -48,10 +52,17 @@ class Channel : public DiscordObject {
4852
/// @return Channelname as std::string
4953
DLL_EXPORT explicit operator std::string() { return name; };
5054

55+
/** Merge permission overwrites into given permission set
56+
@param permissions permission set
57+
@param id member or role id */
58+
DLL_EXPORT Permissions merge_permission_overwrites(const Permissions& permissions, const std::string& id);
59+
5160
/// @return the ChannelType of the channel
5261
DLL_EXPORT Type get_type() { return type; }
5362
/// @return the sorting position
5463
DLL_EXPORT int32_t get_position() { return position; }
64+
/// @return explicit permission overwrites for members and roles
65+
DLL_EXPORT std::vector<PermissionOverwrites> get_permission_overwrites() const { return permission_overwrites; }
5566
/// @return the channel's name
5667
DLL_EXPORT std::string get_name() { return name; }
5768
/// @return channel's icon hash

Discord.C++/Interaction.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,10 @@ std::optional<DiscordCPP::Guild> DiscordCPP::Interaction::get_guild() {
9595
}
9696
return (guild != nullptr) ? std::optional<Guild>{*guild} : std::nullopt;
9797
}
98+
99+
std::optional<DiscordCPP::Channel> DiscordCPP::Interaction::get_channel() {
100+
if (channel_id.has_value() && channel == nullptr) {
101+
channel = new Channel(channel_id.value(), get_token());
102+
}
103+
return (channel != nullptr) ? std::optional<Channel>{*channel} : std::nullopt;
104+
}

Discord.C++/Interaction.h

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <optional>
44

5+
#include "Channel.h"
56
#include "InteractionData.h"
67
#include "Member.h"
78
#include "Message.h"
@@ -36,6 +37,8 @@ class Interaction : public DiscordObject {
3637
Guild* guild = nullptr;
3738
/// The channel the interaction was sent from.
3839
std::optional<std::string> channel_id;
40+
Channel* channel = nullptr;
41+
3942
/// The member that sent the interaction.
4043
std::optional<Member> member;
4144
/// The user that sent the interaction.
@@ -74,6 +77,8 @@ class Interaction : public DiscordObject {
7477
DLL_EXPORT std::optional<DiscordCPP::Guild> get_guild();
7578
/// @return The channel the interaction was sent from.
7679
DLL_EXPORT std::optional<std::string> get_channel_id() const { return channel_id; }
80+
/// @return The channel the interaction was sent from.
81+
DLL_EXPORT std::optional<Channel> get_channel();
7782
/// @return The member that sent the interaction.
7883
DLL_EXPORT std::optional<Member> get_member() const { return member; }
7984
/// @return The user that sent the interaction.

Discord.C++/Permissions.cpp

+22-3
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,19 @@ void DiscordCPP::Permissions::add(const Permissions& permissions) {
2020
this->permissions |= permissions.permissions;
2121
}
2222

23-
bool DiscordCPP::Permissions::has_permission(Permission permission) {
23+
void DiscordCPP::Permissions::remove(const Permission& permission) {
24+
permissions &= ~(1 << permission);
25+
}
26+
27+
void DiscordCPP::Permissions::remove(const Permissions& permissions) {
28+
this->permissions &= ~permissions.permissions;
29+
}
30+
31+
bool DiscordCPP::Permissions::has_permission(Permission permission) const {
2432
return permissions & (1 << permission);
2533
}
2634

27-
bool DiscordCPP::Permissions::has_all_permissions(std::vector<Permission> permissions) {
35+
bool DiscordCPP::Permissions::has_all_permissions(std::vector<Permission> permissions) const {
2836
for (auto permission : permissions) {
2937
if (!has_permission(permission)) {
3038
return false;
@@ -33,11 +41,22 @@ bool DiscordCPP::Permissions::has_all_permissions(std::vector<Permission> permis
3341
return true;
3442
}
3543

36-
bool DiscordCPP::Permissions::has_any_permission(std::vector<Permission> permissions) {
44+
bool DiscordCPP::Permissions::has_any_permission(std::vector<Permission> permissions) const {
3745
for (auto permission : permissions) {
3846
if (has_permission(permission)) {
3947
return true;
4048
}
4149
}
4250
return false;
4351
}
52+
53+
DiscordCPP::PermissionOverwrites::PermissionOverwrites(const json& data) {
54+
id = data.at("id").get<std::string>();
55+
type = static_cast<Type>(data["type"].get<int>());
56+
if (get_or_else<std::string>(data, "allow", "").length() > 0) {
57+
allow = Permissions(data.at("allow").get<std::string>());
58+
}
59+
if (get_or_else<std::string>(data, "deny", "").length() > 0) {
60+
deny = Permissions(data.at("deny").get<std::string>());
61+
}
62+
}

Discord.C++/Permissions.h

+42-3
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,50 @@ class Permissions {
118118
DLL_EXPORT Permissions() : permissions(0) {};
119119
DLL_EXPORT Permissions(const std::string& permissions);
120120

121+
/// add the given permission
121122
DLL_EXPORT void add(const Permission& permission);
123+
/// merge the given permission set
122124
DLL_EXPORT void add(const Permissions& permissions);
125+
/// remove the given permission
126+
DLL_EXPORT void remove(const Permission& permission);
127+
/// remove the given permission set
128+
DLL_EXPORT void remove(const Permissions& permissions);
123129

124-
DLL_EXPORT bool has_permission(Permission permission);
125-
DLL_EXPORT bool has_all_permissions(std::vector<Permission> permissions);
126-
DLL_EXPORT bool has_any_permission(std::vector<Permission> permissions);
130+
/// check if the given permission is set
131+
DLL_EXPORT bool has_permission(Permission permission) const;
132+
/// check if all given permissions is set
133+
DLL_EXPORT bool has_all_permissions(std::vector<Permission> permissions) const;
134+
/// check if at least one of the given permissions is set
135+
DLL_EXPORT bool has_any_permission(std::vector<Permission> permissions) const;
136+
};
137+
138+
class PermissionOverwrites {
139+
public:
140+
enum Type {
141+
ROLE = 0,
142+
MEMBER = 1
143+
};
144+
145+
private:
146+
/// role or user id
147+
std::string id;
148+
/// overwite type
149+
Type type;
150+
/// allowed permissions
151+
Permissions allow;
152+
/// denied permissions
153+
Permissions deny;
154+
155+
public:
156+
DLL_EXPORT PermissionOverwrites(const json& data);
157+
158+
/// @return role or user id
159+
DLL_EXPORT std::string get_id() const { return id; }
160+
/// @return overwite type
161+
DLL_EXPORT Type get_type() const { return type; }
162+
/// @return allowed permissions
163+
DLL_EXPORT Permissions get_allowed_permissions() const { return allow; }
164+
/// @return denied permissions
165+
DLL_EXPORT Permissions get_denied_permissions() const { return deny; }
127166
};
128167
} // namespace DiscordCPP

test_bot/main.cpp

+25-13
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
#include <thread>
33
#include <vector>
44

5-
#include "ApplicationCommand.h"
6-
75
#ifndef _WIN32
86
#include <cstdlib>
97
#endif
@@ -107,13 +105,13 @@ class Client : public Discord {
107105
react.set_type(ApplicationCommand::Type::MESSAGE);
108106
create_application_command(react);
109107

110-
ApplicationCommand admin = ApplicationCommand();
111-
admin.set_name("admin");
112-
admin.set_description("check if you are an admin");
113-
admin.set_type(DiscordCPP::ApplicationCommand::CHAT_INPUT);
114-
admin.add_contexts(DiscordCPP::ApplicationCommand::GUILD);
115-
admin.add_integration_types(DiscordCPP::ApplicationCommand::GUILD_INSTALL);
116-
create_application_command(admin);
108+
ApplicationCommand permissions = ApplicationCommand();
109+
permissions.set_name("permissions");
110+
permissions.set_description("check some permissions");
111+
permissions.set_type(DiscordCPP::ApplicationCommand::CHAT_INPUT);
112+
permissions.add_contexts(DiscordCPP::ApplicationCommand::GUILD);
113+
permissions.add_integration_types(DiscordCPP::ApplicationCommand::GUILD_INSTALL);
114+
create_application_command(permissions);
117115

118116
update_presence(DiscordStatus::Online, Activity("test", Activity::Type::Game));
119117
}
@@ -467,11 +465,25 @@ class Client : public Discord {
467465
this_thread::sleep_for(chrono::seconds(1));
468466
message.remove_all_reactions();
469467
}
470-
} else if (name == "admin") {
471-
if (interaction.get_member().has_value() && interaction.get_guild().has_value()) {
472-
Permissions permissions = interaction.get_guild().value().get_member_permissions(interaction.get_member().value());
468+
} else if (name == "permissions") {
469+
if (interaction.get_member().has_value() && interaction.get_guild().has_value() && interaction.get_channel().has_value()) {
470+
Member member = interaction.get_member().value();
471+
Channel channel = interaction.get_channel().value();
472+
Guild guild = interaction.get_guild().value();
473+
474+
Permissions permissions = guild.get_member_permissions(member);
475+
permissions = channel.merge_permission_overwrites(permissions, member.get_id());
476+
for (auto role : member.get_roles()) {
477+
permissions = channel.merge_permission_overwrites(permissions, role);
478+
}
479+
473480
bool is_admin = permissions.has_permission(DiscordCPP::Permissions::ADMINISTRATOR);
474-
interaction.reply("You are " + std::string(is_admin ? "an" : "no") + " admin");
481+
bool can_delete_messages = permissions.has_permission(DiscordCPP::Permissions::MANAGE_MESSAGES);
482+
bool can_kick_members = permissions.has_permission(DiscordCPP::Permissions::KICK_MEMBERS);
483+
484+
interaction.reply("You are " + std::string(is_admin ? "an" : "no") + " admin" //
485+
+ "\nYou are " + std::string(can_delete_messages ? "" : "not ") + "allowed to delete messages" //
486+
+ "\nYou can " + std::string(can_kick_members ? "" : "not ") + "kick members");
475487
}
476488
}
477489
}

0 commit comments

Comments
 (0)