[DO NOT MERGE] Email notification system (#4338)

* Migration

* Fixup db models

* Redis

* Stuff

* Switch PKs to BIGSERIALs, insert to notifications_deliveries when inserting notifications

* Queue, templates

* Query cache

* Fixes, fixtures

* Perf, cache template data & HTML bodies

* Notification type configuration, ResetPassword notification type

* Reset password

* Query cache

* Clippy + fmt

* Traces, fix typo, fix user email in ResetPassword

* send_email

* Models, db

* Remove dead code, adjust notification settings in migration

* Clippy fmt

* Delete dead code, fixes

* Fmt

* Update apps/labrinth/src/queue/email.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: François-Xavier Talbot <108630700+fetchfern@users.noreply.github.com>

* Remove old fixtures

* Unify email retry delay

* Fix type

* External notifications

* Remove `notifications_types_preference_restrictions`, as user notification preferences is out of scope for this PR

* Query cache, fmt, clippy

* Fix join in get_many_user_exposed_on_site

* Remove migration comment

* Query cache

* Update html body urls

* Remove comment

* Add paymentfailed.service variable to PaymentFailed notification variant

* Fix compile error

* Fix deleting notifications

* Update apps/labrinth/src/database/models/user_item.rs

Co-authored-by: Josiah Glosson <soujournme@gmail.com>
Signed-off-by: François-Xavier Talbot <108630700+fetchfern@users.noreply.github.com>

* Update apps/labrinth/src/database/models/user_item.rs

Co-authored-by: Josiah Glosson <soujournme@gmail.com>
Signed-off-by: François-Xavier Talbot <108630700+fetchfern@users.noreply.github.com>

* Update Cargo.toml

Co-authored-by: Josiah Glosson <soujournme@gmail.com>
Signed-off-by: François-Xavier Talbot <108630700+fetchfern@users.noreply.github.com>

* Update apps/labrinth/migrations/20250902133943_notification-extension.sql

Co-authored-by: Josiah Glosson <soujournme@gmail.com>
Signed-off-by: François-Xavier Talbot <108630700+fetchfern@users.noreply.github.com>

* Address review comments

* Fix compliation

* Update apps/labrinth/src/database/models/users_notifications_preferences_item.rs

Co-authored-by: Josiah Glosson <soujournme@gmail.com>
Signed-off-by: François-Xavier Talbot <108630700+fetchfern@users.noreply.github.com>

* Use strfmt to format emails

* Configurable Reply-To

* Configurable Reply-To

* Refactor for email background task

* Send some emails inline

* Fix account creation email check

* Revert "Use strfmt to format emails"

This reverts commit e0d6614afe51fa6349918377e953ba294c34ae0b.

* Reintroduce fill_template

* Set password reset email inline

* Process more emails per index

* clippy fmt

* Query cache

---------

Signed-off-by: François-Xavier Talbot <108630700+fetchfern@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Josiah Glosson <soujournme@gmail.com>
This commit is contained in:
François-Xavier Talbot
2025-09-15 15:02:29 -04:00
committed by GitHub
parent 1491642209
commit 902d749293
51 changed files with 2958 additions and 3652 deletions

View File

@@ -72,6 +72,30 @@ pub enum LegacyNotificationBody {
link: String,
actions: Vec<NotificationAction>,
},
// In `NotificationBody`, this has the `flow` field, however, don't
// include it here, to be 100% certain we don't end up leaking it
// in site notifications.
ResetPassword,
// Idem as ResetPassword
VerifyEmail,
AuthProviderAdded {
provider: String,
},
AuthProviderRemoved {
provider: String,
},
TwoFactorEnabled,
TwoFactorRemoved,
PasswordChanged,
PasswordRemoved,
EmailChanged {
new_email: String,
to_email: String,
},
PaymentFailed {
amount: String,
service: String,
},
Unknown,
}
@@ -93,6 +117,36 @@ impl LegacyNotification {
NotificationBody::ModeratorMessage { .. } => {
Some("moderator_message".to_string())
}
NotificationBody::ResetPassword { .. } => {
Some("reset_password".to_string())
}
NotificationBody::VerifyEmail { .. } => {
Some("verify_email".to_string())
}
NotificationBody::AuthProviderAdded { .. } => {
Some("auth_provider_added".to_string())
}
NotificationBody::AuthProviderRemoved { .. } => {
Some("auth_provider_removed".to_string())
}
NotificationBody::TwoFactorEnabled => {
Some("two_factor_enabled".to_string())
}
NotificationBody::TwoFactorRemoved => {
Some("two_factor_removed".to_string())
}
NotificationBody::PasswordChanged => {
Some("password_changed".to_string())
}
NotificationBody::PasswordRemoved => {
Some("password_removed".to_string())
}
NotificationBody::EmailChanged { .. } => {
Some("email_changed".to_string())
}
NotificationBody::PaymentFailed { .. } => {
Some("payment_failed".to_string())
}
NotificationBody::LegacyMarkdown {
notification_type, ..
} => notification_type.clone(),
@@ -162,6 +216,40 @@ impl LegacyNotification {
link,
actions,
},
NotificationBody::ResetPassword { .. } => {
LegacyNotificationBody::ResetPassword
}
NotificationBody::VerifyEmail { .. } => {
LegacyNotificationBody::VerifyEmail
}
NotificationBody::AuthProviderAdded { provider } => {
LegacyNotificationBody::AuthProviderAdded { provider }
}
NotificationBody::AuthProviderRemoved { provider } => {
LegacyNotificationBody::AuthProviderRemoved { provider }
}
NotificationBody::TwoFactorEnabled => {
LegacyNotificationBody::TwoFactorEnabled
}
NotificationBody::TwoFactorRemoved => {
LegacyNotificationBody::TwoFactorRemoved
}
NotificationBody::PasswordChanged => {
LegacyNotificationBody::PasswordChanged
}
NotificationBody::PasswordRemoved => {
LegacyNotificationBody::PasswordRemoved
}
NotificationBody::EmailChanged {
new_email,
to_email,
} => LegacyNotificationBody::EmailChanged {
new_email,
to_email,
},
NotificationBody::PaymentFailed { amount, service } => {
LegacyNotificationBody::PaymentFailed { amount, service }
}
NotificationBody::Unknown => LegacyNotificationBody::Unknown,
};