Merge branch 'bug2842'

Change-Id: I169cca2e4dfa1b65a6237ab499f4bfa21dbf15c7
This commit is contained in:
Axel Uhl
2019-10-23 14:47:14 +02:00
31 changed files with 399 additions and 112 deletions
@@ -1,5 +1,6 @@
package com.sap.sailing.domain.common.dto;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.security.SecuredDomainType;
@@ -38,18 +39,25 @@ public class RaceDTO extends BasicRaceDTO implements SecuredDTO {
private String regattaName;
public String boatClass;
private RankingMetrics rankingMetricType;
public RaceDTO() {}
public RaceDTO(RegattaAndRaceIdentifier raceIdentifier, TrackedRaceDTO trackedRace, boolean isCurrentlyTracked) {
public RaceDTO(RegattaAndRaceIdentifier raceIdentifier, TrackedRaceDTO trackedRace, boolean isCurrentlyTracked, RankingMetrics rankingMetricType) {
super(raceIdentifier, trackedRace);
this.regattaName = raceIdentifier.getRegattaName();
this.isTracked = isCurrentlyTracked;
this.rankingMetricType = rankingMetricType;
}
public RegattaAndRaceIdentifier getRaceIdentifier() {
return new RegattaNameAndRaceName(regattaName, getName());
}
public RankingMetrics getRankingMetricType() {
return rankingMetricType;
}
public String getRegattaName() {
return regattaName;
}
@@ -0,0 +1,41 @@
package com.sap.sailing.domain.abstractlog.orc;
import java.io.Serializable;
import java.util.function.Function;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sse.common.Util.Pair;
public class RaceLogORCScratchBoatAnalyzer extends BaseLogAnalyzer<RaceLog, RaceLogEvent, RaceLogEventVisitor, Pair<Competitor, RaceLogORCScratchBoatEvent>> {
private static final Logger logger = Logger.getLogger(RaceLogORCScratchBoatAnalyzer.class.getName());
private final Function<Serializable, Competitor> competitorsById;
public RaceLogORCScratchBoatAnalyzer(RaceLog log, Function<Serializable, Competitor> competitorsById) {
super(log);
this.competitorsById = competitorsById;
}
@Override
protected Pair<Competitor, RaceLogORCScratchBoatEvent> performAnalysis() {
for (final RaceLogEvent o : getLog().getUnrevokedEventsDescending()) {
if (o instanceof RaceLogORCScratchBoatEvent) {
RaceLogORCScratchBoatEvent event = (RaceLogORCScratchBoatEvent) o;
final Serializable competitorId = event.getCompetitorId();
final Competitor competitor = competitorsById.apply(competitorId);
if (competitor != null) {
return new Pair<>(competitor, event);
} else {
logger.warning("Unable to find competitor with ID " + competitorId
+ " as an ORC Performance Curve scratch boat. Race log event is ignored.");
}
}
}
return null;
}
}
@@ -1,40 +1,27 @@
package com.sap.sailing.domain.abstractlog.orc;
import java.io.Serializable;
import java.util.Map;
import java.util.logging.Logger;
import java.util.function.Function;
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sse.common.Util.Pair;
public class RaceLogORCScratchBoatFinder extends BaseLogAnalyzer<RaceLog, RaceLogEvent, RaceLogEventVisitor, Competitor> {
private static final Logger logger = Logger.getLogger(RaceLogORCScratchBoatFinder.class.getName());
private final Map<Serializable, Competitor> competitorsById;
private final Function<Serializable, Competitor> competitorsById;
public RaceLogORCScratchBoatFinder(RaceLog log, Map<Serializable, Competitor> competitorsById) {
public RaceLogORCScratchBoatFinder(RaceLog log, Function<Serializable, Competitor> competitorsById) {
super(log);
this.competitorsById = competitorsById;
}
@Override
protected Competitor performAnalysis() {
for (final RaceLogEvent o : getLog().getUnrevokedEventsDescending()) {
if (o instanceof RaceLogORCScratchBoatEvent) {
RaceLogORCScratchBoatEvent event = (RaceLogORCScratchBoatEvent) o;
final Serializable competitorId = event.getCompetitorId();
final Competitor competitor = competitorsById.get(competitorId);
if (competitor != null) {
return competitor;
} else {
logger.warning("Unable to find competitor with ID " + competitorId
+ " as an ORC Performance Curve scratch boat. Race log event is ignored.");
}
}
}
return null;
final Pair<Competitor, RaceLogORCScratchBoatEvent> preResult = new RaceLogORCScratchBoatAnalyzer(getLog(), competitorsById).analyze();
return preResult == null ? null : preResult.getA();
}
}
@@ -197,7 +197,7 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain
PlacemarkOrderDTO racePlaces = withGeoLocationData ? getRacePlaces(trackedRace) : null;
TrackedRaceDTO trackedRaceDTO = createTrackedRaceDTO(trackedRace);
RaceDTO raceDTO = new RaceDTO(raceIdentifier, trackedRaceDTO, trackedRegattaRegistry.isRaceBeingTracked(
trackedRace.getTrackedRegatta().getRegatta(), trackedRace.getRace()));
trackedRace.getTrackedRegatta().getRegatta(), trackedRace.getRace()), trackedRace.getRankingMetric()==null?null:trackedRace.getRankingMetric().getType());
raceDTO.places = racePlaces;
updateRaceDTOWithTrackedRaceData(trackedRace, raceDTO);
return raceDTO;
@@ -41,6 +41,7 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.common.orc.ORCCertificate;
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveCourse;
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveLeg;
@@ -115,6 +116,11 @@ public class ORCPerformanceCurveByImpliedWindRankingMetric extends AbstractRanki
updateCourseFromRaceLogs();
}
@Override
public RankingMetrics getType() {
return RankingMetrics.ORC_PERFORMANCE_CURVE_BY_IMPLIED_WIND;
}
private void initializeListeners() {
certificatesAndCourseAndScratchBoatFromRaceLogUpdater = createCertificatesFromRaceLogAndCourseAndScratchBoatUpdater();
certificatesFromRegattaLogUpdater = createCertificatesFromRegattaLogUpdater();
@@ -245,7 +251,7 @@ public class ORCPerformanceCurveByImpliedWindRankingMetric extends AbstractRanki
private void updateScratchBoatFromLogs() {
Competitor scratchBoatFromLog = null;
for (final RaceLog raceLog : getTrackedRace().getAttachedRaceLogs()) {
scratchBoatFromLog = new RaceLogORCScratchBoatFinder(raceLog, competitorsById).analyze();
scratchBoatFromLog = new RaceLogORCScratchBoatFinder(raceLog, competitorId->competitorsById.get(competitorId)).analyze();
if (scratchBoatFromLog != null) {
break;
}
@@ -13,6 +13,7 @@ import java.util.logging.Logger;
import org.apache.commons.math.FunctionEvaluationException;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.orc.ORCPerformanceCurve;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
@@ -39,6 +40,11 @@ public class ORCPerformanceCurveRankingMetric extends ORCPerformanceCurveByImpli
super(trackedRace);
}
@Override
public RankingMetrics getType() {
return RankingMetrics.ORC_PERFORMANCE_CURVE;
}
/**
* As opposed to before 2015 when implied wind was the only ranking criterion at all times, in 2015
* it was decided to rank based on corrected times, and corrected times shall be computed not by mapping
@@ -5,6 +5,7 @@ import java.util.HashSet;
import java.util.Set;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingAndORCPerformanceCurveCache;
import com.sap.sse.common.TimePoint;
@@ -29,6 +30,11 @@ public class ORCPerformanceCurveRankingMetricLeaderForBaseline extends ORCPerfor
super(trackedRace);
}
@Override
public RankingMetrics getType() {
return RankingMetrics.ORC_PERFORMANCE_CURVE_LEADER_FOR_BASELINE;
}
@Override
protected Competitor getBaseLineCompetitorForAbsoluteCorrectedTimes(TimePoint timePoint,
WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) {
@@ -8,6 +8,7 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
@@ -27,6 +28,11 @@ public class OneDesignRankingMetric extends NonPerformanceCurveRankingMetric {
super(trackedRace);
}
@Override
public RankingMetrics getType() {
return RankingMetrics.ONE_DESIGN;
}
@Override
public Comparator<Competitor> getRaceRankingComparator(TimePoint timePoint, WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) {
return new RaceRankComparator(getTrackedRace(), timePoint, cache);
@@ -6,6 +6,7 @@ import java.util.function.Function;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuseCache;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
@@ -141,6 +142,8 @@ public interface RankingMetric extends Serializable {
* @return the tracked race to which this ranking metric is specific
*/
TrackedRace getTrackedRace();
RankingMetrics getType();
default Comparator<Competitor> getRaceRankingComparator(TimePoint timePoint) {
return getRaceRankingComparator(timePoint, new LeaderboardDTOCalculationReuseCache(timePoint));
@@ -11,6 +11,7 @@ import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.Mile;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
@@ -76,6 +77,11 @@ public class TimeOnTimeAndDistanceRankingMetric extends NonPerformanceCurveRanki
this.timeOnDistanceFactorNauticalMile = timeOnDistanceFactorInSecondsPerNauticalMile;
}
@Override
public RankingMetrics getType() {
return RankingMetrics.TIME_ON_TIME_AND_DISTANCE;
}
/**
* Ranks the competitors by their average corrected velocity made good, determined by the following formula:
*
@@ -8,6 +8,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
@@ -30,6 +31,8 @@ import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.dto.BoatDTO;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.domain.common.dto.FleetDTO;
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
import com.sap.sailing.domain.common.dto.RaceDTO;
@@ -815,4 +818,61 @@ public abstract class AbstractLeaderboardConfigPanel extends FormPanel
stringMessages, errorReporter, new RaceBoatCertificatesPanel(sailingService, userService, object.getC(), object.getA(), object.getB(), stringMessages, errorReporter));
dialog.show();
}
protected void selectScratchBoat(RaceColumnDTOAndFleetDTOWithNameBasedEquality object) {
sailingService.getORCPerformanceCurveScratchBoat(object.getC().getName(), object.getA().getName(), object.getB().getName(), new AsyncCallback<CompetitorDTO>() {
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError(stringMessages.errorObtainingScratchBoat(caught.getMessage()), /* silent */ true);
}
@Override
public void onSuccess(CompetitorDTO scratchBoatSoFar) {
new CompetitorSelectionDialog(sailingService, userService, errorReporter,
stringMessages.selectScratchBoat(), stringMessages.selectScratchBoat(), getRaceCompetitorProvider(object), stringMessages, scratchBoatSoFar,
new DialogCallback<CompetitorDTO>() {
@Override
public void ok(CompetitorDTO newScratchBoat) {
sailingService.setORCPerformanceCurveScratchBoat(object.getC().getName(), object.getA().getName(), object.getB().getName(),
newScratchBoat, new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError(stringMessages.errorSettingScratchBoat(caught.getMessage()), /* silent */ true);
}
@Override
public void onSuccess(Void result) {
Notification.notify(stringMessages.scratchBoatSetSuccessfully(), NotificationType.SUCCESS);
}
});
}
@Override
public void cancel() {}
}).show();
}
});
}
/**
* Helps in obtaining competitors for a specific "race slot" identified by leaderboard name, race column name and
* fleet name. In particular, the implementation is expected to return a consumer that when called with a callback
* fetches the competitors for the particular race identified by {@code raceSlotIdentifier} and sends them to the
* callback's {@link AsyncCallback#onSuccess(Object)} method.
*/
protected Consumer<AsyncCallback<Iterable<? extends CompetitorDTO>>> getRaceCompetitorProvider(
RaceColumnDTOAndFleetDTOWithNameBasedEquality raceSlotIdentifier) {
return callback -> sailingService.getCompetitorsAndBoatsOfRace(raceSlotIdentifier.getC().getName(),
raceSlotIdentifier.getA().getName(), raceSlotIdentifier.getB().getName(), new AsyncCallback<Map<? extends CompetitorDTO, BoatDTO>>() {
@Override
public void onFailure(Throwable e) {
callback.onFailure(e);
}
@Override
public void onSuccess(Map<? extends CompetitorDTO, BoatDTO> competitorToBoatMap) {
callback.onSuccess(competitorToBoatMap.keySet());
}
});
}
}
@@ -130,4 +130,7 @@ interface AdminConsoleResources extends ClientBundle {
@Source("com/sap/sailing/gwt/ui/client/images/certificates.png")
ImageResource updateCertificatesIcon();
@Source("com/sap/sailing/gwt/ui/client/images/scratchBoat.png")
ImageResource scratchBoatIcon();
}
@@ -0,0 +1,71 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.function.Consumer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
import com.sap.sse.security.ui.client.UserService;
/**
* A dialog that can be used to select a single competitor. The dialog can be customized with a title and message. If a
* competitor is specified as the object to select initially and that object is contained in the result of fetching the
* competitors, it is selected in the table.
* <p>
*
* For fetching the competitors, a {@link Consumer} of an {@link AsyncCallback} must be provided. It is expected that
* this consumer "consumes" the callback by obtaining a list of competitors, possibly asynchronously, and sending the
* result to the callback's {@link AsyncCallback#onSuccess(Object)} method.<p>
*
* The dialog's result is the {@link CompetitorDTO} selected when the dialog is confirmed using the OK button. When
* no selection currently exists, {@code null} will result.
*
* @author Axel Uhl (D043530)
*
*/
public class CompetitorSelectionDialog extends DataEntryDialog<CompetitorDTO> {
private final CompetitorTableWrapper<RefreshableSingleSelectionModel<CompetitorDTO>> competitorTable;
public CompetitorSelectionDialog(SailingServiceAsync sailingService, UserService userService,
ErrorReporter errorReporter, String title, String message,
Consumer<AsyncCallback<Iterable<? extends CompetitorDTO>>> competitorProvider, StringMessages stringMessages,
CompetitorDTO initialSelection,
DialogCallback<CompetitorDTO> callback) {
super(title, message, stringMessages.ok(), stringMessages.cancel(), /* validator */ null, callback);
competitorTable = new CompetitorTableWrapper<>(sailingService, userService, stringMessages, errorReporter,
/* multiSelection */ false, /* enablePager */ true, /* filter with boat */ false,
/* filter without boat */ false);
competitorProvider.accept(new AsyncCallback<Iterable<? extends CompetitorDTO>>() {
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError(stringMessages.errorLoadingCompetitors(caught.getMessage()), /* silentMode */ true);
}
@Override
public void onSuccess(Iterable<? extends CompetitorDTO> result) {
competitorTable.refreshCompetitorList(result);
if (initialSelection != null) {
competitorTable.getSelectionModel().setSelected(initialSelection, /* selected */ true);
}
}
});
}
@Override
protected Widget getAdditionalWidget() {
final VerticalPanel result = new VerticalPanel();
result.add(competitorTable);
return result;
}
@Override
protected CompetitorDTO getResult() {
return competitorTable.getSelectionModel().getSelectedObject();
}
}
@@ -70,6 +70,18 @@ public class CompetitorTableWrapper<S extends RefreshableSelectionModel<Competit
private final boolean filterCompetitorsWithBoat;
private final boolean filterCompetitorsWithoutBoat;
/**
* @param filterCompetitorsWithBoat
* relevant if {@link #refreshCompetitorList(String)} or {@link #refreshCompetitorList(String, Callback)}
* will be called using {@code null} for the leaderboard name, hence requesting <em>all</em> competitors
* to be loaded. In this case, competitors with boat will be fetched only if this flag is
* {@code false}.
* @param filterCompetitorsWithoutBoat
* relevant if {@link #refreshCompetitorList(String)} or {@link #refreshCompetitorList(String, Callback)}
* will be called using {@code null} for the leaderboard name, hence requesting <em>all</em> competitors
* to be loaded. In this case, competitors without boat will be fetched only if this flag is
* {@code false}.
*/
public CompetitorTableWrapper(SailingServiceAsync sailingService, UserService userService, StringMessages stringMessages, ErrorReporter errorReporter,
boolean multiSelection, boolean enablePager, boolean filterCompetitorsWithBoat, boolean filterCompetitorsWithoutBoat) {
super(sailingService, stringMessages, errorReporter, multiSelection, enablePager,
@@ -366,7 +378,7 @@ public class CompetitorTableWrapper<S extends RefreshableSelectionModel<Competit
return filterField;
}
public void refreshCompetitorList(Iterable<CompetitorDTO> competitors) {
public void refreshCompetitorList(Iterable<? extends CompetitorDTO> competitors) {
getFilteredCompetitors(competitors);
}
@@ -375,10 +387,13 @@ public class CompetitorTableWrapper<S extends RefreshableSelectionModel<Competit
}
/**
* @param leaderboardName If null, all existing competitors are loaded
* @param leaderboardName
* If {@code null}, all existing competitors are loaded.
* @param callback
* if not {@code null}, its {@code AsyncCallback#onSuccess(Object)} method will be called after
* successfully refreshing the competitors
*/
public void refreshCompetitorList(String leaderboardName, final Callback<Iterable<CompetitorDTO>,
Throwable> callback) {
public void refreshCompetitorList(String leaderboardName, final Callback<Iterable<CompetitorDTO>, Throwable> callback) {
final AsyncCallback<Iterable<CompetitorDTO>> myCallback = new AsyncCallback<Iterable<CompetitorDTO>>() {
@Override
public void onFailure(Throwable caught) {
@@ -404,7 +419,7 @@ public class CompetitorTableWrapper<S extends RefreshableSelectionModel<Competit
}
}
private void getFilteredCompetitors(Iterable<CompetitorDTO> result) {
private void getFilteredCompetitors(Iterable<? extends CompetitorDTO> result) {
filterField.updateAll(result);
}
@@ -7,6 +7,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Supplier;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -124,8 +125,14 @@ public abstract class CourseManagementWidget implements IsWidget {
return mainPanel;
}
/**
* @param showOrcPcsLegEditActions
* Depending on the ranking metric it may or may not make sense to show the user the actions to maintain
* ORC PCS leg data. By default, these actions are enabled, particularly to cover the case where this
* widget is used without an existing {@code TrackedRace} and only with a race log.
*/
public CourseManagementWidget(final SailingServiceAsync sailingService, ErrorReporter errorReporter,
final StringMessages stringMessages, final UserService userService) {
final StringMessages stringMessages, final UserService userService, final Supplier<Boolean> showOrcPcsLegEditActions) {
this.sailingService = sailingService;
this.errorReporter = errorReporter;
this.stringMessages = stringMessages;
@@ -162,7 +169,7 @@ public abstract class CourseManagementWidget implements IsWidget {
mainPanel.setWidget(1, 1, controlPointsBtnsPanel);
mainPanel.setWidget(1, 2, marksBtnsPanel);
final AccessControlledActionsColumn<WaypointDTO, WaypointImagesBarCell> waypointsActionColumn = create(
new WaypointImagesBarCell(stringMessages, waypoints.getDataProvider()), userService,
new WaypointImagesBarCell(stringMessages, waypoints.getDataProvider(), showOrcPcsLegEditActions), userService,
s -> securedDtoForWaypointsPermissionCheck);
// update permission for tracked race is required for deleting waypoints...
waypointsActionColumn.addAction(DefaultActions.DELETE.name(), DefaultActions.UPDATE,
@@ -405,7 +412,7 @@ public abstract class CourseManagementWidget implements IsWidget {
}).show();
}
public void refresh(){};
public abstract void refresh();
protected void updateWaypointsAndControlPoints(RaceCourseDTO raceCourseDTO, String leaderboardName) {
this.sailingService.getLeaderboardWithSecurity(leaderboardName,
@@ -431,7 +438,6 @@ public abstract class CourseManagementWidget implements IsWidget {
waypoints.getDataProvider().getList().clear();
multiMarkControlPoints.getDataProvider().getList().clear();
waypoints.getDataProvider().getList().addAll(raceCourseDTO.waypoints);
Map<String, ControlPointDTO> noDuplicateCPs = new HashMap<>();
for (ControlPointDTO controlPoint : raceCourseDTO.getControlPoints()) {
if (controlPoint instanceof GateDTO) {
@@ -439,9 +445,7 @@ public abstract class CourseManagementWidget implements IsWidget {
}
}
multiMarkControlPoints.getDataProvider().getList().addAll(noDuplicateCPs.values());
updateWaypointButtons();
final boolean hasUpdatePermission = userService.hasPermission(securedDTO, DefaultActions.UPDATE);
insertWaypointAfter.setVisible(hasUpdatePermission);
insertWaypointBefore.setVisible(hasUpdatePermission);
@@ -10,11 +10,6 @@ import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
import com.sap.sse.security.ui.client.UserService;
/**
*
* @author Daniel Lisunkin (i505543)
*
*/
public class EditCompetitorsDialog extends DataEntryDialog<List<CompetitorWithBoatDTO>> {
private final SailingServiceAsync sailingService;
private final UserService userService;
@@ -51,7 +46,6 @@ public class EditCompetitorsDialog extends DataEntryDialog<List<CompetitorWithBo
@Override
protected Widget getAdditionalWidget() {
CompetitorPanel competitorPanel = new CompetitorPanel(sailingService, userService, leaderboardName, stringMessages, errorReporter);
return competitorPanel;
}
}
@@ -2,11 +2,12 @@ package com.sap.sailing.gwt.ui.adminconsole;
import static com.sap.sailing.domain.common.security.SecuredDomainType.LEADERBOARD;
import static com.sap.sailing.domain.common.security.SecuredDomainType.REGATTA;
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_CERTIFICATE_ASSIGNMENT;
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_EDIT;
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS;
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_CERTIFICATE_ASSIGNMENT;
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_REFRESH_RACELOG;
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_REMOVE;
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_SCRATCH_BOAT_SELECTION;
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_SET_FINISHING_AND_FINISH_TIME;
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_SET_STARTTIME;
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_SHOW_RACELOG;
@@ -540,8 +541,8 @@ public class LeaderboardConfigPanel extends AbstractLeaderboardConfigPanel
actionsColumn.addAction(ACTION_SHOW_RACELOG, UPDATE, object -> showRaceLog(object.getA(), object.getB()));
actionsColumn.addAction(ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS, UPDATE,
object -> editCompetitorToBoatMappings(object.getA(), object.getB()));
actionsColumn.addAction(ACTION_CERTIFICATE_ASSIGNMENT, READ,
object -> assignCertificates(object));
actionsColumn.addAction(ACTION_CERTIFICATE_ASSIGNMENT, READ, object -> assignCertificates(object));
actionsColumn.addAction(ACTION_SCRATCH_BOAT_SELECTION, READ, object -> selectScratchBoat(object));
racesTable.addColumn(isMedalRaceCheckboxColumn, stringMessages.medalRace());
racesTable.addColumn(isLinkedRaceColumn, stringMessages.islinked());
racesTable.addColumn(explicitFactorColumn, stringMessages.factor());
@@ -20,6 +20,7 @@ public class LeaderboardRaceConfigImagesBarCell extends ImagesBarCell {
public final static String ACTION_SHOW_RACELOG = "ACTION_SHOW_RACELOG";
public final static String ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS = "ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS";
public final static String ACTION_CERTIFICATE_ASSIGNMENT = "ACTION_CERTIFICATE_ASSIGNMENT";
public final static String ACTION_SCRATCH_BOAT_SELECTION = "ACTION_SCRATCH_BOAT_SELECTION";
private final StringMessages stringMessages;
private final SelectedLeaderboardProvider<? extends StrippedLeaderboardDTO> selectedLeaderboardProvider;
@@ -53,6 +54,7 @@ public class LeaderboardRaceConfigImagesBarCell extends ImagesBarCell {
}
if (raceHasORCRankingMetric(object)) {
result.add(new ImageSpec(ACTION_CERTIFICATE_ASSIGNMENT, stringMessages.assignCertificates(), resources.updateCertificatesIcon()));
result.add(new ImageSpec(ACTION_SCRATCH_BOAT_SELECTION, stringMessages.selectScratchBoat(), resources.scratchBoatIcon()));
}
return result;
}
@@ -9,6 +9,7 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.common.orc.impl.ORCPerformanceCurveLegImpl;
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
@@ -35,7 +36,7 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
RegattaRefresher regattaRefresher, final StringMessages stringMessages, final UserService userService) {
super(sailingService, userService, errorReporter, regattaRefresher, /* actionButtonsEnabled */ false, stringMessages);
courseManagementWidget = new CourseManagementWidget(sailingService, errorReporter, stringMessages,
userService) {
userService, ()->selectedRaceHasOrcPcsRankingMetric()) {
@Override
protected void save() {
sailingService.updateRaceCourse(singleSelectedRace, createWaypointPairs(), new AsyncCallback<Void>() {
@@ -94,18 +95,20 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
}
private void refreshORCPerformanceCurveLegs() {
sailingService.getORCPerformanceCurveLegInfo(singleSelectedRace,
new AsyncCallback<Map<Integer, ORCPerformanceCurveLegImpl>>() {
@Override
public void onSuccess(Map<Integer, ORCPerformanceCurveLegImpl> result) {
refreshORCPerformanceCurveLegs(result);
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Could not load ORC Performance Curve leg information: " + caught.getMessage());
}
});
if (singleSelectedRace != null) {
sailingService.getORCPerformanceCurveLegInfo(singleSelectedRace,
new AsyncCallback<Map<Integer, ORCPerformanceCurveLegImpl>>() {
@Override
public void onSuccess(Map<Integer, ORCPerformanceCurveLegImpl> result) {
refreshORCPerformanceCurveLegs(result);
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Could not load ORC Performance Curve leg information: " + caught.getMessage());
}
});
}
}
};
FlowPanel courseManagementPanel = new FlowPanel();
@@ -134,6 +137,13 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
this.selectedRaceContentPanel.add(buttonsPanel);
}
private boolean selectedRaceHasOrcPcsRankingMetric() {
final RankingMetrics rankingMetricType = selectedRaceDTO == null ? null : selectedRaceDTO.getRankingMetricType();
return rankingMetricType == RankingMetrics.ORC_PERFORMANCE_CURVE ||
rankingMetricType == RankingMetrics.ORC_PERFORMANCE_CURVE_BY_IMPLIED_WIND ||
rankingMetricType == RankingMetrics.ORC_PERFORMANCE_CURVE_LEADER_FOR_BASELINE;
}
@Override
void refreshSelectedRaceData() {
courseManagementWidget.refresh();
@@ -30,7 +30,7 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget {
public RaceLogCourseManagementWidget(final SailingServiceAsync sailingService, final ErrorReporter errorReporter,
final StringMessages stringMessages, final String leaderboardName, final String raceColumnName,
final String fleetName, final UserService userService) {
super(sailingService, errorReporter, stringMessages, userService);
super(sailingService, errorReporter, stringMessages, userService, /* always show ORC OCS leg data actions */ ()->true);
this.leaderboardName = leaderboardName;
this.raceColumnName = raceColumnName;
this.fleetName = fleetName;
@@ -17,6 +17,7 @@ public class RaceLogTrackingEventManagementRaceImagesBarCell extends ImagesBarCe
public final static String ACTION_COMPETITOR_REGISTRATIONS = "ACTION_COMPETITOR_REGISTRATIONS";
public final static String ACTION_DEFINE_COURSE = "ACTION_DEFINE_COURSE";
public final static String ACTION_COPY = "ACTION_COPY";
public final static String ACTION_UNLINK = "ACTION_UNLINK";
public final static String ACTION_EDIT = "ACTION_EDIT";
public final static String ACTION_REFRESH_RACELOG = "ACTION_REFRESH_RACE_LOG";
public final static String ACTION_SET_STARTTIME = "ACTION_SET_STARTTIME";
@@ -27,6 +28,7 @@ public class RaceLogTrackingEventManagementRaceImagesBarCell extends ImagesBarCe
public final static String ACTION_START_TRACKING = "ACTION_START_TRACKING";
public final static String ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS = "ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS";
public static final String ACTION_CERTIFICATE_ASSIGNMENT = "ACTION_CERTIFICATE_ASSIGNMENT";
public static final String ACTION_SCRATCH_BOAT_SELECTION = "ACTION_SCRATCH_BOAT_SELECTION";
private final StringMessages stringMessages;
private SmartphoneTrackingEventManagementPanel smartphoneTrackingEventManagementPanel;
@@ -51,6 +53,7 @@ public class RaceLogTrackingEventManagementRaceImagesBarCell extends ImagesBarCe
result.add(new ImageSpec(ACTION_COPY, stringMessages.copyCourseAndCompetitors(), makeImagePrototype(resources.copy())));
}
result.add(new ImageSpec(ACTION_EDIT, stringMessages.actionEdit(), makeImagePrototype(IconResources.INSTANCE.editIcon())));
result.add(new ImageSpec(ACTION_UNLINK, stringMessages.actionRaceUnlink(), makeImagePrototype(resources.unlinkIcon())));
result.add(new ImageSpec(ACTION_REFRESH_RACELOG, stringMessages.refreshRaceLog(), makeImagePrototype(resources.reloadIcon())));
result.add(new ImageSpec(ACTION_SET_STARTTIME, stringMessages.setStartTime(), makeImagePrototype(resources.clockIcon())));
result.add(new ImageSpec(ACTION_SET_FINISHING_AND_FINISH_TIME, stringMessages.setFinishingAndFinishTime(), makeImagePrototype(resources.blueSmall())));
@@ -67,14 +70,21 @@ public class RaceLogTrackingEventManagementRaceImagesBarCell extends ImagesBarCe
if (smartphoneTrackingEventManagementPanel.getSelectedLeaderboard().canBoatsOfCompetitorsChangePerRace) {
result.add(new ImageSpec(ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS, stringMessages.actionShowCompetitorToBoatAssignments(), makeImagePrototype(resources.sailboatIcon())));
}
if (raceHasORCRankingMetric(object)) {
if (raceCouldHaveORCRankingMetric(object)) {
result.add(new ImageSpec(ACTION_CERTIFICATE_ASSIGNMENT, stringMessages.assignCertificates(), resources.updateCertificatesIcon()));
result.add(new ImageSpec(ACTION_SCRATCH_BOAT_SELECTION, stringMessages.selectScratchBoat(), resources.scratchBoatIcon()));
}
return result;
}
private boolean raceHasORCRankingMetric(RaceColumnDTOAndFleetDTOWithNameBasedEquality object) {
// TODO Implement RaceLogTrackingEventManagementRaceImagesBarCell.raceHasORCRankingMetric(...)
/**
* The problem with these race log-dependent ORC PCS events is this: at a later point a user could theoretically
* attach an ORC PCS race to the same race column. Corner case... For now we always allow users to make statements
* about ORC certificates at race level.
*
* @return {@code true}
*/
private boolean raceCouldHaveORCRankingMetric(RaceColumnDTOAndFleetDTOWithNameBasedEquality object) {
return true;
}
}
@@ -300,11 +300,11 @@ public class SmartphoneTrackingEventManagementPanel
DefaultActions.UPDATE, this::handleDefineCourse);
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_COPY, DefaultActions.UPDATE,
this::handleCopy);
raceActionColumn.addAction(LeaderboardRaceConfigImagesBarCell.ACTION_EDIT, DefaultActions.UPDATE,
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_EDIT, DefaultActions.UPDATE,
this::editRaceColumnOfLeaderboard);
raceActionColumn.addAction(LeaderboardRaceConfigImagesBarCell.ACTION_UNLINK, DefaultActions.UPDATE,
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_UNLINK, DefaultActions.UPDATE,
t -> unlinkRaceColumnFromTrackedRace(t.getA().getRaceColumnName(), t.getB()));
raceActionColumn.addAction(LeaderboardRaceConfigImagesBarCell.ACTION_REFRESH_RACELOG, DefaultActions.UPDATE,
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_REFRESH_RACELOG, DefaultActions.UPDATE,
t -> refreshRaceLog(t.getA(), t.getB(), true));
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_SET_STARTTIME,
DefaultActions.UPDATE, this::setStartTime);
@@ -324,6 +324,8 @@ public class SmartphoneTrackingEventManagementPanel
DefaultActions.UPDATE, this::showCompetitorToBoatMappings);
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_CERTIFICATE_ASSIGNMENT, READ,
t -> assignCertificates(t));
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_SCRATCH_BOAT_SELECTION, READ,
t -> selectScratchBoat(t));
racesTable.addColumn(raceLogTrackingStateColumn, stringMessages.raceStatusColumn());
racesTable.addColumn(trackerStateColumn, stringMessages.trackerStatus());
@@ -2,6 +2,7 @@ package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import com.google.gwt.core.client.GWT;
import com.google.gwt.view.client.ListDataProvider;
@@ -15,9 +16,12 @@ public class WaypointImagesBarCell extends DefaultActionsImagesBarCell {
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
private final StringMessages stringMessages;
private final ListDataProvider<WaypointDTO> waypointList;
private final Supplier<Boolean> showOrcPcsLegActions;
public WaypointImagesBarCell(final StringMessages stringMessages, ListDataProvider<WaypointDTO> waypointList) {
public WaypointImagesBarCell(final StringMessages stringMessages, ListDataProvider<WaypointDTO> waypointList,
Supplier<Boolean> showOrcPcsLegActions) {
super(stringMessages);
this.showOrcPcsLegActions = showOrcPcsLegActions;
this.stringMessages = stringMessages;
this.waypointList = waypointList;
}
@@ -27,10 +31,12 @@ public class WaypointImagesBarCell extends DefaultActionsImagesBarCell {
final WaypointDTO waypoint = (WaypointDTO) getContext().getKey();
final List<ImageSpec> imageSpecs = new ArrayList<>();
imageSpecs.add(getDeleteImageSpec());
if (waypoint != waypointList.getList().get(0)) {
imageSpecs.add(new ImageSpec(ACTION_ORC_PCS_DEFINE_LEG, stringMessages.actionDefineLegForOrcPcs(), resources.orcPcsDefineLegIcon()));
} else {
imageSpecs.add(new ImageSpec(ACTION_ORC_PCS_DEFINE_ALL_LEGS, stringMessages.actionDefineAllLegsForOrcPcs(), resources.orcPcsDefineAllLegsIcon()));
if (showOrcPcsLegActions.get()) {
if (waypoint != waypointList.getList().get(0)) {
imageSpecs.add(new ImageSpec(ACTION_ORC_PCS_DEFINE_LEG, stringMessages.actionDefineLegForOrcPcs(), resources.orcPcsDefineLegIcon()));
} else {
imageSpecs.add(new ImageSpec(ACTION_ORC_PCS_DEFINE_ALL_LEGS, stringMessages.actionDefineAllLegsForOrcPcs(), resources.orcPcsDefineAllLegsIcon()));
}
}
return imageSpecs;
}
@@ -1248,4 +1248,9 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
Triple<Integer, Integer, Integer> assignORCPerformanceCurveCertificates(String leaderboardName,
Map<String, ORCCertificate> certificatesForBoatsWithIdAsString) throws IOException, NotFoundException;
CompetitorDTO getORCPerformanceCurveScratchBoat(String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException;
void setORCPerformanceCurveScratchBoat(String leaderboardName, String raceColumnName, String fleetName,
CompetitorDTO newScratchBoat) throws NotFoundException;
}
@@ -1172,4 +1172,10 @@ public interface SailingServiceAsync extends FileStorageManagementGwtServiceAsyn
void assignORCPerformanceCurveCertificates(String leaderboardName,
Map<String, ORCCertificate> certificatesForBoatsWithIdAsString,
AsyncCallback<Triple<Integer, Integer, Integer>> callback);
void getORCPerformanceCurveScratchBoat(String leaderboardName, String raceColumnName, String fleetName,
AsyncCallback<CompetitorDTO> asyncCallback);
void setORCPerformanceCurveScratchBoat(String leaderboardName, String raceColumnName, String fleetName, CompetitorDTO newScratchBoat,
AsyncCallback<Void> asyncCallback);
}
@@ -2300,4 +2300,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String totalDistance();
String setAllLegsToType();
String desiredTotalDistanceInNauticalMiles();
String selectScratchBoat();
String errorObtainingScratchBoat(String message);
String errorSettingScratchBoat(String message);
String scratchBoatSetSuccessfully();
}
@@ -2303,4 +2303,8 @@ trackedDistanceInNauticalMiles=Tracked leg distance (NM)
useTrackedData=Use tracked leg data
totalDistance=Total Distance (NM)
setAllLegsToType=Set all legs to type
desiredTotalDistanceInNauticalMiles=Desired Total Distance (NM)
desiredTotalDistanceInNauticalMiles=Desired Total Distance (NM)
selectScratchBoat=Select scratch boat
errorObtainingScratchBoat=Error obtaining scratch boat: {0}
errorSettingScratchBoat=Error setting scratch boat: {0}
scratchBoatSetSuccessfully=Scratch boat set successfully.
@@ -2295,4 +2295,8 @@ trackedDistanceInNauticalMiles=Getrackte Schenkel-Distanz (NM)
useTrackedData=Tracking-Werte verwenden
totalDistance=Gesamtdistanz (NM)
setAllLegsToType=Typ für alle Bahnschenkel setzen
desiredTotalDistanceInNauticalMiles=Gewünschte Gesamtdistanz (NM)
desiredTotalDistanceInNauticalMiles=Gewünschte Gesamtdistanz (NM)
selectScratchBoat="Scratch-Boot" auswählen
errorObtainingScratchBoat=Fehler beim Laden des "Scratch-Bootes": {0}
errorSettingScratchBoat=Fehler beim Setzen des "Scratch-Bootes": {0}
scratchBoatSetSuccessfully="Scratch-Boot" erfolgreich geändert.
@@ -88,9 +88,13 @@ import com.sap.sailing.domain.abstractlog.orc.RaceLogORCCertificateAssignmentFin
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCLegDataAnalyzer;
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCLegDataEvent;
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCLegDataEventFinder;
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCScratchBoatAnalyzer;
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCScratchBoatEvent;
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCScratchBoatFinder;
import com.sap.sailing.domain.abstractlog.orc.RegattaLogORCCertificateAssignmentFinder;
import com.sap.sailing.domain.abstractlog.orc.impl.RaceLogORCCertificateAssignmentEventImpl;
import com.sap.sailing.domain.abstractlog.orc.impl.RaceLogORCLegDataEventImpl;
import com.sap.sailing.domain.abstractlog.orc.impl.RaceLogORCScratchBoatEventImpl;
import com.sap.sailing.domain.abstractlog.orc.impl.RegattaLogORCCertificateAssignmentEventImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent;
@@ -1278,12 +1282,16 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
RegattaAndRaceIdentifier raceIdentifier = new RegattaNameAndRaceName(regatta.getName(), r.getName());
TrackedRace trackedRace = getService().getExistingTrackedRace(raceIdentifier);
TrackedRaceDTO trackedRaceDTO = null;
final RankingMetrics rankingMetricType;
if (trackedRace != null) {
trackedRaceDTO = getBaseDomainFactory().createTrackedRaceDTO(trackedRace);
rankingMetricType = trackedRace.getRankingMetric().getType();
} else {
rankingMetricType = null;
}
Map<CompetitorDTO, BoatDTO> competitorAndBoatDTOs = baseDomainFactory.convertToCompetitorAndBoatDTOs(r.getCompetitorsAndTheirBoats());
RaceWithCompetitorsAndBoatsDTO raceDTO = new RaceWithCompetitorsAndBoatsDTO(raceIdentifier, competitorAndBoatDTOs,
trackedRaceDTO, getService().isRaceBeingTracked(regatta, r));
trackedRaceDTO, getService().isRaceBeingTracked(regatta, r), rankingMetricType);
if (trackedRace != null) {
SecurityDTOUtil.addSecurityInformation(getSecurityService(), raceDTO, trackedRace.getIdentifier());
getBaseDomainFactory().updateRaceDTOWithTrackedRaceData(trackedRace, raceDTO);
@@ -1993,7 +2001,7 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
.convertToCompetitorAndBoatDTOs(race.getCompetitorsAndTheirBoats());
TrackedRaceDTO trackedRaceDTO = getBaseDomainFactory().createTrackedRaceDTO(trackedRace);
raceDTO = new RaceWithCompetitorsAndBoatsDTO(raceIdentifier, competitorsAndBoats, trackedRaceDTO,
getService().isRaceBeingTracked(regatta, race));
getService().isRaceBeingTracked(regatta, race), trackedRace.getRankingMetric().getType());
if (trackedRace != null) {
getBaseDomainFactory().updateRaceDTOWithTrackedRaceData(trackedRace, raceDTO);
}
@@ -5877,30 +5885,22 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
@Override
public Iterable<CompetitorDTO> getCompetitors(boolean filterCompetitorsWithBoat,
boolean filterCompetitorsWithoutBoat) {
Iterable<CompetitorDTO> result;
CompetitorAndBoatStore competitorStore = getService().getBaseDomainFactory().getCompetitorAndBoatStore();
final HasPermissions.Action[] requiredActionsForRead = SecuredSecurityTypes.PublicReadableActions.READ_AND_READ_PUBLIC_ACTIONS;
final Iterable<? extends Competitor> filteredCompetitors;
if (filterCompetitorsWithBoat == false && filterCompetitorsWithoutBoat == false) {
@SuppressWarnings("unchecked")
Iterable<Competitor> competitors = (Iterable<Competitor>) competitorStore.getAllCompetitors();
result = getSecurityService().mapAndFilterByAnyExplicitPermissionForCurrentUser(
SecuredDomainType.COMPETITOR,
requiredActionsForRead, competitors,
this::convertToCompetitorDTO);
filteredCompetitors = competitorStore.getAllCompetitors();
} else if (filterCompetitorsWithBoat == true && filterCompetitorsWithoutBoat == false) {
result = getSecurityService().mapAndFilterByAnyExplicitPermissionForCurrentUser(
SecuredDomainType.COMPETITOR,
requiredActionsForRead, competitorStore.getCompetitorsWithoutBoat(),
this::convertToCompetitorDTO);
filteredCompetitors = competitorStore.getCompetitorsWithoutBoat();
} else if (filterCompetitorsWithBoat == false && filterCompetitorsWithoutBoat == true) {
result = getSecurityService().mapAndFilterByAnyExplicitPermissionForCurrentUser(
SecuredDomainType.COMPETITOR,
requiredActionsForRead, competitorStore.getCompetitorsWithBoat(),
this::convertToCompetitorDTO);
filteredCompetitors = competitorStore.getCompetitorsWithBoat();
} else {
result = Collections.emptyList();
filteredCompetitors = Collections.emptyList();
}
return result;
return getSecurityService().mapAndFilterByAnyExplicitPermissionForCurrentUser(
SecuredDomainType.COMPETITOR,
requiredActionsForRead, filteredCompetitors,
this::convertToCompetitorDTO);
}
@Override
@@ -9588,28 +9588,9 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
private Triple<Integer, Integer, Integer> createCertificateAssignmentsForRaceLog(String leaderboardName, String raceColumnName, String fleetName,
Map<String, ORCCertificate> certificatesForBoatIdsAsString) throws IOException, NotFoundException {
final Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
if (leaderboard == null) {
throw new NotFoundException("Leaderboard named "+leaderboardName+" not found");
} else {
getService().getSecurityService().checkCurrentUserUpdatePermission(leaderboard);
if (leaderboard instanceof RegattaLeaderboard) {
getService().getSecurityService().checkCurrentUserUpdatePermission(((RegattaLeaderboard) leaderboard).getRegatta());
}
final RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName);
if (raceColumn == null) {
throw new NotFoundException("Race column named "+raceColumnName+" not found in leaderboard named "+leaderboardName);
} else {
final Fleet fleet = raceColumn.getFleetByName(fleetName);
if (fleet == null) {
throw new NotFoundException("Fleet "+fleetName+" not found in race column named "+raceColumnName+" in leaderboard named "+leaderboardName);
} else {
final RaceLog raceLog = raceColumn.getRaceLog(fleet);
final LogEventConstructor<RaceLogEvent, RaceLogEventVisitor> logEventConstructor = createRaceLogEventConstructor();
return createCertificateAssignments(raceLog, logEventConstructor, certificatesForBoatIdsAsString);
}
}
}
final RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName);
final LogEventConstructor<RaceLogEvent, RaceLogEventVisitor> logEventConstructor = createRaceLogEventConstructor();
return createCertificateAssignments(raceLog, logEventConstructor, certificatesForBoatIdsAsString);
}
private Triple<Integer, Integer, Integer> createCertificateAssignmentsForRegatta(RegattaIdentifier regattaIdentifier,
@@ -9734,4 +9715,39 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
Map<String, ORCCertificate> certificatesForBoatsWithIdAsString) throws IOException, NotFoundException {
return createCertificateAssignmentsForRaceLog(leaderboardName, raceColumnName, fleetName, certificatesForBoatsWithIdAsString);
}
@Override
public CompetitorDTO getORCPerformanceCurveScratchBoat(String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException {
final RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName);
final RaceLogORCScratchBoatFinder finder = new RaceLogORCScratchBoatFinder(raceLog,
competitorId -> getService().getCompetitorAndBoatStore().getExistingCompetitorById(competitorId));
final Competitor scratchBoat = finder.analyze();
return scratchBoat == null ? null : convertToCompetitorDTO(scratchBoat);
}
@Override
public void setORCPerformanceCurveScratchBoat(String leaderboardName, String raceColumnName, String fleetName, CompetitorDTO newScratchBoatDTO) throws NotFoundException {
final RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName);
final Competitor newScratchBoat = newScratchBoatDTO==null?null:
getService().getCompetitorAndBoatStore().getExistingCompetitorById(UUIDHelper.tryUuidConversion(newScratchBoatDTO.getIdAsString()));
final RaceLogORCScratchBoatAnalyzer analyzer = new RaceLogORCScratchBoatAnalyzer(raceLog,
competitorId -> getService().getCompetitorAndBoatStore().getExistingCompetitorById(competitorId));
final Pair<Competitor, RaceLogORCScratchBoatEvent> previousScratchBoatAndEvent = analyzer.analyze();
final Competitor previousScratchBoat = previousScratchBoatAndEvent == null ? null : previousScratchBoatAndEvent.getA();
if (!Util.equalsWithNull(newScratchBoat, previousScratchBoat)) {
final AbstractLogEventAuthor serverAuthor = getService().getServerAuthor();
if (previousScratchBoatAndEvent != null) {
// revoke scratch boat setting so far:
try {
raceLog.revokeEvent(serverAuthor, previousScratchBoatAndEvent.getB());
} catch (NotRevokableException e) {
logger.log(Level.SEVERE, "Unable to revoke scratch boat definition event "+previousScratchBoatAndEvent.getB(), e);
}
}
if (newScratchBoat != null) {
final TimePoint now = MillisecondsTimePoint.now();
raceLog.add(new RaceLogORCScratchBoatEventImpl(now, now, serverAuthor, UUID.randomUUID(), /* passId */ raceLog.getCurrentPassId(), newScratchBoat));
}
}
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.shared;
import java.util.Collection;
import java.util.Map;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.BoatDTO;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
@@ -19,8 +20,8 @@ public class RaceWithCompetitorsAndBoatsDTO extends RaceDTO {
RaceWithCompetitorsAndBoatsDTO() {}
public RaceWithCompetitorsAndBoatsDTO(RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, BoatDTO> competitorsAndBoats,
TrackedRaceDTO trackedRace, boolean isCurrentlyTracked) {
super(raceIdentifier, trackedRace, isCurrentlyTracked);
TrackedRaceDTO trackedRace, boolean isCurrentlyTracked, RankingMetrics rankingMetricType) {
super(raceIdentifier, trackedRace, isCurrentlyTracked, rankingMetricType);
this.competitorsAndBoats = competitorsAndBoats;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB