serenity/model/permissions.rs
1//! A set of permissions for a role or user. These can be assigned directly to a role or as a
2//! channel's permission overrides.
3//!
4//! For convenience, methods for each permission are available, which can be used to test if the
5//! set of permissions contains a single permission. This can simplify code and reduce a potential
6//! import.
7//!
8//! Additionally, presets equivalent to the official client's `@everyone` role presets are
9//! available. These are [`PRESET_GENERAL`], [`PRESET_TEXT`], and [`PRESET_VOICE`].
10//!
11//! Permissions follow a hierarchy:
12//! - An account can grant roles to users that are of a lower position than its highest role;
13//! - An account can edit roles lesser than its highest role, but can only grant permissions they
14//! have;
15//! - An account can move only roles lesser than its highest role;
16//! - An account can only kick/ban accounts with a lesser role than its top role.
17//!
18//! **Note**: The following permissions require the owner account (e.g. the owner of a bot) to use
19//! two-factor authentication in the case that a guild has guild-wide 2FA enabled:
20//! - [Administrator]
21//! - [Ban Members]
22//! - [Kick Members]
23//! - [Manage Channels]
24//! - [Manage Guild]
25//! - [Manage Messages]
26//! - [Manage Roles]
27//! - [Manage Webhooks]
28//!
29//! [Administrator]: Permissions::ADMINISTRATOR
30//! [Ban Members]: Permissions::BAN_MEMBERS
31//! [Kick Members]: Permissions::KICK_MEMBERS
32//! [Manage Channels]: Permissions::MANAGE_CHANNELS
33//! [Manage Guild]: Permissions::MANAGE_GUILD
34//! [Manage Messages]: Permissions::MANAGE_MESSAGES
35//! [Manage Roles]: Permissions::MANAGE_ROLES
36//! [Manage Webhooks]: Permissions::MANAGE_WEBHOOKS
37
38#[cfg(feature = "model")]
39use std::fmt;
40
41use serde::de::{Deserialize, Deserializer};
42use serde::ser::{Serialize, Serializer};
43
44use super::utils::StrOrInt;
45
46/// This macro generates the `Permissions` type and methods.
47///
48/// It is invoked by passing the names of all methods used to check for permissions along with
49/// their names displayed inside Discord, and their value.
50///
51/// ## Examples
52///
53/// Using this macro
54///
55/// ```ignore
56/// generate_permissions! {
57/// /// Allows adding reactions to messages in channels.
58/// ADD_REACTIONS, add_reaction, "Add Reactions" = 1 << 6;
59/// };
60/// ```
61///
62/// Generates this implementation:
63///
64/// ```ignore
65/// bitflags::bitflags!(
66/// impl Permissions: u64 {
67/// /// Allows adding reactions to messages in channels.
68/// const ADD_REACTIONS = 1 << 6;
69/// }
70/// )
71///
72/// impl Permissions {
73/// fn add_reactions(self) -> bool {
74/// self.contains(Self::ADD_REACTIONS);
75/// }
76///
77/// fn get_permission_names(self) -> Vec<&'static str> {
78/// let mut names = Vec::new();
79///
80/// if self.add_reactions() {
81/// names.push("Add Reactions");
82/// }
83///
84/// names
85/// }
86/// }
87/// ```
88macro_rules! generate_permissions {
89 {$ (
90 $(#[doc = $doc:literal])*
91 $(#[deprecated = $deprecated:literal])?
92 $perm_upper:ident, $perm_lower:ident, $name:literal = $value:expr
93 );*} => {
94 bitflags::bitflags! {
95 impl Permissions: u64 {
96 $(
97 $(#[doc = $doc])*
98 $(#[deprecated = $deprecated])*
99 const $perm_upper = $value;
100 )*
101 }
102 }
103
104 impl Permissions {
105 $(
106 #[doc = concat!("Shorthand for checking that the set of permissions contains the [", $name, "] permission.")]
107 #[doc = ""]
108 #[doc = concat!("[", $name, "]: Self::", stringify!($perm_upper))]
109 #[must_use]
110 $(
111 #[deprecated = $deprecated]
112 #[allow(deprecated)]
113 )*
114 pub fn $perm_lower(self) -> bool {
115 self.contains(Self::$perm_upper)
116 }
117 )*
118
119 /// Returns a list of names of all contained permissions.
120 #[must_use]
121 #[cfg(feature = "model")]
122 #[allow(deprecated, unused_mut, unused_assignments)]
123 pub fn get_permission_names(self) -> Vec<&'static str> {
124 let mut names = Vec::new();
125
126 $(
127 let mut is_deprecated = false;
128 $(
129 let _ = $deprecated;
130 is_deprecated = true;
131 )*
132
133 if !is_deprecated && self.$perm_lower() {
134 names.push($name);
135 }
136 )*
137
138 names
139 }
140 }
141 }
142}
143
144/// Returns a set of permissions with the original @everyone permissions set to true.
145///
146/// This includes the following permissions:
147/// - [Add Reactions]
148/// - [Attach Files]
149/// - [Change Nickname]
150/// - [Connect]
151/// - [Create Instant Invite]
152/// - [Embed Links]
153/// - [Mention Everyone]
154/// - [Read Message History]
155/// - [View Channel]
156/// - [Send Messages]
157/// - [Send TTS Messages]
158/// - [Speak]
159/// - [Use External Emojis]
160/// - [Use VAD]
161///
162/// **Note**: The [Send TTS Messages] permission is set to `true`. Consider setting this to
163/// `false`, via:
164///
165/// ```rust
166/// use serenity::model::permissions::{self, Permissions};
167///
168/// permissions::PRESET_GENERAL.toggle(Permissions::SEND_TTS_MESSAGES);
169/// ```
170///
171/// [Add Reactions]: Permissions::ADD_REACTIONS
172/// [Attach Files]: Permissions::ATTACH_FILES
173/// [Change Nickname]: Permissions::CHANGE_NICKNAME
174/// [Connect]: Permissions::CONNECT
175/// [Create Instant Invite]: Permissions::CREATE_INSTANT_INVITE
176/// [Embed Links]: Permissions::EMBED_LINKS
177/// [Mention Everyone]: Permissions::MENTION_EVERYONE
178/// [Read Message History]: Permissions::READ_MESSAGE_HISTORY
179/// [View Channel]: Permissions::VIEW_CHANNEL
180/// [Send Messages]: Permissions::SEND_MESSAGES
181/// [Send TTS Messages]: Permissions::SEND_TTS_MESSAGES
182/// [Speak]: Permissions::SPEAK
183/// [Use External Emojis]: Permissions::USE_EXTERNAL_EMOJIS
184/// [Use VAD]: Permissions::USE_VAD
185pub const PRESET_GENERAL: Permissions = Permissions::from_bits_truncate(
186 Permissions::ADD_REACTIONS.bits()
187 | Permissions::ATTACH_FILES.bits()
188 | Permissions::CHANGE_NICKNAME.bits()
189 | Permissions::CONNECT.bits()
190 | Permissions::CREATE_INSTANT_INVITE.bits()
191 | Permissions::EMBED_LINKS.bits()
192 | Permissions::MENTION_EVERYONE.bits()
193 | Permissions::READ_MESSAGE_HISTORY.bits()
194 | Permissions::VIEW_CHANNEL.bits()
195 | Permissions::SEND_MESSAGES.bits()
196 | Permissions::SEND_TTS_MESSAGES.bits()
197 | Permissions::SPEAK.bits()
198 | Permissions::USE_EXTERNAL_EMOJIS.bits()
199 | Permissions::USE_VAD.bits(),
200);
201
202/// Returns a set of text-only permissions with the original `@everyone` permissions set to true.
203///
204/// This includes the text permissions that are in [`PRESET_GENERAL`]:
205/// - [Add Reactions]
206/// - [Attach Files]
207/// - [Change Nickname]
208/// - [Create Instant Invite]
209/// - [Embed Links]
210/// - [Mention Everyone]
211/// - [Read Message History]
212/// - [View Channel]
213/// - [Send Messages]
214/// - [Send TTS Messages]
215/// - [Use External Emojis]
216///
217/// [Add Reactions]: Permissions::ADD_REACTIONS
218/// [Attach Files]: Permissions::ATTACH_FILES
219/// [Change Nickname]: Permissions::CHANGE_NICKNAME
220/// [Create Instant Invite]: Permissions::CREATE_INSTANT_INVITE
221/// [Embed Links]: Permissions::EMBED_LINKS
222/// [Mention Everyone]: Permissions::MENTION_EVERYONE
223/// [Read Message History]: Permissions::READ_MESSAGE_HISTORY
224/// [View Channel]: Permissions::VIEW_CHANNEL
225/// [Send Messages]: Permissions::SEND_MESSAGES
226/// [Send TTS Messages]: Permissions::SEND_TTS_MESSAGES
227/// [Use External Emojis]: Permissions::USE_EXTERNAL_EMOJIS
228pub const PRESET_TEXT: Permissions = Permissions::from_bits_truncate(
229 Permissions::ADD_REACTIONS.bits()
230 | Permissions::ATTACH_FILES.bits()
231 | Permissions::CHANGE_NICKNAME.bits()
232 | Permissions::CREATE_INSTANT_INVITE.bits()
233 | Permissions::EMBED_LINKS.bits()
234 | Permissions::MENTION_EVERYONE.bits()
235 | Permissions::READ_MESSAGE_HISTORY.bits()
236 | Permissions::VIEW_CHANNEL.bits()
237 | Permissions::SEND_MESSAGES.bits()
238 | Permissions::SEND_TTS_MESSAGES.bits()
239 | Permissions::USE_EXTERNAL_EMOJIS.bits(),
240);
241
242/// Returns a set of voice-only permissions with the original `@everyone` permissions set to true.
243///
244/// This includes the voice permissions that are in [`PRESET_GENERAL`]:
245/// - [Connect]
246/// - [Speak]
247/// - [Use VAD]
248///
249/// [Connect]: Permissions::CONNECT
250/// [Speak]: Permissions::SPEAK
251/// [Use VAD]: Permissions::USE_VAD
252pub const PRESET_VOICE: Permissions = Permissions::from_bits_truncate(
253 Permissions::CONNECT.bits() | Permissions::SPEAK.bits() | Permissions::USE_VAD.bits(),
254);
255
256/// A set of permissions that can be assigned to [`User`]s and [`Role`]s via
257/// [`PermissionOverwrite`]s, roles globally in a [`Guild`], and to [`GuildChannel`]s.
258///
259/// [Discord docs](https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags).
260///
261/// [`Guild`]: super::guild::Guild
262/// [`GuildChannel`]: super::channel::GuildChannel
263/// [`PermissionOverwrite`]: super::channel::PermissionOverwrite
264/// [`Role`]: super::guild::Role
265/// [`User`]: super::user::User
266#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
267#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq)]
268#[repr(Rust, packed)]
269pub struct Permissions(u64);
270
271generate_permissions! {
272 /// Allows for the creation of [`RichInvite`]s.
273 ///
274 /// [`RichInvite`]: super::invite::RichInvite
275 CREATE_INSTANT_INVITE, create_instant_invite, "Create Invites" = 1 << 0;
276 /// Allows for the kicking of guild [member]s.
277 ///
278 /// [member]: super::guild::Member
279 KICK_MEMBERS, kick_members, "Kick Members" = 1 << 1;
280 /// Allows the banning of guild [member]s.
281 ///
282 /// [member]: super::guild::Member
283 BAN_MEMBERS, ban_members, "Ban Members" = 1 << 2;
284 /// Allows all permissions, bypassing channel [permission overwrite]s.
285 ///
286 /// [permission overwrite]: super::channel::PermissionOverwrite
287 ADMINISTRATOR, administrator, "Administrator" = 1 << 3;
288 /// Allows management and editing of guild [channel]s.
289 ///
290 /// [channel]: super::channel::GuildChannel
291 MANAGE_CHANNELS, manage_channels, "Manage Channels" = 1 << 4;
292 /// Allows management and editing of the [guild].
293 ///
294 /// [guild]: super::guild::Guild
295 MANAGE_GUILD, manage_guild, "Manage Guild" = 1 << 5;
296 /// [`Member`]s with this permission can add new [`Reaction`]s to a [`Message`]. Members
297 /// can still react using reactions already added to messages without this permission.
298 ///
299 /// [`Member`]: super::guild::Member
300 /// [`Message`]: super::channel::Message
301 /// [`Reaction`]: super::channel::Reaction
302 ADD_REACTIONS, add_reactions, "Add Reactions" = 1 << 6;
303 /// Allows viewing a guild's audit logs.
304 VIEW_AUDIT_LOG, view_audit_log, "View Audit Log" = 1 << 7;
305 /// Allows the use of priority speaking in voice channels.
306 PRIORITY_SPEAKER, priority_speaker, "Priority Speaker" = 1 << 8;
307 /// Allows the user to go live.
308 STREAM, stream, "Stream" = 1 << 9;
309 /// Allows guild members to view a channel, which includes reading messages in text
310 /// channels and joining voice channels.
311 VIEW_CHANNEL, view_channel, "View Channel" = 1 << 10;
312 /// Allows sending messages in a guild channel.
313 SEND_MESSAGES, send_messages, "Send Messages" = 1 << 11;
314 /// Allows the sending of text-to-speech messages in a channel.
315 SEND_TTS_MESSAGES, send_tts_messages, "Send TTS Messages" = 1 << 12;
316 /// Allows the deleting of other messages in a guild channel.
317 ///
318 /// **Note**: This does not allow the editing of other messages.
319 MANAGE_MESSAGES, manage_messages, "Manage Messages" = 1 << 13;
320 /// Allows links from this user - or users of this role - to be embedded, with potential
321 /// data such as a thumbnail, description, and page name.
322 EMBED_LINKS, embed_links, "Embed Links" = 1 << 14;
323 /// Allows uploading of files.
324 ATTACH_FILES, attach_files, "Attach Files" = 1 << 15;
325 /// Allows the reading of a channel's message history.
326 READ_MESSAGE_HISTORY, read_message_history, "Read Message History" = 1 << 16;
327 /// Allows the usage of the `@everyone` mention, which will notify all users in a channel.
328 /// The `@here` mention will also be available, and can be used to mention all non-offline
329 /// users.
330 ///
331 /// **Note**: You probably want this to be disabled for most roles and users.
332 MENTION_EVERYONE, mention_everyone, "Mention @everyone, @here, and All Roles" = 1 << 17;
333 /// Allows the usage of custom emojis from other guilds.
334 ///
335 /// This does not dictate whether custom emojis in this guild can be used in other guilds.
336 USE_EXTERNAL_EMOJIS, use_external_emojis, "Use External Emojis" = 1 << 18;
337 /// Allows for viewing guild insights.
338 VIEW_GUILD_INSIGHTS, view_guild_insights, "View Guild Insights" = 1 << 19;
339 /// Allows the joining of a voice channel.
340 CONNECT, connect, "Connect" = 1 << 20;
341 /// Allows the user to speak in a voice channel.
342 SPEAK, speak, "Speak" = 1 << 21;
343 /// Allows the muting of members in a voice channel.
344 MUTE_MEMBERS, mute_members, "Mute Members" = 1 << 22;
345 /// Allows the deafening of members in a voice channel.
346 DEAFEN_MEMBERS, deafen_members, "Deafen Members" = 1 << 23;
347 /// Allows the moving of members from one voice channel to another.
348 MOVE_MEMBERS, move_members, "Move Members" = 1 << 24;
349 /// Allows the usage of voice-activity-detection in a [voice] channel.
350 ///
351 /// If this is disabled, then [`Member`]s must use push-to-talk.
352 ///
353 /// [`Member`]: super::guild::Member
354 /// [voice]: super::channel::ChannelType::Voice
355 USE_VAD, use_vad, "Use Voice Activity" = 1 << 25;
356 /// Allows members to change their own nickname in the guild.
357 CHANGE_NICKNAME, change_nickname, "Change Nickname" = 1 << 26;
358 /// Allows members to change other members' nicknames.
359 MANAGE_NICKNAMES, manage_nicknames, "Manage Nicknames" = 1 << 27;
360 /// Allows management and editing of roles below their own.
361 MANAGE_ROLES, manage_roles, "Manage Roles" = 1 << 28;
362 /// Allows management of webhooks.
363 MANAGE_WEBHOOKS, manage_webhooks, "Manage Webhooks" = 1 << 29;
364 /// Allows for editing and deleting emojis, stickers, and soundboard sounds created by all
365 /// users.
366 MANAGE_GUILD_EXPRESSIONS, manage_guild_expressions, "Manage Guild Expressions" = 1 << 30;
367 #[deprecated = "use `Permissions::MANAGE_GUILD_EXPRESSIONS` instead"]
368 MANAGE_EMOJIS_AND_STICKERS, manage_emojis_and_stickers, "Manage Emojis and Stickers" = 1 << 30;
369 /// Allows members to use application commands, including slash commands and context menu
370 /// commands.
371 USE_APPLICATION_COMMANDS, use_application_commands, "Use Application Commands" = 1 << 31;
372 /// Allows for requesting to speak in stage channels.
373 REQUEST_TO_SPEAK, request_to_speak, "Request to Speak" = 1 << 32;
374 /// Allows for editing, and deleting scheduled events created by all users.
375 MANAGE_EVENTS, manage_events, "Manage Events" = 1 << 33;
376 /// Allows for deleting and archiving threads, and viewing all private threads.
377 MANAGE_THREADS, manage_threads, "Manage Threads" = 1 << 34;
378 /// Allows for creating threads.
379 CREATE_PUBLIC_THREADS, create_public_threads, "Create Public Threads" = 1 << 35;
380 /// Allows for creating private threads.
381 CREATE_PRIVATE_THREADS, create_private_threads, "Create Private Threads" = 1 << 36;
382 /// Allows the usage of custom stickers from other servers.
383 USE_EXTERNAL_STICKERS, use_external_stickers, "Use External Stickers" = 1 << 37;
384 /// Allows for sending messages in threads
385 SEND_MESSAGES_IN_THREADS, send_messages_in_threads, "Send Messages in Threads" = 1 << 38;
386 /// Allows for launching activities in a voice channel
387 USE_EMBEDDED_ACTIVITIES, use_embedded_activities, "Use Embedded Activities" = 1 << 39;
388 /// Allows for timing out users to prevent them from sending or reacting to messages in
389 /// chat and threads, and from speaking in voice and stage channels.
390 MODERATE_MEMBERS, moderate_members, "Moderate Members" = 1 << 40;
391 /// Allows for viewing role subscription insights.
392 VIEW_CREATOR_MONETIZATION_ANALYTICS, view_creator_monetization_analytics, "View Creator Monetization Analytics" = 1 << 41;
393 /// Allows for using soundboard in a voice channel.
394 USE_SOUNDBOARD, use_soundboard, "Use Soundboard" = 1 << 42;
395 /// Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting
396 /// those created by the current user.
397 CREATE_GUILD_EXPRESSIONS, create_guild_expressions, "Create Guild Expressions" = 1 << 43;
398 /// Allows for creating scheduled events, and editing and deleting those created by the
399 /// current user.
400 CREATE_EVENTS, create_events, "Create Events" = 1 << 44;
401 /// Allows the usage of custom soundboard sounds from other servers.
402 USE_EXTERNAL_SOUNDS, use_external_sounds, "Use External Sounds" = 1 << 45;
403 /// Allows sending voice messages.
404 SEND_VOICE_MESSAGES, send_voice_messages, "Send Voice Messages" = 1 << 46;
405 /// Allows setting the status of a voice channel.
406 SET_VOICE_CHANNEL_STATUS, set_voice_channel_status, "Set Voice Channel status" = 1 << 48;
407 /// Allows attaching polls to message sends.
408 SEND_POLLS, send_polls, "Send Polls" = 1 << 49;
409 /// Allows user-installed apps to send public responses.
410 USE_EXTERNAL_APPS, use_external_apps, "Use External Apps" = 1 << 50
411}
412
413#[cfg(feature = "model")]
414impl Permissions {
415 #[must_use]
416 pub fn dm_permissions() -> Self {
417 Self::ADD_REACTIONS
418 | Self::STREAM
419 | Self::VIEW_CHANNEL
420 | Self::SEND_MESSAGES
421 | Self::SEND_TTS_MESSAGES
422 | Self::EMBED_LINKS
423 | Self::ATTACH_FILES
424 | Self::READ_MESSAGE_HISTORY
425 | Self::MENTION_EVERYONE
426 | Self::USE_EXTERNAL_EMOJIS
427 | Self::CONNECT
428 | Self::SPEAK
429 | Self::USE_VAD
430 | Self::USE_APPLICATION_COMMANDS
431 | Self::USE_EXTERNAL_STICKERS
432 | Self::SEND_VOICE_MESSAGES
433 | Self::SEND_POLLS
434 | Self::USE_EXTERNAL_APPS
435 }
436}
437
438// Manual impl needed because Permissions are usually sent as a stringified integer,
439// but audit log changes are sent as an int, which is probably a problem.
440impl<'de> Deserialize<'de> for Permissions {
441 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
442 let val = StrOrInt::deserialize(deserializer)?;
443 let val = val.parse().map_err(serde::de::Error::custom)?;
444
445 Ok(Permissions::from_bits_truncate(val))
446 }
447}
448
449impl Serialize for Permissions {
450 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
451 serializer.collect_str(&self.bits())
452 }
453}
454
455#[cfg(feature = "model")]
456impl fmt::Display for Permissions {
457 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
458 let names = self.get_permission_names();
459
460 let total = names.len();
461 for (i, &name) in names.iter().enumerate() {
462 if i > 0 && i != total - 1 {
463 f.write_str(", ")?;
464 }
465
466 if total > 1 && i == total - 1 {
467 f.write_str(" and ")?;
468 }
469
470 f.write_str(name)?;
471 }
472
473 Ok(())
474 }
475}
476
477#[cfg(test)]
478mod tests {
479 use super::*;
480 use crate::json::{assert_json, json};
481
482 #[test]
483 fn permissions_serde() {
484 let value = Permissions::MANAGE_GUILD | Permissions::MANAGE_ROLES;
485 assert_json(&value, json!("268435488"));
486 }
487}