From 458951e32b3af2312dffb2afcfd602f58f5f2ae6 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 24 Jul 2019 10:46:35 +0200 Subject: [PATCH 01/43] Bug 5101: Initial implementation of an API to get the status of a tracking device --- .../gateway/jaxrs/api/RestApiApplication.java | 1 + .../jaxrs/api/TrackingDevicesResource.java | 92 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDevicesResource.java diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RestApiApplication.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RestApiApplication.java index 66469183084..5bb8c441830 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RestApiApplication.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RestApiApplication.java @@ -36,6 +36,7 @@ public class RestApiApplication extends Application { classes.add(UserGroupsResource.class); classes.add(StatusResource.class); classes.add(TrackedEventsResource.class); + classes.add(TrackingDevicesResource.class); // Exception Mappers classes.add(ShiroAuthorizationExceptionTo401ResponseMapper.class); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDevicesResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDevicesResource.java new file mode 100644 index 00000000000..c81555198b1 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDevicesResource.java @@ -0,0 +1,92 @@ +package com.sap.sailing.server.gateway.jaxrs.api; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import com.sap.sailing.domain.common.DeviceIdentifier; +import com.sap.sailing.domain.common.tracking.GPSFix; +import com.sap.sailing.domain.racelogtracking.impl.SmartphoneUUIDIdentifierImpl; +import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource; +import com.sap.sailing.server.gateway.serialization.JsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.GPSFixJsonSerializer; +import com.sap.sse.common.Timed; + +@Path("/v1/tracking_devices") +public class TrackingDevicesResource extends AbstractSailingServerResource { + private static final Logger logger = Logger.getLogger(TrackingDevicesResource.class.getName()); + private final JsonSerializer serializer = new DeviceStatusSerializer(); + + private static final class DeviceStatus { + private final UUID deviceUUID; + private final GPSFix lastFix; + + public DeviceStatus(UUID deviceUUID, GPSFix lastFix) { + this.deviceUUID = deviceUUID; + this.lastFix = lastFix; + } + } + + private static final class DeviceStatusSerializer implements JsonSerializer { + private final GPSFixJsonSerializer gpsFixSerializer = new GPSFixJsonSerializer(); + @Override + public JSONObject serialize(DeviceStatus deviceStatus) { + JSONObject result = new JSONObject(); + result.put("deviceUUID", deviceStatus.deviceUUID.toString()); + if (deviceStatus.lastFix != null) { + result.put("lastFix", gpsFixSerializer.serialize(deviceStatus.lastFix)); + } + return result; + } + } + + @GET + @Produces("application/json;charset=UTF-8") + @Path("{deviceUUID}") + public Response getDeviceStatus(@PathParam("deviceUUID") UUID deviceUUID) { + JSONObject result = serializer.serialize(calculateDeviceStatus(deviceUUID)); + return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + } + + @GET + @Produces("application/json;charset=UTF-8") + public Response getDeviceStatuses(@QueryParam("deviceUUIDs") Set deviceUUIDs) { + JSONArray result = new JSONArray(); + for (UUID deviceUUID : deviceUUIDs) { + result.add(serializer.serialize(calculateDeviceStatus(deviceUUID))); + } + return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") + .build(); + } + + private DeviceStatus calculateDeviceStatus(UUID deviceUUID) { + final DeviceIdentifier deviceIdentifier = new SmartphoneUUIDIdentifierImpl(deviceUUID); + try { + Map lastFixMap = getService().getSensorFixStore().getLastFix(Collections.singletonList(deviceIdentifier)); + Timed lastFix = lastFixMap.get(deviceIdentifier); + GPSFix lastGPSFix = lastFix instanceof GPSFix ? (GPSFix) lastFix : null; + return new DeviceStatus(deviceUUID, lastGPSFix); + } catch (Exception e) { + final String errorMessage = "Error while loading device status for device " + deviceUUID; + logger.log(Level.SEVERE, errorMessage, e); + throw new WebApplicationException( + Response.status(Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(errorMessage).build()); + } + } +} \ No newline at end of file From a612fed3c0cd7339467c2a5ca715cc97d848bd7c Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 24 Jul 2019 10:47:03 +0200 Subject: [PATCH 02/43] Bug 5101: Initial API test for getting the status of a tracking device --- .../selenium/api/event/TrackingDeviceApi.java | 42 ++++++++++++++ .../api/test/TrackingDeviceStatusApiTest.java | 55 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/event/TrackingDeviceApi.java create mode 100644 java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/TrackingDeviceStatusApiTest.java diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/event/TrackingDeviceApi.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/event/TrackingDeviceApi.java new file mode 100644 index 00000000000..50fb25a330c --- /dev/null +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/event/TrackingDeviceApi.java @@ -0,0 +1,42 @@ +package com.sap.sailing.selenium.api.event; + +import java.util.UUID; + +import org.json.simple.JSONObject; + +import com.sap.sailing.selenium.api.core.ApiContext; +import com.sap.sailing.selenium.api.core.JsonWrapper; + +public class TrackingDeviceApi { + + private static final String BASE_PATH = "/api/v1/tracking_devices"; + + public DeviceStatus getDeviceStatus(ApiContext ctx, UUID deviceUUID) { + return new DeviceStatus(ctx.get(BASE_PATH + "/" + deviceUUID.toString())); + } + + public class DeviceStatus extends JsonWrapper { + private DeviceStatus(JSONObject json) { + super(json); + } + + public UUID getDeviceUUID() { + return UUID.fromString(get("deviceUUID")); + } + + public GPSFixResponse getLastFix() { + JSONObject jsonObject = get("lastFix"); + return jsonObject == null ? null : new GPSFixResponse(jsonObject); + } + } + + public class GPSFixResponse extends JsonWrapper { + private GPSFixResponse(JSONObject json) { + super(json); + } + + public long getTime() { + return ((Number)get("unixtime")).longValue(); + } + } +} diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/TrackingDeviceStatusApiTest.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/TrackingDeviceStatusApiTest.java new file mode 100644 index 00000000000..009e4c3a4b3 --- /dev/null +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/TrackingDeviceStatusApiTest.java @@ -0,0 +1,55 @@ +package com.sap.sailing.selenium.api.test; + +import static com.sap.sailing.selenium.api.core.ApiContext.SERVER_CONTEXT; +import static com.sap.sailing.selenium.api.core.ApiContext.createAdminApiContext; +import static com.sap.sailing.selenium.api.core.GpsFixMoving.createFix; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.UUID; + +import org.junit.Before; +import org.junit.Test; + +import com.sap.sailing.selenium.api.core.ApiContext; +import com.sap.sailing.selenium.api.core.GpsFixMoving; +import com.sap.sailing.selenium.api.event.GpsFixApi; +import com.sap.sailing.selenium.api.event.TrackingDeviceApi; +import com.sap.sailing.selenium.api.event.TrackingDeviceApi.DeviceStatus; +import com.sap.sailing.selenium.api.event.TrackingDeviceApi.GPSFixResponse; +import com.sap.sailing.selenium.test.AbstractSeleniumTest; + +public class TrackingDeviceStatusApiTest extends AbstractSeleniumTest { + + private final GpsFixApi gpsFixApi = new GpsFixApi(); + private final TrackingDeviceApi trackingDeviceApi = new TrackingDeviceApi(); + + @Before + public void setUp() { + clearState(getContextRoot(), /* headless */ true); + } + + @Test + public void testDeviceStatusWithLastFix() { + final UUID deviceUUID = UUID.randomUUID(); + final ApiContext ctx = createAdminApiContext(getContextRoot(), SERVER_CONTEXT); + final DeviceStatus statusBeforeFix = trackingDeviceApi.getDeviceStatus(ctx, deviceUUID); + assertEquals(deviceUUID, statusBeforeFix.getDeviceUUID()); + assertNull(statusBeforeFix.getLastFix()); + + final long fix1Millis = System.currentTimeMillis() - 100; + final GpsFixMoving fix1 = createFix(49.121, 8.5987, fix1Millis, 10.0, 180.0); + gpsFixApi.postGpsFix(ctx, deviceUUID, fix1); + final DeviceStatus statusWithFix1 = trackingDeviceApi.getDeviceStatus(ctx, deviceUUID); + final GPSFixResponse lastFix1 = statusWithFix1.getLastFix(); + assertNotNull(lastFix1); + assertEquals(fix1Millis, lastFix1.getTime()); + + final long fix2Millis = System.currentTimeMillis(); + final GpsFixMoving fix2 = createFix(49.12, 8.599, fix2Millis, 10.0, 180.0); + gpsFixApi.postGpsFix(ctx, deviceUUID, fix2); + final DeviceStatus statusWithFix2 = trackingDeviceApi.getDeviceStatus(ctx, deviceUUID); + assertEquals(fix2Millis, statusWithFix2.getLastFix().getTime()); + } +} From dbaccd2c676c04cc1351e1512a285582e4675215 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 24 Jul 2019 14:56:12 +0200 Subject: [PATCH 03/43] Bug 5101: Refactoring to reuse TrackingDeviceStatus and serializer in other APIs and support different types of DeviceIdentifiers --- .../selenium/api/event/TrackingDeviceApi.java | 8 +-- .../api/test/TrackingDeviceStatusApiTest.java | 8 +-- .../jaxrs/AbstractSailingServerResource.java | 15 ++++- .../jaxrs/api/TrackingDeviceStatus.java | 48 ++++++++++++++ .../api/TrackingDeviceStatusSerializer.java | 26 ++++++++ .../jaxrs/api/TrackingDevicesResource.java | 65 +++++-------------- 6 files changed, 110 insertions(+), 60 deletions(-) create mode 100644 java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDeviceStatus.java create mode 100644 java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDeviceStatusSerializer.java diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/event/TrackingDeviceApi.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/event/TrackingDeviceApi.java index 50fb25a330c..ccde86b129d 100644 --- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/event/TrackingDeviceApi.java +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/event/TrackingDeviceApi.java @@ -20,12 +20,12 @@ public class TrackingDeviceApi { super(json); } - public UUID getDeviceUUID() { - return UUID.fromString(get("deviceUUID")); + public String getDeviceId() { + return (String) ((JSONObject)get("deviceId")).get("id"); } - public GPSFixResponse getLastFix() { - JSONObject jsonObject = get("lastFix"); + public GPSFixResponse getLastGPSFix() { + JSONObject jsonObject = get("lastGPSFix"); return jsonObject == null ? null : new GPSFixResponse(jsonObject); } } diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/TrackingDeviceStatusApiTest.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/TrackingDeviceStatusApiTest.java index 009e4c3a4b3..b9ea508e29c 100644 --- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/TrackingDeviceStatusApiTest.java +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/TrackingDeviceStatusApiTest.java @@ -35,14 +35,14 @@ public class TrackingDeviceStatusApiTest extends AbstractSeleniumTest { final UUID deviceUUID = UUID.randomUUID(); final ApiContext ctx = createAdminApiContext(getContextRoot(), SERVER_CONTEXT); final DeviceStatus statusBeforeFix = trackingDeviceApi.getDeviceStatus(ctx, deviceUUID); - assertEquals(deviceUUID, statusBeforeFix.getDeviceUUID()); - assertNull(statusBeforeFix.getLastFix()); + assertEquals(deviceUUID.toString(), statusBeforeFix.getDeviceId()); + assertNull(statusBeforeFix.getLastGPSFix()); final long fix1Millis = System.currentTimeMillis() - 100; final GpsFixMoving fix1 = createFix(49.121, 8.5987, fix1Millis, 10.0, 180.0); gpsFixApi.postGpsFix(ctx, deviceUUID, fix1); final DeviceStatus statusWithFix1 = trackingDeviceApi.getDeviceStatus(ctx, deviceUUID); - final GPSFixResponse lastFix1 = statusWithFix1.getLastFix(); + final GPSFixResponse lastFix1 = statusWithFix1.getLastGPSFix(); assertNotNull(lastFix1); assertEquals(fix1Millis, lastFix1.getTime()); @@ -50,6 +50,6 @@ public class TrackingDeviceStatusApiTest extends AbstractSeleniumTest { final GpsFixMoving fix2 = createFix(49.12, 8.599, fix2Millis, 10.0, 180.0); gpsFixApi.postGpsFix(ctx, deviceUUID, fix2); final DeviceStatus statusWithFix2 = trackingDeviceApi.getDeviceStatus(ctx, deviceUUID); - assertEquals(fix2Millis, statusWithFix2.getLastFix().getTime()); + assertEquals(fix2Millis, statusWithFix2.getLastGPSFix().getTime()); } } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/AbstractSailingServerResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/AbstractSailingServerResource.java index bfb8670b99a..45f24382036 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/AbstractSailingServerResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/AbstractSailingServerResource.java @@ -16,7 +16,9 @@ import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.server.interfaces.RacingEventService; import com.sap.sse.InvalidDateException; import com.sap.sse.common.TimePoint; +import com.sap.sse.common.TypeBasedServiceFinderFactory; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.osgi.CachedOsgiTypeBasedServiceFinderFactory; import com.sap.sse.replication.ReplicationService; import com.sap.sse.security.SecurityService; import com.sap.sse.util.DateParser; @@ -36,8 +38,7 @@ public abstract class AbstractSailingServerResource { } public T getService(Class clazz) { - BundleContext context = (BundleContext) servletContext - .getAttribute(RestServletContainer.OSGI_RFC66_WEBBUNDLE_BUNDLECONTEXT_NAME); + BundleContext context = getBundleContext(); ServiceTracker tracker = new ServiceTracker(context, clazz, null); tracker.open(); T service = tracker.getService(); @@ -45,6 +46,16 @@ public abstract class AbstractSailingServerResource { return service; } + protected BundleContext getBundleContext() { + BundleContext context = (BundleContext) servletContext + .getAttribute(RestServletContainer.OSGI_RFC66_WEBBUNDLE_BUNDLECONTEXT_NAME); + return context; + } + + protected TypeBasedServiceFinderFactory getServiceFinderFactory () { + return new CachedOsgiTypeBasedServiceFinderFactory(getBundleContext()); + } + public RacingEventService getService() { @SuppressWarnings("unchecked") ServiceTracker tracker = (ServiceTracker) servletContext.getAttribute(RestServletContainer.RACING_EVENT_SERVICE_TRACKER_NAME); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDeviceStatus.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDeviceStatus.java new file mode 100644 index 00000000000..7fe01e9c867 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDeviceStatus.java @@ -0,0 +1,48 @@ +package com.sap.sailing.server.gateway.jaxrs.api; + +import java.util.Collections; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import com.sap.sailing.domain.common.DeviceIdentifier; +import com.sap.sailing.domain.common.tracking.GPSFix; +import com.sap.sailing.server.interfaces.RacingEventService; +import com.sap.sse.common.Timed; + +public final class TrackingDeviceStatus { + private static final Logger logger = Logger.getLogger(TrackingDeviceStatus.class.getName()); + private final DeviceIdentifier deviceId; + private final GPSFix lastFix; + + public TrackingDeviceStatus(DeviceIdentifier deviceId, GPSFix lastFix) { + this.deviceId = deviceId; + this.lastFix = lastFix; + } + + public DeviceIdentifier getDeviceId() { + return deviceId; + } + + public GPSFix getLastGPSFix() { + return lastFix; + } + + public static TrackingDeviceStatus calculateDeviceStatus(DeviceIdentifier deviceIdentifier, RacingEventService service) { + try { + Map lastFixMap = service.getSensorFixStore().getLastFix(Collections.singletonList(deviceIdentifier)); + Timed lastFix = lastFixMap.get(deviceIdentifier); + GPSFix lastGPSFix = lastFix instanceof GPSFix ? (GPSFix) lastFix : null; + return new TrackingDeviceStatus(deviceIdentifier, lastGPSFix); + } catch (Exception e) { + final String errorMessage = "Error while loading device status for device " + deviceIdentifier; + logger.log(Level.SEVERE, errorMessage, e); + throw new WebApplicationException( + Response.status(Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(errorMessage).build()); + } + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDeviceStatusSerializer.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDeviceStatusSerializer.java new file mode 100644 index 00000000000..37f0a23b7c3 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDeviceStatusSerializer.java @@ -0,0 +1,26 @@ +package com.sap.sailing.server.gateway.jaxrs.api; + +import org.json.simple.JSONObject; + +import com.sap.sailing.domain.common.DeviceIdentifier; +import com.sap.sailing.server.gateway.serialization.JsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.GPSFixJsonSerializer; + +public final class TrackingDeviceStatusSerializer implements JsonSerializer { + private final GPSFixJsonSerializer gpsFixSerializer = new GPSFixJsonSerializer(); + private final JsonSerializer deviceIdSerializer; + + public TrackingDeviceStatusSerializer(JsonSerializer deviceIdSerializer) { + this.deviceIdSerializer = deviceIdSerializer; + } + + @Override + public JSONObject serialize(TrackingDeviceStatus deviceStatus) { + JSONObject result = new JSONObject(); + result.put("deviceId", deviceIdSerializer.serialize(deviceStatus.getDeviceId())); + if (deviceStatus.getLastGPSFix() != null) { + result.put("lastGPSFix", gpsFixSerializer.serialize(deviceStatus.getLastGPSFix())); + } + return result; + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDevicesResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDevicesResource.java index c81555198b1..53633cad4e6 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDevicesResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDevicesResource.java @@ -1,92 +1,57 @@ package com.sap.sailing.server.gateway.jaxrs.api; -import java.util.Collections; -import java.util.Map; import java.util.Set; import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; -import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import com.sap.sailing.domain.common.DeviceIdentifier; -import com.sap.sailing.domain.common.tracking.GPSFix; import com.sap.sailing.domain.racelogtracking.impl.SmartphoneUUIDIdentifierImpl; import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource; import com.sap.sailing.server.gateway.serialization.JsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.GPSFixJsonSerializer; -import com.sap.sse.common.Timed; +import com.sap.sailing.server.gateway.serialization.impl.DeviceIdentifierJsonSerializer; +import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler; @Path("/v1/tracking_devices") public class TrackingDevicesResource extends AbstractSailingServerResource { - private static final Logger logger = Logger.getLogger(TrackingDevicesResource.class.getName()); - private final JsonSerializer serializer = new DeviceStatusSerializer(); - - private static final class DeviceStatus { - private final UUID deviceUUID; - private final GPSFix lastFix; - - public DeviceStatus(UUID deviceUUID, GPSFix lastFix) { - this.deviceUUID = deviceUUID; - this.lastFix = lastFix; - } - } - - private static final class DeviceStatusSerializer implements JsonSerializer { - private final GPSFixJsonSerializer gpsFixSerializer = new GPSFixJsonSerializer(); - @Override - public JSONObject serialize(DeviceStatus deviceStatus) { - JSONObject result = new JSONObject(); - result.put("deviceUUID", deviceStatus.deviceUUID.toString()); - if (deviceStatus.lastFix != null) { - result.put("lastFix", gpsFixSerializer.serialize(deviceStatus.lastFix)); - } - return result; - } - } @GET @Produces("application/json;charset=UTF-8") @Path("{deviceUUID}") public Response getDeviceStatus(@PathParam("deviceUUID") UUID deviceUUID) { - JSONObject result = serializer.serialize(calculateDeviceStatus(deviceUUID)); - return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + final JsonSerializer serializer = new TrackingDeviceStatusSerializer( + new DeviceIdentifierJsonSerializer( + getServiceFinderFactory().createServiceFinder(DeviceIdentifierJsonHandler.class))); + final JSONObject result = serializer.serialize(calculateDeviceStatus(deviceUUID)); + return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") + .build(); } @GET @Produces("application/json;charset=UTF-8") public Response getDeviceStatuses(@QueryParam("deviceUUIDs") Set deviceUUIDs) { - JSONArray result = new JSONArray(); + final JsonSerializer serializer = new TrackingDeviceStatusSerializer( + new DeviceIdentifierJsonSerializer( + getServiceFinderFactory().createServiceFinder(DeviceIdentifierJsonHandler.class))); + final JSONArray result = new JSONArray(); for (UUID deviceUUID : deviceUUIDs) { result.add(serializer.serialize(calculateDeviceStatus(deviceUUID))); } return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") .build(); } - - private DeviceStatus calculateDeviceStatus(UUID deviceUUID) { + + private TrackingDeviceStatus calculateDeviceStatus(UUID deviceUUID) { final DeviceIdentifier deviceIdentifier = new SmartphoneUUIDIdentifierImpl(deviceUUID); - try { - Map lastFixMap = getService().getSensorFixStore().getLastFix(Collections.singletonList(deviceIdentifier)); - Timed lastFix = lastFixMap.get(deviceIdentifier); - GPSFix lastGPSFix = lastFix instanceof GPSFix ? (GPSFix) lastFix : null; - return new DeviceStatus(deviceUUID, lastGPSFix); - } catch (Exception e) { - final String errorMessage = "Error while loading device status for device " + deviceUUID; - logger.log(Level.SEVERE, errorMessage, e); - throw new WebApplicationException( - Response.status(Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(errorMessage).build()); - } + return TrackingDeviceStatus.calculateDeviceStatus(deviceIdentifier, getService()); } } \ No newline at end of file From 2af26765cfdf10085ae8e1fd1041d3376b372829 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 24 Jul 2019 15:07:34 +0200 Subject: [PATCH 04/43] Bug 5101: Added an API to get the device statuses associated to a regatta --- .../gateway/jaxrs/api/RegattasResource.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java index 37b72572b01..caf7f9ad80d 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java @@ -17,6 +17,7 @@ import java.util.concurrent.Callable; import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; import javax.ws.rs.Consumes; import javax.ws.rs.DefaultValue; @@ -46,6 +47,8 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent; import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent; import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEventImpl; import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl; +import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceMappingFinder; +import com.sap.sailing.domain.base.Boat; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CompetitorWithBoat; import com.sap.sailing.domain.base.Course; @@ -77,6 +80,7 @@ import com.sap.sailing.domain.common.tracking.GPSFix; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; +import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent; import com.sap.sailing.domain.racelogtracking.impl.SmartphoneUUIDIdentifierImpl; import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.tracking.DynamicTrackedRace; @@ -107,6 +111,7 @@ import com.sap.sailing.server.gateway.serialization.impl.CompleteManeuverCurveWi import com.sap.sailing.server.gateway.serialization.impl.CompleteManeuverCurvesWithEstimationDataJsonSerializer; import com.sap.sailing.server.gateway.serialization.impl.DefaultWindTrackJsonSerializer; import com.sap.sailing.server.gateway.serialization.impl.DetailedBoatClassJsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.DeviceIdentifierJsonSerializer; import com.sap.sailing.server.gateway.serialization.impl.DistanceJsonSerializer; import com.sap.sailing.server.gateway.serialization.impl.FleetJsonSerializer; import com.sap.sailing.server.gateway.serialization.impl.GPSFixJsonSerializer; @@ -129,6 +134,7 @@ import com.sap.sailing.server.gateway.serialization.impl.TargetTimeInfoSerialize import com.sap.sailing.server.gateway.serialization.impl.TeamJsonSerializer; import com.sap.sailing.server.gateway.serialization.impl.TrackedRaceJsonSerializer; import com.sap.sailing.server.gateway.serialization.impl.WindJsonSerializer; +import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler; import com.sap.sailing.server.operationaltransformation.AddColumnToSeries; import com.sap.sailing.server.operationaltransformation.UpdateSeries; import com.sap.sse.InvalidDateException; @@ -139,6 +145,7 @@ import com.sap.sse.common.Speed; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; +import com.sap.sse.common.WithID; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.RGBColor; @@ -2277,4 +2284,47 @@ public class RegattasResource extends AbstractSailingServerResource { } return Response.ok().header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } + + @GET + @Produces("application/json;charset=UTF-8") + @Path("{regattaname}/tracking_devices") + public Response getTrackingStatus(@PathParam("regattaName") String regattaName) { + Regatta regatta = getService().getRegattaByName(regattaName); + if (regatta != null) { + // Deeper insights to tracking data is only available to users who can administer a regatta + SecurityUtils.getSubject().checkPermission(regatta.getIdentifier().getStringPermission(DefaultActions.UPDATE)); + + TrackingDeviceStatusSerializer serializer = new TrackingDeviceStatusSerializer(new DeviceIdentifierJsonSerializer( + getServiceFinderFactory().createServiceFinder(DeviceIdentifierJsonHandler.class))); + + RegattaLogDeviceMappingFinder regattaLogDeviceMappingFinder = new RegattaLogDeviceMappingFinder(regatta.getRegattaLog()); + Map>> foundMappings = regattaLogDeviceMappingFinder.analyze(); + + JSONObject result = new JSONObject(); + foundMappings.forEach((item, mappings) -> { + JSONArray deviceStatusesOfTrackedItem = new JSONArray(); + mappings.stream().map(DeviceMappingWithRegattaLogEvent::getDevice).collect(Collectors.toSet()) + .forEach(deviceIdentifier -> { + deviceStatusesOfTrackedItem.add(serializer.serialize( + TrackingDeviceStatus.calculateDeviceStatus(deviceIdentifier, getService()))); + }); + JSONObject itemObject = new JSONObject(); + itemObject.put("deviceStatuses", deviceStatusesOfTrackedItem); + if (item instanceof Competitor) { + itemObject.put("competitorId", item.getId().toString()); + ((JSONArray) result.computeIfAbsent("competitors", k -> new JSONArray())).add(itemObject); + } else if (item instanceof Boat) { + itemObject.put("boatId", item.getId().toString()); + ((JSONArray) result.computeIfAbsent("boats", k -> new JSONArray())).add(itemObject); + } else if (item instanceof Mark) { + itemObject.put("markId", item.getId().toString()); + ((JSONArray) result.computeIfAbsent("marks", k -> new JSONArray())).add(itemObject); + } + }); + return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") + .build(); + } else { + throw new IllegalStateException("Regatta named " + regattaName + " could not be resolved"); + } + } } From cec4e4e2ecadf9ec88e1562f3f5875734964ef35 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 24 Jul 2019 15:19:54 +0200 Subject: [PATCH 05/43] Bug 5101: Consistent naming --- .../sap/sailing/server/gateway/jaxrs/api/RegattasResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java index caf7f9ad80d..5adc05ff402 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java @@ -2287,7 +2287,7 @@ public class RegattasResource extends AbstractSailingServerResource { @GET @Produces("application/json;charset=UTF-8") - @Path("{regattaname}/tracking_devices") + @Path("{regattaName}/tracking_devices") public Response getTrackingStatus(@PathParam("regattaName") String regattaName) { Regatta regatta = getService().getRegattaByName(regattaName); if (regatta != null) { From 640e25837bad7bf14201e41206f46040fde648a5 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 24 Jul 2019 16:37:22 +0200 Subject: [PATCH 06/43] Bug 5101: Added docs --- .../webservices/api/v1/index.html | 12 +++++ .../api/v1/regattasTrackingDevicesGet.html | 46 +++++++++++++++++++ .../api/v1/trackingDeviceStatusGet.html | 46 +++++++++++++++++++ .../api/v1/trackingDeviceStatusesGet.html | 46 +++++++++++++++++++ 4 files changed, 150 insertions(+) create mode 100644 java/com.sap.sailing.server.gateway/webservices/api/v1/regattasTrackingDevicesGet.html create mode 100644 java/com.sap.sailing.server.gateway/webservices/api/v1/trackingDeviceStatusGet.html create mode 100644 java/com.sap.sailing.server.gateway/webservices/api/v1/trackingDeviceStatusesGet.html diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/index.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/index.html index 82a2df2eab7..dfeeccef5fb 100644 --- a/java/com.sap.sailing.server.gateway/webservices/api/v1/index.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/index.html @@ -161,6 +161,10 @@ name to make sure you get to the event you're interested in. /api/v1/regattas/{regattaname}/competitors/{competitorId}/remove Removes a competitor from a regatta (POST) + + /api/v1/regattas/{regattaName}/tracking_devices + Gets the status for all GPS trackers associated to a regatta (GET) + /api/v1/regattas/{regattaname}/races/{racename}/datamining/{queryidentifier} Executes the query for the race and gets the result @@ -356,6 +360,14 @@ name to make sure you get to the event you're interested in. /api/v1/trackedevents Delete a tracked event for the current user. + + /api/v1/tracking_devices/{deviceUUID} + Gets the status of an app based tracking device (GET) + + + /api/v1/tracking_devices + Gets the status of multiple app based tracking devices (GET) +
diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/regattasTrackingDevicesGet.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/regattasTrackingDevicesGet.html new file mode 100644 index 00000000000..bc1ab66ccb2 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/regattasTrackingDevicesGet.html @@ -0,0 +1,46 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 + + +

SAP Sailing Analytics Webservices API Version 1.0

+

URL: /api/v1/regattas/{regattaName}/tracking_devices

+ +Description: +

The service gets the status of all GPS tracking devices associated to the regatta. The user needs to have UPDATE permission granted to be allowed to access tracking device data.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters:None
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/regattas/Kornati Cup 2019 - SUP Contest/tracking_devices
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/trackingDeviceStatusGet.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/trackingDeviceStatusGet.html new file mode 100644 index 00000000000..23fd993c46b --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/trackingDeviceStatusGet.html @@ -0,0 +1,46 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 + + +

SAP Sailing Analytics Webservices API Version 1.0

+

URL: /api/v1/tracking_devices/{deviceUUID}

+ +Description: +

The service gets the status of an app based tracker defined by the given UUID.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters:None
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/tracking_devices/dc77e3d1-d405-435e-8699-ce7245a6fd4a
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/trackingDeviceStatusesGet.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/trackingDeviceStatusesGet.html new file mode 100644 index 00000000000..c34e36e1b96 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/trackingDeviceStatusesGet.html @@ -0,0 +1,46 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 + + +

SAP Sailing Analytics Webservices API Version 1.0

+

URL: /api/v1/tracking_devices/{deviceUUID}

+ +Description: +

The service gets the status of app based trackers defined by their respective UUID.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:deviceUUIDs: UUIDs of the devices to get the status for (multiple occurrences of the parameter are allowed)
Optional parameters:None
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/tracking_devices?deviceUUIDs=dc77e3d1-d405-435e-8699-ce7245a6fd4a&deviceUUIDs=dc77e3d1-d405-435e-8699-ce7245a6fd4b
+
+Back to Web Service Overview + + From 4209e5c2a37e47921376c24cf641c1b7ac973319 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 24 Jul 2019 16:58:17 +0200 Subject: [PATCH 07/43] Bug 5101: Refactoring for reusability --- .../selenium/api/core/DeviceStatus.java | 18 ++++++++++++ .../selenium/api/core/GPSFixResponse.java | 13 +++++++++ .../selenium/api/event/TrackingDeviceApi.java | 29 +------------------ .../api/test/TrackingDeviceStatusApiTest.java | 4 +-- 4 files changed, 34 insertions(+), 30 deletions(-) create mode 100644 java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/DeviceStatus.java create mode 100644 java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/GPSFixResponse.java diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/DeviceStatus.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/DeviceStatus.java new file mode 100644 index 00000000000..7147936d827 --- /dev/null +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/DeviceStatus.java @@ -0,0 +1,18 @@ +package com.sap.sailing.selenium.api.core; + +import org.json.simple.JSONObject; + +public class DeviceStatus extends JsonWrapper { + public DeviceStatus(JSONObject json) { + super(json); + } + + public String getDeviceId() { + return (String) ((JSONObject)get("deviceId")).get("id"); + } + + public GPSFixResponse getLastGPSFix() { + JSONObject jsonObject = get("lastGPSFix"); + return jsonObject == null ? null : new GPSFixResponse(jsonObject); + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/GPSFixResponse.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/GPSFixResponse.java new file mode 100644 index 00000000000..0153fe1a6d6 --- /dev/null +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/GPSFixResponse.java @@ -0,0 +1,13 @@ +package com.sap.sailing.selenium.api.core; + +import org.json.simple.JSONObject; + +public class GPSFixResponse extends JsonWrapper { + public GPSFixResponse(JSONObject json) { + super(json); + } + + public long getTime() { + return ((Number)get("unixtime")).longValue(); + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/event/TrackingDeviceApi.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/event/TrackingDeviceApi.java index ccde86b129d..a769e8e8313 100644 --- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/event/TrackingDeviceApi.java +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/event/TrackingDeviceApi.java @@ -2,10 +2,8 @@ package com.sap.sailing.selenium.api.event; import java.util.UUID; -import org.json.simple.JSONObject; - import com.sap.sailing.selenium.api.core.ApiContext; -import com.sap.sailing.selenium.api.core.JsonWrapper; +import com.sap.sailing.selenium.api.core.DeviceStatus; public class TrackingDeviceApi { @@ -14,29 +12,4 @@ public class TrackingDeviceApi { public DeviceStatus getDeviceStatus(ApiContext ctx, UUID deviceUUID) { return new DeviceStatus(ctx.get(BASE_PATH + "/" + deviceUUID.toString())); } - - public class DeviceStatus extends JsonWrapper { - private DeviceStatus(JSONObject json) { - super(json); - } - - public String getDeviceId() { - return (String) ((JSONObject)get("deviceId")).get("id"); - } - - public GPSFixResponse getLastGPSFix() { - JSONObject jsonObject = get("lastGPSFix"); - return jsonObject == null ? null : new GPSFixResponse(jsonObject); - } - } - - public class GPSFixResponse extends JsonWrapper { - private GPSFixResponse(JSONObject json) { - super(json); - } - - public long getTime() { - return ((Number)get("unixtime")).longValue(); - } - } } diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/TrackingDeviceStatusApiTest.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/TrackingDeviceStatusApiTest.java index b9ea508e29c..7ee6e914eb6 100644 --- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/TrackingDeviceStatusApiTest.java +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/TrackingDeviceStatusApiTest.java @@ -13,11 +13,11 @@ import org.junit.Before; import org.junit.Test; import com.sap.sailing.selenium.api.core.ApiContext; +import com.sap.sailing.selenium.api.core.DeviceStatus; +import com.sap.sailing.selenium.api.core.GPSFixResponse; import com.sap.sailing.selenium.api.core.GpsFixMoving; import com.sap.sailing.selenium.api.event.GpsFixApi; import com.sap.sailing.selenium.api.event.TrackingDeviceApi; -import com.sap.sailing.selenium.api.event.TrackingDeviceApi.DeviceStatus; -import com.sap.sailing.selenium.api.event.TrackingDeviceApi.GPSFixResponse; import com.sap.sailing.selenium.test.AbstractSeleniumTest; public class TrackingDeviceStatusApiTest extends AbstractSeleniumTest { From 5d483b73aa4c20ed2c38bc941bc9f90ee8c9d788 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 24 Jul 2019 16:59:04 +0200 Subject: [PATCH 08/43] Bug 5101: Extended regatta test API to read the tracking device status --- .../selenium/api/regatta/RegattaApi.java | 7 +- .../api/regatta/RegattaDeviceStatus.java | 77 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/regatta/RegattaDeviceStatus.java diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/regatta/RegattaApi.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/regatta/RegattaApi.java index ad892d30766..8131eb13716 100644 --- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/regatta/RegattaApi.java +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/regatta/RegattaApi.java @@ -19,6 +19,7 @@ public class RegattaApi { private static final String ADD = "/add"; private static final String ADD_RACE_COLUMN_URL = "/addracecolumns"; private static final String LIST_COMPETITORS = "/competitors"; + private static final String TRACKING_DEVICES = "/tracking_devices"; public Regatta getRegatta(ApiContext ctx, String regattaName) { return new Regatta(ctx.get(REGATTAS + "/" + regattaName)); @@ -96,5 +97,9 @@ public class RegattaApi { queryParams.put("secret", secret.orElse(null)); ctx.post(url, queryParams); } - + + public RegattaDeviceStatus getTrackingDeviceStatus(ApiContext ctx, String regattaName) { + final String url = REGATTAS + "/" + regattaName + TRACKING_DEVICES; + return new RegattaDeviceStatus(ctx.get(url)); + } } diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/regatta/RegattaDeviceStatus.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/regatta/RegattaDeviceStatus.java new file mode 100644 index 00000000000..93bbbb631de --- /dev/null +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/regatta/RegattaDeviceStatus.java @@ -0,0 +1,77 @@ +package com.sap.sailing.selenium.api.regatta; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import com.sap.sailing.selenium.api.core.DeviceStatus; +import com.sap.sailing.selenium.api.core.JsonWrapper; + +public class RegattaDeviceStatus extends JsonWrapper { + public abstract static class TrackedItemDeviceStatus extends JsonWrapper { + public TrackedItemDeviceStatus(JSONObject json) { + super(json); + } + + public List getDeviceStatuses() { + JSONArray statusArray = get("deviceStatuses"); + return statusArray.stream().map(o -> new DeviceStatus((JSONObject) o)).collect(Collectors.toList()); + } + } + + public static class CompetitorDeviceStatus extends TrackedItemDeviceStatus { + public CompetitorDeviceStatus(JSONObject json) { + super(json); + } + + public String getCompetitorId() { + return (String) get("competitorId"); + } + } + + public static class BoatDeviceStatus extends TrackedItemDeviceStatus { + public BoatDeviceStatus(JSONObject json) { + super(json); + } + + public String getBoatId() { + return (String) get("boatId"); + } + } + + public static class MarkDeviceStatus extends TrackedItemDeviceStatus { + public MarkDeviceStatus(JSONObject json) { + super(json); + } + + public String getMarkId() { + return (String) get("markId"); + } + } + + public RegattaDeviceStatus(JSONObject json) { + super(json); + } + + public List getCompetitors() { + Object jsonObjectOrNull = get("competitors"); + return jsonObjectOrNull instanceof JSONArray ? ((JSONArray) jsonObjectOrNull).stream() + .map(o -> new CompetitorDeviceStatus((JSONObject) o)).collect(Collectors.toList()) + : Collections.emptyList(); + } + + public List getBoats() { + Object jsonObjectOrNull = get("boats"); + return jsonObjectOrNull instanceof JSONArray ? ((JSONArray) jsonObjectOrNull).stream() + .map(o -> new BoatDeviceStatus((JSONObject) o)).collect(Collectors.toList()) : Collections.emptyList(); + } + + public List getMarks() { + Object jsonObjectOrNull = get("marks"); + return jsonObjectOrNull instanceof JSONArray ? ((JSONArray) jsonObjectOrNull).stream() + .map(o -> new MarkDeviceStatus((JSONObject) o)).collect(Collectors.toList()) : Collections.emptyList(); + } +} \ No newline at end of file From d598792cfb9955985efc2745454bb3358bfcd9fa Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 25 Jul 2019 09:01:29 +0200 Subject: [PATCH 09/43] Bug 5101: Initial API test for tracking device status of a regatta --- .../selenium/api/test/RegattaApiTest.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/RegattaApiTest.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/RegattaApiTest.java index 4c675b433f9..66e8b9a80ed 100644 --- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/RegattaApiTest.java +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/RegattaApiTest.java @@ -1,9 +1,11 @@ package com.sap.sailing.selenium.api.test; import static com.sap.sailing.domain.common.CompetitorRegistrationType.CLOSED; +import static com.sap.sailing.domain.common.CompetitorRegistrationType.OPEN_UNMODERATED; import static com.sap.sailing.selenium.api.core.ApiContext.SERVER_CONTEXT; import static com.sap.sailing.selenium.api.core.ApiContext.createAdminApiContext; import static com.sap.sailing.selenium.api.core.ApiContext.createApiContext; +import static com.sap.sailing.selenium.api.core.GpsFixMoving.createFix; import static com.sap.sailing.selenium.pages.adminconsole.AdminConsolePage.goToPage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -11,8 +13,11 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.UUID; +import java.util.stream.Collectors; import org.json.simple.JSONArray; import org.json.simple.JSONObject; @@ -22,8 +27,10 @@ import org.junit.Test; import com.sap.sailing.domain.common.CompetitorRegistrationType; import com.sap.sailing.selenium.api.core.ApiContext; +import com.sap.sailing.selenium.api.core.DeviceStatus; import com.sap.sailing.selenium.api.event.EventApi; import com.sap.sailing.selenium.api.event.EventApi.Event; +import com.sap.sailing.selenium.api.event.GpsFixApi; import com.sap.sailing.selenium.api.event.LeaderboardApi; import com.sap.sailing.selenium.api.event.SecurityApi; import com.sap.sailing.selenium.api.event.UserGroupApi; @@ -32,6 +39,8 @@ import com.sap.sailing.selenium.api.regatta.Competitor; import com.sap.sailing.selenium.api.regatta.RaceColumn; import com.sap.sailing.selenium.api.regatta.Regatta; import com.sap.sailing.selenium.api.regatta.RegattaApi; +import com.sap.sailing.selenium.api.regatta.RegattaDeviceStatus; +import com.sap.sailing.selenium.api.regatta.RegattaDeviceStatus.CompetitorDeviceStatus; import com.sap.sailing.selenium.api.regatta.RegattaRaces; import com.sap.sailing.selenium.pages.adminconsole.AdminConsolePage; import com.sap.sailing.selenium.test.AbstractSeleniumTest; @@ -46,6 +55,7 @@ public class RegattaApiTest extends AbstractSeleniumTest { private final RegattaApi regattaApi = new RegattaApi(); private final LeaderboardApi leaderboardApi = new LeaderboardApi(); private final UserGroupApi usergroupApi = new UserGroupApi(); + private final GpsFixApi gpsFixApi = new GpsFixApi(); @Before public void setUp() { @@ -228,4 +238,42 @@ public class RegattaApiTest extends AbstractSeleniumTest { assertEquals(0, competitors.length); } + + @Test + public void testTrackingDeviceStatus() { + final ApiContext ctx = createAdminApiContext(getContextRoot(), SERVER_CONTEXT); + + Event event = eventApi.createEvent(ctx, EVENT_NAME, BOAT_CLASS, OPEN_UNMODERATED, "default"); + final UUID competitor1DeviceID = UUID.randomUUID(); + final Competitor competitor1 = regattaApi.createAndAddCompetitorWithSecret(ctx, EVENT_NAME, BOAT_CLASS, "test@de", "Max", + "USA", event.getSecret(), competitor1DeviceID); + final UUID competitor2DeviceID = UUID.randomUUID(); + final Competitor competitor2 = regattaApi.createAndAddCompetitorWithSecret(ctx, EVENT_NAME, BOAT_CLASS, "test@de", + "Peter", "USA", event.getSecret(), competitor2DeviceID); + + final long timeMillisCompetitor1 = System.currentTimeMillis(); + gpsFixApi.postGpsFix(ctx, competitor1DeviceID, createFix(49.121, 8.5987, timeMillisCompetitor1, 10.0, 180.0)); + final long timeMillisCompetitor2 = System.currentTimeMillis() - 50; + gpsFixApi.postGpsFix(ctx, competitor2DeviceID, createFix(49.120, 8.5988, timeMillisCompetitor2, 10.0, 180.0)); + + final RegattaDeviceStatus trackingDeviceStatus = regattaApi.getTrackingDeviceStatus(ctx, EVENT_NAME); + + final List competitorsTrackingDeviceStatus = trackingDeviceStatus.getCompetitors(); + assertEquals(2, competitorsTrackingDeviceStatus.size()); + final Map> statusByCompetitorUUID = competitorsTrackingDeviceStatus.stream() + .collect(Collectors.toMap(c -> UUID.fromString(c.getCompetitorId()), c -> c.getDeviceStatuses())); + assertTrue(statusByCompetitorUUID.containsKey(competitor1.getId())); + assertTrue(statusByCompetitorUUID.containsKey(competitor2.getId())); + + List competitor1DeviceStatuses = statusByCompetitorUUID.get(competitor1.getId()); + assertEquals(1, competitor1DeviceStatuses.size()); + DeviceStatus competitor1DeviceStatus = competitor1DeviceStatuses.iterator().next(); + assertEquals(competitor1DeviceID.toString(), competitor1DeviceStatus.getDeviceId()); + assertEquals(timeMillisCompetitor1, competitor1DeviceStatus.getLastGPSFix().getTime()); + List competitor2DeviceStatuses = statusByCompetitorUUID.get(competitor2.getId()); + assertEquals(1, competitor1DeviceStatuses.size()); + DeviceStatus competitor2DeviceStatus = competitor2DeviceStatuses.iterator().next(); + assertEquals(competitor2DeviceID.toString(), competitor2DeviceStatus.getDeviceId()); + assertEquals(timeMillisCompetitor2, competitor2DeviceStatus.getLastGPSFix().getTime()); + } } From ff908c20c3cb7cbbd4627f022feb3a0e0db7ed3c Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 30 Jul 2019 15:25:12 +0200 Subject: [PATCH 10/43] Bug 5092: added "hide elements w/o update rights" checkbox to filter panel --- .../panels/AbstractFilterablePanel.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java index 2256ae4c13b..1b548e8e7cf 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java @@ -11,6 +11,7 @@ import com.google.gwt.event.dom.client.KeyUpHandler; import com.google.gwt.user.cellview.client.AbstractCellTable; import com.google.gwt.user.cellview.client.CellTable; import com.google.gwt.user.cellview.client.ColumnSortEvent; +import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Panel; @@ -49,8 +50,38 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { protected ListDataProvider all; protected final ListDataProvider filtered; protected final TextBox textBox; + protected final CheckBox checkbox; private final Set> filters = new HashSet<>(); + private final CheckboxEnablableFilter checkboxFilter; + + static class CheckboxEnablableFilter implements Filter { + + private final CheckBox checkbox; + private Filter filterToApply; + + public CheckboxEnablableFilter(CheckBox checkbox) { + this.checkbox = checkbox; + } + + @Override + public boolean matches(T object) { + if (!this.checkbox.getValue()) { + return true; + } + return filterToApply.matches(object); + } + + @Override + public String getName() { + return filterToApply.getName(); + } + + public void setFilterToApply(Filter filterToApply) { + this.filterToApply = filterToApply; + } + + } protected final AbstractKeywordFilter filterer = new AbstractKeywordFilter() { @Override @@ -79,6 +110,9 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { this.filtered = filtered; this.textBox = new TextBox(); this.textBox.ensureDebugId("FilterTextBox"); + // TODO: i18n + this.checkbox = new CheckBox("Hide elements w/o update rights"); + checkboxFilter = new CheckboxEnablableFilter<>(checkbox); this.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); setAll(all); if (drawTextBox) { @@ -221,6 +255,11 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { }); } + public void addDefaultCheckBox() { + add(getCheckBox()); + getCheckBox().addClickHandler(e -> filter()); + } + public void search(String searchString) { getTextBox().setText(searchString); filterer.setKeywords(Util.splitAlongWhitespaceRespectingDoubleQuotedPhrases(searchString)); @@ -231,6 +270,14 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { return textBox; } + public CheckBox getCheckBox() { + return checkbox; + } + + public void setCheckboxEnabledFilter(Filter filter) { + this.checkboxFilter.setFilterToApply(filter); + } + public Iterable getAll() { return all.getList(); } From a5d2d2fb70a02d1fdf6711d0aa66a46df08bb04e Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 30 Jul 2019 15:27:47 +0200 Subject: [PATCH 11/43] Bug 5092: adjusted new checkbox to be hidden and deactivated per default + added utilization of new checkbox in EventListComposite --- .../gwt/ui/adminconsole/EventListComposite.java | 13 +++++++++++++ .../client/panels/AbstractFilterablePanel.java | 17 ++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java index 16749247f6d..ad43cf4609f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java @@ -57,6 +57,7 @@ import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; import com.sap.sailing.gwt.ui.shared.RegattaDTO; import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; +import com.sap.sse.common.filter.Filter; import com.sap.sse.common.util.NaturalComparator; import com.sap.sse.gwt.adminconsole.AdminConsoleTableResources; import com.sap.sse.gwt.adminconsole.HandleTabSelectable; @@ -215,6 +216,18 @@ public class EventListComposite extends Composite implements EventsRefresher, Le panel.add(noEventsLabel); fillEvents(); initWidget(panel); + filterTextbox.setCheckboxEnabledFilter(new Filter() { + + @Override + public boolean matches(EventDTO object) { + return userService.hasPermission(object, DefaultActions.UPDATE); + } + + @Override + public String getName() { + return "Update Permission Filter"; + } + }); } private CellTable createEventTable(UserDTO user) { diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java index 1b548e8e7cf..b162ade05e5 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java @@ -55,6 +55,8 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { private final Set> filters = new HashSet<>(); private final CheckboxEnablableFilter checkboxFilter; + private boolean added = false; + static class CheckboxEnablableFilter implements Filter { private final CheckBox checkbox; @@ -66,6 +68,9 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { @Override public boolean matches(T object) { + if (filterToApply == null) { + return true; + } if (!this.checkbox.getValue()) { return true; } @@ -112,7 +117,9 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { this.textBox.ensureDebugId("FilterTextBox"); // TODO: i18n this.checkbox = new CheckBox("Hide elements w/o update rights"); + checkbox.setValue(true); checkboxFilter = new CheckboxEnablableFilter<>(checkbox); + filters.add(checkboxFilter); this.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); setAll(all); if (drawTextBox) { @@ -255,9 +262,12 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { }); } - public void addDefaultCheckBox() { - add(getCheckBox()); - getCheckBox().addClickHandler(e -> filter()); + public void addDefaultCheckBoxIfNecessary() { + if (!added) { + add(getCheckBox()); + getCheckBox().addClickHandler(e -> filter()); + added = true; + } } public void search(String searchString) { @@ -276,6 +286,7 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { public void setCheckboxEnabledFilter(Filter filter) { this.checkboxFilter.setFilterToApply(filter); + addDefaultCheckBoxIfNecessary(); } public Iterable getAll() { From 8ac44af42950bbc801dae29b9c115505e06d5d9a Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 30 Jul 2019 15:32:53 +0200 Subject: [PATCH 12/43] Bug 5092: cleanup in AbstractFilterablePanel: move boilerplate code into this class instead of spreading it around in the table classes --- .../gwt/ui/adminconsole/EventListComposite.java | 14 +------------- .../client/panels/AbstractFilterablePanel.java | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java index ad43cf4609f..d936f965cab 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java @@ -57,7 +57,6 @@ import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; import com.sap.sailing.gwt.ui.shared.RegattaDTO; import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; -import com.sap.sse.common.filter.Filter; import com.sap.sse.common.util.NaturalComparator; import com.sap.sse.gwt.adminconsole.AdminConsoleTableResources; import com.sap.sse.gwt.adminconsole.HandleTabSelectable; @@ -216,18 +215,7 @@ public class EventListComposite extends Composite implements EventsRefresher, Le panel.add(noEventsLabel); fillEvents(); initWidget(panel); - filterTextbox.setCheckboxEnabledFilter(new Filter() { - - @Override - public boolean matches(EventDTO object) { - return userService.hasPermission(object, DefaultActions.UPDATE); - } - - @Override - public String getName() { - return "Update Permission Filter"; - } - }); + filterTextbox.setCheckboxEnabledFilter(event -> userService.hasPermission(event, DefaultActions.UPDATE)); } private CellTable createEventTable(UserDTO user) { diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java index b162ade05e5..09fc61a5430 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Function; import com.google.gwt.core.client.Scheduler; import com.google.gwt.event.dom.client.KeyUpEvent; @@ -284,8 +285,19 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { return checkbox; } - public void setCheckboxEnabledFilter(Filter filter) { - this.checkboxFilter.setFilterToApply(filter); + public void setCheckboxEnabledFilter(Function filterFunction) { + + this.checkboxFilter.setFilterToApply(new Filter() { + @Override + public boolean matches(T object) { + return filterFunction.apply(object); + } + + @Override + public String getName() { + return "Update Permission Filter"; + } + }); addDefaultCheckBoxIfNecessary(); } From 1523c9511fb9b38bf02bbcd02a7698445a777001 Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 30 Jul 2019 15:41:20 +0200 Subject: [PATCH 13/43] added checkbox to Leaderboard, Races, LeaderboardGroup and Regatta list --- .../gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java | 3 +++ .../gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java | 1 + .../gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java | 2 ++ .../sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java | 2 ++ 4 files changed, 8 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java index 79ef6af15c7..7145c0beae2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java @@ -61,6 +61,7 @@ import com.sap.sse.gwt.client.celltable.RefreshableSelectionModel; import com.sap.sse.gwt.client.celltable.SelectionCheckboxColumn; import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel; +import com.sap.sse.security.shared.HasPermissions.DefaultActions; import com.sap.sse.security.shared.dto.NamedDTO; import com.sap.sse.security.ui.client.UserService; import com.sap.sse.security.ui.client.component.AccessControlledButtonPanel; @@ -199,6 +200,8 @@ public abstract class AbstractLeaderboardConfigPanel extends FormPanel } }; filterLeaderboardPanel.getTextBox().ensureDebugId("LeaderboardsFilterTextBox"); + filterLeaderboardPanel + .setCheckboxEnabledFilter(leaderboard -> userService.hasPermission(leaderboard, DefaultActions.UPDATE)); leaderboardsPanel.add(filterLeaderboardPanel); leaderboardTable.ensureDebugId("AvailableLeaderboardsTable"); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java index 405dba290a0..054aacbf233 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java @@ -205,6 +205,7 @@ public abstract class AbstractTrackedRacesListComposite extends AbstractComposit filterPanel.add(filterablePanelRaces); filterPanel.setCellVerticalAlignment(filterablePanelRaces, HasVerticalAlignment.ALIGN_MIDDLE); + filterablePanelRaces.setCheckboxEnabledFilter(race -> userService.hasPermission(race, DefaultActions.UPDATE)); refreshableSelectionModel = raceTableWrapper.getSelectionModel(); setupTableColumns(stringMessages, raceTableWrapper.getColumnSortHandler()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java index 238be6e8bd4..41465817c86 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java @@ -499,6 +499,8 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel }; groupsFilterablePanel.getTextBox().ensureDebugId("LeaderboardGroupsFilterTextBox"); leaderboardGroupsContentPanel.add(groupsFilterablePanel); + groupsFilterablePanel.setCheckboxEnabledFilter( + leaderboardGroup -> userService.hasPermission(leaderboardGroup, DefaultActions.UPDATE)); final Button createButton = buttonPanel.addCreateAction(stringMessages.createNewLeaderboardGroup(), this::addNewGroup); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java index 1a6743eb6e7..93a57939dfa 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java @@ -129,6 +129,8 @@ public class RegattaListComposite extends Composite implements RegattasDisplayer regattaTable.ensureDebugId("RegattasCellTable"); refreshableRegattaMultiSelectionModel = (RefreshableMultiSelectionModel) regattaTable.getSelectionModel(); regattaTable.setVisible(false); + filterablePanelRegattas + .setCheckboxEnabledFilter(regatta -> userService.hasPermission(regatta, DefaultActions.UPDATE)); panel.add(filterablePanelRegattas); panel.add(regattaTable); From dc5902cd00df8529137a717fec9e855ee7685da7 Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 30 Jul 2019 18:22:09 +0200 Subject: [PATCH 14/43] Bug 5092: added filter checkbox to Competitor tables --- .../ui/adminconsole/CompactCompetitorTableWrapper.java | 6 +++++- .../gwt/ui/adminconsole/CompetitorTableWrapper.java | 1 + .../ui/adminconsole/CompetitorToBoatMappingsDialog.java | 9 ++++++--- .../adminconsole/CompetitorToBoatMappingsViewPanel.java | 7 +++++-- .../gwt/ui/adminconsole/LeaderboardConfigPanel.java | 3 ++- .../adminconsole/ShowCompetitorToBoatMappingsDialog.java | 5 +++-- .../SmartphoneTrackingEventManagementPanel.java | 4 ++-- 7 files changed, 24 insertions(+), 11 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompactCompetitorTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompactCompetitorTableWrapper.java index a2bdd211038..942c6cb1aaa 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompactCompetitorTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompactCompetitorTableWrapper.java @@ -28,6 +28,8 @@ import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.celltable.EntityIdentityComparator; import com.sap.sse.gwt.client.celltable.RefreshableSelectionModel; import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel; +import com.sap.sse.security.shared.HasPermissions.DefaultActions; +import com.sap.sse.security.ui.client.UserService; /** * A compact filterable competitor table. The data model is managed by the {@link #getFilterField() filter field}. In @@ -44,7 +46,7 @@ public class CompactCompetitorTableWrapper boatsForCompetitors; public CompactCompetitorTableWrapper(SailingServiceAsync sailingService, StringMessages stringMessages, ErrorReporter errorReporter, - boolean multiSelection, boolean enablePager) { + boolean multiSelection, boolean enablePager, UserService userService) { super(sailingService, stringMessages, errorReporter, multiSelection, enablePager, new EntityIdentityComparator() { @Override @@ -148,6 +150,8 @@ public class CompactCompetitorTableWrapper userService.hasPermission(comp, DefaultActions.UPDATE)); + registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider()); mainPanel.insert(filterField, 0); table.addColumnSortHandler(competitorColumnListHandler); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java index ee2270f901e..9beb76bdd7a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java @@ -321,6 +321,7 @@ public class CompetitorTableWrapper userService.hasPermission(comp, DefaultActions.UPDATE)); registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider()); // CompetitorTableEditFeatures diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorToBoatMappingsDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorToBoatMappingsDialog.java index c50a16c26d5..da729623038 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorToBoatMappingsDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorToBoatMappingsDialog.java @@ -22,12 +22,13 @@ import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.common.Util; import com.sap.sse.gwt.client.ErrorReporter; -import com.sap.sse.gwt.client.celltable.ImagesBarColumn; import com.sap.sse.gwt.client.Notification; import com.sap.sse.gwt.client.Notification.NotificationType; +import com.sap.sse.gwt.client.celltable.ImagesBarColumn; import com.sap.sse.gwt.client.celltable.RefreshableSelectionModel; import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel; import com.sap.sse.gwt.client.dialog.DataEntryDialog; +import com.sap.sse.security.ui.client.UserService; /** * Allows an administrator to map a list of given competitors to boats for a race. @@ -60,11 +61,13 @@ public class CompetitorToBoatMappingsDialog extends DataEntryDialog competitorsAndBoats, DialogCallback> callback) { + final ErrorReporter errorReporter, String leaderboardName, Map competitorsAndBoats, + DialogCallback> callback, UserService userService) { super(stringMessages.actionEditCompetitorToBoatAssignments(), null, stringMessages.ok(), stringMessages.cancel(), new CompetitorToBoatMappingValidator(), callback); this.stringMessages = stringMessages; this.competitorToBoatMappings = new HashMap<>(competitorsAndBoats); - this.competitorTable = new CompactCompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */ false, /* enablePager */ true); + this.competitorTable = new CompactCompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, + /* multiSelection */ false, /* enablePager */ true, userService); this.boatTable = new CompactBoatTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */ false, /* enablePager */ true); ImagesBarColumn competitorActionColumn = new ImagesBarColumn<>(new CompactCompetitorConfigImagesBarCell(stringMessages)); competitorActionColumn.setFieldUpdater(new FieldUpdater() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorToBoatMappingsViewPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorToBoatMappingsViewPanel.java index 07a2c90348a..1de886e2b12 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorToBoatMappingsViewPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorToBoatMappingsViewPanel.java @@ -16,6 +16,7 @@ import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.async.MarkedAsyncCallback; import com.sap.sse.gwt.client.celltable.RefreshableSelectionModel; import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel; +import com.sap.sse.security.ui.client.UserService; /** * Allows an administrator to view the boats assigned to the competitors of a race. @@ -36,7 +37,8 @@ public class CompetitorToBoatMappingsViewPanel extends SimplePanel { private final RefreshableSelectionModel refreshableCompetitorSelectionModel; public CompetitorToBoatMappingsViewPanel(final SailingServiceAsync sailingService, final StringMessages stringMessages, - final ErrorReporter errorReporter, final String leaderboardName, final String raceColumnName, final String fleetName) { + final ErrorReporter errorReporter, final String leaderboardName, final String raceColumnName, + final String fleetName, UserService userService) { super(); this.sailingService = sailingService; this.stringMessages = stringMessages; @@ -44,7 +46,8 @@ public class CompetitorToBoatMappingsViewPanel extends SimplePanel { this.raceColumnName = raceColumnName; this.fleetName = fleetName; this.errorReporter = errorReporter; - this.competitorTable = new CompactCompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */ false, /* enablePager */ true); + this.competitorTable = new CompactCompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, + /* multiSelection */ false, /* enablePager */ true, userService); this.boatTable = new CompactBoatTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */ false, /* enablePager */ true); refreshableCompetitorSelectionModel = competitorTable.getSelectionModel(); refreshableCompetitorSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java index 1cf3f9ab334..52e4c1447c8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java @@ -652,7 +652,8 @@ public class LeaderboardConfigPanel extends AbstractLeaderboardConfigPanel final String raceName = LeaderboardNameConstants.DEFAULT_FLEET_NAME.equals(fleetName) ? raceColumnName : raceColumnName + ", " + fleetName; ShowCompetitorToBoatMappingsDialog dialog = new ShowCompetitorToBoatMappingsDialog(sailingService, - stringMessages, errorReporter, selectedLeaderboardName, raceColumnName, fleetName, raceName); + stringMessages, errorReporter, selectedLeaderboardName, raceColumnName, fleetName, raceName, + userService); dialog.center(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ShowCompetitorToBoatMappingsDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ShowCompetitorToBoatMappingsDialog.java index 78319335b3b..cbdd1d94c17 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ShowCompetitorToBoatMappingsDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ShowCompetitorToBoatMappingsDialog.java @@ -9,11 +9,12 @@ import com.google.gwt.user.client.ui.VerticalPanel; 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.security.ui.client.UserService; public class ShowCompetitorToBoatMappingsDialog extends DialogBox { public ShowCompetitorToBoatMappingsDialog(final SailingServiceAsync sailingService, final StringMessages stringMessages, final ErrorReporter errorReporter, String leaderboardName, final String raceColumnName, final String fleetName, - String raceName) { + String raceName, UserService userService) { super(); setText(stringMessages.actionShowCompetitorToBoatAssignments()); setAnimationEnabled(true); @@ -26,7 +27,7 @@ public class ShowCompetitorToBoatMappingsDialog extends DialogBox { }); VerticalPanel vPanel = new VerticalPanel(); CompetitorToBoatMappingsViewPanel competitorPanel = new CompetitorToBoatMappingsViewPanel(sailingService, - stringMessages, errorReporter, leaderboardName, raceColumnName, fleetName); + stringMessages, errorReporter, leaderboardName, raceColumnName, fleetName, userService); vPanel.add(new Label(stringMessages.race() + ": " + raceName)); vPanel.add(competitorPanel); vPanel.add(okButton); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java index 52c18c66cca..72f7b0b1a76 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java @@ -451,7 +451,7 @@ public class SmartphoneTrackingEventManagementPanel @Override public void cancel() { } - }).show(); + }, userService).show(); } @Override @@ -935,7 +935,7 @@ public class SmartphoneTrackingEventManagementPanel final String raceName = LeaderboardNameConstants.DEFAULT_FLEET_NAME.equals(fleetName) ? raceColumnName : raceColumnName + ", " + fleetName; ShowCompetitorToBoatMappingsDialog dialog = new ShowCompetitorToBoatMappingsDialog(sailingService, stringMessages, errorReporter, selectedLeaderboardName, raceColumnName, fleetName, - raceName); + raceName, userService); dialog.center(); } From 3e884759a04f4382665fa6426115fbbf30d0497b Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 30 Jul 2019 18:23:13 +0200 Subject: [PATCH 15/43] Bug 5092: added filter checkbox to Boats table --- .../com/sap/sailing/gwt/ui/adminconsole/BoatTableWrapper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/BoatTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/BoatTableWrapper.java index 264b99c7368..a64685a00e2 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/BoatTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/BoatTableWrapper.java @@ -167,6 +167,7 @@ public class BoatTableWrapper> exte return table; } }; + filterField.setCheckboxEnabledFilter(boat -> userService.hasPermission(boat, DefaultActions.UPDATE)); registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider()); // BoatTable edit features From b76c1d7eae45cb72ed2e085627cccc26ea84b8ce Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 30 Jul 2019 18:24:27 +0200 Subject: [PATCH 16/43] Bug 5092: added filter checkbox to MediaTracks table --- .../java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java index 200e6ae1daa..7d13d05dfa8 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java @@ -194,6 +194,8 @@ public class MediaPanel extends FlowPanel implements MediaTracksRefresher { }; createMediaTracksTable(userService); filterableMediaTracks.getTextBox().ensureDebugId("MediaTracksFilterTextBox"); + filterableMediaTracks + .setCheckboxEnabledFilter(mediaTrack -> userService.hasPermission(mediaTrack, DefaultActions.UPDATE)); buttonAndFilterPanel.addUnsecuredWidget(filterableMediaTracks); refreshableSelectionModel.addSelectionChangeHandler(new Handler() { From 01a233054d6003167f38b82ee3f4caaa5024b782 Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 30 Jul 2019 18:27:27 +0200 Subject: [PATCH 17/43] Bug 5092: added filter checkbox to SwissTiming/-Archived/TricTrac connection tables --- .../swisstiming/SwissTimingArchivedConnectionTableWrapper.java | 2 ++ .../swisstiming/SwissTimingConnectionTableWrapper.java | 2 ++ .../adminconsole/tractrac/TracTracConnectionTableWrapper.java | 2 ++ 3 files changed, 6 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingArchivedConnectionTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingArchivedConnectionTableWrapper.java index e124ae0bbaf..b3aa996d85c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingArchivedConnectionTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingArchivedConnectionTableWrapper.java @@ -137,6 +137,8 @@ public class SwissTimingArchivedConnectionTableWrapper extends } }; registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider()); + filterField + .setCheckboxEnabledFilter(connection -> userService.hasPermission(connection, DefaultActions.UPDATE)); mainPanel.insert(filterField, 0); table.addColumnSortHandler(swissTimingAccountColumnListHandler); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingConnectionTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingConnectionTableWrapper.java index 1adafbfc4f4..fda22017094 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingConnectionTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingConnectionTableWrapper.java @@ -166,6 +166,8 @@ public class SwissTimingConnectionTableWrapper extends return table; } }; + filterField + .setCheckboxEnabledFilter(connection -> userService.hasPermission(connection, DefaultActions.UPDATE)); registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider()); mainPanel.insert(filterField, 0); table.addColumnSortHandler(swissTimingConectionColumnListHandler); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/tractrac/TracTracConnectionTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/tractrac/TracTracConnectionTableWrapper.java index 29660d5cca8..ba124ab0694 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/tractrac/TracTracConnectionTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/tractrac/TracTracConnectionTableWrapper.java @@ -150,6 +150,8 @@ public class TracTracConnectionTableWrapper extends } }; registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider()); + filterField + .setCheckboxEnabledFilter(connection -> userService.hasPermission(connection, DefaultActions.UPDATE)); mainPanel.insert(filterField, 0); table.addColumnSortHandler(tracTracAccountColumnListHandler); table.addColumn(tracTracAccountNameColumn, getStringMessages().name()); From 0af70ce4d0eeefb43b3cde2f26093e375ced0160 Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 30 Jul 2019 18:27:40 +0200 Subject: [PATCH 18/43] Bug 5092: added filter checkbox to igtimi accounts table --- .../sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java index 931903bd935..4a725efb935 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java @@ -124,6 +124,8 @@ public class IgtimiAccountsPanel extends FlowPanel { .getSelectionModel(); final Panel controlsPanel = new HorizontalPanel(); + filterAccountsPanel + .setCheckboxEnabledFilter(account -> userService.hasPermission(account, DefaultActions.UPDATE)); controlsPanel.add(filterAccountsPanel); final AccessControlledButtonPanel buttonPanel = new AccessControlledButtonPanel(userService, From 970fed908e68712ecf804261141c6d950e4d9faa Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 30 Jul 2019 18:32:50 +0200 Subject: [PATCH 19/43] Bug 5092: added filter checkbox to role tables --- .../sse/security/ui/client/component/RoleDefinitionsPanel.java | 2 ++ .../usermanagement/roles/RoleWithSecurityDTOTableWrapper.java | 1 + 2 files changed, 3 insertions(+) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/RoleDefinitionsPanel.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/RoleDefinitionsPanel.java index d478a690e30..dd351c470eb 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/RoleDefinitionsPanel.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/RoleDefinitionsPanel.java @@ -91,6 +91,8 @@ public class RoleDefinitionsPanel extends VerticalPanel { return roleDefinitionsTable; } }; + filterablePanelRoleDefinitions + .setCheckboxEnabledFilter(role -> userService.hasPermission(role, DefaultActions.UPDATE)); roleDefinitionsTable = createRoleDefinitionsTable(tableResources); roleDefinitionsTable.ensureDebugId("RolesCellTable"); filterablePanelRoleDefinitions.getTextBox().ensureDebugId("RolesFilterTextBox"); diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/roles/RoleWithSecurityDTOTableWrapper.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/roles/RoleWithSecurityDTOTableWrapper.java index bb6201b8ba3..8fc6131a489 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/roles/RoleWithSecurityDTOTableWrapper.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/roles/RoleWithSecurityDTOTableWrapper.java @@ -133,6 +133,7 @@ public class RoleWithSecurityDTOTableWrapper extends return table; } }; + filterField.setCheckboxEnabledFilter(role -> userService.hasPermission(role, DefaultActions.UPDATE)); registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider()); mainPanel.insert(filterField, 0); From b593ca202e2a79f3035f5531e17f8ca403814f30 Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 30 Jul 2019 18:33:01 +0200 Subject: [PATCH 20/43] Bug 5092: added filter checkbox to user group tables --- .../sse/security/ui/client/component/UserGroupTableWrapper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/UserGroupTableWrapper.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/UserGroupTableWrapper.java index 9a711f64ab3..7a8c9382664 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/UserGroupTableWrapper.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/UserGroupTableWrapper.java @@ -121,6 +121,7 @@ public class UserGroupTableWrapper extends return table; } }; + filterField.setCheckboxEnabledFilter(userGroup -> userService.hasPermission(userGroup, DefaultActions.UPDATE)); registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider()); mainPanel.insert(filterField, 0); From ee4ddb65f2a49b2c8802648e539859d5b54cb3cc Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 30 Jul 2019 18:33:10 +0200 Subject: [PATCH 21/43] Bug 5092: added filter checkbox to permission tables --- .../WildcardPermissionWithSecurityDTOTableWrapper.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/permissions/WildcardPermissionWithSecurityDTOTableWrapper.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/permissions/WildcardPermissionWithSecurityDTOTableWrapper.java index d31c5b3bd9c..a1da6c31b8b 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/permissions/WildcardPermissionWithSecurityDTOTableWrapper.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/permissions/WildcardPermissionWithSecurityDTOTableWrapper.java @@ -133,6 +133,8 @@ public class WildcardPermissionWithSecurityDTOTableWrapper extends } }; registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider()); + filterField + .setCheckboxEnabledFilter(permission -> userService.hasPermission(permission, DefaultActions.UPDATE)); mainPanel.insert(filterField, 0); From 065ccad74230c3a1b13fdf286b923974c85eeb26 Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 30 Jul 2019 18:33:19 +0200 Subject: [PATCH 22/43] Bug 5092: added filter checkbox to user tables --- .../sse/security/ui/client/usermanagement/UserTableWrapper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java index a18f6cbf456..2a5b85c3414 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java @@ -213,6 +213,7 @@ extends TableWrapper { } }; registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider()); + filterField.setCheckboxEnabledFilter(user -> userService.hasPermission(user, DefaultActions.UPDATE)); mainPanel.insert(filterField, 0); table.addColumnSortHandler(userColumnListHandler); From bd83d0468ed2b7f252e001da458867ff32a1867c Mon Sep 17 00:00:00 2001 From: Thomas Wiese Date: Wed, 31 Jul 2019 09:14:03 +0200 Subject: [PATCH 23/43] bug4942: allow testing of http error status responses by mapping http status code to an exception type --- .../sailing/selenium/api/core/ApiContext.java | 12 +-- .../selenium/api/core/HttpException.java | 94 +++++++++++++++++++ 2 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/HttpException.java diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/ApiContext.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/ApiContext.java index b7bf4e9e4ed..44995fc18ff 100644 --- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/ApiContext.java +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/ApiContext.java @@ -112,7 +112,7 @@ public class ApiContext { String error = "API POST request " + url + " failed (rc=" + e.getResponse().getStatus() + "): " + e.getResponse().getEntity(String.class); logger.severe(error); - throw new RuntimeException(error); + throw HttpException.forResponse(e.getResponse(), error).orElse(e); } return (R) JSONValue.parse(result); } @@ -141,7 +141,7 @@ public class ApiContext { String error = "API POST request " + url + " failed (rc=" + e.getResponse().getStatus() + "): " + e.getResponse().getEntity(String.class); logger.severe(error); - throw new RuntimeException(error); + throw HttpException.forResponse(e.getResponse(), error).orElse(e); } return (R) JSONValue.parse(result); } @@ -167,7 +167,7 @@ public class ApiContext { String error = "API POST request " + url + " failed (rc=" + e.getResponse().getStatus() + "): " + e.getResponse().getEntity(String.class); logger.severe(error); - throw new RuntimeException(error); + throw HttpException.forResponse(e.getResponse(), error).orElse(e); } return (R) JSONValue.parse(result); } @@ -193,7 +193,7 @@ public class ApiContext { String error = "API PUT request " + url + " failed (rc=" + e.getResponse().getStatus() + "): " + e.getResponse().getEntity(String.class); logger.severe(error); - throw new RuntimeException(error); + throw HttpException.forResponse(e.getResponse(), error).orElse(e); } return (R) JSONValue.parse(result); } @@ -212,7 +212,7 @@ public class ApiContext { String error = "API DELETE request " + url + " failed (rc=" + e.getResponse().getStatus() + "): " + e.getResponse().getEntity(String.class); logger.severe(error); - throw new RuntimeException(error); + throw HttpException.forResponse(e.getResponse(), error).orElse(e); } } @@ -256,7 +256,7 @@ public class ApiContext { String error = "API GET request " + url + " failed (rc=" + rc + "): " + e.getResponse().getEntity(String.class); logger.severe(error); - throw new RuntimeException(error); + throw HttpException.forResponse(e.getResponse(), error).orElse(e); } } return JSONValue.parse(result); diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/HttpException.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/HttpException.java new file mode 100644 index 00000000000..bfed76aed10 --- /dev/null +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/HttpException.java @@ -0,0 +1,94 @@ +package com.sap.sailing.selenium.api.core; + +import java.util.Optional; + +import javax.ws.rs.core.Response; + +import com.sun.jersey.api.client.ClientResponse; + +public class HttpException extends RuntimeException { + + private static final long serialVersionUID = -7750172668418557820L; + + private final int httpStatusCode; + + public static Optional forResponse(final ClientResponse response) { + return forResponse(response, null); + } + + public static Optional forResponse(final ClientResponse response, String message) { + final int statusCode = response.getStatus(); + switch (statusCode) { + case 200: + return Optional.empty(); + case 401: + return Optional.of(new Unauthorized(message)); + case 403: + return Optional.of(new Forbidden(message)); + case 404: + return Optional.of(new NotFound(message)); + default: + return Optional.of(new HttpException(statusCode, message)); + } + } + + public HttpException(final int httpStatusCode) { + super(); + this.httpStatusCode = httpStatusCode; + } + + public HttpException(final int httpStatusCode, final String message) { + super(message); + this.httpStatusCode = httpStatusCode; + } + + public void rethrow() { + throw this; + } + + public int getHttpStatusCode() { + return httpStatusCode; + } + + public static final class NotFound extends HttpException { + + private static final long serialVersionUID = 1875842782488954242L; + + NotFound() { + super(Response.Status.NOT_FOUND.getStatusCode()); + } + + NotFound(String message) { + super(Response.Status.NOT_FOUND.getStatusCode(), message); + } + + } + + public static final class Unauthorized extends HttpException { + + private static final long serialVersionUID = 1875842782488954242L; + + Unauthorized() { + super(Response.Status.UNAUTHORIZED.getStatusCode()); + } + + Unauthorized(String message) { + super(Response.Status.UNAUTHORIZED.getStatusCode(), message); + } + + } + + public static final class Forbidden extends HttpException { + + private static final long serialVersionUID = 1875842782488954242L; + + Forbidden() { + super(Response.Status.FORBIDDEN.getStatusCode()); + } + + Forbidden(String message) { + super(Response.Status.FORBIDDEN.getStatusCode(), message); + } + + } +} From e8272eb2c7822ff4fa7ec353892779a0864ce318 Mon Sep 17 00:00:00 2001 From: Thomas Wiese Date: Wed, 31 Jul 2019 09:56:03 +0200 Subject: [PATCH 24/43] bug4942: add exceptional test for MarkApiTest --- .../selenium/api/test/MarkApiTest.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/MarkApiTest.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/MarkApiTest.java index a2c7c9bc3f3..c6571c23ba8 100644 --- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/MarkApiTest.java +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/MarkApiTest.java @@ -1,7 +1,10 @@ package com.sap.sailing.selenium.api.test; +import static com.sap.sailing.selenium.api.core.ApiContext.SECURITY_CONTEXT; import static com.sap.sailing.selenium.api.core.ApiContext.SERVER_CONTEXT; import static com.sap.sailing.selenium.api.core.ApiContext.createAdminApiContext; +import static com.sap.sailing.selenium.api.core.ApiContext.createAnonymousApiContext; +import static com.sap.sailing.selenium.api.core.ApiContext.createApiContext; import static java.lang.System.currentTimeMillis; import static org.junit.Assert.assertNotNull; @@ -10,8 +13,10 @@ import org.junit.Test; import com.sap.sailing.domain.common.CompetitorRegistrationType; import com.sap.sailing.selenium.api.core.ApiContext; +import com.sap.sailing.selenium.api.core.HttpException; import com.sap.sailing.selenium.api.event.EventApi; import com.sap.sailing.selenium.api.event.MarkApi; +import com.sap.sailing.selenium.api.event.SecurityApi; import com.sap.sailing.selenium.api.event.MarkApi.Mark; import com.sap.sailing.selenium.api.regatta.RaceColumn; import com.sap.sailing.selenium.api.regatta.Regatta; @@ -26,6 +31,7 @@ public class MarkApiTest extends AbstractSeleniumTest { private final EventApi eventApi = new EventApi(); private final RegattaApi regattaApi = new RegattaApi(); private final MarkApi markApi = new MarkApi(); + private final SecurityApi securityApi = new SecurityApi(); @Before public void setUp() { @@ -55,4 +61,21 @@ public class MarkApiTest extends AbstractSeleniumTest { markApi.addMarkFix(ctx, EVENT_NAME, race.getRaceName(), "Default", mark.getMarkId(), 9.12, .599, currentTimeMillis()); } + + @Test(expected = HttpException.NotFound.class) + public void testAddMarkToRegattaForNonExistingEvent() { + final ApiContext ctx = createAdminApiContext(getContextRoot(), SERVER_CONTEXT); + markApi.addMarkToRegatta(ctx, "NONEVENT", "Startboat"); + } + + @Test(expected = HttpException.Unauthorized.class) + public void testAddMarkToRegattaWithoutPermission() { + final ApiContext adminSecurityCtx = createAdminApiContext(getContextRoot(), SECURITY_CONTEXT); + final ApiContext ownerCtx = createAdminApiContext(getContextRoot(), SERVER_CONTEXT); + securityApi.createUser(adminSecurityCtx, "donald", "Donald Duck", null, "daisy0815"); + final ApiContext readerCtx = createApiContext(getContextRoot(), SERVER_CONTEXT, "donald", "daisy0815"); + + eventApi.createEvent(ownerCtx, EVENT_NAME, BOAT_CLASS, CompetitorRegistrationType.CLOSED, "default"); + markApi.addMarkToRegatta(readerCtx, EVENT_NAME, "Startboat"); + } } From 53a5619ed1ecf9a7dc67c7f11dd35870671fff24 Mon Sep 17 00:00:00 2001 From: Thomas Wiese Date: Wed, 31 Jul 2019 09:58:39 +0200 Subject: [PATCH 25/43] bug4942: formatting --- .../src/com/sap/sailing/selenium/api/test/MarkApiTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/MarkApiTest.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/MarkApiTest.java index c6571c23ba8..cd696e04b41 100644 --- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/MarkApiTest.java +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/MarkApiTest.java @@ -3,7 +3,6 @@ package com.sap.sailing.selenium.api.test; import static com.sap.sailing.selenium.api.core.ApiContext.SECURITY_CONTEXT; import static com.sap.sailing.selenium.api.core.ApiContext.SERVER_CONTEXT; import static com.sap.sailing.selenium.api.core.ApiContext.createAdminApiContext; -import static com.sap.sailing.selenium.api.core.ApiContext.createAnonymousApiContext; import static com.sap.sailing.selenium.api.core.ApiContext.createApiContext; import static java.lang.System.currentTimeMillis; import static org.junit.Assert.assertNotNull; @@ -16,8 +15,8 @@ import com.sap.sailing.selenium.api.core.ApiContext; import com.sap.sailing.selenium.api.core.HttpException; import com.sap.sailing.selenium.api.event.EventApi; import com.sap.sailing.selenium.api.event.MarkApi; -import com.sap.sailing.selenium.api.event.SecurityApi; import com.sap.sailing.selenium.api.event.MarkApi.Mark; +import com.sap.sailing.selenium.api.event.SecurityApi; import com.sap.sailing.selenium.api.regatta.RaceColumn; import com.sap.sailing.selenium.api.regatta.Regatta; import com.sap.sailing.selenium.api.regatta.RegattaApi; From 1a1e158d9734a475755e2b9a06e6fd36b2e2aaac Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 1 Aug 2019 08:14:42 +0200 Subject: [PATCH 26/43] Bug 5101: Added logging for the case that an unexpected tracked item is found when calculating the tracker status of a regatta --- .../sap/sailing/server/gateway/jaxrs/api/RegattasResource.java | 3 +++ 1 file changed, 3 insertions(+) mode change 100755 => 100644 java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java old mode 100755 new mode 100644 index bdd8e7f6a77..fbf745862e6 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java @@ -2319,6 +2319,9 @@ public class RegattasResource extends AbstractSailingServerResource { } else if (item instanceof Mark) { itemObject.put("markId", item.getId().toString()); ((JSONArray) result.computeIfAbsent("marks", k -> new JSONArray())).add(itemObject); + } else { + logger.log(Level.WARNING, "Unexpected tracked item found while calculating the tracker status. ID: " + + item.getId() + "; type: " + item.getClass().getName()); } }); return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") From 8c70bb95284a490ca58ccfe8a61c764e3ed7e87d Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 1 Aug 2019 08:15:40 +0200 Subject: [PATCH 27/43] Bug 5101: Code improvements, cleanup and formatting --- .../gateway/jaxrs/api/RegattasResource.java | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java index fbf745862e6..67d93b13225 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java @@ -2289,26 +2289,30 @@ public class RegattasResource extends AbstractSailingServerResource { @Produces("application/json;charset=UTF-8") @Path("{regattaName}/tracking_devices") public Response getTrackingStatus(@PathParam("regattaName") String regattaName) { - Regatta regatta = getService().getRegattaByName(regattaName); + final Regatta regatta = getService().getRegattaByName(regattaName); if (regatta != null) { // Deeper insights to tracking data is only available to users who can administer a regatta - SecurityUtils.getSubject().checkPermission(regatta.getIdentifier().getStringPermission(DefaultActions.UPDATE)); - - TrackingDeviceStatusSerializer serializer = new TrackingDeviceStatusSerializer(new DeviceIdentifierJsonSerializer( - getServiceFinderFactory().createServiceFinder(DeviceIdentifierJsonHandler.class))); - - RegattaLogDeviceMappingFinder regattaLogDeviceMappingFinder = new RegattaLogDeviceMappingFinder(regatta.getRegattaLog()); - Map>> foundMappings = regattaLogDeviceMappingFinder.analyze(); - - JSONObject result = new JSONObject(); + SecurityUtils.getSubject() + .checkPermission(regatta.getIdentifier().getStringPermission(DefaultActions.UPDATE)); + + final TrackingDeviceStatusSerializer serializer = new TrackingDeviceStatusSerializer( + new DeviceIdentifierJsonSerializer( + getServiceFinderFactory().createServiceFinder(DeviceIdentifierJsonHandler.class))); + + final RegattaLogDeviceMappingFinder regattaLogDeviceMappingFinder = new RegattaLogDeviceMappingFinder( + regatta.getRegattaLog()); + final Map>> foundMappings = regattaLogDeviceMappingFinder + .analyze(); + + final JSONObject result = new JSONObject(); foundMappings.forEach((item, mappings) -> { - JSONArray deviceStatusesOfTrackedItem = new JSONArray(); - mappings.stream().map(DeviceMappingWithRegattaLogEvent::getDevice).collect(Collectors.toSet()) - .forEach(deviceIdentifier -> { - deviceStatusesOfTrackedItem.add(serializer.serialize( - TrackingDeviceStatus.calculateDeviceStatus(deviceIdentifier, getService()))); - }); - JSONObject itemObject = new JSONObject(); + final JSONArray deviceStatusesOfTrackedItem = new JSONArray(); + deviceStatusesOfTrackedItem + .addAll(mappings.stream().map(DeviceMappingWithRegattaLogEvent::getDevice).distinct() + .map(deviceIdentifier -> serializer.serialize( + TrackingDeviceStatus.calculateDeviceStatus(deviceIdentifier, getService()))) + .collect(Collectors.toList())); + final JSONObject itemObject = new JSONObject(); itemObject.put("deviceStatuses", deviceStatusesOfTrackedItem); if (item instanceof Competitor) { itemObject.put("competitorId", item.getId().toString()); @@ -2324,8 +2328,8 @@ public class RegattasResource extends AbstractSailingServerResource { + item.getId() + "; type: " + item.getClass().getName()); } }); - return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") - .build(); + return Response.ok(result.toJSONString()) + .header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } else { throw new IllegalStateException("Regatta named " + regattaName + " could not be resolved"); } From 6b3052824960c309367ece19f5b30e9f1a23eb26 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 1 Aug 2019 08:23:34 +0200 Subject: [PATCH 28/43] Bug 5101: Added release notes --- java/com.sap.sailing.www/release_notes_admin.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/java/com.sap.sailing.www/release_notes_admin.html b/java/com.sap.sailing.www/release_notes_admin.html index 581d67c76ea..7c7d83e4e4b 100755 --- a/java/com.sap.sailing.www/release_notes_admin.html +++ b/java/com.sap.sailing.www/release_notes_admin.html @@ -21,6 +21,15 @@

Release Notes - Administration Console

+

August 2019

+
    +
  • New API endpoints were added to get the status of tracking devices. + Under /sailingserver/api/v1/tracking_devices/[deviceUUID] the status of smartphone tracking devices can be read by using the device's UUID. + /sailingserver/api/v1/regattas/[regattaName]/tracking_devices the status for all tracking devices associated to a regatta is returned. + While the first requires the non public device UUID to be included in the request, the latter requires a user to have UPDATE permission for the regatta in question. +
  • +
+

July 2019

  • Result and competitor import URLs are now only considered when the requesting user From 8608d4e28d6c2aa6799d83aa53c2d54822eca098 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 1 Aug 2019 08:26:03 +0200 Subject: [PATCH 29/43] Bug 5101: Improved release notes --- java/com.sap.sailing.www/release_notes_admin.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.www/release_notes_admin.html b/java/com.sap.sailing.www/release_notes_admin.html index 7c7d83e4e4b..4811f0cbcae 100755 --- a/java/com.sap.sailing.www/release_notes_admin.html +++ b/java/com.sap.sailing.www/release_notes_admin.html @@ -21,16 +21,16 @@

    Release Notes - Administration Console

    -

    August 2019

    +

    August 2019

      -
    • New API endpoints were added to get the status of tracking devices. +
    • New API endpoints were added to get the status of tracking devices. By now, just the last received GPS fix is returned in the status. Under /sailingserver/api/v1/tracking_devices/[deviceUUID] the status of smartphone tracking devices can be read by using the device's UUID. /sailingserver/api/v1/regattas/[regattaName]/tracking_devices the status for all tracking devices associated to a regatta is returned. While the first requires the non public device UUID to be included in the request, the latter requires a user to have UPDATE permission for the regatta in question.
    - -

    July 2019

    + +

    July 2019

    • Result and competitor import URLs are now only considered when the requesting user has the permission to read that URL.
    • From 26895e0a5dce780a54708570828a8d826a8d8539 Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Thu, 1 Aug 2019 09:16:32 +0200 Subject: [PATCH 30/43] Bug 5092: added i18n --- .../adminconsole/AbstractLeaderboardConfigPanel.java | 2 +- .../AbstractTrackedRacesListComposite.java | 2 +- .../sailing/gwt/ui/adminconsole/BoatTableWrapper.java | 2 +- .../gwt/ui/adminconsole/CompactBoatTableWrapper.java | 2 +- .../ui/adminconsole/CompactCompetitorTableWrapper.java | 2 +- .../adminconsole/CompetitorDescriptorTableWrapper.java | 2 +- .../gwt/ui/adminconsole/CompetitorTableWrapper.java | 2 +- .../gwt/ui/adminconsole/EventListComposite.java | 2 +- .../ExpeditionDeviceConfigurationsPanel.java | 2 +- .../gwt/ui/adminconsole/IgtimiAccountsPanel.java | 2 +- .../ui/adminconsole/LeaderboardGroupConfigPanel.java | 4 ++-- .../LeaderboardGroupSelectorComposite.java | 2 +- .../sap/sailing/gwt/ui/adminconsole/MediaPanel.java | 2 +- .../gwt/ui/adminconsole/RegattaListComposite.java | 2 +- .../RegattaLogTrackingDeviceMappingsDialog.java | 2 +- .../RemoteServerInstancesManagementPanel.java | 2 +- .../adminconsole/SwissTimingEventManagementPanel.java | 2 +- .../adminconsole/SwissTimingReplayConnectorPanel.java | 3 ++- .../ui/adminconsole/TracTracEventManagementPanel.java | 3 ++- .../SwissTimingArchivedConnectionTableWrapper.java | 2 +- .../swisstiming/SwissTimingConnectionTableWrapper.java | 2 +- .../tractrac/TracTracConnectionTableWrapper.java | 2 +- .../selection/DimensionFilterSelectionProvider.java | 2 +- ...erarchicalDimensionListFilterSelectionProvider.java | 2 +- .../src/com/sap/sse/gwt/client/StringMessages.java | 2 ++ .../com/sap/sse/gwt/client/StringMessages.properties | 1 + .../sap/sse/gwt/client/StringMessages_de.properties | 3 ++- .../sse/gwt/client/panels/AbstractFilterablePanel.java | 10 ++++++---- .../gwt/client/panels/CustomizableFilterablePanel.java | 5 +++-- .../client/panels/LabeledAbstractFilterablePanel.java | 6 ++++-- .../ui/client/component/RoleDefinitionsPanel.java | 2 +- .../ui/client/component/UserGroupTableWrapper.java | 2 +- .../usergroup/roles/RoleDefinitionTableWrapper.java | 2 +- .../ui/client/usermanagement/UserTableWrapper.java | 2 +- .../WildcardPermissionWithSecurityDTOTableWrapper.java | 2 +- .../roles/RoleWithSecurityDTOTableWrapper.java | 2 +- 36 files changed, 51 insertions(+), 40 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java index 7145c0beae2..6a45fdf97c2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java @@ -185,7 +185,7 @@ public abstract class AbstractLeaderboardConfigPanel extends FormPanel AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class); leaderboardTable = new FlushableCellTable(/* pageSize */10000, tableRes); filterLeaderboardPanel = new LabeledAbstractFilterablePanel(lblFilterEvents, - availableLeaderboardList, filteredLeaderboardList) { + availableLeaderboardList, filteredLeaderboardList, stringMessages) { @Override public List getSearchableStrings(StrippedLeaderboardDTOWithSecurity t) { List strings = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java index 054aacbf233..9f27522ac85 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java @@ -161,7 +161,7 @@ public abstract class AbstractTrackedRacesListComposite extends AbstractComposit filterPanel.add(lblFilterRaces); filterPanel.setCellVerticalAlignment(lblFilterRaces, HasVerticalAlignment.ALIGN_MIDDLE); raceList = raceTableWrapper.getDataProvider(); - filterablePanelRaces = new CustomizableFilterablePanel(allRaces, raceList) { + filterablePanelRaces = new CustomizableFilterablePanel(allRaces, raceList, stringMessages) { @Override public List getSearchableStrings(RaceDTO t) { List strings = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/BoatTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/BoatTableWrapper.java index a64685a00e2..88baee4f89f 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/BoatTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/BoatTableWrapper.java @@ -151,7 +151,7 @@ public class BoatTableWrapper> exte }); filterField = new LabeledAbstractFilterablePanel(new Label(stringMessages.filterBoats()), - new ArrayList(), dataProvider) { + new ArrayList(), dataProvider, stringMessages) { @Override public Iterable getSearchableStrings(BoatDTO boat) { List string = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompactBoatTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompactBoatTableWrapper.java index 4b5b08268f3..dee2696f1aa 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompactBoatTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompactBoatTableWrapper.java @@ -132,7 +132,7 @@ public class CompactBoatTableWrapper(new ArrayList<>(), getDataProvider()) { + filterField = new CustomizableFilterablePanel(new ArrayList<>(), getDataProvider(), stringMessages) { @Override public Iterable getSearchableStrings(BoatDTO boat) { List string = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompactCompetitorTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompactCompetitorTableWrapper.java index 942c6cb1aaa..368a7e92cb8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompactCompetitorTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompactCompetitorTableWrapper.java @@ -135,7 +135,7 @@ public class CompactCompetitorTableWrapper(new Label(stringMessages.filterCompetitors()), - new ArrayList(), dataProvider) { + new ArrayList(), dataProvider, stringMessages) { @Override public Iterable getSearchableStrings(CompetitorDTO t) { List string = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorDescriptorTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorDescriptorTableWrapper.java index b18f591e867..3f10ad46039 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorDescriptorTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorDescriptorTableWrapper.java @@ -102,7 +102,7 @@ public class CompetitorDescriptorTableWrapper( new Label(stringMessages.filterImportedCompetitorsByNameSailRaceFleet()), - new ArrayList(), dataProvider) { + new ArrayList(), dataProvider, stringMessages) { @Override public Iterable getSearchableStrings(CompetitorDescriptor competitorDescriptor) { List string = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java index 9beb76bdd7a..51b8b1b37e6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java @@ -301,7 +301,7 @@ public class CompetitorTableWrapper(new Label(getStringMessages().filterCompetitors()), - new ArrayList(), dataProvider) { + new ArrayList(), dataProvider, stringMessages) { @Override public Iterable getSearchableStrings(CompetitorDTO t) { List string = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java index d936f965cab..42001790574 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java @@ -163,7 +163,7 @@ public class EventListComposite extends Composite implements EventsRefresher, Le eventListDataProvider = new ListDataProvider(); filterTextbox = new LabeledAbstractFilterablePanel(new Label(stringMessages.filterEventsByName()), - allEvents, eventListDataProvider) { + allEvents, eventListDataProvider, stringMessages) { @Override public Iterable getSearchableStrings(EventDTO t) { List result = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExpeditionDeviceConfigurationsPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExpeditionDeviceConfigurationsPanel.java index d665a883208..2b54159f9d8 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExpeditionDeviceConfigurationsPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExpeditionDeviceConfigurationsPanel.java @@ -88,7 +88,7 @@ public class ExpeditionDeviceConfigurationsPanel extends FlowPanel { filteredDeviceConfigurations.addDataDisplay(allDeviceConfigurations); final List emptyList = Collections.emptyList(); filterDeviceConfigurationsPanel = new LabeledAbstractFilterablePanel(new Label(stringMessages.expeditionDeviceConfigurations()), - emptyList, filteredDeviceConfigurations) { + emptyList, filteredDeviceConfigurations, stringMessages) { @Override public Iterable getSearchableStrings(ExpeditionDeviceConfiguration t) { Set strings = new HashSet<>(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java index 4a725efb935..cfa73e57946 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java @@ -105,7 +105,7 @@ public class IgtimiAccountsPanel extends FlowPanel { tableRes); final ListDataProvider filteredAccounts = new ListDataProvider<>(); filterAccountsPanel = new LabeledAbstractFilterablePanel( - new Label(stringMessages.igtimiAccounts()), Collections.emptyList(), filteredAccounts) { + new Label(stringMessages.igtimiAccounts()), Collections.emptyList(), filteredAccounts, stringMessages) { @Override public Iterable getSearchableStrings(AccountWithSecurityDTO t) { Set strings = Collections.singleton(t.getEmail()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java index 41465817c86..4af19d4f721 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java @@ -220,7 +220,7 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel leaderboardsTable = new FlushableCellTable(10000, tableRes); leaderboardsTable.ensureDebugId("LeaderboardsCellTable"); leaderboardsFilterablePanel = new LabeledAbstractFilterablePanel( - filterLeaderboardsLabel, availableLeaderboards, leaderboardsProvider) { + filterLeaderboardsLabel, availableLeaderboards, leaderboardsProvider, stringMessages) { @Override public Iterable getSearchableStrings(StrippedLeaderboardDTO t) { List strings = new ArrayList(); @@ -484,7 +484,7 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel groupsTable = new FlushableCellTable(10000, tableRes); groupsTable.ensureDebugId("LeaderboardGroupsCellTable"); groupsFilterablePanel = new LabeledAbstractFilterablePanel(filterLeaderboardGroupsLbl, - availableLeaderboardGroups, groupsProvider) { + availableLeaderboardGroups, groupsProvider, stringMessages) { @Override public Iterable getSearchableStrings(LeaderboardGroupDTO t) { List string = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupSelectorComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupSelectorComposite.java index c17ba4bc277..19a95938b18 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupSelectorComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupSelectorComposite.java @@ -145,7 +145,7 @@ public class LeaderboardGroupSelectorComposite extends Composite implements HasV availableLeaderboardGroupsProvider.addDataDisplay(availableLeaderboardGroupsTable); availableLeaderboardGroupsFilterablePanel = new LabeledAbstractFilterablePanel( new Label(stringMessages.filterLeaderboardGroupsByName()), - Collections. emptyList(), availableLeaderboardGroupsProvider) { + Collections. emptyList(), availableLeaderboardGroupsProvider, stringMessages) { @Override public Iterable getSearchableStrings(LeaderboardGroupDTO t) { List result = new ArrayList<>(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java index 7d13d05dfa8..6fe181066d4 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java @@ -173,7 +173,7 @@ public class MediaPanel extends FlowPanel implements MediaTracksRefresher { this.filterableMediaTracks = new LabeledAbstractFilterablePanel(lblFilterRaces, allMediaTracks, - mediaTrackListDataProvider) { + mediaTrackListDataProvider, stringMessages) { @Override public List getSearchableStrings(MediaTrackWithSecurityDTO t) { List strings = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java index 93a57939dfa..cd6e7588046 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java @@ -108,7 +108,7 @@ public class RegattaListComposite extends Composite implements RegattasDisplayer regattaListDataProvider = new ListDataProvider(); filterablePanelRegattas = new LabeledAbstractFilterablePanel(filterRegattasLabel, allRegattas, - regattaListDataProvider) { + regattaListDataProvider, stringMessages) { @Override public Iterable getSearchableStrings(RegattaDTO t) { List string = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogTrackingDeviceMappingsDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogTrackingDeviceMappingsDialog.java index a56a2f7d33c..5223b66f7c4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogTrackingDeviceMappingsDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogTrackingDeviceMappingsDialog.java @@ -184,7 +184,7 @@ public class RegattaLogTrackingDeviceMappingsDialog extends DataEntryDialog( new Label(stringMessages.filterDeviceMappings()), - new ArrayList(), deviceMappingTable.getDataProvider()) { + new ArrayList(), deviceMappingTable.getDataProvider(), stringMessages) { @Override public Iterable getSearchableStrings(DeviceMappingDTO t) { List string = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RemoteServerInstancesManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RemoteServerInstancesManagementPanel.java index eb63e28f431..a0737083725 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RemoteServerInstancesManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RemoteServerInstancesManagementPanel.java @@ -70,7 +70,7 @@ public class RemoteServerInstancesManagementPanel extends SimplePanel { serverDataProvider = new ListDataProvider(); filteredServerTablePanel = new LabeledAbstractFilterablePanel( new Label(stringMessages.filterBy() + ":"), Collections. emptyList(), - serverDataProvider) { + serverDataProvider, stringMessages) { @Override public List getSearchableStrings(RemoteSailingServerReferenceDTO t) { List strings = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingEventManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingEventManagementPanel.java index 4de9e3fd461..5630453be38 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingEventManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingEventManagementPanel.java @@ -200,7 +200,7 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane raceTable.setWidth("300px"); raceList = new ListDataProvider(); filterablePanelEvents = new LabeledAbstractFilterablePanel(lblFilterEvents, - availableSwissTimingRaces, raceList) { + availableSwissTimingRaces, raceList, stringMessages) { @Override public Iterable getSearchableStrings(SwissTimingRaceRecordDTO t) { List strings = new ArrayList<>(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingReplayConnectorPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingReplayConnectorPanel.java index e6e8c5ac587..da50f66ad5d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingReplayConnectorPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingReplayConnectorPanel.java @@ -177,7 +177,8 @@ public class SwissTimingReplayConnectorPanel extends AbstractEventManagementPane raceTable.addColumn(raceStartTrackingColumn, stringMessages.startTime()); raceTable.setWidth("300px"); raceList = new ListDataProvider(); - filterablePanelEvents = new LabeledAbstractFilterablePanel(lblFilterEvents, availableSwissTimingRaces, raceList) { + filterablePanelEvents = new LabeledAbstractFilterablePanel(lblFilterEvents, + availableSwissTimingRaces, raceList, stringMessages) { @Override public List getSearchableStrings(SwissTimingReplayRaceDTO t) { List strings = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TracTracEventManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TracTracEventManagementPanel.java index f472a1f5501..52683733937 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TracTracEventManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TracTracEventManagementPanel.java @@ -252,7 +252,8 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel { AdminConsoleTableResources tableResources = GWT.create(AdminConsoleTableResources.class); racesTable = new FlushableCellTable(10000, tableResources); racesTable.ensureDebugId("TrackableRacesCellTable"); - this.racesFilterablePanel = new LabeledAbstractFilterablePanel(racesFilterLabel, availableTracTracRaces, raceList) { + this.racesFilterablePanel = new LabeledAbstractFilterablePanel(racesFilterLabel, + availableTracTracRaces, raceList, stringMessages) { @Override public List getSearchableStrings(TracTracRaceRecordDTO t) { List strings = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingArchivedConnectionTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingArchivedConnectionTableWrapper.java index b3aa996d85c..52fbc1cafb9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingArchivedConnectionTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingArchivedConnectionTableWrapper.java @@ -122,7 +122,7 @@ public class SwissTimingArchivedConnectionTableWrapper extends u -> configACL.openDialog(u)); filterField = new LabeledAbstractFilterablePanel( new Label(stringMessages.filterSwissTimingAchivedConnections()), - new ArrayList(), dataProvider) { + new ArrayList(), dataProvider, stringMessages) { @Override public Iterable getSearchableStrings(SwissTimingArchiveConfigurationWithSecurityDTO t) { List strings = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingConnectionTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingConnectionTableWrapper.java index fda22017094..e6818dd97b2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingConnectionTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/swisstiming/SwissTimingConnectionTableWrapper.java @@ -140,7 +140,7 @@ public class SwissTimingConnectionTableWrapper extends filterField = new LabeledAbstractFilterablePanel( new Label(stringMessagesClient.filterSwissTimingConnections()), - new ArrayList(), dataProvider) { + new ArrayList(), dataProvider, stringMessages) { @Override public Iterable getSearchableStrings(SwissTimingConfigurationWithSecurityDTO t) { List strings = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/tractrac/TracTracConnectionTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/tractrac/TracTracConnectionTableWrapper.java index ba124ab0694..f84f1a517b9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/tractrac/TracTracConnectionTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/tractrac/TracTracConnectionTableWrapper.java @@ -134,7 +134,7 @@ public class TracTracConnectionTableWrapper extends u -> configACL.openDialog(u)); filterField = new LabeledAbstractFilterablePanel( new Label(stringMessages.filterTracTracConnections()), - new ArrayList(), dataProvider) { + new ArrayList(), dataProvider, stringMessages) { @Override public Iterable getSearchableStrings(TracTracConfigurationWithSecurityDTO t) { List strings = new ArrayList(); diff --git a/java/com.sap.sse.datamining.ui/src/main/java/com/sap/sse/datamining/ui/client/selection/DimensionFilterSelectionProvider.java b/java/com.sap.sse.datamining.ui/src/main/java/com/sap/sse/datamining/ui/client/selection/DimensionFilterSelectionProvider.java index 41a1b3fc3ea..8ebf0e17c6d 100644 --- a/java/com.sap.sse.datamining.ui/src/main/java/com/sap/sse/datamining/ui/client/selection/DimensionFilterSelectionProvider.java +++ b/java/com.sap.sse.datamining.ui/src/main/java/com/sap/sse/datamining/ui/client/selection/DimensionFilterSelectionProvider.java @@ -119,7 +119,7 @@ public class DimensionFilterSelectionProvider extends AbstractDataMiningComponen availableData = new HashSet<>(); filteredData = new ListDataProvider(this::elementAsString); - filterPanel = new AbstractFilterablePanel(null, filteredData) { + filterPanel = new AbstractFilterablePanel(null, filteredData, getDataMiningStringMessages()) { @Override public Iterable getSearchableStrings(Serializable element) { return Collections.singleton(elementAsString(element)); diff --git a/java/com.sap.sse.datamining.ui/src/main/java/com/sap/sse/datamining/ui/client/selection/HierarchicalDimensionListFilterSelectionProvider.java b/java/com.sap.sse.datamining.ui/src/main/java/com/sap/sse/datamining/ui/client/selection/HierarchicalDimensionListFilterSelectionProvider.java index ec8846d6e0c..abc2b2be895 100644 --- a/java/com.sap.sse.datamining.ui/src/main/java/com/sap/sse/datamining/ui/client/selection/HierarchicalDimensionListFilterSelectionProvider.java +++ b/java/com.sap.sse.datamining.ui/src/main/java/com/sap/sse/datamining/ui/client/selection/HierarchicalDimensionListFilterSelectionProvider.java @@ -148,7 +148,7 @@ public class HierarchicalDimensionListFilterSelectionProvider extends AbstractDa filteredFilterDimensions.addDataDisplay(filterDimensionsList); filterFilterDimensionsPanel = new AbstractFilterablePanel( - null, filteredFilterDimensions) { + null, filteredFilterDimensions, stringMessages) { @Override public Iterable getSearchableStrings(DimensionWithContext dimension) { return dimension.getMatchingStrings(); diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/StringMessages.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/StringMessages.java index 07c042d24e7..525673adf0c 100755 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/StringMessages.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/StringMessages.java @@ -100,4 +100,6 @@ public interface StringMessages extends Messages { String whatsNewDialogMessage(); String showChangelog(); + String hideElementsWithoutUpdateRights(); + } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/StringMessages.properties b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/StringMessages.properties index 26ae65d7291..a0b4c76b86a 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/StringMessages.properties +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/StringMessages.properties @@ -82,3 +82,4 @@ loadOrSaveQueries=Load or save query: whatsNewDialogTitle=What''s New? whatsNewDialogMessage=We added some features for you. If you are interested, click below to see what''s new. showChangelog=View Changelog +hideElementsWithoutUpdateRights=Hide elements without update rights diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/StringMessages_de.properties b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/StringMessages_de.properties index fbac38ff8b4..2077e2e75ac 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/StringMessages_de.properties +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/StringMessages_de.properties @@ -81,4 +81,5 @@ dataMiningStoredQueryRemovedFailed=Die gespeicherte Anfrage ''{0}'' konnte nicht loadOrSaveQueries=Anfrage laden oder speichern: whatsNewDialogTitle=Was gibt''s Neues? whatsNewDialogMessage=Wir haben einige neue Funktionen für Sie hinzugefügt. Klicken Sie unten, um zu sehen, was sich geändert hat. -showChangelog=Änderungen anzeigen \ No newline at end of file +showChangelog=Änderungen anzeigen +hideElementsWithoutUpdateRights=Elemente ohne Aktualisierungsberechtigung ausblenden diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java index 09fc61a5430..904a66d64e7 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java @@ -22,6 +22,7 @@ import com.sap.sse.common.Util; import com.sap.sse.common.filter.AbstractKeywordFilter; import com.sap.sse.common.filter.AbstractListFilter; import com.sap.sse.common.filter.Filter; +import com.sap.sse.gwt.client.StringMessages; import com.sap.sse.gwt.client.celltable.RefreshableSelectionModel; /** @@ -109,7 +110,7 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { * normal circumstances the text box will be empty in this case, not making filtering any stricter. */ public AbstractFilterablePanel(Iterable all, final ListDataProvider filtered, - boolean drawTextBox) { + boolean drawTextBox, final StringMessages stringMessages) { filters.add(filterer); setSpacing(5); this.all = new ListDataProvider<>(); @@ -117,7 +118,7 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { this.textBox = new TextBox(); this.textBox.ensureDebugId("FilterTextBox"); // TODO: i18n - this.checkbox = new CheckBox("Hide elements w/o update rights"); + this.checkbox = new CheckBox(stringMessages.hideElementsWithoutUpdateRights()); checkbox.setValue(true); checkboxFilter = new CheckboxEnablableFilter<>(checkbox); filters.add(checkboxFilter); @@ -128,8 +129,9 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { } } - public AbstractFilterablePanel(Iterable all, final ListDataProvider filtered) { - this(all, filtered, /* show default filter text box */ true); + public AbstractFilterablePanel(Iterable all, final ListDataProvider filtered, + final StringMessages stringMessages) { + this(all, filtered, /* show default filter text box */ true, stringMessages); } private void setAll(Iterable all) { diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/CustomizableFilterablePanel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/CustomizableFilterablePanel.java index 7b087250675..9f2a9b356fc 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/CustomizableFilterablePanel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/CustomizableFilterablePanel.java @@ -5,6 +5,7 @@ import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.view.client.ListDataProvider; import com.sap.sse.common.filter.Filter; +import com.sap.sse.gwt.client.StringMessages; /** * Customizable filter panel which allows to create a flexible filter panel with various number of filter inputs (e.g. @@ -19,8 +20,8 @@ public abstract class CustomizableFilterablePanel extends AbstractFilterableP * Does not add the default filter text box yet; use {@link #addDefaultTextBox()} to do so; you may * add other widgets before the default text filter box. */ - public CustomizableFilterablePanel(Iterable all, ListDataProvider filtered) { - super(all, filtered, /* show default filter text box */ false); + public CustomizableFilterablePanel(Iterable all, ListDataProvider filtered, StringMessages stringMessages) { + super(all, filtered, /* show default filter text box */ false, stringMessages); } public void add(Label label, Widget widget, Filter filter) { diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/LabeledAbstractFilterablePanel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/LabeledAbstractFilterablePanel.java index 1b58c83e575..e96196518f8 100755 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/LabeledAbstractFilterablePanel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/LabeledAbstractFilterablePanel.java @@ -4,6 +4,7 @@ import com.google.gwt.user.cellview.client.CellTable; import com.google.gwt.user.client.ui.Label; import com.google.gwt.view.client.ListDataProvider; import com.sap.sse.common.filter.AbstractListFilter; +import com.sap.sse.gwt.client.StringMessages; /** * This Panel contains a label and a text box. Text entered into the text box filters the {@link CellTable} passed to @@ -29,8 +30,9 @@ public abstract class LabeledAbstractFilterablePanel extends AbstractFilterab /** */ - public LabeledAbstractFilterablePanel(Label label, Iterable all, final ListDataProvider filtered) { - super(all, filtered); + public LabeledAbstractFilterablePanel(Label label, Iterable all, final ListDataProvider filtered, + StringMessages stringMessages) { + super(all, filtered, stringMessages); insert(label, 0); } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/RoleDefinitionsPanel.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/RoleDefinitionsPanel.java index dd351c470eb..4d51b82af2f 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/RoleDefinitionsPanel.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/RoleDefinitionsPanel.java @@ -80,7 +80,7 @@ public class RoleDefinitionsPanel extends VerticalPanel { this.userManagementService = userService.getUserManagementService(); rolesListDataProvider = new ListDataProvider<>(); filterablePanelRoleDefinitions = new LabeledAbstractFilterablePanel(new Label(stringMessages.filterRoles()), new ArrayList<>(), - rolesListDataProvider) { + rolesListDataProvider, stringMessages) { @Override public Iterable getSearchableStrings(RoleDefinitionDTO roleDefinition) { return Arrays.asList(roleDefinition.getName(), roleDefinition.getId().toString(), roleDefinition.getPermissions().toString()); diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/UserGroupTableWrapper.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/UserGroupTableWrapper.java index 7a8c9382664..be37598d17d 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/UserGroupTableWrapper.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/UserGroupTableWrapper.java @@ -108,7 +108,7 @@ public class UserGroupTableWrapper extends u -> configACL.openDialog(u)); filterField = new LabeledAbstractFilterablePanel(new Label(stringMessages.filterUserGroups()), - new ArrayList(), dataProvider) { + new ArrayList(), dataProvider, stringMessages) { @Override public Iterable getSearchableStrings(UserGroupDTO t) { List string = new ArrayList(); diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/usergroup/roles/RoleDefinitionTableWrapper.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/usergroup/roles/RoleDefinitionTableWrapper.java index a7899af2614..74da9d5a548 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/usergroup/roles/RoleDefinitionTableWrapper.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/usergroup/roles/RoleDefinitionTableWrapper.java @@ -114,7 +114,7 @@ public class RoleDefinitionTableWrapper extends // filter field configuration filterField = new LabeledAbstractFilterablePanel>( new Label(stringMessages.filterRoles()), new ArrayList>(), - dataProvider) { + dataProvider, stringMessages) { @Override public Iterable getSearchableStrings(Pair t) { List string = new ArrayList(); diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java index 2a5b85c3414..fcb8b0b1b0a 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java @@ -195,7 +195,7 @@ extends TableWrapper { u -> configACL.openDialog(u)); filterField = new LabeledAbstractFilterablePanel(new Label(stringMessages.filterUsers()), - new ArrayList(), dataProvider) { + new ArrayList(), dataProvider, stringMessages) { @Override public Iterable getSearchableStrings(UserDTO t) { List string = new ArrayList(); diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/permissions/WildcardPermissionWithSecurityDTOTableWrapper.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/permissions/WildcardPermissionWithSecurityDTOTableWrapper.java index a1da6c31b8b..907e66ac675 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/permissions/WildcardPermissionWithSecurityDTOTableWrapper.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/permissions/WildcardPermissionWithSecurityDTOTableWrapper.java @@ -119,7 +119,7 @@ public class WildcardPermissionWithSecurityDTOTableWrapper extends // filter field configuration filterField = new LabeledAbstractFilterablePanel( new Label(stringMessages.filterPermission()), new ArrayList(), - dataProvider) { + dataProvider, stringMessages) { @Override public Iterable getSearchableStrings(WildcardPermissionWithSecurityDTO t) { List string = new ArrayList(); diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/roles/RoleWithSecurityDTOTableWrapper.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/roles/RoleWithSecurityDTOTableWrapper.java index 8fc6131a489..818ea6b2f25 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/roles/RoleWithSecurityDTOTableWrapper.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/roles/RoleWithSecurityDTOTableWrapper.java @@ -120,7 +120,7 @@ public class RoleWithSecurityDTOTableWrapper extends // filter field configuration filterField = new LabeledAbstractFilterablePanel(new Label(stringMessages.filterRoles()), - new ArrayList(), dataProvider) { + new ArrayList(), dataProvider, stringMessages) { @Override public Iterable getSearchableStrings(RoleWithSecurityDTO t) { List string = new ArrayList(); From 7c1dba8940693a095138c0662a56f71cfcef4aef Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Thu, 1 Aug 2019 11:26:24 +0200 Subject: [PATCH 31/43] Bug 5092: added release notes for edit filter --- java/com.sap.sailing.www/release_notes_admin.html | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.www/release_notes_admin.html b/java/com.sap.sailing.www/release_notes_admin.html index 581d67c76ea..22a81de7739 100755 --- a/java/com.sap.sailing.www/release_notes_admin.html +++ b/java/com.sap.sailing.www/release_notes_admin.html @@ -21,7 +21,14 @@

      Release Notes - Administration Console

      -

      July 2019

      +

      August 2019

      +
        +
      • Added a filter to hide all elements the current user is not allowed to edit. The filter can + be applied for each table in the AdminConsole and is active per default. +
      • +
      + +

      July 2019

      • Result and competitor import URLs are now only considered when the requesting user has the permission to read that URL.
      • From 7b952be154eb65f8bd6621b700060e46dd23c495 Mon Sep 17 00:00:00 2001 From: Daniel Lisunkin Date: Thu, 1 Aug 2019 13:58:31 +0200 Subject: [PATCH 32/43] Small changes in planning/orc.md --- wiki/planning/orc.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wiki/planning/orc.md b/wiki/planning/orc.md index b2c5e77a458..15674a59700 100644 --- a/wiki/planning/orc.md +++ b/wiki/planning/orc.md @@ -10,6 +10,7 @@ The scoring itself allows to choose between using the simpler provided ToT/ToD s Currently the calculation for a constructed course with set TWAs does work with matching values to the official ORC tools and M2S. The internal calculations follow the ideas provided in the ORC pascal code, many calculating parts are using the predicted velocity value instead of the allowance. The calculation involves the following implemented parts: + - get Allowances for Leg with TWA - get Lagrange interpolated Allowance for TWA/TWS - get Allowances for whole Course out of leg parts @@ -19,6 +20,7 @@ The calculation involves the following implemented parts: ### Mixed Course The next step is to extend the properties of an ORCPerformanceCurveLeg to not only be defined as a leg with a specified TWA and an fixed allowance calculated with Lagrange but also be defined as a leg as a predefined course. + - [ ] Add enums for predefined courses - [ ] Add or change ORCPerformanceCurveLeg implementation (and interface) - [ ] Adapt ORCPerformanceCurveImpl to handle Legs with predefined allowances @@ -32,8 +34,8 @@ This problem should be resolved by the usage of the RaceLog and by the usage of For this purpose there are the following subtasks: - [ ] UML for this concept -- [ ] create RaceLogEvent for TWA/Length information per Leg. This task additionally consists out of some design decisions regarding the revokability of events. -- [ ] create RaceLogEventAnalyzer for this Event +- [x] create RaceLogEvent for TWA/Length information per Leg. This task additionally consists out of some design decisions regarding the revokability of events. +- [x] create RaceLogEventAnalyzer for this Event *currently focussed on these tasks* - [ ] implement logic to get TWA/Length from a TrackedLeg - [ ] implement logic wether to use information from RaceLog or automatic generated from TrackedLeg - [ ] implement Listener on RaceLog From 12878fd2257012e1dd030ebdbde7a7795a5c6525 Mon Sep 17 00:00:00 2001 From: Daniel Lisunkin Date: Thu, 1 Aug 2019 14:01:45 +0200 Subject: [PATCH 33/43] Small changes in planning/orc.md --- wiki/planning/orc.md | 1 + 1 file changed, 1 insertion(+) diff --git a/wiki/planning/orc.md b/wiki/planning/orc.md index 15674a59700..4835ca6c7c6 100644 --- a/wiki/planning/orc.md +++ b/wiki/planning/orc.md @@ -33,6 +33,7 @@ After the functionality for the different course possibilities is added, there n This problem should be resolved by the usage of the RaceLog and by the usage of an adapter pattern to match the information given from a TrackedRace to the ORCPerformanceCurveCourse. For this purpose there are the following subtasks: + - [ ] UML for this concept - [x] create RaceLogEvent for TWA/Length information per Leg. This task additionally consists out of some design decisions regarding the revokability of events. - [x] create RaceLogEventAnalyzer for this Event *currently focussed on these tasks* From 85a2cacac85faf06ce1141576aa9832a1c1eb4a5 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 1 Aug 2019 18:52:23 +0200 Subject: [PATCH 34/43] removed unused HUDSON slave image comment Change-Id: Ie7b0a6baadb9daa6bb02bc2dedce8f52403a3ddb --- configuration/launchhudsonslave | 1 - 1 file changed, 1 deletion(-) diff --git a/configuration/launchhudsonslave b/configuration/launchhudsonslave index ce5b79e4054..963374c8835 100755 --- a/configuration/launchhudsonslave +++ b/configuration/launchhudsonslave @@ -1,7 +1,6 @@ #!/bin/bash AWS=/root/.local/bin/aws REGION=eu-west-1 -#HUDSON_SLAVE_AMI_ID=ami-09f0f1f11364aeddb HUDSON_SLAVE_AMI_ID=ami-027eed1bdca18b979 echo Launching instance... instanceid=`$AWS ec2 run-instances --image-id $HUDSON_SLAVE_AMI_ID --count 1 --instance-type c5d.4xlarge --key-name Axel --security-groups "Sailing Analytics App" --region $REGION --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=Hudson Ubuntu Slave}]' --instance-initiated-shutdown-behavior terminate | tee /tmp/slavelaunch.out | jq .Instances[0].InstanceId | sed -e 's/"//g'` From a2701c756208312579110bae8691d509610a96ae Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 1 Aug 2019 23:54:46 +0200 Subject: [PATCH 35/43] MongoDB replica set: longer shutdown timeout, added REPLICA_SET_VOTES param --- configuration/aws-automation/launch-mongodb-replica.sh | 10 +++++++--- configuration/mongo_instance_setup/add-as-replica | 6 +++++- .../mongo_instance_setup/mongo-replica-set.service | 1 + 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/configuration/aws-automation/launch-mongodb-replica.sh b/configuration/aws-automation/launch-mongodb-replica.sh index 63dfb6a3b59..ce3814d060f 100755 --- a/configuration/aws-automation/launch-mongodb-replica.sh +++ b/configuration/aws-automation/launch-mongodb-replica.sh @@ -13,18 +13,20 @@ # AVAILABILITY_ZONE=eu-west-1c INSTANCE_TYPE=i2.xlarge -IMAGE_ID=ami-0875074f93689aa3a +IMAGE_ID=ami-01b868df7b51fa5e5 KEY_NAME=Axel REPLICA_SET_NAME= REPLICA_SET_PRIMARY= REPLICA_SET_PRIORITY= +REPLICA_SET_VOTES= if [ $# -eq 0 ]; then - echo "$0 [-r ] [-p :] [-P ] [-a ] [-i ] [-k ]" + echo "$0 [-r ] [-p :] [-P ] [-a ] [-i ] [-k ] [-v ]" echo "" echo "-r Replica set name, e.g., live" echo "-p Primary host:port, e.g., mongo0.internal.sapsailing.com:27017" echo "-P priority, e.g., 0 if the replica shall never become PRIMARY" + echo "-v number of votes, e.g., 0 to not let this affect the PRIMARY's votes" echo "-t Instance type; defaults to $INSTANCE_TYPE" echo "-a Availability zone, defaults to $AVAILABILITY_ZONE" echo "-i Amazon Machine Image (AMI) ID to use to launch the instance" @@ -46,6 +48,7 @@ do r) REPLICA_SET_NAME=$OPTARG;; p) REPLICA_SET_PRIMARY=$OPTARG;; P) REPLICA_SET_PRIORITY=$OPTARG;; + v) REPLICA_SET_VOTES=$OPTARG;; t) INSTANCE_TYPE=$OPTARG;; a) AVAILABILITY_ZONE=$OPTARG;; i) IMAGE_ID=$OPTARG;; @@ -57,4 +60,5 @@ done aws ec2 run-instances --placement AvailabilityZone=$AVAILABILITY_ZONE --instance-type $INSTANCE_TYPE --security-group-ids sg-0a9bc2fb61f10a342 --image-id $IMAGE_ID --count 1 --user-data "REPLICA_SET_NAME=$REPLICA_SET_NAME REPLICA_SET_PRIMARY=$REPLICA_SET_PRIMARY -REPLICA_SET_PRIORITY=$REPLICA_SET_PRIORITY" --ebs-optimized --key-name $KEY_NAME --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=MongoDB Replica Set $REPLICA_SET_NAME P$REPLICA_SET_PRIORITY}]" "ResourceType=volume,Tags=[{Key=Name,Value=MongoDB Replica Set $REPLICA_SET_NAME P$REPLICA_SET_PRIORITY}]" +REPLICA_SET_PRIORITY=$REPLICA_SET_PRIORITY +REPLICA_SET_VOTES=$REPLICA_SET_VOTES" --ebs-optimized --key-name $KEY_NAME --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=MongoDB Replica Set $REPLICA_SET_NAME P$REPLICA_SET_PRIORITY}]" "ResourceType=volume,Tags=[{Key=Name,Value=MongoDB Replica Set $REPLICA_SET_NAME P$REPLICA_SET_PRIORITY}]" diff --git a/configuration/mongo_instance_setup/add-as-replica b/configuration/mongo_instance_setup/add-as-replica index 32996a8155b..2556fefcc73 100755 --- a/configuration/mongo_instance_setup/add-as-replica +++ b/configuration/mongo_instance_setup/add-as-replica @@ -11,7 +11,11 @@ REPLICA_SET_PRIORITY=$(ec2-metadata | grep REPLICA_SET_PRIORITY | sed -e 's/^use if [ -z "$REPLICA_SET_PRIORITY" ]; then REPLICA_SET_PRIORITY=1 fi +REPLICA_SET_VOTES=$(ec2-metadata | grep REPLICA_SET_VOTES | sed -e 's/^user-data: //' | sed -e 's/^REPLICA_SET_VOTES=//') +if [ -z "$REPLICA_SET_VOTES" ]; then + REPLICA_SET_VOTES=0 +fi if [ \! -z "REPLICA_SET_PRIMARY" ]; then IP=$(ec2-metadata -o | sed -e 's/^local-ipv4: //') - echo "rs.add({host: \"$IP:27017\", priority: $REPLICA_SET_PRIORITY})" | mongo "mongodb://$REPLICA_SET_PRIMARY/?replicaSet=$REPLICA_SET_NAME&retryWrites=true" + echo "rs.add({host: \"$IP:27017\", priority: $REPLICA_SET_PRIORITY, votes: $REPLICA_SET_VOTES})" | mongo "mongodb://$REPLICA_SET_PRIMARY/?replicaSet=$REPLICA_SET_NAME&retryWrites=true" fi diff --git a/configuration/mongo_instance_setup/mongo-replica-set.service b/configuration/mongo_instance_setup/mongo-replica-set.service index 7868305cef1..5cba8232875 100644 --- a/configuration/mongo_instance_setup/mongo-replica-set.service +++ b/configuration/mongo_instance_setup/mongo-replica-set.service @@ -11,3 +11,4 @@ Type=oneshot RemainAfterExit=true ExecStart=/usr/local/bin/add-as-replica ExecStop=/usr/local/bin/remove-as-replica +TimeoutStopSpec=120s From 753ab9beed578487347ae59576f8c0e347a8c825 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 1 Aug 2019 23:58:23 +0200 Subject: [PATCH 36/43] fixed mongo replica launch script parameter list --- configuration/aws-automation/launch-mongodb-replica.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration/aws-automation/launch-mongodb-replica.sh b/configuration/aws-automation/launch-mongodb-replica.sh index ce3814d060f..e6b0ee13b45 100755 --- a/configuration/aws-automation/launch-mongodb-replica.sh +++ b/configuration/aws-automation/launch-mongodb-replica.sh @@ -41,7 +41,7 @@ if [ $# -eq 0 ]; then exit 2 fi -options='r:p:P:t:a:i:k:' +options='r:p:P:t:a:i:k:v:' while getopts $options option do case $option in From 2a30bb49361eeaf94b33560930f657d5b10d5bd7 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 2 Aug 2019 00:17:54 +0200 Subject: [PATCH 37/43] use 1.4 image for MongoDB replica set instance launch --- configuration/aws-automation/launch-mongodb-replica.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration/aws-automation/launch-mongodb-replica.sh b/configuration/aws-automation/launch-mongodb-replica.sh index e6b0ee13b45..931c343c024 100755 --- a/configuration/aws-automation/launch-mongodb-replica.sh +++ b/configuration/aws-automation/launch-mongodb-replica.sh @@ -13,7 +13,7 @@ # AVAILABILITY_ZONE=eu-west-1c INSTANCE_TYPE=i2.xlarge -IMAGE_ID=ami-01b868df7b51fa5e5 +IMAGE_ID=ami-0e5f927ef86e00bd2 KEY_NAME=Axel REPLICA_SET_NAME= REPLICA_SET_PRIMARY= From d343409df9bf4c72daddb01f7a1aeefbf3a78679 Mon Sep 17 00:00:00 2001 From: "service.tip.git" Date: Thu, 8 Aug 2019 15:56:35 +0000 Subject: [PATCH 38/43] [INTERNAL] Translation delivery: commit by LX Lab Change-Id: I8ee97b5ba36072492407cb9120d0ab8b54de3693 --- .../sap/sailing/gwt/ui/client/StringMessages_es.properties | 6 ++++-- .../sap/sailing/gwt/ui/client/StringMessages_fr.properties | 6 ++++-- .../sap/sailing/gwt/ui/client/StringMessages_it.properties | 6 ++++-- .../sap/sailing/gwt/ui/client/StringMessages_ja.properties | 6 ++++-- .../sap/sailing/gwt/ui/client/StringMessages_pt.properties | 6 ++++-- .../sap/sailing/gwt/ui/client/StringMessages_ru.properties | 6 ++++-- .../sap/sailing/gwt/ui/client/StringMessages_zh.properties | 6 ++++-- .../stringmessages/Polars_StringMessages_it.properties | 2 +- .../stringmessages/Polars_StringMessages_ja.properties | 2 +- .../stringmessages/Polars_StringMessages_zh.properties | 2 +- 10 files changed, 31 insertions(+), 17 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties index cc16cf3188d..0aca1ba8dab 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties @@ -475,8 +475,8 @@ scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=Puntuación baja con scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=Una variante del esquema de puntuación baja que utiliza eliminaciones que constan de rondas.\nCada ronda es una serie de la regata y para la clasificación de la flota se cuenta hacia atrás\nempezando por el número más alto de la primera ronda.\nlf tiene lugar una final y una final de los perdedores, utilizan 1 y 2 para la clasificación. Empiezan con 3 para la ronda de semifinal. scoringSchemeLowPointForLeagueOverallLeaderboard=Puntuación baja para la tabla de clasificación general, los empates se resuelven por el total de puntos de las pruebas, luego la última prueba scoringSchemeLowPointForLeagueOverallLeaderboardDescription=En lugar del sistema habitual de recuento hacia atrás que se utiliza para los esquemas de puntuación baja para romper empates, para clasificar los competidores que tienen los mismos totales de puntos se compara el total de los puntos que han obtenido en todas las pruebas. Si aún persiste el empate, el empate se resuelve con la última prueba. -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=Puntuación baja, los empates se resuelven por la última serie -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=En lugar del sistema habitual de recuento para los esquemas de puntuación baja para romper empates, se tiene en cuenta la puntuación de la serie final sin regatas excluidas si dos competidores tienen los mismos puntos. +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=Puntuación baja, los empates se resuelven por la última serie sin medalla +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=En lugar del sistema habitual de recuento para los esquemas de puntuación baja para romper empates, se tiene en cuenta la puntuación de la serie sin medalla sin regatas excluidas si dos competidores tienen los mismos puntos. scoringSchemeLowPointWithAutomaticRdg=Sistema de puntuación baja, RDG obtiene una puntuación por defecto basada en la media de todas las puntuaciones que no sean de RDG scoringSchemeHighPointFirstGetsOne=Puntuación alta, el ganador obtiene 1 punto; el perdedor, 0 scoringSchemeHighPointFirstGetsOneDescription=Puntuación alta, el ganador obtiene 1 punto; el perdedor, 0; los empates se han resuelto basándose en la comparación directa con la última comparación directa resolviendo otro empate; si se producen ciclos en la comparación directa, los competidores se han tratado por igual; los competidores que no hayan competido entre sí (aún) se clasificarán basándose en su posición en el gráfico de victorias/derrotas. @@ -1284,6 +1284,7 @@ editMarkPassings=Editar superaciones de marca editMarkPositions=Editar posiciones de marca removeFixedPassings=Eliminar superación de marca corregida setFixedPassing=Fijar hora como superación de marca +chooseFixedPassing=Seleccione la hora como superación de marca setSuppressedPassing=Suprimir inicio de superación de marca con actual removeSuppressedPassing=Eliminar superación de marca suprimida warningSettingFixedPassing=La hora de superación {0} del punto de ruta no puede ser anterior a la hora del punto de ruta anterior o posterior a la hora del punto siguiente @@ -1293,6 +1294,7 @@ errorSuppressingPassing=Error al suprimir superaciones de marca: {0} errorRemovingSupressedPassing=Error al eliminar superaciones de marca suprimidas: {0} errorTryingToObtainMarkPassing=Error al intentar obtener superaciones de marca: {0} errorTryingToObtainRaceLogMarkPassingData=Error al intentar obtener datos de superación de marca de registro de carrera: {0} +warningMarkPassingChangesNoEffect=Advertencia: la carrera no está respaldada por el algoritmo de superación de marca interno. Las modificaciones no tendrán efecto. email=Correo electrónico pleaseEnterAnEmail=Indique un correo electrónico inviteCompetitors=Invitar a competidores diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties index 8d965ea698d..b6bf4f4b726 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties @@ -475,8 +475,8 @@ scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=Système de points à scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=Une variante du schéma de scores a minima qui utilise des éliminations sous forme de tours. \nChaque tour est organisé comme série dans la régate, et l''ordre de départ de la flotte est inversé, \ncommençant par le numéro le plus élevé pour le premier tour. \nSi une finale et une finale des perdants ont lieu, utilisez 1 et 2 comme ordre. Commencez à trois pour le tour des demi-finales. scoringSchemeLowPointForLeagueOverallLeaderboard=Système de points à minima pour le palmarès général, en cas d''égalité, le total des points de l''Act est utilisé, puis celui du dernier Act scoringSchemeLowPointForLeagueOverallLeaderboardDescription=À la place du système habituel de comptage pour schémas à minima en cas d''égalité, les concurrents dont le total des points est égal sont départagés en comparant le total des points qu''ils ont obtenus dans tous les Act. Si l''égalité persiste, la victoire est accordée en fonction du classement dans le dernier Act. -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=Système de points a minima, en cas d''égalité, seule la dernière série compte -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=À la place du système habituel de comptage pour schémas à minima en cas d''égalité, le score de la dernière série sans exclusion de course est pris en compte si deux concurrents sont à égalité. +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=Système de points a minima, en cas d''égalité, seule la dernière série non médaillée compte +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=À la place du système habituel de comptage pour schémas à minima en cas d''égalité, le score de la dernière série non médaillée sans exclusion de course est pris en compte si deux concurrents sont à égalité. scoringSchemeLowPointWithAutomaticRdg=Système de points a minima, reclassement à une manche avec score par défaut basé sur la moyenne de tous les scores non reclassés. scoringSchemeHighPointFirstGetsOne=Système de points avec bonus, le vainqueur obtient 1 point, le perdant 0 scoringSchemeHighPointFirstGetsOneDescription=Système de points avec bonus, le vainqueur obtient 1 point, le perdant 0. En cas d''égalité, l''égalité est départagée par comparaison directe avec la dernière comparaison directe où des concurrents à égalité ont été départagés. Si des cycles avec comparaison directe existent, les concurrents sont traités à égalités ; les concurrents qui ne se sont pas (encore) affrontés sont classés en fonction de leur position dans le classement des courses gagnées/perdues. @@ -1284,6 +1284,7 @@ editMarkPassings=Modifier passages des marques editMarkPositions=Modifier positions des marques removeFixedPassings=Supprimer passage de marque fixé setFixedPassing=Définir l''heure comme passage de marque +chooseFixedPassing=Sélectionner l''heure comme passage de marque setSuppressedPassing=Supprimer passage de marque en commençant par marque actuelle removeSuppressedPassing=Supprimer passage de marque supprimé warningSettingFixedPassing=L''heure à laquelle le point de cheminement {0} a été passé ne peut pas être antérieure à l''heure de passage du point de cheminement précédent, ni postérieure à l''heure de passage du point de cheminement suivant. @@ -1293,6 +1294,7 @@ errorSuppressingPassing=Erreur lors de la suppression des passages de marques : errorRemovingSupressedPassing=Erreur lors de la suppression des passages de marques supprimés : {0} errorTryingToObtainMarkPassing=Erreur lors de la tentative d''obtention des passages de marques : {0} errorTryingToObtainRaceLogMarkPassingData=Erreur lors de la tentative d''obtention des données de passages de marques du journal de course : {0} +warningMarkPassingChangesNoEffect=Avertissement : la course n''est pas gérée par un algorithme de passage de marque interne. Les modifications seront sans effet. email=E-mail pleaseEnterAnEmail=Saisissez un e-mail. inviteCompetitors=Inviter des concurrents diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_it.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_it.properties index cacbe67887c..d7385728b22 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_it.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_it.properties @@ -475,8 +475,8 @@ scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=Punteggio minimo con scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=Una variante dello schema di calcolo del punteggio minimo che utilizza eliminazioni attraverso round.\nOgni round verrà configurato come una serie nella manifestazione e l''ordine delle flotte procede all''indietro\ncominciando dal numero più alto per il primo round.\nSe si svolgono una finale e una finale tra perdenti, utilizzare 1 e 2 per il relativo ordine. Iniziare con 3 per il round della semifinale. scoringSchemeLowPointForLeagueOverallLeaderboard=Punteggio minimo per classifica generale, parità risolta con la somma dei punti delle prove, quindi ultima prova scoringSchemeLowPointForLeagueOverallLeaderboardDescription=Invece dell''usuale sistema di count-back utilizzato per il punteggio minimo per risolvere le parità, i concorrenti con uguali punti totali vengono confrontati in base al totale di punti accumulati in tutte le prove. Se il pareggio ancora permane, viene risolto in base all''ultima prova. -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=Punteggio minimo, parità risolta solo in base all''ultima serie -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=Invece dell''usuale sistema di count-back degli schemi di punteggio minimo per risolvere i pareggi, il punteggio della serie finale senza esclusione di prove viene considerato se i concorrenti hanno pari punti. +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=Punteggio minimo, parità risolta solo in base all''ultima non-medal series +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=Invece dell''usuale sistema di count-back degli schemi di punteggio minimo per risolvere i pareggi, il punteggio dell''ultima non-medal series senza esclusione di prove viene considerato se i concorrenti hanno pari punti. scoringSchemeLowPointWithAutomaticRdg=Sistema di punteggio minimo, RDG ottiene un punteggio predefinito in base alla media di tutti i punteggi non RDG scoringSchemeHighPointFirstGetsOne=Punteggio massimo, il vincitore ottiene 1 punto, il perdente 0 scoringSchemeHighPointFirstGetsOneDescription=Punteggio massimo, il vincitore ottiene 1 punto, il perdente 0; i pareggi vengono risolti in base al confronto diretto con l''ultimo confronto diretto che ha risolto un altro pareggio; in caso di catene nei confronti diretti, i concorrenti vengono trattati alla pari; i concorrenti che non hanno (ancora) gareggiato fra loro vengono classificati in base alla loro posizione nel grafico vittorie/sconfitte. @@ -1284,6 +1284,7 @@ editMarkPassings=Modifica passaggi segnali editMarkPositions=Modifica posizioni segnali removeFixedPassings=Rimuovi passaggio segnale fisso setFixedPassing=Imposta ora come passaggio segnale +chooseFixedPassing=Scegli ora come passaggio segnale setSuppressedPassing=Annulla passaggio segnale a cominciare dall''attuale removeSuppressedPassing=Rimuovi passaggio segnale annullato warningSettingFixedPassing=l''ora del passaggio del waypoint {0} non può essere antecedente all''ora del precedente waypoint o posteriore all''ora del successivo @@ -1293,6 +1294,7 @@ errorSuppressingPassing=Errore in annullamento passaggi segnale: {0} errorRemovingSupressedPassing=Errore in rimozione passaggi segnali annullati: {0} errorTryingToObtainMarkPassing=Errore in tentativo di ottenere passaggi segnale: {0} errorTryingToObtainRaceLogMarkPassingData=Errore in tentativo di ottenere dati sul passaggio segnale dal registro gara: {0} +warningMarkPassingChangesNoEffect=Attenzione: la gara non è supportata dall''algoritmo interno del passaggio segnale. Le modifiche non saranno valide. email=E-mail pleaseEnterAnEmail=Inserire un''e-mail. inviteCompetitors=Invita concorrenti diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties index 59db7b5fef3..156543f7801 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties @@ -475,8 +475,8 @@ scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=低得点方式、予 scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=ラウンドから構成される予選を用いた低得点方式のバリエーションです。\n各ラウンドがレガッタ内のシリーズとして形成されることになり、フリート順序は\n最初のラウンドで最も大きい数から開始してカウントダウンします。\n決勝や最下位決定戦が行われる場合は、その順序として 1 および 2 を使用します。準決勝ラウンドは 3 から始めます。 scoringSchemeLowPointForLeagueOverallLeaderboard=全体リーダーボードに対して低得点方式、アクト総得点、次に最終アクトによって順位を決定 scoringSchemeLowPointForLeagueOverallLeaderboardDescription=順位決定のための低得点方式に使用される通常のカウントダウン方式ではなく、総得点が同点の競技者が全アクト共通で得点した総得点で比較されます。これでも同順位となる場合は、最終アクトによって順位を決定します。 -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=低得点方式、最終シリーズのみに基づいて順位を決定 -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=順序を決定するための低得点方式の通常のカウントダウン方式ではなく、2 艇の競技者の得点が同一の場合に、除外するレースなしに最終シリーズの得点を考慮します。 +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=低得点方式、最後の非メダルシリーズのみに基づいて順位を決定 +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=順序を決定するための低得点方式の通常のカウントダウン方式ではなく、2 艇の競技者の得点が同一の場合に、除外するレースなしに最後の非メダルシリーズの得点を考慮します。 scoringSchemeLowPointWithAutomaticRdg=低得点方式、RDG (救済を受けた艇) はすべての非 RDG (Redress give) スコアの平均に基づくデフォルトスコアを獲得 scoringSchemeHighPointFirstGetsOne=高得点方式、勝者が 1 点、敗者が 0 点を獲得 scoringSchemeHighPointFirstGetsOneDescription=高得点方式、勝者が 1 点、敗者が 0 点を獲得します。順位の決定は、同順位が崩れた最終の直接比較に基づいて行われます。直接比較が繰り返されている場合、競技者は対等に扱われます。(まだ) 直接対戦していない競技者は勝敗グラフにおける位置に基づいて並べられます。 @@ -1284,6 +1284,7 @@ editMarkPassings=マーク通過編集 editMarkPositions=マーク位置編集 removeFixedPassings=固定マーク通過を削除 setFixedPassing=マーク通過の時刻を設定 +chooseFixedPassing=マーク通過の時刻を選択 setSuppressedPassing=現在のもので開始したマーク通過を非表示 removeSuppressedPassing=非表示のマーク通過を削除 warningSettingFixedPassing=変針点 {0} を通過する時刻は、前の変針点の時刻より前であってはならず、後の変針点の時刻より後であってはなりません。 @@ -1293,6 +1294,7 @@ errorSuppressingPassing=マーク通過の非表示でエラー発生: {0} errorRemovingSupressedPassing=非表示のマーク通過の削除でエラー発生: {0} errorTryingToObtainMarkPassing=マーク通過を取得しようとしてエラーが発生: {0} errorTryingToObtainRaceLogMarkPassingData=レースログのマーク通過データを取得しようとしてエラーが発生: {0} +warningMarkPassingChangesNoEffect=警告: レースはマーク通過の内部アルゴリズムによって裏付けられていません。変更は反映されません。 email=電子メール pleaseEnterAnEmail=電子メールを入力してください inviteCompetitors=競技者の招待 diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties index 52282e85741..8a140f54b47 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties @@ -475,8 +475,8 @@ scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=Sistema linear com el scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=Uma variante do esquema de pontuação linear, utilizando eliminatórias compostas de rodadas.\nCada rodada será modelada como uma série na regata e a ordenação da flotilha com contagem regressiva\ncomeçando pelo número mais alto para a primeira rodada.\nSe for realizada uma final e uma final "B", utilize 1 e 2 como ordenação. Comece com 3 para a rodada da semifinal. scoringSchemeLowPointForLeagueOverallLeaderboard=Sistema linear para painel de classificação geral, desempates efetuados pela soma dos pontos das etapas, em seguida pela última etapa scoringSchemeLowPointForLeagueOverallLeaderboardDescription=Em vez do habitual sistema de contagem regressiva utilizado para esquemas lineares para efetuar os desempates, os competidores com somas de pontos iguais são comparados comparando a soma dos pontos obtidos em todas as etapas. Se o empate continuar, o desempate é efetuado pela última etapa. -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=Sistema linear, desempates só com base na última série -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=Em vez do habitual sistema de contagem regressiva para esquemas lineares para efetuar os desempates, a pontuação da série final sem corridas excluídas é considerada se dois competidores tiverem pontuações iguais. +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=Sistema linear, desempates só com base na última série sem medalhas +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=Em vez do habitual sistema de contagem regressiva para esquemas lineares para efetuar os desempates, a pontuação da série final sem medalhas sem corridas excluídas é considerada se dois competidores tiverem pontuações iguais. scoringSchemeLowPointWithAutomaticRdg=Sistema linear, a RDG recebe a pontuação padrão com base na média de todas as pontuações não RDG scoringSchemeHighPointFirstGetsOne=Sistema de bônus, o vencedor recebe 1 ponto, o perdedor 0 scoringSchemeHighPointFirstGetsOneDescription=Sistema de bônus, o vencedor recebe 1 ponto, o perdedor 0; os desempates são efetuados com base na comparação direta com a última comparação direta de outro desempate; se ocorrerem ciclos nas comparações diretas, os competidores são tratados da mesma forma; os competidores que (ainda) não competiram uns com os outros são ordenados com base na sua posição no diagrama de vitórias/derrotas. @@ -1284,6 +1284,7 @@ editMarkPassings=Processar passagens da marca editMarkPositions=Processar posições da marca removeFixedPassings=Remover passagem da marca fixa setFixedPassing=Definir hora como passagem da marca +chooseFixedPassing=Selecionar hora como passagem da marca setSuppressedPassing=Suprimir passagem da marca começando pela atual removeSuppressedPassing=Remover passagem da marca suprimida warningSettingFixedPassing=O tempo de passagem do waypoint {0} não pode ser anterior ao tempo do waypoint anterior ou posterior ao tempo do seguinte @@ -1293,6 +1294,7 @@ errorSuppressingPassing=Erro ao suprimir passagens da marca: {0} errorRemovingSupressedPassing=Erro ao remover passagens da marca suprimidas: {0} errorTryingToObtainMarkPassing=Erro ao tentar obter passagens da marca: {0} errorTryingToObtainRaceLogMarkPassingData=Erro ao tentar obter dados de passagem da marca do registro da corrida: {0} +warningMarkPassingChangesNoEffect=Aviso: a corrida não é apoiada pelo algoritmo de passagem da marca interno. As modificações não terão efeito. email=E-mail pleaseEnterAnEmail=Insira um e-mail. inviteCompetitors=Convidar competidores diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index 52d408826fe..a00439e408c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -475,8 +475,8 @@ scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=Низкий балл scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=Вариант схемы оценки с низкими баллами, использующий туры на выбывание.\nКаждый тур моделируется как серия в регате, и суда ранжируются в обратном порядке,\nначиная с наибольшего числа за первый раунд.\nВ финале и при определении 3-го места используйте ранги 1 и 2. Для полуфинального тура начните с 3. scoringSchemeLowPointForLeagueOverallLeaderboard=Низкий балл по всей таблице лидеров, равенство разрешается по сумме актов, затем по последнему акту scoringSchemeLowPointForLeagueOverallLeaderboardDescription=Вместо обычной системы обратного отсчета, используемой для разрешения равенства в схемах низких баллов, участники с равными суммами баллов сравниваются по сумме баллов, полученных за все акты. Если равенство сохраняется, оно разрешается по последнему акту. -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=Низкий балл, равенство разрешается только по последней серии -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=Вместо обычной системы обратного отсчета, используемой для разрешения равенства в системах низких баллов, при равенстве оценок двух участников учитывается оценка последней серии без исключенных гонок. +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=Низкий балл, равенство разрешается только по последней не медальной серии +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=Вместо обычной системы обратного отсчета, используемой для разрешения равенства в системах низких баллов, при равенстве оценок двух участников учитывается оценка последней не медальной серии без исключенных гонок. scoringSchemeLowPointWithAutomaticRdg=Система низких баллов, RDG получает оценку по умолчанию на основе среднего всех оценок без RDG scoringSchemeHighPointFirstGetsOne=Высокий балл, победитель получает 1 балл, проигравший получает 0 баллов scoringSchemeHighPointFirstGetsOneDescription=Высокий балл, победитель получает 1 балл, проигравший получает 0 баллов; равенство разрешается путем прямого сравнения с последним прямым сравнением при разрешении другого равенства; если в прямом сравнении обнаружен цикл, участники считаются равными; участники, (еще) не соревновавшиеся друг против друга, располагаются согласно позициям в графе побед/поражений. @@ -1284,6 +1284,7 @@ editMarkPassings=Изменить прохождения отметок editMarkPositions=Изменить позиции отметок removeFixedPassings=Удалить прохождение фиксированной отметки setFixedPassing=Установить время как прохождение отметки +chooseFixedPassing=Выбрать время как прохождение отметки setSuppressedPassing=Подавить прохождение отметки, начиная с текущей removeSuppressedPassing=Удалить подавленное прохождение отметки warningSettingFixedPassing=Время прохождения отметки {0} не может быть раньше времени предыдущей отметки или позже времени следующей @@ -1293,6 +1294,7 @@ errorSuppressingPassing=Ошибка при подавлении прохожд errorRemovingSupressedPassing=Ошибка при удалении подавленных прохождений отметок: {0} errorTryingToObtainMarkPassing=Ошибка при попытке получить прохождения отметок: {0} errorTryingToObtainRaceLogMarkPassingData=Ошибка при попытке получить данные журнала гонки о прохождении отметок: {0} +warningMarkPassingChangesNoEffect=Предупреждение: гонка не поддерживается внутренним алгоритмом прохождения отметок. Изменения не будут иметь влияния. email=Эл. почта pleaseEnterAnEmail=Введите электронную почту. inviteCompetitors=Пригласить участников diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties index 018a8860a42..61e4b7f969f 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties @@ -475,8 +475,8 @@ scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=采用多轮淘汰制 scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=低分记分系统的一种,采用多轮淘汰制。\n每一轮应作为比赛系列,船队顺序\n从第一轮的最高数向后计。\n如果有最终一支舰队和最终败者,则使用 1 和 2 排序。 半决赛从第 3 位开始。 scoringSchemeLowPointForLeagueOverallLeaderboard=总积分榜的低分,分站赛得分总和,否则采用最后一个分站赛的得分打破平局 scoringSchemeLowPointForLeagueOverallLeaderboardDescription=与用于低分记分系统打破平局的常规倒算系统不同,对于总得分相同的参赛队,比较其在所有分站赛中的得分总和。 如果仍有平局,则以最后一个分站赛的得分打破平局。 -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=低分,仅根据上一系列赛打破平局。 -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=与用于低分记分系统打破平局的常规倒算系统不同,如果两支参赛队的得分相同,则考虑不排除比赛轮次的总决赛系列赛的得分。 +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=低分,仅根据最后非奖牌轮系列赛打破平局。 +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=与用于低分记分系统打破平局的常规倒算系统不同,如果两支参赛队的得分相同,则考虑不排除比赛轮次的最后非奖牌轮系列赛的得分。 scoringSchemeLowPointWithAutomaticRdg=低分系统,RDG 根据所有非 RDG 得分的平均值获得默认得分 scoringSchemeHighPointFirstGetsOne=高分,获胜者得 1 分,败者 0 分 scoringSchemeHighPointFirstGetsOneDescription=高分,获胜者得 1 分,败者 0 分;根据与打破其他平局的上次直接比较进行直接比较打破平局;如果直接比较中出现循环赛,公平对待参赛队;根据输赢图中的位置将(尚未)互相比赛的参赛队排序。 @@ -1284,6 +1284,7 @@ editMarkPassings=编辑绕标 editMarkPositions=编辑标位 removeFixedPassings=移除固定的绕标 setFixedPassing=设置绕标时间 +chooseFixedPassing=选择绕标时间 setSuppressedPassing=从当前开始禁止绕标 removeSuppressedPassing=移除禁止的绕标 warningSettingFixedPassing=通过{0}航路点的时间不能在上一航路点的时间之前或下一航路点的时间之后 @@ -1293,6 +1294,7 @@ errorSuppressingPassing=禁止绕标出错: {0} errorRemovingSupressedPassing=移除禁止的绕标出错: {0} errorTryingToObtainMarkPassing=尝试获取绕标出错: {0} errorTryingToObtainRaceLogMarkPassingData=尝试获取比赛轮次日志绕标数据出错: {0} +warningMarkPassingChangesNoEffect=警告:内部绕标算法不支持竞赛。更改将不会产生任何影响! email=电子邮件 pleaseEnterAnEmail=请输入电子邮件。 inviteCompetitors=邀请参赛队 diff --git a/java/com.sap.sailing.polars.datamining/resources/stringmessages/Polars_StringMessages_it.properties b/java/com.sap.sailing.polars.datamining/resources/stringmessages/Polars_StringMessages_it.properties index 082ef7fc8ab..db0fa7505c5 100644 --- a/java/com.sap.sailing.polars.datamining/resources/stringmessages/Polars_StringMessages_it.properties +++ b/java/com.sap.sailing.polars.datamining/resources/stringmessages/Polars_StringMessages_it.properties @@ -9,4 +9,4 @@ WindIsConfident=Affidabile misurazione del vento Rank=Posizione in classifica BackendPolars=Polari back-end TargetBeatAngle=Angolo target di bolina -TargetRunawayAngle=Angolo di fuga target +TargetRunawayAngle=Angolo di lasco target diff --git a/java/com.sap.sailing.polars.datamining/resources/stringmessages/Polars_StringMessages_ja.properties b/java/com.sap.sailing.polars.datamining/resources/stringmessages/Polars_StringMessages_ja.properties index fb48b7dfabe..8dfec87ebb4 100644 --- a/java/com.sap.sailing.polars.datamining/resources/stringmessages/Polars_StringMessages_ja.properties +++ b/java/com.sap.sailing.polars.datamining/resources/stringmessages/Polars_StringMessages_ja.properties @@ -9,4 +9,4 @@ WindIsConfident=風測定確度 Rank=ランク BackendPolars=バックエンドポーラー TargetBeatAngle=目標ビートアングル -TargetRunawayAngle=目標ランナウェイアングル +TargetRunawayAngle=目標ランアングル diff --git a/java/com.sap.sailing.polars.datamining/resources/stringmessages/Polars_StringMessages_zh.properties b/java/com.sap.sailing.polars.datamining/resources/stringmessages/Polars_StringMessages_zh.properties index 6f344bcf675..2455df4358c 100755 --- a/java/com.sap.sailing.polars.datamining/resources/stringmessages/Polars_StringMessages_zh.properties +++ b/java/com.sap.sailing.polars.datamining/resources/stringmessages/Polars_StringMessages_zh.properties @@ -9,4 +9,4 @@ WindIsConfident=风力测量置信度 Rank=名次 BackendPolars=后端极坐标图 TargetBeatAngle=目标迎风航行角度 -TargetRunawayAngle=目标失控角度 +TargetRunawayAngle=目标顺风航行角度 From c2e66b24e48a699d9c7c3d4b31f119d28df70b07 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Sun, 11 Aug 2019 14:54:55 -0600 Subject: [PATCH 39/43] performance improvement by re-using total points calculation for net points in comparator Change-Id: I92a0fdf5270414d05465fbb3a6101e11dc736a3b --- .../sap/sailing/domain/leaderboard/Leaderboard.java | 10 ++++++++++ .../impl/AbstractSimpleLeaderboardImpl.java | 9 ++++++++- .../impl/LeaderboardTotalRankComparator.java | 6 ++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java index 01b3ed75872..5e4366997d0 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; import com.sap.sailing.domain.base.Boat; import com.sap.sailing.domain.base.BoatClass; @@ -539,6 +540,15 @@ public interface Leaderboard extends LeaderboardBase, HasRaceColumns { Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint, Set discardedRaceColumns); + /** + * Same as {@link #getNetPoints(Competitor, RaceColumn, TimePoint, Set)}, only that a supplier for + * the total points for the {@code competitor} in column {@code raceColumn} at time point {@code timePoint} + * is provided. This helps if a caller also needs to determine the total points anyway, saving redundant + * calculations. + */ + Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint, + Set discardedRaceColumns, Supplier totalPointsProvider); + TimePoint getNowMinusDelay(); /** diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java index 8185529a029..e1c2add400f 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java @@ -13,6 +13,7 @@ import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -466,11 +467,17 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW @Override public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint, Set discardedRaceColumns) { + return getNetPoints(competitor, raceColumn, timePoint, discardedRaceColumns, ()->getTotalPoints(competitor, raceColumn, timePoint)); + } + + @Override + public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint, + Set discardedRaceColumns, Supplier totalPointsProvider) { Double result; if (isDiscarded(competitor, raceColumn, timePoint, discardedRaceColumns)) { result = 0.0; } else { - final Double totalPoints = getTotalPoints(competitor, raceColumn, timePoint); + final Double totalPoints = totalPointsProvider.get(); if (totalPoints == null) { result = null; } else { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LeaderboardTotalRankComparator.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LeaderboardTotalRankComparator.java index 3b79eee114d..377cfbe0fd1 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LeaderboardTotalRankComparator.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LeaderboardTotalRankComparator.java @@ -94,8 +94,10 @@ public class LeaderboardTotalRankComparator implements Comparator { this.discardedRaceColumnsPerCompetitor.put(competitor, discardedRaceColumns); for (RaceColumn raceColumn : raceColumnsToConsider) { Pair key = new Util.Pair(competitor, raceColumn); - netPointsCache.put(key, leaderboard.getNetPoints(competitor, raceColumn, timePoint, discardedRaceColumns)); - totalPointsCache.put(key, leaderboard.getTotalPoints(competitor, raceColumn, timePoint)); + final Double totalPoints = leaderboard.getTotalPoints(competitor, raceColumn, timePoint); + netPointsCache.put(key, leaderboard.getNetPoints(competitor, raceColumn, timePoint, discardedRaceColumns, + /* total points provider */ ()->totalPoints)); + totalPointsCache.put(key, totalPoints); } } } From 7f89731e2c3392a0fd5e5bdbfe046182a6e7f51c Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Mon, 12 Aug 2019 09:49:00 +0200 Subject: [PATCH 40/43] Bug 5101: attempt to fix sporadically failing selenium test with LeaderboardDetailsPanel --- .../LeaderboardDetailsPanelPO.java | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/leaderboard/LeaderboardDetailsPanelPO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/leaderboard/LeaderboardDetailsPanelPO.java index a9ba620a57b..d8d4d510ca6 100644 --- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/leaderboard/LeaderboardDetailsPanelPO.java +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/leaderboard/LeaderboardDetailsPanelPO.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Objects; import java.util.function.Function; +import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.WebDriverWait; @@ -96,6 +97,9 @@ public class LeaderboardDetailsPanelPO extends PageArea { @FindBy(how = BySeleniumId.class, using = "TrackedRacesFilterTextBox") private WebElement trackedRacesFilterTextBox; + @FindBy(how = BySeleniumId.class, using = "RefreshButton") + private WebElement refreshButton; + public LeaderboardDetailsPanelPO(WebDriver driver, WebElement element) { super(driver, element); } @@ -175,15 +179,30 @@ public class LeaderboardDetailsPanelPO extends PageArea { return findRace(race); } }); - DataEntryPO trackingRow = webDriverWait.until(new Function() { + DataEntryPO trackingRow; + + try { + trackingRow = findTrackingRow(tracking, webDriverWait); + } catch (TimeoutException e) { + // click the refresh button to refresh the tracking grid + refreshButton.click(); + trackingRow = findTrackingRow(tracking, webDriverWait); + } + + raceRow.select(); + trackingRow.select(); + waitForAjaxRequests(); // the selection will update elements of the cell table; wait until the callback has been + // received + } + + private DataEntryPO findTrackingRow(TrackedRaceDescriptor tracking, WebDriverWait webDriverWait) + throws TimeoutException { + return webDriverWait.until(new Function() { @Override public DataEntryPO apply(WebDriver t) { return findTracking(tracking); } }); - raceRow.select(); - trackingRow.select(); - waitForAjaxRequests(); // the selection will update elements of the cell table; wait until the callback has been received } private DataEntryPO findRace(RaceDescriptor race) { From aa07fedae095bb81a7e806f63e6af09502f1383c Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Mon, 12 Aug 2019 09:59:37 +0200 Subject: [PATCH 41/43] added missing getNetPoints method in DelegatingRegattaLeaderboardWithCompetitorElimination to fix compiler error --- ...egatingRegattaLeaderboardWithCompetitorElimination.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelegatingRegattaLeaderboardWithCompetitorElimination.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelegatingRegattaLeaderboardWithCompetitorElimination.java index d0dfd8cf9af..841e32df4c2 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelegatingRegattaLeaderboardWithCompetitorElimination.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelegatingRegattaLeaderboardWithCompetitorElimination.java @@ -495,4 +495,11 @@ public class DelegatingRegattaLeaderboardWithCompetitorElimination extends Abstr public void deregisterBoats(Iterable boats) { getFullLeaderboard().deregisterBoats(boats); } + + @Override + public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint, + Set discardedRaceColumns, Supplier totalPointsProvider) { + return getFullLeaderboard().getNetPoints(competitor, raceColumn, timePoint, discardedRaceColumns, + totalPointsProvider); + } } From 4fb4a9af00bd93f2a156a7edcae32e0e7dad2b71 Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Mon, 12 Aug 2019 10:33:37 +0200 Subject: [PATCH 42/43] Bug 5101: drive-by fix for sporadically failing RegattaApiTest --- .../selenium/api/regatta/RegattaApi.java | 22 +++++++++++++++++++ .../selenium/api/test/RegattaApiTest.java | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/regatta/RegattaApi.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/regatta/RegattaApi.java index 8131eb13716..f569c3c39ef 100644 --- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/regatta/RegattaApi.java +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/regatta/RegattaApi.java @@ -4,9 +4,11 @@ import java.util.Map; import java.util.Optional; import java.util.TreeMap; import java.util.UUID; +import java.util.function.Predicate; import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import org.openqa.selenium.TimeoutException; import com.sap.sailing.selenium.api.core.ApiContext; @@ -29,6 +31,26 @@ public class RegattaApi { return new RegattaRaces(ctx.get(REGATTAS + "/" + regattaName + LIST_REGATTA_RACES)); } + public RegattaRaces getRegattaRaces(ApiContext ctx, String regattaName, Predicate predicateToCheck) + throws TimeoutException { + for (int i = 0; i < 20; i++) { + final RegattaRaces regattaRaces = getRegattaRaces(ctx, regattaName); + if (predicateToCheck.test(regattaRaces)) { + return regattaRaces; + } + if (i == 19) { + // skip unnecessary 500ms wait + break; + } + try { + Thread.sleep(500); + } catch (InterruptedException e) { + throw new TimeoutException(e); + } + } + throw new TimeoutException("Expected condition failed, 20 tries, waited for 10 seconds."); + } + public Competitor createAndAddCompetitor(ApiContext ctx, String regattaName, String boatclass, String competitorEmail, String competitorName, String nationalityIOC, UUID deviceUuid) { return createAndAddCompetitor(ctx, regattaName, boatclass, competitorEmail, competitorName, nationalityIOC, diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/RegattaApiTest.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/RegattaApiTest.java index 66e8b9a80ed..c25ab0a2e72 100644 --- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/RegattaApiTest.java +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/test/RegattaApiTest.java @@ -102,7 +102,7 @@ public class RegattaApiTest extends AbstractSeleniumTest { RaceColumn[] raceColumns = regattaApi.addRaceColumn(ctx, EVENT_NAME, "R", 1); leaderboardApi.startRaceLogTracking(ctx, EVENT_NAME, raceColumns[0].getRaceName(), "Default"); - regattaRaces = regattaApi.getRegattaRaces(ctx, EVENT_NAME); + regattaRaces = regattaApi.getRegattaRaces(ctx, EVENT_NAME, r -> r.getRaces().length > 0); assertEquals("read: reagtta.series should have 1 entries", 1, regattaRaces.getRaces().length); } From 9e668b187f7bbadfa604146620b3ba8703b6e916 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 14 Aug 2019 22:20:04 -0600 Subject: [PATCH 43/43] catch all Exceptions in thread spawned for RacingEventServiceImpl initialization; this will now log all exceptions that occur which otherwise ended up in the init background thread's default thread group exception handler which simply prints it to stderr. Change-Id: If3f1bcf88b4ca365f22805f6da08c11a0ec39e7e --- .../src/com/sap/sailing/server/impl/Activator.java | 11 +---------- .../sailing/server/impl/RacingEventServiceImpl.java | 1 - 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java index e617930a836..0bc62c7239c 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java @@ -133,8 +133,7 @@ public class Activator implements BundleActivator { // only continue once we have the service, as some of the services require it to start properly securityServiceTracker.waitForService(0); internalStartBundle(context); - } catch (InterruptedException | MalformedObjectNameException | InstanceAlreadyExistsException - | MBeanRegistrationException | NotCompliantMBeanException | MalformedURLException e) { + } catch (Exception e) { logger.log(Level.SEVERE, "Could not start RacingEvent service properly", e); } }; @@ -204,39 +203,31 @@ public class Activator implements BundleActivator { InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { mailQueue = new ExecutorMailQueue(mailServiceTracker); notificationService = new SailingNotificationServiceImpl(context, mailQueue); - trackedRegattaListener = new OSGiBasedTrackedRegattaListener(context); - registrations.add(context.registerService(HasPermissionsProvider.class, (HasPermissionsProvider) SecuredDomainType::getAllInstances, null)); - registrations.add(context.registerService(SecurityInitializationCustomizer.class, (SecurityInitializationCustomizer) securityService -> { final RoleDefinition sailingViewerRoleDefinition = securityService.getOrCreateRoleDefinitionFromPrototype(SailingViewerRole.getInstance()); if (securityService.isInitialOrMigration()) { - // The server is initially set to be public by adding sailing_viewer role to the server group // with forAll=true securityService.putRoleDefinitionToUserGroup(securityService.getDefaultTenant(), sailingViewerRoleDefinition, true); - // sailing_viewer role is publicly readable securityService.addToAccessControlList(sailingViewerRoleDefinition.getIdentifier(), null, DefaultActions.READ.name()); } }, null)); - final TrackedRaceStatisticsCache trackedRaceStatisticsCache = new TrackedRaceStatisticsCacheImpl(); registrations.add(context.registerService(TrackedRaceStatisticsCache.class.getName(), trackedRaceStatisticsCache, null)); registrations.add(context.registerService(TrackedRegattaListener.class.getName(), trackedRaceStatisticsCache, null)); - // At this point the OSGi resolver is used as device type service finder. // In the case that we are not in an OSGi context (e.g. running a JUnit test instead), // this code block is not run, and the test case can inject some other type of finder // instead. serviceFinderFactory = new CachedOsgiTypeBasedServiceFinderFactory(context); - racingEventService = new RacingEventServiceImpl(clearPersistentCompetitors, serviceFinderFactory, trackedRegattaListener, notificationService, trackedRaceStatisticsCache, restoreTrackedRaces, securityServiceTracker); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index fbaa74b3bf0..e88ce01abd4 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -800,7 +800,6 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes } }); this.dataImportLock = new DataImportLockWithProgress(); - remoteSailingServerSet = new RemoteSailingServerSet(scheduler, baseDomainFactory); regattasByName = new ConcurrentHashMap(); regattasByNameLock = new NamedReentrantReadWriteLock("regattasByName for " + this, /* fair */false);