add: user secondary permission
This commit is contained in:
parent
339aa59434
commit
9528d71b2a
6 changed files with 128 additions and 95 deletions
|
@ -393,10 +393,6 @@
|
||||||
(script ("id" "editor_content") ("type" "text/markdown") (text "{{ note.content|remove_script_tags|safe }}"))
|
(script ("id" "editor_content") ("type" "text/markdown") (text "{{ note.content|remove_script_tags|safe }}"))
|
||||||
(script
|
(script
|
||||||
(text "setTimeout(async () => {
|
(text "setTimeout(async () => {
|
||||||
if (!document.getElementById(\"preview_tab\").shadowRoot) {
|
|
||||||
document.getElementById(\"preview_tab\").attachShadow({ mode: \"open\" });
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById(\"editor_tab\").innerHTML = \"\";
|
document.getElementById(\"editor_tab\").innerHTML = \"\";
|
||||||
globalThis.editor = CodeMirror(document.getElementById(\"editor_tab\"), {
|
globalThis.editor = CodeMirror(document.getElementById(\"editor_tab\"), {
|
||||||
value: document.getElementById(\"editor_content\").innerHTML,
|
value: document.getElementById(\"editor_content\").innerHTML,
|
||||||
|
@ -451,8 +447,7 @@
|
||||||
).text();
|
).text();
|
||||||
|
|
||||||
const preview_token = window.crypto.randomUUID();
|
const preview_token = window.crypto.randomUUID();
|
||||||
document.getElementById(\"preview_tab\").shadowRoot.innerHTML = `${res}<style>
|
document.getElementById(\"preview_tab\").innerHTML = `${res}<style>
|
||||||
@import url(\"/css/style.css\");
|
|
||||||
@import url(\"/api/v1/journals/{{ journal.id }}/journal.css?v=preview-${preview_token}\");
|
@import url(\"/api/v1/journals/{{ journal.id }}/journal.css?v=preview-${preview_token}\");
|
||||||
</style>`;
|
</style>`;
|
||||||
trigger(\"atto::hooks::tabs:switch\", [\"preview\"]);
|
trigger(\"atto::hooks::tabs:switch\", [\"preview\"]);
|
||||||
|
|
|
@ -3,6 +3,7 @@ use oiseau::cache::Cache;
|
||||||
use crate::model::auth::UserConnections;
|
use crate::model::auth::UserConnections;
|
||||||
use crate::model::moderation::AuditLogEntry;
|
use crate::model::moderation::AuditLogEntry;
|
||||||
use crate::model::oauth::AuthGrant;
|
use crate::model::oauth::AuthGrant;
|
||||||
|
use crate::model::permissions::SecondaryPermission;
|
||||||
use crate::model::{
|
use crate::model::{
|
||||||
Error, Result,
|
Error, Result,
|
||||||
auth::{Token, User, UserSettings},
|
auth::{Token, User, UserSettings},
|
||||||
|
@ -46,6 +47,7 @@ impl DataManager {
|
||||||
grants: serde_json::from_str(&get!(x->19(String)).to_string()).unwrap(),
|
grants: serde_json::from_str(&get!(x->19(String)).to_string()).unwrap(),
|
||||||
associated: serde_json::from_str(&get!(x->20(String)).to_string()).unwrap(),
|
associated: serde_json::from_str(&get!(x->20(String)).to_string()).unwrap(),
|
||||||
invite_code: get!(x->21(i64)) as usize,
|
invite_code: get!(x->21(i64)) as usize,
|
||||||
|
secondary_permissions: SecondaryPermission::from_bits(get!(x->7(i32)) as u32).unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +226,8 @@ impl DataManager {
|
||||||
&"",
|
&"",
|
||||||
&serde_json::to_string(&data.grants).unwrap(),
|
&serde_json::to_string(&data.grants).unwrap(),
|
||||||
&serde_json::to_string(&data.associated).unwrap(),
|
&serde_json::to_string(&data.associated).unwrap(),
|
||||||
&(data.invite_code as i64)
|
&(data.invite_code as i64),
|
||||||
|
&(SecondaryPermission::DEFAULT.bits() as i32),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -19,5 +19,6 @@ CREATE TABLE IF NOT EXISTS users (
|
||||||
connections TEXT NOT NULL,
|
connections TEXT NOT NULL,
|
||||||
stripe_id TEXT NOT NULL,
|
stripe_id TEXT NOT NULL,
|
||||||
grants TEXT NOT NULL,
|
grants TEXT NOT NULL,
|
||||||
associated TEXT NOT NULL
|
associated TEXT NOT NULL,
|
||||||
|
secondary_permissions INT NOT NULL
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use super::{oauth::AuthGrant, permissions::FinePermission};
|
use super::{
|
||||||
|
oauth::AuthGrant,
|
||||||
|
permissions::{FinePermission, SecondaryPermission},
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use totp_rs::TOTP;
|
use totp_rs::TOTP;
|
||||||
use tetratto_shared::{
|
use tetratto_shared::{
|
||||||
|
@ -52,6 +55,9 @@ pub struct User {
|
||||||
/// The ID of the [`InviteCode`] this user provided during registration.
|
/// The ID of the [`InviteCode`] this user provided during registration.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub invite_code: usize,
|
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 =
|
pub type UserConnections =
|
||||||
|
@ -287,6 +293,7 @@ impl User {
|
||||||
grants: Vec::new(),
|
grants: Vec::new(),
|
||||||
associated: Vec::new(),
|
associated: Vec::new(),
|
||||||
invite_code: 0,
|
invite_code: 0,
|
||||||
|
secondary_permissions: SecondaryPermission::DEFAULT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,18 +44,20 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for FinePermission {
|
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>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
serializer.serialize_u32(self.bits())
|
serializer.serialize_u32(self.bits())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FinePermissionVisitor;
|
struct $visitor;
|
||||||
impl Visitor<'_> for FinePermissionVisitor {
|
impl Visitor<'_> for $visitor {
|
||||||
type Value = FinePermission;
|
type Value = $struct;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
formatter.write_str("u32")
|
formatter.write_str("u32")
|
||||||
|
@ -65,10 +67,10 @@ impl Visitor<'_> for FinePermissionVisitor {
|
||||||
where
|
where
|
||||||
E: DeError,
|
E: DeError,
|
||||||
{
|
{
|
||||||
if let Some(permission) = FinePermission::from_bits(value) {
|
if let Some(permission) = $struct::from_bits(value) {
|
||||||
Ok(permission)
|
Ok(permission)
|
||||||
} else {
|
} else {
|
||||||
Ok(FinePermission::from_bits_retain(value))
|
Ok($struct::from_bits_retain(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,10 +78,10 @@ impl Visitor<'_> for FinePermissionVisitor {
|
||||||
where
|
where
|
||||||
E: DeError,
|
E: DeError,
|
||||||
{
|
{
|
||||||
if let Some(permission) = FinePermission::from_bits(value as u32) {
|
if let Some(permission) = $struct::from_bits(value as u32) {
|
||||||
Ok(permission)
|
Ok(permission)
|
||||||
} else {
|
} else {
|
||||||
Ok(FinePermission::from_bits_retain(value as u32))
|
Ok($struct::from_bits_retain(value as u32))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,35 +89,35 @@ impl Visitor<'_> for FinePermissionVisitor {
|
||||||
where
|
where
|
||||||
E: DeError,
|
E: DeError,
|
||||||
{
|
{
|
||||||
if let Some(permission) = FinePermission::from_bits(value as u32) {
|
if let Some(permission) = $struct::from_bits(value as u32) {
|
||||||
Ok(permission)
|
Ok(permission)
|
||||||
} else {
|
} else {
|
||||||
Ok(FinePermission::from_bits_retain(value as u32))
|
Ok($struct::from_bits_retain(value as u32))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for FinePermission {
|
impl<'de> Deserialize<'de> for $struct {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
deserializer.deserialize_any(FinePermissionVisitor)
|
deserializer.deserialize_any($visitor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl FinePermission {
|
impl $struct {
|
||||||
/// Join two [`FinePermission`]s into a single `u32`.
|
/// Join two permissions into a single `u32`.
|
||||||
pub fn join(lhs: FinePermission, rhs: FinePermission) -> FinePermission {
|
pub fn join(lhs: $struct, rhs: $struct) -> Self {
|
||||||
lhs | rhs
|
lhs | rhs
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the given `input` contains the given [`FinePermission`].
|
/// Check if the given `input` contains the given permission.
|
||||||
pub fn check(self, permission: FinePermission) -> bool {
|
pub fn check(self, permission: $struct) -> bool {
|
||||||
if (self & FinePermission::ADMINISTRATOR) == FinePermission::ADMINISTRATOR {
|
if (self & $struct::ADMINISTRATOR) == $struct::ADMINISTRATOR {
|
||||||
// has administrator permission, meaning everything else is automatically true
|
// has administrator permission, meaning everything else is automatically true
|
||||||
return true;
|
return true;
|
||||||
} else if self.check_banned() {
|
} else if self.$banned_check() {
|
||||||
// has banned permission, meaning everything else is automatically false
|
// has banned permission, meaning everything else is automatically false
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -123,7 +125,29 @@ impl FinePermission {
|
||||||
(self & permission) == permission
|
(self & permission) == permission
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the given [`FinePermission`] qualifies as "Helper" status.
|
/// 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 {
|
pub fn check_helper(self) -> bool {
|
||||||
self.check(FinePermission::MANAGE_COMMUNITIES)
|
self.check(FinePermission::MANAGE_COMMUNITIES)
|
||||||
&& self.check(FinePermission::MANAGE_POSTS)
|
&& self.check(FinePermission::MANAGE_POSTS)
|
||||||
|
@ -133,24 +157,26 @@ impl FinePermission {
|
||||||
&& self.check(FinePermission::VIEW_AUDIT_LOG)
|
&& 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 {
|
pub fn check_manager(self) -> bool {
|
||||||
self.check_helper() && self.check(FinePermission::MANAGE_USERS)
|
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 {
|
pub fn check_admin(self) -> bool {
|
||||||
self.check_manager() && self.check(FinePermission::ADMINISTRATOR)
|
self.check_manager() && self.check(FinePermission::ADMINISTRATOR)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if the given [`FinePermission`] qualifies as "Banned" status.
|
bitflags! {
|
||||||
pub fn check_banned(self) -> bool {
|
/// Fine-grained permissions built using bitwise operations. Second permission value.
|
||||||
(self & FinePermission::BANNED) == FinePermission::BANNED
|
#[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 {
|
user_permission!(SecondaryPermission, SecondaryPermissionVisitor, sink);
|
||||||
fn default() -> Self {
|
|
||||||
Self::DEFAULT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,8 +14,9 @@ pub fn render_markdown(input: &str) -> String {
|
||||||
},
|
},
|
||||||
parse: ParseOptions {
|
parse: ParseOptions {
|
||||||
constructs: Constructs {
|
constructs: Constructs {
|
||||||
gfm_autolink_literal: true,
|
math_flow: true,
|
||||||
..Default::default()
|
math_text: true,
|
||||||
|
..Constructs::gfm()
|
||||||
},
|
},
|
||||||
gfm_strikethrough_single_tilde: false,
|
gfm_strikethrough_single_tilde: false,
|
||||||
math_text_single_dollar: false,
|
math_text_single_dollar: false,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue