add: user secondary permission
This commit is contained in:
parent
339aa59434
commit
9528d71b2a
6 changed files with 128 additions and 95 deletions
|
@ -1,6 +1,9 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use super::{oauth::AuthGrant, permissions::FinePermission};
|
||||
use super::{
|
||||
oauth::AuthGrant,
|
||||
permissions::{FinePermission, SecondaryPermission},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use totp_rs::TOTP;
|
||||
use tetratto_shared::{
|
||||
|
@ -52,6 +55,9 @@ pub struct User {
|
|||
/// The ID of the [`InviteCode`] this user provided during registration.
|
||||
#[serde(default)]
|
||||
pub invite_code: usize,
|
||||
/// Secondary permissions because the regular permissions struct ran out of possible bits.
|
||||
#[serde(default)]
|
||||
pub secondary_permissions: SecondaryPermission,
|
||||
}
|
||||
|
||||
pub type UserConnections =
|
||||
|
@ -287,6 +293,7 @@ impl User {
|
|||
grants: Vec::new(),
|
||||
associated: Vec::new(),
|
||||
invite_code: 0,
|
||||
secondary_permissions: SecondaryPermission::DEFAULT,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,86 +44,110 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for FinePermission {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_u32(self.bits())
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct FinePermissionVisitor;
|
||||
impl Visitor<'_> for FinePermissionVisitor {
|
||||
type Value = FinePermission;
|
||||
|
||||
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) = FinePermission::from_bits(value) {
|
||||
Ok(permission)
|
||||
} else {
|
||||
Ok(FinePermission::from_bits_retain(value))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
|
||||
where
|
||||
E: DeError,
|
||||
{
|
||||
if let Some(permission) = FinePermission::from_bits(value as u32) {
|
||||
Ok(permission)
|
||||
} else {
|
||||
Ok(FinePermission::from_bits_retain(value as u32))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: DeError,
|
||||
{
|
||||
if let Some(permission) = FinePermission::from_bits(value as u32) {
|
||||
Ok(permission)
|
||||
} else {
|
||||
Ok(FinePermission::from_bits_retain(value as u32))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for FinePermission {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_any(FinePermissionVisitor)
|
||||
}
|
||||
}
|
||||
user_permission!(FinePermission, FinePermissionVisitor, check_banned);
|
||||
|
||||
impl FinePermission {
|
||||
/// Join two [`FinePermission`]s into a single `u32`.
|
||||
pub fn join(lhs: FinePermission, rhs: FinePermission) -> FinePermission {
|
||||
lhs | rhs
|
||||
/// Check if the given permission qualifies as "Banned" status.
|
||||
pub fn check_banned(self) -> bool {
|
||||
(self & FinePermission::BANNED) == FinePermission::BANNED
|
||||
}
|
||||
|
||||
/// Check if the given `input` contains the given [`FinePermission`].
|
||||
pub fn check(self, permission: FinePermission) -> bool {
|
||||
if (self & FinePermission::ADMINISTRATOR) == FinePermission::ADMINISTRATOR {
|
||||
// has administrator permission, meaning everything else is automatically true
|
||||
return true;
|
||||
} else if self.check_banned() {
|
||||
// has banned permission, meaning everything else is automatically false
|
||||
return false;
|
||||
}
|
||||
|
||||
(self & permission) == permission
|
||||
}
|
||||
|
||||
/// Check if the given [`FinePermission`] qualifies as "Helper" status.
|
||||
/// 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)
|
||||
|
@ -133,24 +157,26 @@ impl FinePermission {
|
|||
&& self.check(FinePermission::VIEW_AUDIT_LOG)
|
||||
}
|
||||
|
||||
/// Check if the given [`FinePermission`] qualifies as "Manager" status.
|
||||
/// 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 [`FinePermission`] qualifies as "Administrator" status.
|
||||
/// Check if the given permission qualifies as "Administrator" status.
|
||||
pub fn check_admin(self) -> bool {
|
||||
self.check_manager() && self.check(FinePermission::ADMINISTRATOR)
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the given [`FinePermission`] qualifies as "Banned" status.
|
||||
pub fn check_banned(self) -> bool {
|
||||
(self & FinePermission::BANNED) == FinePermission::BANNED
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FinePermission {
|
||||
fn default() -> Self {
|
||||
Self::DEFAULT
|
||||
}
|
||||
}
|
||||
user_permission!(SecondaryPermission, SecondaryPermissionVisitor, sink);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue