From 3671ca7598bb361e7609d4f64f41c1e1fb93745f Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Wed, 19 Apr 2023 17:08:39 -0700 Subject: [PATCH 1/5] Add rudementry email template support, available with the auth plugin --- Cargo.lock | 7 + create-rust-app/Cargo.toml | 173 ++++++++++++++++++------- create-rust-app/src/auth/controller.rs | 26 ++-- create-rust-app/src/auth/mod.rs | 2 +- create-rust-app/src/lib.rs | 16 ++- create-rust-app/src/mailer.rs | 109 ++++++++++++++++ 6 files changed, 271 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5bb68acd..da73a694 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1390,6 +1390,7 @@ dependencies = [ "diesel_derives", "diesel_migrations", "dotenv", + "dyn-clone", "env_logger", "fang", "futures", @@ -1720,6 +1721,12 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "dyn-clone" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" + [[package]] name = "either" version = "1.8.1" diff --git a/create-rust-app/Cargo.toml b/create-rust-app/Cargo.toml index f31a33c6..436867d9 100644 --- a/create-rust-app/Cargo.toml +++ b/create-rust-app/Cargo.toml @@ -8,7 +8,13 @@ readme = "../README.md" repository = "https://github.com/Wulf/create-rust-app" license = "MIT OR Apache-2.0" keywords = ["react", "typescript", "generation", "backend", "frontend"] -categories = ["command-line-utilities", "development-tools", "web-programming", "config", "database"] +categories = [ + "command-line-utilities", + "development-tools", + "web-programming", + "config", + "database", +] [dependencies] ## @@ -17,10 +23,14 @@ categories = ["command-line-utilities", "development-tools", "web-programming", dotenv = "0.15.0" # + plugin_dev serde_json = "1.0.93" lettre = "0.10.2" -tera = { version="1.17.0" } -lazy_static = { version="1.4.0" } +tera = { version = "1.17.0" } +lazy_static = { version = "1.4.0" } serde = { version = "1.0.152", features = ["derive"] } -diesel = { version="2.0.0-rc.1", default-features = false, features = ["uuid", "r2d2", "chrono"] } # + plugin_dev, plugin_auth +diesel = { version = "2.0.0-rc.1", default-features = false, features = [ + "uuid", + "r2d2", + "chrono", +] } # + plugin_dev, plugin_auth once_cell = "1.17.1" ## @@ -35,83 +45,150 @@ libsqlite3-sys = { version = "0.25", optional = true, features = ["bundled"] } ## # plugin_auth -rust-argon2 = { optional=true, version="1.0" } -rand = { optional=true, version="0.8.5" } -jsonwebtoken = { optional=true, version="8.2.0" } -tsync = { optional=true, version="1.6.0" } -chrono = { optional=true, version = "0.4.23", default-features = false, features = ["clock", "serde"] } +rust-argon2 = { optional = true, version = "1.0" } +rand = { optional = true, version = "0.8.5" } +jsonwebtoken = { optional = true, version = "8.2.0" } +tsync = { optional = true, version = "1.6.0" } +chrono = { optional = true, version = "0.4.23", default-features = false, features = [ + "clock", + "serde", +] } +dyn-clone = { optional = true, version = "1.0" } # needed to allow the Mailer struct to be cloned # plugin_dev -diesel_migrations = { optional=true, version="2.0.0" } -cargo_metadata = { optional=true, version="0.15.2" } -watchexec = { optional=true, version="2.2.0" } +diesel_migrations = { optional = true, version = "2.0.0" } +cargo_metadata = { optional = true, version = "0.15.2" } +watchexec = { optional = true, version = "2.2.0" } #### tracing = { optional=true, version="0.1" } #### tracing-subscriber = { optional=true, version="0.3.16", features=["env-filter"] } -reqwest = { optional=true, version="0.11.13" } -clearscreen = { optional=true, version="2.0.0" } -open = { optional=true, version="3.2.0" } -cargo_toml = { optional=true, version = "0.14.0" } +reqwest = { optional = true, version = "0.11.13" } +clearscreen = { optional = true, version = "2.0.0" } +open = { optional = true, version = "3.2.0" } +cargo_toml = { optional = true, version = "0.14.0" } # plugin_storage -aws-config = { optional=true, version="0.14.0" } -aws-types = { optional=true, version="0.8.0" } -aws-endpoint = { optional=true, version="0.14.0" } -aws-sdk-s3 = { optional=true, version="0.8.0" } -http = { optional=true, version="0.2.6" } -diesel_derives = { optional=true, version="2.0.1" } -uuid = { optional=true, version="1.2.2", features=["v4", "serde"] } -md5 = { optional=true, version="0.7.0" } -base64 = { optional=true, version="0.21.0" } +aws-config = { optional = true, version = "0.14.0" } +aws-types = { optional = true, version = "0.8.0" } +aws-endpoint = { optional = true, version = "0.14.0" } +aws-sdk-s3 = { optional = true, version = "0.8.0" } +http = { optional = true, version = "0.2.6" } +diesel_derives = { optional = true, version = "2.0.1" } +uuid = { optional = true, version = "1.2.2", features = ["v4", "serde"] } +md5 = { optional = true, version = "0.7.0" } +base64 = { optional = true, version = "0.21.0" } # plugin_utoipa dependencies -utoipa = { optional=true, version="3", features=["actix_extras", "chrono", "openapi_extensions"] } -utoipa-swagger-ui = { optional=true, version="3", features=["actix-web"]} +utoipa = { optional = true, version = "3", features = [ + "actix_extras", + "chrono", + "openapi_extensions", +] } +utoipa-swagger-ui = { optional = true, version = "3", features = ["actix-web"] } # plugin_tasks -fang = { optional=true, version = "0.10.3" } +fang = { optional = true, version = "0.10.3" } ## ## BACKENDS ## # poem dependencies -poem = { optional=true, version="1.3.52", features=["anyhow", "cookie", "static-files"] } +poem = { optional = true, version = "1.3.52", features = [ + "anyhow", + "cookie", + "static-files", +] } # actix_web dependencies -actix-multipart = { optional=true, version="0.4.0" } -actix-files = { optional=true, version="0.6.2" } -actix-http = { optional=true, version="3.0.4" } -actix-web = { optional=true, version="4.2.1" } -actix-web-httpauth = { optional=true, version="0.8.0" } -derive_more = { optional=true, version="0.99.17" } -futures = { optional=true, version="0.3.25" } -env_logger = { optional=true, version= "0.10.0" } +actix-multipart = { optional = true, version = "0.4.0" } +actix-files = { optional = true, version = "0.6.2" } +actix-http = { optional = true, version = "3.0.4" } +actix-web = { optional = true, version = "4.2.1" } +actix-web-httpauth = { optional = true, version = "0.8.0" } +derive_more = { optional = true, version = "0.99.17" } +futures = { optional = true, version = "0.3.25" } +env_logger = { optional = true, version = "0.10.0" } # axum dependencies (not yet released; only used for plugin_dev) -axum = { optional=true, version="0.6.1" } +axum = { optional = true, version = "0.6.1" } ## ## MISC - here, we list deps which are required by multiple features but are not required in all configurations ## -mime_guess = { optional=true, version="2.0.4" } # backend_poem, plugin_storage -anyhow = { optional=true, version="1.0.57" } # backend_poem, plugin_auth, plugin_dev -tokio = { optional=true, version = "1", features = ["full"] } # backend_poem, backend_axum, plugin_storage +mime_guess = { optional = true, version = "2.0.4" } # backend_poem, plugin_storage +anyhow = { optional = true, version = "1.0.57" } # backend_poem, plugin_auth, plugin_dev +tokio = { optional = true, version = "1", features = [ + "full", +] } # backend_poem, backend_axum, plugin_storage async-priority-channel = "0.1.0" -futures-util = { optional=true, version = "0.3.25" } # plugin_dev, TODO:plugin_storage? +futures-util = { optional = true, version = "0.3.25" } # plugin_dev, TODO:plugin_storage? [features] -default = ["backend_actix-web", "database_postgres", "plugin_auth", "plugin_container", "plugin_dev", "plugin_graphql", "plugin_storage", "plugin_utoipa"] -plugin_dev = ["backend_axum", "cargo_toml", "open", "reqwest", "anyhow", "clearscreen", "watchexec", "cargo_metadata", "diesel_migrations", "futures-util"] +default = [ + "backend_actix-web", + "database_postgres", + "plugin_auth", + "plugin_container", + "plugin_dev", + "plugin_graphql", + "plugin_storage", + "plugin_utoipa", +] +plugin_dev = [ + "backend_axum", + "cargo_toml", + "open", + "reqwest", + "anyhow", + "clearscreen", + "watchexec", + "cargo_metadata", + "diesel_migrations", + "futures-util", +] plugin_container = [] -plugin_auth = ["anyhow", "rust-argon2", "rand", "jsonwebtoken", "chrono", "tsync"] -plugin_storage = [ "aws-config", "aws-types", "aws-endpoint", "aws-sdk-s3", "tokio", "http", "diesel_derives", "uuid", "md5", "mime_guess", "base64" ] # note: might need to add "futures-util"? +plugin_auth = [ + "anyhow", + "rust-argon2", + "rand", + "jsonwebtoken", + "chrono", + "tsync", + "dyn-clone", +] +plugin_storage = [ + "aws-config", + "aws-types", + "aws-endpoint", + "aws-sdk-s3", + "tokio", + "http", + "diesel_derives", + "uuid", + "md5", + "mime_guess", + "base64", +] # note: might need to add "futures-util"? plugin_graphql = [] plugin_utoipa = ["utoipa", "utoipa-swagger-ui", "backend_actix-web"] plugin_tasks = ["fang"] backend_poem = ["poem", "anyhow", "mime_guess", "tokio"] -backend_actix-web = ["actix-web", "actix-http", "actix-files", "actix-multipart", "actix-web-httpauth","derive_more", "futures", "env_logger"] +backend_actix-web = [ + "actix-web", + "actix-http", + "actix-files", + "actix-multipart", + "actix-web-httpauth", + "derive_more", + "futures", + "env_logger", +] backend_axum = ["axum", "axum/ws", "tokio"] -database_sqlite = ["diesel/sqlite", "diesel/returning_clauses_for_sqlite_3_35", "libsqlite3-sys/bundled"] +database_sqlite = [ + "diesel/sqlite", + "diesel/returning_clauses_for_sqlite_3_35", + "libsqlite3-sys/bundled", +] database_postgres = ["diesel/postgres"] diff --git a/create-rust-app/src/auth/controller.rs b/create-rust-app/src/auth/controller.rs index b9132bba..052fbd11 100644 --- a/create-rust-app/src/auth/controller.rs +++ b/create-rust-app/src/auth/controller.rs @@ -529,11 +529,9 @@ pub fn register( ) .unwrap(); - mail::auth_register::send( - mailer, - &user.email, - &format!("http://localhost:3000/activate?token={token}"), - ); + mailer + .templates + .send_register(mailer, &user.email, &format!("activate?token={token}")); Ok(()) } @@ -598,7 +596,7 @@ pub fn activate( return Err((500, "Could not activate user.")); } - mail::auth_activated::send(mailer, &user.email); + mailer.templates.send_activated(mailer, &user.email); Ok(()) } @@ -642,11 +640,15 @@ pub fn forgot_password( ) .unwrap(); - let link = &format!("http://localhost:3000/reset?token={reset_token}"); - mail::auth_recover_existent_account::send(mailer, &user.email, link); + let link = &format!("reset?token={reset_token}"); + mailer + .templates + .send_recover_existent_account(mailer, &user.email, link); } else { - let link = &"http://localhost:300/register".to_string(); - mail::auth_recover_nonexistent_account::send(mailer, &item.email, link); + let link = &"register".to_string(); + mailer + .templates + .send_recover_nonexistent_account(mailer, &item.email, link); } Ok(()) @@ -718,7 +720,7 @@ pub fn change_password( return Err((500, "Could not update password")); } - mail::auth_password_changed::send(mailer, &user.email); + mailer.templates.send_password_changed(mailer, &user.email); Ok(()) } @@ -794,7 +796,7 @@ pub fn reset_password( return Err((500, "Could not update password")); } - mail::auth_password_reset::send(mailer, &user.email); + mailer.templates.send_password_reset(mailer, &user.email); Ok(()) } diff --git a/create-rust-app/src/auth/mod.rs b/create-rust-app/src/auth/mod.rs index ec6642b4..e8dcb0b0 100644 --- a/create-rust-app/src/auth/mod.rs +++ b/create-rust-app/src/auth/mod.rs @@ -15,7 +15,7 @@ pub mod controller; mod endpoints; pub use endpoints::*; -mod mail; +pub(crate) mod mail; mod permissions; mod schema; mod user; diff --git a/create-rust-app/src/lib.rs b/create-rust-app/src/lib.rs index 8cae7cb6..ba49cd86 100644 --- a/create-rust-app/src/lib.rs +++ b/create-rust-app/src/lib.rs @@ -11,6 +11,9 @@ compile_error!( // #[cfg(not(any(feature = "backend_poem", feature = "backend_actix-web")))] // compile_error!("Please enable one of the backend features (options: 'backend_actix-web', 'backend-poem')"); +#[cfg(feature = "plugin_auth")] +use mailer::EmailTemplates; + mod util; pub use util::*; @@ -67,6 +70,17 @@ pub struct AppData { pub storage: Storage, } +#[cfg(feature = "plugin_auth")] +impl AppData { + pub fn with_custom_email_templates( + mut self, + templates: T, + ) -> Self { + self.mailer = Mailer::new(Box::new(templates)); + self + } +} + #[cfg(debug_assertions)] fn load_env_vars() { static START: std::sync::Once = std::sync::Once::new(); @@ -103,7 +117,7 @@ pub fn setup() -> AppData { } AppData { - mailer: Mailer::new(), + mailer: Mailer::default(), database: Database::new(), #[cfg(feature = "plugin_storage")] storage: Storage::new(), diff --git a/create-rust-app/src/mailer.rs b/create-rust-app/src/mailer.rs index e2b84d0a..ef217d57 100644 --- a/create-rust-app/src/mailer.rs +++ b/create-rust-app/src/mailer.rs @@ -1,8 +1,32 @@ +#[cfg(feature = "plugin_auth")] +use crate::auth::mail::{ + auth_activated, auth_password_changed, auth_password_reset, auth_recover_existent_account, + auth_recover_nonexistent_account, auth_register, +}; +#[cfg(feature = "plugin_auth")] +use dyn_clone::{clone_trait_object, DynClone}; + use lettre::message::{Message, MultiPart}; use lettre::transport::smtp::authentication::Credentials; use lettre::transport::stub::StubTransport; use lettre::{SmtpTransport, Transport}; +// the DyncClone trait bound is for cloning, and the +// Send trait bound is for thread-safety +#[cfg(feature = "plugin_auth")] +/// A trait that defines the behavior of an email template +pub trait EmailTemplates: DynClone + Send { + fn send_activated(&self, mailer: &Mailer, to_email: &str); + fn send_password_changed(&self, mailer: &Mailer, to_email: &str); + fn send_password_reset(&self, mailer: &Mailer, to_email: &str); + fn send_recover_existent_account(&self, mailer: &Mailer, to_email: &str, link: &str); + fn send_recover_nonexistent_account(&self, mailer: &Mailer, to_email: &str, link: &str); + fn send_register(&self, mailer: &Mailer, to_email: &str, link: &str); +} + +#[cfg(feature = "plugin_auth")] +clone_trait_object!(EmailTemplates); + #[derive(Clone)] /// struct used to handle sending emails pub struct Mailer { @@ -29,9 +53,17 @@ pub struct Mailer { /// /// set by the `SEND_MAIL` environment variable pub actually_send: bool, + #[cfg(feature = "plugin_auth")] + // Structure containing email templates to be used for various purposes + pub templates: Box, } impl Default for Mailer { + #[cfg(feature = "plugin_auth")] + fn default() -> Self { + Self::new(Box::new(DefaultMailTemplates::default())) + } + #[cfg(not(feature = "plugin_auth"))] fn default() -> Self { Self::new() } @@ -43,6 +75,7 @@ impl Mailer { /// /// allows webservers to send emails to users for purposes /// like marketing, user authentification, etc. + #[cfg(not(feature = "plugin_auth"))] pub fn new() -> Self { Mailer::check_environment_variables(); @@ -56,13 +89,36 @@ impl Mailer { let actually_send: bool = std::env::var("SEND_MAIL") .unwrap_or_else(|_| "false".to_string()) .eq_ignore_ascii_case("true"); + Mailer { + from_address, + smtp_server, + smtp_username, + smtp_password, + actually_send, + } + } + + #[cfg(feature = "plugin_auth")] + pub fn new(templates: Box) -> Self { + Mailer::check_environment_variables(); + let from_address: String = std::env::var("SMTP_FROM_ADDRESS") + .unwrap_or_else(|_| "create-rust-app@localhost".to_string()); + let smtp_server: String = std::env::var("SMTP_SERVER").unwrap_or_else(|_| "".to_string()); + let smtp_username: String = + std::env::var("SMTP_USERNAME").unwrap_or_else(|_| "".to_string()); + let smtp_password: String = + std::env::var("SMTP_PASSWORD").unwrap_or_else(|_| "".to_string()); + let actually_send: bool = std::env::var("SEND_MAIL") + .unwrap_or_else(|_| "false".to_string()) + .eq_ignore_ascii_case("true"); Mailer { from_address, smtp_server, smtp_username, smtp_password, actually_send, + templates, } } @@ -158,3 +214,56 @@ message: } } } + +#[cfg(feature = "plugin_auth")] +#[derive(Clone)] +pub struct DefaultMailTemplates { + pub base_url: String, +} +#[cfg(feature = "plugin_auth")] +impl DefaultMailTemplates { + pub fn new(base_url: &str) -> Self { + Self { + base_url: base_url.to_string(), + } + } +} +#[cfg(feature = "plugin_auth")] +impl Default for DefaultMailTemplates { + fn default() -> Self { + Self::new("http://localhost:3000/") + } +} +#[cfg(feature = "plugin_auth")] +impl EmailTemplates for DefaultMailTemplates { + fn send_activated(&self, mailer: &Mailer, to_email: &str) { + auth_activated::send(mailer, to_email); + } + fn send_password_changed(&self, mailer: &Mailer, to_email: &str) { + auth_password_changed::send(mailer, to_email); + } + fn send_password_reset(&self, mailer: &Mailer, to_email: &str) { + auth_password_reset::send(mailer, to_email); + } + fn send_recover_existent_account(&self, mailer: &Mailer, to_email: &str, url_path: &str) { + auth_recover_existent_account::send( + mailer, + to_email, + format!("{base_url}{url_path}", base_url = self.base_url).as_str(), + ); + } + fn send_recover_nonexistent_account(&self, mailer: &Mailer, to_email: &str, url_path: &str) { + auth_recover_nonexistent_account::send( + mailer, + to_email, + format!("{base_url}{url_path}", base_url = self.base_url).as_str(), + ); + } + fn send_register(&self, mailer: &Mailer, to_email: &str, url_path: &str) { + auth_register::send( + mailer, + to_email, + format!("{base_url}{url_path}", base_url = self.base_url).as_str(), + ); + } +} From e134895871d1ead22d0cc7cd27a62f43621173fb Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Wed, 19 Apr 2023 19:42:02 -0700 Subject: [PATCH 2/5] fix #202 --- .../src/auth/mail/auth_activated.rs | 12 ++++++------ .../src/auth/mail/auth_password_changed.rs | 12 ++++++------ .../src/auth/mail/auth_password_reset.rs | 12 ++++++------ .../auth/mail/auth_recover_existent_account.rs | 18 +++++++++--------- .../mail/auth_recover_nonexistent_account.rs | 16 ++++++++-------- create-rust-app/src/auth/mail/auth_register.rs | 14 +++++++------- 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/create-rust-app/src/auth/mail/auth_activated.rs b/create-rust-app/src/auth/mail/auth_activated.rs index 2dfaeed0..53c43ff8 100644 --- a/create-rust-app/src/auth/mail/auth_activated.rs +++ b/create-rust-app/src/auth/mail/auth_activated.rs @@ -2,7 +2,7 @@ use crate::Mailer; #[allow(dead_code)] pub fn send(mailer: &Mailer, to_email: &str) { - let subject = "Account activated)"; + let subject = "Account activated"; let text = r#" (This is an automated message.) @@ -12,11 +12,11 @@ Your account has been activated! "# .to_string(); let html = r#" -(This is an automated message.) - -Hello, - -Your account has been activated! +

(This is an automated message.)

+
+

Hello,

+
+

Your account has been activated!

"# .to_string(); diff --git a/create-rust-app/src/auth/mail/auth_password_changed.rs b/create-rust-app/src/auth/mail/auth_password_changed.rs index c1c4b2de..84245b49 100644 --- a/create-rust-app/src/auth/mail/auth_password_changed.rs +++ b/create-rust-app/src/auth/mail/auth_password_changed.rs @@ -2,7 +2,7 @@ use crate::Mailer; #[allow(dead_code)] pub fn send(mailer: &Mailer, to_email: &str) { - let subject = "Your password was changed)"; + let subject = "Your password was changed"; let text = r#" (This is an automated message.) @@ -12,11 +12,11 @@ Your password was changed successfully! "# .to_string(); let html = r#" -(This is an automated message.) - -Hello, - -Your password was changed successfully! +

(This is an automated message.)

+
+

Hello,

+
+

Your password was changed successfully!

"# .to_string(); diff --git a/create-rust-app/src/auth/mail/auth_password_reset.rs b/create-rust-app/src/auth/mail/auth_password_reset.rs index eee78367..8acce2fa 100644 --- a/create-rust-app/src/auth/mail/auth_password_reset.rs +++ b/create-rust-app/src/auth/mail/auth_password_reset.rs @@ -2,7 +2,7 @@ use crate::Mailer; #[allow(dead_code)] pub fn send(mailer: &Mailer, to_email: &str) { - let subject = "Your password was reset)"; + let subject = "Your password was reset"; let text = r#" (This is an automated message.) @@ -13,11 +13,11 @@ Your password was successfully reset! .to_string(); let html = r#" -(This is an automated message.) - -Hello, - -Your password was successfully reset! +

(This is an automated message.)

+
+

Hello,

+
+

Your password was successfully reset!

"# .to_string(); diff --git a/create-rust-app/src/auth/mail/auth_recover_existent_account.rs b/create-rust-app/src/auth/mail/auth_recover_existent_account.rs index 88f6f60e..a4429681 100644 --- a/create-rust-app/src/auth/mail/auth_recover_existent_account.rs +++ b/create-rust-app/src/auth/mail/auth_recover_existent_account.rs @@ -2,7 +2,7 @@ use crate::Mailer; #[allow(dead_code)] pub fn send(mailer: &Mailer, to_email: &str, link: &str) { - let subject = "Reset Password Instructions)"; + let subject = "Reset Password Instructions"; let text = format!( r#" (This is an automated message.) @@ -17,14 +17,14 @@ Please visit this link to reset your password: ); let html = format!( r#" -(This is an automated message.) - -Hello, - -Someone requested a password reset for the account associated with this email. -Please visit this link to reset your password: -{link} -(valid for 24 hours) +

(This is an automated message.)

+
+

Hello,

+
+

Someone requested a password reset for the account associated with this email.

+

Please visit this link to reset your password:

+

{link}

+

(valid for 24 hours)

"# ); diff --git a/create-rust-app/src/auth/mail/auth_recover_nonexistent_account.rs b/create-rust-app/src/auth/mail/auth_recover_nonexistent_account.rs index 919f00fa..17dbc5c9 100644 --- a/create-rust-app/src/auth/mail/auth_recover_nonexistent_account.rs +++ b/create-rust-app/src/auth/mail/auth_recover_nonexistent_account.rs @@ -2,7 +2,7 @@ use crate::Mailer; #[allow(dead_code)] pub fn send(mailer: &Mailer, to_email: &str, link: &str) { - let subject = "Reset Password Instructions)"; + let subject = "Reset Password Instructions"; let text = format!( r#" (This is an automated message.) @@ -16,13 +16,13 @@ If this was intentional, you can register for a new account using the link below ); let html = format!( r#" -(This is an automated message.) - -Hello, - -Someone requested a password reset for the account associated with this email, but no account exists! -If this was intentional, you can register for a new account using the link below: -{link} +

(This is an automated message.)

+
+

Hello,

+
+

Someone requested a password reset for the account associated with this email, but no account exists!

+

If this was intentional, you can register for a new account using the link below:

+

{link}

"# ); diff --git a/create-rust-app/src/auth/mail/auth_register.rs b/create-rust-app/src/auth/mail/auth_register.rs index e2e571f1..30540476 100644 --- a/create-rust-app/src/auth/mail/auth_register.rs +++ b/create-rust-app/src/auth/mail/auth_register.rs @@ -2,7 +2,7 @@ use crate::Mailer; #[allow(dead_code)] pub fn send(mailer: &Mailer, to_email: &str, link: &str) { - let subject = "Registration Confirmation)"; + let subject = "Registration Confirmation"; let text = format!( r#" (This is an automated message.) @@ -15,12 +15,12 @@ Please follow the link below to complete your registration: ); let html = format!( r#" -(This is an automated message.) - -Hello, - -Please follow the link below to complete your registration: -{link} +

(This is an automated message.)

+
+

Hello,

+
+

Please follow the link below to complete your registration:

+

{link}

"# ); From fb18b8985b7596e61645d3861bd6738b746f6b00 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Wed, 19 Apr 2023 22:12:12 -0700 Subject: [PATCH 3/5] make email trait and struct public --- create-rust-app/src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/create-rust-app/src/lib.rs b/create-rust-app/src/lib.rs index ba49cd86..998409fd 100644 --- a/create-rust-app/src/lib.rs +++ b/create-rust-app/src/lib.rs @@ -11,9 +11,6 @@ compile_error!( // #[cfg(not(any(feature = "backend_poem", feature = "backend_actix-web")))] // compile_error!("Please enable one of the backend features (options: 'backend_actix-web', 'backend-poem')"); -#[cfg(feature = "plugin_auth")] -use mailer::EmailTemplates; - mod util; pub use util::*; @@ -47,6 +44,8 @@ pub use storage::{Attachment, AttachmentBlob, AttachmentData, Storage}; mod mailer; pub use mailer::Mailer; +#[cfg(feature = "plugin_auth")] +pub use mailer::{DefaultMailTemplates, EmailTemplates}; // #[cfg(debug_assertions)] // #[macro_use] From bbbf4ecfe84dea7b6b3d84da85f7eccf8a0de7f0 Mon Sep 17 00:00:00 2001 From: AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com> Date: Wed, 19 Apr 2023 22:46:09 -0700 Subject: [PATCH 4/5] improve template formatting --- create-rust-app/src/auth/mail/auth_activated.rs | 4 ++-- create-rust-app/src/auth/mail/auth_password_changed.rs | 4 ++-- create-rust-app/src/auth/mail/auth_password_reset.rs | 4 ++-- .../src/auth/mail/auth_recover_existent_account.rs | 8 ++++---- .../src/auth/mail/auth_recover_nonexistent_account.rs | 8 ++++---- create-rust-app/src/auth/mail/auth_register.rs | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/create-rust-app/src/auth/mail/auth_activated.rs b/create-rust-app/src/auth/mail/auth_activated.rs index 53c43ff8..6e7f4b0b 100644 --- a/create-rust-app/src/auth/mail/auth_activated.rs +++ b/create-rust-app/src/auth/mail/auth_activated.rs @@ -13,9 +13,9 @@ Your account has been activated! .to_string(); let html = r#"

(This is an automated message.)

-
+

Hello,

-
+

Your account has been activated!

"# .to_string(); diff --git a/create-rust-app/src/auth/mail/auth_password_changed.rs b/create-rust-app/src/auth/mail/auth_password_changed.rs index 84245b49..84538b20 100644 --- a/create-rust-app/src/auth/mail/auth_password_changed.rs +++ b/create-rust-app/src/auth/mail/auth_password_changed.rs @@ -13,9 +13,9 @@ Your password was changed successfully! .to_string(); let html = r#"

(This is an automated message.)

-
+

Hello,

-
+

Your password was changed successfully!

"# .to_string(); diff --git a/create-rust-app/src/auth/mail/auth_password_reset.rs b/create-rust-app/src/auth/mail/auth_password_reset.rs index 8acce2fa..0299c99e 100644 --- a/create-rust-app/src/auth/mail/auth_password_reset.rs +++ b/create-rust-app/src/auth/mail/auth_password_reset.rs @@ -14,9 +14,9 @@ Your password was successfully reset! let html = r#"

(This is an automated message.)

-
+

Hello,

-
+

Your password was successfully reset!

"# .to_string(); diff --git a/create-rust-app/src/auth/mail/auth_recover_existent_account.rs b/create-rust-app/src/auth/mail/auth_recover_existent_account.rs index a4429681..62e59cf4 100644 --- a/create-rust-app/src/auth/mail/auth_recover_existent_account.rs +++ b/create-rust-app/src/auth/mail/auth_recover_existent_account.rs @@ -18,11 +18,11 @@ Please visit this link to reset your password: let html = format!( r#"

(This is an automated message.)

-
+

Hello,

-
-

Someone requested a password reset for the account associated with this email.

-

Please visit this link to reset your password:

+ +

Someone requested a password reset for the account associated with this email. +Please visit this link to reset your password:

{link}

(valid for 24 hours)

"# diff --git a/create-rust-app/src/auth/mail/auth_recover_nonexistent_account.rs b/create-rust-app/src/auth/mail/auth_recover_nonexistent_account.rs index 17dbc5c9..0fcaefc7 100644 --- a/create-rust-app/src/auth/mail/auth_recover_nonexistent_account.rs +++ b/create-rust-app/src/auth/mail/auth_recover_nonexistent_account.rs @@ -17,11 +17,11 @@ If this was intentional, you can register for a new account using the link below let html = format!( r#"

(This is an automated message.)

-
+

Hello,

-
-

Someone requested a password reset for the account associated with this email, but no account exists!

-

If this was intentional, you can register for a new account using the link below:

+ +

Someone requested a password reset for the account associated with this email, but no account exists! +If this was intentional, you can register for a new account using the link below:

{link}

"# ); diff --git a/create-rust-app/src/auth/mail/auth_register.rs b/create-rust-app/src/auth/mail/auth_register.rs index 30540476..dda7e6fb 100644 --- a/create-rust-app/src/auth/mail/auth_register.rs +++ b/create-rust-app/src/auth/mail/auth_register.rs @@ -16,9 +16,9 @@ Please follow the link below to complete your registration: let html = format!( r#"

(This is an automated message.)

-
+

Hello,

-
+

Please follow the link below to complete your registration:

{link}

"# From e20eeed68e2d300635a9620e1a72ad4d8b41387c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 May 2023 16:06:26 +0000 Subject: [PATCH 5/5] Bump @types/node in /create-rust-app_cli/template/frontend Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 18.13.0 to 20.2.4. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- create-rust-app_cli/template/frontend/package-lock.json | 6 +++--- create-rust-app_cli/template/frontend/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/create-rust-app_cli/template/frontend/package-lock.json b/create-rust-app_cli/template/frontend/package-lock.json index 32d424e7..60e5daef 100644 --- a/create-rust-app_cli/template/frontend/package-lock.json +++ b/create-rust-app_cli/template/frontend/package-lock.json @@ -483,9 +483,9 @@ "integrity": "sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==" }, "@types/node": { - "version": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.4.tgz", + "integrity": "sha512-ni5f8Xlf4PwnT/Z3f0HURc3ZSw8UyrqMqmM3L5ysa7VjHu8c3FOmIo1nKCcLrV/OAmtf3N4kFna/aJqxsfEtnA==", "dev": true }, "@types/prop-types": { diff --git a/create-rust-app_cli/template/frontend/package.json b/create-rust-app_cli/template/frontend/package.json index cbdb871a..78fd4a2d 100644 --- a/create-rust-app_cli/template/frontend/package.json +++ b/create-rust-app_cli/template/frontend/package.json @@ -37,7 +37,7 @@ }, "devDependencies": { "@playwright/test": "^1.30.0", - "@types/node": "^18.13.0", + "@types/node": "^20.2.4", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", "@vitejs/plugin-react": "^3.0.1",