浏览代码

Fixed subtle bugs

Lukas Cerny 1 年之前
父节点
当前提交
bb044fcf86

+ 1 - 1
docker.dev.env

@@ -11,7 +11,7 @@ DATABASE_PASSWORD=MAPlog
 DATABASE_POOL_SIZE=5
 DATABASE_POOL_SIZE=5
 
 
 # Auth
 # Auth
-# AUTH_DISABLED=true
+AUTH_DISABLED=true
 AUTH_KEYSTORE_PATH=/app/keystore.jceks
 AUTH_KEYSTORE_PATH=/app/keystore.jceks
 AUTH_KEYSTORE_TYPE=PKCS12
 AUTH_KEYSTORE_TYPE=PKCS12
 AUTH_KEYSTORE_PASSWORD=SENSlog
 AUTH_KEYSTORE_PASSWORD=SENSlog

+ 102 - 86
src/main/java/cz/senslog/telemetry/database/repository/MapLogRepository.java

@@ -1,20 +1,18 @@
 package cz.senslog.telemetry.database.repository;
 package cz.senslog.telemetry.database.repository;
 
 
 import cz.senslog.telemetry.database.DataNotFoundException;
 import cz.senslog.telemetry.database.DataNotFoundException;
-import cz.senslog.telemetry.database.PagingRetrieve;
 import cz.senslog.telemetry.database.SortType;
 import cz.senslog.telemetry.database.SortType;
 import cz.senslog.telemetry.database.domain.*;
 import cz.senslog.telemetry.database.domain.*;
 import cz.senslog.telemetry.database.domain.Filter;
 import cz.senslog.telemetry.database.domain.Filter;
 import io.vertx.core.Future;
 import io.vertx.core.Future;
-import io.vertx.ext.auth.impl.UserImpl;
+import io.vertx.core.json.JsonObject;
 import io.vertx.sqlclient.*;
 import io.vertx.sqlclient.*;
 
 
-import java.sql.Array;
 import java.time.OffsetDateTime;
 import java.time.OffsetDateTime;
-import java.time.ZoneId;
 import java.util.*;
 import java.util.*;
 import java.util.function.Function;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 import java.util.stream.StreamSupport;
 
 
 import static java.lang.String.format;
 import static java.lang.String.format;
@@ -33,6 +31,18 @@ public class MapLogRepository implements SensLogRepository {
         return new MapLogRepository(client);
         return new MapLogRepository(client);
     }
     }
 
 
+
+    private static JsonObject convertSensorIdToName(Map<Long, String> sensors, JsonObject observedValues) {
+        JsonObject res = new JsonObject(new HashMap<>(observedValues.size()));
+        for (Map.Entry<String, Object> val : observedValues) {
+            Long sensorId = Long.parseLong(val.getKey());
+            if (sensors.containsKey(sensorId)) {
+                res.put(sensors.get(sensorId), val.getValue());
+            }
+        }
+        return res;
+    }
+
     @Override
     @Override
     public Future<Integer> updateEvent(EntityAction data) {
     public Future<Integer> updateEvent(EntityAction data) {
         Tuple params = Tuple.of(data.getTimestamp(), data.getEntityId(), data.getActionId(), data.getUnitId());
         Tuple params = Tuple.of(data.getTimestamp(), data.getEntityId(), data.getActionId(), data.getUnitId());
@@ -309,7 +319,7 @@ public class MapLogRepository implements SensLogRepository {
         return client.preparedQuery("SELECT s.sensor_id, s.name, s.type " +
         return client.preparedQuery("SELECT s.sensor_id, s.name, s.type " +
                         "FROM maplog.unit_to_sensor AS uts " +
                         "FROM maplog.unit_to_sensor AS uts " +
                         "JOIN maplog.sensor s on s.sensor_id = uts.sensor_id " +
                         "JOIN maplog.sensor s on s.sensor_id = uts.sensor_id " +
-                        "WHERE UTS.unit_id = $1 ORDER BY s.sensor_id")
+                        "WHERE uts.unit_id = $1 AND s.io_id != 0 ORDER BY s.sensor_id")
                 .execute(Tuple.of(unitId))
                 .execute(Tuple.of(unitId))
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                         .map((row) -> Sensor.of(
                         .map((row) -> Sensor.of(
@@ -1318,7 +1328,14 @@ public class MapLogRepository implements SensLogRepository {
                     "WHERE utc.campaign_id = $1 AND " + whereTimestampClause + whereFiltersClause + " " +
                     "WHERE utc.campaign_id = $1 AND " + whereTimestampClause + whereFiltersClause + " " +
                     "ORDER BY tel.time_stamp OFFSET $2 LIMIT $3;";
                     "ORDER BY tel.time_stamp OFFSET $2 LIMIT $3;";
 
 
-        return client.preparedQuery(sql)
+        return client.preparedQuery("SELECT s.sensor_id, s.name FROM maplog.sensor s " +
+                "JOIN maplog.unit_to_sensor uts ON uts.sensor_id = s.sensor_id " +
+                "JOIN maplog.unit_to_campaign utc ON utc.unit_id = uts.unit_id " +
+                "WHERE utc.campaign_id = $1")
+                .execute(Tuple.of(campaignId))
+                .map(r -> StreamSupport.stream(r.spliterator(), false)
+                        .collect(Collectors.toMap(row -> row.getLong("sensor_id"), row -> row.getString("name"))))
+                .flatMap(sensors -> client.preparedQuery(sql)
                 .execute(tupleParams)
                 .execute(tupleParams)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                         .map(r -> UnitTelemetry.of(
                         .map(r -> UnitTelemetry.of(
@@ -1331,24 +1348,10 @@ public class MapLogRepository implements SensLogRepository {
                                         r.getFloat("alt"),
                                         r.getFloat("alt"),
                                         r.getFloat("angle")),
                                         r.getFloat("angle")),
                                 r.getInteger("speed"),
                                 r.getInteger("speed"),
-                                r.getJsonObject("observed_values")
+                                convertSensorIdToName(sensors, r.getJsonObject("observed_values"))
                         ))
                         ))
                         .collect(toList())
                         .collect(toList())
-                );
-    }
-
-    @Override
-    public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdWithPaging(
-            long campaignId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters
-    ) {
-        return findObservationsByCampaignId(campaignId, from, to, offset, limit+1, filters)
-                .map(data -> {
-                    boolean hasNext = data.size() > limit;
-                    if (hasNext) {
-                        data.remove(data.size() - 1);
-                    }
-                    return new PagingRetrieve<>(hasNext, data.size(), data);
-                });
+                ));
     }
     }
 
 
     @Override
     @Override
@@ -1408,7 +1411,14 @@ public class MapLogRepository implements SensLogRepository {
                     "WHERE utc.campaign_id = $1 AND su.identity = $4 AND " + whereTimestampClause + whereFiltersClause + " " +
                     "WHERE utc.campaign_id = $1 AND su.identity = $4 AND " + whereTimestampClause + whereFiltersClause + " " +
                     "ORDER BY tel.time_stamp OFFSET $2 LIMIT $3;";
                     "ORDER BY tel.time_stamp OFFSET $2 LIMIT $3;";
 
 
-        return client.preparedQuery(sql)
+        return client.preparedQuery("SELECT s.sensor_id, s.name FROM maplog.sensor s " +
+                        "JOIN maplog.unit_to_sensor uts ON uts.sensor_id = s.sensor_id " +
+                        "JOIN maplog.unit_to_campaign utc ON utc.unit_id = uts.unit_id " +
+                        "WHERE utc.campaign_id = $1")
+                .execute(Tuple.of(campaignId))
+                .map(r -> StreamSupport.stream(r.spliterator(), false)
+                        .collect(Collectors.toMap(row -> row.getLong("sensor_id"), row -> row.getString("name"))))
+                .flatMap(sensors -> client.preparedQuery(sql)
                 .execute(tupleParams)
                 .execute(tupleParams)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                         .map(r -> UnitTelemetry.of(
                         .map(r -> UnitTelemetry.of(
@@ -1421,10 +1431,10 @@ public class MapLogRepository implements SensLogRepository {
                                         r.getFloat("alt"),
                                         r.getFloat("alt"),
                                         r.getFloat("angle")),
                                         r.getFloat("angle")),
                                 r.getInteger("speed"),
                                 r.getInteger("speed"),
-                                r.getJsonObject("observed_values")
+                                convertSensorIdToName(sensors, r.getJsonObject("observed_values"))
                         ))
                         ))
                         .collect(toList())
                         .collect(toList())
-                );
+                ));
     }
     }
 
 
     @Override
     @Override
@@ -1480,7 +1490,13 @@ public class MapLogRepository implements SensLogRepository {
                     "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND " + whereTimestampClause + whereFiltersClause + " " +
                     "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND " + whereTimestampClause + whereFiltersClause + " " +
                     "ORDER BY tel.time_stamp OFFSET $3 LIMIT $4;";
                     "ORDER BY tel.time_stamp OFFSET $3 LIMIT $4;";
 
 
-        return client.preparedQuery(sql)
+        return client.preparedQuery("SELECT s.sensor_id, s.name FROM maplog.sensor s " +
+                        "JOIN maplog.unit_to_sensor uts ON uts.sensor_id = s.sensor_id " +
+                        "WHERE uts.unit_id = $1")
+                .execute(Tuple.of(unitId))
+                .map(r -> StreamSupport.stream(r.spliterator(), false)
+                        .collect(Collectors.toMap(row -> row.getLong("sensor_id"), row -> row.getString("name"))))
+                .flatMap(sensors -> client.preparedQuery(sql)
                 .execute(tupleParams)
                 .execute(tupleParams)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                         .map(r -> UnitTelemetry.of(
                         .map(r -> UnitTelemetry.of(
@@ -1493,23 +1509,10 @@ public class MapLogRepository implements SensLogRepository {
                                         r.getFloat("alt"),
                                         r.getFloat("alt"),
                                         r.getFloat("angle")),
                                         r.getFloat("angle")),
                                 r.getInteger("speed"),
                                 r.getInteger("speed"),
-                                r.getJsonObject("observed_values")))
+                                convertSensorIdToName(sensors, r.getJsonObject("observed_values"))
+                        ))
                         .collect(toList())
                         .collect(toList())
-                );
-    }
-
-    @Override
-    public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdAndUnitIdWithPaging(
-            long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters
-    ) {
-        return findObservationsByCampaignIdAndUnitId(campaignId, unitId, from, to, offset, limit+1, filters)
-                .map(data -> {
-                    boolean hasNext = data.size() > limit;
-                    if (hasNext) {
-                        data.remove(data.size() - 1);
-                    }
-                   return new PagingRetrieve<>(hasNext, data.size(), data);
-                });
+                ));
     }
     }
 
 
     @Override
     @Override
@@ -1568,7 +1571,13 @@ public class MapLogRepository implements SensLogRepository {
                         "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND su.identity = $5 AND " + whereTimestampClause + whereFiltersClause + " " +
                         "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND su.identity = $5 AND " + whereTimestampClause + whereFiltersClause + " " +
                         "ORDER BY tel.time_stamp OFFSET $3 LIMIT $4";
                         "ORDER BY tel.time_stamp OFFSET $3 LIMIT $4";
 
 
-        return client.preparedQuery(sql)
+        return client.preparedQuery("SELECT s.sensor_id, s.name FROM maplog.sensor s " +
+                        "JOIN maplog.unit_to_sensor uts ON uts.sensor_id = s.sensor_id " +
+                        "WHERE uts.unit_id = $1")
+                .execute(Tuple.of(unitId))
+                .map(r -> StreamSupport.stream(r.spliterator(), false)
+                        .collect(Collectors.toMap(row -> row.getLong("sensor_id"), row -> row.getString("name"))))
+                .flatMap(sensors -> client.preparedQuery(sql)
                 .execute(tupleParams)
                 .execute(tupleParams)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                         .map(r -> UnitTelemetry.of(
                         .map(r -> UnitTelemetry.of(
@@ -1581,9 +1590,10 @@ public class MapLogRepository implements SensLogRepository {
                                         r.getFloat("alt"),
                                         r.getFloat("alt"),
                                         r.getFloat("angle")),
                                         r.getFloat("angle")),
                                 r.getInteger("speed"),
                                 r.getInteger("speed"),
-                                r.getJsonObject("observed_values")))
+                                convertSensorIdToName(sensors, r.getJsonObject("observed_values"))
+                        ))
                         .collect(toList())
                         .collect(toList())
-                );
+                ));
     }
     }
 
 
     @Override
     @Override
@@ -1629,8 +1639,7 @@ public class MapLogRepository implements SensLogRepository {
             }
             }
         }
         }
 
 
-        String sql = "SELECT tel.id, tel.unit_id, tel.observed_values::json, tel.speed, " +
-                        "tel.time_stamp, $4 AS zone_id, " + // ::timestamp with time zone at time zone $4 AS time_stamp
+        String sql = "SELECT tel.id, tel.unit_id, tel.observed_values::json, tel.speed, tel.time_stamp, " +
                         "ST_X (ST_Transform (tel.the_geom, 4326)) AS long, " +
                         "ST_X (ST_Transform (tel.the_geom, 4326)) AS long, " +
                         "ST_Y (ST_Transform (tel.the_geom, 4326)) AS lat, " +
                         "ST_Y (ST_Transform (tel.the_geom, 4326)) AS lat, " +
                         "ST_Z (ST_Transform (tel.the_geom, 4326)) AS alt, " +
                         "ST_Z (ST_Transform (tel.the_geom, 4326)) AS alt, " +
@@ -1640,7 +1649,14 @@ public class MapLogRepository implements SensLogRepository {
                 "WHERE e.id = $1 AND " + whereTimestampClause + whereFiltersClause + " " +
                 "WHERE e.id = $1 AND " + whereTimestampClause + whereFiltersClause + " " +
                 "ORDER BY tel.time_stamp OFFSET $2 LIMIT $3";
                 "ORDER BY tel.time_stamp OFFSET $2 LIMIT $3";
 
 
-        return client.preparedQuery(sql)
+        return client.preparedQuery("SELECT s.sensor_id, s.name FROM maplog.sensor s " +
+                        "JOIN maplog.unit_to_sensor uts ON uts.sensor_id = s.sensor_id " +
+                        "JOIN maplog.event e ON e.unit_id = uts.unit_id " +
+                        "WHERE e.id = $1")
+                .execute(Tuple.of(eventId))
+                .map(r -> StreamSupport.stream(r.spliterator(), false)
+                        .collect(Collectors.toMap(row -> row.getLong("sensor_id"), row -> row.getString("name"))))
+                .flatMap(sensors -> client.preparedQuery(sql)
                 .execute(tupleParams)
                 .execute(tupleParams)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                         .map(r -> UnitTelemetry.of(
                         .map(r -> UnitTelemetry.of(
@@ -1653,9 +1669,10 @@ public class MapLogRepository implements SensLogRepository {
                                         r.getFloat("alt"),
                                         r.getFloat("alt"),
                                         r.getFloat("angle")),
                                         r.getFloat("angle")),
                                 r.getInteger("speed"),
                                 r.getInteger("speed"),
-                                r.getJsonObject("observed_values")))
+                                convertSensorIdToName(sensors, r.getJsonObject("observed_values"))
+                        ))
                         .collect(toList())
                         .collect(toList())
-                );
+                ));
     }
     }
 
 
     @Override
     @Override
@@ -1714,7 +1731,14 @@ public class MapLogRepository implements SensLogRepository {
                         "WHERE e.id = $1 AND su.identity = $4 AND " + whereTimestampClause + whereFiltersClause + " " +
                         "WHERE e.id = $1 AND su.identity = $4 AND " + whereTimestampClause + whereFiltersClause + " " +
                         "ORDER BY tel.time_stamp OFFSET $2 LIMIT $3";
                         "ORDER BY tel.time_stamp OFFSET $2 LIMIT $3";
 
 
-        return client.preparedQuery(sql)
+        return client.preparedQuery("SELECT s.sensor_id, s.name FROM maplog.sensor s " +
+                        "JOIN maplog.unit_to_sensor uts ON uts.sensor_id = s.sensor_id " +
+                        "JOIN maplog.event e ON e.unit_id = uts.unit_id " +
+                        "WHERE e.id = $1")
+                .execute(Tuple.of(eventId))
+                .map(r -> StreamSupport.stream(r.spliterator(), false)
+                        .collect(Collectors.toMap(row -> row.getLong("sensor_id"), row -> row.getString("name"))))
+                .flatMap(sensors -> client.preparedQuery(sql)
                 .execute(tupleParams)
                 .execute(tupleParams)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                         .map(r -> UnitTelemetry.of(
                         .map(r -> UnitTelemetry.of(
@@ -1727,9 +1751,10 @@ public class MapLogRepository implements SensLogRepository {
                                         r.getFloat("alt"),
                                         r.getFloat("alt"),
                                         r.getFloat("angle")),
                                         r.getFloat("angle")),
                                 r.getInteger("speed"),
                                 r.getInteger("speed"),
-                                r.getJsonObject("observed_values")))
+                                convertSensorIdToName(sensors, r.getJsonObject("observed_values"))
+                        ))
                         .collect(toList())
                         .collect(toList())
-                );
+                ));
     }
     }
 
 
     @Override
     @Override
@@ -1775,8 +1800,7 @@ public class MapLogRepository implements SensLogRepository {
             }
             }
         }
         }
 
 
-        String sql = "SELECT tel.id, (tel.observed_values::jsonb ->> $3::bigint::text::varchar)::integer AS value, tel.speed, " +
-                        "tel.time_stamp, $6 AS zone_id, " + // ::timestamp with time zone at time zone $6 AS time_stamp
+        String sql = "SELECT tel.id, (tel.observed_values::jsonb ->> $3::bigint::text::varchar)::integer AS value, tel.speed, tel.time_stamp, " +
                         "ST_X (ST_Transform (tel.the_geom, 4326)) AS long, " +
                         "ST_X (ST_Transform (tel.the_geom, 4326)) AS long, " +
                         "ST_Y (ST_Transform (tel.the_geom, 4326)) AS lat, " +
                         "ST_Y (ST_Transform (tel.the_geom, 4326)) AS lat, " +
                         "ST_Z (ST_Transform (tel.the_geom, 4326)) AS alt, " +
                         "ST_Z (ST_Transform (tel.the_geom, 4326)) AS alt, " +
@@ -1922,7 +1946,7 @@ public class MapLogRepository implements SensLogRepository {
             }
             }
         }
         }
 
 
-        String sql = "SELECT tel.unit_id, tel.time_stamp, $5 AS zone_id, " + // ::timestamp with time zone at time zone $5 AS time_stamp
+        String sql = "SELECT tel.unit_id, tel.time_stamp, " +
                         "ST_X (ST_Transform (tel.the_geom, 4326)) AS long, " +
                         "ST_X (ST_Transform (tel.the_geom, 4326)) AS long, " +
                         "ST_Y (ST_Transform (tel.the_geom, 4326)) AS lat, " +
                         "ST_Y (ST_Transform (tel.the_geom, 4326)) AS lat, " +
                         "ST_Z (ST_Transform (tel.the_geom, 4326)) AS alt " +
                         "ST_Z (ST_Transform (tel.the_geom, 4326)) AS alt " +
@@ -2063,7 +2087,7 @@ public class MapLogRepository implements SensLogRepository {
             }
             }
         }
         }
 
 
-        String sql = "SELECT tel.unit_id, tel.time_stamp, $4 AS zone_id, " + // ::timestamp with time zone at time zone $4 AS time_stamp
+        String sql = "SELECT tel.unit_id, tel.time_stamp, " +
                         "ST_X (ST_Transform (tel.the_geom, 4326)) AS long, " +
                         "ST_X (ST_Transform (tel.the_geom, 4326)) AS long, " +
                         "ST_Y (ST_Transform (tel.the_geom, 4326)) AS lat, " +
                         "ST_Y (ST_Transform (tel.the_geom, 4326)) AS lat, " +
                         "ST_Z (ST_Transform (tel.the_geom, 4326)) AS alt " +
                         "ST_Z (ST_Transform (tel.the_geom, 4326)) AS alt " +
@@ -2201,7 +2225,7 @@ public class MapLogRepository implements SensLogRepository {
             }
             }
         }
         }
 
 
-        String sql = "SELECT unit_id, time_stamp, $3 AS zone_id, " + // ::timestamp with time zone at time zone $5 AS time_stamp
+        String sql = "SELECT unit_id, time_stamp, " +
                     "ST_X (ST_Transform (the_geom, 4326)) AS long, " +
                     "ST_X (ST_Transform (the_geom, 4326)) AS long, " +
                     "ST_Y (ST_Transform (the_geom, 4326)) AS lat, " +
                     "ST_Y (ST_Transform (the_geom, 4326)) AS lat, " +
                     "ST_Z (ST_Transform (the_geom, 4326)) AS alt, " +
                     "ST_Z (ST_Transform (the_geom, 4326)) AS alt, " +
@@ -2384,14 +2408,12 @@ public class MapLogRepository implements SensLogRepository {
             statusFilter = Set.of(AlertStatus.CREATED, AlertStatus.INFORMED, AlertStatus.IN_PROCESS, AlertStatus.SOLVED);
             statusFilter = Set.of(AlertStatus.CREATED, AlertStatus.INFORMED, AlertStatus.IN_PROCESS, AlertStatus.SOLVED);
         }
         }
 
 
-        String statuses = String.join(",", statusFilter.stream().map(s -> "'"+s.name()+"'").collect(toSet()));
-
         return client.preparedQuery("SELECT a.id, a.message, a.status, a.time_stamp FROM maplog.alert AS a " +
         return client.preparedQuery("SELECT a.id, a.message, a.status, a.time_stamp FROM maplog.alert AS a " +
                         "JOIN maplog.event AS e ON e.unit_id = a.unit_id " +
                         "JOIN maplog.event AS e ON e.unit_id = a.unit_id " +
                         "WHERE e.from_time <= a.time_stamp AND (CASE WHEN e.to_time IS NULL THEN now() ELSE e.to_time END) >= a.time_stamp " +
                         "WHERE e.from_time <= a.time_stamp AND (CASE WHEN e.to_time IS NULL THEN now() ELSE e.to_time END) >= a.time_stamp " +
-                            "AND e.id = $1 AND a.status IN ("+statuses+") " + // TODO better solution IN (array)
+                            "AND e.id = $1 AND a.status = ANY($2) " +
                         "ORDER BY a.time_stamp "+sortType.name())
                         "ORDER BY a.time_stamp "+sortType.name())
-                .execute(Tuple.of(eventId))
+                .execute(Tuple.of(eventId, statusFilter))
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                         .map(r -> Alert.of(
                         .map(r -> Alert.of(
                                 r.getLong("id"),
                                 r.getLong("id"),
@@ -2473,22 +2495,20 @@ public class MapLogRepository implements SensLogRepository {
             statusFilter = Set.of(AlertStatus.CREATED, AlertStatus.INFORMED, AlertStatus.IN_PROCESS, AlertStatus.SOLVED);
             statusFilter = Set.of(AlertStatus.CREATED, AlertStatus.INFORMED, AlertStatus.IN_PROCESS, AlertStatus.SOLVED);
         }
         }
 
 
-        String statuses = String.join(",", statusFilter.stream().map(s -> "'"+s.name()+"'").collect(toSet()));
-
         String whereTimestampClause;
         String whereTimestampClause;
         Tuple tupleParams;
         Tuple tupleParams;
         if (from != null && to != null) {
         if (from != null && to != null) {
-            whereTimestampClause = "WHERE utc.campaign_id = $1 AND a.status IN ("+statuses+") AND a.time_stamp >= (CASE WHEN utc.from_time > $2 THEN utc.from_time ELSE $2 END) AND a.time_stamp <= (CASE WHEN utc.to_time < $3 THEN utc.to_time ELSE $3 END)";
-            tupleParams = Tuple.of(campaignId, from, to);
+            whereTimestampClause = "WHERE utc.campaign_id = $1 AND a.status = ANY($2) AND a.time_stamp >= (CASE WHEN utc.from_time > $3 THEN utc.from_time ELSE $3 END) AND a.time_stamp <= (CASE WHEN utc.to_time < $4 THEN utc.to_time ELSE $4 END)";
+            tupleParams = Tuple.of(campaignId, statusFilter, from, to);
         } else if (from != null) {
         } else if (from != null) {
-            whereTimestampClause = "WHERE utc.campaign_id = $1 AND a.status IN ("+statuses+") AND a.time_stamp >= (CASE WHEN utc.from_time > $2 THEN utc.from_time ELSE $2 END) AND a.time_stamp <= utc.to_time";
-            tupleParams = Tuple.of(campaignId, from);
+            whereTimestampClause = "WHERE utc.campaign_id = $1 AND a.status = ANY($2) AND a.time_stamp >= (CASE WHEN utc.from_time > $3 THEN utc.from_time ELSE $3 END) AND a.time_stamp <= utc.to_time";
+            tupleParams = Tuple.of(campaignId, statusFilter, from);
         } else if (to != null) {
         } else if (to != null) {
-            whereTimestampClause = "WHERE utc.campaign_id = $1 AND a.status IN ("+statuses+") AND a.time_stamp >= utc.from_time AND a.time_stamp <= (CASE WHEN utc.to_time < $2 THEN utc.to_time ELSE $2 END)";
-            tupleParams = Tuple.of(campaignId, to);
+            whereTimestampClause = "WHERE utc.campaign_id = $1 AND a.status = ANY($2) AND a.time_stamp >= utc.from_time AND a.time_stamp <= (CASE WHEN utc.to_time < $3 THEN utc.to_time ELSE $3 END)";
+            tupleParams = Tuple.of(campaignId, statusFilter, to);
         } else {
         } else {
-            whereTimestampClause = "WHERE utc.campaign_id = $1 AND a.status IN ("+statuses+")";
-            tupleParams = Tuple.of(campaignId);
+            whereTimestampClause = "WHERE utc.campaign_id = $1 AND a.status = ANY($2)";
+            tupleParams = Tuple.of(campaignId, statusFilter);
         }
         }
 
 
         return client.preparedQuery("SELECT a.id, utc.campaign_id, a.unit_id, a.message, a.time_stamp, a.status FROM maplog.alert AS a " +
         return client.preparedQuery("SELECT a.id, utc.campaign_id, a.unit_id, a.message, a.time_stamp, a.status FROM maplog.alert AS a " +
@@ -2556,22 +2576,20 @@ public class MapLogRepository implements SensLogRepository {
             statusFilter = Set.of(AlertStatus.CREATED, AlertStatus.INFORMED, AlertStatus.IN_PROCESS, AlertStatus.SOLVED);
             statusFilter = Set.of(AlertStatus.CREATED, AlertStatus.INFORMED, AlertStatus.IN_PROCESS, AlertStatus.SOLVED);
         }
         }
 
 
-        String statuses = String.join(",", statusFilter.stream().map(s -> "'"+s.name()+"'").collect(toSet()));
-
         String whereTimestampClause;
         String whereTimestampClause;
         Tuple tupleParams;
         Tuple tupleParams;
         if (from != null && to != null) {
         if (from != null && to != null) {
-            whereTimestampClause = "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND a.status IN ("+statuses+") AND a.time_stamp >= (CASE WHEN utc.from_time > $3 THEN utc.from_time ELSE $3 END) AND a.time_stamp <= (CASE WHEN utc.to_time < $4 THEN utc.to_time ELSE $4 END)";
-            tupleParams = Tuple.of(campaignId, unitId, from, to);
+            whereTimestampClause = "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND a.status = ANY($3) AND a.time_stamp >= (CASE WHEN utc.from_time > $4 THEN utc.from_time ELSE $4 END) AND a.time_stamp <= (CASE WHEN utc.to_time < $5 THEN utc.to_time ELSE $5 END)";
+            tupleParams = Tuple.of(campaignId, unitId, statusFilter, from, to);
         } else if (from != null) {
         } else if (from != null) {
-            whereTimestampClause = "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND a.status IN ("+statuses+") AND a.time_stamp >= (CASE WHEN utc.from_time > $3 THEN utc.from_time ELSE $3 END) AND a.time_stamp <= utc.to_time";
-            tupleParams = Tuple.of(campaignId, unitId, from);
+            whereTimestampClause = "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND a.status = ANY($3) AND a.time_stamp >= (CASE WHEN utc.from_time > $4 THEN utc.from_time ELSE $4 END) AND a.time_stamp <= utc.to_time";
+            tupleParams = Tuple.of(campaignId, unitId, statusFilter, from);
         } else if (to != null) {
         } else if (to != null) {
-            whereTimestampClause = "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND a.status IN ("+statuses+") AND a.time_stamp >= utc.from_time AND a.time_stamp <= (CASE WHEN utc.to_time < $3 THEN utc.to_time ELSE $3 END)";
-            tupleParams = Tuple.of(campaignId, unitId, to);
+            whereTimestampClause = "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND a.status = ANY($3) AND a.time_stamp >= utc.from_time AND a.time_stamp <= (CASE WHEN utc.to_time < $4 THEN utc.to_time ELSE $4 END)";
+            tupleParams = Tuple.of(campaignId, unitId, statusFilter, to);
         } else {
         } else {
-            whereTimestampClause = "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND a.status IN ("+statuses+")";
-            tupleParams = Tuple.of(campaignId, unitId);
+            whereTimestampClause = "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND a.status = ANY($3)";
+            tupleParams = Tuple.of(campaignId, unitId, statusFilter);
         }
         }
 
 
         return client.preparedQuery("SELECT a.id, a.unit_id, a.message, a.time_stamp, a.status FROM maplog.alert AS a " +
         return client.preparedQuery("SELECT a.id, a.unit_id, a.message, a.time_stamp, a.status FROM maplog.alert AS a " +
@@ -2637,15 +2655,13 @@ public class MapLogRepository implements SensLogRepository {
             statusFilter = Set.of(AlertStatus.CREATED, AlertStatus.INFORMED, AlertStatus.IN_PROCESS, AlertStatus.SOLVED);
             statusFilter = Set.of(AlertStatus.CREATED, AlertStatus.INFORMED, AlertStatus.IN_PROCESS, AlertStatus.SOLVED);
         }
         }
 
 
-        String statuses = String.join(",", statusFilter.stream().map(s -> "'"+s.name()+"'").collect(toSet()));
-
         return client.preparedQuery("SELECT a.id, a.message, a.time_stamp, a.status FROM maplog.alert AS a " +
         return client.preparedQuery("SELECT a.id, a.message, a.time_stamp, a.status FROM maplog.alert AS a " +
                         "JOIN maplog.event AS e on a.unit_id = e.unit_id " +
                         "JOIN maplog.event AS e on a.unit_id = e.unit_id " +
                         "WHERE e.entity_id = $1 AND e.action_id = $2 AND e.unit_id = $3 " +
                         "WHERE e.entity_id = $1 AND e.action_id = $2 AND e.unit_id = $3 " +
                             "AND e.from_time <= a.time_stamp AND (CASE WHEN e.to_time IS NULL THEN now() ELSE e.to_time END) >= a.time_stamp " +
                             "AND e.from_time <= a.time_stamp AND (CASE WHEN e.to_time IS NULL THEN now() ELSE e.to_time END) >= a.time_stamp " +
-                            "AND a.status IN ("+statuses+")" +
+                            "AND a.status = ANY($4)" +
                         "ORDER BY a.time_stamp "+sort.name())
                         "ORDER BY a.time_stamp "+sort.name())
-                .execute(Tuple.of(entityId, actionId, unitId))
+                .execute(Tuple.of(entityId, actionId, unitId, statusFilter))
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
                         .map(r -> Alert.of(
                         .map(r -> Alert.of(
                                 r.getLong("id"),
                                 r.getLong("id"),

+ 20 - 2
src/main/java/cz/senslog/telemetry/database/repository/SensLogRepository.java

@@ -101,7 +101,16 @@ public interface SensLogRepository {
     Future<List<Unit>> findUnitsByEntityId(int entityId, OffsetDateTime from, OffsetDateTime to);
     Future<List<Unit>> findUnitsByEntityId(int entityId, OffsetDateTime from, OffsetDateTime to);
     Future<List<Unit>> findUnitsByIdentityAndEntityId(String userIdentity, int entityId, OffsetDateTime from, OffsetDateTime to);
     Future<List<Unit>> findUnitsByIdentityAndEntityId(String userIdentity, int entityId, OffsetDateTime from, OffsetDateTime to);
     Future<List<UnitTelemetry>> findObservationsByCampaignId(long campaignId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
     Future<List<UnitTelemetry>> findObservationsByCampaignId(long campaignId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
-    Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdWithPaging(long campaignId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
+    default Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdWithPaging(long campaignId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findObservationsByCampaignId(campaignId, from, to, offset, limit+1, filters)
+                .map(data -> {
+                    boolean hasNext = data.size() > limit;
+                    if (hasNext) {
+                        data.remove(data.size() - 1);
+                    }
+                    return new PagingRetrieve<>(hasNext, data.size(), data);
+                });
+    }
 
 
     Future<List<UnitTelemetry>> findObservationsByIdentityAndCampaignId(String userIdentity, long campaignId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
     Future<List<UnitTelemetry>> findObservationsByIdentityAndCampaignId(String userIdentity, long campaignId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
     default Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByIdentityAndCampaignIdWithPaging(String userIdentity, long campaignId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
     default Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByIdentityAndCampaignIdWithPaging(String userIdentity, long campaignId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
@@ -116,7 +125,16 @@ public interface SensLogRepository {
     }
     }
 
 
     Future<List<UnitTelemetry>> findObservationsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
     Future<List<UnitTelemetry>> findObservationsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
-    Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdAndUnitIdWithPaging(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
+    default Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdAndUnitIdWithPaging(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findObservationsByCampaignIdAndUnitId(campaignId, unitId, from, to, offset, limit+1, filters)
+                .map(data -> {
+                    boolean hasNext = data.size() > limit;
+                    if (hasNext) {
+                        data.remove(data.size() - 1);
+                    }
+                    return new PagingRetrieve<>(hasNext, data.size(), data);
+                });
+    }
     Future<List<UnitTelemetry>> findObservationsByIdentityAndCampaignIdAndUnitId(String userIdentity, long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
     Future<List<UnitTelemetry>> findObservationsByIdentityAndCampaignIdAndUnitId(String userIdentity, long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
     default Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByIdentityAndCampaignIdAndUnitIdWithPaging(String userIdentity, long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
     default Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByIdentityAndCampaignIdAndUnitIdWithPaging(String userIdentity, long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
         return findObservationsByIdentityAndCampaignIdAndUnitId(userIdentity, campaignId, unitId, from, to, offset, limit+1, filters)
         return findObservationsByIdentityAndCampaignIdAndUnitId(userIdentity, campaignId, unitId, from, to, offset, limit+1, filters)

+ 8 - 4
src/main/java/cz/senslog/telemetry/protocol/Fm4ex.java

@@ -3,11 +3,15 @@ package cz.senslog.telemetry.protocol;
 import cz.senslog.telemetry.protocol.domain.AVLPacket;
 import cz.senslog.telemetry.protocol.domain.AVLPacket;
 import cz.senslog.telemetry.utils.CRC16;
 import cz.senslog.telemetry.utils.CRC16;
 import io.vertx.core.buffer.Buffer;
 import io.vertx.core.buffer.Buffer;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 
 import java.util.regex.Pattern;
 import java.util.regex.Pattern;
 
 
 public class Fm4ex {
 public class Fm4ex {
 
 
+    private static final Logger logger = LogManager.getLogger(Fm4ex.class);
+
     private static final Pattern NM_PATTERN = Pattern.compile("-?\\d+");
     private static final Pattern NM_PATTERN = Pattern.compile("-?\\d+");
 
 
     public static float coordToDecimalDegrees(long coordination) {
     public static float coordToDecimalDegrees(long coordination) {
@@ -19,15 +23,15 @@ public class Fm4ex {
 
 
     public static String parseIMEI(Buffer buffer) {
     public static String parseIMEI(Buffer buffer) {
         if (buffer.length() > 20) {
         if (buffer.length() > 20) {
-            throw new IllegalArgumentException(String.format(
-                    "Received IMEI is larger than expected. The length is <%d>.", buffer.length())
-            );
+            logger.warn("Received IMEI is larger than expected. The length is <{}>.", buffer.length());
+            return null;
         }
         }
         String imei = buffer.getString(2, buffer.getShort(0) + 2);
         String imei = buffer.getString(2, buffer.getShort(0) + 2);
         if (NM_PATTERN.matcher(imei).matches()) {
         if (NM_PATTERN.matcher(imei).matches()) {
             return imei;
             return imei;
         }
         }
-        throw new IllegalArgumentException("Received data is not IMEI number format.");
+        logger.warn("Received data is not IMEI number format.");
+        return null;
     }
     }
 
 
     public static AVLPacket parseAVL(Buffer avlPacket) {
     public static AVLPacket parseAVL(Buffer avlPacket) {

+ 4 - 20
src/main/java/cz/senslog/telemetry/server/Fm4exSocketHandler.java

@@ -50,12 +50,6 @@ public class Fm4exSocketHandler {
 
 
     public Future<Buffer> process(String socketID, Buffer buffer) {
     public Future<Buffer> process(String socketID, Buffer buffer) {
         return sockets.computeIfAbsent(socketID, newContext).invoke(buffer);
         return sockets.computeIfAbsent(socketID, newContext).invoke(buffer);
-//        LoopInvoker<Buffer, Buffer, SocketContext> looper = sockets.get(socketID);
-//        if (looper == null) {
-//            looper = newContext.apply(socketID);
-//            sockets.put(socketID, looper);
-//        }
-//        return looper.invoke(buffer);
     }
     }
 
 
     private static class SocketContext {
     private static class SocketContext {
@@ -81,8 +75,10 @@ public class Fm4exSocketHandler {
             String imei;
             String imei;
             try {
             try {
                 imei = Fm4ex.parseIMEI(buffer);
                 imei = Fm4ex.parseIMEI(buffer);
+                if (imei == null) {
+                    return Future.succeededFuture(ERROR);
+                }
             } catch (RuntimeException e) {
             } catch (RuntimeException e) {
-                tempFileWriter("IMEI_ERROR", buffer.getBytes(), Instant.now(), "bin");
                 return Future.failedFuture(e);
                 return Future.failedFuture(e);
             }
             }
             return repo.findUnitByIMEI(imei).map(u -> {
             return repo.findUnitByIMEI(imei).map(u -> {
@@ -106,7 +102,6 @@ public class Fm4exSocketHandler {
             try {
             try {
                 avlPacket = Fm4ex.parseAVL(buffer);
                 avlPacket = Fm4ex.parseAVL(buffer);
             } catch (Exception e) {
             } catch (Exception e) {
-                tempFileWriter("AVL_ERROR", buffer.getBytes(), Instant.now(), "bin");
                 return Future.failedFuture(e);
                 return Future.failedFuture(e);
             }
             }
 
 
@@ -167,7 +162,7 @@ public class Fm4exSocketHandler {
                     for (IOProperty io : avl.getIoProperties()) {
                     for (IOProperty io : avl.getIoProperties()) {
                         Sensor sensor = ioToSensor.get((long)io.getId());
                         Sensor sensor = ioToSensor.get((long)io.getId());
                         if (sensor != null) {
                         if (sensor != null) {
-                            observedValues.put(sensor.getName(), io.getValue());
+                            observedValues.put(Long.toString(sensor.getSensorId()), io.getValue());
                         } else {
                         } else {
                             logger.error("Sensor for the IO Property <{}> does not exist.", io.getId());
                             logger.error("Sensor for the IO Property <{}> does not exist.", io.getId());
                         }
                         }
@@ -182,16 +177,5 @@ public class Fm4exSocketHandler {
                         })
                         })
             );
             );
         }
         }
-
-        @Deprecated
-        public static void tempFileWriter(String fileName, byte[] bytes, Instant at, String ext) {
-            final String dir = "/volume/logs";
-            final String fullName = String.format("%d_%s.%s",at.getEpochSecond(), fileName, ext);
-            try {
-                Files.write(Paths.get(dir, fullName), bytes);
-            } catch (IOException e) {
-                logger.error(e.getMessage());
-            }
-        }
     }
     }
 }
 }

+ 7 - 3
src/main/java/cz/senslog/telemetry/server/ws/OpenAPIHandler.java

@@ -54,7 +54,11 @@ public class OpenAPIHandler {
     }
     }
 
 
     private static String hostURLFull(HttpServerRequest req) {
     private static String hostURLFull(HttpServerRequest req) {
-        return String.format("%s://%s", req.scheme(), req.authority().host());
+//        if (req.authority().port() == 80) {
+            return String.format("%s://%s", req.scheme(), req.authority().host());
+//        } else {
+//            return String.format("%s://%s:%s", req.scheme(), req.authority().host(), req.authority().port());
+//        }
     }
     }
 
 
 
 
@@ -99,7 +103,7 @@ public class OpenAPIHandler {
 
 
     public void campaignIdGET(RoutingContext rc) {
     public void campaignIdGET(RoutingContext rc) {
         String host =  hostURLFull(rc.request());
         String host =  hostURLFull(rc.request());
-        AuthBearerUser user = AuthBearerUser.of(rc.user().principal());
+        AuthBearerUser user = AuthBearerUser.of(rc.user());
         WSParameters params = WSParameters.wrap(rc.queryParams(), rc.pathParams());
         WSParameters params = WSParameters.wrap(rc.queryParams(), rc.pathParams());
 
 
         long campaignId = params.pathParams().campaignId();
         long campaignId = params.pathParams().campaignId();
@@ -363,7 +367,7 @@ public class OpenAPIHandler {
                                                         "longitude", l.getLocation().getLongitude(),
                                                         "longitude", l.getLocation().getLongitude(),
                                                         "latitude", l.getLocation().getLatitude(),
                                                         "latitude", l.getLocation().getLatitude(),
                                                         "altitude", l.getLocation().getAltitude())
                                                         "altitude", l.getLocation().getAltitude())
-                                        )).collect(toList())))).encode()))
+                                        )).toList()))).encode()))
                                     .onFailure(rc::fail);
                                     .onFailure(rc::fail);
                         case GEOJSON -> r.onSuccess(data -> Optional.of(data.stream().collect(groupingBy(UnitLocation::getUnitId))).ifPresent(unitLocation -> rc.response()
                         case GEOJSON -> r.onSuccess(data -> Optional.of(data.stream().collect(groupingBy(UnitLocation::getUnitId))).ifPresent(unitLocation -> rc.response()
                                         .putHeader(CONTENT_TYPE, GEOJSON.contentType()).end(JsonObject.of(
                                         .putHeader(CONTENT_TYPE, GEOJSON.contentType()).end(JsonObject.of(

+ 25 - 4
src/main/java/cz/senslog/telemetry/server/ws/WSParameters.java

@@ -8,8 +8,10 @@ import io.vertx.core.json.JsonArray;
 import io.vertx.core.json.JsonObject;
 import io.vertx.core.json.JsonObject;
 import io.vertx.ext.web.RoutingContext;
 import io.vertx.ext.web.RoutingContext;
 
 
+import javax.print.DocFlavor;
 import java.time.OffsetDateTime;
 import java.time.OffsetDateTime;
 import java.time.ZoneId;
 import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Set;
 import java.util.Set;
@@ -73,7 +75,7 @@ public class WSParameters {
         public ZoneId zone() {
         public ZoneId zone() {
             String strParam = queryParams.get("zone");
             String strParam = queryParams.get("zone");
             if (strParam == null) {
             if (strParam == null) {
-                return null;
+                return DEFAULT_ZONE_ID;
             }
             }
             ZoneId zone = ZoneId.of(strParam);
             ZoneId zone = ZoneId.of(strParam);
             if (backup != null) {
             if (backup != null) {
@@ -89,12 +91,24 @@ public class WSParameters {
 
 
         public OffsetDateTime from() {
         public OffsetDateTime from() {
             String strParam = queryParams.get("from");
             String strParam = queryParams.get("from");
-            return backupAs("from", strParam != null ? OffsetDateTime.parse(strParam) : null);
+            if (strParam == null) {
+                return null;
+            }
+
+            OffsetDateTime from = OffsetDateTime.parse(strParam);
+            backup.put("from", from.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
+            return from;
         }
         }
 
 
         public OffsetDateTime to() {
         public OffsetDateTime to() {
             String strParam = queryParams.get("to");
             String strParam = queryParams.get("to");
-            return backupAs("to", strParam != null ? OffsetDateTime.parse(strParam) : null);
+            if (strParam == null) {
+                return null;
+            }
+
+            OffsetDateTime to = OffsetDateTime.parse(strParam);
+            backup.put("to", to.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
+            return to;
         }
         }
 
 
         public int offset() {
         public int offset() {
@@ -104,7 +118,14 @@ public class WSParameters {
 
 
         public int limit() {
         public int limit() {
             String strParam = queryParams.get("limit");
             String strParam = queryParams.get("limit");
-            return backupAs("limit", strParam != null ? Integer.parseInt(strParam) : DEFAULT_MAX_DATA_LIMIT);
+            int limit = DEFAULT_MAX_DATA_LIMIT;
+            if (strParam != null) {
+                limit = Integer.parseInt(strParam);
+                if (limit > DEFAULT_MAX_DATA_LIMIT) {
+                    limit = DEFAULT_MAX_DATA_LIMIT;
+                }
+            }
+            return backupAs("limit", limit);
         }
         }
 
 
         public ContentType format() {
         public ContentType format() {

+ 1 - 0
src/main/resources/openAPISpec.yaml

@@ -1545,6 +1545,7 @@ components:
       schema:
       schema:
         type: integer
         type: integer
         format: int64
         format: int64
+        maximum: 500
       required: false
       required: false
       example: 100
       example: 100
     offsetParam:
     offsetParam:

+ 4 - 1
testing/update.sql

@@ -1,6 +1,9 @@
-ALTER TABLE maplog.driver RENAME TO maplog.entity;
+ALTER TABLE maplog.driver RENAME TO entity;
+
 ALTER TABLE maplog.entity RENAME COLUMN driver_id TO id;
 ALTER TABLE maplog.entity RENAME COLUMN driver_id TO id;
+
 ALTER TABLE maplog.entity ADD COLUMN identity VARCHAR(30) NOT NULL DEFAULT '';
 ALTER TABLE maplog.entity ADD COLUMN identity VARCHAR(30) NOT NULL DEFAULT '';
+
 CREATE SEQUENCE maplog.entity_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
 CREATE SEQUENCE maplog.entity_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
 ALTER TABLE maplog.entity_id_seq OWNER TO senslog;
 ALTER TABLE maplog.entity_id_seq OWNER TO senslog;
 ALTER SEQUENCE maplog.entity_id_seq OWNED BY maplog.entity.id;
 ALTER SEQUENCE maplog.entity_id_seq OWNED BY maplog.entity.id;