Skip to main content

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}