mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-24 04:53:54 +00:00
Changes notification mails to use html with styled link buttons
This commit is contained in:
1 parent
133fcdaa58
commit
23615ef97f
5 files changed
+192
-88
No files matched your search
+27
@@ -0,0 +1,27 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>${title}</title>
|
||||
<style type="text/css">
|
||||
.linkButton, .linkButton:active, .linkButton:visited {
|
||||
padding: 15px;
|
||||
margin: 10px;
|
||||
width: 200px;
|
||||
display: inline-block;
|
||||
background-color: #337ab7;
|
||||
border-radius: 4px;
|
||||
color: #ffffff;
|
||||
border: 1px solid #2e6da4;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.linkButton:hover {
|
||||
background-color: #2b618e;
|
||||
border: 1px solid #204d74;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${body}
|
||||
</body>
|
||||
</html>
|
||||
@@ -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}.
|
||||
|
||||
|
||||
+42
@@ -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<Pair<String, String>> labelsAndLinkUrls;
|
||||
|
||||
@SafeVarargs
|
||||
public NotificationMailTemplate(String subject, String text, Pair<String, String>... labelsAndLinkUrls) {
|
||||
this(subject, null, text, labelsAndLinkUrls);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public NotificationMailTemplate(String subject, String title, String text, Pair<String, String>... 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<Pair<String, String>> getLabelsAndLinkUrls() {
|
||||
return labelsAndLinkUrls;
|
||||
}
|
||||
}
|
||||
+41
-5
@@ -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<T> 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<T> 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("<h1>").append(notificationMailTemplate.getTitle()).append("</h1>");
|
||||
}
|
||||
bodyContent.append("<p>").append(notificationMailTemplate.getText()).append("</p>");
|
||||
for (Pair<String, String> link : notificationMailTemplate.getLabelsAndLinkUrls()) {
|
||||
bodyContent.append("<a class=\"linkButton\" href=\"").append(link.getB()).append("\">");
|
||||
bodyContent.append(link.getA()).append("</a>");
|
||||
}
|
||||
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);
|
||||
}
|
||||
+66
-73
@@ -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<String, String> 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<String, String> createRaceBoardRaceAnalysisLink(TrackedRace trackedRace, Leaderboard leaderboard,
|
||||
Event event, LeaderboardGroup leaderboardGroup, Locale locale) {
|
||||
return createRaceBoardLink(trackedRace, leaderboard, event, leaderboardGroup, "FULL_ANALYSIS",
|
||||
"raceboardRaceAnalysisLinkTitle", locale);
|
||||
}
|
||||
|
||||
private Pair<String, String> 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<String, String>(messages.get(locale, labelMessageKey), link);
|
||||
}
|
||||
|
||||
private Pair<String, String> createHomeRacesListLink(Leaderboard leaderboard, Event event, Locale locale) {
|
||||
return createHomeRegattaLink("races", "racesOverviewLinkTitle", leaderboard, event, locale);
|
||||
}
|
||||
|
||||
private Pair<String, String> createHomeLeaderboardLink(Leaderboard leaderboard, Event event,
|
||||
Locale locale) {
|
||||
return createHomeRegattaLink("leaderboard", "leaderboardShowResultsLinkTitle", leaderboard, event, locale);
|
||||
}
|
||||
|
||||
private Pair<String, String> 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<String, String>(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>(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>(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>(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 = "<a href=\""+link+"\">"+link.replace("&", "&")+"</a>";
|
||||
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>(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>(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));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user