tetratto_core/model/
permissions.rs

1use bitflags::bitflags;
2use serde::{
3    Deserialize, Deserializer, Serialize,
4    de::{Error as DeError, Visitor},
5};
6
7bitflags! {
8    /// Fine-grained permissions built using bitwise operations.
9    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
10    pub struct FinePermission: u32 {
11        const DEFAULT = 1 << 0;
12        const ADMINISTRATOR = 1 << 1;
13        const MANAGE_COMMUNITIES = 1 << 2;
14        const MANAGE_POSTS = 1 << 3;
15        const MANAGE_POST_REPLIES = 1 << 4;
16        const MANAGE_USERS = 1 << 5;
17        const MANAGE_BANS = 1 << 6;
18        const MANAGE_WARNINGS = 1 << 7;
19        const MANAGE_NOTIFICATIONS = 1 << 8;
20        const VIEW_REPORTS = 1 << 9;
21        const VIEW_AUDIT_LOG = 1 << 10;
22        const MANAGE_MEMBERSHIPS = 1 << 11;
23        const MANAGE_REACTIONS = 1 << 12;
24        const MANAGE_FOLLOWS = 1 << 13;
25        const MANAGE_VERIFIED = 1 << 14;
26        const MANAGE_AUDITLOG = 1 << 15;
27        const MANAGE_REPORTS = 1 << 16;
28        const BANNED = 1 << 17;
29        const INFINITE_COMMUNITIES = 1 << 18;
30        const SUPPORTER = 1 << 19;
31        const MANAGE_REQUESTS = 1 << 20;
32        const MANAGE_QUESTIONS = 1 << 21;
33        const MANAGE_CHANNELS = 1 << 22;
34        const MANAGE_MESSAGES = 1 << 23;
35        const MANAGE_UPLOADS = 1 << 24;
36        const MANAGE_EMOJIS = 1 << 25;
37        const MANAGE_STACKS = 1 << 26;
38        const STAFF_BADGE = 1 << 27;
39        const MANAGE_APPS = 1 << 28;
40        const MANAGE_JOURNALS = 1 << 29;
41        const MANAGE_NOTES = 1 << 30;
42
43        const _ = !0;
44    }
45}
46
47macro_rules! user_permission {
48    ($struct:ident, $visitor:ident, $banned_check:ident) => {
49        impl Serialize for $struct {
50            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
51            where
52                S: serde::Serializer,
53            {
54                serializer.serialize_u32(self.bits())
55            }
56        }
57
58        struct $visitor;
59        impl Visitor<'_> for $visitor {
60            type Value = $struct;
61
62            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
63                formatter.write_str("u32")
64            }
65
66            fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
67            where
68                E: DeError,
69            {
70                if let Some(permission) = $struct::from_bits(value) {
71                    Ok(permission)
72                } else {
73                    Ok($struct::from_bits_retain(value))
74                }
75            }
76
77            fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
78            where
79                E: DeError,
80            {
81                if let Some(permission) = $struct::from_bits(value as u32) {
82                    Ok(permission)
83                } else {
84                    Ok($struct::from_bits_retain(value as u32))
85                }
86            }
87
88            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
89            where
90                E: DeError,
91            {
92                if let Some(permission) = $struct::from_bits(value as u32) {
93                    Ok(permission)
94                } else {
95                    Ok($struct::from_bits_retain(value as u32))
96                }
97            }
98        }
99
100        impl<'de> Deserialize<'de> for $struct {
101            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
102            where
103                D: Deserializer<'de>,
104            {
105                deserializer.deserialize_any($visitor)
106            }
107        }
108
109        impl $struct {
110            /// Join two permissions into a single `u32`.
111            pub fn join(lhs: $struct, rhs: $struct) -> Self {
112                lhs | rhs
113            }
114
115            /// Check if the given `input` contains the given permission.
116            pub fn check(self, permission: $struct) -> bool {
117                if (self & $struct::ADMINISTRATOR) == $struct::ADMINISTRATOR {
118                    // has administrator permission, meaning everything else is automatically true
119                    return true;
120                } else if self.$banned_check() {
121                    // has banned permission, meaning everything else is automatically false
122                    return false;
123                }
124
125                (self & permission) == permission
126            }
127
128            /// Sink for checking if the permission is banned.
129            pub fn sink(&self) -> bool {
130                false
131            }
132        }
133
134        impl Default for $struct {
135            fn default() -> Self {
136                Self::DEFAULT
137            }
138        }
139    };
140}
141
142user_permission!(FinePermission, FinePermissionVisitor, check_banned);
143
144impl FinePermission {
145    /// Check if the given permission qualifies as "Banned" status.
146    pub fn check_banned(self) -> bool {
147        (self & FinePermission::BANNED) == FinePermission::BANNED
148    }
149
150    /// Check if the given permission qualifies as "Helper" status.
151    pub fn check_helper(self) -> bool {
152        self.check(FinePermission::MANAGE_COMMUNITIES)
153            && self.check(FinePermission::MANAGE_POSTS)
154            && self.check(FinePermission::MANAGE_POST_REPLIES)
155            && self.check(FinePermission::MANAGE_WARNINGS)
156            && self.check(FinePermission::VIEW_REPORTS)
157            && self.check(FinePermission::VIEW_AUDIT_LOG)
158    }
159
160    /// Check if the given permission qualifies as "Manager" status.
161    pub fn check_manager(self) -> bool {
162        self.check_helper() && self.check(FinePermission::MANAGE_USERS)
163    }
164
165    /// Check if the given permission qualifies as "Administrator" status.
166    pub fn check_admin(self) -> bool {
167        self.check_manager() && self.check(FinePermission::ADMINISTRATOR)
168    }
169}
170
171bitflags! {
172    /// Fine-grained permissions built using bitwise operations. Second permission value.
173    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
174    pub struct SecondaryPermission: u32 {
175        const DEFAULT = 1 << 0;
176        const ADMINISTRATOR = 1 << 1;
177        const MANAGE_DOMAINS = 1 << 2;
178        const MANAGE_SERVICES = 1 << 3;
179        const MANAGE_PRODUCTS = 1 << 4;
180        const DEVELOPER_PASS = 1 << 5;
181        const MANAGE_LETTERS = 1 << 6;
182
183        const _ = !0;
184    }
185}
186
187user_permission!(SecondaryPermission, SecondaryPermissionVisitor, sink);