tetratto-core 17.0.1

The core behind Tetratto
Documentation
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 UNUSED_0 = 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 UNUSED_1 = 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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            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<E>(self, value: u32) -> Result<Self::Value, E>
            where
                E: DeError,
            {
                if let Some(permission) = $struct::from_bits(value) {
                    Ok(permission)
                } else {
                    Ok($struct::from_bits_retain(value))
                }
            }

            fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
            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<E>(self, value: u64) -> Result<Self::Value, E>
            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<D>(deserializer: D) -> Result<Self, D::Error>
            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 MANAGE_DOMAINS = 1 << 2;
        const MANAGE_SERVICES = 1 << 3;
        const MANAGE_PRODUCTS = 1 << 4;
        const DEVELOPER_PASS = 1 << 5;
        const MANAGE_LETTERS = 1 << 6;
        const MANAGE_GUEST_LOGS = 1 << 7;

        const _ = !0;
    }
}

user_permission!(SecondaryPermission, SecondaryPermissionVisitor, sink);