use bitflags::bitflags; use serde::{ Deserialize, Deserializer, Serialize, de::{Error as DeError, Visitor}, }; bitflags! { /// Fine-grained permissions built using bitwise operations. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FinePermission: u32 { const DEFAULT = 1 << 0; const ADMINISTRATOR = 1 << 1; const MANAGE_COMMUNITIES = 1 << 2; const MANAGE_POSTS = 1 << 3; const MANAGE_POST_REPLIES = 1 << 4; const MANAGE_USERS = 1 << 5; const MANAGE_BANS = 1 << 6; const MANAGE_WARNINGS = 1 << 7; const MANAGE_NOTIFICATIONS = 1 << 8; const VIEW_REPORTS = 1 << 9; const VIEW_AUDIT_LOG = 1 << 10; const MANAGE_MEMBERSHIPS = 1 << 11; const MANAGE_REACTIONS = 1 << 12; const MANAGE_FOLLOWS = 1 << 13; const MANAGE_VERIFIED = 1 << 14; const MANAGE_AUDITLOG = 1 << 15; const MANAGE_REPORTS = 1 << 16; const BANNED = 1 << 17; const INFINITE_COMMUNITIES = 1 << 18; const SUPPORTER = 1 << 19; const MANAGE_REQUESTS = 1 << 20; const MANAGE_QUESTIONS = 1 << 21; const MANAGE_CHANNELS = 1 << 22; const MANAGE_MESSAGES = 1 << 23; const MANAGE_UPLOADS = 1 << 24; const MANAGE_EMOJIS = 1 << 25; const MANAGE_STACKS = 1 << 26; const STAFF_BADGE = 1 << 27; const MANAGE_APPS = 1 << 28; const MANAGE_JOURNALS = 1 << 29; const MANAGE_NOTES = 1 << 30; const _ = !0; } } macro_rules! user_permission { ($struct:ident, $visitor:ident, $banned_check:ident) => { impl Serialize for $struct { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.serialize_u32(self.bits()) } } struct $visitor; impl Visitor<'_> for $visitor { type Value = $struct; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("u32") } fn visit_u32(self, value: u32) -> Result where E: DeError, { if let Some(permission) = $struct::from_bits(value) { Ok(permission) } else { Ok($struct::from_bits_retain(value)) } } fn visit_i32(self, value: i32) -> Result where E: DeError, { if let Some(permission) = $struct::from_bits(value as u32) { Ok(permission) } else { Ok($struct::from_bits_retain(value as u32)) } } fn visit_u64(self, value: u64) -> Result where E: DeError, { if let Some(permission) = $struct::from_bits(value as u32) { Ok(permission) } else { Ok($struct::from_bits_retain(value as u32)) } } } impl<'de> Deserialize<'de> for $struct { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_any($visitor) } } impl $struct { /// Join two permissions into a single `u32`. pub fn join(lhs: $struct, rhs: $struct) -> Self { lhs | rhs } /// Check if the given `input` contains the given permission. pub fn check(self, permission: $struct) -> bool { if (self & $struct::ADMINISTRATOR) == $struct::ADMINISTRATOR { // has administrator permission, meaning everything else is automatically true return true; } else if self.$banned_check() { // has banned permission, meaning everything else is automatically false return false; } (self & permission) == permission } /// Sink for checking if the permission is banned. pub fn sink(&self) -> bool { false } } impl Default for $struct { fn default() -> Self { Self::DEFAULT } } }; } user_permission!(FinePermission, FinePermissionVisitor, check_banned); impl FinePermission { /// Check if the given permission qualifies as "Banned" status. pub fn check_banned(self) -> bool { (self & FinePermission::BANNED) == FinePermission::BANNED } /// Check if the given permission qualifies as "Helper" status. pub fn check_helper(self) -> bool { self.check(FinePermission::MANAGE_COMMUNITIES) && self.check(FinePermission::MANAGE_POSTS) && self.check(FinePermission::MANAGE_POST_REPLIES) && self.check(FinePermission::MANAGE_WARNINGS) && self.check(FinePermission::VIEW_REPORTS) && self.check(FinePermission::VIEW_AUDIT_LOG) } /// Check if the given permission qualifies as "Manager" status. pub fn check_manager(self) -> bool { self.check_helper() && self.check(FinePermission::MANAGE_USERS) } /// Check if the given permission qualifies as "Administrator" status. pub fn check_admin(self) -> bool { self.check_manager() && self.check(FinePermission::ADMINISTRATOR) } } bitflags! { /// Fine-grained permissions built using bitwise operations. Second permission value. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SecondaryPermission: u32 { const DEFAULT = 1 << 0; const ADMINISTRATOR = 1 << 1; const _ = !0; } } user_permission!(SecondaryPermission, SecondaryPermissionVisitor, sink);