From 6242d9dad12d968a75544576fedfdb227d1b99fe Mon Sep 17 00:00:00 2001 From: Johannes Passing Date: Tue, 28 Nov 2023 14:28:13 +1100 Subject: [PATCH] Move NotificationTemplate to MailNotificationService as it's mostly relevant for formatting email --- .../services/MailNotificationService.java | 64 ++++++++++++++++- .../core/services/NotificationService.java | 68 ++----------------- .../solutions/jitaccess/web/ApiResource.java | 4 +- .../services/TestMailNotificationService.java | 2 +- ...Template.java => TestMessageTemplate.java} | 8 +-- 5 files changed, 74 insertions(+), 72 deletions(-) rename sources/src/test/java/com/google/solutions/jitaccess/core/services/{TestNotificationTemplate.java => TestMessageTemplate.java} (94%) diff --git a/sources/src/main/java/com/google/solutions/jitaccess/core/services/MailNotificationService.java b/sources/src/main/java/com/google/solutions/jitaccess/core/services/MailNotificationService.java index d56f84b83..2f1f95fb9 100644 --- a/sources/src/main/java/com/google/solutions/jitaccess/core/services/MailNotificationService.java +++ b/sources/src/main/java/com/google/solutions/jitaccess/core/services/MailNotificationService.java @@ -22,13 +22,18 @@ package com.google.solutions.jitaccess.core.services; import com.google.common.base.Preconditions; +import com.google.common.escape.Escaper; import com.google.common.html.HtmlEscapers; import com.google.solutions.jitaccess.core.AccessException; import com.google.solutions.jitaccess.core.adapters.SmtpAdapter; import java.io.IOException; +import java.time.Instant; +import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import java.util.EnumSet; /** @@ -97,7 +102,7 @@ public void sendNotification(Notification notification) throws NotificationExcep Preconditions.checkNotNull(notification, "notification"); var htmlTemplate = loadResource( - String.format("notifications/%s.html", notification.getTemplateId())); + String.format("notifications/%s.html", notification.getType())); if (htmlTemplate == null) { // // Unknown kind of notification, ignore. @@ -105,7 +110,7 @@ public void sendNotification(Notification notification) throws NotificationExcep return; } - var formattedMessage = new NotificationTemplate( + var formattedMessage = new MessageTemplate( htmlTemplate, this.options.timeZone, HtmlEscapers.htmlEscaper()) @@ -130,6 +135,61 @@ public void sendNotification(Notification notification) throws NotificationExcep // Inner classes. // ------------------------------------------------------------------------- + /** + * Template for turning a notification object into some textual representation. + */ + public static class MessageTemplate { + private final String template; + private final Escaper escaper; + private final ZoneId timezoneId; + + public MessageTemplate( + String template, + ZoneId timezoneId, + Escaper escaper + ) { + Preconditions.checkNotNull(template, "template"); + Preconditions.checkNotNull(timezoneId, "timezoneId"); + Preconditions.checkNotNull(escaper, "escaper"); + + this.template = template; + this.timezoneId = timezoneId; + this.escaper = escaper; + } + + public String format(NotificationService.Notification notification) { + Preconditions.checkNotNull(notification, "notification"); + + // + // Replace all {{PROPERTY}} placeholders in the template. + // + + var message = this.template; + for (var property : notification.properties.entrySet()) { + String propertyValue; + if (property.getValue() instanceof Instant) { + // + // Apply time zone and convert to string. + // + propertyValue = OffsetDateTime + .ofInstant((Instant) property.getValue(), this.timezoneId) + .truncatedTo(ChronoUnit.SECONDS) + .format(DateTimeFormatter.RFC_1123_DATE_TIME); + } + else { + // + // Convert to a safe string. + // + propertyValue = escaper.escape(property.getValue().toString()); + } + + message = message.replace("{{" + property.getKey() + "}}", propertyValue); + } + + return message; + } + } + public static class Options { public static final ZoneId DEFAULT_TIMEZONE = ZoneOffset.UTC; diff --git a/sources/src/main/java/com/google/solutions/jitaccess/core/services/NotificationService.java b/sources/src/main/java/com/google/solutions/jitaccess/core/services/NotificationService.java index 812dcb429..a88757ed5 100644 --- a/sources/src/main/java/com/google/solutions/jitaccess/core/services/NotificationService.java +++ b/sources/src/main/java/com/google/solutions/jitaccess/core/services/NotificationService.java @@ -22,16 +22,10 @@ package com.google.solutions.jitaccess.core.services; import com.google.common.base.Preconditions; -import com.google.common.escape.Escaper; import com.google.solutions.jitaccess.core.data.UserId; import jakarta.enterprise.context.ApplicationScoped; -import java.io.IOException; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoUnit; + import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -96,7 +90,10 @@ public String getSubject() { return subject; } - public abstract String getTemplateId(); + /** + * @return string identifying the type of notification. + */ + public abstract String getType(); protected Notification( Collection toRecipients, @@ -126,61 +123,6 @@ public String toString() { } } - /** - * Template for turning a notification object into some textual representation. - */ - public static class NotificationTemplate { - private final String template; - private final Escaper escaper; - private final ZoneId timezoneId; - - public NotificationTemplate( - String template, - ZoneId timezoneId, - Escaper escaper - ) { - Preconditions.checkNotNull(template, "template"); - Preconditions.checkNotNull(timezoneId, "timezoneId"); - Preconditions.checkNotNull(escaper, "escaper"); - - this.template = template; - this.timezoneId = timezoneId; - this.escaper = escaper; - } - - public String format(NotificationService.Notification notification) { - Preconditions.checkNotNull(notification, "notification"); - - // - // Replace all {{PROPERTY}} placeholders in the template. - // - - var message = this.template; - for (var property : notification.properties.entrySet()) { - String propertyValue; - if (property.getValue() instanceof Instant) { - // - // Apply time zone and convert to string. - // - propertyValue = OffsetDateTime - .ofInstant((Instant)property.getValue(), this.timezoneId) - .truncatedTo(ChronoUnit.SECONDS) - .format(DateTimeFormatter.RFC_1123_DATE_TIME); - } - else { - // - // Convert to a safe string. - // - propertyValue = escaper.escape(property.getValue().toString()); - } - - message = message.replace("{{" + property.getKey() + "}}", propertyValue); - } - - return message; - } - } - public static class NotificationException extends Exception { public NotificationException(String message, Throwable cause) { super(message, cause); diff --git a/sources/src/main/java/com/google/solutions/jitaccess/web/ApiResource.java b/sources/src/main/java/com/google/solutions/jitaccess/web/ApiResource.java index 6a7e465e8..061866c2b 100644 --- a/sources/src/main/java/com/google/solutions/jitaccess/web/ApiResource.java +++ b/sources/src/main/java/com/google/solutions/jitaccess/web/ApiResource.java @@ -894,7 +894,7 @@ protected RequestActivationNotification( } @Override - public String getTemplateId() { + public String getType() { return "RequestActivation"; } } @@ -932,7 +932,7 @@ protected boolean isReply() { } @Override - public String getTemplateId() { + public String getType() { return "ActivationApproved"; } } diff --git a/sources/src/test/java/com/google/solutions/jitaccess/core/services/TestMailNotificationService.java b/sources/src/test/java/com/google/solutions/jitaccess/core/services/TestMailNotificationService.java index 9ec934e4e..6d57d7477 100644 --- a/sources/src/test/java/com/google/solutions/jitaccess/core/services/TestMailNotificationService.java +++ b/sources/src/test/java/com/google/solutions/jitaccess/core/services/TestMailNotificationService.java @@ -56,7 +56,7 @@ protected TestNotification( } @Override - public String getTemplateId() { + public String getType() { return this.templateId; } } diff --git a/sources/src/test/java/com/google/solutions/jitaccess/core/services/TestNotificationTemplate.java b/sources/src/test/java/com/google/solutions/jitaccess/core/services/TestMessageTemplate.java similarity index 94% rename from sources/src/test/java/com/google/solutions/jitaccess/core/services/TestNotificationTemplate.java rename to sources/src/test/java/com/google/solutions/jitaccess/core/services/TestMessageTemplate.java index f45331d24..f9f7be44b 100644 --- a/sources/src/test/java/com/google/solutions/jitaccess/core/services/TestNotificationTemplate.java +++ b/sources/src/test/java/com/google/solutions/jitaccess/core/services/TestMessageTemplate.java @@ -34,7 +34,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class TestNotificationTemplate { +public class TestMessageTemplate { private static class TestNotification extends NotificationService.Notification { private final String templateId; @@ -53,7 +53,7 @@ protected TestNotification( } @Override - public String getTemplateId() { + public String getType() { return this.templateId; } } @@ -74,7 +74,7 @@ public void whenPropertiesContainHtmlTags_ThenFormatEscapesTags() { properties, "ignored-templateid"); - var template = new NotificationService.NotificationTemplate( + var template = new MailNotificationService.MessageTemplate( notification.properties .entrySet() .stream() @@ -99,7 +99,7 @@ public void whenPropertiesContainDates_ThenFormatAppliesTimezone() { properties, "ignored-templateid"); - var template = new NotificationService.NotificationTemplate( + var template = new MailNotificationService.MessageTemplate( notification.properties .entrySet() .stream()