This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git


The following commit(s) were added to refs/heads/main by this push:
     new 98588bf2ab feat(amber): include requester name in account email (#7639)
98588bf2ab is described below

commit 98588bf2ab49aac65ebf002496eb057670e6fc07
Author: anthonychengit <[email protected]>
AuthorDate: Sun Aug 30 03:51:50 2026 +0000

    feat(amber): include requester name in account email (#7639)
    
    ### What changes were proposed in this PR?
    
    The account-request notification only forwarded the requester's email
    address to the template. Although the stored user record already
    contains the requester's name, the notification path never retrieved it.
    
    ```text
    Before: account request -> email only -> admin notification omits name
    After:  account request -> stored user lookup -> admin receives name and 
email
    ```
    
    This change looks up the stored requester by email and includes the name
    in the admin notification. Missing or blank names render as `Not
    provided`. The requester-facing acknowledgement remains unchanged and
    does not expose the name field.
    
    Tests cover the positive stored-name path, the missing-requester
    fallback, blank and absent names, and the negative requester-facing
    template case.
    
    ### Any related issues, documentation, discussions?
    
    Closes #7595
    
    ### How was this PR tested?
    
    ```bash
    sbt "WorkflowExecutionService / Test / testOnly 
org.apache.texera.web.resource.EmailTemplateSpec 
org.apache.texera.web.resource.GmailResourceSpec"
    sbt scalafmtCheckAll
    sbt "scalafixAll --check"
    ```
    
    The focused suite passed 12 tests. Scala formatting and Scalafix checks
    also passed.
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: OpenAI Codex (GPT-5)
---
 .../apache/texera/web/resource/EmailTemplate.scala |  3 ++
 .../apache/texera/web/resource/GmailResource.scala | 33 ++++++++++++++++------
 .../texera/web/resource/EmailTemplateSpec.scala    | 11 +++++++-
 .../texera/web/resource/GmailResourceSpec.scala    | 23 +++++++++++++++
 4 files changed, 61 insertions(+), 9 deletions(-)

diff --git 
a/amber/src/main/scala/org/apache/texera/web/resource/EmailTemplate.scala 
b/amber/src/main/scala/org/apache/texera/web/resource/EmailTemplate.scala
index 17084b6c10..a79c0eabfa 100644
--- a/amber/src/main/scala/org/apache/texera/web/resource/EmailTemplate.scala
+++ b/amber/src/main/scala/org/apache/texera/web/resource/EmailTemplate.scala
@@ -41,12 +41,14 @@ object EmailTemplate {
     *
     * @param receiverEmail the email address of the receiver (admin or user)
     * @param userEmail optional; the email address of the user requesting an 
account (only needed if toAdmin is true)
+    * @param userName optional; the stored name of the user requesting an 
account (only needed if toAdmin is true)
     * @param toAdmin flag indicating whether the notification is for the admin 
(true) or the user (false)
     * @return an EmailMessage ready to be sent
     */
   def userRegistrationNotification(
       receiverEmail: String,
       userEmail: Option[String],
+      userName: Option[String],
       affiliation: Option[String],
       reason: Option[String],
       toAdmin: Boolean
@@ -62,6 +64,7 @@ object EmailTemplate {
            |A new user has attempted to log in or register, but their account 
is not yet approved.
            |Please review the account request for the following user:
            |
+           |Name: ${userName.filter(_.trim.nonEmpty).getOrElse("Not provided")}
            |Email: ${userEmail.getOrElse("Unknown")}
            |Affiliation: ${affiliation.filter(_.trim.nonEmpty).getOrElse("Not 
provided")}
            |Reason: ${reason.filter(_.trim.nonEmpty).getOrElse("Not provided")}
diff --git 
a/amber/src/main/scala/org/apache/texera/web/resource/GmailResource.scala 
b/amber/src/main/scala/org/apache/texera/web/resource/GmailResource.scala
index 348dad6ff7..5f9197b516 100644
--- a/amber/src/main/scala/org/apache/texera/web/resource/GmailResource.scala
+++ b/amber/src/main/scala/org/apache/texera/web/resource/GmailResource.scala
@@ -26,7 +26,13 @@ import org.apache.texera.dao.SqlServer
 import org.apache.texera.dao.jooq.generated.enums.UserRoleEnum
 import org.apache.texera.dao.jooq.generated.tables.daos.UserDao
 import 
org.apache.texera.web.resource.EmailTemplate.userRegistrationNotification
-import org.apache.texera.web.resource.GmailResource.{isValidEmail, sendEmail, 
senderGmail, userDao}
+import org.apache.texera.web.resource.GmailResource.{
+  adminRegistrationNotification,
+  isValidEmail,
+  sendEmail,
+  senderGmail,
+  userDao
+}
 import org.slf4j.LoggerFactory
 
 import javax.annotation.security.RolesAllowed
@@ -51,6 +57,22 @@ object GmailResource {
       .createDSLContext()
   private def userDao = new UserDao(context.configuration)
 
+  private[resource] def adminRegistrationNotification(
+      adminEmail: String,
+      emailMessage: EmailMessage
+  ): EmailMessage = {
+    val requesterName =
+      Option(userDao.fetchOneByEmail(emailMessage.receiver)).flatMap(user => 
Option(user.getName))
+    userRegistrationNotification(
+      receiverEmail = adminEmail,
+      userEmail = Some(emailMessage.receiver),
+      userName = requesterName,
+      affiliation = emailMessage.affiliation,
+      reason = emailMessage.reason,
+      toAdmin = true
+    )
+  }
+
   private lazy val senderGmail: String = UserSystemConfig.gmail
   private val smtpProperties = Map(
     "mail.smtp.host" -> "smtp.gmail.com",
@@ -179,13 +201,7 @@ class GmailResource {
 
       try {
         sendEmail(
-          userRegistrationNotification(
-            receiverEmail = adminEmail,
-            userEmail = Some(emailMessage.receiver),
-            affiliation = emailMessage.affiliation,
-            reason = emailMessage.reason,
-            toAdmin = true
-          ),
+          adminRegistrationNotification(adminEmail, emailMessage),
           adminEmail
         )
       } catch {
@@ -199,6 +215,7 @@ class GmailResource {
         userRegistrationNotification(
           receiverEmail = emailMessage.receiver,
           userEmail = None,
+          userName = None,
           affiliation = None,
           reason = None,
           toAdmin = false
diff --git 
a/amber/src/test/scala/org/apache/texera/web/resource/EmailTemplateSpec.scala 
b/amber/src/test/scala/org/apache/texera/web/resource/EmailTemplateSpec.scala
index 64e6636a36..1651e3a23d 100644
--- 
a/amber/src/test/scala/org/apache/texera/web/resource/EmailTemplateSpec.scala
+++ 
b/amber/src/test/scala/org/apache/texera/web/resource/EmailTemplateSpec.scala
@@ -38,12 +38,14 @@ class EmailTemplateSpec extends AnyFlatSpec with Matchers {
     val msg = EmailTemplate.userRegistrationNotification(
       receiverEmail = "[email protected]",
       userEmail = Some("[email protected]"),
+      userName = Some("Alice Example"),
       affiliation = Some("UC Irvine"),
       reason = Some("research"),
       toAdmin = true
     )
     msg.receiver shouldBe "[email protected]"
     msg.subject should startWith("New Account Request Pending Approval")
+    msg.content should include("Name: Alice Example")
     msg.content should include("Email: [email protected]")
     msg.content should include("Affiliation: UC Irvine")
     msg.content should include("Reason: research")
@@ -54,6 +56,7 @@ class EmailTemplateSpec extends AnyFlatSpec with Matchers {
     val msg = EmailTemplate.userRegistrationNotification(
       receiverEmail = "[email protected]",
       userEmail = None,
+      userName = None,
       affiliation = Some("UC Irvine"),
       reason = Some("research"),
       toAdmin = true
@@ -61,20 +64,23 @@ class EmailTemplateSpec extends AnyFlatSpec with Matchers {
     msg.content should include("Email: Unknown")
   }
 
-  it should "render 'Not provided' for affiliation/reason when None or 
whitespace-only" in {
+  it should "render 'Not provided' for name, affiliation, and reason when 
blank" in {
     val withNone = EmailTemplate.userRegistrationNotification(
       receiverEmail = "[email protected]",
       userEmail = Some("[email protected]"),
+      userName = None,
       affiliation = None,
       reason = None,
       toAdmin = true
     )
     withNone.content should include("Affiliation: Not provided")
     withNone.content should include("Reason: Not provided")
+    withNone.content should include("Name: Not provided")
 
     val withBlank = EmailTemplate.userRegistrationNotification(
       receiverEmail = "[email protected]",
       userEmail = Some("[email protected]"),
+      userName = Some("   "),
       affiliation = Some("   "),
       reason = Some(""),
       toAdmin = true
@@ -83,6 +89,7 @@ class EmailTemplateSpec extends AnyFlatSpec with Matchers {
     // strings the same as None.
     withBlank.content should include("Affiliation: Not provided")
     withBlank.content should include("Reason: Not provided")
+    withBlank.content should include("Name: Not provided")
   }
 
   // -- userRegistrationNotification (user branch) 
-----------------------------
@@ -92,6 +99,7 @@ class EmailTemplateSpec extends AnyFlatSpec with Matchers {
     val msg = EmailTemplate.userRegistrationNotification(
       receiverEmail = "[email protected]",
       userEmail = Some("[email protected]"),
+      userName = Some("Ignored Name"),
       affiliation = Some("ignored"),
       reason = Some("ignored"),
       toAdmin = false
@@ -103,6 +111,7 @@ class EmailTemplateSpec extends AnyFlatSpec with Matchers {
     // fields back to the requester — if a refactor accidentally surfaces
     // them, this assertion will catch the leak.
     msg.content should not include "Email: ignored"
+    msg.content should not include "Name: Ignored Name"
     msg.content should not include "Affiliation: ignored"
     msg.content should not include "Reason: ignored"
   }
diff --git 
a/amber/src/test/scala/org/apache/texera/web/resource/GmailResourceSpec.scala 
b/amber/src/test/scala/org/apache/texera/web/resource/GmailResourceSpec.scala
index bcdb72de8d..036532df6a 100644
--- 
a/amber/src/test/scala/org/apache/texera/web/resource/GmailResourceSpec.scala
+++ 
b/amber/src/test/scala/org/apache/texera/web/resource/GmailResourceSpec.scala
@@ -301,4 +301,27 @@ class GmailResourceSpec
     }
     assert(ex.getResponse.getStatus == 403)
   }
+
+  "adminRegistrationNotification" should "resolve the requester's stored name 
by email" in {
+    val requesterEmail = s"[email protected]"
+    val requesterName = s"gmailspec_requester_$runId"
+    seedUser("requester", UserRoleEnum.REGULAR, requesterEmail)
+
+    val message = GmailResource.adminRegistrationNotification(
+      "[email protected]",
+      EmailMessage(receiver = requesterEmail, subject = "", content = "")
+    )
+
+    message.content should include(s"Name: $requesterName")
+    message.content should include(s"Email: $requesterEmail")
+  }
+
+  it should "render the fallback when no user matches the requester email" in {
+    val message = GmailResource.adminRegistrationNotification(
+      "[email protected]",
+      EmailMessage(receiver = "[email protected]", subject = "", 
content = "")
+    )
+
+    message.content should include("Name: Not provided")
+  }
 }

Reply via email to