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")
+ }
}