From 5cdc3ea29df7314bc8e7941a9de0127f7f9704be Mon Sep 17 00:00:00 2001 From: Alphonse Paix Date: Tue, 16 Sep 2025 15:20:32 +0200 Subject: [PATCH] Remove name from subscriptions table --- ...6131543_remove_name_from_subscriptions.sql | 1 + src/domain.rs | 2 - src/domain/new_subscriber.rs | 3 +- src/domain/subscriber_name.rs | 69 ------------------- src/routes/subscriptions.rs | 16 ++--- templates/home.html | 2 +- tests/api/subscriptions.rs | 25 +++---- tests/api/subscriptions_confirm.rs | 5 +- 8 files changed, 17 insertions(+), 106 deletions(-) create mode 100644 migrations/20250916131543_remove_name_from_subscriptions.sql delete mode 100644 src/domain/subscriber_name.rs diff --git a/migrations/20250916131543_remove_name_from_subscriptions.sql b/migrations/20250916131543_remove_name_from_subscriptions.sql new file mode 100644 index 0000000..0ecbac9 --- /dev/null +++ b/migrations/20250916131543_remove_name_from_subscriptions.sql @@ -0,0 +1 @@ +ALTER TABLE subscriptions DROP COLUMN name; diff --git a/src/domain.rs b/src/domain.rs index e771a2e..3d5a056 100644 --- a/src/domain.rs +++ b/src/domain.rs @@ -1,7 +1,5 @@ mod new_subscriber; mod subscriber_email; -mod subscriber_name; pub use new_subscriber::NewSubscriber; pub use subscriber_email::SubscriberEmail; -pub use subscriber_name::SubscriberName; diff --git a/src/domain/new_subscriber.rs b/src/domain/new_subscriber.rs index 66c678f..fe84a7a 100644 --- a/src/domain/new_subscriber.rs +++ b/src/domain/new_subscriber.rs @@ -1,6 +1,5 @@ -use crate::domain::{SubscriberName, subscriber_email::SubscriberEmail}; +use crate::domain::subscriber_email::SubscriberEmail; pub struct NewSubscriber { pub email: SubscriberEmail, - pub name: SubscriberName, } diff --git a/src/domain/subscriber_name.rs b/src/domain/subscriber_name.rs deleted file mode 100644 index 89171e4..0000000 --- a/src/domain/subscriber_name.rs +++ /dev/null @@ -1,69 +0,0 @@ -use unicode_segmentation::UnicodeSegmentation; - -#[derive(Debug)] -pub struct SubscriberName(String); - -impl SubscriberName { - pub fn parse(s: String) -> Result { - let is_empty_or_whitespace = s.trim().is_empty(); - let is_too_long = s.graphemes(true).count() > 256; - let forbidden_characters = ['/', '(', ')', '"', '<', '>', '\\', '{', '}']; - let contains_forbidden_characters = s.chars().any(|g| forbidden_characters.contains(&g)); - - if is_empty_or_whitespace || is_too_long || contains_forbidden_characters { - Err(format!("{} is not a valid subscriber name.", s)) - } else { - Ok(Self(s)) - } - } -} - -impl AsRef for SubscriberName { - fn as_ref(&self) -> &str { - self.0.as_str() - } -} - -#[cfg(test)] -mod tests { - use crate::domain::SubscriberName; - use claims::{assert_err, assert_ok}; - - #[test] - fn a_256_grapheme_long_name_is_valid() { - let name = "ê".repeat(256); - assert_ok!(SubscriberName::parse(name)); - } - - #[test] - fn a_name_longer_than_256_graphemes_is_rejected() { - let name = "ê".repeat(257); - assert_err!(SubscriberName::parse(name)); - } - - #[test] - fn a_whitespace_only_name_is_rejected() { - let name = "\n \t ".to_string(); - assert_err!(SubscriberName::parse(name)); - } - - #[test] - fn empty_string_is_rejected() { - let name = "".to_string(); - assert_err!(SubscriberName::parse(name)); - } - - #[test] - fn a_name_containing_invalid_character_is_rejected() { - for name in ['/', '(', ')', '"', '<', '>', '\\', '{', '}'] { - let name = name.to_string(); - assert_err!(SubscriberName::parse(name)); - } - } - - #[test] - fn a_valid_name_is_parsed_successfully() { - let name = "Alphonse".to_string(); - assert_ok!(SubscriberName::parse(name)); - } -} diff --git a/src/routes/subscriptions.rs b/src/routes/subscriptions.rs index 1c9640d..6302a94 100644 --- a/src/routes/subscriptions.rs +++ b/src/routes/subscriptions.rs @@ -1,5 +1,5 @@ use crate::{ - domain::{NewSubscriber, SubscriberEmail, SubscriberName}, + domain::{NewSubscriber, SubscriberEmail}, email_client::EmailClient, startup::AppState, }; @@ -82,7 +82,6 @@ impl IntoResponse for SubscribeError { skip(messages, connection_pool, email_client, base_url, form), fields( subscriber_email = %form.email, - subscriber_name = %form.name ) )] pub async fn subscribe( @@ -140,12 +139,11 @@ pub async fn insert_subscriber( let subscriber_id = Uuid::new_v4(); let query = sqlx::query!( r#" - INSERT INTO subscriptions (id, email, name, subscribed_at, status) - VALUES ($1, $2, $3, $4, 'pending_confirmation') + INSERT INTO subscriptions (id, email, subscribed_at, status) + VALUES ($1, $2, $3, 'pending_confirmation') "#, subscriber_id, new_subscriber.email.as_ref(), - new_subscriber.name.as_ref(), Utc::now() ); transaction.execute(query).await?; @@ -209,20 +207,14 @@ Click here to confirm your subscription.", #[derive(Debug, Deserialize)] #[allow(dead_code)] pub struct SubscriptionFormData { - name: String, email: String, - email_check: String, } impl TryFrom for NewSubscriber { type Error = String; fn try_from(value: SubscriptionFormData) -> Result { - let name = SubscriberName::parse(value.name)?; - if value.email != value.email_check { - return Err("Email addresses don't match.".into()); - } let email = SubscriberEmail::parse(value.email)?; - Ok(Self { name, email }) + Ok(Self { email }) } } diff --git a/templates/home.html b/templates/home.html index 38dba5f..0bfcf5c 100644 --- a/templates/home.html +++ b/templates/home.html @@ -117,7 +117,7 @@ block content %}