Sfoglia il codice sorgente

Implemented permission scopes [read:personal, read:infrastructure] for all endpoints.

Lukas Cerny 1 anno fa
parent
commit
93a683c1cd

+ 1 - 0
docker.dev.env

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

+ 11 - 4
init.sql

@@ -166,12 +166,19 @@ ALTER TABLE ONLY maplog.sensor ALTER COLUMN sensor_id SET DEFAULT nextval('maplo
 
 
 CREATE TABLE maplog.system_user (
-    user_id INTEGER NOT NULL PRIMARY KEY,
-    name TEXT NOT NULL
+    id          INTEGER NOT NULL PRIMARY KEY,
+    identity    VARCHAR(50) NOT NULL,
+    name        TEXT NOT NULL
 );
 ALTER TABLE maplog.system_user OWNER TO senslog;
 
-INSERT INTO maplog.system_user(user_id, name) VALUES (0, 'admin');
+CREATE SEQUENCE maplog.system_user_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
+
+ALTER TABLE maplog.system_user_id_seq OWNER TO senslog;
+
+ALTER SEQUENCE maplog.system_user_id_seq OWNED BY maplog.sensor.sensor_id;
+
+ALTER TABLE ONLY maplog.system_user ALTER COLUMN id SET DEFAULT nextval('maplog.system_user_id_seq'::regclass);
 
 CREATE TABLE maplog.unit (
     unit_id BIGINT NOT NULL PRIMARY KEY,
@@ -289,7 +296,7 @@ ALTER TABLE ONLY maplog.sensor ADD CONSTRAINT sens_phenom_fk FOREIGN KEY (phenom
 
 ALTER TABLE ONLY maplog.user_to_campaign_config ADD CONSTRAINT u2c_campid FOREIGN KEY (campaign_id) REFERENCES maplog.campaign(id) ON UPDATE CASCADE ON DELETE CASCADE;
 
-ALTER TABLE ONLY maplog.user_to_campaign_config ADD CONSTRAINT u2c_userid_fk FOREIGN KEY (user_id) REFERENCES maplog.system_user(user_id) ON UPDATE CASCADE ON DELETE CASCADE;
+ALTER TABLE ONLY maplog.user_to_campaign_config ADD CONSTRAINT u2c_userid_fk FOREIGN KEY (user_id) REFERENCES maplog.system_user(id) ON UPDATE CASCADE ON DELETE CASCADE;
 
 ALTER TABLE ONLY maplog.user_to_campaign_config ADD CONSTRAINT u2c_entityid_fk FOREIGN KEY (entity_id) REFERENCES maplog.entity(id) ON UPDATE CASCADE ON DELETE CASCADE;
 

+ 52 - 0
src/main/java/cz/senslog/telemetry/database/domain/AuthBearerUser.java

@@ -0,0 +1,52 @@
+package cz.senslog.telemetry.database.domain;
+
+import cz.senslog.telemetry.server.ws.AuthorizationScope;
+import io.vertx.core.json.JsonArray;
+import io.vertx.core.json.JsonObject;
+import io.vertx.ext.auth.User;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static java.util.Collections.emptyList;
+
+public class AuthBearerUser {
+
+    private final String id;
+
+    private final Set<AuthorizationScope> permissionScopes;
+
+    public static AuthBearerUser of(User user) {
+        return user != null ? of(user.principal()) : null;
+    }
+
+    public static AuthBearerUser of(JsonObject jsonUser) {
+        JsonArray jsonPermissions = jsonUser.getJsonArray("permissions", new JsonArray(emptyList()));
+        Set<AuthorizationScope> permissions = new HashSet<>(jsonPermissions.size());
+        for (Object jsonP : jsonPermissions) {
+            AuthorizationScope scope = AuthorizationScope.ofScope((String)jsonP);
+            if (scope != null) {
+                permissions.add(scope);
+            }
+        }
+
+        return new AuthBearerUser(jsonUser.getString("azp"), permissions);
+    }
+
+    public AuthBearerUser(String id, Set<AuthorizationScope> permissionScopes) {
+        this.id = id;
+        this.permissionScopes = permissionScopes;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public Set<AuthorizationScope> getPermissionScopes() {
+        return permissionScopes;
+    }
+
+    public boolean hasPermissionScope(AuthorizationScope scope) {
+        return permissionScopes.contains(scope);
+    }
+}

File diff suppressed because it is too large
+ 615 - 82
src/main/java/cz/senslog/telemetry/database/repository/MapLogRepository.java


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

@@ -27,76 +27,219 @@ public interface SensLogRepository {
 
 
     Future<List<Unit>> allUnits();
+    Future<List<Unit>> allUnitsByIdentity(String userIdentity);
     Future<Unit> findUnitById(long unitId);
+    Future<Unit> findUnitByIdentityAndId(String userIdentity, long unitId);
     Future<Unit> findUnitByIMEI(String imei);
     Future<List<Unit>> findUnitsBySensorId(long sensorId);
+    Future<List<Unit>> findUnitsByIdentityAndSensorId(String userIdentity, long sensorId);
     Future<List<CampaignUnit>> findUnitsByCampaignId(long campaignId);
+    Future<List<CampaignUnit>> findUnitsByIdentityAndCampaignId(String userIdentity, long campaignId);
     Future<Set<Long>> findUnitsIDByCampaignId(long campaignId);
     Future<CampaignUnit> findUnitByIdAndCampaignId(long unitId, long campaignId);
+    Future<CampaignUnit> findUnitByIdentityAndIdAndCampaignId(String userIdentity, long unitId, long campaignId);
     Future<Unit> findUnitByIdAndEntityId(long unitId, int entityId);
+    Future<Unit> findUnitByIdentityAndIdAndEntityId(String userIdentity, long unitId, int entityId);
     Future<Unit> findUnitByIdAndEntityIdAndActionId(long unitId, int entityId, int actionId);
+    Future<Unit> findUnitByIdentityAndIdAndEntityIdAndActionId(String userIdentity, long unitId, int entityId, int actionId);
     Future<List<Unit>> findUnitsByEntityIdAndActionId(int entityId, int actionId);
+    Future<List<Unit>> findUnitsByIdentityAndEntityIdAndActionId(String userIdentity, int entityId, int actionId);
     Future<List<Long>> findUnitIdsByCampaignId(long campaignId);
 
     Future<List<Sensor>> allSensors();
+    Future<List<Sensor>> allSensorsByIdentity(String userIdentity);
     Future<Sensor> findSensorById(long sensorId);
+    Future<Sensor> findSensorByIdentityAndId(String userIdentity, long sensorId);
     Future<Sensor> findSensorByIOAndUnitId(int ioID, long unitId);
     Future<Map<Long, Sensor>> findSensorsByUnitIdGroupById(long unitId);
     Future<Map<Long, List<Sensor>>> findSensorsByCampaignIdGroupByUnitId(long campaignId);
     Future<List<Sensor>> findSensorsByUnitId(long unitId);
+    Future<List<Sensor>> findSensorsByIdentityAndUnitId(String userIdentity, long unitId);
     Future<List<Sensor>> findSensorsByPhenomenonId(long phenomenonId);
+    Future<List<Sensor>> findSensorsByIdentityAndPhenomenonId(String userIdentity, long phenomenonId);
     Future<List<Sensor>> findSensorsByCampaignIdAndUnitId(long campaignId, long unitId);
+    Future<List<Sensor>> findSensorsByIdentityAndCampaignIdAndUnitId(String userIdentity, long campaignId, long unitId);
     Future<Sensor> findSensorByCampaignIdAndUnitId(long campaignId, long unitId, long sensorId);
+    Future<Sensor> findSensorByIdentityAndCampaignIdAndUnitId(String userIdentity, long campaignId, long unitId, long sensorId);
 
     Future<List<Phenomenon>> allPhenomenons();
+    Future<List<Phenomenon>> allPhenomenonsByIdentity(String userIdentity);
     Future<Phenomenon> findPhenomenonById(long phenomenonId);
+    Future<Phenomenon> findPhenomenonByIdentityAndId(String userIdentity, long phenomenonId);
 
     Future<List<Campaign>> allCampaigns();
+    Future<List<Campaign>> allCampaignsByIdentity(String userIdentity);
+
     Future<Campaign> findCampaignById(long campaignId);
-    Future<List<Campaign>> findCampaignsByUnitId(long unitId, ZoneId zone);
+    Future<Campaign> findCampaignByIdentityAndId(String userIdentity, long campaignId);
+    Future<List<Campaign>> findCampaignsByUnitId(long unitId);
+    Future<List<Campaign>> findCampaignsByIdentityAndUnitId(String userIdentity, long unitId);
 
 
     Future<List<Entity>> allEntities();
+    Future<List<Entity>> allEntitiesByIdentity(String userIdentity);
     Future<Entity> findEntityById(int entityId);
+    Future<Entity> findEntityByIdentityId(String userIdentity, int entityId);
     Future<List<Entity>> findEntitiesByUnitId(long unitId);
+    Future<List<Entity>> findEntitiesByIdentityAndUnitId(String userIdentity, long unitId);
 
     Future<List<Action>> findActionsByEntityIdAndUnitId(int entityId, long unitId);
+    Future<List<Action>> findActionsByIdentityAndEntityIdAndUnitId(String userIdentity, int entityId, long unitId);
     Future<List<Action>> findActionsByEntityId(int entityId, OffsetDateTime from, OffsetDateTime to);
+    Future<List<Action>> findActionsByIdentityAndEntityId(String userIdentity, int entityId, OffsetDateTime from, OffsetDateTime to);
     Future<Action> findActionByIdAndEntityId(int actionId, int entityId);
+    Future<Action> findActionByIdentityIdAndEntityId(String userIdentity, int actionId, int entityId);
     Future<Action> findActionByIdAndEntityIdAndUnitId(int actionId, int entityId, long unitId);
+    Future<Action> findActionByIdentityAndIdAndEntityIdAndUnitId(String userIdentity, int actionId, int entityId, long unitId);
 
 
     Future<List<Event>> findEventsByEntityIdAndUnitIdAndActionId(int entityId, long unitId, int actionId);
+    Future<List<Event>> findEventsByIdentityAndEntityIdAndUnitIdAndActionId(String userIdentity, int entityId, long unitId, int actionId);
     Future<Event> findEventById(long eventId);
+    Future<Event> findEventByIdentityAndId(String userIdentity, long eventId);
 
     Future<List<Unit>> findUnitsByEntityId(int entityId, OffsetDateTime from, OffsetDateTime to);
-    Future<List<UnitTelemetry>> findObservationsByCampaignId(long campaignId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters);
-    Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdWithPaging(long campaignId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters);
-
-    Future<List<UnitTelemetry>> findObservationsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters);
-    Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdAndUnitIdWithPaging(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters);
-
-    Future<List<UnitTelemetry>> findObservationsByEventId(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters);
-    Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByEventIdWithPaging(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters);
-
-    Future<List<SensorTelemetry>> findObservationsByCampaignIdAndUnitIdAndSensorId(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters);
-    Future<PagingRetrieve<List<SensorTelemetry>>> findObservationsByCampaignIdAndUnitIdAndSensorIdWithPaging(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters);
-
-    Future<List<UnitLocation>> findLocationsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters);
-    Future<PagingRetrieve<List<UnitLocation>>> findLocationsByCampaignIdAndUnitIdWithPaging(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters);
-
-    Future<List<UnitLocation>> findLocationsByEventId(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters);
-    Future<PagingRetrieve<List<UnitLocation>>> findLocationsByEventIdWithPaging(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters);
-
-    Future<List<UnitLocation>> findUnitsLocationsByCampaignId(long campaignId, int limitPerUnit, OffsetDateTime from, OffsetDateTime to, ZoneId zone, SortType sort, List<Filter> filters);
+    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<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdWithPaging(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) {
+        return findObservationsByIdentityAndCampaignId(userIdentity, 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>> 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);
+    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) {
+        return findObservationsByIdentityAndCampaignIdAndUnitId(userIdentity, 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>> findObservationsByEventId(long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
+    default Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByEventIdWithPaging(long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findObservationsByEventId(eventId, 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>> findObservationsByIdentityAndEventId(String userIdentity, long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
+    default Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByIdentityAndEventIdWithPaging(String userIdentity, long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findObservationsByIdentityAndEventId(userIdentity, eventId, 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<SensorTelemetry>> findObservationsByCampaignIdAndUnitIdAndSensorId(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
+    default Future<PagingRetrieve<List<SensorTelemetry>>> findObservationsByCampaignIdAndUnitIdAndSensorIdWithPaging(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findObservationsByCampaignIdAndUnitIdAndSensorId(campaignId, unitId, sensorId, 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<SensorTelemetry>> findObservationsByIdentityAndCampaignIdAndUnitIdAndSensorId(String userIdentity, long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
+    default Future<PagingRetrieve<List<SensorTelemetry>>> findObservationsByIdentityAndCampaignIdAndUnitIdAndSensorIdWithPaging(String userIdentity, long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findObservationsByIdentityAndCampaignIdAndUnitIdAndSensorId(userIdentity, campaignId, unitId, sensorId, 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<UnitLocation>> findLocationsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
+    default Future<PagingRetrieve<List<UnitLocation>>> findLocationsByCampaignIdAndUnitIdWithPaging(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findLocationsByCampaignIdAndUnitId(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<UnitLocation>> findLocationsByIdentityCampaignIdAndUnitId(String userIdentity, long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
+    default Future<PagingRetrieve<List<UnitLocation>>> findLocationsByIdentityCampaignIdAndUnitIdWithPaging(String userIdentity, long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findLocationsByIdentityCampaignIdAndUnitId(userIdentity, 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<UnitLocation>> findLocationsByEventId(long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
+    default Future<PagingRetrieve<List<UnitLocation>>> findLocationsByEventIdWithPaging(long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findLocationsByEventId(eventId, 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<UnitLocation>> findLocationsByIdentityAndEventId(String userIdentity, long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters);
+
+    default Future<PagingRetrieve<List<UnitLocation>>> findLocationsByIdentityAndEventIdWithPaging(String userIdentity, long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findLocationsByIdentityAndEventId(userIdentity, eventId, 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<UnitLocation>> findUnitsLocationsByCampaignId(long campaignId, int limitPerUnit, OffsetDateTime from, OffsetDateTime to, SortType sort, List<Filter> filters);
+    Future<List<UnitLocation>> findUnitsLocationsByIdentityAndCampaignId(String userIdentity, long campaignId, int limitPerUnit, OffsetDateTime from, OffsetDateTime to, SortType sort, List<Filter> filters);
 
     Future<CampaignUnitAlert> findAlertById(long alertId);
+    Future<CampaignUnitAlert> findAlertByIdentityAndId(String userIdentity, long alertId);
     Future<Long> updateAlert(long alertId, AlertStatus status);
     Future<Long> saveAlert(UnitAlert alert);
     Future<List<Long>> saveAlerts(List<UnitAlert> alerts);
     Future<List<Alert>> findAlertsByEventId(long eventId, Set<AlertStatus> statusFilter, SortType sortType);
+    Future<List<Alert>> findAlertsByIdentityAndEventId(String userIdentity, long eventId, Set<AlertStatus> statusFilter, SortType sortType);
     Future<EventAlert> findAlertByIdAndEventId(long alertId, long eventId);
+    Future<EventAlert> findAlertByIdentityAndIdAndEventId(String userIdentity, long alertId, long eventId);
     Future<List<CampaignUnitAlert>> findAlertsByCampaignId(long campaignId, OffsetDateTime from, OffsetDateTime to, Set<AlertStatus> statusFilter, SortType sort);
+    Future<List<CampaignUnitAlert>> findAlertsByIdentityAndCampaignId(String userIdentity, long campaignId, OffsetDateTime from, OffsetDateTime to, Set<AlertStatus> statusFilter, SortType sort);
     Future<List<UnitAlert>> findAlertsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, Set<AlertStatus> statusFilter, SortType sort);
+    Future<List<UnitAlert>> findAlertsByIdentityAndCampaignIdAndUnitId(String userIdentity, long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, Set<AlertStatus> statusFilter, SortType sort);
     Future<List<Alert>> findAlertsByEntityIdAndActionIdAndUnitId(long entityId, long actionId, long unitId, Set<AlertStatus> statusFilter, SortType sort);
+    Future<List<Alert>> findAlertsByIdentityAndEntityIdAndActionIdAndUnitId(String userIdentity, long entityId, long actionId, long unitId, Set<AlertStatus> statusFilter, SortType sort);
 }

+ 12 - 7
src/main/java/cz/senslog/telemetry/server/HttpVertxServer.java

@@ -1,14 +1,17 @@
 package cz.senslog.telemetry.server;
 
 import cz.senslog.telemetry.database.repository.SensLogRepository;
+import cz.senslog.telemetry.server.ws.AuthorizationType;
+import cz.senslog.telemetry.server.ws.DisableAuthorizationHandler;
 import cz.senslog.telemetry.server.ws.ExceptionHandler;
 import cz.senslog.telemetry.server.ws.OpenAPIHandler;
 import cz.senslog.telemetry.utils.ResourcesUtils;
-import io.vertx.core.AbstractVerticle;
-import io.vertx.core.Promise;
+import io.vertx.core.*;
 import io.vertx.core.http.HttpMethod;
+import io.vertx.core.json.JsonArray;
 import io.vertx.core.json.JsonObject;
 import io.vertx.ext.auth.KeyStoreOptions;
+import io.vertx.ext.auth.User;
 import io.vertx.ext.auth.jwt.JWTAuth;
 import io.vertx.ext.auth.jwt.JWTAuthOptions;
 import io.vertx.ext.web.Router;
@@ -33,6 +36,8 @@ public final class HttpVertxServer extends AbstractVerticle {
 
     @Override
     public void start(Promise<Void> startPromise) {
+        final AuthorizationType openAPIAuthType = BEARER;
+
         Path openApiUrl = ResourcesUtils.getPath("openAPISpec.yaml");
         logger.info("Loading the OpenAPI spec from '{}'", openApiUrl);
 
@@ -57,15 +62,15 @@ public final class HttpVertxServer extends AbstractVerticle {
 
                     JsonObject authConfig = config().getJsonObject("auth");
                     if (authConfig.getBoolean("disabled")) {
-                        openAPIRouterBuilder.getOptions().setRequireSecurityHandlers(false);
+                        logger.info("Security schema for all endpoints is disabled.");
+                        openAPIRouterBuilder.securityHandler(openAPIAuthType.getSecuritySchemaKey(), DisableAuthorizationHandler.create());
                     } else {
-                        JWTAuthHandler authHandler = JWTAuthHandler.create(JWTAuth.create(vertx, new JWTAuthOptions()
+                        logger.info("Setting security schema for the type '{}' with the schema key '{}'.", openAPIAuthType.name(), openAPIAuthType.getSecuritySchemaKey());
+                        openAPIRouterBuilder.securityHandler(openAPIAuthType.getSecuritySchemaKey(), JWTAuthHandler.create(JWTAuth.create(vertx, new JWTAuthOptions()
                                 .setKeyStore(new KeyStoreOptions()
                                         .setPath(authConfig.getString("keystore.path"))
                                         .setType(authConfig.getString("keystore.type"))
-                                        .setPassword(authConfig.getString("keystore.password")))));
-
-                        openAPIRouterBuilder.securityHandler(BEARER.getSecuritySchemaKey(), authHandler);
+                                        .setPassword(authConfig.getString("keystore.password"))))));
                     }
 
 

+ 29 - 0
src/main/java/cz/senslog/telemetry/server/ws/AuthorizationScope.java

@@ -0,0 +1,29 @@
+package cz.senslog.telemetry.server.ws;
+
+public enum AuthorizationScope {
+
+    READ_PERSONAL           ("read:personal"),
+    WRITE_PERSONAL          ("write:personal"),
+    READ_INFRASTRUCTURE     ("read:infrastructure"),
+    WRITE_INFRASTRUCTURE    ("write:infrastructure"),
+
+    ;
+    private final String permissionScope;
+
+    AuthorizationScope(String permissionScope) {
+        this.permissionScope = permissionScope;
+    }
+
+    public String getPermissionScope() {
+        return permissionScope;
+    }
+
+    public static AuthorizationScope ofScope(String permissionScope) {
+        for (AuthorizationScope value : values()) {
+            if (value.permissionScope.equalsIgnoreCase(permissionScope)) {
+                return value;
+            }
+        }
+        return null;
+    }
+}

+ 29 - 0
src/main/java/cz/senslog/telemetry/server/ws/DisableAuthorizationHandler.java

@@ -0,0 +1,29 @@
+package cz.senslog.telemetry.server.ws;
+
+import io.vertx.core.AsyncResult;
+import io.vertx.core.Future;
+import io.vertx.core.Handler;
+import io.vertx.ext.auth.User;
+import io.vertx.ext.web.RoutingContext;
+import io.vertx.ext.web.handler.impl.AuthenticationHandlerInternal;
+
+public final class DisableAuthorizationHandler implements AuthenticationHandlerInternal {
+
+
+    public static DisableAuthorizationHandler create() {
+        return new DisableAuthorizationHandler();
+    }
+
+    private DisableAuthorizationHandler() {}
+
+    @Override
+    public void authenticate(RoutingContext routingContext, Handler<AsyncResult<User>> handler) {
+        handler.handle(Future.succeededFuture());
+    }
+
+    @Override
+    public void handle(RoutingContext routingContext) {
+        routingContext.next();
+    }
+
+}

File diff suppressed because it is too large
+ 369 - 485
src/main/java/cz/senslog/telemetry/server/ws/OpenAPIHandler.java


+ 183 - 0
src/main/java/cz/senslog/telemetry/server/ws/WSParameters.java

@@ -0,0 +1,183 @@
+package cz.senslog.telemetry.server.ws;
+
+import cz.senslog.telemetry.database.SortType;
+import cz.senslog.telemetry.database.domain.AlertStatus;
+import cz.senslog.telemetry.database.domain.Filter;
+import io.vertx.core.MultiMap;
+import io.vertx.core.json.JsonArray;
+import io.vertx.core.json.JsonObject;
+import io.vertx.ext.web.RoutingContext;
+
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static cz.senslog.telemetry.server.ws.ContentType.JSON;
+import static java.lang.Boolean.parseBoolean;
+import static java.util.Collections.emptyList;
+import static java.util.stream.Collectors.toSet;
+
+public class WSParameters {
+
+    private static final int DEFAULT_MAX_DATA_LIMIT = 500;
+    private static final ZoneId DEFAULT_ZONE_ID = ZoneId.of("UTC");
+    private static final SortType DEFAULT_SORT_TYPE = SortType.ASC;
+    private static final boolean DEFAULT_NAVIGATION_LINKS = true;
+    private static final int DEFAULT_LIMIT_PER_UNIT = 1;
+    private static final ContentType DEFAULT_RESPONSE_FORMAT = JSON;
+
+
+    private final WSQueryParameters queryParams;
+    private final WSPathParameters pathParams;
+
+    public WSQueryParameters queryParams() {
+        return queryParams;
+    }
+
+    public WSPathParameters pathParams() {
+        return pathParams;
+    }
+
+    public static WSParameters wrap(MultiMap queryParams, Map<String, String> pathParams, JsonObject backup) {
+        return new WSParameters(new WSQueryParameters(queryParams, backup), new WSPathParameters(pathParams));
+    }
+
+    public static WSParameters wrap(MultiMap queryParams, Map<String, String> pathParams) {
+        return new WSParameters(new WSQueryParameters(queryParams, null), new WSPathParameters(pathParams));
+    }
+
+    private WSParameters(WSQueryParameters queryParams, WSPathParameters pathParams) {
+        this.queryParams = queryParams;
+        this.pathParams = pathParams;
+    }
+
+    public static class WSQueryParameters {
+
+        private final MultiMap queryParams;
+        private final JsonObject backup;
+
+        private WSQueryParameters(MultiMap queryParams, JsonObject backup) {
+            this.queryParams = queryParams;
+            this.backup = backup;
+        }
+
+        private <T> T backupAs(String name, T value) {
+            if (backup != null && value != null) {
+                backup.put(name, value);
+            }
+            return value;
+        }
+
+        public ZoneId zone() {
+            String strParam = queryParams.get("zone");
+            if (strParam == null) {
+                return null;
+            }
+            ZoneId zone = ZoneId.of(strParam);
+            if (backup != null) {
+                backup.put("zone", zone.toString());
+            }
+            return zone;
+        }
+
+        public boolean navigationLinks() {
+            String strParam = queryParams.get("navigationLinks");
+            return backupAs("navigationLinks", strParam != null ? parseBoolean(strParam) : DEFAULT_NAVIGATION_LINKS);
+        }
+
+        public OffsetDateTime from() {
+            String strParam = queryParams.get("from");
+            return backupAs("from", strParam != null ? OffsetDateTime.parse(strParam) : null);
+        }
+
+        public OffsetDateTime to() {
+            String strParam = queryParams.get("to");
+            return backupAs("to", strParam != null ? OffsetDateTime.parse(strParam) : null);
+        }
+
+        public int offset() {
+            String strParam = queryParams.get("offset");
+            return backupAs("offset", strParam != null ? Integer.parseInt(strParam) : 0);
+        }
+
+        public int limit() {
+            String strParam = queryParams.get("limit");
+            return backupAs("limit", strParam != null ? Integer.parseInt(strParam) : DEFAULT_MAX_DATA_LIMIT);
+        }
+
+        public ContentType format() {
+            String strParam = queryParams.get("format");
+            return backupAs("format", strParam != null ? ContentType.of(strParam) : DEFAULT_RESPONSE_FORMAT);
+        }
+
+        public List<Filter> filter() {
+            List<String> strParams = queryParams.getAll("filter");
+            if (strParams.isEmpty()) {
+                return emptyList();
+            }
+            if (backup != null) {
+                backup.put("filter", new JsonArray(strParams));
+            }
+            return FilterParser.parse(strParams);
+        }
+
+        public int limitPerUnit() {
+            String strParam = queryParams.get("limitPerUnit");
+            return backupAs("limitPerUnit", strParam != null ? Integer.parseInt(strParam) : DEFAULT_LIMIT_PER_UNIT);
+        }
+
+        public SortType sort() {
+            String strParam = queryParams.get("sort");
+            return backupAs("sort", strParam != null ? SortType.of(strParam) : DEFAULT_SORT_TYPE);
+        }
+
+        public Set<AlertStatus> status() {
+            return queryParams.getAll("status").stream().map(AlertStatus::valueOf).collect(toSet());
+        }
+    }
+
+    public static class WSPathParameters {
+
+        private final Map<String, String> pathParams;
+
+        private WSPathParameters(Map<String, String> pathParams) {
+            this.pathParams = pathParams;
+        }
+
+        public long campaignId() {
+            return Long.parseLong(pathParams.get("campaignId"));
+        }
+
+        public long unitId() {
+            return Long.parseLong(pathParams.get("unitId"));
+        }
+
+        public long sensorId() {
+            return Long.parseLong(pathParams.get("sensorId"));
+        }
+
+        public long phenomenonId() {
+            return  Long.parseLong(pathParams.get("phenomenonId"));
+        }
+
+        public int entityId() {
+            return Integer.parseInt(pathParams.get("entityId"));
+        }
+
+        public int actionId() {
+            return Integer.parseInt(pathParams.get("actionId"));
+        }
+
+        public int eventId() {
+            return Integer.parseInt(pathParams.get("eventId"));
+        }
+
+        public long alertId() {
+            return Long.parseLong(pathParams.get("alertId"));
+        }
+    }
+
+
+}

+ 80 - 0
src/main/java/cz/senslog/telemetry/utils/CascadeCondition.java

@@ -0,0 +1,80 @@
+package cz.senslog.telemetry.utils;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+public interface CascadeCondition {
+
+    interface CascadeConditionBuilder<I, O> {
+
+        CascadeConditionBuilder<I, O> ifThen(Function<I, Boolean> condition, Function<I, O> consumer);
+
+        void execute(Consumer<O> finalizer);
+    }
+
+    interface CascadeConditionNullable<I, O> {
+
+        CascadeConditionBuilder<I, O> ifThenAsDefault (Function < I, Boolean > condition, Supplier < O > consumer);
+
+        CascadeConditionBuilder<I, O> withDefault (Supplier < O > consumer);
+    }
+
+
+        static <I, O> CascadeConditionBuilder<I, O> of(I input) {
+        return new CascadeConditionImpl<>(Objects.requireNonNull(input));
+    }
+
+    static <I, O> CascadeConditionNullable<I, O> ofNullable(I input) {
+        return new CascadeConditionImpl<>(input);
+    }
+
+    class CascadeConditionImpl<I, O> implements CascadeConditionNullable<I, O>, CascadeConditionBuilder<I, O> {
+
+        private final I input;
+        private O result;
+        private Supplier<O> defaultConsumer;
+
+        private CascadeConditionImpl(I input) {
+            this.input = input;
+        }
+
+        @Override
+        public CascadeConditionBuilder<I, O> ifThenAsDefault(Function<I, Boolean> condition, Supplier<O> consumer) {
+            this.defaultConsumer = consumer;
+            if (input == null || condition.apply(input)) {
+                this.result = consumer.get();
+            }
+            return this;
+        }
+
+        @Override
+        public CascadeConditionBuilder<I, O> withDefault(Supplier<O> consumer) {
+            this.defaultConsumer = consumer;
+            if (input == null) {
+                this.result = consumer.get();
+            }
+            return this;
+        }
+
+        @Override
+        public CascadeConditionBuilder<I, O> ifThen(Function<I, Boolean> condition, Function<I, O> consumer) {
+            if (result == null && condition.apply(input)) {
+                this.result = consumer.apply(input);
+            }
+            return this;
+        }
+
+        @Override
+        public void execute(Consumer<O> finalizer) {
+            if (result != null) {
+                finalizer.accept(result);
+            } else if (defaultConsumer != null) {
+                finalizer.accept(defaultConsumer.get());
+            } else {
+                throw new IllegalStateException("No define default action!");
+            }
+        }
+    }
+}

+ 90 - 48
src/main/resources/openAPISpec.yaml

@@ -33,7 +33,8 @@ paths:
       tags:
         - Campaign
       security:
-        - bearerAuth: [telemetry:read]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/zoneParam'
         - $ref: '#/components/parameters/navigationLinksParam'
@@ -60,7 +61,8 @@ paths:
       tags:
         - Campaign
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
         - $ref: '#/components/parameters/zoneParam'
@@ -86,7 +88,8 @@ paths:
       tags:
         - Unit
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
         - $ref: '#/components/parameters/zoneParam'
@@ -114,7 +117,8 @@ paths:
       tags:
         - Observation
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
         - $ref: '#/components/parameters/fromParam'
@@ -146,7 +150,7 @@ paths:
       tags:
         - Observation
       security:
-        - bearerAuth: [ telemetry:write ]
+        - bearerAuth: [write:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
       requestBody:
@@ -181,7 +185,8 @@ paths:
       tags:
         - Observation
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
         - $ref: '#/components/parameters/limitPerUnitParam'
@@ -216,7 +221,8 @@ paths:
       tags:
         - Unit
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
         - $ref: '#/components/parameters/unitIdParam'
@@ -243,7 +249,8 @@ paths:
       tags:
         - Observation
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
         - $ref: '#/components/parameters/unitIdParam'
@@ -279,7 +286,8 @@ paths:
       tags:
         - Observation
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
         - $ref: '#/components/parameters/unitIdParam'
@@ -315,7 +323,8 @@ paths:
       tags:
         - Sensor
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
         - $ref: '#/components/parameters/unitIdParam'
@@ -343,7 +352,8 @@ paths:
       tags:
         - Sensor
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
         - $ref: '#/components/parameters/unitIdParam'
@@ -370,7 +380,8 @@ paths:
       tags:
         - Observation
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
         - $ref: '#/components/parameters/unitIdParam'
@@ -407,7 +418,8 @@ paths:
       tags:
         - Unit
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/navigationLinksParam'
       responses:
@@ -433,7 +445,8 @@ paths:
       tags:
         - Unit
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/unitIdParam'
         - $ref: '#/components/parameters/navigationLinksParam'
@@ -458,7 +471,8 @@ paths:
       tags:
         - Sensor
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/unitIdParam'
         - $ref: '#/components/parameters/navigationLinksParam'
@@ -485,7 +499,8 @@ paths:
       tags:
         - Campaign
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/unitIdParam'
         - $ref: '#/components/parameters/zoneParam'
@@ -513,7 +528,8 @@ paths:
       tags:
         - Entity
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/unitIdParam'
         - $ref: '#/components/parameters/navigationLinksParam'
@@ -540,7 +556,8 @@ paths:
       tags:
         - Sensor
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/navigationLinksParam'
       responses:
@@ -566,7 +583,8 @@ paths:
       tags:
         - Sensor
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/sensorIdParam'
         - $ref: '#/components/parameters/navigationLinksParam'
@@ -591,7 +609,8 @@ paths:
       tags:
         - Unit
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/sensorIdParam'
         - $ref: '#/components/parameters/navigationLinksParam'
@@ -619,7 +638,8 @@ paths:
       tags:
         - Phenomenon
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/navigationLinksParam'
       responses:
@@ -645,7 +665,8 @@ paths:
       tags:
         - Phenomenon
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/phenomenonIdParam'
         - $ref: '#/components/parameters/navigationLinksParam'
@@ -670,7 +691,8 @@ paths:
       tags:
         - Sensor
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/phenomenonIdParam'
         - $ref: '#/components/parameters/navigationLinksParam'
@@ -697,7 +719,8 @@ paths:
       tags:
         - Entity
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/navigationLinksParam'
       responses:
@@ -723,7 +746,8 @@ paths:
       tags:
         - Entity
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/entityIdParam'
         - $ref: '#/components/parameters/navigationLinksParam'
@@ -748,7 +772,8 @@ paths:
       tags:
         - Unit
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/entityIdParam'
         - $ref: '#/components/parameters/fromParam'
@@ -777,7 +802,8 @@ paths:
       tags:
         - Unit
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/entityIdParam'
         - $ref: '#/components/parameters/unitIdParam'
@@ -803,7 +829,8 @@ paths:
       tags:
         - Action
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/entityIdParam'
         - $ref: '#/components/parameters/unitIdParam'
@@ -831,7 +858,8 @@ paths:
       tags:
         - Action
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/entityIdParam'
         - $ref: '#/components/parameters/fromParam'
@@ -860,7 +888,8 @@ paths:
       tags:
         - Action
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/entityIdParam'
         - $ref: '#/components/parameters/actionIdParam'
@@ -886,7 +915,8 @@ paths:
       tags:
         - Unit
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/entityIdParam'
         - $ref: '#/components/parameters/actionIdParam'
@@ -914,7 +944,8 @@ paths:
       tags:
         - Unit
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/entityIdParam'
         - $ref: '#/components/parameters/actionIdParam'
@@ -941,7 +972,8 @@ paths:
       tags:
         - Action
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/entityIdParam'
         - $ref: '#/components/parameters/unitIdParam'
@@ -968,7 +1000,8 @@ paths:
       tags:
         - Event
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/entityIdParam'
         - $ref: '#/components/parameters/unitIdParam'
@@ -995,7 +1028,7 @@ paths:
       tags:
         - Event
       security:
-        - bearerAuth: [ telemetry:write ]
+        - bearerAuth: [write:infrastructure]
       parameters:
         - $ref: '#/components/parameters/entityIdParam'
         - $ref: '#/components/parameters/unitIdParam'
@@ -1034,7 +1067,8 @@ paths:
       tags:
         - Event
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/eventIdParam'
         - $ref: '#/components/parameters/zoneParam'
@@ -1057,7 +1091,7 @@ paths:
       tags:
         - Event
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [write:infrastructure]
       parameters:
         - $ref: '#/components/parameters/eventIdParam'
       requestBody:
@@ -1092,7 +1126,8 @@ paths:
       tags:
         - Observation
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/eventIdParam'
         - $ref: '#/components/parameters/zoneParam'
@@ -1125,7 +1160,8 @@ paths:
       tags:
         - Observation
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/eventIdParam'
         - $ref: '#/components/parameters/fromParam'
@@ -1159,7 +1195,8 @@ paths:
       tags:
         - Alert
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/alertIdParam'
         - $ref: '#/components/parameters/zoneParam'
@@ -1182,7 +1219,7 @@ paths:
       tags:
         - Alert
       security:
-        - bearerAuth: [ telemetry:write ]
+        - bearerAuth: [write:infrastructure]
       parameters:
         - $ref: '#/components/parameters/alertIdParam'
       requestBody:
@@ -1209,7 +1246,7 @@ paths:
       tags:
         - Alert
       security:
-        - bearerAuth: [ telemetry:write ]
+        - bearerAuth: [write:infrastructure]
       parameters:
         - $ref: '#/components/parameters/alertIdParam'
       responses:
@@ -1232,7 +1269,8 @@ paths:
       tags:
         - Alert
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/eventIdParam'
         - $ref: '#/components/parameters/alertStatusParam'
@@ -1261,7 +1299,8 @@ paths:
       tags:
         - Alert
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/eventIdParam'
         - $ref: '#/components/parameters/alertIdParam'
@@ -1287,7 +1326,8 @@ paths:
       tags:
         - Alert
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
         - $ref: '#/components/parameters/fromParam'
@@ -1316,7 +1356,7 @@ paths:
       tags:
         - Alert
       security:
-        - bearerAuth: [ telemetry:write ]
+        - bearerAuth: [write:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
       requestBody:
@@ -1351,7 +1391,8 @@ paths:
       tags:
         - Alert
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/campaignIdParam'
         - $ref: '#/components/parameters/unitIdParam'
@@ -1383,7 +1424,8 @@ paths:
       tags:
         - Alert
       security:
-        - bearerAuth: [ telemetry:read ]
+        - bearerAuth: [read:personal]
+        - bearerAuth: [read:infrastructure]
       parameters:
         - $ref: '#/components/parameters/entityIdParam'
         - $ref: '#/components/parameters/actionIdParam'

+ 256 - 14
src/test/java/cz/senslog/telemetry/MockSensLogRepository.java

@@ -61,11 +61,21 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Unit>> allUnitsByIdentity(String userIdentity) {
+        return allUnits();
+    }
+
+    @Override
     public Future<Unit> findUnitById(long unitId) {
         return Future.succeededFuture(Unit.of(1000, "mock(name)", "mock(imei)", "mock(description)"));
     }
 
     @Override
+    public Future<Unit> findUnitByIdentityAndId(String userIdentity, long unitId) {
+        return findUnitById(unitId);
+    }
+
+    @Override
     public Future<Unit> findUnitByIMEI(String imei) {
         return Future.succeededFuture(Unit.of(1000, "mock(imei)"));
     }
@@ -80,6 +90,11 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Unit>> findUnitsByIdentityAndSensorId(String userIdentity, long sensorId) {
+        return findUnitsBySensorId(sensorId);
+    }
+
+    @Override
     public Future<List<CampaignUnit>> findUnitsByCampaignId(long campaignId) {
         OffsetDateTime baseTimestamp = OffsetDateTime.ofInstant(BASE_INSTANT_TIMESTAMP, ZoneOffset.UTC);
         return Future.succeededFuture(List.of(
@@ -89,6 +104,11 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<CampaignUnit>> findUnitsByIdentityAndCampaignId(String userIdentity, long campaignId) {
+        return findUnitsByCampaignId(campaignId);
+    }
+
+    @Override
     public Future<Set<Long>> findUnitsIDByCampaignId(long campaignId) {
         return Future.succeededFuture(Set.of(1000L, 2000L, 3000L));
     }
@@ -100,16 +120,31 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<CampaignUnit> findUnitByIdentityAndIdAndCampaignId(String userIdentity, long unitId, long campaignId) {
+        return findUnitByIdAndCampaignId(unitId, campaignId);
+    }
+
+    @Override
     public Future<Unit> findUnitByIdAndEntityId(long unitId, int entityId) {
         return Future.succeededFuture(Unit.of(1000, "mock(name)", "mock(imei)", "mock(description)"));
     }
 
     @Override
+    public Future<Unit> findUnitByIdentityAndIdAndEntityId(String userIdentity, long unitId, int entityId) {
+        return findUnitByIdAndEntityId(unitId, entityId);
+    }
+
+    @Override
     public Future<Unit> findUnitByIdAndEntityIdAndActionId(long unitId, int entityId, int actionId) {
         return Future.succeededFuture(Unit.of(1000, "mock(name)", "mock(imei)", "mock(description)"));
     }
 
     @Override
+    public Future<Unit> findUnitByIdentityAndIdAndEntityIdAndActionId(String userIdentity, long unitId, int entityId, int actionId) {
+        return findUnitByIdAndEntityIdAndActionId(unitId, entityId, actionId);
+    }
+
+    @Override
     public Future<List<Unit>> findUnitsByEntityIdAndActionId(int entityId, int actionId) {
         return Future.succeededFuture(List.of(
                 Unit.of(1000, "mock(name)", "mock(imei)", "mock(description)"),
@@ -119,6 +154,11 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Unit>> findUnitsByIdentityAndEntityIdAndActionId(String userIdentity, int entityId, int actionId) {
+        return findUnitsByEntityIdAndActionId(entityId, actionId);
+    }
+
+    @Override
     public Future<List<Long>> findUnitIdsByCampaignId(long campaignId) {
         return Future.succeededFuture(List.of(1L,2L,3L));
     }
@@ -133,6 +173,11 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Sensor>> allSensorsByIdentity(String userIdentity) {
+        return allSensors();
+    }
+
+    @Override
     public Future<Sensor> findSensorById(long sensorId) {
         return Future.succeededFuture(
                 Sensor.of(105, "mock(name)", "M", 98, Phenomenon.of(15, "mock(phenomenon)"), "mock(description)")
@@ -140,6 +185,11 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<Sensor> findSensorByIdentityAndId(String userIdentity, long sensorId) {
+        return findSensorById(sensorId);
+    }
+
+    @Override
     public Future<Sensor> findSensorByIOAndUnitId(int ioID, long unitId) {
         return Future.succeededFuture(Sensor.of(105, "mock(name)", "M", 98, Phenomenon.of(15, "mock(phenomenon)"), "mock(description)"));
     }
@@ -177,6 +227,11 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Sensor>> findSensorsByIdentityAndUnitId(String userIdentity, long unitId) {
+        return findSensorsByUnitId(unitId);
+    }
+
+    @Override
     public Future<List<Sensor>> findSensorsByPhenomenonId(long phenomenonId) {
         return Future.succeededFuture(List.of(
                 Sensor.of(105, "mock(name)", "M", 98, Phenomenon.of(15, "mock(phenomenon)"), "mock(description)"),
@@ -186,6 +241,11 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Sensor>> findSensorsByIdentityAndPhenomenonId(String userIdentity, long phenomenonId) {
+        return findSensorsByPhenomenonId(phenomenonId);
+    }
+
+    @Override
     public Future<List<Sensor>> findSensorsByCampaignIdAndUnitId(long campaignId, long unitId) {
         return Future.succeededFuture(List.of(
                 Sensor.of(105, "mock(name)", "M"),
@@ -195,6 +255,11 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Sensor>> findSensorsByIdentityAndCampaignIdAndUnitId(String userIdentity, long campaignId, long unitId) {
+        return findSensorsByCampaignIdAndUnitId(campaignId, unitId);
+    }
+
+    @Override
     public Future<Sensor> findSensorByCampaignIdAndUnitId(long campaignId, long unitId, long sensorId) {
         return Future.succeededFuture(
                 Sensor.of(105, "mock(name)", "M", 98, Phenomenon.of(15, "mock(phenomenon)"), "mock(description)")
@@ -202,6 +267,11 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<Sensor> findSensorByIdentityAndCampaignIdAndUnitId(String userIdentity, long campaignId, long unitId, long sensorId) {
+        return findSensorByCampaignIdAndUnitId(campaignId, unitId, sensorId);
+    }
+
+    @Override
     public Future<List<Phenomenon>> allPhenomenons() {
         return Future.succeededFuture(List.of(
                 Phenomenon.of(1, "mock(name)"),
@@ -211,11 +281,21 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Phenomenon>> allPhenomenonsByIdentity(String userIdentity) {
+        return allPhenomenons();
+    }
+
+    @Override
     public Future<Phenomenon> findPhenomenonById(long phenomenonId) {
         return Future.succeededFuture(Phenomenon.of(1, "mock(name)", "mock(uom)", "http://uomlink"));
     }
 
     @Override
+    public Future<Phenomenon> findPhenomenonByIdentityAndId(String userIdentity, long phenomenonId) {
+        return findPhenomenonById(phenomenonId);
+    }
+
+    @Override
     public Future<List<Campaign>> allCampaigns() {
         OffsetDateTime baseTimestamp = OffsetDateTime.ofInstant(BASE_INSTANT_TIMESTAMP, ZoneOffset.UTC);
         return Future.succeededFuture(List.of(
@@ -224,13 +304,23 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Campaign>> allCampaignsByIdentity(String userIdentity) {
+        return allCampaigns();
+    }
+
+    @Override
     public Future<Campaign> findCampaignById(long campaignId) {
         OffsetDateTime baseTimestamp = OffsetDateTime.ofInstant(BASE_INSTANT_TIMESTAMP, ZoneOffset.UTC);
         return Future.succeededFuture(Campaign.of(1, "mock(description)", baseTimestamp, baseTimestamp.plusYears(1)));
     }
 
     @Override
-    public Future<List<Campaign>> findCampaignsByUnitId(long unitId, ZoneId zone) {
+    public Future<Campaign> findCampaignByIdentityAndId(String userIdentity, long campaignId) {
+        return findCampaignById(campaignId);
+    }
+
+    @Override
+    public Future<List<Campaign>> findCampaignsByUnitId(long unitId) {
         OffsetDateTime baseTimestamp = OffsetDateTime.ofInstant(BASE_INSTANT_TIMESTAMP, ZoneOffset.UTC);
         return Future.succeededFuture(List.of(
                 Campaign.of(1, "mock(description)", baseTimestamp, baseTimestamp.plusMonths(1)),
@@ -240,6 +330,11 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Campaign>> findCampaignsByIdentityAndUnitId(String userIdentity, long unitId) {
+        return findCampaignsByUnitId(unitId);
+    }
+
+    @Override
     public Future<List<Entity>> allEntities() {
         return Future.succeededFuture(List.of(
                 Entity.of(1, "mock(name)"),
@@ -249,11 +344,21 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Entity>> allEntitiesByIdentity(String userIdentity) {
+        return allEntities();
+    }
+
+    @Override
     public Future<Entity> findEntityById(int entityId) {
         return Future.succeededFuture(Entity.of(1, "mock(name)"));
     }
 
     @Override
+    public Future<Entity> findEntityByIdentityId(String userIdentity, int entityId) {
+        return findEntityById(entityId);
+    }
+
+    @Override
     public Future<List<Entity>> findEntitiesByUnitId(long unitId) {
         return Future.succeededFuture(List.of(
                 Entity.of(1, "mock(name)"),
@@ -262,6 +367,11 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Entity>> findEntitiesByIdentityAndUnitId(String userIdentity, long unitId) {
+        return findEntitiesByUnitId(unitId);
+    }
+
+    @Override
     public Future<List<Action>> findActionsByEntityIdAndUnitId(int entityId, long unitId) {
         return Future.succeededFuture(List.of(
                 Action.of(1, "mock(name)"),
@@ -271,6 +381,11 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Action>> findActionsByIdentityAndEntityIdAndUnitId(String userIdentity, int entityId, long unitId) {
+        return findActionsByEntityIdAndUnitId(entityId, unitId);
+    }
+
+    @Override
     public Future<List<Action>> findActionsByEntityId(int entityId, OffsetDateTime from, OffsetDateTime to) {
         return Future.succeededFuture(List.of(
                 Action.of(1, "mock(name)"),
@@ -280,16 +395,31 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Action>> findActionsByIdentityAndEntityId(String userIdentity, int entityId, OffsetDateTime from, OffsetDateTime to) {
+        return findActionsByEntityId(entityId, from, to);
+    }
+
+    @Override
     public Future<Action> findActionByIdAndEntityId(int actionId, int entityId) {
         return Future.succeededFuture(Action.of(1, "mock(name)"));
     }
 
     @Override
+    public Future<Action> findActionByIdentityIdAndEntityId(String userIdentity, int actionId, int entityId) {
+        return findActionByIdAndEntityId(actionId, entityId);
+    }
+
+    @Override
     public Future<Action> findActionByIdAndEntityIdAndUnitId(int actionId, int entityId, long unitId) {
         return Future.succeededFuture(Action.of(1, "mock(name)"));
     }
 
     @Override
+    public Future<Action> findActionByIdentityAndIdAndEntityIdAndUnitId(String userIdentity, int actionId, int entityId, long unitId) {
+        return findActionByIdAndEntityIdAndUnitId(actionId, entityId, unitId);
+    }
+
+    @Override
     public Future<List<Event>> findEventsByEntityIdAndUnitIdAndActionId(int entityId, long unitId, int actionId) {
         OffsetDateTime baseTimestamp = OffsetDateTime.ofInstant(BASE_INSTANT_TIMESTAMP, ZoneOffset.UTC);
         return Future.succeededFuture(List.of(
@@ -300,12 +430,22 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Event>> findEventsByIdentityAndEntityIdAndUnitIdAndActionId(String userIdentity, int entityId, long unitId, int actionId) {
+        return findEventsByEntityIdAndUnitIdAndActionId(entityId, unitId, actionId);
+    }
+
+    @Override
     public Future<Event> findEventById(long eventId) {
         OffsetDateTime baseTimestamp = OffsetDateTime.ofInstant(BASE_INSTANT_TIMESTAMP, ZoneOffset.UTC);
         return Future.succeededFuture(Event.of(1, 1, 1,1000, baseTimestamp, baseTimestamp.plusHours(8)));
     }
 
     @Override
+    public Future<Event> findEventByIdentityAndId(String userIdentity, long eventId) {
+        return findEventById(eventId);
+    }
+
+    @Override
     public Future<List<Unit>> findUnitsByEntityId(int entityId, OffsetDateTime from, OffsetDateTime to) {
         return Future.succeededFuture(List.of(
                 Unit.of(1000, "mock(name)", "mock(imei)", "mock(description)"),
@@ -314,6 +454,11 @@ public class MockSensLogRepository implements SensLogRepository {
         ));
     }
 
+    @Override
+    public Future<List<Unit>> findUnitsByIdentityAndEntityId(String userIdentity, int entityId, OffsetDateTime from, OffsetDateTime to) {
+        return findUnitsByEntityId(entityId, from, to);
+    }
+
     private static List<UnitTelemetry> mockUnitTelemetries() {
         OffsetDateTime baseTimestamp = OffsetDateTime.ofInstant(BASE_INSTANT_TIMESTAMP, ZoneOffset.UTC);
         Location location = Location.of(14f, 49f, 450f, 0);
@@ -326,34 +471,65 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
-    public Future<List<UnitTelemetry>> findObservationsByCampaignId(long campaignId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters) {
+    public Future<List<UnitTelemetry>> findObservationsByCampaignId(long campaignId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
         return Future.succeededFuture(mockUnitTelemetries());
     }
 
     @Override
-    public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdWithPaging(long campaignId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters) {
+    public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdWithPaging(long campaignId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
         List<UnitTelemetry> observations = mockUnitTelemetries();
         return Future.succeededFuture(new PagingRetrieve<>(true, observations.size(), observations));
     }
 
     @Override
-    public Future<List<UnitTelemetry>> findObservationsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters) {
+    public Future<List<UnitTelemetry>> findObservationsByIdentityAndCampaignId(String userIdentity, long campaignId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findObservationsByCampaignId(campaignId, from, to, offset, limit, filters);
+    }
+
+    @Override
+    public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByIdentityAndCampaignIdWithPaging(String userIdentity, long campaignId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findObservationsByCampaignIdWithPaging(campaignId, from, to, offset, limit, filters);
+    }
+
+    @Override
+    public Future<List<UnitTelemetry>> findObservationsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
         return Future.succeededFuture(mockUnitTelemetries());
     }
 
     @Override
-    public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdAndUnitIdWithPaging(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters) {
+    public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdAndUnitIdWithPaging(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
         List<UnitTelemetry> observations = mockUnitTelemetries();
         return Future.succeededFuture(new PagingRetrieve<>(true, observations.size(), observations));
     }
 
     @Override
-    public Future<List<UnitTelemetry>> findObservationsByEventId(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters) {
+    public Future<List<UnitTelemetry>> findObservationsByIdentityAndCampaignIdAndUnitId(String userIdentity, long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findObservationsByCampaignIdAndUnitId(campaignId, unitId, from, to, offset, limit, filters);
+    }
+
+    @Override
+    public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByIdentityAndCampaignIdAndUnitIdWithPaging(String userIdentity, long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findObservationsByCampaignIdAndUnitIdWithPaging(campaignId, unitId, from, to, offset, limit, filters);
+    }
+
+    @Override
+    public Future<List<UnitTelemetry>> findObservationsByEventId(long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
         return Future.succeededFuture(mockUnitTelemetries());
     }
 
     @Override
-    public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByEventIdWithPaging(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters) {
+    public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByEventIdWithPaging(long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        List<UnitTelemetry> observations = mockUnitTelemetries();
+        return Future.succeededFuture(new PagingRetrieve<>(true, observations.size(), observations));
+    }
+
+    @Override
+    public Future<List<UnitTelemetry>> findObservationsByIdentityAndEventId(String userIdentity, long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findObservationsByEventId(eventId, from, to, offset, limit, filters);
+    }
+
+    @Override
+    public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByIdentityAndEventIdWithPaging(String userIdentity, long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
         List<UnitTelemetry> observations = mockUnitTelemetries();
         return Future.succeededFuture(new PagingRetrieve<>(true, observations.size(), observations));
     }
@@ -369,16 +545,26 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
-    public Future<List<SensorTelemetry>> findObservationsByCampaignIdAndUnitIdAndSensorId(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters) {
+    public Future<List<SensorTelemetry>> findObservationsByCampaignIdAndUnitIdAndSensorId(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
         return Future.succeededFuture(mockSensorTelemetries());
     }
 
     @Override
-    public Future<PagingRetrieve<List<SensorTelemetry>>> findObservationsByCampaignIdAndUnitIdAndSensorIdWithPaging(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters) {
+    public Future<PagingRetrieve<List<SensorTelemetry>>> findObservationsByCampaignIdAndUnitIdAndSensorIdWithPaging(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
         List<SensorTelemetry> mock = mockSensorTelemetries();
         return Future.succeededFuture(new PagingRetrieve<>(true, mock.size(), mock));
     }
 
+    @Override
+    public Future<List<SensorTelemetry>> findObservationsByIdentityAndCampaignIdAndUnitIdAndSensorId(String userIdentity, long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findObservationsByCampaignIdAndUnitIdAndSensorId(campaignId, unitId, sensorId, from, to, offset, limit, filters);
+    }
+
+    @Override
+    public Future<PagingRetrieve<List<SensorTelemetry>>> findObservationsByIdentityAndCampaignIdAndUnitIdAndSensorIdWithPaging(String userIdentity, long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return SensLogRepository.super.findObservationsByIdentityAndCampaignIdAndUnitIdAndSensorIdWithPaging(userIdentity, campaignId, unitId, sensorId, from, to, offset, limit, filters);
+    }
+
     private static List<UnitLocation> mockUnitLocations() {
         OffsetDateTime baseTimestamp = OffsetDateTime.ofInstant(BASE_INSTANT_TIMESTAMP, ZoneOffset.UTC);
         Location location = Location.of(14f, 49f, 450f, 0);
@@ -390,39 +576,70 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
-    public Future<List<UnitLocation>> findLocationsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters) {
+    public Future<List<UnitLocation>> findLocationsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
         return Future.succeededFuture(mockUnitLocations());
     }
 
     @Override
-    public Future<PagingRetrieve<List<UnitLocation>>> findLocationsByCampaignIdAndUnitIdWithPaging(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters) {
+    public Future<PagingRetrieve<List<UnitLocation>>> findLocationsByCampaignIdAndUnitIdWithPaging(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
         List<UnitLocation> mock = mockUnitLocations();
         return Future.succeededFuture(new PagingRetrieve<>(true, mock.size(), mock));
     }
 
     @Override
-    public Future<List<UnitLocation>> findLocationsByEventId(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters) {
+    public Future<List<UnitLocation>> findLocationsByIdentityCampaignIdAndUnitId(String userIdentity, long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findLocationsByCampaignIdAndUnitId(campaignId, unitId, from, to, offset, limit, filters);
+    }
+
+    @Override
+    public Future<PagingRetrieve<List<UnitLocation>>> findLocationsByIdentityCampaignIdAndUnitIdWithPaging(String userIdentity, long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findLocationsByCampaignIdAndUnitIdWithPaging(campaignId, unitId, from, to, offset, limit, filters);
+    }
+
+    @Override
+    public Future<List<UnitLocation>> findLocationsByEventId(long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
         return Future.succeededFuture(mockUnitLocations());
     }
 
     @Override
-    public Future<PagingRetrieve<List<UnitLocation>>> findLocationsByEventIdWithPaging(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters) {
+    public Future<PagingRetrieve<List<UnitLocation>>> findLocationsByEventIdWithPaging(long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
         List<UnitLocation> mock = mockUnitLocations();
         return Future.succeededFuture(new PagingRetrieve<>(true, mock.size(), mock));
     }
 
     @Override
-    public Future<List<UnitLocation>> findUnitsLocationsByCampaignId(long campaignId, int limitPerUnit, OffsetDateTime from, OffsetDateTime to, ZoneId zone, SortType sort, List<Filter> filters) {
+    public Future<List<UnitLocation>> findLocationsByIdentityAndEventId(String userIdentity, long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        return findLocationsByEventId(eventId, from, to, offset, limit, filters);
+    }
+
+    @Override
+    public Future<PagingRetrieve<List<UnitLocation>>> findLocationsByIdentityAndEventIdWithPaging(String userIdentity, long eventId, OffsetDateTime from, OffsetDateTime to, int offset, int limit, List<Filter> filters) {
+        List<UnitLocation> mock = mockUnitLocations();
+        return Future.succeededFuture(new PagingRetrieve<>(true, mock.size(), mock));
+    }
+
+    @Override
+    public Future<List<UnitLocation>> findUnitsLocationsByCampaignId(long campaignId, int limitPerUnit, OffsetDateTime from, OffsetDateTime to, SortType sort, List<Filter> filters) {
         return Future.succeededFuture(mockUnitLocations());
     }
 
     @Override
+    public Future<List<UnitLocation>> findUnitsLocationsByIdentityAndCampaignId(String userIdentity, long campaignId, int limitPerUnit, OffsetDateTime from, OffsetDateTime to, SortType sort, List<Filter> filters) {
+        return findUnitsLocationsByCampaignId(campaignId, limitPerUnit, from, to, sort, filters);
+    }
+
+    @Override
     public Future<CampaignUnitAlert> findAlertById(long alertId) {
         OffsetDateTime baseTimestamp = OffsetDateTime.ofInstant(BASE_INSTANT_TIMESTAMP, ZoneOffset.UTC);
         return Future.succeededFuture(CampaignUnitAlert.of(1, 1, 1000, "mock(message)", baseTimestamp, AlertStatus.CREATED));
     }
 
     @Override
+    public Future<CampaignUnitAlert> findAlertByIdentityAndId(String userIdentity, long alertId) {
+        return findAlertById(alertId);
+    }
+
+    @Override
     public Future<Long> updateAlert(long alertId, AlertStatus status) {
         return Future.succeededFuture(1L);
     }
@@ -444,26 +661,51 @@ public class MockSensLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<Alert>> findAlertsByIdentityAndEventId(String userIdentity, long eventId, Set<AlertStatus> statusFilter, SortType sortType) {
+        return findAlertsByEventId(eventId, statusFilter, sortType);
+    }
+
+    @Override
     public Future<EventAlert> findAlertByIdAndEventId(long alertId, long eventId) {
         OffsetDateTime baseTimestamp = OffsetDateTime.ofInstant(BASE_INSTANT_TIMESTAMP, ZoneOffset.UTC);
         return Future.succeededFuture(EventAlert.of(1, 1, 1000, "mock(message)", baseTimestamp, AlertStatus.CREATED));
     }
 
     @Override
+    public Future<EventAlert> findAlertByIdentityAndIdAndEventId(String userIdentity, long alertId, long eventId) {
+        return findAlertByIdAndEventId(alertId, eventId);
+    }
+
+    @Override
     public Future<List<CampaignUnitAlert>> findAlertsByCampaignId(long campaignId, OffsetDateTime from, OffsetDateTime to, Set<AlertStatus> statusFilter, SortType sort) {
         OffsetDateTime baseTimestamp = OffsetDateTime.ofInstant(BASE_INSTANT_TIMESTAMP, ZoneOffset.UTC);
         return Future.succeededFuture(List.of(CampaignUnitAlert.of(1, 1, 1000, "mock(message)", baseTimestamp, AlertStatus.CREATED)));
     }
 
     @Override
+    public Future<List<CampaignUnitAlert>> findAlertsByIdentityAndCampaignId(String userIdentity, long campaignId, OffsetDateTime from, OffsetDateTime to, Set<AlertStatus> statusFilter, SortType sort) {
+        return findAlertsByCampaignId(campaignId, from, to, statusFilter, sort);
+    }
+
+    @Override
     public Future<List<UnitAlert>> findAlertsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, Set<AlertStatus> statusFilter, SortType sort) {
         OffsetDateTime baseTimestamp = OffsetDateTime.ofInstant(BASE_INSTANT_TIMESTAMP, ZoneOffset.UTC);
         return Future.succeededFuture(List.of(UnitAlert.of(1, 1, "mock(message)", baseTimestamp, AlertStatus.CREATED)));
     }
 
     @Override
+    public Future<List<UnitAlert>> findAlertsByIdentityAndCampaignIdAndUnitId(String userIdentity, long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, Set<AlertStatus> statusFilter, SortType sort) {
+        return findAlertsByCampaignIdAndUnitId(campaignId, unitId, from, to, statusFilter, sort);
+    }
+
+    @Override
     public Future<List<Alert>> findAlertsByEntityIdAndActionIdAndUnitId(long driverId, long actionId, long unitId, Set<AlertStatus> statusFilter, SortType sort) {
         OffsetDateTime baseTimestamp = OffsetDateTime.ofInstant(BASE_INSTANT_TIMESTAMP, ZoneOffset.UTC);
         return Future.succeededFuture(List.of(Alert.of(1, "mock(message)", baseTimestamp, AlertStatus.CREATED)));
     }
+
+    @Override
+    public Future<List<Alert>> findAlertsByIdentityAndEntityIdAndActionIdAndUnitId(String userIdentity, long entityId, long actionId, long unitId, Set<AlertStatus> statusFilter, SortType sort) {
+        return findAlertsByEntityIdAndActionIdAndUnitId(entityId, actionId, unitId, statusFilter, sort);
+    }
 }

+ 2 - 2
src/test/java/cz/senslog/telemetry/server/ws/OpenAPIHandlerTest.java

@@ -806,7 +806,7 @@ class OpenAPIHandlerTest {
     @DisplayName("API Spec Test: unitIdCampaignsGET")
     void unitIdCampaignsGET_bySpec(Future<List<Campaign>> dbFuture, OpenAPIResponseTyp responseTyp, ContentType contentType, Vertx vertx, VertxTestContext testContext) {
 
-        Mockito.when(repo.findCampaignsByUnitId(anyLong(), any())).thenReturn(dbFuture);
+        Mockito.when(repo.findCampaignsByUnitId(anyLong())).thenReturn(dbFuture);
 
         Operation operation = OPEN_API.getOperationById("unitIdCampaignsGET");
         RequestOptions reqOpt = new RequestOptions()
@@ -851,7 +851,7 @@ class OpenAPIHandlerTest {
     @DisplayName("API Params Test: unitIdCampaignsGET")
     void unitIdCampaignsGET_byParams(Future<List<Campaign>> dbFuture, String zoneParam, Tuple<String, String> expectedTimezones, boolean navigationLinks, Vertx vertx, VertxTestContext testContext) {
 
-        Mockito.when(repo.findCampaignsByUnitId(anyLong(), any())).thenReturn(dbFuture);
+        Mockito.when(repo.findCampaignsByUnitId(anyLong())).thenReturn(dbFuture);
 
         RequestOptions reqOpt = new RequestOptions()
                 .setMethod(HttpMethod.GET).setPort(PORT).setHost(HOST).setURI(

+ 33 - 0
testing/update.sql

@@ -0,0 +1,33 @@
+ALTER TABLE maplog.driver RENAME TO maplog.entity;
+ALTER TABLE maplog.entity RENAME COLUMN driver_id TO id;
+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;
+ALTER TABLE maplog.entity_id_seq OWNER TO senslog;
+ALTER SEQUENCE maplog.entity_id_seq OWNED BY maplog.entity.id;
+ALTER TABLE ONLY maplog.entity ALTER COLUMN id SET DEFAULT nextval('maplog.entity_id_seq'::regclass);
+
+ALTER TABLE maplog.driver_to_action RENAME TO event;
+ALTER TABLE maplog.event RENAME COLUMN driver_id TO entity_id;
+
+ALTER TABLE maplog.user_to_campaign RENAME TO user_to_campaign_config;
+ALTER TABLE maplog.user_to_campaign_config RENAME COLUMN user_id TO entity_id;
+ALTER TABLE maplog.user_to_campaign_config ADD COLUMN config JSONB NOT NULL DEFAULT '{}'::JSONB;
+ALTER TABLE ONLY maplog.user_to_campaign_config ADD CONSTRAINT u2c_entityid_fk FOREIGN KEY (entity_id) REFERENCES maplog.entity(id) ON UPDATE CASCADE ON DELETE CASCADE;
+
+CREATE TYPE alert_status AS ENUM ('CREATED', 'INFORMED', 'IN_PROCESS', 'SOLVED', 'DELETED');
+CREATE TABLE maplog.alert (
+    id BIGINT NOT NULL PRIMARY KEY,
+    time_stamp TIMESTAMP WITH TIME ZONE NOT NULL,
+    unit_id BIGINT NOT NULL,
+    message TEXT NOT NULL,
+    status alert_status NOT NULL,
+    time_received TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
+);
+ALTER TABLE maplog.alert OWNER TO senslog;
+CREATE SEQUENCE maplog.alert_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
+ALTER TABLE maplog.alert_id_seq OWNER TO senslog;
+ALTER SEQUENCE maplog.alert_id_seq OWNED BY maplog.alert.id;
+ALTER TABLE ONLY maplog.alert ALTER COLUMN id SET DEFAULT nextval('maplog.alert_id_seq'::regclass);
+
+CREATE INDEX fki_alert_unitid_fk ON maplog.alert USING btree (unit_id);
+ALTER TABLE ONLY maplog.alert ADD CONSTRAINT alert_unitid_fk FOREIGN KEY (unit_id) REFERENCES maplog.unit(unit_id) ON UPDATE CASCADE ON DELETE CASCADE;

Some files were not shown because too many files changed in this diff