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 %}