Merge branch 'jbross-buoy-tender' into bug2724

Conflicts:
	java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties
This commit is contained in:
Axel Uhl committed 2015-03-23 16:18:37 +01:00
commit f8c16d1049
46 files changed
+1219 -399

No files matched your search

@@ -1,4 +1,5 @@
trackingInvitationFor=Einladung zum Tracken für
scanQRCodeOrVisitUrlToRegisterAs=Scanne den QRCode oder klicke den Link mit deinem Smartphone an um dich zu registrieren als
welcomeTo=Willkommen zu
alternativelyVisitThisLink=Alternativ kannst du diesen Link anklicken
alternativelyVisitThisLink=Alternativ kannst du diesen Link anklicken
buoyTender=Bojenleger
@@ -1,4 +1,5 @@
trackingInvitationFor=Tracking Invitation for
scanQRCodeOrVisitUrlToRegisterAs=Scan the following QRCode or click the link using your smartphone to register as
welcomeTo=Welcome to
alternativelyVisitThisLink=Alternatively, you can click this Link
alternativelyVisitThisLink=Alternatively, you can click this Link
buoyTender=buoy tender
@@ -78,7 +78,22 @@ public interface RaceLogTrackingAdapter {
/**
* Add a fix to the {@link GPSFixStore}, and create a mapping with a virtual device for exactly that timepoint.
*/
void pingMark(RaceLog raceLogToAddTo, Mark mark, GPSFix gpsFix, RacingEventService service, DeviceIdentifier device);
/**
* @see #pingMark(RaceLog, Mark, GPSFix, RacingEventService) using a random {@link PingDeviceIdentifier}
*/
void pingMark(RaceLog raceLogToAddTo, Mark mark, GPSFix gpsFix, RacingEventService service);
/**
* @see #pingMark(RaceLog, Mark, GPSFix, RacingEventService)
*/
void pingMark(RegattaLog regattaLogToAddTo, Mark mark, GPSFix gpsFix, RacingEventService service);
/**
* @see #pingMark(RaceLog, Mark, GPSFix, RacingEventService, DeviceIdentifier)
*/
void pingMark(RegattaLog regattaLogToAddTo, Mark mark, GPSFix gpsFix, RacingEventService service, DeviceIdentifier device);
/**
* Duplicate the course and competitor registrations in the newest {@link RaceLogCourseDesignChangedEvent} in
@@ -102,7 +117,15 @@ public interface RaceLogTrackingAdapter {
/**
* Invite competitors for tracking via the Tracking App by sending out emails.
* @throws MailException
*/
void inviteCompetitorsForTrackingViaEmail(Event event, Leaderboard leaderboard,
String serverUrlWithoutTrailingSlash, Set<Competitor> competitors, Locale locale) throws MailException;
/**
* Invite buoy tenders for buoy pinging via the Buoy Tender App by sending out emails.
* @throws MailException
*/
void inviteBuoyTenderViaEmail(Event event, Leaderboard leaderboard, String serverUrlWithoutTrailingSlash,
String emails, Locale locale) throws MailException;
}
@@ -2,11 +2,9 @@ package com.sap.sailing.domain.racelogtracking.impl;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
@@ -38,12 +36,12 @@ import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTracking
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceMarkMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.shared.analyzing.RegisteredCompetitorsAnalyzer;
import com.sap.sailing.domain.abstractlog.shared.events.RegisterCompetitorEvent;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.CourseBase;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Event;
@@ -54,7 +52,6 @@ import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.SharedDomainFactory;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.CourseDataImpl;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.common.RegattaIdentifier;
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
import com.sap.sailing.domain.common.racelog.tracking.DeviceMappingConstants;
@@ -75,7 +72,6 @@ import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.mail.MailException;
import com.sap.sse.mail.MailService;
@@ -184,44 +180,6 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
public RaceLogTrackingState getRaceLogTrackingState(RacingEventService service, RaceColumn raceColumn, Fleet fleet) {
return new RaceLogTrackingStateAnalyzer(raceColumn.getRaceLog(fleet)).analyze();
}
private Waypoint duplicateWaypoint(Waypoint waypoint, Map<ControlPoint, ControlPoint> controlPointDuplicationCache,
Map<Mark, Mark> markDuplicationCache, SharedDomainFactory baseDomainFactory) {
ControlPoint oldCP = waypoint.getControlPoint();
ControlPoint newCP = null;
PassingInstruction pi = waypoint.getPassingInstructions();
if (controlPointDuplicationCache.get(oldCP) != null) {
newCP = controlPointDuplicationCache.get(oldCP);
} else {
Mark[] newMarks = new Mark[Util.size(oldCP.getMarks())];
int i = 0;
for (Mark oldMark : oldCP.getMarks()) {
newMarks[i] = null;
if (markDuplicationCache.get(oldMark) != null) {
newMarks[i] = markDuplicationCache.get(oldMark);
} else {
newMarks[i] = baseDomainFactory.getOrCreateMark(UUID.randomUUID(), oldMark.getName(), oldMark.getType(),
oldMark.getColor(), oldMark.getShape(), oldMark.getPattern());
markDuplicationCache.put(oldMark, newMarks[i]);
}
i++;
}
switch (newMarks.length) {
case 1:
newCP = newMarks[0];
break;
case 2:
newCP = baseDomainFactory.createControlPointWithTwoMarks(newMarks[0], newMarks[1], oldCP.getName());
break;
default:
logger.log(Level.WARNING, "Don't know how to duplicate CP with more than 2 marks");
throw new RuntimeException("Don't know how to duplicate CP with more than 2 marks");
}
controlPointDuplicationCache.put(oldCP, newCP);
}
return baseDomainFactory.createWaypoint(newCP, pi);
}
private void revokeAlreadyDefinedMarks(RaceLog raceLog, AbstractLogEventAuthor author) {
List<RaceLogEvent> markEvents = new AllEventsOfTypeFinder<>(raceLog, /* only unrevoked */ true, RaceLogDefineMarkEvent.class).analyze();
@@ -246,16 +204,14 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
CourseBase to = new CourseDataImpl("Copy of \"" + course.getName());
TimePoint now = MillisecondsTimePoint.now();
int i = 0;
Map<ControlPoint, ControlPoint> controlPointDuplicationCache = new HashMap<ControlPoint, ControlPoint>();
revokeAlreadyDefinedMarks(toRaceLog, service.getServerAuthor());
Map<Mark, Mark> markDuplicationCache = new HashMap<Mark, Mark>();
for (Waypoint oldWaypoint : course.getWaypoints()) {
to.addWaypoint(i++, duplicateWaypoint(oldWaypoint, controlPointDuplicationCache, markDuplicationCache, baseDomainFactory));
}
for (Mark mark : markDuplicationCache.values()) {
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createDefineMarkEvent(now, service.getServerAuthor(),
toRaceLog.getCurrentPassId(), mark);
toRaceLog.add(event);
to.addWaypoint(i++, oldWaypoint);
for (Mark mark : oldWaypoint.getMarks()) {
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createDefineMarkEvent(now, service.getServerAuthor(),
toRaceLog.getCurrentPassId(), mark);
toRaceLog.add(event);
}
}
int passId = toRaceLog.getCurrentPassId();
RaceLogEvent newCourseEvent = RaceLogEventFactory.INSTANCE.createCourseDesignChangedEvent(
@@ -265,21 +221,47 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
}
}
@Override
public void pingMark(RaceLog raceLog, Mark mark, GPSFix gpsFix, RacingEventService service) {
DeviceIdentifier device = new PingDeviceIdentifierImpl();
TimePoint time = gpsFix.getTimePoint();
@FunctionalInterface
private static interface DeviceMarkMappingEventFactory<VisitorT, EventT extends AbstractLogEvent<VisitorT>>{
EventT createDeviceMarkMapping(DeviceIdentifier device, TimePoint timePoint);
}
RaceLogEvent mapping = RaceLogEventFactory.INSTANCE.createDeviceMarkMappingEvent(time,
service.getServerAuthor(), device, mark, raceLog.getCurrentPassId(), time, time);
raceLog.add(mapping);
private <VisitorT, EventT extends AbstractLogEvent<VisitorT>, LogT extends AbstractLog<EventT, VisitorT>> void pingMark(
LogT log, Mark mark, GPSFix gpsFix, RacingEventService service,
DeviceMarkMappingEventFactory<VisitorT, EventT> factory, DeviceIdentifier device) {
TimePoint time = gpsFix.getTimePoint();
EventT mapping = factory.createDeviceMarkMapping(device, time);
log.add(mapping);
try {
service.getGPSFixStore().storeFix(device, gpsFix);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not pint mark " + mark);
logger.log(Level.WARNING, "Could not ping mark " + mark);
}
}
@Override
public void pingMark(RaceLog raceLog, Mark mark, GPSFix gpsFix, RacingEventService service, DeviceIdentifier device) {
pingMark(raceLog, mark, gpsFix, service, (DeviceIdentifier dev, TimePoint timePoint) ->
RaceLogEventFactory.INSTANCE.createDeviceMarkMappingEvent(timePoint,
service.getServerAuthor(), dev, mark, raceLog.getCurrentPassId(), timePoint, timePoint), device);
}
@Override
public void pingMark(RaceLog raceLog, Mark mark, GPSFix gpsFix, RacingEventService service) {
pingMark(raceLog, mark, gpsFix, service, new PingDeviceIdentifierImpl());
}
@Override
public void pingMark(RegattaLog regattaLog, Mark mark, GPSFix gpsFix, RacingEventService service, DeviceIdentifier device) {
pingMark(regattaLog, mark, gpsFix, service, (DeviceIdentifier dev, TimePoint timePoint) ->
new RegattaLogDeviceMarkMappingEventImpl(service.getServerAuthor(), timePoint, mark, dev, timePoint, timePoint), device);
}
@Override
public void pingMark(RegattaLog regattaLog, Mark mark, GPSFix gpsFix, RacingEventService service) {
pingMark(regattaLog, mark, gpsFix, service, new PingDeviceIdentifierImpl());
}
@Override
public void removeDenotationForRaceLogTracking(RacingEventService service, RaceLog raceLog) {
RaceLogEvent denoteForTrackingEvent = new LastEventOfTypeFinder<>(raceLog, true, RaceLogDenoteForTrackingEvent.class).analyze();
@@ -365,35 +347,10 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
String url = DeviceMappingConstants.getDeviceMappingForRegattaLogUrl(serverUrlWithoutTrailingSlash,
event.getId().toString(), leaderboardName, DeviceMappingConstants.URL_COMPETITOR_ID_AS_STRING,
competitor.getId().toString(), NonGwtUrlHelper.INSTANCE);
String subject = String.format("%s %s",
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "trackingInvitationFor"), competitorName);
// taken from http://www.tutorialspoint.com/javamail_api/javamail_api_send_inlineimage_in_email.htm
BodyPart messageTextPart = new MimeBodyPart();
String htmlText = String.format("<h1>%s %s</h1>" + "<p>%s <b>%s</b></p>"
+ "<img src=\"cid:image\" title=\"%s\"><br/>"
+ "<a href=\"%s\">%s</a>",
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "welcomeTo"), leaderboardName,
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "scanQRCodeOrVisitUrlToRegisterAs"), competitorName,
url, url, RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "alternativelyVisitThisLink"));
try {
messageTextPart.setContent(htmlText, "text/html");
BodyPart messageImagePart = new MimeBodyPart();
InputStream imageIs = QRCodeGenerationUtil.create(url, 250);
DataSource imageDs = new ByteArrayDataSource(imageIs, "image/png");
messageImagePart.setDataHandler(new DataHandler(imageDs));
messageImagePart.setHeader("Content-ID", "<image>");
MimeMultipart multipart = new MimeMultipart();
multipart.addBodyPart(messageTextPart);
multipart.addBodyPart(messageImagePart);
getMailService().sendMail(toAddress, subject, multipart);
} catch (MessagingException | MailException | WriterException | IOException e) {
logger.log(Level.SEVERE, "Error trying to send mail to " + competitor.getName()
+ " with e-mail address " + toAddress, e);
sendInvitationEmail(locale, toAddress, leaderboardName, competitorName,
url);
} catch (MailException e){
occuredExceptions.append(e.getMessage()+"\r\n");
}
}
@@ -402,4 +359,62 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
throw new MailException(occuredExceptions.toString());
}
}
private void sendInvitationEmail(Locale locale, final String toAddress, String leaderboardName, String invitee, String url) throws MailException {
String subject = String.format("%s %s",
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "trackingInvitationFor"), invitee);
// taken from http://www.tutorialspoint.com/javamail_api/javamail_api_send_inlineimage_in_email.htm
BodyPart messageTextPart = new MimeBodyPart();
String htmlText = String.format("<h1>%s %s</h1>" + "<p>%s <b>%s</b></p>"
+ "<img src=\"cid:image\" title=\"%s\"><br/>"
+ "<a href=\"%s\">%s</a>",
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "welcomeTo"), leaderboardName,
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "scanQRCodeOrVisitUrlToRegisterAs"), invitee,
url, url, RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "alternativelyVisitThisLink"));
try {
messageTextPart.setContent(htmlText, "text/html");
BodyPart messageImagePart = new MimeBodyPart();
InputStream imageIs = QRCodeGenerationUtil.create(url, 250);
DataSource imageDs = new ByteArrayDataSource(imageIs, "image/png");
messageImagePart.setDataHandler(new DataHandler(imageDs));
messageImagePart.setHeader("Content-ID", "<image>");
MimeMultipart multipart = new MimeMultipart();
multipart.addBodyPart(messageTextPart);
multipart.addBodyPart(messageImagePart);
getMailService().sendMail(toAddress, subject, multipart);
} catch (MessagingException | MailException | WriterException | IOException e) {
logger.log(Level.SEVERE, "Error trying to send mail to " + invitee
+ " with e-mail address " + toAddress, e);
throw new MailException(e.getMessage());
}
}
@Override
public void inviteBuoyTenderViaEmail(Event event, Leaderboard leaderboard, String serverUrlWithoutTrailingSlash,
String emails, Locale locale) throws MailException {
StringBuilder occuredExceptions = new StringBuilder();
String[] emailArray = emails.split(",");
String leaderboardName = leaderboard.getName();
//http://<host>/buoy-tender/checkin&leaderboard_name=<leaderboard-name>
String url = DeviceMappingConstants.getBuoyTenderInvitationUrl(serverUrlWithoutTrailingSlash, leaderboardName,NonGwtUrlHelper.INSTANCE);
for (String toAddress : emailArray){
try {
sendInvitationEmail(locale, toAddress, leaderboardName, RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "buoyTender"), url);
} catch (MailException e) {
occuredExceptions.append(e.getMessage()+"\r\n");
}
}
if (!(occuredExceptions.length() == 0)){
throw new MailException(occuredExceptions.toString());
}
}
}