diff --git a/app/src/main/java/org/transitclock/api/data/ApiServiceId.java b/app/src/main/java/org/transitclock/api/data/ApiServiceId.java new file mode 100644 index 000000000..b31a3c93e --- /dev/null +++ b/app/src/main/java/org/transitclock/api/data/ApiServiceId.java @@ -0,0 +1,35 @@ +/* (C)2023 */ +package org.transitclock.api.data; + +import jakarta.xml.bind.annotation.XmlAttribute; + +import java.util.List; +import java.util.Map; + +/** + * A short description of a serviceId. For when outputting list of block IDs for service. + * + * @author SkiBu Smith + */ +public class ApiServiceId { + + @XmlAttribute + private String id; + + @XmlAttribute + private List blockIds; + + /********************** Member Functions **************************/ + + /** + * Need a no-arg constructor for Jersey. Otherwise get really obtuse "MessageBodyWriter not + * found for media type=application/json" exception. + */ + protected ApiServiceId() { + } + + public ApiServiceId(String serviceId, List blockIds) { + this.id = serviceId; + this.blockIds = blockIds; + } +} diff --git a/app/src/main/java/org/transitclock/api/data/ApiServiceIds.java b/app/src/main/java/org/transitclock/api/data/ApiServiceIds.java new file mode 100644 index 000000000..72912b8b3 --- /dev/null +++ b/app/src/main/java/org/transitclock/api/data/ApiServiceIds.java @@ -0,0 +1,41 @@ +/* (C)2023 */ +package org.transitclock.api.data; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * For outputting simple list of unsorted service IDs with lists of sorted block IDs + * + * @author SkiBu Smith + */ +@XmlRootElement +public class ApiServiceIds { + + @XmlElement(name= "serviceIds") + private List apiServiceIds; + + /********************** Member Functions **************************/ + + /** + * Need a no-arg constructor for Jersey. Otherwise get really obtuse "MessageBodyWriter not + * found for media type=application/json" exception. + */ + protected ApiServiceIds() { + } + + /** + * Creates the API unsorted version of list of IDs. + * + * @param serviceIds + */ + public ApiServiceIds(Map> serviceIds) { + apiServiceIds = new ArrayList<>(); + serviceIds.forEach((key, list) -> apiServiceIds + .add(new ApiServiceId(key,list))); + } +} diff --git a/app/src/main/java/org/transitclock/api/data/ApiVehicleToBlockConfig.java b/app/src/main/java/org/transitclock/api/data/ApiVehicleToBlockConfig.java index e6f7348c9..9da737b26 100644 --- a/app/src/main/java/org/transitclock/api/data/ApiVehicleToBlockConfig.java +++ b/app/src/main/java/org/transitclock/api/data/ApiVehicleToBlockConfig.java @@ -27,9 +27,9 @@ protected ApiVehicleToBlockConfig() {} * Takes a Vehicle object for client/server communication and constructs a ApiVehicle object for * the API. Sets UiMode to UiMode.NORMAL. * - * @param vTBC + * @param vehicleToBlockConfig */ - public ApiVehicleToBlockConfig(IpcVehicleToBlockConfig vTBC) { - super(vTBC); + public ApiVehicleToBlockConfig(IpcVehicleToBlockConfig vehicleToBlockConfig) { + super(vehicleToBlockConfig); } } diff --git a/app/src/main/java/org/transitclock/api/data/ApiVehicleToBlockConfigAbstract.java b/app/src/main/java/org/transitclock/api/data/ApiVehicleToBlockConfigAbstract.java index 025a43664..77d5b07e3 100644 --- a/app/src/main/java/org/transitclock/api/data/ApiVehicleToBlockConfigAbstract.java +++ b/app/src/main/java/org/transitclock/api/data/ApiVehicleToBlockConfigAbstract.java @@ -50,19 +50,18 @@ public abstract class ApiVehicleToBlockConfigAbstract { protected ApiVehicleToBlockConfigAbstract() {} /** - * Takes a Vehicle object for client/server communication and constructs a ApiVehicle object for + * Takes a VehicleToBlockConfig object for client/server communication and constructs a ApiVehicleToBlockConfig object for * the API. * - * @param vehicle - * @param uiType If should be labeled as "minor" in output for UI. + * @param vehicleToBlockConfig */ - public ApiVehicleToBlockConfigAbstract(IpcVehicleToBlockConfig vTBC) { - id = vTBC.getId(); - vehicleId = vTBC.getVehicleId(); - tripId = vTBC.getTripId(); - blockId = vTBC.getBlockId(); - validFrom = vTBC.getValidFrom(); - validTo = vTBC.getValidTo(); - assignmentDate = vTBC.getAssignmentDate(); + public ApiVehicleToBlockConfigAbstract(IpcVehicleToBlockConfig vehicleToBlockConfig) { + id = vehicleToBlockConfig.getId(); + vehicleId = vehicleToBlockConfig.getVehicleId(); + tripId = vehicleToBlockConfig.getTripId(); + blockId = vehicleToBlockConfig.getBlockId(); + validFrom = vehicleToBlockConfig.getValidFrom(); + validTo = vehicleToBlockConfig.getValidTo(); + assignmentDate = vehicleToBlockConfig.getAssignmentDate(); } } diff --git a/app/src/main/java/org/transitclock/api/data/ApiVehicleToBlockConfigs.java b/app/src/main/java/org/transitclock/api/data/ApiVehicleToBlockConfigs.java index 92821ea7b..2ed3e7ab3 100644 --- a/app/src/main/java/org/transitclock/api/data/ApiVehicleToBlockConfigs.java +++ b/app/src/main/java/org/transitclock/api/data/ApiVehicleToBlockConfigs.java @@ -1,14 +1,13 @@ /* (C)2023 */ package org.transitclock.api.data; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlRootElement; import org.transitclock.service.dto.IpcVehicleToBlockConfig; +import java.util.ArrayList; +import java.util.List; + /** * For when have list of VehicleDetails. By using this class can control the element name when data * is output. @@ -27,23 +26,16 @@ public class ApiVehicleToBlockConfigs { * Need a no-arg constructor for Jersey. Otherwise get really obtuse "MessageBodyWriter not * found for media type=application/json" exception. */ - protected ApiVehicleToBlockConfigs() {} + protected ApiVehicleToBlockConfigs() { + } /** - * For constructing a ApiVehiclesDetails object from a Collection of Vehicle objects. + * For constructing a ApiVehicleToBlockConfigs object from a Collection of VehicleToBlockConfig objects. * * @param vehicles - * @param agencyId - * @param uiTypesForVehicles Specifies how vehicles should be drawn in UI. Can be NORMAL, - * SECONDARY, or MINOR - * @param assigned - * @throws InvocationTargetException - * @throws IllegalAccessException */ - public ApiVehicleToBlockConfigs(Collection vehicles) - throws IllegalAccessException, InvocationTargetException { + public ApiVehicleToBlockConfigs(List vehicles) { vehiclesData = new ArrayList(); - for (IpcVehicleToBlockConfig vehicleToBlock : vehicles) { vehiclesData.add(new ApiVehicleToBlockConfig(vehicleToBlock)); } diff --git a/app/src/main/java/org/transitclock/api/resources/TransitimeApi.java b/app/src/main/java/org/transitclock/api/resources/TransitimeApi.java index 1811cdebe..4b850c86b 100644 --- a/app/src/main/java/org/transitclock/api/resources/TransitimeApi.java +++ b/app/src/main/java/org/transitclock/api/resources/TransitimeApi.java @@ -26,33 +26,7 @@ import jakarta.ws.rs.core.Response; import org.apache.commons.lang3.StringUtils; import org.hibernate.Session; -import org.transitclock.api.data.ApiActiveBlocks; -import org.transitclock.api.data.ApiActiveBlocksRoutes; -import org.transitclock.api.data.ApiAdherenceSummary; -import org.transitclock.api.data.ApiAgencies; -import org.transitclock.api.data.ApiAgency; -import org.transitclock.api.data.ApiBlock; -import org.transitclock.api.data.ApiBlocks; -import org.transitclock.api.data.ApiBlocksTerse; -import org.transitclock.api.data.ApiCalendars; -import org.transitclock.api.data.ApiCurrentServerDate; -import org.transitclock.api.data.ApiDirections; -import org.transitclock.api.data.ApiExportsData; -import org.transitclock.api.data.ApiIds; -import org.transitclock.api.data.ApiPredictions; -import org.transitclock.api.data.ApiRmiServerStatus; -import org.transitclock.api.data.ApiRoutes; -import org.transitclock.api.data.ApiRoutesDetails; -import org.transitclock.api.data.ApiSchedulesHorizStops; -import org.transitclock.api.data.ApiSchedulesVertStops; -import org.transitclock.api.data.ApiServerStatus; -import org.transitclock.api.data.ApiTrip; -import org.transitclock.api.data.ApiTripPatterns; -import org.transitclock.api.data.ApiTripWithTravelTimes; -import org.transitclock.api.data.ApiVehicleConfigs; -import org.transitclock.api.data.ApiVehicleToBlockConfigs; -import org.transitclock.api.data.ApiVehicles; -import org.transitclock.api.data.ApiVehiclesDetails; +import org.transitclock.api.data.*; import org.transitclock.api.utils.PredsByLoc; import org.transitclock.api.utils.StandardParameters; import org.transitclock.api.utils.WebUtils; @@ -76,7 +50,6 @@ import org.transitclock.service.dto.IpcTripPattern; import org.transitclock.service.dto.IpcVehicle; import org.transitclock.service.dto.IpcVehicleConfig; -import org.transitclock.service.dto.IpcVehicleToBlockConfig; import org.transitclock.service.contract.ConfigInterface; import org.transitclock.service.contract.PredictionsInterface; import org.transitclock.service.contract.PredictionsInterface.RouteStop; @@ -196,28 +169,38 @@ public Response getVehicles( @Operation( summary = "Returns data for vehicles assignment for specific block in current day", - description = "Returns data for vehicles assignment for specific block in current day") + description = "Returns data for vehicles assignment for specific block in current day", + tags = {"vehicle", "block"}) @Path("/command/vehiclesToBlock") @GET @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getVehiclesToBlock( @BeanParam StandardParameters stdParameters, - @Parameter(description = "Block id") @QueryParam(value = "blockId") String blockId) + @Parameter(description = "If set 'true', returns only the data with actual time windows.", required = false) + @QueryParam(value = "actual") + boolean isActual, + @Parameter(description = "If set, returns only the data for that block Id.", required = false) + @QueryParam(value = "blockId") + String blockId) throws WebApplicationException { stdParameters.validate(); - Collection result = null; try { // Get Vehicle data from server VehiclesInterface inter = stdParameters.getVehiclesInterface(); - result = inter.getVehicleToBlockConfig(blockId); - - ApiVehicleToBlockConfigs apiVTBC = new ApiVehicleToBlockConfigs(result); + if(isActual){ + var actualConfigs = inter.getActualVehicleToBlockConfigs(); + ApiVehicleToBlockConfigs vehiclesToBlocks = new ApiVehicleToBlockConfigs(actualConfigs); + // return actual ApiVehicleToBlockConfigs response + return stdParameters.createResponse(vehiclesToBlocks); + } + var configs = inter.getVehicleToBlockConfigByBlockId(blockId); - // return ApiVehicles response - return stdParameters.createResponse(apiVTBC); + ApiVehicleToBlockConfigs vehiclesToBlocks = new ApiVehicleToBlockConfigs(configs); + // return ApiVehicleToBlockConfigs response + return stdParameters.createResponse(vehiclesToBlocks); } catch (Exception e) { // If problem getting data then return a Bad Request throw WebUtils.badRequestException(e); @@ -1254,13 +1237,13 @@ public Response getBlocks( @Operation( summary = "Retrives a list of all blockId for the specified service ID", description = "Retrives a list of all blockId for the specified service ID." - + "Every trip is associated with a block.", + + " Every trip is associated with a block.", tags = {"base data", "trip", "block"}) public Response getBlockIds( @BeanParam StandardParameters stdParameters, - @Parameter(description = "if set, returns only the data for that serviceId.", required = false) - @QueryParam(value = "serviceId") - String serviceId) + @Parameter(description = "If set, returns only the data for that serviceId.", required = false) + @QueryParam(value = "serviceId") + String serviceId) throws WebApplicationException { // Make sure request is valid stdParameters.validate(); @@ -2002,16 +1985,24 @@ public Response getAllCalendars(@BeanParam StandardParameters stdParameters) thr @GET @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Operation( - summary = "Retrives all service id.", - description = "Retrives all service id.", + summary = "Retrives all service id. Optionally, retrives all service id with blockIds", + description = "Retrives all service id. Optionally, retrives all service id with blockIds", tags = {"base data", "serviceId"}) - public Response getServiceIds(@BeanParam StandardParameters stdParameters) throws WebApplicationException { + public Response getServiceIds(@BeanParam StandardParameters stdParameters, + @Parameter (description = "If set 'true', returns serviceIds with assigned blockIds", required = false) + @QueryParam(value = "withBlockIds") + boolean withBlockIds) throws WebApplicationException { // Make sure request is valid stdParameters.validate(); try { // Get Vehicle data from server ConfigInterface inter = stdParameters.getConfigInterface(); + // Get service IDs with block Ids + if (withBlockIds) { + ApiServiceIds serviceIdsWithBlockIds = new ApiServiceIds(inter.getServiceIdsWithBlockIds()); + return stdParameters.createResponse(serviceIdsWithBlockIds); + } List ids = inter.getServiceIds(); ApiIds apiIds = new ApiIds(ids); diff --git a/core/pom.xml b/core/pom.xml index fbcba4492..e2b64fc9d 100755 --- a/core/pom.xml +++ b/core/pom.xml @@ -207,6 +207,11 @@ com.fasterxml.jackson.module jackson-module-jakarta-xmlbind-annotations + + pl.goeuropa + traccar-client + ${revision} + diff --git a/core/src/main/java/org/transitclock/config/data/TraccarConfig.java b/core/src/main/java/org/transitclock/config/data/TraccarConfig.java new file mode 100644 index 000000000..1250712d9 --- /dev/null +++ b/core/src/main/java/org/transitclock/config/data/TraccarConfig.java @@ -0,0 +1,25 @@ +/* (C)2023 */ +package org.transitclock.config.data; + +import org.transitclock.config.StringConfigValue; + + +public class TraccarConfig { + /** + * Traccar properties for log in by "TraccarAVLModule" + * + * @return + */ + public static final StringConfigValue TRACCAREMAIL = new StringConfigValue("transitclock.avl.traccar.email", null, + "This is the username for the traccar server api."); + + public static final StringConfigValue TRACCARPASSWORD = new StringConfigValue("transitclock.avl.traccar.password", + null, "This is the password for the traccar server api"); + + public static final StringConfigValue TRACCARBASEURL = new StringConfigValue("transitclock.avl.traccar.baseurl", + null, "This is the url for the traccar server api."); + + public static final StringConfigValue TRACCARSOURCE = new StringConfigValue("transitclock.avl.traccar.source", + "TRACCAR", "This is the value recorded in the source for the AVL Report."); + +} diff --git a/core/src/main/java/org/transitclock/core/AvlProcessor.java b/core/src/main/java/org/transitclock/core/AvlProcessor.java index bd8b10c74..b1e172e03 100644 --- a/core/src/main/java/org/transitclock/core/AvlProcessor.java +++ b/core/src/main/java/org/transitclock/core/AvlProcessor.java @@ -1386,12 +1386,12 @@ public void processAvlReport(AvlReport avlReport) { } try (Session session = HibernateUtils.getSession()) { String blockId = null; - for (VehicleToBlockConfig vTBC : + for (VehicleToBlockConfig vehicleToBlock : VehicleToBlockConfig.getVehicleToBlockConfigsByVehicleId(session, avlReport.getVehicleId())) { Date d = new Date(); - if (d.after(vTBC.getValidFrom()) && d.before(vTBC.getValidTo())) { - blockId = vTBC.getBlockId(); + if (d.after(vehicleToBlock.getValidFrom()) && d.before(vehicleToBlock.getValidTo())) { + blockId = vehicleToBlock.getBlockId(); break; } } diff --git a/core/src/main/java/org/transitclock/core/avl/TraccarAVLModule.java b/core/src/main/java/org/transitclock/core/avl/TraccarAVLModule.java new file mode 100644 index 000000000..5afb5bbd5 --- /dev/null +++ b/core/src/main/java/org/transitclock/core/avl/TraccarAVLModule.java @@ -0,0 +1,144 @@ +/* + * This file is part of thetransitclock.org + * + * thetransitclock.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License (GPL) as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * thetransitclock.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with thetransitclock.org . If not, see . + */ +package org.transitclock.core.avl; + +import java.io.InputStream; +import java.math.BigDecimal; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import org.transitclock.domain.structs.AvlReport; +import org.transitclock.extension.traccar.ApiClient; +import org.transitclock.extension.traccar.ApiException; +import org.transitclock.extension.traccar.api.DefaultApi; +import org.transitclock.extension.traccar.model.DeviceDto; +import org.transitclock.extension.traccar.model.PositionDto; +import org.transitclock.extension.traccar.model.UserDto; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.apache.hc.client5.http.auth.AuthCache; +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.impl.auth.BasicAuthCache; +import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +import org.apache.hc.client5.http.impl.auth.BasicScheme; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.core5.http.HttpHost; + +import static org.transitclock.config.data.TraccarConfig.TRACCARBASEURL; +import static org.transitclock.config.data.TraccarConfig.TRACCAREMAIL; +import static org.transitclock.config.data.TraccarConfig.TRACCARPASSWORD; +import static org.transitclock.config.data.TraccarConfig.TRACCARSOURCE; + + +/** + * @author Sean Óg Crudden This module integrates TheTransitClock with the API of a traccar + * server to get vehicle locations. + *

+ * See http://www.traccar.org + *

+ * It uses classes that where generated using the swagger file provided + * with traccar. + */ +@Slf4j +public class TraccarAVLModule extends PollUrlAvlModule { + @NonNull + private final DefaultApi api; + @NonNull + private final UserDto user; + + public TraccarAVLModule(String agencyId) throws URISyntaxException { + super(agencyId); + useCompression = false; + + var host = HttpHost.create(TRACCARBASEURL.getValue()); + var httpClientBuilder = HttpClientBuilder.create(); + + final AuthCache authCache = new BasicAuthCache(); + authCache.put(host, new BasicScheme()); + + var provider = new BasicCredentialsProvider(); + provider.setCredentials(new AuthScope(host), new UsernamePasswordCredentials(TRACCAREMAIL.getValue(), TRACCARPASSWORD.getValue().toCharArray())); + httpClientBuilder.setDefaultCredentialsProvider(provider); + + ApiClient client = new ApiClient(httpClientBuilder.build()); + client.setBasePath(TRACCARBASEURL.getValue()); + client.setUsername(TRACCARPASSWORD.getValue()); + client.setPassword(TRACCARPASSWORD.getValue()); + this.api = new DefaultApi(client); + + try { + this.user = this.api + .sessionPost(TRACCAREMAIL.getValue(), TRACCARPASSWORD.getValue()); + } catch (ApiException e) { + throw new RuntimeException("Traccar login denied", e); + } + } + + @Override + protected void getAndProcessData() throws Exception { + + Collection avlReportsReadIn = new ArrayList<>(); + + List devices = api.devicesGet(true, user.getId(), null, null); + + List results = api.positionsGet(null, null, null, null); + for (PositionDto result : results) { + DeviceDto device = findDeviceById(devices, result.getDeviceId()); + + AvlReport avlReport; + + // If have device details use name. + if (device != null && device.getUniqueId() != null && !device.getUniqueId().isEmpty()) { + //Traccar return speed in kt + avlReport = new AvlReport(device.getUniqueId(), device.getName(), + result.getDeviceTime().toEpochSecond(), result.getLatitude().doubleValue(), + result.getLongitude().doubleValue(), result.getSpeed().multiply(BigDecimal.valueOf(0.5144444)).floatValue(), result.getCourse().floatValue(), TRACCARSOURCE.toString()); + } else { + avlReport = new AvlReport(result.getDeviceId().toString(), + result.getDeviceTime().toEpochSecond(), result.getLatitude().doubleValue(), + result.getLongitude().doubleValue(), result.getSpeed().multiply(BigDecimal.valueOf(0.5144444)).floatValue(), result.getCourse().floatValue(), TRACCARSOURCE.toString()); + } + avlReportsReadIn.add(avlReport); + } + forwardAvlReports(avlReportsReadIn); + } + + protected void forwardAvlReports(Collection avlReportsReadIn) { + processAvlReports(avlReportsReadIn); + } + + private DeviceDto findDeviceById(List devices, Integer id) { + for (DeviceDto device : devices) { + if (Objects.equals(device.getId(), id)) { + return device; + } + } + return null; + } + + @Override + protected Collection processData(InputStream in) throws Exception { + // Auto-generated method stub + return null; + } + +} diff --git a/core/src/main/java/org/transitclock/domain/structs/AvlReport.java b/core/src/main/java/org/transitclock/domain/structs/AvlReport.java index c74bc6e5e..78dbeb518 100644 --- a/core/src/main/java/org/transitclock/domain/structs/AvlReport.java +++ b/core/src/main/java/org/transitclock/domain/structs/AvlReport.java @@ -199,6 +199,31 @@ protected AvlReport() { * if speed not available * @param source Text describing the source of the report */ + + public AvlReport(String vehicleId, String vehicleName, long time, double lat, double lon, float speed, float heading, String source) { + // Store the values + this.vehicleId = vehicleId; + this.time = new Date(time); + this.location = new Location(lat, lon); + // DB requires null instead of NaN + this.speed = Float.isNaN(speed) ? null : speed; + this.heading = Float.isNaN(heading) ? null : heading; + this.source = sized(source); + this.assignmentId = null; + this.assignmentType = AssignmentType.UNSET; + this.leadVehicleId = null; + this.driverId = null; + this.licensePlate = null; + this.passengerCount = null; + this.passengerFullness = null; + this.field1Name = null; + this.field1Value = null; + this.vehicleName = vehicleName; + + // Don't yet know when processed so set timeProcessed to null + this.timeProcessed = null; + } + public AvlReport(String vehicleId, long time, double lat, double lon, float speed, float heading, String source) { // Store the values this.vehicleId = vehicleId; diff --git a/core/src/main/java/org/transitclock/domain/structs/VehicleToBlockConfig.java b/core/src/main/java/org/transitclock/domain/structs/VehicleToBlockConfig.java index bc0a81a51..3fa36508e 100644 --- a/core/src/main/java/org/transitclock/domain/structs/VehicleToBlockConfig.java +++ b/core/src/main/java/org/transitclock/domain/structs/VehicleToBlockConfig.java @@ -2,17 +2,17 @@ package org.transitclock.domain.structs; import jakarta.persistence.*; -import java.io.Serializable; -import java.util.Date; -import java.util.List; - -import lombok.*; +import lombok.Data; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.annotations.DynamicUpdate; import org.transitclock.Core; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + /** * For storing static configuration for vehicle in block. * @@ -64,7 +64,7 @@ public VehicleToBlockConfig( /** * @param vehicleId vehicle ID * @param blockId block ID * @param tripId trip ID * @param - * assignmentDate time * * @param validFrom time * * @param validTo time + * assignmentDate time * * @param validFrom time * * @param validTo time */ public static VehicleToBlockConfig create( String vehicleId, String blockId, String tripId, Date assignmentDate, Date validFrom, Date validTo) { @@ -78,7 +78,9 @@ public static VehicleToBlockConfig create( return vehicleToBlockConfig; } - /** Needed because Hibernate requires no-arg constructor */ + /** + * Needed because Hibernate requires no-arg constructor + */ @SuppressWarnings("unused") protected VehicleToBlockConfig() { vehicleId = null; @@ -128,6 +130,12 @@ public static void deleteVehicleToBlockConfig(long id, Session session) throws H } } + public static List getActualVehicleToBlockConfigs(Session session) throws HibernateException { + return session + .createQuery("FROM VehicleToBlockConfig WHERE validTo > now() ORDER BY assignmentDate DESC", VehicleToBlockConfig.class) + .list(); + } + public static List getVehicleToBlockConfigsByBlockId(Session session, String blockId) throws HibernateException { return session .createQuery("FROM VehicleToBlockConfig WHERE blockId = :blockId ORDER BY assignmentDate DESC", VehicleToBlockConfig.class) diff --git a/core/src/main/java/org/transitclock/gtfs/DbConfig.java b/core/src/main/java/org/transitclock/gtfs/DbConfig.java index 15f1ca20d..b5a6d5d1d 100644 --- a/core/src/main/java/org/transitclock/gtfs/DbConfig.java +++ b/core/src/main/java/org/transitclock/gtfs/DbConfig.java @@ -14,8 +14,6 @@ import lombok.extern.slf4j.Slf4j; import org.hibernate.HibernateException; import org.hibernate.Session; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.transitclock.Core; import org.transitclock.core.ServiceUtils; import org.transitclock.domain.hibernate.HibernateUtils; @@ -31,10 +29,7 @@ import org.transitclock.domain.structs.Transfer; import org.transitclock.domain.structs.Trip; import org.transitclock.domain.structs.TripPattern; -import org.transitclock.utils.IntervalTimer; -import org.transitclock.utils.MapKey; -import org.transitclock.utils.SystemTime; -import org.transitclock.utils.Time; +import org.transitclock.utils.*; /** * Reads all the configuration data from the database. The data is based on GTFS but is heavily @@ -686,6 +681,23 @@ public int getBlockCount() { return blockCount; } + /** + * Returns sorted lists of block IDs what belong to all service IDs + * + * @return Map of all service IDs with belong to block IDs + */ + public Map> getBlockIdsForAllServiceIds() { + Map> serviceIdsWithBlocks = new HashMap<>(); + + blocksByServiceMap.forEach((key, element) -> { + List ids = new ArrayList<>(); + element.forEach((innerKey, block) -> ids.add(block.getId())); + StringUtils.sortIdsNumerically(ids); + serviceIdsWithBlocks.put(key, ids); + }); + return serviceIdsWithBlocks; + } + /** * Returns blocks for the specified blockId for all service IDs. * diff --git a/core/src/main/java/org/transitclock/service/ConfigServiceImpl.java b/core/src/main/java/org/transitclock/service/ConfigServiceImpl.java index acc05666e..79abb0cd0 100644 --- a/core/src/main/java/org/transitclock/service/ConfigServiceImpl.java +++ b/core/src/main/java/org/transitclock/service/ConfigServiceImpl.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; /** @@ -360,4 +361,14 @@ public List getBlockIds(String serviceId) { .distinct() .collect(Collectors.toList()); } + + /* (non-Javadoc) + * @see org.transitclock.ipc.interfaces.ConfigInterface#getBlockIds() + */ + @Override + public Map> getServiceIdsWithBlockIds() { + return Core.getInstance() + .getDbConfig() + .getBlockIdsForAllServiceIds(); + } } diff --git a/core/src/main/java/org/transitclock/service/VehiclesServiceImpl.java b/core/src/main/java/org/transitclock/service/VehiclesServiceImpl.java index f622e9566..a152a29cc 100644 --- a/core/src/main/java/org/transitclock/service/VehiclesServiceImpl.java +++ b/core/src/main/java/org/transitclock/service/VehiclesServiceImpl.java @@ -3,29 +3,21 @@ import com.querydsl.jpa.impl.JPAQuery; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.hibernate.Session; import org.transitclock.core.BlocksInfo; import org.transitclock.core.dataCache.VehicleDataCache; import org.transitclock.domain.hibernate.HibernateUtils; -import org.transitclock.domain.structs.Block; -import org.transitclock.domain.structs.QRoute; -import org.transitclock.domain.structs.Trip; -import org.transitclock.domain.structs.VehicleConfig; -import org.transitclock.domain.structs.VehicleToBlockConfig; +import org.transitclock.domain.structs.*; import org.transitclock.service.contract.VehiclesInterface; -import org.transitclock.service.dto.IpcActiveBlock; -import org.transitclock.service.dto.IpcBlock; -import org.transitclock.service.dto.IpcVehicle; -import org.transitclock.service.dto.IpcVehicleComplete; -import org.transitclock.service.dto.IpcVehicleConfig; -import org.transitclock.service.dto.IpcVehicleGtfsRealtime; -import org.transitclock.service.dto.IpcVehicleToBlockConfig; +import org.transitclock.service.dto.*; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.stream.Collectors; /** * Implements the VehiclesInterface interface on the server side such that a VehiclessClient can @@ -396,30 +388,48 @@ public Collection getVehiclesForBlocks() { } @Override - public Collection getVehicleToBlockConfig(String blockId) { + public List getActualVehicleToBlockConfigs() { List result = new ArrayList<>(); - try (Session session = HibernateUtils.getSession()){ - for (VehicleToBlockConfig vTBC : VehicleToBlockConfig.getVehicleToBlockConfigsByBlockId(session, blockId)) { - result.add(new IpcVehicleToBlockConfig(vTBC)); + try (Session session = HibernateUtils.getSession()) { + for (VehicleToBlockConfig vehicleToBlockConfig : VehicleToBlockConfig + .getActualVehicleToBlockConfigs(session)) { + result.add(new IpcVehicleToBlockConfig(vehicleToBlockConfig)); } } catch (Exception ex) { - logger.error("Something happened while fetching the VehicleToBlockConfig.", ex); + logger.error("Something happened while fetching the data: ", ex); } return result; } @Override - public Collection getVehicleToBlockConfigByVehicleId(String vehicleId) { - List result = new ArrayList<>(); - Session session = HibernateUtils.getSession(); - try { - for (var vTBC : VehicleToBlockConfig.getVehicleToBlockConfigsByVehicleId(session, vehicleId)) { - result.add(new IpcVehicleToBlockConfig(vTBC)); + public List getVehicleToBlockConfigByBlockId(String blockId) { + try (Session session = HibernateUtils.getSession()) { + if (StringUtils.isEmpty(blockId)) { + return VehicleToBlockConfig.getVehicleToBlockConfigsByBlockId(session, blockId) + .stream() + .map(IpcVehicleToBlockConfig::new) + .collect(Collectors.toList()); } - session.close(); + return VehicleToBlockConfig.getVehicleToBlockConfigs(session) + .stream() + .map(IpcVehicleToBlockConfig::new) + .collect(Collectors.toList()); } catch (Exception ex) { - session.close(); + logger.error("Something happened while fetching the data.", ex); } - return result; + return List.of(); + } + + @Override + public List getVehicleToBlockConfigByVehicleId(String vehicleId) { + try (Session session = HibernateUtils.getSession()) { + return VehicleToBlockConfig.getVehicleToBlockConfigsByVehicleId(session, vehicleId) + .stream() + .map(IpcVehicleToBlockConfig::new) + .collect(Collectors.toList()); + } catch (Exception ex) { + logger.error("Something happened while fetching the data.", ex); + } + return List.of(); } } diff --git a/core/src/main/java/org/transitclock/service/contract/ConfigInterface.java b/core/src/main/java/org/transitclock/service/contract/ConfigInterface.java index 0be18333b..d8e59e759 100644 --- a/core/src/main/java/org/transitclock/service/contract/ConfigInterface.java +++ b/core/src/main/java/org/transitclock/service/contract/ConfigInterface.java @@ -13,6 +13,7 @@ import java.util.Collection; import java.util.List; +import java.util.Map; /** * Defines the RMI interface for getting configuration data. @@ -51,7 +52,7 @@ IpcRoute getRoute(String routeIdOrShortName, String directionId, String stopId, /** * Obtains ordered list of route details * - * @param routeIdOrShortName + * @param routeIdsOrShortNames * @return */ List getRoutes(List routeIdsOrShortNames); @@ -174,4 +175,11 @@ IpcRoute getRoute(String routeIdOrShortName, String directionId, String stopId, * @return vehicle IDs */ List getBlockIds(String serviceId); + + /** + * Returns sorted lists of block IDs what belong to all service IDs + * + * @return Map of service IDs with belong block IDs + */ + Map> getServiceIdsWithBlockIds(); } diff --git a/core/src/main/java/org/transitclock/service/contract/VehiclesInterface.java b/core/src/main/java/org/transitclock/service/contract/VehiclesInterface.java index 8b308fee9..278d95c16 100644 --- a/core/src/main/java/org/transitclock/service/contract/VehiclesInterface.java +++ b/core/src/main/java/org/transitclock/service/contract/VehiclesInterface.java @@ -9,6 +9,7 @@ import org.transitclock.service.dto.IpcVehicleToBlockConfig; import java.util.Collection; +import java.util.List; /** * Defines the RMI interface used for obtaining vehicle information. @@ -174,7 +175,14 @@ Collection getActiveBlocks(Collection routeIds, int allo */ int getNumActiveBlocks(Collection routeIds, int allowableBeforeTimeSecs); - Collection getVehicleToBlockConfig(String blockId); + /** + * Gets from the server the List of VehicleToBlocksConfig that are currently active. + * + * @return Collection of VehicleToBlocksConfig that are active. + */ + List getActualVehicleToBlockConfigs(); + + List getVehicleToBlockConfigByBlockId(String blockId); - Collection getVehicleToBlockConfigByVehicleId(String vehicleId); + List getVehicleToBlockConfigByVehicleId(String vehicleId); } diff --git a/extensions/pom.xml b/extensions/pom.xml index 19546110e..70acacd81 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -13,6 +13,7 @@ ${revision} + traccar api diff --git a/extensions/traccar/pom.xml b/extensions/traccar/pom.xml new file mode 100644 index 000000000..84d9605e3 --- /dev/null +++ b/extensions/traccar/pom.xml @@ -0,0 +1,81 @@ + + 4.0.0 + + + ro.vladvesa.transitclock + extensions + ${revision} + + + + pl.goeuropa + traccar-client + ${revision} + + + + + org.openapitools + openapi-generator-maven-plugin + 7.4.0 + + + + generate + + + ${project.basedir}/src/main/resources/swagger.json + org.transitclock.extension.traccar.api + org.transitclock.extension.traccar + java + true + false + org.transitclock.extension.traccar.model + Dto + + apache-httpclient + true + java8 + false + + + + + + + + + + org.openapitools + jackson-databind-nullable + 0.2.6 + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + + + jakarta.annotation + jakarta.annotation-api + 2.1.1 + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + org.apache.httpcomponents.client5 + httpclient5 + 5.2.3 + + + diff --git a/extensions/traccar/src/main/resources/swagger.json b/extensions/traccar/src/main/resources/swagger.json new file mode 100644 index 000000000..fc077d3c9 --- /dev/null +++ b/extensions/traccar/src/main/resources/swagger.json @@ -0,0 +1,2278 @@ +{ + "swagger": "2.0", + "info": { + "version": "4.8", + "title": "traccar" + }, + "host": "demo.traccar.org", + "basePath": "/api", + "schemes": [ + "http" + ], + "security": [ + { + "basicAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/commands": { + "get": { + "summary": "Fetch a list of Saved Commands", + "description": "Without params, it returns a list of Drivers the user has access to", + "parameters": [ + { + "$ref": "#/parameters/all" + }, + { + "$ref": "#/parameters/userId" + }, + { + "$ref": "#/parameters/deviceId" + }, + { + "$ref": "#/parameters/groupId" + }, + { + "$ref": "#/parameters/refresh" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Command" + } + } + } + } + }, + "post": { + "summary": "Create a Saved Command", + "parameters": [ + { + "$ref": "#/parameters/Command" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Command" + } + } + } + } + }, + "/commands/{id}": { + "put": { + "summary": "Update a Saved Command", + "parameters": [ + { + "$ref": "#/parameters/entityId" + }, + { + "$ref": "#/parameters/Command" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Command" + } + } + } + }, + "delete": { + "summary": "Delete a Saved Command", + "parameters": [ + { + "$ref": "#/parameters/entityId" + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/commands/send": { + "get": { + "summary": "Fetch a list of Saved Commands supported by Device at the moment", + "description": "Return a list of saved commands linked to Device and its groups, filtered by current Device protocol support", + "parameters": [ + { + "$ref": "#/parameters/deviceId" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Command" + } + } + }, + "400": { + "description": "Could happen when the user doesn't have permission for the device" + } + } + }, + "post": { + "summary": "Dispatch commands to device", + "description": "Dispatch a new command or Saved Command if _body.id_ set", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Command" + } + } + ], + "responses": { + "200": { + "description": "Command sent", + "schema": { + "$ref": "#/definitions/Command" + } + }, + "202": { + "description": "Command queued", + "schema": { + "$ref": "#/definitions/Command" + } + }, + "400": { + "description": "Could happen when the user doesn't have permission or an incorrect command _type_ for the device" + } + } + } + }, + "/commands/types": { + "get": { + "summary": "Fetch a list of available Commands for the Device or all possible Commands if Device ommited", + "parameters": [ + { + "name": "deviceId", + "in": "query", + "description" : "Internal device identifier. Only works if device has already reported some locations", + "required" : false, + "type": "integer" + }, + { + "name": "protocol", + "in": "query", + "description" : "Protocol name. Can be used instead of device id", + "required" : false, + "type": "string" + }, + { + "name": "textChannel", + "in": "query", + "description" : "When `true` return SMS commands. If not specified or `false` return data commands", + "required" : false, + "type": "boolean" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/CommandType" + } + } + }, + "400": { + "description": "Could happen when trying to fetch from a device the user does not have permission" + } + } + } + }, + "/devices": { + "get": { + "summary": "Fetch a list of Devices", + "description": "Without any params, returns a list of the user's devices", + "parameters": [ + { + "$ref": "#/parameters/all" + }, + { + "$ref": "#/parameters/userId" + }, + { + "name" : "id", + "in" : "query", + "description" : "To fetch one or more devices. Multiple params can be passed like `id=31&id=42`", + "required" : false, + "type" : "integer", + "collectionFormat" : "multi" + }, + { + "name" : "uniqueId", + "in" : "query", + "description" : "To fetch one or more devices. Multiple params can be passed like `uniqueId=333331&uniqieId=44442`", + "required" : false, + "type" : "string", + "collectionFormat" : "multi" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + } + }, + "400": { + "description": "No permission" + } + } + }, + "post": { + "summary": "Create a Device", + "parameters": [ + { + "$ref": "#/parameters/Device" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Device" + } + } + } + } + }, + "/devices/{id}": { + "put": { + "summary": "Update a Device", + "parameters": [ + { + "$ref": "#/parameters/entityId" + }, + { + "$ref": "#/parameters/Device" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Device" + } + } + } + }, + "delete": { + "summary": "Delete a Device", + "parameters": [ + { + "$ref": "#/parameters/entityId" + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/devices/{id}/accumulators": { + "put": { + "summary": "Update total distance and hours of the Device", + "parameters": [ + { + "$ref": "#/parameters/entityId" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/DeviceAccumulators" + } + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/groups": { + "get": { + "summary": "Fetch a list of Groups", + "description": "Without any params, returns a list of the Groups the user belongs to", + "parameters": [ + { + "$ref": "#/parameters/all" + }, + { + "$ref": "#/parameters/userId" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Group" + } + } + } + } + }, + "post": { + "summary": "Create a Group", + "parameters": [ + { + "$ref": "#/parameters/Group" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Group" + } + }, + "400": { + "description": "No permission" + } + } + } + }, + "/groups/{id}": { + "put": { + "summary": "Update a Group", + "parameters": [ + { + "$ref": "#/parameters/entityId" + }, + { + "$ref": "#/parameters/Group" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Group" + } + } + } + }, + "delete": { + "summary": "Delete a Group", + "parameters": [ + { + "$ref": "#/parameters/entityId" + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/permissions": { + "post": { + "summary": "Link an Object to another Object", + "parameters": [ + { + "$ref": "#/parameters/Permission" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Permission" + } + }, + "400": { + "description": "No permission" + } + } + }, + "delete": { + "summary": "Unlink an Object from another Object", + "parameters": [ + { + "$ref": "#/parameters/Permission" + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/positions": { + "get": { + "summary" : "Fetches a list of Positions", + "description" : "Without any params, it returns a list of last known positions for all the user's Devices. _from_ and _to_ fields are not required with _id_", + "consumes": [ + "application/json", + "text/csv", + "application/gpx+xml" + ], + "produces": [ + "application/json", + "text/csv", + "application/gpx+xml" + ], + "parameters": [ + { + "name": "deviceId", + "in": "query", + "description": "_deviceId_ is optional, but requires the _from_ and _to_ parameters when used", + "required": false, + "type": "integer" + }, + { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": false, + "type": "string", + "format": "date-time" + }, + { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": false, + "type": "string", + "format": "date-time" + }, + { + "name" : "id", + "in" : "query", + "description" : "To fetch one or more positions. Multiple params can be passed like `id=31&id=42`", + "required" : false, + "type" : "integer", + "collectionFormat" : "multi" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Position" + } + } + } + } + } + }, + "/server": { + "get": { + "summary": "Fetch Server information", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Server" + } + } + } + }, + "put": { + "summary": "Update Server information", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Server" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Server" + } + } + } + } + }, + "/session": { + "get": { + "summary": "Fetch Session information", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "parameters": [ + { + "name": "token", + "in": "query", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/User" + } + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Create a new Session", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "parameters": [ + { + "name": "email", + "in": "formData", + "required": true, + "type": "string" + }, + { + "name": "password", + "in": "formData", + "required": true, + "type": "string", + "format": "password" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/User" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "delete": { + "summary": "Close the Session", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "parameters": [], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/users": { + "get": { + "summary": "Fetch a list of Users", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "Can only be used by admin or manager users", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/User" + } + } + }, + "400": { + "description": "No Permission" + } + } + }, + "post": { + "summary": "Create a User", + "parameters": [ + { + "$ref": "#/parameters/User" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/User" + } + } + } + } + }, + "/users/{id}": { + "put": { + "summary": "Update a User", + "parameters": [ + { + "$ref": "#/parameters/entityId" + }, + { + "$ref": "#/parameters/User" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/User" + } + } + } + }, + "delete": { + "summary": "Delete a User", + "parameters": [ + { + "$ref": "#/parameters/entityId" + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/notifications": { + "get": { + "summary": "Fetch a list of Notifications", + "description": "Without params, it returns a list of Notifications the user has access to", + "parameters": [ + { + "$ref": "#/parameters/all" + }, + { + "$ref": "#/parameters/userId" + }, + { + "$ref": "#/parameters/deviceId" + }, + { + "$ref": "#/parameters/groupId" + }, + { + "$ref": "#/parameters/refresh" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Notification" + } + } + } + } + }, + "post": { + "summary": "Create a Notification", + "parameters": [ + { + "$ref": "#/parameters/Notification" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Notification" + } + } + } + } + }, + "/notifications/{id}": { + "put": { + "summary": "Update a Notification", + "parameters": [ + { + "$ref": "#/parameters/entityId" + }, + { + "$ref": "#/parameters/Notification" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Notification" + } + } + } + }, + "delete": { + "summary": "Delete a Notification", + "parameters": [ + { + "$ref": "#/parameters/entityId" + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/notifications/types": { + "get": { + "summary": "Fetch a list of available Notification types", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/NotificationType" + } + } + } + } + } + }, + "/notifications/test": { + "post": { + "summary": "Send test notification to current user via Email and SMS", + "parameters": [], + "responses": { + "204": { + "description": "Successful sending" + }, + "400": { + "description": "Could happen if sending has failed" + } + } + } + }, + "/geofences": { + "get": { + "summary": "Fetch a list of Geofences", + "description": "Without params, it returns a list of Geofences the user has access to", + "parameters": [ + { + "$ref": "#/parameters/all" + }, + { + "$ref": "#/parameters/userId" + }, + { + "$ref": "#/parameters/deviceId" + }, + { + "$ref": "#/parameters/groupId" + }, + { + "$ref": "#/parameters/refresh" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Geofence" + } + } + } + } + }, + "post": { + "summary": "Create a Geofence", + "parameters": [ + { + "$ref": "#/parameters/Geofence" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Geofence" + } + } + } + } + }, + "/geofences/{id}": { + "put": { + "summary": "Update a Geofence", + "parameters": [ + { + "$ref": "#/parameters/entityId" + }, + { + "$ref": "#/parameters/Geofence" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Geofence" + } + } + } + }, + "delete": { + "summary": "Delete a Geofence", + "parameters": [ + { + "$ref": "#/parameters/entityId" + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/events/{id}": { + "get": { + "parameters": [ + { + "$ref": "#/parameters/entityId" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Event" + } + } + } + } + }, + "/reports/route": { + "get": { + "summary": "Fetch a list of Positions within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "consumes": [ + "application/json", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ], + "produces": [ + "application/json", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ], + "parameters": [ + { + "$ref": "#/parameters/deviceIdArray" + }, + { + "$ref": "#/parameters/groupIdArray" + }, + { + "$ref": "#/parameters/fromTime" + }, + { + "$ref": "#/parameters/toTime" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Position" + } + } + } + } + } + }, + "/reports/events": { + "get": { + "summary": "Fetch a list of Events within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "consumes": [ + "application/json", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ], + "produces": [ + "application/json", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ], + "parameters": [ + { + "$ref": "#/parameters/deviceIdArray" + }, + { + "$ref": "#/parameters/groupIdArray" + }, + { + "name": "type", + "in": "query", + "description": "% can be used to return events of all types", + "type": "array", + "items": { + "type": "string" + } + }, + { + "$ref": "#/parameters/fromTime" + }, + { + "$ref": "#/parameters/toTime" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Event" + } + } + } + } + } + }, + "/reports/summary": { + "get": { + "summary": "Fetch a list of ReportSummary within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "consumes": [ + "application/json", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ], + "produces": [ + "application/json", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ], + "parameters": [ + { + "$ref": "#/parameters/deviceIdArray" + }, + { + "$ref": "#/parameters/groupIdArray" + }, + { + "$ref": "#/parameters/fromTime" + }, + { + "$ref": "#/parameters/toTime" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ReportSummary" + } + } + } + } + } + }, + "/reports/trips": { + "get": { + "summary": "Fetch a list of ReportTrips within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "consumes": [ + "application/json", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ], + "produces": [ + "application/json", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ], + "parameters": [ + { + "$ref": "#/parameters/deviceIdArray" + }, + { + "$ref": "#/parameters/groupIdArray" + }, + { + "$ref": "#/parameters/fromTime" + }, + { + "$ref": "#/parameters/toTime" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ReportTrips" + } + } + } + } + } + }, + "/reports/stops": { + "get": { + "summary": "Fetch a list of ReportStops within the time period for the Devices or Groups", + "description": "At least one _deviceId_ or one _groupId_ must be passed", + "consumes": [ + "application/json", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ], + "produces": [ + "application/json", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ], + "parameters": [ + { + "$ref": "#/parameters/deviceIdArray" + }, + { + "$ref": "#/parameters/groupIdArray" + }, + { + "$ref": "#/parameters/fromTime" + }, + { + "$ref": "#/parameters/toTime" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ReportStops" + } + } + } + } + } + }, + "/statistics": { + "get": { + "summary": "Fetch server Statistics", + "parameters": [ + { + "$ref": "#/parameters/fromTime" + }, + { + "$ref": "#/parameters/toTime" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Statistics" + } + } + } + } + } + }, + "/calendars": { + "get": { + "summary": "Fetch a list of Calendars", + "description": "Without params, it returns a list of Calendars the user has access to", + "parameters": [ + { + "$ref": "#/parameters/all" + }, + { + "$ref": "#/parameters/userId" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Calendar" + } + } + } + } + }, + "post": { + "summary": "Create a Calendar", + "parameters": [ + { + "$ref": "#/parameters/Calendar" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Calendar" + } + } + } + } + }, + "/calendars/{id}": { + "put": { + "summary": "Update a Calendar", + "parameters": [ + { + "$ref": "#/parameters/entityId" + }, + { + "$ref": "#/parameters/Calendar" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Calendar" + } + } + } + }, + "delete": { + "summary": "Delete a Calendar", + "parameters": [ + { + "$ref": "#/parameters/entityId" + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/attributes/computed": { + "get": { + "summary": "Fetch a list of Attributes", + "description": "Without params, it returns a list of Attributes the user has access to", + "parameters": [ + { + "$ref": "#/parameters/all" + }, + { + "$ref": "#/parameters/userId" + }, + { + "$ref": "#/parameters/deviceId" + }, + { + "$ref": "#/parameters/groupId" + }, + { + "$ref": "#/parameters/refresh" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Attribute" + } + } + } + } + }, + "post": { + "summary": "Create an Attribute", + "parameters": [ + { + "$ref": "#/parameters/Attribute" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Attribute" + } + } + } + } + }, + "/attributes/computed/{id}": { + "put": { + "summary": "Update an Attribute", + "parameters": [ + { + "$ref": "#/parameters/entityId" + }, + { + "$ref": "#/parameters/Attribute" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Attribute" + } + } + } + }, + "delete": { + "summary": "Delete an Attribute", + "parameters": [ + { + "$ref": "#/parameters/entityId" + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/drivers": { + "get": { + "summary": "Fetch a list of Drivers", + "description": "Without params, it returns a list of Drivers the user has access to", + "parameters": [ + { + "$ref": "#/parameters/all" + }, + { + "$ref": "#/parameters/userId" + }, + { + "$ref": "#/parameters/deviceId" + }, + { + "$ref": "#/parameters/groupId" + }, + { + "$ref": "#/parameters/refresh" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Driver" + } + } + } + } + }, + "post": { + "summary": "Create a Driver", + "parameters": [ + { + "$ref": "#/parameters/Driver" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Driver" + } + } + } + } + }, + "/drivers/{id}": { + "put": { + "summary": "Update a Driver", + "parameters": [ + { + "$ref": "#/parameters/entityId" + }, + { + "$ref": "#/parameters/Driver" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Driver" + } + } + } + }, + "delete": { + "summary": "Delete a Driver", + "parameters": [ + { + "$ref": "#/parameters/entityId" + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/maintenance": { + "get": { + "summary": "Fetch a list of Maintenance", + "description": "Without params, it returns a list of Maintenance the user has access to", + "parameters": [ + { + "$ref": "#/parameters/all" + }, + { + "$ref": "#/parameters/userId" + }, + { + "$ref": "#/parameters/deviceId" + }, + { + "$ref": "#/parameters/groupId" + }, + { + "$ref": "#/parameters/refresh" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Maintenance" + } + } + } + } + }, + "post": { + "summary": "Create a Maintenance", + "parameters": [ + { + "$ref": "#/parameters/Maintenance" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Maintenance" + } + } + } + } + }, + "/maintenance/{id}": { + "put": { + "summary": "Update a Maintenance", + "parameters": [ + { + "$ref": "#/parameters/entityId" + }, + { + "$ref": "#/parameters/Maintenance" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Maintenance" + } + } + } + }, + "delete": { + "summary": "Delete a Maintenance", + "parameters": [ + { + "$ref": "#/parameters/entityId" + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + } + }, + "definitions": { + "Position": { + "properties": { + "id": { + "type": "integer" + }, + "deviceId": { + "type": "integer" + }, + "protocol": { + "type": "string" + }, + "deviceTime": { + "type": "string", + "format": "date-time", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`" + }, + "fixTime": { + "type": "string", + "format": "date-time", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`" + }, + "serverTime": { + "type": "string", + "format": "date-time", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`" + }, + "outdated": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "altitude": { + "type": "number" + }, + "speed": { + "type": "number", + "description": "in knots" + }, + "course": { + "type": "number" + }, + "address": { + "type": "string" + }, + "accuracy": { + "type": "number" + }, + "network": { + "type": "object", + "additionalProperties": true + }, + "attributes": { + "type": "object", + "additionalProperties": true + } + } + }, + "User": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "readonly": { + "type": "boolean" + }, + "administrator": { + "type": "boolean" + }, + "map": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "zoom": { + "type": "integer" + }, + "password": { + "type": "string" + }, + "twelveHourFormat": { + "type": "boolean" + }, + "coordinateFormat": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "expirationTime": { + "type": "string", + "format": "date-time", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`" + }, + "deviceLimit": { + "type": "integer" + }, + "userLimit": { + "type": "integer" + }, + "deviceReadonly": { + "type": "boolean" + }, + "limitCommands": { + "type": "boolean" + }, + "poiLayer": { + "type": "string" + }, + "token": { + "type": "string" + }, + "attributes": { + "type": "object", + "additionalProperties": true + } + } + }, + "Server": { + "properties": { + "id": { + "type": "integer" + }, + "registration": { + "type": "boolean" + }, + "readonly": { + "type": "boolean" + }, + "deviceReadonly": { + "type": "boolean" + }, + "limitCommands": { + "type": "boolean" + }, + "map": { + "type": "string" + }, + "bingKey": { + "type": "string" + }, + "mapUrl": { + "type": "string" + }, + "poiLayer": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "zoom": { + "type": "integer" + }, + "twelveHourFormat": { + "type": "boolean" + }, + "version": { + "type": "string" + }, + "forceSettings": { + "type": "boolean" + }, + "coordinateFormat": { + "type": "string" + }, + "attributes": { + "type": "object", + "additionalProperties": true + } + } + }, + "Command": { + "properties": { + "id": { + "type": "integer" + }, + "deviceId": { + "type": "integer" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string" + }, + "attributes": { + "type": "object", + "additionalProperties": true + } + } + }, + "Device": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "uniqueId": { + "type": "string" + }, + "status": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "lastUpdate": { + "type": "string", + "format": "date-time", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`" + }, + "positionId": { + "type": "integer" + }, + "groupId": { + "type": "integer" + }, + "phone": { + "type": "string" + }, + "model": { + "type": "string" + }, + "contact": { + "type": "string" + }, + "category": { + "type": "string" + }, + "geofenceIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "attributes": { + "type": "object", + "additionalProperties": true + } + } + }, + "Group": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "groupId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "additionalProperties": true + } + } + }, + "Permission": { + "description": "This is a permission map that contain two object indexes. It is used to link/unlink objects. Order is important. Example: { deviceId:8, geofenceId: 16 }", + "properties": { + "userId": { + "description": "User Id, can be only first parameter", + "type": "integer" + }, + "deviceId": { + "description": "Device Id, can be first parameter or second only in combination with userId", + "type": "integer" + }, + "groupId": { + "description": "Group Id, can be first parameter or second only in combination with userId", + "type": "integer" + }, + "geofenceId": { + "description": "Geofence Id, can be second parameter only", + "type": "integer" + }, + "calendarId": { + "description": "Calendar Id, can be second parameter only and only in combination with userId", + "type": "integer" + }, + "attributeId": { + "description": "Computed Attribute Id, can be second parameter only", + "type": "integer" + }, + "driverId": { + "description": "Driver Id, can be second parameter only", + "type": "integer" + }, + "managedUserId": { + "description": "User Id, can be second parameter only and only in combination with userId", + "type": "integer" + } + } + }, + "CommandType": { + "properties": { + "type": { + "type": "string" + } + } + }, + "Geofence": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "area": { + "type": "string" + }, + "calendarId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "additionalProperties": true + } + } + }, + "Notification": { + "properties": { + "id": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "always": { + "type": "boolean" + }, + "web": { + "type": "boolean" + }, + "mail": { + "type": "boolean" + }, + "sms": { + "type": "boolean" + }, + "calendarId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "additionalProperties": true + } + } + }, + "NotificationType": { + "properties": { + "type": { + "type": "string" + } + } + }, + "Event": { + "properties": { + "id": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "serverTime": { + "type": "string", + "format": "date-time", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`" + }, + "deviceId": { + "type": "integer" + }, + "positionId": { + "type": "integer" + }, + "geofenceId": { + "type": "integer" + }, + "maintenanceId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "additionalProperties": true + } + } + }, + "ReportSummary": { + "properties": { + "deviceId": { + "type": "integer" + }, + "deviceName": { + "type": "string" + }, + "maxSpeed": { + "type": "number", + "description": "in knots" + }, + "averageSpeed": { + "type": "number", + "description": "in knots" + }, + "distance": { + "type": "number", + "description": "in meters" + }, + "spentFuel": { + "type": "number", + "description": "in liters" + }, + "engineHours": { + "type": "integer" + } + } + }, + "ReportTrips": { + "properties": { + "deviceId": { + "type": "integer" + }, + "deviceName": { + "type": "string" + }, + "maxSpeed": { + "type": "number", + "description": "in knots" + }, + "averageSpeed": { + "type": "number", + "description": "in knots" + }, + "distance": { + "type": "number", + "description": "in meters" + }, + "spentFuel": { + "type": "number", + "description": "in liters" + }, + "duration": { + "type": "integer" + }, + "startTime": { + "type": "string", + "format": "date-time", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`" + }, + "startAddress": { + "type": "string" + }, + "startLat": { + "type": "number" + }, + "startLon": { + "type": "number" + }, + "endTime": { + "type": "string", + "format": "date-time", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`" + }, + "endAddress": { + "type": "string" + }, + "endLat": { + "type": "number" + }, + "endLon": { + "type": "number" + }, + "driverUniqueId": { + "type": "integer" + }, + "driverName": { + "type": "string" + } + } + }, + "ReportStops": { + "properties": { + "deviceId": { + "type": "integer" + }, + "deviceName": { + "type": "string" + }, + "duration": { + "type": "integer" + }, + "startTime": { + "type": "string", + "format": "date-time", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`" + }, + "address": { + "type": "string" + }, + "lat": { + "type": "number" + }, + "lon": { + "type": "number" + }, + "endTime": { + "type": "string", + "format": "date-time", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`" + }, + "spentFuel": { + "type": "number", + "description": "in liters" + }, + "engineHours": { + "type": "integer" + } + } + }, + "Statistics": { + "properties": { + "captureTime": { + "type": "string", + "format": "date-time", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`" + }, + "activeUsers": { + "type": "integer" + }, + "activeDevices": { + "type": "integer" + }, + "requests": { + "type": "integer" + }, + "messagesReceived": { + "type": "integer" + }, + "messagesStored": { + "type": "integer" + } + } + }, + "DeviceAccumulators": { + "properties": { + "deviceId": { + "type": "integer" + }, + "totalDistance": { + "type": "number", + "description": "in meters" + }, + "hours": { + "type": "number" + } + } + }, + "Calendar": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "data": { + "type": "string", + "description": "base64 encoded in iCalendar format" + }, + "attributes": { + "type": "object", + "additionalProperties": true + } + } + }, + "Attribute": { + "properties": { + "id": { + "type": "integer" + }, + "description": { + "type": "string" + }, + "attribute": { + "type": "string" + }, + "expression": { + "type": "string" + }, + "type": { + "type": "string", + "description": "String|Number|Boolean" + } + } + }, + "Driver": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "uniqueId": { + "type": "string" + }, + "attributes": { + "type": "object", + "additionalProperties": true + } + } + }, + "Maintenance": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "start": { + "type": "number" + }, + "period": { + "type": "number" + }, + "attributes": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "parameters": { + "entityId": { + "name": "id", + "in": "path", + "required": true, + "type": "integer" + }, + "all": { + "name": "all", + "in": "query", + "description": "Can only be used by admins or managers to fetch all entities", + "type": "boolean" + }, + "refresh": { + "name": "refresh", + "in": "query", + "required": false, + "type": "boolean" + }, + "userId": { + "name": "userId", + "in": "query", + "description": "Standard users can use this only with their own _userId_", + "type": "integer" + }, + "deviceId": { + "name": "deviceId", + "in": "query", + "description": "Standard users can use this only with _deviceId_s, they have access to", + "type": "integer" + }, + "groupId": { + "name": "groupId", + "in": "query", + "description": "Standard users can use this only with _groupId_s, they have access to", + "type": "integer" + }, + "Device": { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Device" + } + }, + "Permission": { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Permission" + } + }, + "Group": { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Group" + } + }, + "User": { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/User" + } + }, + "Geofence": { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Geofence" + } + }, + "Calendar": { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Calendar" + } + }, + "Attribute": { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Attribute" + } + }, + "Driver": { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Driver" + } + }, + "Command": { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Command" + } + }, + "Notification": { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Notification" + } + }, + "Maintenance": { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Maintenance" + } + }, + "deviceIdArray": { + "name": "deviceId", + "in": "query", + "type": "array", + "items": { + "type": "integer" + }, + "collectionFormat": "multi" + }, + "groupIdArray": { + "name": "groupId", + "in": "query", + "type": "array", + "items": { + "type": "integer" + }, + "collectionFormat": "multi" + }, + "fromTime": { + "name": "from", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "type": "string", + "format": "date-time" + }, + "toTime": { + "name": "to", + "in": "query", + "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`", + "required": true, + "type": "string", + "format": "date-time" + } + }, + "securityDefinitions": { + "basicAuth": { + "type": "basic", + "description": "Basic HTTP authorization with _email_ and _password_" + } + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 3fb175fad..3daaad8f0 100644 --- a/pom.xml +++ b/pom.xml @@ -8,9 +8,9 @@ pom + extensions core app - extensions