From d4825d57fc27384288d9f3e1c1dd9e4bd7e29160 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 9 Mar 2016 16:09:00 +1300 Subject: Implement API resource for groups --- debug.xml | 8 +- src/org/traccar/api/AsyncSocket.java | 2 +- src/org/traccar/api/resource/GroupResource.java | 85 ++++++++++++++++++++++ src/org/traccar/api/resource/PositionResource.java | 2 +- src/org/traccar/database/DataManager.java | 52 +++++++++++-- src/org/traccar/database/PermissionsManager.java | 14 ++-- src/org/traccar/web/AsyncServlet.java | 2 +- 7 files changed, 144 insertions(+), 21 deletions(-) create mode 100644 src/org/traccar/api/resource/GroupResource.java diff --git a/debug.xml b/debug.xml index 413c020eb..2266a1eea 100644 --- a/debug.xml +++ b/debug.xml @@ -125,10 +125,6 @@ SELECT * FROM devices; - - SELECT * FROM devices d INNER JOIN user_device ud ON d.id = ud.deviceId WHERE ud.userId = :userId; - - INSERT INTO devices (name, uniqueId) VALUES (:name, :uniqueId); @@ -153,6 +149,10 @@ DELETE FROM user_device WHERE userId = :userId AND deviceId = :deviceId; + + SELECT * FROM groups; + + INSERT INTO groups (name) VALUES (:name); diff --git a/src/org/traccar/api/AsyncSocket.java b/src/org/traccar/api/AsyncSocket.java index 96ad2c450..c289367ea 100644 --- a/src/org/traccar/api/AsyncSocket.java +++ b/src/org/traccar/api/AsyncSocket.java @@ -36,7 +36,7 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U private Collection devices; public AsyncSocket(long userId) { - devices = Context.getPermissionsManager().allowedDevices(userId); + devices = Context.getPermissionsManager().getDevicePermissions(userId); } @Override diff --git a/src/org/traccar/api/resource/GroupResource.java b/src/org/traccar/api/resource/GroupResource.java new file mode 100644 index 000000000..49f839499 --- /dev/null +++ b/src/org/traccar/api/resource/GroupResource.java @@ -0,0 +1,85 @@ +/* + * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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.model.Device; +import org.traccar.model.Group; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +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 java.sql.SQLException; +import java.util.Collection; + +@Path("groups") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class GroupResource extends BaseResource { + + @GET + public Collection get( + @QueryParam("all") boolean all, @QueryParam("userId") long userId) throws SQLException { + if (all) { + Context.getPermissionsManager().checkAdmin(getUserId()); + return Context.getDataManager().getAllGroups(); + } else { + if (userId == 0) { + userId = getUserId(); + } + Context.getPermissionsManager().checkUser(getUserId(), userId); + return Context.getDataManager().getGroups(userId); + } + } + + @POST + public Response add(Group entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getDataManager().addGroup(entity); + Context.getDataManager().linkGroup(getUserId(), entity.getId()); + Context.getPermissionsManager().refresh(); + return Response.ok(entity).build(); + } + + @Path("{id}") + @PUT + public Response update(@PathParam("id") long id, Group entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkGroup(getUserId(), id); + Context.getDataManager().updateGroup(entity); + return Response.ok(entity).build(); + } + + @Path("{id}") + @DELETE + public Response remove(@PathParam("id") long id) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkGroup(getUserId(), id); + Context.getDataManager().removeGroup(id); + Context.getPermissionsManager().refresh(); + return Response.noContent().build(); + } + +} diff --git a/src/org/traccar/api/resource/PositionResource.java b/src/org/traccar/api/resource/PositionResource.java index b9e8e877e..9c174625c 100644 --- a/src/org/traccar/api/resource/PositionResource.java +++ b/src/org/traccar/api/resource/PositionResource.java @@ -40,7 +40,7 @@ public class PositionResource extends BaseResource { throws SQLException { if (deviceId == 0) { return Context.getConnectionManager().getInitialState( - Context.getPermissionsManager().allowedDevices(getUserId())); + Context.getPermissionsManager().getDevicePermissions(getUserId())); } else { Context.getPermissionsManager().checkDevice(getUserId(), deviceId); return Context.getDataManager().getPositions( diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java index 9a8a14615..d2da4e701 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -21,6 +21,7 @@ import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.sql.SQLException; +import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; @@ -36,6 +37,7 @@ import liquibase.exception.LiquibaseException; import liquibase.resource.FileSystemResourceAccessor; import liquibase.resource.ResourceAccessor; import org.traccar.Config; +import org.traccar.Context; import org.traccar.helper.Log; import org.traccar.model.Device; import org.traccar.model.Group; @@ -55,10 +57,14 @@ public class DataManager implements IdentityManager { private DataSource dataSource; + private final long dataRefreshDelay; + private final Map devicesById = new HashMap<>(); private final Map devicesByUniqueId = new HashMap<>(); private long devicesLastUpdate; - private final long devicesRefreshDelay; + + private final Map groupsById = new HashMap<>(); + private long groupsLastUpdate; public DataManager(Config config) throws Exception { this.config = config; @@ -66,7 +72,7 @@ public class DataManager implements IdentityManager { initDatabase(); initDatabaseSchema(); - devicesRefreshDelay = config.getLong("database.refreshDelay", DEFAULT_REFRESH_DELAY) * 1000; + dataRefreshDelay = config.getLong("database.refreshDelay", DEFAULT_REFRESH_DELAY) * 1000; } public DataSource getDataSource() { @@ -114,7 +120,7 @@ public class DataManager implements IdentityManager { } private void updateDeviceCache(boolean force) throws SQLException { - if (System.currentTimeMillis() - devicesLastUpdate > devicesRefreshDelay || force) { + if (System.currentTimeMillis() - devicesLastUpdate > dataRefreshDelay || force) { devicesById.clear(); devicesByUniqueId.clear(); for (Device device : getAllDevices()) { @@ -142,6 +148,25 @@ public class DataManager implements IdentityManager { return devicesByUniqueId.get(uniqueId); } + private void updateGroupCache(boolean force) throws SQLException { + if (System.currentTimeMillis() - groupsLastUpdate > dataRefreshDelay || force) { + groupsById.clear(); + for (Group group : getAllGroups()) { + groupsById.put(group.getId(), group); + } + groupsLastUpdate = System.currentTimeMillis(); + } + } + + public Group getGroupById(long id) { + try { + updateGroupCache(!groupsById.containsKey(id)); + } catch (SQLException e) { + Log.warning(e); + } + return groupsById.get(id); + } + private String getQuery(String key) { String query = config.getString(key); if (query == null) { @@ -239,9 +264,11 @@ public class DataManager implements IdentityManager { } public Collection getDevices(long userId) throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectDevices")) - .setLong("userId", userId) - .executeQuery(Device.class); + Collection devices = new ArrayList<>(); + for (long id : Context.getPermissionsManager().getDevicePermissions(userId)) { + devices.add(getDeviceById(id)); + } + return devices; } public void addDevice(Device device) throws SQLException { @@ -293,6 +320,19 @@ public class DataManager implements IdentityManager { AsyncServlet.sessionRefreshUser(userId); } + public Collection getAllGroups() throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectGroupsAll")) + .executeQuery(Group.class); + } + + public Collection getGroups(long userId) throws SQLException { + Collection groups = new ArrayList<>(); + for (long id : Context.getPermissionsManager().getGroupPermissions(userId)) { + groups.add(getGroupById(id)); + } + return groups; + } + public void addGroup(Group group) throws SQLException { group.setId(QueryBuilder.create(dataSource, getQuery("database.insertGroup"), true) .setObject(group) diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java index 0ed8227b4..5d6430764 100644 --- a/src/org/traccar/database/PermissionsManager.java +++ b/src/org/traccar/database/PermissionsManager.java @@ -38,14 +38,14 @@ public class PermissionsManager { private final Map> groupPermissions = new HashMap<>(); private final Map> devicePermissions = new HashMap<>(); - private Set getGroupPermissions(long userId) { + public Set getGroupPermissions(long userId) { if (!groupPermissions.containsKey(userId)) { groupPermissions.put(userId, new HashSet()); } return groupPermissions.get(userId); } - private Set getDevicePermissions(long userId) { + public Set getDevicePermissions(long userId) { if (!devicePermissions.containsKey(userId)) { devicePermissions.put(userId, new HashSet()); } @@ -92,12 +92,10 @@ public class PermissionsManager { } } - public Collection allowedGroups(long userId) { - return getGroupPermissions(userId); - } - - public Collection allowedDevices(long userId) { - return getDevicePermissions(userId); + public void checkGroup(long userId, long groupId) throws SecurityException { + if (!getGroupPermissions(userId).contains(groupId)) { + throw new SecurityException("Group access denied"); + } } public void checkDevice(long userId, long deviceId) throws SecurityException { diff --git a/src/org/traccar/web/AsyncServlet.java b/src/org/traccar/web/AsyncServlet.java index b10df5408..e4cb64c57 100644 --- a/src/org/traccar/web/AsyncServlet.java +++ b/src/org/traccar/web/AsyncServlet.java @@ -226,7 +226,7 @@ public class AsyncServlet extends BaseServlet { synchronized (ASYNC_SESSIONS) { if (Boolean.parseBoolean(req.getParameter("first")) || !ASYNC_SESSIONS.containsKey(userId)) { - Collection devices = Context.getPermissionsManager().allowedDevices(userId); + Collection devices = Context.getPermissionsManager().getDevicePermissions(userId); ASYNC_SESSIONS.put(userId, new AsyncSession(userId, devices)); } -- cgit v1.2.3