aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/api/resource
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/traccar/api/resource')
-rw-r--r--src/main/java/org/traccar/api/resource/AttributeResource.java97
-rw-r--r--src/main/java/org/traccar/api/resource/CalendarResource.java36
-rw-r--r--src/main/java/org/traccar/api/resource/CommandResource.java89
-rw-r--r--src/main/java/org/traccar/api/resource/DeviceResource.java100
-rw-r--r--src/main/java/org/traccar/api/resource/DriverResource.java36
-rw-r--r--src/main/java/org/traccar/api/resource/EventResource.java38
-rw-r--r--src/main/java/org/traccar/api/resource/GeofenceResource.java35
-rw-r--r--src/main/java/org/traccar/api/resource/GroupResource.java35
-rw-r--r--src/main/java/org/traccar/api/resource/MaintenanceResource.java36
-rw-r--r--src/main/java/org/traccar/api/resource/NotificationResource.java76
-rw-r--r--src/main/java/org/traccar/api/resource/PermissionsResource.java84
-rw-r--r--src/main/java/org/traccar/api/resource/PositionResource.java96
-rw-r--r--src/main/java/org/traccar/api/resource/ReportResource.java210
-rw-r--r--src/main/java/org/traccar/api/resource/ServerResource.java63
-rw-r--r--src/main/java/org/traccar/api/resource/SessionResource.java120
-rw-r--r--src/main/java/org/traccar/api/resource/StatisticsResource.java44
-rw-r--r--src/main/java/org/traccar/api/resource/UserResource.java94
17 files changed, 1289 insertions, 0 deletions
diff --git a/src/main/java/org/traccar/api/resource/AttributeResource.java b/src/main/java/org/traccar/api/resource/AttributeResource.java
new file mode 100644
index 000000000..de69d871c
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/AttributeResource.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import java.sql.SQLException;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.traccar.Context;
+import org.traccar.api.ExtendedObjectResource;
+import org.traccar.model.Attribute;
+import org.traccar.model.Position;
+import org.traccar.handler.ComputedAttributesHandler;
+
+@Path("attributes/computed")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class AttributeResource extends ExtendedObjectResource<Attribute> {
+
+ public AttributeResource() {
+ super(Attribute.class);
+ }
+
+ @POST
+ @Path("test")
+ public Response test(@QueryParam("deviceId") long deviceId, Attribute entity) {
+ Context.getPermissionsManager().checkAdmin(getUserId());
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ Position last = Context.getIdentityManager().getLastPosition(deviceId);
+ if (last != null) {
+ Object result = new ComputedAttributesHandler(
+ Context.getConfig(),
+ Context.getIdentityManager(),
+ Context.getAttributesManager()).computeAttribute(entity, last);
+ if (result != null) {
+ switch (entity.getType()) {
+ case "number":
+ Number numberValue = (Number) result;
+ return Response.ok(numberValue).build();
+ case "boolean":
+ Boolean booleanValue = (Boolean) result;
+ return Response.ok(booleanValue).build();
+ default:
+ return Response.ok(result.toString()).build();
+ }
+ } else {
+ return Response.noContent().build();
+ }
+ } else {
+ throw new IllegalArgumentException("Device has no last position");
+ }
+ }
+
+ @POST
+ public Response add(Attribute entity) throws SQLException {
+ Context.getPermissionsManager().checkAdmin(getUserId());
+ return super.add(entity);
+ }
+
+ @Path("{id}")
+ @PUT
+ public Response update(Attribute entity) throws SQLException {
+ Context.getPermissionsManager().checkAdmin(getUserId());
+ return super.update(entity);
+ }
+
+ @Path("{id}")
+ @DELETE
+ public Response remove(@PathParam("id") long id) throws SQLException {
+ Context.getPermissionsManager().checkAdmin(getUserId());
+ return super.remove(id);
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/CalendarResource.java b/src/main/java/org/traccar/api/resource/CalendarResource.java
new file mode 100644
index 000000000..9399c34a5
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/CalendarResource.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.traccar.api.SimpleObjectResource;
+import org.traccar.model.Calendar;
+
+@Path("calendars")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class CalendarResource extends SimpleObjectResource<Calendar> {
+
+ public CalendarResource() {
+ super(Calendar.class);
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java
new file mode 100644
index 000000000..703638701
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/CommandResource.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 Gabor Somogyi (gabor.g.somogyi@gmail.com)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import org.traccar.Context;
+import org.traccar.api.ExtendedObjectResource;
+import org.traccar.database.CommandsManager;
+import org.traccar.model.Command;
+import org.traccar.model.Typed;
+
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("commands")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class CommandResource extends ExtendedObjectResource<Command> {
+
+ public CommandResource() {
+ super(Command.class);
+ }
+
+ @GET
+ @Path("send")
+ public Collection<Command> get(@QueryParam("deviceId") long deviceId) throws SQLException {
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ CommandsManager commandsManager = Context.getCommandsManager();
+ Set<Long> result = new HashSet<>(commandsManager.getUserItems(getUserId()));
+ result.retainAll(commandsManager.getSupportedCommands(deviceId));
+ return commandsManager.getItems(result);
+ }
+
+ @POST
+ @Path("send")
+ public Response send(Command entity) throws Exception {
+ Context.getPermissionsManager().checkReadonly(getUserId());
+ long deviceId = entity.getDeviceId();
+ long id = entity.getId();
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ if (id != 0) {
+ Context.getPermissionsManager().checkPermission(Command.class, getUserId(), id);
+ Context.getPermissionsManager().checkUserDeviceCommand(getUserId(), deviceId, id);
+ } else {
+ Context.getPermissionsManager().checkLimitCommands(getUserId());
+ }
+ if (!Context.getCommandsManager().sendCommand(entity)) {
+ return Response.accepted(entity).build();
+ }
+ return Response.ok(entity).build();
+ }
+
+ @GET
+ @Path("types")
+ public Collection<Typed> get(@QueryParam("deviceId") long deviceId,
+ @QueryParam("textChannel") boolean textChannel) {
+ if (deviceId != 0) {
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ return Context.getCommandsManager().getCommandTypes(deviceId, textChannel);
+ } else {
+ return Context.getCommandsManager().getAllCommandTypes();
+ }
+ }
+}
diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java
new file mode 100644
index 000000000..f9c9a139d
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/DeviceResource.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import org.traccar.Context;
+import org.traccar.api.BaseObjectResource;
+import org.traccar.database.DeviceManager;
+import org.traccar.helper.LogAction;
+import org.traccar.model.Device;
+import org.traccar.model.DeviceAccumulators;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Path("devices")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class DeviceResource extends BaseObjectResource<Device> {
+
+ public DeviceResource() {
+ super(Device.class);
+ }
+
+ @GET
+ public Collection<Device> get(
+ @QueryParam("all") boolean all, @QueryParam("userId") long userId,
+ @QueryParam("uniqueId") List<String> uniqueIds,
+ @QueryParam("id") List<Long> deviceIds) throws SQLException {
+ DeviceManager deviceManager = Context.getDeviceManager();
+ Set<Long> result = null;
+ if (all) {
+ if (Context.getPermissionsManager().getUserAdmin(getUserId())) {
+ result = deviceManager.getAllItems();
+ } else {
+ Context.getPermissionsManager().checkManager(getUserId());
+ result = deviceManager.getManagedItems(getUserId());
+ }
+ } else if (uniqueIds.isEmpty() && deviceIds.isEmpty()) {
+ if (userId == 0) {
+ userId = getUserId();
+ }
+ Context.getPermissionsManager().checkUser(getUserId(), userId);
+ if (Context.getPermissionsManager().getUserAdmin(getUserId())) {
+ result = deviceManager.getAllUserItems(userId);
+ } else {
+ result = deviceManager.getUserItems(userId);
+ }
+ } else {
+ result = new HashSet<>();
+ for (String uniqueId : uniqueIds) {
+ Device device = deviceManager.getByUniqueId(uniqueId);
+ Context.getPermissionsManager().checkDevice(getUserId(), device.getId());
+ result.add(device.getId());
+ }
+ for (Long deviceId : deviceIds) {
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ result.add(deviceId);
+ }
+ }
+ return deviceManager.getItems(result);
+ }
+
+ @Path("{id}/accumulators")
+ @PUT
+ public Response updateAccumulators(DeviceAccumulators entity) throws SQLException {
+ if (!Context.getPermissionsManager().getUserAdmin(getUserId())) {
+ Context.getPermissionsManager().checkManager(getUserId());
+ Context.getPermissionsManager().checkPermission(Device.class, getUserId(), entity.getDeviceId());
+ }
+ Context.getDeviceManager().resetDeviceAccumulators(entity);
+ LogAction.resetDeviceAccumulators(getUserId(), entity.getDeviceId());
+ return Response.noContent().build();
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/DriverResource.java b/src/main/java/org/traccar/api/resource/DriverResource.java
new file mode 100644
index 000000000..91aa54c5e
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/DriverResource.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.traccar.api.ExtendedObjectResource;
+import org.traccar.model.Driver;
+
+@Path("drivers")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class DriverResource extends ExtendedObjectResource<Driver> {
+
+ public DriverResource() {
+ super(Driver.class);
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/EventResource.java b/src/main/java/org/traccar/api/resource/EventResource.java
new file mode 100644
index 000000000..e0ccf7020
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/EventResource.java
@@ -0,0 +1,38 @@
+package org.traccar.api.resource;
+
+import java.sql.SQLException;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.traccar.Context;
+import org.traccar.api.BaseResource;
+import org.traccar.model.Event;
+import org.traccar.model.Geofence;
+import org.traccar.model.Maintenance;
+
+@Path("events")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+
+public class EventResource extends BaseResource {
+
+ @Path("{id}")
+ @GET
+ public Event get(@PathParam("id") long id) throws SQLException {
+ Event event = Context.getDataManager().getObject(Event.class, id);
+ Context.getPermissionsManager().checkDevice(getUserId(), event.getDeviceId());
+ if (event.getGeofenceId() != 0) {
+ Context.getPermissionsManager().checkPermission(Geofence.class, getUserId(), event.getGeofenceId());
+ }
+ if (event.getMaintenanceId() != 0) {
+ Context.getPermissionsManager().checkPermission(Maintenance.class, getUserId(), event.getMaintenanceId());
+ }
+ return event;
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/GeofenceResource.java b/src/main/java/org/traccar/api/resource/GeofenceResource.java
new file mode 100644
index 000000000..58f2c188c
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/GeofenceResource.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import org.traccar.api.ExtendedObjectResource;
+import org.traccar.model.Geofence;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("geofences")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class GeofenceResource extends ExtendedObjectResource<Geofence> {
+
+ public GeofenceResource() {
+ super(Geofence.class);
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/GroupResource.java b/src/main/java/org/traccar/api/resource/GroupResource.java
new file mode 100644
index 000000000..fcea15d0a
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/GroupResource.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import org.traccar.api.SimpleObjectResource;
+import org.traccar.model.Group;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("groups")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class GroupResource extends SimpleObjectResource<Group> {
+
+ public GroupResource() {
+ super(Group.class);
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/MaintenanceResource.java b/src/main/java/org/traccar/api/resource/MaintenanceResource.java
new file mode 100644
index 000000000..fa1b359ce
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/MaintenanceResource.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.traccar.api.ExtendedObjectResource;
+import org.traccar.model.Maintenance;
+
+@Path("maintenance")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class MaintenanceResource extends ExtendedObjectResource<Maintenance> {
+
+ public MaintenanceResource() {
+ super(Maintenance.class);
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/NotificationResource.java b/src/main/java/org/traccar/api/resource/NotificationResource.java
new file mode 100644
index 000000000..9631a52b7
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/NotificationResource.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import java.util.Collection;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.traccar.Context;
+import org.traccar.api.ExtendedObjectResource;
+import org.traccar.model.Event;
+import org.traccar.model.Notification;
+import org.traccar.model.Typed;
+import org.traccar.notification.MessageException;
+
+
+@Path("notifications")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class NotificationResource extends ExtendedObjectResource<Notification> {
+
+ public NotificationResource() {
+ super(Notification.class);
+ }
+
+ @GET
+ @Path("types")
+ public Collection<Typed> get() {
+ return Context.getNotificationManager().getAllNotificationTypes();
+ }
+
+ @GET
+ @Path("notificators")
+ public Collection<Typed> getNotificators() {
+ return Context.getNotificatorManager().getAllNotificatorTypes();
+ }
+
+ @POST
+ @Path("test")
+ public Response testMessage() throws MessageException, InterruptedException {
+ for (Typed method : Context.getNotificatorManager().getAllNotificatorTypes()) {
+ Context.getNotificatorManager()
+ .getNotificator(method.getType()).sendSync(getUserId(), new Event("test", 0), null);
+ }
+ return Response.noContent().build();
+ }
+
+ @POST
+ @Path("test/{notificator}")
+ public Response testMessage(@PathParam("notificator") String notificator)
+ throws MessageException, InterruptedException {
+ Context.getNotificatorManager().getNotificator(notificator).sendSync(getUserId(), new Event("test", 0), null);
+ return Response.noContent().build();
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/PermissionsResource.java b/src/main/java/org/traccar/api/resource/PermissionsResource.java
new file mode 100644
index 000000000..b89d9d376
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/PermissionsResource.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import java.sql.SQLException;
+import java.util.LinkedHashMap;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.traccar.Context;
+import org.traccar.api.BaseResource;
+import org.traccar.helper.LogAction;
+import org.traccar.model.Device;
+import org.traccar.model.Permission;
+import org.traccar.model.User;
+
+@Path("permissions")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class PermissionsResource extends BaseResource {
+
+ private void checkPermission(Permission permission, boolean link) {
+ if (!link && permission.getOwnerClass().equals(User.class)
+ && permission.getPropertyClass().equals(Device.class)) {
+ if (getUserId() != permission.getOwnerId()) {
+ Context.getPermissionsManager().checkUser(getUserId(), permission.getOwnerId());
+ } else {
+ Context.getPermissionsManager().checkAdmin(getUserId());
+ }
+ } else {
+ Context.getPermissionsManager().checkPermission(
+ permission.getOwnerClass(), getUserId(), permission.getOwnerId());
+ }
+ Context.getPermissionsManager().checkPermission(
+ permission.getPropertyClass(), getUserId(), permission.getPropertyId());
+ }
+
+ @POST
+ public Response add(LinkedHashMap<String, Long> entity) throws SQLException, ClassNotFoundException {
+ Context.getPermissionsManager().checkReadonly(getUserId());
+ Permission permission = new Permission(entity);
+ checkPermission(permission, true);
+ Context.getDataManager().linkObject(permission.getOwnerClass(), permission.getOwnerId(),
+ permission.getPropertyClass(), permission.getPropertyId(), true);
+ LogAction.link(getUserId(), permission.getOwnerClass(), permission.getOwnerId(),
+ permission.getPropertyClass(), permission.getPropertyId());
+ Context.getPermissionsManager().refreshPermissions(permission);
+ return Response.noContent().build();
+ }
+
+ @DELETE
+ public Response remove(LinkedHashMap<String, Long> entity) throws SQLException, ClassNotFoundException {
+ Context.getPermissionsManager().checkReadonly(getUserId());
+ Permission permission = new Permission(entity);
+ checkPermission(permission, false);
+ Context.getDataManager().linkObject(permission.getOwnerClass(), permission.getOwnerId(),
+ permission.getPropertyClass(), permission.getPropertyId(), false);
+ LogAction.unlink(getUserId(), permission.getOwnerClass(), permission.getOwnerId(),
+ permission.getPropertyClass(), permission.getPropertyId());
+ Context.getPermissionsManager().refreshPermissions(permission);
+ return Response.noContent().build();
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java
new file mode 100644
index 000000000..c031b842f
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/PositionResource.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import org.traccar.Context;
+import org.traccar.api.BaseResource;
+import org.traccar.helper.DateUtil;
+import org.traccar.model.Position;
+import org.traccar.web.CsvBuilder;
+import org.traccar.web.GpxBuilder;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+@Path("positions")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class PositionResource extends BaseResource {
+
+ public static final String TEXT_CSV = "text/csv";
+ public static final String CONTENT_DISPOSITION_VALUE_CSV = "attachment; filename=positions.csv";
+ public static final String GPX = "application/gpx+xml";
+ public static final String CONTENT_DISPOSITION_VALUE_GPX = "attachment; filename=positions.gpx";
+
+ @GET
+ public Collection<Position> getJson(
+ @QueryParam("deviceId") long deviceId, @QueryParam("id") List<Long> positionIds,
+ @QueryParam("from") String from, @QueryParam("to") String to)
+ throws SQLException {
+ if (!positionIds.isEmpty()) {
+ ArrayList<Position> positions = new ArrayList<>();
+ for (Long positionId : positionIds) {
+ Position position = Context.getDataManager().getObject(Position.class, positionId);
+ Context.getPermissionsManager().checkDevice(getUserId(), position.getDeviceId());
+ positions.add(position);
+ }
+ return positions;
+ } else if (deviceId == 0) {
+ return Context.getDeviceManager().getInitialState(getUserId());
+ } else {
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ return Context.getDataManager().getPositions(
+ deviceId, DateUtil.parseDate(from), DateUtil.parseDate(to));
+ }
+ }
+
+ @GET
+ @Produces(TEXT_CSV)
+ public Response getCsv(
+ @QueryParam("deviceId") long deviceId, @QueryParam("from") String from, @QueryParam("to") String to)
+ throws SQLException {
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ CsvBuilder csv = new CsvBuilder();
+ csv.addHeaderLine(new Position());
+ csv.addArray(Context.getDataManager().getPositions(
+ deviceId, DateUtil.parseDate(from), DateUtil.parseDate(to)));
+ return Response.ok(csv.build()).header(HttpHeaders.CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE_CSV).build();
+ }
+
+ @GET
+ @Produces(GPX)
+ public Response getGpx(
+ @QueryParam("deviceId") long deviceId, @QueryParam("from") String from, @QueryParam("to") String to)
+ throws SQLException {
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ GpxBuilder gpx = new GpxBuilder(Context.getIdentityManager().getById(deviceId).getName());
+ gpx.addPositions(Context.getDataManager().getPositions(
+ deviceId, DateUtil.parseDate(from), DateUtil.parseDate(to)));
+ return Response.ok(gpx.build()).header(HttpHeaders.CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE_GPX).build();
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java
new file mode 100644
index 000000000..d371cf987
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/ReportResource.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.List;
+
+import javax.activation.DataHandler;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.util.ByteArrayDataSource;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.Context;
+import org.traccar.api.BaseResource;
+import org.traccar.helper.DateUtil;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+import org.traccar.reports.Events;
+import org.traccar.reports.Summary;
+import org.traccar.reports.Trips;
+import org.traccar.reports.model.StopReport;
+import org.traccar.reports.model.SummaryReport;
+import org.traccar.reports.model.TripReport;
+import org.traccar.reports.Route;
+import org.traccar.reports.Stops;
+
+@Path("reports")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class ReportResource extends BaseResource {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ReportResource.class);
+
+ private static final String XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
+ private static final String CONTENT_DISPOSITION_VALUE_XLSX = "attachment; filename=report.xlsx";
+
+ private interface ReportExecutor {
+ void execute(ByteArrayOutputStream stream) throws SQLException, IOException;
+ }
+
+ private Response executeReport(
+ long userId, boolean mail, ReportExecutor executor) throws SQLException, IOException {
+ final ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ if (mail) {
+ new Thread(() -> {
+ try {
+ executor.execute(stream);
+
+ MimeBodyPart attachment = new MimeBodyPart();
+
+ attachment.setFileName("report.xlsx");
+ attachment.setDataHandler(new DataHandler(new ByteArrayDataSource(
+ stream.toByteArray(), "application/octet-stream")));
+
+ Context.getMailManager().sendMessage(
+ userId, "Report", "The report is in the attachment.", attachment);
+ } catch (SQLException | IOException | MessagingException e) {
+ LOGGER.warn("Report failed", e);
+ }
+ }).start();
+ return Response.noContent().build();
+ } else {
+ executor.execute(stream);
+ return Response.ok(stream.toByteArray())
+ .header(HttpHeaders.CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE_XLSX).build();
+ }
+ }
+
+ @Path("route")
+ @GET
+ public Collection<Position> getRoute(
+ @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
+ @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException {
+ return Route.getObjects(getUserId(), deviceIds, groupIds,
+ DateUtil.parseDate(from), DateUtil.parseDate(to));
+ }
+
+ @Path("route")
+ @GET
+ @Produces(XLSX)
+ public Response getRouteExcel(
+ @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
+ @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail)
+ throws SQLException, IOException {
+ return executeReport(getUserId(), mail, stream -> {
+ Route.getExcel(stream, getUserId(), deviceIds, groupIds,
+ DateUtil.parseDate(from), DateUtil.parseDate(to));
+ });
+ }
+
+ @Path("events")
+ @GET
+ public Collection<Event> getEvents(
+ @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
+ @QueryParam("type") final List<String> types,
+ @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException {
+ return Events.getObjects(getUserId(), deviceIds, groupIds, types,
+ DateUtil.parseDate(from), DateUtil.parseDate(to));
+ }
+
+ @Path("events")
+ @GET
+ @Produces(XLSX)
+ public Response getEventsExcel(
+ @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
+ @QueryParam("type") final List<String> types,
+ @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail)
+ throws SQLException, IOException {
+ return executeReport(getUserId(), mail, stream -> {
+ Events.getExcel(stream, getUserId(), deviceIds, groupIds, types,
+ DateUtil.parseDate(from), DateUtil.parseDate(to));
+ });
+ }
+
+ @Path("summary")
+ @GET
+ public Collection<SummaryReport> getSummary(
+ @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
+ @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException {
+ return Summary.getObjects(getUserId(), deviceIds, groupIds,
+ DateUtil.parseDate(from), DateUtil.parseDate(to));
+ }
+
+ @Path("summary")
+ @GET
+ @Produces(XLSX)
+ public Response getSummaryExcel(
+ @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
+ @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail)
+ throws SQLException, IOException {
+ return executeReport(getUserId(), mail, stream -> {
+ Summary.getExcel(stream, getUserId(), deviceIds, groupIds,
+ DateUtil.parseDate(from), DateUtil.parseDate(to));
+ });
+ }
+
+ @Path("trips")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Collection<TripReport> getTrips(
+ @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
+ @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException {
+ return Trips.getObjects(getUserId(), deviceIds, groupIds,
+ DateUtil.parseDate(from), DateUtil.parseDate(to));
+ }
+
+ @Path("trips")
+ @GET
+ @Produces(XLSX)
+ public Response getTripsExcel(
+ @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
+ @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail)
+ throws SQLException, IOException {
+ return executeReport(getUserId(), mail, stream -> {
+ Trips.getExcel(stream, getUserId(), deviceIds, groupIds,
+ DateUtil.parseDate(from), DateUtil.parseDate(to));
+ });
+ }
+
+ @Path("stops")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Collection<StopReport> getStops(
+ @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
+ @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException {
+ return Stops.getObjects(getUserId(), deviceIds, groupIds,
+ DateUtil.parseDate(from), DateUtil.parseDate(to));
+ }
+
+ @Path("stops")
+ @GET
+ @Produces(XLSX)
+ public Response getStopsExcel(
+ @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
+ @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail)
+ throws SQLException, IOException {
+ return executeReport(getUserId(), mail, stream -> {
+ Stops.getExcel(stream, getUserId(), deviceIds, groupIds,
+ DateUtil.parseDate(from), DateUtil.parseDate(to));
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java
new file mode 100644
index 000000000..e7cad2a0c
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/ServerResource.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import org.traccar.Context;
+import org.traccar.api.BaseResource;
+import org.traccar.helper.LogAction;
+import org.traccar.model.Server;
+
+import javax.annotation.security.PermitAll;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.sql.SQLException;
+
+@Path("server")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class ServerResource extends BaseResource {
+
+ @PermitAll
+ @GET
+ public Server get() throws SQLException {
+ return Context.getPermissionsManager().getServer();
+ }
+
+ @PUT
+ public Response update(Server entity) throws SQLException {
+ Context.getPermissionsManager().checkAdmin(getUserId());
+ Context.getPermissionsManager().updateServer(entity);
+ LogAction.edit(getUserId(), entity);
+ return Response.ok(entity).build();
+ }
+
+ @Path("geocode")
+ @GET
+ public String geocode(@QueryParam("latitude") double latitude, @QueryParam("longitude") double longitude) {
+ if (Context.getGeocoder() != null) {
+ return Context.getGeocoder().getAddress(latitude, longitude, null);
+ } else {
+ throw new RuntimeException("Reverse geocoding is not enabled");
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java
new file mode 100644
index 000000000..fd331c766
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/SessionResource.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import org.traccar.Context;
+import org.traccar.api.BaseResource;
+import org.traccar.helper.DataConverter;
+import org.traccar.helper.LogAction;
+import org.traccar.model.User;
+
+import javax.annotation.security.PermitAll;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.sql.SQLException;
+
+@Path("session")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+public class SessionResource extends BaseResource {
+
+ public static final String USER_ID_KEY = "userId";
+ public static final String USER_COOKIE_KEY = "user";
+ public static final String PASS_COOKIE_KEY = "password";
+
+ @javax.ws.rs.core.Context
+ private HttpServletRequest request;
+
+ @PermitAll
+ @GET
+ public User get(@QueryParam("token") String token) throws SQLException, UnsupportedEncodingException {
+ Long userId = (Long) request.getSession().getAttribute(USER_ID_KEY);
+ if (userId == null) {
+ Cookie[] cookies = request.getCookies();
+ String email = null, password = null;
+ if (cookies != null) {
+ for (Cookie cookie : cookies) {
+ if (cookie.getName().equals(USER_COOKIE_KEY)) {
+ byte[] emailBytes = DataConverter.parseBase64(
+ URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII.name()));
+ email = new String(emailBytes, StandardCharsets.UTF_8);
+ } else if (cookie.getName().equals(PASS_COOKIE_KEY)) {
+ byte[] passwordBytes = DataConverter.parseBase64(
+ URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII.name()));
+ password = new String(passwordBytes, StandardCharsets.UTF_8);
+ }
+ }
+ }
+ if (email != null && password != null) {
+ User user = Context.getPermissionsManager().login(email, password);
+ if (user != null) {
+ userId = user.getId();
+ request.getSession().setAttribute(USER_ID_KEY, userId);
+ }
+ } else if (token != null) {
+ User user = Context.getUsersManager().getUserByToken(token);
+ if (user != null) {
+ userId = user.getId();
+ request.getSession().setAttribute(USER_ID_KEY, userId);
+ }
+ }
+ }
+
+ if (userId != null) {
+ Context.getPermissionsManager().checkUserEnabled(userId);
+ return Context.getPermissionsManager().getUser(userId);
+ } else {
+ throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
+ }
+ }
+
+ @PermitAll
+ @POST
+ public User add(
+ @FormParam("email") String email, @FormParam("password") String password) throws SQLException {
+ User user = Context.getPermissionsManager().login(email, password);
+ if (user != null) {
+ request.getSession().setAttribute(USER_ID_KEY, user.getId());
+ LogAction.login(user.getId());
+ return user;
+ } else {
+ throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build());
+ }
+ }
+
+ @DELETE
+ public Response remove() {
+ LogAction.logout(getUserId());
+ request.getSession().removeAttribute(USER_ID_KEY);
+ return Response.noContent().build();
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/StatisticsResource.java b/src/main/java/org/traccar/api/resource/StatisticsResource.java
new file mode 100644
index 000000000..e801d4ff3
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/StatisticsResource.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import org.traccar.Context;
+import org.traccar.api.BaseResource;
+import org.traccar.helper.DateUtil;
+import org.traccar.model.Statistics;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.sql.SQLException;
+import java.util.Collection;
+
+@Path("statistics")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class StatisticsResource extends BaseResource {
+
+ @GET
+ public Collection<Statistics> get(
+ @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException {
+ Context.getPermissionsManager().checkAdmin(getUserId());
+ return Context.getDataManager().getStatistics(DateUtil.parseDate(from), DateUtil.parseDate(to));
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java
new file mode 100644
index 000000000..0b42d8d92
--- /dev/null
+++ b/src/main/java/org/traccar/api/resource/UserResource.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.resource;
+
+import org.traccar.Context;
+import org.traccar.api.BaseObjectResource;
+import org.traccar.database.UsersManager;
+import org.traccar.helper.LogAction;
+import org.traccar.model.ManagedUser;
+import org.traccar.model.User;
+
+import javax.annotation.security.PermitAll;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Set;
+
+@Path("users")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class UserResource extends BaseObjectResource<User> {
+
+ public UserResource() {
+ super(User.class);
+ }
+
+ @GET
+ public Collection<User> get(@QueryParam("userId") long userId) throws SQLException {
+ UsersManager usersManager = Context.getUsersManager();
+ Set<Long> result = null;
+ if (Context.getPermissionsManager().getUserAdmin(getUserId())) {
+ if (userId != 0) {
+ result = usersManager.getUserItems(userId);
+ } else {
+ result = usersManager.getAllItems();
+ }
+ } else if (Context.getPermissionsManager().getUserManager(getUserId())) {
+ result = usersManager.getManagedItems(getUserId());
+ } else {
+ throw new SecurityException("Admin or manager access required");
+ }
+ return usersManager.getItems(result);
+ }
+
+ @Override
+ @PermitAll
+ @POST
+ public Response add(User entity) throws SQLException {
+ if (!Context.getPermissionsManager().getUserAdmin(getUserId())) {
+ Context.getPermissionsManager().checkUserUpdate(getUserId(), new User(), entity);
+ if (Context.getPermissionsManager().getUserManager(getUserId())) {
+ Context.getPermissionsManager().checkUserLimit(getUserId());
+ } else {
+ Context.getPermissionsManager().checkRegistration(getUserId());
+ entity.setDeviceLimit(Context.getConfig().getInteger("users.defaultDeviceLimit", -1));
+ int expirationDays = Context.getConfig().getInteger("users.defaultExpirationDays");
+ if (expirationDays > 0) {
+ entity.setExpirationTime(
+ new Date(System.currentTimeMillis() + (long) expirationDays * 24 * 3600 * 1000));
+ }
+ }
+ }
+ Context.getUsersManager().addItem(entity);
+ LogAction.create(getUserId(), entity);
+ if (Context.getPermissionsManager().getUserManager(getUserId())) {
+ Context.getDataManager().linkObject(User.class, getUserId(), ManagedUser.class, entity.getId(), true);
+ LogAction.link(getUserId(), User.class, getUserId(), ManagedUser.class, entity.getId());
+ }
+ Context.getUsersManager().refreshUserItems();
+ return Response.ok(entity).build();
+ }
+
+}