DiscordCoreAPI
A Discord bot library written in C++, with custom asynchronous coroutines.
Loading...
Searching...
No Matches
RoleEntities.cpp
Go to the documentation of this file.
1/*
2 DiscordCoreAPI, A bot library for Discord, written in C++, and featuring explicit multithreading through the usage of custom, asynchronous C++ CoRoutines.
3
4 Copyright 2021, 2022 Chris M. (RealTimeChris)
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 USA
20*/
21/// RoleEntities.cpp - Source file for the Role related classes and structs.
22/// May 13, 2021
23/// https://discordcoreapi.com
24/// \file RoleEntities.cpp
25
28
29namespace DiscordCoreAPI {
30
31 CreateGuildRoleData::operator Jsonifier() {
32 int32_t roleColorInt = stol(this->hexColorValue, 0, 16);
33 std::stringstream stream;
34 stream << std::setbase(10) << roleColorInt;
35 std::string roleColorReal = stream.str();
36 Jsonifier data{};
37 data["permissions"] = this->permissions.getCurrentPermissionString();
38 data["mentionable"] = this->mentionable;
39 data["hoist"] = this->hoist;
40 data["name"] = this->name;
41 data["color"] = roleColorReal;
42 if (this->icon.size() > 0) {
43 data["icon"] = this->icon;
44 }
45 if (this->unicodeEmoji.size() > 0) {
46 data["unicode_emoji"] = this->unicodeEmoji;
47 }
48 return data;
49 }
50
51 ModifyGuildRolePositionsData::operator Jsonifier() {
52 Jsonifier data{};
53 for (auto& value: this->rolePositions) {
54 Jsonifier newData{};
55 newData["position"] = value.rolePosition;
56 newData["id"] = value.roleId;
57 data.emplaceBack(newData);
58 }
59 return data;
60 }
61
62 ModifyGuildRoleData::operator Jsonifier() {
63 int32_t roleColorInt = stol(this->hexColorValue, 0, 16);
64 std::stringstream stream;
65 stream << std::setbase(10) << roleColorInt;
66 std::string roleColorReal = stream.str();
67 Jsonifier data{};
68 data["permissions"] = this->permissions.getCurrentPermissionString();
69 data["mentionable"] = this->mentionable;
70 data["hoist"] = this->hoist;
71 data["name"] = this->name;
72 data["color"] = roleColorReal;
73 if (this->icon.size() > 0) {
74 data["icon"] = this->icon;
75 }
76 if (this->unicodeEmoji.size() > 0) {
77 data["unicode_emoji"] = this->unicodeEmoji;
78 }
79 return data;
80 }
81
82 Role::Role(simdjson::ondemand::value jsonObjectData) {
83 this->id = getId(jsonObjectData, "id");
84
85 this->icon = getString(jsonObjectData, "icon");
86
87 this->name = getString(jsonObjectData, "name");
88
89 std::stringstream stream{};
90 stream << getString(jsonObjectData, "unicode_emoji");
91 for (auto& value: stream.str()) {
92 this->unicodeEmoji.emplace_back(value);
93 }
94 if (this->unicodeEmoji.size() > 3) {
95 this->unicodeEmoji = static_cast<std::string>(this->unicodeEmoji).substr(1, this->unicodeEmoji.size() - 3);
96 }
97
98 this->color = getUint32(jsonObjectData, "color");
99
100 uint8_t newFlags{};
101
102 newFlags = setBool(newFlags, RoleFlags::Hoist, getBool(jsonObjectData, "hoist"));
103
104 this->position = getUint32(jsonObjectData, "position");
105
106 this->permissions = getString(jsonObjectData, "permissions");
107
108 newFlags = setBool(newFlags, RoleFlags::Managed, getBool(jsonObjectData, "managed"));
109
110 newFlags = setBool(newFlags, RoleFlags::Mentionable, getBool(jsonObjectData, "mentionable"));
111
112 this->flags = static_cast<RoleFlags>(newFlags);
113
114 simdjson::ondemand::value roleTagsNew{};
115 if (jsonObjectData["tags"].get(roleTagsNew) == simdjson::error_code::SUCCESS) {
116 RoleTagsData roleTags{ roleTagsNew };
117 this->tags = std::move(roleTags);
118 }
119 }
120
121 RoleVector::RoleVector(simdjson::ondemand::value jsonObjectData) {
122 if (jsonObjectData.type() != simdjson::ondemand::json_type::null) {
123 simdjson::ondemand::array arrayValue{};
124 if (getArray(arrayValue, jsonObjectData)) {
125 for (simdjson::simdjson_result<simdjson::ondemand::value> value: arrayValue) {
126 Role newData{ value.value() };
127 this->roles.emplace_back(std::move(newData));
128 }
129 }
130 }
131 }
132
133 Role& Role::operator=(RoleData&& other) noexcept {
134 if (this != &other) {
135 this->unicodeEmoji = std::move(other.unicodeEmoji);
136 this->permissions = std::move(other.permissions);
137 this->name = std::move(other.name);
138 this->position = other.position;
139 this->guildId = other.guildId;
140 this->flags = other.flags;
141 this->color = other.color;
142 this->id = other.id;
143 }
144 return *this;
145 }
146
147 Role::Role(RoleData&& other) noexcept {
148 *this = std::move(other);
149 }
150
151 Role& Role::operator=(const RoleData& other) noexcept {
152 if (this != &other) {
153 this->unicodeEmoji = other.unicodeEmoji;
154 this->permissions = other.permissions;
155 this->position = other.position;
156 this->guildId = other.guildId;
157 this->flags = other.flags;
158 this->color = other.color;
159 this->name = other.name;
160 this->id = other.id;
161 }
162 return *this;
163 }
164
165 Role::Role(const RoleData& other) noexcept {
166 *this = other;
167 }
168
169 RoleVector::operator std::vector<Role>() {
170 return this->roles;
171 }
172
173 void Roles::initialize(DiscordCoreInternal::HttpsClient* client, ConfigManager* configManagerNew) {
174 Roles::doWeCacheRolesBool = configManagerNew->doWeCacheRoles();
175 Roles::httpsClient = client;
176 }
177
179 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Put_Guild_Member_Role };
180 co_await NewThreadAwaitable<void>();
181 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Put;
182 workload.relativePath = "/guilds/" + dataPackage.guildId + "/members/" + dataPackage.userId + "/roles/" + dataPackage.roleId;
183 workload.callStack = "Roles::addGuildMemberRoleAsync()";
184 if (dataPackage.reason != "") {
185 workload.headersToInsert["X-Audit-Log-Reason"] = dataPackage.reason;
186 }
187 co_return Roles::httpsClient->submitWorkloadAndGetResult<void>(workload);
188 }
189
191 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Delete_Guild_Member_Role };
192 co_await NewThreadAwaitable<void>();
193 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Delete;
194 workload.relativePath = "/guilds/" + dataPackage.guildId + "/members/" + dataPackage.userId + "/roles/" + dataPackage.roleId;
195 workload.callStack = "Roles::removeGuildMemberRoleAsync()";
196 if (dataPackage.reason != "") {
197 workload.headersToInsert["X-Audit-Log-Reason"] = dataPackage.reason;
198 }
199 co_return Roles::httpsClient->submitWorkloadAndGetResult<void>(workload);
200 }
201
203 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Get_Guild_Roles };
204 co_await NewThreadAwaitable<std::vector<Role>>();
205 if (dataPackage.guildId == 0) {
206 throw DCAException{ "Roles::getGuildRolesAsync() Error: Sorry, but you forgot to set the guildId!\n\n" };
207 }
208 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Get;
209 workload.relativePath = "/guilds/" + dataPackage.guildId + "/roles";
210 workload.callStack = "Roles::getGuildRolesAsync()";
211 RoleVector returnValue{};
212 co_return Roles::httpsClient->submitWorkloadAndGetResult<RoleVector>(workload, &returnValue);
213 }
214
216 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Post_Guild_Role };
217 co_await NewThreadAwaitable<Role>();
218 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Post;
219 workload.relativePath = "/guilds/" + dataPackage.guildId + "/roles";
220 auto serializer = dataPackage.operator Jsonifier();
221 serializer.refreshString(JsonifierSerializeType::Json);
222 workload.content = serializer.operator std::string();
223 workload.callStack = "Roles::createGuildRoleAsync()";
224 if (dataPackage.reason != "") {
225 workload.headersToInsert["X-Audit-Log-Reason"] = dataPackage.reason;
226 }
227 Role returnValue{};
228 auto roleNew = Roles::httpsClient->submitWorkloadAndGetResult<Role>(workload, &returnValue);
229 ModifyGuildRolePositionsData newDataPackage{};
230 newDataPackage.guildId = dataPackage.guildId;
231 newDataPackage.newPosition = dataPackage.position;
232 newDataPackage.roleId = roleNew.id;
233 auto results = modifyGuildRolePositionsAsync(newDataPackage).get();
234 for (auto& value: results) {
235 if (value.id == roleNew.id) {
236 roleNew = value;
237 }
238 }
239 co_return std::move(roleNew);
240 }
241
243 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Patch_Guild_Role_Positions };
244 co_await NewThreadAwaitable<std::vector<Role>>();
245 std::vector<Role> currentRoles = Roles::getGuildRolesAsync({ .guildId = dataPackage.guildId }).get();
246 RoleData newRole = Roles::getCachedRole({ .roleId = dataPackage.roleId });
247 for (auto& value: currentRoles) {
248 if (value.id == newRole.id) {
249 continue;
250 }
251 RolePositionData newData;
252 if (newRole.position < dataPackage.newPosition) {
253 if (value.position <= dataPackage.newPosition && value.position > newRole.position) {
254 newData.roleId = value.id;
255 newData.rolePosition = value.position - 1;
256 dataPackage.rolePositions.emplace_back(newData);
257 }
258 } else {
259 if (value.position >= dataPackage.newPosition && value.position < newRole.position) {
260 newData.roleId = value.id;
261 newData.rolePosition = value.position + 1;
262 dataPackage.rolePositions.emplace_back(newData);
263 }
264 }
265 }
266 RolePositionData newDataPos;
267 newDataPos.roleId = dataPackage.roleId;
268 newDataPos.rolePosition = dataPackage.newPosition;
269 dataPackage.rolePositions.emplace_back(newDataPos);
270 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Patch;
271 workload.relativePath = "/guilds/" + dataPackage.guildId + "/roles";
272 auto serializer = dataPackage.operator Jsonifier();
273 serializer.refreshString(JsonifierSerializeType::Json);
274 workload.content = serializer.operator std::string();
275 workload.callStack = "Roles::modifyGuildRolePositionsAsync()";
276 if (dataPackage.reason != "") {
277 workload.headersToInsert["X-Audit-Log-Reason"] = dataPackage.reason;
278 }
279 RoleVector returnValue{};
280 co_return Roles::httpsClient->submitWorkloadAndGetResult<RoleVector>(workload, &returnValue);
281 }
282
284 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Patch_Guild_Role };
285 co_await NewThreadAwaitable<Role>();
286 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Patch;
287 workload.relativePath = "/guilds/" + dataPackage.guildId + "/roles/" + dataPackage.roleId;
288 auto serializer = dataPackage.operator Jsonifier();
289 serializer.refreshString(JsonifierSerializeType::Json);
290 workload.content = serializer.operator std::string();
291 workload.callStack = "Roles::modifyGuildRoleAsync()";
292 if (dataPackage.reason != "") {
293 workload.headersToInsert["X-Audit-Log-Reason"] = dataPackage.reason;
294 }
295 Role data{};
296 data = Roles::httpsClient->submitWorkloadAndGetResult<Role>(workload, &data);
297 if (Roles::cache.contains(data)) {
298 data = Roles::cache.at(data);
299 } else {
300 Roles::insertRole(data);
301 }
302 co_return std::move(data);
303 }
304
306 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Delete_Guild_Role };
307 co_await NewThreadAwaitable<void>();
308 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Delete;
309 workload.relativePath = "/guilds/" + dataPackage.guildId + "/roles/" + dataPackage.roleId;
310 workload.callStack = "Roles::removeGuildRoleAsync()";
311 if (dataPackage.reason != "") {
312 workload.headersToInsert["X-Audit-Log-Reason"] = dataPackage.reason;
313 }
314 co_return Roles::httpsClient->submitWorkloadAndGetResult<void>(workload);
315 }
316
318 co_await NewThreadAwaitable<std::vector<Role>>();
319 std::vector<Role> rolesVector = getGuildRolesAsync({ .guildId = dataPackage.guildId }).get();
320 std::vector<Role> rolesVectorNew{};
321 for (auto& value: rolesVector) {
322 for (auto& value2: dataPackage.guildMember.roles) {
323 if (value2 == value.id) {
324 rolesVectorNew.emplace_back(value);
325 }
326 }
327 }
328 co_return std::move(rolesVectorNew);
329 }
330
332 co_await NewThreadAwaitable<Role>();
333 auto roles = getGuildRolesAsync({ .guildId = dataPackage.guildId }).get();
334 if (dataPackage.guildId == 0) {
335 throw DCAException{ "Roles::getRoleAsync() Error: Sorry, but you forgot to set the guildId!\n\n" };
336 }
337 for (auto& value: roles) {
338 if (value.id == dataPackage.roleId) {
339 value.guildId = dataPackage.guildId;
340 co_return std::move(value);
341 }
342 }
343 co_return {};
344 }
345
347 RoleData data{};
348 data.id = dataPackage.roleId;
349 if (!Roles::cache.contains(data)) {
350 return Roles::getRoleAsync(dataPackage).get();
351 } else {
352 data = Roles::cache.at(data);
353 return data;
354 }
355 }
356 StopWatch<Milliseconds> stopWatchNew{ 5ms };
357 void Roles::insertRole(RoleData role) {
358 if (role.id == 0) {
359 return;
360 }
361 if (Roles::doWeCacheRoles()) {
362 if (!Roles::cache.contains(role)) {
363 Roles::cache.emplace(std::move(role));
364 } else {
365 Roles::cache[role] = std::move(role);
366 }
367 if (Roles::cache.size() % 10000 == 0) {
368 std::cout << "ROLE COUNT: " << Roles::cache.size() << ", AFTER: " << stopWatchNew.totalTimePassed().count() << "s" << std::endl;
369 }
370 }
371 }
372
373 void Roles::removeRole(const Snowflake roleId) {
374 RoleData data{};
375 data.id = roleId;
376 Roles::cache.erase(data);
377 };
378
379 bool Roles::doWeCacheRoles() {
380 return Roles::doWeCacheRolesBool;
381 }
382
383 DiscordCoreInternal::HttpsClient* Roles::httpsClient{ nullptr };
384 bool Roles::doWeCacheRolesBool{};
385 ObjectCache<RoleData> Roles::cache{};
386}
The main namespace for this library.
A CoRoutine - representing a potentially asynchronous operation/function.
Definition: CoRoutine.hpp:59
Data structure representing a single Role.
Permissions permissions
The Role's base Guild Permissions.
StringWrapper name
The Role's name.
int16_t position
Its position amongst the rest of the Guild's roles.
ColorValue color
The Role's color.
StringWrapper unicodeEmoji
Emoji representing the Role.
RoleFlags flags
Role flags.
std::vector< Snowflake > roles
The Guild roles that they have.
For addin a Role to a GuildMember.
std::string reason
Reason for adding the GuildMember's Role.
Snowflake userId
The id of the User to whom to assign the Role.
Snowflake roleId
The id of the Role to be assigned.
Snowflake guildId
The id of the Guild within which to assign the Role.
For removing a Role from a GuildMember.
Snowflake userId
The id of the User from whom to remove the Role.
std::string reason
Reason for removing the GuildMember's Role.
Snowflake guildId
The id of the Guild within which to remove the Role.
Snowflake roleId
The id of the Role to be removed.
For getting a chosen Guild's Roles.
Snowflake guildId
Guild id for which Guild to get the roles from.
For creating a new Role within a chosen Guild.
int32_t position
The position amongst the other roles.
Snowflake guildId
Which Guild to make the Role in.
std::string reason
Reason for creating the Role.
For updating the positions of the roles.
int32_t rolePosition
The new Role position.
Snowflake roleId
The Role to update.
For updating the Role positions.
Snowflake guildId
The Guild within which to move the Role.
std::string reason
Reason for modifying the Role positions.
int32_t newPosition
The new position of the Role.
Snowflake roleId
The id of the Role to move.
For updating a Role's options within a chosen Guild.
Snowflake roleId
The id of the Role to update.
std::string reason
< Reason for modifying the Role.
Snowflake guildId
The id of the Guild within which to update the Role.
For removing a Role from a chosen Guild.
Snowflake roleId
The id of the Role to remove.
std::string reason
Reason for removing this Role.
Snowflake guildId
The id of the Guild from which to remove the Role.
For getting a chosen GuildMember's Roles.
GuildMember guildMember
Which Guild member to collect the roles from.
Snowflake guildId
Which Guild to collect their roles from.
For getting a Role from the library's cache, or the Discord server.
Snowflake guildId
Which Guild to collect the Role from.
Snowflake roleId
Which Role to collect.
RoleTagsData tags
Role tags for the Role.
IconHash icon
Icon representing the Role.
static CoRoutine< void > removeGuildMemberRoleAsync(RemoveGuildMemberRoleData dataPackage)
Removes a given Role from a chosen GuildMember.
static RoleData getCachedRole(GetRoleData dataPackage)
Collects a given Role from the library's cache.
static CoRoutine< std::vector< Role > > getGuildMemberRolesAsync(GetGuildMemberRolesData dataPackage)
Collects the Roles that a GuildMember has.
static CoRoutine< std::vector< Role > > modifyGuildRolePositionsAsync(ModifyGuildRolePositionsData dataPackage)
Updates a Role's positions.
static CoRoutine< Role > getRoleAsync(GetRoleData dataPackage)
Collects a Role from the Discord servers.
static CoRoutine< std::vector< Role > > getGuildRolesAsync(GetGuildRolesData dataPackage)
Collects the Roles that a Guild has.
static CoRoutine< void > addGuildMemberRoleAsync(AddGuildMemberRoleData dataPackage)
Adds a Role to a chosen Guild member.
static CoRoutine< Role > modifyGuildRoleAsync(ModifyGuildRoleData dataPackage)
Updates a given Role's properties.
static CoRoutine< void > removeGuildRoleAsync(RemoveGuildRoleData dataPackage)
Removes a given Role from a Guild.
static CoRoutine< Role > createGuildRoleAsync(CreateGuildRoleData dataPackage)
Creates a new Role within the given Guild.