From 33cd5d0b5c248d80b7001c6bb8f1631294686965 Mon Sep 17 00:00:00 2001 From: itsscb Date: Sat, 15 Mar 2025 22:15:59 +0100 Subject: [PATCH] feat: implement event model for registration process with payload handling --- Cargo.toml | 2 ++ src/lib.rs | 6 ++-- src/model.rs | 2 ++ src/model/event.rs | 59 +++++++++++++++++++++++++++++++++ src/model/event/registration.rs | 54 ++++++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 src/model/event.rs create mode 100644 src/model/event/registration.rs diff --git a/Cargo.toml b/Cargo.toml index 4c2969a..165d564 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,5 @@ tower-http = { version = "0.6.2", features = ["fs"] } tracing = "0.1.41" serde = { version = "1.0.203", features = ["derive"] } lettre = { version = "0.11.15", default-features = false, features = ["builder", "smtp-transport", "ring", "rustls", "rustls-tls"] } +uuid = { version = "1.16.0", features = ["serde", "v4"] } +chrono = "0.4.38" diff --git a/src/lib.rs b/src/lib.rs index 34df6cb..c33d4fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,12 @@ mod api; mod model; -pub use model::config; - use crate::model::config::SMTPConfig; use axum::Router; +pub use model::config; +pub use model::event; +pub use model::Event; +pub use model::EventPayload; use tower_http::services::{ServeDir, ServeFile}; const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/src/model.rs b/src/model.rs index ef68c36..884f07b 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1 +1,3 @@ pub mod config; +pub mod event; +pub use event::{Event, EventPayload}; diff --git a/src/model/event.rs b/src/model/event.rs new file mode 100644 index 0000000..23f1678 --- /dev/null +++ b/src/model/event.rs @@ -0,0 +1,59 @@ +mod registration; +use chrono::{DateTime, Utc}; +pub use registration::RegistrationEvent; +use serde::de::DeserializeOwned; +use serde::{Deserialize, Serialize}; +use std::fmt::Debug; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd)] +#[serde(bound = "T: DeserializeOwned")] +pub struct Event +where + T: EventPayload, +{ + id: uuid::Uuid, + timestamp: DateTime, + version: u32, + domain: String, + payload: T, +} + +impl From for Event +where + T: EventPayload, +{ + fn from(payload: T) -> Self { + Self { + id: uuid::Uuid::new_v4(), + timestamp: Utc::now(), + version: 1, + domain: payload.domain().to_string(), + payload, + } + } +} + +impl Event +where + T: EventPayload, +{ + pub const fn id(&self) -> &uuid::Uuid { + &self.id + } + + pub const fn timestamp(&self) -> &DateTime { + &self.timestamp + } + + pub const fn version(&self) -> u32 { + self.version + } + + pub const fn payload(&self) -> &T { + &self.payload + } +} + +pub trait EventPayload: Debug + Clone + Serialize + DeserializeOwned + PartialEq + Eq { + fn domain(&self) -> &str; +} diff --git a/src/model/event/registration.rs b/src/model/event/registration.rs new file mode 100644 index 0000000..b06c550 --- /dev/null +++ b/src/model/event/registration.rs @@ -0,0 +1,54 @@ +use crate::model::event::EventPayload; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd)] +pub enum RegistrationEvent { + RegistrationRequestReceived { + email_address: String, + }, + VerificationEmailSent { + email_address: String, + secret: String, + }, + VerificationEmailFailed { + email_address: String, + error: String, + }, + VerificationSucceeded { + email_address: String, + }, +} + +impl RegistrationEvent { + #[must_use] + pub const fn registration_request_received(email_address: String) -> Self { + Self::RegistrationRequestReceived { email_address } + } + + #[must_use] + pub const fn verification_email_sent(email_address: String, secret: String) -> Self { + Self::VerificationEmailSent { + email_address, + secret, + } + } + + #[must_use] + pub const fn verification_email_failed(email_address: String, error: String) -> Self { + Self::VerificationEmailFailed { + email_address, + error, + } + } + + #[must_use] + pub const fn verification_succeeded(email_address: String) -> Self { + Self::VerificationSucceeded { email_address } + } +} + +impl EventPayload for RegistrationEvent { + fn domain(&self) -> &'static str { + "registration" + } +}