From ee07db6d747b4af0e76171686c12ebc83a0f380e Mon Sep 17 00:00:00 2001 From: Martin Gaughran Date: Wed, 25 Feb 2026 13:47:36 +0000 Subject: [PATCH 1/4] Add settings option for default 'to' in emails --- .../applications/email/ui/EmailDialogController.java | 6 +++++- .../src/main/java/org/phoebus/email/EmailPreferences.java | 1 + core/email/src/main/resources/email_preferences.properties | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/email/ui/src/main/java/org/phoebus/applications/email/ui/EmailDialogController.java b/app/email/ui/src/main/java/org/phoebus/applications/email/ui/EmailDialogController.java index ff398adb13..8931e300bd 100644 --- a/app/email/ui/src/main/java/org/phoebus/applications/email/ui/EmailDialogController.java +++ b/app/email/ui/src/main/java/org/phoebus/applications/email/ui/EmailDialogController.java @@ -184,7 +184,11 @@ public void send(Event event) { @FXML public void initialize() { - txtTo.setText(prefs.get(LAST_TO, "")); + if(EmailPreferences.to == null || EmailPreferences.to.isBlank()) + txtTo.setText(prefs.get(LAST_TO, "")); + else + txtTo.setText(EmailPreferences.to); + if(EmailPreferences.from == null || EmailPreferences.from.isBlank()) txtFrom.setText(prefs.get(LAST_FROM, "")); else diff --git a/core/email/src/main/java/org/phoebus/email/EmailPreferences.java b/core/email/src/main/java/org/phoebus/email/EmailPreferences.java index 354665f5ca..7115dca044 100644 --- a/core/email/src/main/java/org/phoebus/email/EmailPreferences.java +++ b/core/email/src/main/java/org/phoebus/email/EmailPreferences.java @@ -22,6 +22,7 @@ public class EmailPreferences @Preference public static String username; @Preference public static String password; @Preference public static String from; + @Preference public static String to; /** @return Is email supported? */ public static final boolean isEmailSupported() diff --git a/core/email/src/main/resources/email_preferences.properties b/core/email/src/main/resources/email_preferences.properties index 7e44660053..34b64c9000 100644 --- a/core/email/src/main/resources/email_preferences.properties +++ b/core/email/src/main/resources/email_preferences.properties @@ -19,3 +19,8 @@ password= # # If left empty then the last used {mailheader}`From` address is used. from= + +# Default address to be used for {mailheader}`To:`. +# +# If left empty then the last used {mailheader}`To` address is used. +to= From b4513d8dd2ed07763338093debe6f358c2af5ec1 Mon Sep 17 00:00:00 2001 From: Martin Gaughran Date: Wed, 25 Feb 2026 16:50:53 +0000 Subject: [PATCH 2/4] Use macro substition for email 'from' and 'to' fields --- .../email/ui/EmailDialogController.java | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/app/email/ui/src/main/java/org/phoebus/applications/email/ui/EmailDialogController.java b/app/email/ui/src/main/java/org/phoebus/applications/email/ui/EmailDialogController.java index 8931e300bd..7d89f5540b 100644 --- a/app/email/ui/src/main/java/org/phoebus/applications/email/ui/EmailDialogController.java +++ b/app/email/ui/src/main/java/org/phoebus/applications/email/ui/EmailDialogController.java @@ -24,6 +24,9 @@ import org.phoebus.applications.email.EmailApp; import org.phoebus.email.EmailPreferences; import org.phoebus.email.EmailService; +import org.phoebus.framework.macros.MacroHandler; +import org.phoebus.framework.macros.MacroOrSystemProvider; +import org.phoebus.framework.macros.Macros; import org.phoebus.framework.preferences.PhoebusPreferenceService; import org.phoebus.ui.javafx.FilesTab; import org.phoebus.ui.javafx.ImagesTab; @@ -58,6 +61,8 @@ public class EmailDialogController { final Preferences prefs = PhoebusPreferenceService.userNodeForClass(EmailApp.class); + private final MacroOrSystemProvider systemMacros = new MacroOrSystemProvider(new Macros()); + private static final String TEXT_PLAIN = "text/plain"; private static final String TEXT_HTML = "text/html"; @@ -184,15 +189,17 @@ public void send(Event event) { @FXML public void initialize() { - if(EmailPreferences.to == null || EmailPreferences.to.isBlank()) - txtTo.setText(prefs.get(LAST_TO, "")); - else - txtTo.setText(EmailPreferences.to); + String to = EmailPreferences.to; + if(to == null || to.isBlank()) + to = prefs.get(LAST_TO, ""); - if(EmailPreferences.from == null || EmailPreferences.from.isBlank()) - txtFrom.setText(prefs.get(LAST_FROM, "")); - else - txtFrom.setText(EmailPreferences.from); + txtTo.setText(substituteSystemMacros(to)); + + String from = EmailPreferences.from; + if(from == null || from.isBlank()) + from = prefs.get(LAST_FROM, ""); + + txtFrom.setText(substituteSystemMacros(from)); txtFrom.setPromptText("Enter your email address"); txtTo.setPromptText("Enter receipient's email address(es)"); @@ -281,6 +288,18 @@ public void setAttachmets(final List files) att_files.setFiles(files); } + private String substituteSystemMacros(String input) { + String output; + try { + output = MacroHandler.replace(systemMacros, input); + } catch (Exception ignored) { + logger.warning("Failed macro expansion in email address field. Using original string"); + output = input; + } + + return output; + } + private void recomputeTextArea() { simpleTextVBox.setVisible(choiceBox.getValue().equals(TEXT_PLAIN)); simpleTextVBox.setManaged(choiceBox.getValue().equals(TEXT_PLAIN)); From dce9c32ff8c97cde0c8753c81370c76ef669840f Mon Sep 17 00:00:00 2001 From: Martin Gaughran Date: Wed, 25 Feb 2026 16:59:59 +0000 Subject: [PATCH 3/4] Document use of email field macro expansion --- core/email/src/main/resources/email_preferences.properties | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/email/src/main/resources/email_preferences.properties b/core/email/src/main/resources/email_preferences.properties index 34b64c9000..44297fbc76 100644 --- a/core/email/src/main/resources/email_preferences.properties +++ b/core/email/src/main/resources/email_preferences.properties @@ -17,10 +17,12 @@ password= # Default address to be used for {mailheader}`From:`. # -# If left empty then the last used {mailheader}`From` address is used. +# If left empty then the last used {mailheader}`From` address is used. System or environment +# variable macro substitution is applied to this field. from= # Default address to be used for {mailheader}`To:`. # -# If left empty then the last used {mailheader}`To` address is used. +# If left empty then the last used {mailheader}`To` address is used. System or environment +# variable macro substitution is applied to this field. to= From bc0a5bad1736f6d19ec043080089c80eff6cd99e Mon Sep 17 00:00:00 2001 From: Martin Gaughran Date: Fri, 27 Feb 2026 10:39:23 +0000 Subject: [PATCH 4/4] Add UI test for EmailDialogController email substitutions This needs to be a UI test since the class uses JavaFX. --- app/email/ui/pom.xml | 26 ++++++- .../email/ui/EmailDialogController.java | 1 - .../email/ui/EmailDialogControllerTestUI.java | 75 +++++++++++++++++++ 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 app/email/ui/src/test/java/org/phoebus/applications/email/ui/EmailDialogControllerTestUI.java diff --git a/app/email/ui/pom.xml b/app/email/ui/pom.xml index a1cc12a617..8eb8919a9f 100644 --- a/app/email/ui/pom.xml +++ b/app/email/ui/pom.xml @@ -23,7 +23,31 @@ core-ui 5.0.3-SNAPSHOT - + + org.testfx + testfx-core + 4.0.18 + test + + + org.testfx + testfx-junit5 + 4.0.18 + test + + + junit + junit + + + + + org.junit.jupiter + junit-jupiter + ${junit.version} + test + + diff --git a/app/email/ui/src/main/java/org/phoebus/applications/email/ui/EmailDialogController.java b/app/email/ui/src/main/java/org/phoebus/applications/email/ui/EmailDialogController.java index 7d89f5540b..4cda6fec5f 100644 --- a/app/email/ui/src/main/java/org/phoebus/applications/email/ui/EmailDialogController.java +++ b/app/email/ui/src/main/java/org/phoebus/applications/email/ui/EmailDialogController.java @@ -188,7 +188,6 @@ public void send(Event event) { @FXML public void initialize() { - String to = EmailPreferences.to; if(to == null || to.isBlank()) to = prefs.get(LAST_TO, ""); diff --git a/app/email/ui/src/test/java/org/phoebus/applications/email/ui/EmailDialogControllerTestUI.java b/app/email/ui/src/test/java/org/phoebus/applications/email/ui/EmailDialogControllerTestUI.java new file mode 100644 index 0000000000..7df2d23976 --- /dev/null +++ b/app/email/ui/src/test/java/org/phoebus/applications/email/ui/EmailDialogControllerTestUI.java @@ -0,0 +1,75 @@ +package org.phoebus.applications.email.ui; + +import javafx.fxml.FXMLLoader; +import javafx.stage.Stage; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import org.phoebus.applications.email.EmailApp; +import org.phoebus.email.EmailPreferences; +import org.testfx.framework.junit5.ApplicationTest; + +import java.io.IOException; + +class EmailDialogControllerTestUI extends ApplicationTest { + + EmailDialogController controller; + + @Override + public void start(Stage stage) throws IOException + { + final FXMLLoader loader = new FXMLLoader(); + loader.setLocation(EmailApp.class.getResource("ui/EmailDialog.fxml")); + loader.load(); + controller = loader.getController(); + } + + @BeforeEach + public void setup() { + System.setProperty("test_key1", "test_value1"); + System.setProperty("test_key2", "test_value2"); + System.setProperty("test_recursive1", "$(test_recursive2)"); + System.setProperty("test_recursive2", "$(test_recursive1)"); + } + + @AfterEach + public void tearDown() { + System.clearProperty("test_key1"); + System.clearProperty("test_key2"); + System.clearProperty("test_recursive1"); + System.clearProperty("test_recursive2"); + } + + @Test + void testEmailAddressSubstitutions() { + EmailPreferences.to = "$(test_key1)@place"; + EmailPreferences.from = "$(test_key2)@other"; + controller.initialize(); + + Assertions.assertEquals("test_value1@place", controller.txtTo.getText()); + Assertions.assertEquals("test_value2@other", controller.txtFrom.getText()); + } + + @Test + void testEmailAddressSubstitutionsWithIncorrectProperties() { + EmailPreferences.to = "$(nonexistent)@place"; + EmailPreferences.from = "$(test_key2@other"; + controller.initialize(); + + Assertions.assertEquals("$(nonexistent)@place", controller.txtTo.getText()); + Assertions.assertEquals("$(test_key2@other", controller.txtFrom.getText()); + } + + @Test + void testEmailAddressSubstitutionsWithRecursiveProperties() { + EmailPreferences.to = "$(test_recursive1)@place"; + EmailPreferences.from = "$(test_recursive2)@other"; + controller.initialize(); + + Assertions.assertEquals("$(test_recursive1)@place", controller.txtTo.getText()); + Assertions.assertEquals("$(test_recursive2)@other", controller.txtFrom.getText()); + } +}