use std::collections::BTreeSet;
use std::fmt;
use std::str::FromStr;
use nostr::{EventId, PublicKey, RelayUrl, Timestamp, UnsignedEvent};
use openmls::group::GroupId;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use super::error::WelcomeError;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct ProcessedWelcome {
pub wrapper_event_id: EventId,
pub welcome_event_id: Option<EventId>,
pub processed_at: Timestamp,
pub state: ProcessedWelcomeState,
pub failure_reason: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Welcome {
pub id: EventId,
pub event: UnsignedEvent,
pub mls_group_id: GroupId,
pub nostr_group_id: [u8; 32],
pub group_name: String,
pub group_description: String,
pub group_image_url: Option<String>,
pub group_image_key: Option<Vec<u8>>,
pub group_image_nonce: Option<Vec<u8>>,
pub group_admin_pubkeys: BTreeSet<PublicKey>,
pub group_relays: BTreeSet<RelayUrl>,
pub welcomer: PublicKey,
pub member_count: u32,
pub state: WelcomeState,
pub wrapper_event_id: EventId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ProcessedWelcomeState {
Processed,
Failed,
}
impl fmt::Display for ProcessedWelcomeState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl ProcessedWelcomeState {
pub fn as_str(&self) -> &str {
match self {
Self::Processed => "processed",
Self::Failed => "failed",
}
}
}
impl FromStr for ProcessedWelcomeState {
type Err = WelcomeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"processed" => Ok(Self::Processed),
"failed" => Ok(Self::Failed),
_ => Err(WelcomeError::InvalidParameters(format!(
"Invalid processed welcome state: {}",
s
))),
}
}
}
impl Serialize for ProcessedWelcomeState {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl<'de> Deserialize<'de> for ProcessedWelcomeState {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s: String = String::deserialize(deserializer)?;
Self::from_str(&s).map_err(serde::de::Error::custom)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum WelcomeState {
Pending,
Accepted,
Declined,
Ignored,
}
impl fmt::Display for WelcomeState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl WelcomeState {
pub fn as_str(&self) -> &str {
match self {
Self::Pending => "pending",
Self::Accepted => "accepted",
Self::Declined => "declined",
Self::Ignored => "ignored",
}
}
}
impl FromStr for WelcomeState {
type Err = WelcomeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"pending" => Ok(Self::Pending),
"accepted" => Ok(Self::Accepted),
"declined" => Ok(Self::Declined),
"ignored" => Ok(Self::Ignored),
_ => Err(WelcomeError::InvalidParameters(format!(
"Invalid welcome state: {}",
s
))),
}
}
}
impl Serialize for WelcomeState {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl<'de> Deserialize<'de> for WelcomeState {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s: String = String::deserialize(deserializer)?;
Self::from_str(&s).map_err(serde::de::Error::custom)
}
}
#[cfg(test)]
mod tests {
use serde_json::json;
use super::*;
#[test]
fn test_processed_welcome_state_from_str() {
assert_eq!(
ProcessedWelcomeState::from_str("processed").unwrap(),
ProcessedWelcomeState::Processed
);
assert_eq!(
ProcessedWelcomeState::from_str("failed").unwrap(),
ProcessedWelcomeState::Failed
);
let err = ProcessedWelcomeState::from_str("invalid").unwrap_err();
match err {
WelcomeError::InvalidParameters(msg) => {
assert!(msg.contains("Invalid processed welcome state: invalid"));
}
_ => panic!("Expected InvalidParameters error"),
}
}
#[test]
fn test_processed_welcome_state_to_string() {
assert_eq!(ProcessedWelcomeState::Processed.to_string(), "processed");
assert_eq!(ProcessedWelcomeState::Failed.to_string(), "failed");
}
#[test]
fn test_processed_welcome_state_serialization() {
let processed = ProcessedWelcomeState::Processed;
let serialized = serde_json::to_string(&processed).unwrap();
assert_eq!(serialized, r#""processed""#);
let failed = ProcessedWelcomeState::Failed;
let serialized = serde_json::to_string(&failed).unwrap();
assert_eq!(serialized, r#""failed""#);
}
#[test]
fn test_processed_welcome_state_deserialization() {
let processed: ProcessedWelcomeState = serde_json::from_str(r#""processed""#).unwrap();
assert_eq!(processed, ProcessedWelcomeState::Processed);
let failed: ProcessedWelcomeState = serde_json::from_str(r#""failed""#).unwrap();
assert_eq!(failed, ProcessedWelcomeState::Failed);
}
#[test]
fn test_welcome_state_from_str() {
assert_eq!(
WelcomeState::from_str("pending").unwrap(),
WelcomeState::Pending
);
assert_eq!(
WelcomeState::from_str("accepted").unwrap(),
WelcomeState::Accepted
);
assert_eq!(
WelcomeState::from_str("declined").unwrap(),
WelcomeState::Declined
);
assert_eq!(
WelcomeState::from_str("ignored").unwrap(),
WelcomeState::Ignored
);
let err = WelcomeState::from_str("invalid").unwrap_err();
match err {
WelcomeError::InvalidParameters(msg) => {
assert!(msg.contains("Invalid welcome state: invalid"));
}
_ => panic!("Expected InvalidParameters error"),
}
}
#[test]
fn test_welcome_state_to_string() {
assert_eq!(WelcomeState::Pending.to_string(), "pending");
assert_eq!(WelcomeState::Accepted.to_string(), "accepted");
assert_eq!(WelcomeState::Declined.to_string(), "declined");
assert_eq!(WelcomeState::Ignored.to_string(), "ignored");
}
#[test]
fn test_welcome_state_serialization() {
let pending = WelcomeState::Pending;
let serialized = serde_json::to_string(&pending).unwrap();
assert_eq!(serialized, r#""pending""#);
let accepted = WelcomeState::Accepted;
let serialized = serde_json::to_string(&accepted).unwrap();
assert_eq!(serialized, r#""accepted""#);
let declined = WelcomeState::Declined;
let serialized = serde_json::to_string(&declined).unwrap();
assert_eq!(serialized, r#""declined""#);
let ignored = WelcomeState::Ignored;
let serialized = serde_json::to_string(&ignored).unwrap();
assert_eq!(serialized, r#""ignored""#);
}
#[test]
fn test_welcome_state_deserialization() {
let pending: WelcomeState = serde_json::from_str(r#""pending""#).unwrap();
assert_eq!(pending, WelcomeState::Pending);
let accepted: WelcomeState = serde_json::from_str(r#""accepted""#).unwrap();
assert_eq!(accepted, WelcomeState::Accepted);
let declined: WelcomeState = serde_json::from_str(r#""declined""#).unwrap();
assert_eq!(declined, WelcomeState::Declined);
let ignored: WelcomeState = serde_json::from_str(r#""ignored""#).unwrap();
assert_eq!(ignored, WelcomeState::Ignored);
}
#[test]
fn test_processed_welcome_serialization() {
let processed_welcome = ProcessedWelcome {
wrapper_event_id: EventId::all_zeros(), welcome_event_id: None,
processed_at: Timestamp::now(),
state: ProcessedWelcomeState::Processed,
failure_reason: None,
};
let serialized = serde_json::to_value(&processed_welcome).unwrap();
assert_eq!(serialized["state"], json!("processed"));
assert_eq!(serialized["failure_reason"], json!(null));
}
}