From 3a62afb53c08159ead706387268ee65cef72fc45 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Wed, 3 Jun 2026 00:33:52 -0400 Subject: [PATCH] usernames --- .../list_user_email_changes_for_user.rs | 67 ++++++++++++++++--- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/crates/schema/database/mysql_queries/src/queries/users/user_email_changes/list_user_email_changes_for_user.rs b/crates/schema/database/mysql_queries/src/queries/users/user_email_changes/list_user_email_changes_for_user.rs index 4afea84b0c..c989ff8005 100644 --- a/crates/schema/database/mysql_queries/src/queries/users/user_email_changes/list_user_email_changes_for_user.rs +++ b/crates/schema/database/mysql_queries/src/queries/users/user_email_changes/list_user_email_changes_for_user.rs @@ -25,6 +25,18 @@ pub struct UserEmailChangeRow { pub ip_address: String, pub maybe_changed_by_user_token: Option, pub created_at: DateTime, + + // Denormalized display fields for the user whose email was changed. + pub user_username: String, + pub user_display_name: String, + pub user_gravatar_hash: String, + + // Denormalized display fields for the user who performed the change, if + // there was one. NULL when `maybe_changed_by_user_token` is NULL or when + // the referenced row has been hard-deleted. + pub maybe_changed_by_user_username: Option, + pub maybe_changed_by_user_display_name: Option, + pub maybe_changed_by_user_gravatar_hash: Option, } #[derive(Debug)] @@ -36,9 +48,23 @@ struct RawUserEmailChangeRow { ip_address: String, maybe_changed_by_user_token: Option, created_at: NaiveDateTime, + + user_username: String, + user_display_name: String, + user_gravatar_hash: String, + + maybe_changed_by_user_username: Option, + maybe_changed_by_user_display_name: Option, + maybe_changed_by_user_gravatar_hash: Option, } /// Return all `user_email_changes` rows for the given user, newest first. +/// +/// Joins `users` twice to denormalize the username, display name, and +/// gravatar hash for both the subject (`user_token`) and the acting user +/// (`maybe_changed_by_user_token`). The actor join is a LEFT JOIN so rows +/// where there is no acting user (e.g. self-service changes) still come +/// back. pub async fn list_user_email_changes_for_user<'e, 'c: 'e, E>( args: ListUserEmailChangesForUserArgs<'e, 'c, E>, ) -> Result, sqlx::Error> @@ -49,16 +75,29 @@ where RawUserEmailChangeRow, r#" SELECT - id as `id: u64`, - user_token as `user_token: tokens::tokens::users::UserToken`, - old_email, - new_email, - ip_address, - maybe_changed_by_user_token as `maybe_changed_by_user_token: tokens::tokens::users::UserToken`, - created_at -FROM user_email_changes -WHERE user_token = ? -ORDER BY id DESC + uec.id as `id: u64`, + uec.user_token as `user_token: tokens::tokens::users::UserToken`, + uec.old_email, + uec.new_email, + uec.ip_address, + uec.maybe_changed_by_user_token as `maybe_changed_by_user_token: tokens::tokens::users::UserToken`, + uec.created_at, + + u_subject.username as user_username, + u_subject.display_name as user_display_name, + u_subject.email_gravatar_hash as user_gravatar_hash, + + u_changer.username as `maybe_changed_by_user_username?`, + u_changer.display_name as `maybe_changed_by_user_display_name?`, + u_changer.email_gravatar_hash as `maybe_changed_by_user_gravatar_hash?` + +FROM user_email_changes AS uec +JOIN users AS u_subject + ON uec.user_token = u_subject.token +LEFT JOIN users AS u_changer + ON uec.maybe_changed_by_user_token = u_changer.token +WHERE uec.user_token = ? +ORDER BY uec.id DESC "#, args.user_token.as_str(), ) @@ -74,6 +113,14 @@ ORDER BY id DESC ip_address: row.ip_address, maybe_changed_by_user_token: row.maybe_changed_by_user_token, created_at: row.created_at.and_utc(), + + user_username: row.user_username, + user_display_name: row.user_display_name, + user_gravatar_hash: row.user_gravatar_hash, + + maybe_changed_by_user_username: row.maybe_changed_by_user_username, + maybe_changed_by_user_display_name: row.maybe_changed_by_user_display_name, + maybe_changed_by_user_gravatar_hash: row.maybe_changed_by_user_gravatar_hash, } }).collect();