From 463253dbb565ca024633cd49e8054c0454619566 Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Mon, 9 Sep 2024 20:52:53 -0700 Subject: [PATCH] Email delivery tweaks --- pkg/config/config.go | 1 + pkg/controller/account/signup.go | 35 +++++++------ pkg/controller/photo/certification.go | 50 +++++++++++-------- pkg/models/user.go | 5 ++ .../email/certification_rejected.html | 2 +- 5 files changed, 56 insertions(+), 37 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 3a93a2f..b81cda4 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -50,6 +50,7 @@ const ( ResetPasswordRedisKey = "reset-password/%s" ChangeEmailRedisKey = "change-email/%s" SignupTokenExpires = 24 * time.Hour // used for all tokens so far + EmailDebounceExpires = 24 * time.Hour // how to rate limit duplicate mail being sent // Rate limits RateLimitRedisKey = "rate-limit/%s/%s" // namespace, id diff --git a/pkg/controller/account/signup.go b/pkg/controller/account/signup.go index 27d4e5b..c045172 100644 --- a/pkg/controller/account/signup.go +++ b/pkg/controller/account/signup.go @@ -139,24 +139,29 @@ func Signup() http.HandlerFunc { } // Already an account? - if _, err := models.FindUser(email); err == nil { + if user, err := models.FindUser(email); err == nil { // We don't want to admit that the email already is registered, so send an email to the // address in case the user legitimately forgot, but flash the regular success message. - if err := mail.LockSending("signup", email, config.SignupTokenExpires); err == nil { - err := mail.Send(mail.Message{ - To: email, - Subject: "You already have a nonshy account", - Template: "email/already_signed_up.html", - Data: map[string]interface{}{ - "Title": config.Title, - "URL": config.Current.BaseURL + "/forgot-password", - }, - }) - if err != nil { - session.FlashError(w, r, "Error sending an email: %s", err) - } + if user.IsBanned() { + log.Error("Do not send signup e-mail to %s: user is banned", email) } else { - log.Error("LockSending: signup e-mail is not sent to %s: one was sent recently", email) + if err := mail.LockSending("signup", email, config.EmailDebounceExpires); err == nil { + err := mail.Send(mail.Message{ + To: email, + Subject: "You already have a nonshy account", + Template: "email/already_signed_up.html", + Data: map[string]interface{}{ + "Title": config.Title, + "URL": config.Current.BaseURL + "/forgot-password", + }, + }) + if err != nil { + session.FlashError(w, r, "Error sending an email: %s", err) + } + + } else { + log.Error("LockSending: signup e-mail is not sent to %s: one was sent recently", email) + } } session.Flash(w, r, "We have sent an e-mail to %s with a link to continue signing up your account. Please go and check your e-mail.", email) diff --git a/pkg/controller/photo/certification.go b/pkg/controller/photo/certification.go index d7fecad..b2c0194 100644 --- a/pkg/controller/photo/certification.go +++ b/pkg/controller/photo/certification.go @@ -434,17 +434,21 @@ func AdminCertification() http.HandlerFunc { } // Notify the user via email. - if err := mail.Send(mail.Message{ - To: user.Email, - Subject: "Your certification photo has been rejected", - Template: "email/certification_rejected.html", - Data: map[string]interface{}{ - "Username": user.Username, - "AdminComment": comment, - "URL": config.Current.BaseURL + "/photo/certification", - }, - }); err != nil { - session.FlashError(w, r, "Note: failed to email user about the rejection: %s", err) + if err := mail.LockSending("cert_rejected", user.Email, config.EmailDebounceExpires); err == nil { + if err := mail.Send(mail.Message{ + To: user.Email, + Subject: "Your certification photo has been denied", + Template: "email/certification_rejected.html", + Data: map[string]interface{}{ + "Username": user.Username, + "AdminComment": comment, + "URL": config.Current.BaseURL + "/photo/certification", + }, + }); err != nil { + session.FlashError(w, r, "Note: failed to email user about the rejection: %s", err) + } + } else { + log.Error("LockSending: cert_rejected e-mail is not sent to %s: one was sent recently", user.Email) } } @@ -503,16 +507,20 @@ func AdminCertification() http.HandlerFunc { } // Notify the user via email. - if err := mail.Send(mail.Message{ - To: user.Email, - Subject: "Your certification photo has been approved!", - Template: "email/certification_approved.html", - Data: map[string]interface{}{ - "Username": user.Username, - "URL": config.Current.BaseURL, - }, - }); err != nil { - session.FlashError(w, r, "Note: failed to email user about the approval: %s", err) + if err := mail.LockSending("cert_approved", user.Email, config.EmailDebounceExpires); err == nil { + if err := mail.Send(mail.Message{ + To: user.Email, + Subject: "Your certification photo has been approved!", + Template: "email/certification_approved.html", + Data: map[string]interface{}{ + "Username": user.Username, + "URL": config.Current.BaseURL, + }, + }); err != nil { + session.FlashError(w, r, "Note: failed to email user about the approval: %s", err) + } + } else { + log.Error("LockSending: cert_approved e-mail is not sent to %s: one was sent recently", user.Email) } // Log the change. diff --git a/pkg/models/user.go b/pkg/models/user.go index 6e93485..0061e8e 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -226,6 +226,11 @@ func IsValidUsername(username string) error { return nil } +// IsBanned returns if the user account is banned. +func (u *User) IsBanned() bool { + return u.Status == UserStatusBanned +} + // IsShyFrom tells whether the user is shy from the perspective of the other user. // // That is, depending on our profile visibility and friendship status. diff --git a/web/templates/email/certification_rejected.html b/web/templates/email/certification_rejected.html index 2d93a36..fb45afb 100644 --- a/web/templates/email/certification_rejected.html +++ b/web/templates/email/certification_rejected.html @@ -3,7 +3,7 @@ -

Your certification photo has been rejected

+

Your certification photo has been denied

Dear {{.Data.Username}},