diff --git a/home.md b/home.md index 22c56a7a49b..a5a11b21c28 100644 --- a/home.md +++ b/home.md @@ -94,6 +94,7 @@ SAP is at the center of today’s technology revolution, developing innovations ## HowTo * [[Onboarding|wiki/howto/onboarding]] +* [[Managing Events with the AdminConsole|wiki/howto/adminconsoleinstructions]] * [[Importing Sessions from Expedition|wiki/howto/expeditionimport]] * [[Checking our DBs for a user record by e-mail|wiki/howto/privacy]] * [[Managing ORC Performance Curve Regattas|wiki/howto/setup-orc-regatta]] diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java index 835bfc675f3..5f06edf0c58 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java @@ -372,6 +372,7 @@ public enum DetailType implements Serializable { allowed.add(RACE_IMPLIED_WIND); allowed.add(RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD); allowed.add(RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS); + allowed.add(RACE_CURRENT_COURSE_OVER_GROUND_IN_TRUE_DEGREES); allowed.add(RACE_CURRENT_DISTANCE_FOILED_IN_METERS); allowed.add(RACE_CURRENT_DURATION_FOILED_IN_SECONDS); allowed.add(RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS); diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/BoatClassDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/BoatClassDTO.java index 9f3beb0590c..df29dfa6d84 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/BoatClassDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/BoatClassDTO.java @@ -16,20 +16,15 @@ public class BoatClassDTO extends NamedDTO implements Serializable, Comparablenull, no leg details are known yet, the race is not being tracked or the details @@ -618,6 +621,8 @@ public class LeaderboardEntryDTO implements Serializable { result = prime * result + ((calculatedTime == null) ? 0 : calculatedTime.hashCode()); result = prime * result + ((calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) ? 0 : calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.hashCode()); + result = prime * result + ((currentSpeedAndCourseOverGround == null) ? 0 + : currentSpeedAndCourseOverGround.hashCode()); result = prime * result + (discarded ? 1231 : 1237); result = prime * result + ((distanceToStarboardSideOfStartLineInMeters == null) ? 0 : distanceToStarboardSideOfStartLineInMeters.hashCode()); @@ -703,6 +708,12 @@ public class LeaderboardEntryDTO implements Serializable { } else if (!calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead .equals(other.calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead)) return false; + if (currentSpeedAndCourseOverGround == null) { + if (other.currentSpeedAndCourseOverGround != null) + return false; + } else if (!currentSpeedAndCourseOverGround + .equals(other.currentSpeedAndCourseOverGround)) + return false; if (discarded != other.discarded) return false; if (distanceToStarboardSideOfStartLineInMeters == null) { diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/windfinder/AvailableWindFinderSpotCollections.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/windfinder/AvailableWindFinderSpotCollections.java index 2ae5d1c2842..83019609dba 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/windfinder/AvailableWindFinderSpotCollections.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/windfinder/AvailableWindFinderSpotCollections.java @@ -24,7 +24,8 @@ public enum AvailableWindFinderSpotCollections { TEGERNSEE("tegernsee"), TORTOLA("tortola"), AUCKLAND("auckland"), - AARHUS("aarhus"); + AARHUS("aarhus"), + NEW_YORK("new_york"); private final String name; diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/base/racegroup/impl/CurrentRaceFilterImplTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/base/racegroup/impl/CurrentRaceFilterImplTest.java index 1e9d9a598a8..3d59e1c1c90 100644 --- a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/base/racegroup/impl/CurrentRaceFilterImplTest.java +++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/base/racegroup/impl/CurrentRaceFilterImplTest.java @@ -65,7 +65,7 @@ public class CurrentRaceFilterImplTest { _505RaceRows.add(_505RaceRow); _505Series.add(new SeriesWithRowsImpl("Default", /* isMedal */ false, /* isFleetsCanRunInParallel */ false, _505RaceRows)); final RaceGroup _505 = new RaceGroupImpl("505", /* displayName */ null, - new BoatClassImpl(BoatClassMasterdata._5O5.getDisplayName(), BoatClassMasterdata._5O5), /* canBoatsOfCompetitorsChangePerRace */ false, + new BoatClassImpl(BoatClassMasterdata._5O5), /* canBoatsOfCompetitorsChangePerRace */ false, _505Series, /* regattaConfiguration */ null); return _505; } @@ -75,7 +75,7 @@ public class CurrentRaceFilterImplTest { final List yesRaceRows = Arrays.asList(createRaceRow(1, 9, "R", "Yellow"), createRaceRow(1, 9, "R", "Blue")); yesSeries.add(new SeriesWithRowsImpl("Default", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, yesRaceRows)); final RaceGroup yes = new RaceGroupImpl("YES", /* displayName */ null, - new BoatClassImpl(BoatClassMasterdata._470.getDisplayName(), BoatClassMasterdata._470), /* canBoatsOfCompetitorsChangePerRace */ false, + new BoatClassImpl(BoatClassMasterdata._470), /* canBoatsOfCompetitorsChangePerRace */ false, yesSeries, /* regattaConfiguration */ null); return yes; } @@ -89,7 +89,7 @@ public class CurrentRaceFilterImplTest { final List isafMedalRaceRows = Arrays.asList(createRaceRow(1, 1, "M", "Medal")); isafSeries.add(new SeriesWithRowsImpl("Medal", /* isMedal */ true, /* isFleetsCanRunInParallel */ true, isafMedalRaceRows)); final RaceGroup isaf = new RaceGroupImpl("ISAF", /* displayName */ null, - new BoatClassImpl(BoatClassMasterdata._470.getDisplayName(), BoatClassMasterdata._470), /* canBoatsOfCompetitorsChangePerRace */ false, + new BoatClassImpl(BoatClassMasterdata._470), /* canBoatsOfCompetitorsChangePerRace */ false, isafSeries, /* regattaConfiguration */ null); return isaf; } @@ -109,7 +109,7 @@ public class CurrentRaceFilterImplTest { final List essDay4RaceRows = Arrays.asList(createRaceRow(16, 5, "R", "Default")); essSeries.add(new SeriesWithRowsImpl("Day 4", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, essDay4RaceRows)); final RaceGroup ess = new RaceGroupImpl("ESS", /* displayName */ null, - new BoatClassImpl(BoatClassMasterdata.EXTREME_40.getDisplayName(), BoatClassMasterdata.EXTREME_40), /* canBoatsOfCompetitorsChangePerRace */ false, + new BoatClassImpl(BoatClassMasterdata.EXTREME_40), /* canBoatsOfCompetitorsChangePerRace */ false, essSeries, /* regattaConfiguration */ null); return ess; } @@ -119,7 +119,7 @@ public class CurrentRaceFilterImplTest { final List leagueRaceRows = Arrays.asList(createRaceRow(1, 15, "F", "Red"), createRaceRow(1, 15, "F", "Green"), createRaceRow(1, 15, "F", "Blue")); leagueSeries.add(new SeriesWithRowsImpl("Default", /* isMedal */ false, /* isFleetsCanRunInParallel */ false, leagueRaceRows)); final RaceGroup league = new RaceGroupImpl("League", /* displayName */ null, - new BoatClassImpl(BoatClassMasterdata.J70.getDisplayName(), BoatClassMasterdata.J70), /* canBoatsOfCompetitorsChangePerRace */ false, + new BoatClassImpl(BoatClassMasterdata.J70), /* canBoatsOfCompetitorsChangePerRace */ false, leagueSeries, /* regattaConfiguration */ null); return league; } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/BoatClass.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/BoatClass.java index 76924454a73..81709ca3e8c 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/BoatClass.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/BoatClass.java @@ -45,8 +45,6 @@ public interface BoatClass extends Named, IsManagedByCache implements Sha result = boatClassCache.get(unifiedBoatClassName); if (result == null) { if (unifiedBoatClassName != null && boatClassMasterdata != null) { - result = new BoatClassImpl(boatClassMasterdata.getDisplayName(), boatClassMasterdata); + result = new BoatClassImpl(boatClassMasterdata); boatClassCache.put(unifiedBoatClassName, result); } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/TransientCompetitorAndBoatStoreImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/TransientCompetitorAndBoatStoreImpl.java index 6ae5b241c82..43b4841134a 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/TransientCompetitorAndBoatStoreImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/TransientCompetitorAndBoatStoreImpl.java @@ -647,7 +647,7 @@ public class TransientCompetitorAndBoatStoreImpl implements CompetitorAndBoatSto boatDTO = weakBoatDTOCache.get(b); if (boatDTO == null) { BoatClassDTO boatClassDTO = new BoatClassDTO(b.getBoatClass().getName(), - b.getBoatClass().getDisplayName(), b.getBoatClass().getHullLength(), b.getBoatClass().getHullBeam()); + b.getBoatClass().getHullLength(), b.getBoatClass().getHullBeam()); boatDTO = new BoatDTO(b.getId().toString(), b.getName(), boatClassDTO, b.getSailID(), b.getColor()); weakBoatDTOCache.put(b, boatDTO); } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CompetitorProviderCacheInvalidationTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CompetitorProviderCacheInvalidationTest.java index c846860e42f..0eefe69193b 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CompetitorProviderCacheInvalidationTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CompetitorProviderCacheInvalidationTest.java @@ -78,7 +78,7 @@ public class CompetitorProviderCacheInvalidationTest extends AbstractLeaderboard new ThresholdBasedResultDiscardingRuleImpl(new int[0]), new LowPoint(), courseArea); competitorProviderFlexibleLeaderboard = new CompetitorProviderFromRaceColumnsAndRegattaLike(flexibleLeaderboard); regatta = new RegattaImpl(EmptyRaceLogStore.INSTANCE, - EmptyRegattaLogStore.INSTANCE, "Test Regatta", new BoatClassImpl("49er", BoatClassMasterdata._49ER), + EmptyRegattaLogStore.INSTANCE, "Test Regatta", new BoatClassImpl(BoatClassMasterdata._49ER), /* canBoatsOfCompetitorsChangePerRace */ true, CompetitorRegistrationType.CLOSED, /* startDate */ null, /* endDate */null, /* trackedRegattaRegistry */null, new LowPoint(), UUID.randomUUID(), courseArea, /* registrationLinkSecret */ UUID.randomUUID().toString()); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateDuringNonAtomicSerializationTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateDuringNonAtomicSerializationTest.java index d38a049e397..c4a96ff76a9 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateDuringNonAtomicSerializationTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateDuringNonAtomicSerializationTest.java @@ -77,7 +77,7 @@ public class CourseUpdateDuringNonAtomicSerializationTest implements Serializabl removeCalls = new HashMap<>(); course = new CourseImpl("Test Course", waypoints); Regatta regatta = new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, "Test Regatta", - new BoatClassImpl("505", BoatClassMasterdata._5O5), + new BoatClassImpl(BoatClassMasterdata._5O5), /* canBoatsOfCompetitorsChangePerRace */ true, CompetitorRegistrationType.CLOSED, /*startDate*/ null, /*endDate*/ null, /* trackedRegattaRegistry */ null, new LowPoint(), UUID.randomUUID(), new CourseAreaImpl("Alpha", UUID.randomUUID()), diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DomainFactoryImplTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DomainFactoryImplTest.java index 4028c4e361a..11d80655f72 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DomainFactoryImplTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DomainFactoryImplTest.java @@ -33,7 +33,7 @@ public class DomainFactoryImplTest { public void testGetDominantBoatClass_TestWithOneObject() { List list = new ArrayList<>(); list.add("LSR"); - Assert.assertEquals("Laser Int.", domainFactory.getDominantBoatClass(list).getDisplayName()); + Assert.assertEquals("Laser Int.", domainFactory.getDominantBoatClass(list).getName()); } @Test @@ -41,7 +41,7 @@ public class DomainFactoryImplTest { List list = new ArrayList<>(); list.add("LSR"); list.add("18.Footer"); - String result = domainFactory.getDominantBoatClass(list).getDisplayName(); + String result = domainFactory.getDominantBoatClass(list).getName(); if(!(result == "Laser Int." || result == "18Footer")) { Assert.assertEquals("Laser Int.", result); } @@ -53,7 +53,7 @@ public class DomainFactoryImplTest { list.add("LSR"); list.add("18.Footer"); list.add("LSR"); - String result = domainFactory.getDominantBoatClass(list).getDisplayName(); + String result = domainFactory.getDominantBoatClass(list).getName(); Assert.assertEquals("Laser Int.", result); } @@ -65,7 +65,7 @@ public class DomainFactoryImplTest { list.add("18.Footer"); list.add("Laser Int."); list.add("Laser"); - String result = domainFactory.getDominantBoatClass(list).getDisplayName(); + String result = domainFactory.getDominantBoatClass(list).getName(); Assert.assertEquals("Laser Int.", result); } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackBasedTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackBasedTest.java index 082b05eb499..d15c374f718 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackBasedTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackBasedTest.java @@ -218,7 +218,7 @@ public abstract class TrackBasedTest { } public static RegattaImpl createTestRegatta(String regattaName, Iterable raceColumnNames) { - final BoatClass boatClass = new BoatClassImpl("boat class name", BoatClassMasterdata._12M); + final BoatClass boatClass = new BoatClassImpl(BoatClassMasterdata._12M); final TimePoint startDate = MillisecondsTimePoint.now(); final TimePoint endDate = startDate.plus(MillisecondsDurationImpl.ONE_DAY); final boolean isMedal = false; diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMockedRaceMarkPassingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMockedRaceMarkPassingTest.java index 6aa01edcd23..1c37e34d88e 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMockedRaceMarkPassingTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMockedRaceMarkPassingTest.java @@ -48,7 +48,7 @@ import com.sap.sse.common.Util; import com.sap.sse.common.impl.MillisecondsTimePoint; public class AbstractMockedRaceMarkPassingTest { - final BoatClassImpl boatClass = new BoatClassImpl("boat", true, "boat", new MeterDistance(10), new MeterDistance(5), null); + final BoatClassImpl boatClass = new BoatClassImpl("boat", true, new MeterDistance(10), new MeterDistance(5), null); protected Competitor ron = new CompetitorImpl("Ron", "Ron", "KYC", null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null); protected Competitor tom = new CompetitorImpl("Tom", "Tom", "KYC", null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null); protected Competitor ben = new CompetitorImpl("Ben", "Ben", "KYC", null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/MarkPassingCalculatorWithTrackersOnStartBoatTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/MarkPassingCalculatorWithTrackersOnStartBoatTest.java index f940443e48b..0d0b95b67eb 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/MarkPassingCalculatorWithTrackersOnStartBoatTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/MarkPassingCalculatorWithTrackersOnStartBoatTest.java @@ -45,7 +45,7 @@ public class MarkPassingCalculatorWithTrackersOnStartBoatTest extends AbstractEx @Before public void setUp() throws IOException, ParseException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { startOfSetup = MillisecondsTimePoint.now(); - trackedRace = readRace("/MoevensteinCompetitorPositions.json.gz", "/MoevensteinMarkPositions.json.gz", new BoatClassImpl("J/70", BoatClassMasterdata.J70)); + trackedRace = readRace("/MoevensteinCompetitorPositions.json.gz", "/MoevensteinMarkPositions.json.gz", new BoatClassImpl(BoatClassMasterdata.J70)); markPassings = new HashMap<>(); for (final Competitor competitor : trackedRace.getRace().getCompetitors()) { markPassings.put(competitor, trackedRace.getMarkPassings(competitor, /* waitForLatest */ true)); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java index f4cce8b36c3..a506181bf6d 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java @@ -394,7 +394,7 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard { this.getScoreCorrection() == null ? null : this.getScoreCorrection().getComment(), this.getScoringScheme() == null ? null : this.getScoringScheme().getType(), this .getScoringScheme().isHigherBetter(), () -> UUID.randomUUID().toString(), addOverallDetails, - boatClass==null?null:new BoatClassDTO(boatClass.getName(), boatClass.getDisplayName(), boatClass.getHullLength(), boatClass.getHullBeam())); + boatClass==null?null:new BoatClassDTO(boatClass.getName(), boatClass.getHullLength(), boatClass.getHullBeam())); result.type = getLeaderboardType(); result.competitors = new ArrayList<>(); result.setName(this.getName()); @@ -689,6 +689,7 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard { Date timePointOfLastPositionFixAtOrBeforeQueryTimePoint = getTimePointOfLastFixAtOrBefore(competitor, trackedRace, timePoint); if (track != null) { entryDTO.averageSamplingInterval = track.getAverageIntervalBetweenRawFixes(); + entryDTO.currentSpeedAndCourseOverGround = track.getEstimatedSpeed(timePoint); } if (timePointOfLastPositionFixAtOrBeforeQueryTimePoint != null) { long timeDifferenceInMs = timePoint.asMillis() - timePointOfLastPositionFixAtOrBeforeQueryTimePoint.getTime(); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPublicCertificateDatabaseImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPublicCertificateDatabaseImpl.java index e476a4b4c2a..4260a5d1288 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPublicCertificateDatabaseImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPublicCertificateDatabaseImpl.java @@ -629,7 +629,7 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat final Set restrictedResults = new HashSet<>(); for (final CertificateHandle handle : filterHandlesForCurrentYear(certificateHandles)) { final BoatClassMasterdata boatClassMasterData = BoatClassMasterdata.resolveBoatClass(handle.getBoatClassName()); - if (boatClassMasterData != null && boatClassMasterData.getDisplayName().equals(boatClass.getDisplayName())) { + if (boatClassMasterData != null && boatClassMasterData.getDisplayName().equals(boatClass.getName())) { restrictedResults.add(handle); } } diff --git a/java/com.sap.sailing.gwt.ui/imprint.json b/java/com.sap.sailing.gwt.ui/imprint.json index 97ff0810937..3f9b67610b3 100644 --- a/java/com.sap.sailing.gwt.ui/imprint.json +++ b/java/com.sap.sailing.gwt.ui/imprint.json @@ -753,7 +753,7 @@ "acknowledgements": [ "Copyright 2016 yanwsh@gmail.com" ], - "key": "Apache License 2.0" + "key": "ASL2.0" } ], "licenses": [ @@ -781,5 +781,27 @@ "key": "UNIDATA", "file": "unidata.txt" } + ], + "disclaimers":[ + { + "title":"SAP Legal Disclosure", + "link": "https://www.sap.com/corporate/en/legal/impressum.html", + "content": "Please visit ${link} to view the general SAP legal disclosure." + }, + { + "title":"YouTube", + "link": "https://www.youtube.com/t/terms", + "content": "The application utilizes the YouTube video streaming service. Therefore, by using the application, users implicitly agree to the terms of service provided by YouTube, found under ${link}." + }, + { + "title":"Google Privacy", + "link": "https://policies.google.com/privacy", + "content": "The application utilizes services of Google. Therefore, by using the application, users implicitly agree to the privacy policies of Google, as stated under ${link}." + }, + { + "title":"Google Maps", + "link": "http://www.google.com/intl/en/policies/terms/", + "content": "Google Maps Service (\"GM Service\"). If the Cloud Service accesses the GM Service through a Google Maps API, customer's use of the GM Service is subject to Google's Terms of Service, which are set forth at ${link}. If customer does not accept the Google Terms of Service, including, but not limited to, all limitations and restrictions therein, customer may not use the GM Service in the Cloud Service. Use of the GM Service in or through the Cloud Service will constitute customer's acceptance of Google's Terms of Service. Customer's usage of the GM Service in or through the Cloud Service can be terminated by SAP without reason at any time and SAP will not be required to provide an equivalent service via another provider." + } ] } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetFavoritesAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetFavoritesAction.java index 58029acce59..e503665de4d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetFavoritesAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetFavoritesAction.java @@ -3,6 +3,8 @@ package com.sap.sailing.gwt.home.communication.user.profile; import java.util.TreeSet; import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.domain.base.CompetitorAndBoatStore; +import com.sap.sailing.domain.base.impl.DynamicCompetitor; import com.sap.sailing.domain.common.dto.BoatClassDTO; import com.sap.sailing.gwt.home.communication.SailingAction; import com.sap.sailing.gwt.home.communication.SailingDispatchContext; @@ -11,6 +13,7 @@ import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPrefer import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreferences; import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreference; import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreferences; +import com.sap.sailing.server.interfaces.RacingEventService; import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; /** @@ -33,8 +36,8 @@ public class GetFavoritesAction implements SailingAction { boolean notifyAboutUpcomingRaces = false, notifyAboutResults = false; if (preferences != null) { for (BoatClassNotificationPreference pref : preferences.getBoatClasses()) { - String name = pref.getBoatClass().getName(), displayName = pref.getBoatClass().getDisplayName(); - selected.add(new BoatClassDTO(name, displayName, pref.getBoatClass().getHullLength(), pref.getBoatClass().getHullBeam())); + String name = pref.getBoatClass().getName(); + selected.add(new BoatClassDTO(name, pref.getBoatClass().getHullLength(), pref.getBoatClass().getHullBeam())); notifyAboutUpcomingRaces |= pref.isNotifyAboutUpcomingRaces(); notifyAboutResults |= pref.isNotifyAboutResults(); } @@ -50,7 +53,13 @@ public class GetFavoritesAction implements SailingAction { boolean notifyAboutResults = false; if (preferences != null) { for (CompetitorNotificationPreference pref : preferences.getCompetitors()) { - selected.add(new SimpleCompetitorWithIdDTO(pref.getCompetitor())); + final String competitorId = pref.getCompetitorId(); + final RacingEventService racingEventService = ctx.getRacingEventService(); + final CompetitorAndBoatStore competitorAndBoatStore = racingEventService.getCompetitorAndBoatStore(); + DynamicCompetitor competitor = competitorAndBoatStore.getExistingCompetitorByIdAsString(competitorId); + selected.add(competitor == null ? + new SimpleCompetitorWithIdDTO(competitorId,"Not found","ID:" + competitorId, null, null) + : new SimpleCompetitorWithIdDTO(competitor)); notifyAboutResults |= pref.isNotifyAboutResults(); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteCompetitorsAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteCompetitorsAction.java index d6d698e3336..e88ba579688 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteCompetitorsAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteCompetitorsAction.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.List; import com.google.gwt.core.shared.GwtIncompatible; -import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CompetitorAndBoatStore; import com.sap.sailing.gwt.home.communication.SailingAction; import com.sap.sailing.gwt.home.communication.SailingDispatchContext; @@ -36,9 +35,14 @@ public class SaveFavoriteCompetitorsAction implements SailingAction, List competitorPreferences = new ArrayList<>(); CompetitorAndBoatStore competitorStore = ctx.getRacingEventService().getCompetitorAndBoatStore(); for (SimpleCompetitorWithIdDTO competitorDTO : favorites.getSelectedCompetitors()) { - Competitor competitor = competitorStore.getExistingCompetitorByIdAsString(competitorDTO.getIdAsString()); - competitorPreferences.add(new CompetitorNotificationPreference(competitorStore, competitor, - favorites.isNotifyAboutResults())); + String competitorId = competitorDTO.getIdAsString(); + if (competitorStore.getExistingCompetitorByIdAsString(competitorId) != null) { + competitorPreferences + .add(new CompetitorNotificationPreference(competitorId, favorites.isNotifyAboutResults())); + } else { + throw new DispatchException( + "Competitor with ID: " + competitorId + "is not an existing Competitor on this server."); + } } prefs.setCompetitors(competitorPreferences); ctx.setPreferenceForCurrentUser(CompetitorNotificationPreferences.PREF_NAME, prefs); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/sailorprofile/SailorProfileConverter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/sailorprofile/SailorProfileConverter.java index 5561b801170..d3245a083bc 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/sailorprofile/SailorProfileConverter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/sailorprofile/SailorProfileConverter.java @@ -102,6 +102,6 @@ public interface SailorProfileConverter { /** @return converted BoatClassDTO from BoatClass */ @GwtIncompatible default BoatClassDTO convertBoatClassToDTO(BoatClass bc) { - return new BoatClassDTO(bc.getName(), bc.getDisplayName(), bc.getHullLength(), bc.getHullBeam()); + return new BoatClassDTO(bc.getName(), bc.getHullLength(), bc.getHullBeam()); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html index 1eaf6b9a16b..b5d500246c3 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html @@ -12,6 +12,12 @@ by the tab for the next three months. We're looking forward to your feedback!
  • Bug fix: if a start or finish line was missing position information for one of its ends, the map display of tracks and course broke. This has been fixed now.
  • +
  • For better visibility especially with satellite view enabled, rhumb line display now uses a bright + green color.
  • +
  • Added an optional COG (Course over Ground) column to the leaderboard which shows all competitors' + COG in true degrees.
  • +
  • The rhumb line ("course middle line") for the first leg is now already displayed prior to the + start time point.
  • September 2020

    September 2020

      diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java index 4c159cf4407..35ec7e8e8ba 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -11,9 +11,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; -import org.osgi.util.tracker.ServiceTrackerCustomizer; import com.sap.sse.common.Stoppable; import com.sap.sse.common.Util; @@ -66,9 +64,7 @@ public abstract class PreferenceObjectBasedNotificationSet implements */ private final Map> notifications = new HashMap<>(); - private final BundleContext context; - - private final String key; + protected final BundleContext context; private final ServiceTracker tracker; @@ -78,15 +74,29 @@ public abstract class PreferenceObjectBasedNotificationSet implements * Constructor used to automatically track {@link UserStore} as OSGi service. */ public PreferenceObjectBasedNotificationSet(String key, BundleContext context) { - this.key = key; this.context = context; if (context == null) { this.tracker = null; } else { - this.tracker = new ServiceTracker(context, UserStore.class, new Cutomizer()); + this.tracker = new ServiceTracker(context, UserStore.class, + new StoreServiceTrackerCustomizer(context, logger) { + @Override + protected void setStore(UserStore store) { + PreferenceObjectBasedNotificationSet.this.store = store; + store.addPreferenceObjectListener(key, listener, true); + } + @Override + protected void removeStore() { + PreferenceObjectBasedNotificationSet.this.store = null; + } + @Override + protected UserStore getStore() { + return PreferenceObjectBasedNotificationSet.this.store; + } + }); this.tracker.open(); } - this.lock = new NamedReentrantReadWriteLock(getClass().getName()+" for "+key, /* fair */ false); + this.lock = new NamedReentrantReadWriteLock(getClass().getName()+" for "+ key, /* fair */ false); } /** @@ -106,7 +116,7 @@ public abstract class PreferenceObjectBasedNotificationSet implements removeStore(); } - private void removeStore() { + protected void removeStore() { if (store != null) { store.removePreferenceObjectListener(listener); store = null; @@ -186,31 +196,4 @@ public abstract class PreferenceObjectBasedNotificationSet implements } } } - - private class Cutomizer implements ServiceTrackerCustomizer { - @Override - public UserStore addingService(ServiceReference reference) { - UserStore store = context.getService(reference); - if (PreferenceObjectBasedNotificationSet.this.store != null - && PreferenceObjectBasedNotificationSet.this.store != store) { - logger.severe("Multiple " + UserStore.class.getSimpleName() - + " instances found. Only one instance is handled."); - } else { - PreferenceObjectBasedNotificationSet.this.store = store; - store.addPreferenceObjectListener(key, listener, true); - } - return store; - } - - @Override - public void modifiedService(ServiceReference reference, UserStore service) { - } - - @Override - public void removedService(ServiceReference reference, UserStore service) { - if (PreferenceObjectBasedNotificationSet.this.store == service) { - removeStore(); - } - } - } } diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/StoreServiceTrackerCustomizer.java b/java/com.sap.sse.security/src/com/sap/sse/security/StoreServiceTrackerCustomizer.java new file mode 100644 index 00000000000..fec10dfcc62 --- /dev/null +++ b/java/com.sap.sse.security/src/com/sap/sse/security/StoreServiceTrackerCustomizer.java @@ -0,0 +1,50 @@ +package com.sap.sse.security; + +import java.util.logging.Logger; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + +import com.sap.sse.security.interfaces.UserStore; + +public abstract class StoreServiceTrackerCustomizer implements ServiceTrackerCustomizer { + private final Logger logger; + + private final BundleContext context; + + public StoreServiceTrackerCustomizer(BundleContext context, Logger logger) { + this.logger = logger; + this.context = context; + } + + protected abstract void setStore(T store); + + protected abstract void removeStore(); + + protected abstract T getStore(); + + @Override + public T addingService(ServiceReference reference) { + T contextStore = context.getService(reference); + T thisStore = getStore(); + if (thisStore != null && thisStore != contextStore) { + logger.severe("Multiple " + UserStore.class.getSimpleName() + + " instances found. Only one instance is handled."); + } else { + setStore(contextStore); + } + return contextStore; + } + + @Override + public void modifiedService(ServiceReference reference, T store) { + } + + @Override + public void removedService(ServiceReference reference, T store) { + if (getStore() == store) { + removeStore(); + } + } +} diff --git a/wiki/howto/adminconsoleinstructions.md b/wiki/howto/adminconsoleinstructions.md new file mode 100644 index 00000000000..f5530ba65f0 --- /dev/null +++ b/wiki/howto/adminconsoleinstructions.md @@ -0,0 +1,71 @@ +1. [General Introduction to SAP Sailing Analytics](https://sapsailing-documentation.s3-eu-west-1.amazonaws.com/adminconsole/Advanced+Topics/MatchraceSetup.mp4) + +2. General Introduction to SAP Sailing Analytics Backend + Overview Functions, Features, known issues and quirks (Explaining start/stop of races and connecting races and how it can go wrong (dos and donts) + +3. How to enhance events created with Sail Insight + Moving Marks + Adding Marks + Managing Media (enhance event website) + Editing competitors - what can be changed, what can not be changed (Name, Sailnumber, Boatclass) + How to correct results + How to combine single regattas into one event + How to add GPS data of individual boats + Adding Video Playback to a Race Replay + +4. Using the race Manager app in combination with Sail insight + To manage results + To add and update Wind data + To manage a daily schedule + To manage start times + … + + + +- Anlegen eines einfachen Events in der Admin Console +- Rechteverwaltung des Events: "Publishing"-Levels (show on homepage und/vs. Group Ownership Management) +- Grundlagen Rechteverwaltung: User, Group, Permissions, Roles, Ownerships +- [Create an event with multiple regattas](https://sapsailing-documentation.s3-eu-west-1.amazonaws.com/adminconsole/Advanced+Topics/Setting+up+Events+with+multiple+Regattas+or+Classes.mp4) + * (boat) classes + * assigning regattas to course areas + * leaderboards, including sub-divisions +- Details of regatta set-up explained: + * Provisioned/changing boats + * all the bells and whistles including advanced discarding rules +- Import competitors from Manage2Sail +- Import results using Manage2Sail as an example +- Importing an entire event from Manage2Sail ("regatta structure import") +- How to get going with the Race Manager App? +- Setting up TracTrac connectivity +- Setting things up for Smartphone Tracking +- How to invite competitors for Sail Insight tracking? + * closed regatta, e-mail per competitor + * open unmoderated regatta, share QR code/link +- How to use the Buoy Pinger app? +- Using display names for leaderboards to keep things tidy +- Using media to enrich the event + * Add images and videos to my event + * Link and time-sync audio and video clips to my races +- Different ways to add wind data + * GRIB files + * manual entry in AdminConsole + * using the Race Manager App for wind data entry + * Expedition logs + * Bravo files + * connecting Expedition live + * Igtimi WindBot live connectivity + * Igtimi WindBot data import +- Handling split fleet racing + * setting it up in the regatta +- Course set-up and mark positioning explained + * AdminConsole + RaceBoard + * Sail Insight + * Race Manager App + * Buoy Pinger App +- Setting up and running ORC PCS regattas +- [Setting up a Matchrace Regatta](https://sapsailing-documentation.s3-eu-west-1.amazonaws.com/adminconsole/Advanced+Topics/MatchraceSetup.mp4) +- Setting up a 4 boat final +- Tips and Tricks for Cleansing Your Event + * check max speeds to find outliers + * check for mark passing completeness + * spot-checks for mark positions in multiple races