use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum GroupDiscoverability {
#[default]
Hidden,
ListedToContacts,
PublicDirectory,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum GroupAdmission {
#[default]
InviteOnly,
RequestAccess,
OpenJoin,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum GroupConfidentiality {
#[default]
MlsEncrypted,
SignedPublic,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum GroupReadAccess {
#[default]
MembersOnly,
Public,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum GroupWriteAccess {
#[default]
MembersOnly,
ModeratedPublic,
AdminOnly,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct GroupPolicy {
pub discoverability: GroupDiscoverability,
pub admission: GroupAdmission,
pub confidentiality: GroupConfidentiality,
pub read_access: GroupReadAccess,
pub write_access: GroupWriteAccess,
}
impl Default for GroupPolicy {
fn default() -> Self {
GroupPolicyPreset::PrivateSecure.to_policy()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum GroupPolicyPreset {
PrivateSecure,
PublicRequestSecure,
PublicOpen,
PublicAnnounce,
}
impl GroupPolicyPreset {
#[must_use]
pub fn to_policy(self) -> GroupPolicy {
match self {
Self::PrivateSecure => GroupPolicy {
discoverability: GroupDiscoverability::Hidden,
admission: GroupAdmission::InviteOnly,
confidentiality: GroupConfidentiality::MlsEncrypted,
read_access: GroupReadAccess::MembersOnly,
write_access: GroupWriteAccess::MembersOnly,
},
Self::PublicRequestSecure => GroupPolicy {
discoverability: GroupDiscoverability::PublicDirectory,
admission: GroupAdmission::RequestAccess,
confidentiality: GroupConfidentiality::MlsEncrypted,
read_access: GroupReadAccess::MembersOnly,
write_access: GroupWriteAccess::MembersOnly,
},
Self::PublicOpen => GroupPolicy {
discoverability: GroupDiscoverability::PublicDirectory,
admission: GroupAdmission::OpenJoin,
confidentiality: GroupConfidentiality::SignedPublic,
read_access: GroupReadAccess::Public,
write_access: GroupWriteAccess::MembersOnly,
},
Self::PublicAnnounce => GroupPolicy {
discoverability: GroupDiscoverability::PublicDirectory,
admission: GroupAdmission::OpenJoin,
confidentiality: GroupConfidentiality::SignedPublic,
read_access: GroupReadAccess::Public,
write_access: GroupWriteAccess::AdminOnly,
},
}
}
#[must_use]
pub fn from_name(name: &str) -> Option<Self> {
match name.to_lowercase().replace('-', "_").as_str() {
"private_secure" => Some(Self::PrivateSecure),
"public_request_secure" => Some(Self::PublicRequestSecure),
"public_open" => Some(Self::PublicOpen),
"public_announce" => Some(Self::PublicAnnounce),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct GroupPolicySummary {
pub discoverability: GroupDiscoverability,
pub admission: GroupAdmission,
pub confidentiality: GroupConfidentiality,
#[serde(default)]
pub read_access: GroupReadAccess,
#[serde(default)]
pub write_access: GroupWriteAccess,
}
impl From<&GroupPolicy> for GroupPolicySummary {
fn from(p: &GroupPolicy) -> Self {
Self {
discoverability: p.discoverability,
admission: p.admission,
confidentiality: p.confidentiality,
read_access: p.read_access,
write_access: p.write_access,
}
}
}
impl From<&GroupPolicySummary> for GroupPolicy {
fn from(s: &GroupPolicySummary) -> Self {
Self {
discoverability: s.discoverability,
admission: s.admission,
confidentiality: s.confidentiality,
read_access: s.read_access,
write_access: s.write_access,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn private_secure_defaults() {
let p = GroupPolicyPreset::PrivateSecure.to_policy();
assert_eq!(p.discoverability, GroupDiscoverability::Hidden);
assert_eq!(p.admission, GroupAdmission::InviteOnly);
assert_eq!(p.confidentiality, GroupConfidentiality::MlsEncrypted);
assert_eq!(p.read_access, GroupReadAccess::MembersOnly);
assert_eq!(p.write_access, GroupWriteAccess::MembersOnly);
}
#[test]
fn public_request_secure_preset() {
let p = GroupPolicyPreset::PublicRequestSecure.to_policy();
assert_eq!(p.discoverability, GroupDiscoverability::PublicDirectory);
assert_eq!(p.admission, GroupAdmission::RequestAccess);
assert_eq!(p.confidentiality, GroupConfidentiality::MlsEncrypted);
}
#[test]
fn public_announce_preset() {
let p = GroupPolicyPreset::PublicAnnounce.to_policy();
assert_eq!(p.discoverability, GroupDiscoverability::PublicDirectory);
assert_eq!(p.write_access, GroupWriteAccess::AdminOnly);
}
#[test]
fn default_policy_is_private_secure() {
let default = GroupPolicy::default();
let preset = GroupPolicyPreset::PrivateSecure.to_policy();
assert_eq!(default, preset);
}
#[test]
fn preset_name_parsing() {
assert_eq!(
GroupPolicyPreset::from_name("private_secure"),
Some(GroupPolicyPreset::PrivateSecure)
);
assert_eq!(
GroupPolicyPreset::from_name("PRIVATE-SECURE"),
Some(GroupPolicyPreset::PrivateSecure)
);
assert_eq!(
GroupPolicyPreset::from_name("public_request_secure"),
Some(GroupPolicyPreset::PublicRequestSecure)
);
assert_eq!(GroupPolicyPreset::from_name("nonsense"), None);
}
#[test]
fn summary_from_policy() {
let p = GroupPolicyPreset::PublicRequestSecure.to_policy();
let s: GroupPolicySummary = (&p).into();
assert_eq!(s.admission, GroupAdmission::RequestAccess);
}
}