96883875c15594d058bbadfb6660d22a4f0b3265
java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapter.java
| ... | ... | @@ -140,4 +140,6 @@ public interface RaceLogTrackingAdapter { |
| 140 | 140 | */ |
| 141 | 141 | void copyPairingListFromOtherLeaderboard(RegattaLeaderboard sourceLeaderboard, RegattaLeaderboard targetLeaderboard, |
| 142 | 142 | String fromRaceColumnName, String toRaceColumnInclusiveName) throws NotFoundException; |
| 143 | + |
|
| 144 | + void revokeExplicitTrackingTimes(RegattaLeaderboard leaderboard, RacingEventService raceLogResolver); |
|
| 143 | 145 | } |
java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java
| ... | ... | @@ -22,8 +22,14 @@ import org.osgi.framework.ServiceReference; |
| 22 | 22 | import com.sap.sailing.domain.abstractlog.impl.LastEventOfTypeFinder; |
| 23 | 23 | import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl; |
| 24 | 24 | import com.sap.sailing.domain.abstractlog.race.RaceLog; |
| 25 | +import com.sap.sailing.domain.abstractlog.race.RaceLogEndOfTrackingEvent; |
|
| 25 | 26 | import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; |
| 27 | +import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent; |
|
| 28 | +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.FinishedTimeFinder; |
|
| 26 | 29 | import com.sap.sailing.domain.abstractlog.race.analyzing.impl.LastPublishedCourseDesignFinder; |
| 30 | +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder; |
|
| 31 | +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinderResult; |
|
| 32 | +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.TrackingTimesEventFinder; |
|
| 27 | 33 | import com.sap.sailing.domain.abstractlog.race.impl.RaceLogCourseDesignChangedEventImpl; |
| 28 | 34 | import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent; |
| 29 | 35 | import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent; |
| ... | ... | @@ -463,4 +469,42 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter { |
| 463 | 469 | copyCompetitors(sourceRaceColumn, sourceFleet, Collections.singleton(new Pair<>(targetRaceColumn, targetFleet))); |
| 464 | 470 | } |
| 465 | 471 | } |
| 472 | + |
|
| 473 | + @Override |
|
| 474 | + public void revokeExplicitTrackingTimes(RegattaLeaderboard leaderboard, RacingEventService service) { |
|
| 475 | + for (final RaceColumn raceColumn : leaderboard.getRaceColumns()) { |
|
| 476 | + for (final Fleet fleet : raceColumn.getFleets()) { |
|
| 477 | + final RaceLog raceLog = raceColumn.getRaceLog(fleet); |
|
| 478 | + if (raceLog != null) { |
|
| 479 | + // handle only races denoted for smartphone tracking: |
|
| 480 | + if (new RaceLogTrackingStateAnalyzer(raceLog).analyze().isForTracking()) { |
|
| 481 | + final StartTimeFinder startTimeFinder = new StartTimeFinder(service, raceLog); |
|
| 482 | + final StartTimeFinderResult startTimeFinderResult = startTimeFinder.analyze(); |
|
| 483 | + final FinishedTimeFinder finishedTimeFinder = new FinishedTimeFinder(raceLog); |
|
| 484 | + final TimePoint finishedTime = finishedTimeFinder.analyze(); |
|
| 485 | + final TrackingTimesEventFinder trackingTimesEventFinder = new TrackingTimesEventFinder(raceLog); |
|
| 486 | + if (startTimeFinderResult != null && startTimeFinderResult.getStartTime() != null && finishedTime != null) { |
|
| 487 | + Pair<RaceLogStartOfTrackingEvent, RaceLogEndOfTrackingEvent> trackingTimes; |
|
| 488 | + while ((trackingTimes = trackingTimesEventFinder.analyze()) != null) { |
|
| 489 | + if (trackingTimes.getA() != null) { |
|
| 490 | + try { |
|
| 491 | + raceLog.revokeEvent(service.getServerAuthor(), trackingTimes.getA(), "revoke explicit start of tracking time"); |
|
| 492 | + } catch (NotRevokableException e) { |
|
| 493 | + logger.log(Level.WARNING, "could not revoke explicit start of tracking time by adding RevokeEvent", e); |
|
| 494 | + } |
|
| 495 | + } |
|
| 496 | + if (trackingTimes.getB() != null) { |
|
| 497 | + try { |
|
| 498 | + raceLog.revokeEvent(service.getServerAuthor(), trackingTimes.getB(), "revoke explicit end of tracking time"); |
|
| 499 | + } catch (NotRevokableException e) { |
|
| 500 | + logger.log(Level.WARNING, "could not revoke explicit end of tracking time by adding RevokeEvent", e); |
|
| 501 | + } |
|
| 502 | + } |
|
| 503 | + } |
|
| 504 | + } |
|
| 505 | + } |
|
| 506 | + } |
|
| 507 | + } |
|
| 508 | + } |
|
| 509 | + } |
|
| 466 | 510 | } |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleResources.java
| ... | ... | @@ -118,6 +118,9 @@ public interface AdminConsoleResources extends ClientBundle { |
| 118 | 118 | |
| 119 | 119 | @Source("com/sap/sailing/gwt/ui/client/images/compose_mail_small.png") |
| 120 | 120 | ImageResource inviteBuoyTenders(); |
| 121 | + |
|
| 122 | + @Source("com/sap/sailing/gwt/ui/client/images/eraser-icon.png") |
|
| 123 | + ImageResource eraser(); |
|
| 121 | 124 | |
| 122 | 125 | @Source("com/sap/sailing/gwt/ui/client/images/ajax-loader.gif") |
| 123 | 126 | ImageResource loaderGif(); |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementImagesBarCell.java
| ... | ... | @@ -17,6 +17,7 @@ public class RaceLogTrackingEventManagementImagesBarCell extends ImagesBarCell { |
| 17 | 17 | public final static String ACTION_MAP_DEVICES = "ACTION_MAP_DEVICES"; |
| 18 | 18 | public final static String ACTION_INVITE_BUOY_TENDERS = "ACTION_INVITE_BUOY_TENDERS"; |
| 19 | 19 | public static final String ACTION_SHOW_REGATTA_LOG = "ACTION_SHOW_REGATTA_LOG"; |
| 20 | + public static final String ACTION_REVOKE_EXPLICIT_TRACKING_TIMES = "ACTION_REVOKE_EXPLICIT_TRACKING_TIMES"; |
|
| 20 | 21 | private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class); |
| 21 | 22 | private final StringMessages stringMessages; |
| 22 | 23 | |
| ... | ... | @@ -48,11 +49,12 @@ public class RaceLogTrackingEventManagementImagesBarCell extends ImagesBarCell { |
| 48 | 49 | makeImagePrototype(resources.inviteBuoyTenders()))); |
| 49 | 50 | result.add(new ImageSpec(ACTION_SHOW_REGATTA_LOG, stringMessages.regattaLog(), |
| 50 | 51 | makeImagePrototype(resources.flagIcon()))); |
| 52 | + result.add(new ImageSpec(ACTION_REVOKE_EXPLICIT_TRACKING_TIMES, stringMessages.revokeExplicitTrackingTimes(), |
|
| 53 | + makeImagePrototype(resources.eraser()))); |
|
| 51 | 54 | result.add(new ImageSpec(DefaultActions.CHANGE_OWNERSHIP.name(), stringMessages.actionChangeOwnership(), |
| 52 | 55 | IconResources.INSTANCE.changeOwnershipIcon())); |
| 53 | 56 | result.add(new ImageSpec(DefaultActions.CHANGE_ACL.name(), stringMessages.actionChangeACL(), |
| 54 | 57 | IconResources.INSTANCE.changeACLIcon())); |
| 55 | - |
|
| 56 | 58 | return result; |
| 57 | 59 | } |
| 58 | 60 | } |
| ... | ... | \ No newline at end of file |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java
| ... | ... | @@ -208,6 +208,8 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC |
| 208 | 208 | DefaultActions.UPDATE, t -> openChooseEventDialogAndSendMails(t.getName())); |
| 209 | 209 | leaderboardActionColumn.addAction(RaceLogTrackingEventManagementImagesBarCell.ACTION_SHOW_REGATTA_LOG, |
| 210 | 210 | DefaultActions.UPDATE, t -> showRegattaLog()); |
| 211 | + leaderboardActionColumn.addAction(RaceLogTrackingEventManagementImagesBarCell.ACTION_REVOKE_EXPLICIT_TRACKING_TIMES, |
|
| 212 | + DefaultActions.UPDATE, t -> revokeExplicitTrackingTimes()); |
|
| 211 | 213 | leaderboardActionColumn.addAction(DefaultActionsImagesBarCell.ACTION_CHANGE_OWNERSHIP, DefaultActions.UPDATE, |
| 212 | 214 | configOwnership::openOwnershipDialog); |
| 213 | 215 | leaderboardActionColumn.addAction(DefaultActionsImagesBarCell.ACTION_CHANGE_ACL, DefaultActions.UPDATE, |
| ... | ... | @@ -223,6 +225,23 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC |
| 223 | 225 | selectionCheckboxColumn.getSelectionManager()); |
| 224 | 226 | } |
| 225 | 227 | |
| 228 | + private void revokeExplicitTrackingTimes() { |
|
| 229 | + if (Window.confirm(stringMessages.confirmRevokeExplicitTrackingTimes(getSelectedLeaderboard().getName()))) { |
|
| 230 | + sailingServiceWrite.revokeExplicitTrackingTimes(getSelectedLeaderboard().getName(), new AsyncCallback<Void>() { |
|
| 231 | + @Override |
|
| 232 | + public void onFailure(Throwable caught) { |
|
| 233 | + errorReporter.reportError(stringMessages.errorRevokingExplicitTrackingTimes(getSelectedLeaderboard().getName(), caught.getMessage())); |
|
| 234 | + } |
|
| 235 | + |
|
| 236 | + @Override |
|
| 237 | + public void onSuccess(Void result) { |
|
| 238 | + Notification.notify(stringMessages.successfullyREvokedExplicitTrackingTimes(getSelectedLeaderboard().getName()), NotificationType.SUCCESS); |
|
| 239 | + loadAndRefreshLeaderboard(getSelectedLeaderboard().getName()); |
|
| 240 | + } |
|
| 241 | + }); |
|
| 242 | + } |
|
| 243 | + } |
|
| 244 | + |
|
| 226 | 245 | private RaceLogTrackingState getTrackingState( |
| 227 | 246 | RaceColumnDTOAndFleetDTOWithNameBasedEquality race) { |
| 228 | 247 | return race.getA().getRaceLogTrackingInfo(race.getB()).raceLogTrackingState; |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceWrite.java
| ... | ... | @@ -762,4 +762,6 @@ public interface SailingServiceWrite extends FileStorageManagementGwtService, Sa |
| 762 | 762 | |
| 763 | 763 | void copyPairingListFromOtherLeaderboard(String sourceLeaderboardName, String targetLeaderboardName, String fromRaceColumnName, |
| 764 | 764 | String toRaceColumnInclusiveName) throws UnauthorizedException, NotFoundException; |
| 765 | + |
|
| 766 | + void revokeExplicitTrackingTimes(String leaderboardName) throws NotFoundException; |
|
| 765 | 767 | } |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceWriteAsync.java
| ... | ... | @@ -13,6 +13,7 @@ import org.apache.shiro.authz.UnauthorizedException; |
| 13 | 13 | import com.google.gwt.user.client.rpc.AsyncCallback; |
| 14 | 14 | import com.sap.sailing.domain.base.Fleet; |
| 15 | 15 | import com.sap.sailing.domain.base.RaceColumn; |
| 16 | +import com.sap.sailing.domain.base.Regatta; |
|
| 16 | 17 | import com.sap.sailing.domain.common.CompetitorDescriptor; |
| 17 | 18 | import com.sap.sailing.domain.common.CompetitorRegistrationType; |
| 18 | 19 | import com.sap.sailing.domain.common.DataImportProgress; |
| ... | ... | @@ -41,6 +42,7 @@ import com.sap.sailing.domain.common.orc.ORCCertificate; |
| 41 | 42 | import com.sap.sailing.domain.common.orc.impl.ORCPerformanceCurveLegImpl; |
| 42 | 43 | import com.sap.sailing.domain.common.security.SecuredDomainType; |
| 43 | 44 | import com.sap.sailing.domain.common.security.SecuredDomainType.EventActions; |
| 45 | +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; |
|
| 44 | 46 | import com.sap.sailing.expeditionconnector.ExpeditionDeviceConfiguration; |
| 45 | 47 | import com.sap.sailing.gwt.ui.adminconsole.RaceLogSetTrackingTimesDTO; |
| 46 | 48 | import com.sap.sailing.gwt.ui.adminconsole.RemoteSailingServerEventsSelectionDialog; |
| ... | ... | @@ -776,4 +778,18 @@ public interface SailingServiceWriteAsync extends FileStorageManagementGwtServic |
| 776 | 778 | |
| 777 | 779 | void copyPairingListFromOtherLeaderboard(String sourceLeaderboardName, String targetLeaderboardName, String fromRaceColumnName, |
| 778 | 780 | String toRaceColumnInclusiveName, AsyncCallback<Void> asyncCallback); |
| 781 | + |
|
| 782 | + /** |
|
| 783 | + * For the leaderboard identified by {@code leaderboardName}, revokes the explicit tracking times for all its |
|
| 784 | + * {@link RaceColumn}/{@link Fleet} combinations where the race log of that slot has a valid race start time and |
|
| 785 | + * valid finishing/finished times ("blue flag") in the Race Log. Multiple revocation events may be required because |
|
| 786 | + * due to priorities and time order, some tracking time events may "shadow" other such events that become valid |
|
| 787 | + * after revoking the one currently valid. The process continues until no more valid start/end tracking events exist |
|
| 788 | + * in that race log. |
|
| 789 | + * <p> |
|
| 790 | + * |
|
| 791 | + * Precondition: The leaderboard must be a {@link RegattaLeaderboard}, and the corresponding regatta must be in more |
|
| 792 | + * {@link Regatta#isControlTrackingFromStartAndFinishTimes()} |
|
| 793 | + */ |
|
| 794 | + void revokeExplicitTrackingTimes(String leaderboardName, AsyncCallback<Void> asyncCallback); |
|
| 779 | 795 | } |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
| ... | ... | @@ -2555,4 +2555,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, |
| 2555 | 2555 | String ipsLockedForUserCreationAbuse(); |
| 2556 | 2556 | String unableToLoadIpsBlockedForUserCreationAbuse(); |
| 2557 | 2557 | String sourceCode(); |
| 2558 | + String revokeExplicitTrackingTimes(); |
|
| 2559 | + String confirmRevokeExplicitTrackingTimes(String leaderboardName); |
|
| 2560 | + String errorRevokingExplicitTrackingTimes(String leaderboardName, String message); |
|
| 2561 | + String successfullyREvokedExplicitTrackingTimes(String leaderboardName); |
|
| 2558 | 2562 | } |
| ... | ... | \ No newline at end of file |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
| ... | ... | @@ -2591,3 +2591,7 @@ unlock=Unlock |
| 2591 | 2591 | ipsLockedForUserCreationAbuse=IPs Locked for User Creation Abuse |
| 2592 | 2592 | unableToLoadIpsBlockedForUserCreationAbuse=Unable to load IPs Blocked for User Creation Abuse |
| 2593 | 2593 | sourceCode=Source Code |
| 2594 | +revokeExplicitTrackingTimes=Revoke explicit tracking times for races with valid start and finishing times |
|
| 2595 | +confirmRevokeExplicitTrackingTimes=Really revoke explicit tracking times for all races of leaderboard {0} that have valid start and finishing times? |
|
| 2596 | +errorRevokingExplicitTrackingTimes=Error revoking explicit tracking times for leaderboard {0}: {1} |
|
| 2597 | +successfullyREvokedExplicitTrackingTimes=Successfully revoked explicit tracking times for leaderboard {0} |
|
| ... | ... | \ No newline at end of file |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
| ... | ... | @@ -2585,3 +2585,7 @@ unlock=Entsperren |
| 2585 | 2585 | ipsLockedForUserCreationAbuse=Wegen Missbrauchs bei der Benutzererstellung gesperrte IPs |
| 2586 | 2586 | unableToLoadIpsBlockedForUserCreationAbuse=Wegen Missbrauchs der Benutzererstellung blockierte IPs können nicht geladen werden |
| 2587 | 2587 | sourceCode=Quellcode |
| 2588 | +revokeExplicitTrackingTimes=Explizite Tracking-Zeiten zurücksetzen für Rennen mit gültigen Start- und Endzeitpunkten |
|
| 2589 | +confirmRevokeExplicitTrackingTimes=Wirklich explizite Tracking-Zeiten zurücksetzen für Rennen mit gültigen Start- und Endzeitpunkten der Rangliste {0}? |
|
| 2590 | +errorRevokingExplicitTrackingTimes=Fehler beim Zurücksetzen expliziter Tracking-Zeiten für Rennen mit gültigen Start- und Endzeitpunkten der Rangliste {0}: {1} |
|
| 2591 | +successfullyREvokedExplicitTrackingTimes=Explizite Tracking-Zeiten erfolgreich zurückgesetzt für Rangliste {0} |
|
| ... | ... | \ No newline at end of file |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceWriteImpl.java
| ... | ... | @@ -4195,4 +4195,24 @@ public class SailingServiceWriteImpl extends SailingServiceImpl implements Saili |
| 4195 | 4195 | getRaceLogTrackingAdapter().copyPairingListFromOtherLeaderboard((RegattaLeaderboard) sourceLeaderboard, |
| 4196 | 4196 | (RegattaLeaderboard) targetLeaderboard, fromRaceColumnName, toRaceColumnInclusiveName); |
| 4197 | 4197 | } |
| 4198 | + |
|
| 4199 | + @Override |
|
| 4200 | + public void revokeExplicitTrackingTimes(String leaderboardName) throws NotFoundException { |
|
| 4201 | + final Leaderboard leaderboard = getLeaderboardByName(leaderboardName); |
|
| 4202 | + getService().getSecurityService().checkCurrentUserUpdatePermission(leaderboard); |
|
| 4203 | + if (leaderboard instanceof RegattaLeaderboard) { |
|
| 4204 | + final Regatta regatta = ((RegattaLeaderboard) leaderboard).getRegatta(); |
|
| 4205 | + if (regatta.isControlTrackingFromStartAndFinishTimes()) { |
|
| 4206 | + getRaceLogTrackingAdapter().revokeExplicitTrackingTimes((RegattaLeaderboard) leaderboard, /* raceLogResolver */ getService()); |
|
| 4207 | + } else { |
|
| 4208 | + throw new IllegalStateException("Leaderboard " + leaderboardName |
|
| 4209 | + + " is not configured to control tracking from start and finish times, so explicit tracking times should not exist and thus cannot be revoked."); |
|
| 4210 | + } |
|
| 4211 | + } else { |
|
| 4212 | + throw new IllegalArgumentException("Leaderboard " + leaderboardName |
|
| 4213 | + + " must be a regatta leaderboard, but was: " + leaderboard.getLeaderboardType()); |
|
| 4214 | + } |
|
| 4215 | + // TODO Auto-generated method stub |
|
| 4216 | + |
|
| 4217 | + } |
|
| 4198 | 4218 | } |
java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/eraser-icon.png
| ... | ... | Binary files /dev/null and b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/eraser-icon.png differ |