diff --git a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html
new file mode 100644
index 00000000000..e26d3e760bb
--- /dev/null
+++ b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html
@@ -0,0 +1,27 @@
+
+
+
+ ${title}
+
+
+
+ ${body}
+
+
\ No newline at end of file
diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties
index 0a380024413..62d6ddca390 100644
--- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties
+++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties
@@ -2,23 +2,29 @@ raceInRegattaOfEvent=race {0} in regatta {1} of event {2}
raceInFleetInRegattaOfEvent={0} ({3}) in regatta {1} of event {2}
leaderboardOfEvent=leaderboard {0} of event {1}
+leaderboardShowResultsLinkTitle=Show results
+racesOverviewLinkTitle=Show races overview
+raceboardShowRaceLinkTitle=Show race
+raceboardRaceAnalysisLinkTitle=Show race analysis
boatClassRaceFinishedSubject=Race for boat class {0} has finished - new results available
-# 0: boatClassName, 1: raceDescription, 2: link
-boatClassRaceFinishedBody=New results for boat class {0} in {1} are available. See: {2}
+# 0: boatClassName, 1: raceDescription
+boatClassRaceFinishedBody=New results for boat class {0} in {1} are available.
boatClassScoreCorrectionSubject=New results are available for boat class {0}
-# 0: boatClassName, 1: leaderboardDescription, 2: link
-boatClassScoreCorrectionBody=New results for boat class {0} in {1} are available. See: {2}
+# 0: boatClassName, 1: leaderboardDescription
+boatClassScoreCorrectionBody=New results for boat class {0} in {1} are available.
competitorPassesFinishSubject=Competitor {0} passed finish line in a race
-# 0: competitorName, 1: raceDescription, 2: link
-competitorPassesFinishBody=Competitor {0} passed finish line in {1}. See: {2}
+# 0: competitorName, 1: raceDescription
+competitorPassesFinishBody=Competitor {0} passed finish line in {1}.
competitorScoreCorrectionSubject=New results are available for competitor {0}
-# 0: competitorName, 1: leaderboardDescription, 2: link
-competitorScoreCorrectionBody=New results for competitor {0} in {1} are available. See: {2}
+# 0: competitorName, 1: leaderboardDescription
+competitorScoreCorrectionBody=New results for competitor {0} in {1} are available.
boatClassUpcomingRaceSubject=A race for boat class {0} will start soon
-# 0: boatClassName, 1: raceDescription, 2: time, 3: link
-boatClassUpcomingRaceBody=A race for boat class {0} in {1} will start approximately at {2}. See: {3}
+# 0: boatClassName, 1: raceDescription, 2: time
+boatClassUpcomingRaceBody=A race for boat class {0} in {1} will start approximately at {2}.
+
+
diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationMailTemplate.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationMailTemplate.java
new file mode 100644
index 00000000000..be88f351ec9
--- /dev/null
+++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationMailTemplate.java
@@ -0,0 +1,42 @@
+package com.sap.sailing.server.notification.impl;
+
+import java.util.Arrays;
+
+import com.sap.sse.common.Util.Pair;
+
+public class NotificationMailTemplate {
+
+ private final String subject;
+ private final String title;
+ private final String text;
+ private final Iterable> labelsAndLinkUrls;
+
+ @SafeVarargs
+ public NotificationMailTemplate(String subject, String text, Pair... labelsAndLinkUrls) {
+ this(subject, null, text, labelsAndLinkUrls);
+ }
+
+ @SafeVarargs
+ public NotificationMailTemplate(String subject, String title, String text, Pair... labelsAndLinkUrls) {
+ this.subject = subject;
+ this.title = title;
+ this.text = text;
+ this.labelsAndLinkUrls = Arrays.asList(labelsAndLinkUrls);
+ }
+
+ public String getSubject() {
+ return subject;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public Iterable> getLabelsAndLinkUrls() {
+ return labelsAndLinkUrls;
+ }
+}
diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java
index 8d051707277..91976427a2f 100644
--- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java
+++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java
@@ -1,5 +1,9 @@
package com.sap.sailing.server.notification.impl;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -9,12 +13,31 @@ import javax.mail.Multipart;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
+import com.sap.sse.common.Util.Pair;
import com.sap.sse.mail.MailService;
import com.sap.sse.mail.queue.MailNotification;
import com.sap.sse.security.PreferenceObjectBasedNotificationSet;
public abstract class NotificationSetNotification implements MailNotification {
private static final Logger logger = Logger.getLogger(NotificationSetNotification.class.getName());
+
+ private static final String TEMPLATE_FILE = "notification-mail-template.html";
+ private static final String TEMPLATE = loadTemplateFile();
+
+ private static String loadTemplateFile() {
+ StringBuilder content = new StringBuilder();
+ try (BufferedReader in = new BufferedReader(new InputStreamReader(
+ NotificationSetNotification.class.getResourceAsStream(TEMPLATE_FILE), StandardCharsets.UTF_8))) {
+ String line;
+ while ((line = in.readLine()) != null) {
+ content.append(line).append("\n");
+ }
+ } catch (IOException exc) {
+ logger.log(Level.SEVERE, "Error while loading notification mail template!", exc);
+ }
+ return content.toString();
+ }
+
private final T objectToNotifyAbout;
private final PreferenceObjectBasedNotificationSet, T> associatedNotificationSet;
@@ -33,17 +56,30 @@ public abstract class NotificationSetNotification implements MailNotification
Multipart multipart = new MimeMultipart();
BodyPart bodyPart = new MimeBodyPart();
try {
- bodyPart.setContent(constructBody(objectToNotifyAbout, locale), "text/html");
+ NotificationMailTemplate mailTemplate = getMailTemplate(objectToNotifyAbout, locale);
+ bodyPart.setContent(getMailContent(mailTemplate), "text/html");
multipart.addBodyPart(bodyPart);
- mailService.sendMail(user.getEmail(), constructSubject(objectToNotifyAbout, locale), multipart);
+ mailService.sendMail(user.getEmail(), mailTemplate.getSubject(), multipart);
} catch (Exception e) {
logger.log(Level.SEVERE,
"Could not send mail notification for \"" + objectToNotifyAbout + "\" to user \" + user + \"", e);
}
});
}
+
+ private String getMailContent(NotificationMailTemplate notificationMailTemplate) {
+ StringBuilder bodyContent = new StringBuilder();
+ if (notificationMailTemplate.getTitle() != null) {
+ bodyContent.append("").append(notificationMailTemplate.getTitle()).append("
");
+ }
+ bodyContent.append("").append(notificationMailTemplate.getText()).append("
");
+ for (Pair link : notificationMailTemplate.getLabelsAndLinkUrls()) {
+ bodyContent.append("");
+ bodyContent.append(link.getA()).append("");
+ }
+ return TEMPLATE.replace("${title}", notificationMailTemplate.getSubject()).replace("${body}", bodyContent.toString());
+ }
+
+ protected abstract NotificationMailTemplate getMailTemplate(T objectToNotifyAbout, Locale locale);
- protected abstract String constructSubject(T objectToNotifyAbout, Locale locale);
-
- protected abstract String constructBody(T objectToNotifyAbout, Locale locale);
}
\ No newline at end of file
diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java
index 2f60ce3462a..c42fcd7673d 100644
--- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java
+++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java
@@ -173,19 +173,44 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific
return messages.get(locale, "leaderboardOfEvent", leaderboardDisplayName, eventName);
}
-
- private String createRaceBoardLink(TrackedRace trackedRace, Leaderboard leaderboard, Event event,
- LeaderboardGroup leaderboardGroup) {
- RegattaAndRaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier();
- String link = getBaseURL(event).toString() + "/gwt/RaceBoard.html?eventId=" + event.getId() + "&leaderboardName=" + leaderboard.getName()
- + "&leaderboardGroupName=" + leaderboardGroup.getName() + "&raceName="
- + raceIdentifier.getRaceName() + "&showMapControls=true&viewShowNavigationPanel=true®attaName="
- + raceIdentifier.getRegattaName();
- return link;
+
+ private Pair createRaceBoardShowRaceLink(TrackedRace trackedRace, Leaderboard leaderboard,
+ Event event, LeaderboardGroup leaderboardGroup, Locale locale) {
+ return createRaceBoardLink(trackedRace, leaderboard, event, leaderboardGroup, "PLAYER",
+ "raceboardShowRaceLinkTitle", locale);
}
- private String createHomeRacesListLink(Leaderboard leaderboard, Event event) {
- return createHomeRegattaLink("races", leaderboard, event);
+ private Pair createRaceBoardRaceAnalysisLink(TrackedRace trackedRace, Leaderboard leaderboard,
+ Event event, LeaderboardGroup leaderboardGroup, Locale locale) {
+ return createRaceBoardLink(trackedRace, leaderboard, event, leaderboardGroup, "FULL_ANALYSIS",
+ "raceboardRaceAnalysisLinkTitle", locale);
+ }
+
+ private Pair createRaceBoardLink(TrackedRace trackedRace, Leaderboard leaderboard, Event event,
+ LeaderboardGroup leaderboardGroup, String raceboardMode, String labelMessageKey, Locale locale) {
+ RegattaAndRaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier();
+ String link = getBaseURL(event).toString() + "/gwt/RaceBoard.html?locale=" + locale.toLanguageTag()
+ + "&eventId=" + event.getId() + "&leaderboardName=" + leaderboard.getName()
+ + "&leaderboardGroupName=" + leaderboardGroup.getName() + "&raceName="
+ + raceIdentifier.getRaceName() + "&showMapControls=true&viewShowNavigationPanel=true®attaName="
+ + raceIdentifier.getRegattaName() + "&mode=" + raceboardMode;
+ return new Pair(messages.get(locale, labelMessageKey), link);
+ }
+
+ private Pair createHomeRacesListLink(Leaderboard leaderboard, Event event, Locale locale) {
+ return createHomeRegattaLink("races", "racesOverviewLinkTitle", leaderboard, event, locale);
+ }
+
+ private Pair createHomeLeaderboardLink(Leaderboard leaderboard, Event event,
+ Locale locale) {
+ return createHomeRegattaLink("leaderboard", "leaderboardShowResultsLinkTitle", leaderboard, event, locale);
+ }
+
+ private Pair createHomeRegattaLink(String tab, String labelMessageKey, Leaderboard leaderboard,
+ Event event, Locale locale) {
+ String link = getBaseURL(event).toString() + "/gwt/Home.html?locale=" + locale.toLanguageTag()
+ + "#/regatta/" + tab + "/:eventId=" + event.getId() + "®attaId=" + leaderboard.getName();
+ return new Pair(messages.get(locale, labelMessageKey), link);
}
/**
@@ -201,34 +226,21 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific
}
return result;
}
-
- private String createHomeLeaderboardLink(Leaderboard leaderboard, Event event) {
- return createHomeRegattaLink("leaderboard", leaderboard, event);
- }
-
- private String createHomeRegattaLink(String tab, Leaderboard leaderboard, Event event) {
- String link = getBaseURL(event).toString() + "/gwt/Home.html#/regatta/" + tab + "/:eventId=" + event.getId() + "®attaId="
- + leaderboard.getName();
- return link;
- }
@Override
public void notifyUserOnBoatClassRaceChangesStateToFinished(BoatClass boatClass, TrackedRace trackedRace,
Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) {
doWithEvent(leaderboard, (event, leaderboardGroup) -> {
- String link = createRaceBoardLink(trackedRace, leaderboard, event, leaderboardGroup);
-
mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassResults) {
+
@Override
- protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) {
- return messages.get(locale, "boatClassRaceFinishedSubject", boatClass.getDisplayName());
- }
-
- @Override
- protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) {
+ protected NotificationMailTemplate getMailTemplate(BoatClass objectToNotifyAbout, Locale locale) {
String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet);
- return messages.get(locale, "boatClassRaceFinishedBody", boatClass.getDisplayName(),
- raceDescription, encodeLink(link));
+ return new NotificationMailTemplate(
+ messages.get(locale, "boatClassRaceFinishedSubject", boatClass.getDisplayName()),
+ messages.get(locale, "boatClassRaceFinishedBody", boatClass.getDisplayName(), raceDescription),
+ createRaceBoardShowRaceLink(trackedRace, leaderboard, event, leaderboardGroup, locale),
+ createRaceBoardRaceAnalysisLink(trackedRace, leaderboard, event, leaderboardGroup, locale));
}
});
});
@@ -238,19 +250,15 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific
public void notifyUserOnBoatClassWhenScoreCorrectionsAreAvailable(BoatClass boatClass, Leaderboard leaderboard) {
// TODO don't send notifications when a notification for the same boatClass / leaderboard has already been sent shortly before
doWithEvent(leaderboard, (event, leaderboardGroup) -> {
- String link = createHomeLeaderboardLink(leaderboard, event);
mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassResults) {
@Override
- protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) {
- return messages.get(locale, "boatClassScoreCorrectionSubject", boatClass.getDisplayName());
- }
-
- @Override
- protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) {
+ protected NotificationMailTemplate getMailTemplate(BoatClass objectToNotifyAbout, Locale locale) {
String leaderboardDescription = calculateLeaderboardDescription(locale, event, leaderboard);
- return messages.get(locale, "boatClassScoreCorrectionBody", boatClass.getDisplayName(),
- leaderboardDescription, encodeLink(link));
+ return new NotificationMailTemplate(
+ messages.get(locale, "boatClassScoreCorrectionSubject", boatClass.getDisplayName()),
+ messages.get(locale, "boatClassScoreCorrectionBody", boatClass.getDisplayName(), leaderboardDescription),
+ createHomeLeaderboardLink(leaderboard, event, locale));
}
});
});
@@ -259,49 +267,37 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific
public void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, Leaderboard leaderboard, RaceColumn raceColumn,
Fleet fleet, TimePoint when) {
doWithEvent(leaderboard, (event, leaderboardGroup) -> {
- String link = createHomeRacesListLink(leaderboard, event);
mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassUpcomingRace) {
@Override
- protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) {
- return messages.get(locale, "boatClassUpcomingRaceSubject", boatClass.getDisplayName());
- }
-
- @Override
- protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) {
+ protected NotificationMailTemplate getMailTemplate(BoatClass objectToNotifyAbout, Locale locale) {
String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet);
// TODO properly format time in the user's locale
String time = when.toString();
- return messages.get(locale, "boatClassUpcomingRaceBody", boatClass.getDisplayName(),
- raceDescription, time, encodeLink(link));
+ return new NotificationMailTemplate(
+ messages.get(locale, "boatClassUpcomingRaceSubject", boatClass.getDisplayName()),
+ messages.get(locale, "boatClassUpcomingRaceBody", boatClass.getDisplayName(),
+ raceDescription, time),
+ createHomeRacesListLink(leaderboard, event, locale));
}
});
});
}
-
- private String encodeLink(String link) {
- String encodedLink = ""+link.replace("&", "&")+"";
- return encodedLink;
- }
-
@Override
public void notifyUserOnCompetitorPassesFinish(Competitor competitor, TrackedRace trackedRace,
Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) {
doWithEvent(leaderboard, (event, leaderboardGroup) -> {
- String link = createRaceBoardLink(trackedRace, leaderboard, event, leaderboardGroup);
mailQueue.addNotification(new NotificationSetNotification(competitor, competitorResults) {
@Override
- protected String constructSubject(Competitor objectToNotifyAbout, Locale locale) {
- return messages.get(locale, "competitorPassesFinishSubject", competitor.getName());
- }
-
- @Override
- protected String constructBody(Competitor objectToNotifyAbout, Locale locale) {
+ protected NotificationMailTemplate getMailTemplate(Competitor objectToNotifyAbout, Locale locale) {
String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet);
- return messages.get(locale, "competitorPassesFinishBody", competitor.getName(), raceDescription,
- encodeLink(link));
+ return new NotificationMailTemplate(
+ messages.get(locale, "competitorPassesFinishSubject", competitor.getName()),
+ messages.get(locale, "competitorPassesFinishBody", competitor.getName(), raceDescription),
+ createRaceBoardShowRaceLink(trackedRace, leaderboard, event, leaderboardGroup, locale),
+ createRaceBoardRaceAnalysisLink(trackedRace, leaderboard, event, leaderboardGroup, locale));
}
});
});
@@ -310,19 +306,16 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific
@Override
public void notifyUserOnCompetitorScoreCorrections(Competitor competitor, Leaderboard leaderboard) {
doWithEvent(leaderboard, (event, leaderboardGroup) -> {
- String link = createHomeLeaderboardLink(leaderboard, event);
mailQueue.addNotification(new NotificationSetNotification(competitor, competitorResults) {
@Override
- protected String constructSubject(Competitor objectToNotifyAbout, Locale locale) {
- return messages.get(locale, "boatClassScoreCorrectionSubject", competitor.getName());
- }
-
- @Override
- protected String constructBody(Competitor objectToNotifyAbout, Locale locale) {
+ protected NotificationMailTemplate getMailTemplate(Competitor objectToNotifyAbout, Locale locale) {
String leaderboardDescription = calculateLeaderboardDescription(locale, event, leaderboard);
- return messages.get(locale, "boatClassScoreCorrectionBody", competitor.getName(),
- leaderboardDescription, encodeLink(link));
+ return new NotificationMailTemplate(
+ messages.get(locale, "boatClassScoreCorrectionSubject", competitor.getName()),
+ messages.get(locale, "boatClassScoreCorrectionBody", competitor.getName(), leaderboardDescription),
+ createHomeLeaderboardLink(leaderboard, event, locale),
+ createHomeLeaderboardLink(leaderboard, event, locale));
}
});
});