mirror of
https://github.com/block/buzz.git
synced 2026-11-01 15:01:12 +00:00
Signed-off-by: Tyler Longwell <tlongwell@block.xyz> Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Max <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Mari <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Quinn <96f056ad5f2305c8ddf637dc65d048aa4c12d7daeb8867690e34fca46b0ef64c@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Perci <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
170 lines
4.8 KiB
Rust
170 lines
4.8 KiB
Rust
//! Channel and membership enums shared across crates.
|
|
//!
|
|
//! These live in `buzz-core` (zero I/O deps) so both the SDK (client-side)
|
|
//! and the DB layer (server-side) can use the same types without pulling in
|
|
//! sqlx/tokio.
|
|
|
|
use std::fmt;
|
|
use std::str::FromStr;
|
|
|
|
/// Whether a channel is publicly visible or invite-only.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum ChannelVisibility {
|
|
/// Searchable; anyone can join without an invite.
|
|
Open,
|
|
/// Hidden; requires an invite to join.
|
|
Private,
|
|
}
|
|
|
|
impl ChannelVisibility {
|
|
/// Canonical string representation (matches DB enum and Nostr tags).
|
|
pub fn as_str(&self) -> &'static str {
|
|
match self {
|
|
Self::Open => "open",
|
|
Self::Private => "private",
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for ChannelVisibility {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.write_str(self.as_str())
|
|
}
|
|
}
|
|
|
|
impl FromStr for ChannelVisibility {
|
|
type Err = String;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
match s {
|
|
"open" => Ok(Self::Open),
|
|
"private" => Ok(Self::Private),
|
|
other => Err(format!("unknown channel visibility: {other:?}")),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The functional type of a channel.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum ChannelType {
|
|
/// Linear message stream (the default).
|
|
Stream,
|
|
/// Threaded forum-style discussion.
|
|
Forum,
|
|
/// Direct message conversation.
|
|
Dm,
|
|
/// Internal workflow execution channel.
|
|
Workflow,
|
|
}
|
|
|
|
impl ChannelType {
|
|
/// Canonical string representation (matches DB enum and Nostr tags).
|
|
pub fn as_str(&self) -> &'static str {
|
|
match self {
|
|
Self::Stream => "stream",
|
|
Self::Forum => "forum",
|
|
Self::Dm => "dm",
|
|
Self::Workflow => "workflow",
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for ChannelType {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.write_str(self.as_str())
|
|
}
|
|
}
|
|
|
|
impl FromStr for ChannelType {
|
|
type Err = String;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
match s {
|
|
"stream" => Ok(Self::Stream),
|
|
"forum" => Ok(Self::Forum),
|
|
"dm" => Ok(Self::Dm),
|
|
"workflow" => Ok(Self::Workflow),
|
|
other => Err(format!("unknown channel type: {other:?}")),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A member's role within a channel.
|
|
///
|
|
/// The hierarchy for permission checks is: Owner > Admin > Member > Guest.
|
|
/// Bot is a **separate designation** — it is not part of the linear hierarchy.
|
|
/// Use [`MemberRole::permission_level`] for numeric comparisons in authorization.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum MemberRole {
|
|
/// Full control — can manage members and delete the channel.
|
|
Owner,
|
|
/// Can manage members and channel settings.
|
|
Admin,
|
|
/// Standard participant.
|
|
Member,
|
|
/// Read-only external participant.
|
|
Guest,
|
|
/// Automated agent or integration (not in the role hierarchy).
|
|
Bot,
|
|
}
|
|
|
|
impl MemberRole {
|
|
/// Canonical string representation (matches DB enum and Nostr tags).
|
|
pub fn as_str(&self) -> &'static str {
|
|
match self {
|
|
Self::Owner => "owner",
|
|
Self::Admin => "admin",
|
|
Self::Member => "member",
|
|
Self::Guest => "guest",
|
|
Self::Bot => "bot",
|
|
}
|
|
}
|
|
|
|
/// Elevated roles that only existing owners/admins may grant.
|
|
pub fn is_elevated(&self) -> bool {
|
|
matches!(self, Self::Owner | Self::Admin)
|
|
}
|
|
|
|
/// Numeric permission level for authorization comparisons.
|
|
///
|
|
/// Higher = more privileged. Bot returns 0 (must use explicit grants).
|
|
/// Use `role.permission_level() >= required.permission_level()` for checks.
|
|
pub fn permission_level(self) -> u8 {
|
|
match self {
|
|
Self::Owner => 4,
|
|
Self::Admin => 3,
|
|
Self::Member => 2,
|
|
Self::Guest => 1,
|
|
Self::Bot => 0,
|
|
}
|
|
}
|
|
|
|
/// Returns true if this role meets or exceeds the required role's permission level.
|
|
///
|
|
/// Bot never meets any requirement (returns false for all non-Bot requirements).
|
|
pub fn has_at_least(self, required: MemberRole) -> bool {
|
|
self.permission_level() >= required.permission_level()
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for MemberRole {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.write_str(self.as_str())
|
|
}
|
|
}
|
|
|
|
impl FromStr for MemberRole {
|
|
type Err = String;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
match s {
|
|
"owner" => Ok(Self::Owner),
|
|
"admin" => Ok(Self::Admin),
|
|
"member" => Ok(Self::Member),
|
|
"guest" => Ok(Self::Guest),
|
|
"bot" => Ok(Self::Bot),
|
|
other => Err(format!("unknown member role: {other:?}")),
|
|
}
|
|
}
|
|
}
|