From ec76482c15094a7e04964c67d3011a7e8e1ad6a9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 4 Jun 2022 06:33:02 -0700 Subject: Refactor commands manager --- .../org/traccar/api/resource/CommandResource.java | 104 +++++++++++++++------ .../org/traccar/api/resource/PositionResource.java | 3 +- .../org/traccar/api/resource/ReportResource.java | 21 +++-- .../traccar/api/security/PermissionsService.java | 12 ++- 4 files changed, 97 insertions(+), 43 deletions(-) (limited to 'src/main/java/org/traccar/api') diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java index a31345246..17bb150f6 100644 --- a/src/main/java/org/traccar/api/resource/CommandResource.java +++ b/src/main/java/org/traccar/api/resource/CommandResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) * Copyright 2016 Gabor Somogyi (gabor.g.somogyi@gmail.com) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * @@ -17,16 +17,23 @@ */ package org.traccar.api.resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.BaseProtocol; import org.traccar.Context; import org.traccar.api.ExtendedObjectResource; import org.traccar.database.CommandsManager; import org.traccar.model.Command; +import org.traccar.model.Device; +import org.traccar.model.Position; import org.traccar.model.Typed; +import org.traccar.model.UserRestrictions; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - +import javax.inject.Inject; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -35,40 +42,61 @@ import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; @Path("commands") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class CommandResource extends ExtendedObjectResource { + private static final Logger LOGGER = LoggerFactory.getLogger(CommandResource.class); + + @Inject + private CommandsManager commandsManager; + public CommandResource() { super(Command.class); } + private BaseProtocol getDeviceProtocol(long deviceId) throws StorageException { + Position position = storage.getObject(Position.class, new Request( + new Columns.All(), new Condition.LatestPositions(deviceId))); + if (position != null) { + return Context.getServerManager().getProtocol(position.getProtocol()); + } else { + return null; + } + } + @GET @Path("send") - public Collection get(@QueryParam("deviceId") long deviceId) { - Context.getPermissionsManager().checkDevice(getUserId(), deviceId); - CommandsManager commandsManager = Context.getCommandsManager(); - Set result = new HashSet<>(commandsManager.getUserItems(getUserId())); - result.retainAll(commandsManager.getSupportedCommands(deviceId)); - return commandsManager.getItems(result); + public Collection get(@QueryParam("deviceId") long deviceId) throws StorageException { + permissionsService.checkPermission(Device.class, getUserId(), deviceId); + BaseProtocol protocol = getDeviceProtocol(deviceId); + return get(false, 0, 0, deviceId).stream().filter(command -> { + String type = command.getType(); + if (protocol != null) { + return command.getTextChannel() && protocol.getSupportedTextCommands().contains(type) + || !command.getTextChannel() && protocol.getSupportedDataCommands().contains(type); + } else { + return type.equals(Command.TYPE_CUSTOM); + } + }).collect(Collectors.toList()); } @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)) { + permissionsService.checkRestriction(getUserId(), UserRestrictions::getReadonly); + permissionsService.checkRestriction(getUserId(), UserRestrictions::getLimitCommands); + permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId()); + if (!commandsManager.sendCommand(entity)) { return Response.accepted(entity).build(); } return Response.ok(entity).build(); @@ -78,15 +106,33 @@ public class CommandResource extends ExtendedObjectResource { @Path("types") public Collection get( @QueryParam("deviceId") long deviceId, - @QueryParam("protocol") String protocol, - @QueryParam("textChannel") boolean textChannel) { + @QueryParam("textChannel") boolean textChannel) throws StorageException { if (deviceId != 0) { - Context.getPermissionsManager().checkDevice(getUserId(), deviceId); - return Context.getCommandsManager().getCommandTypes(deviceId, textChannel); - } else if (protocol != null) { - return Context.getCommandsManager().getCommandTypes(protocol, textChannel); + permissionsService.checkPermission(Device.class, getUserId(), deviceId); + BaseProtocol protocol = getDeviceProtocol(deviceId); + if (protocol != null) { + if (textChannel) { + return protocol.getSupportedTextCommands().stream().map(Typed::new).collect(Collectors.toList()); + } else { + return protocol.getSupportedDataCommands().stream().map(Typed::new).collect(Collectors.toList()); + } + } else { + return Collections.singletonList(new Typed(Command.TYPE_CUSTOM)); + } } else { - return Context.getCommandsManager().getAllCommandTypes(); + List result = new ArrayList<>(); + Field[] fields = Command.class.getDeclaredFields(); + for (Field field : fields) { + if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TYPE_")) { + try { + result.add(new Typed(field.get(null).toString())); + } catch (IllegalArgumentException | IllegalAccessException error) { + LOGGER.warn("Get command types error", error); + } + } + } + return result; } } + } diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java index 941417231..2618a04cb 100644 --- a/src/main/java/org/traccar/api/resource/PositionResource.java +++ b/src/main/java/org/traccar/api/resource/PositionResource.java @@ -18,6 +18,7 @@ package org.traccar.api.resource; import org.traccar.Context; import org.traccar.api.BaseResource; import org.traccar.model.Position; +import org.traccar.model.UserRestrictions; import org.traccar.storage.StorageException; import javax.ws.rs.Consumes; @@ -55,7 +56,7 @@ public class PositionResource extends BaseResource { } else { Context.getPermissionsManager().checkDevice(getUserId(), deviceId); if (from != null && to != null) { - permissionsService.checkReports(getUserId()); + permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return Context.getDataManager().getPositions(deviceId, from, to); } else { return Collections.singleton(Context.getDeviceManager().getLastPosition(deviceId)); diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java index 901385d0d..06ccbe4fd 100644 --- a/src/main/java/org/traccar/api/resource/ReportResource.java +++ b/src/main/java/org/traccar/api/resource/ReportResource.java @@ -42,6 +42,7 @@ import org.traccar.api.BaseResource; import org.traccar.helper.LogAction; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.model.UserRestrictions; import org.traccar.reports.Events; import org.traccar.reports.Summary; import org.traccar.reports.Trips; @@ -99,7 +100,7 @@ public class ReportResource extends BaseResource { public Collection getRoute( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { - permissionsService.checkReports(getUserId()); + permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds); return Route.getObjects(getUserId(), deviceIds, groupIds, from, to); } @@ -111,7 +112,7 @@ public class ReportResource extends BaseResource { @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail) throws StorageException, IOException { - permissionsService.checkReports(getUserId()); + permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds); Route.getExcel(stream, getUserId(), deviceIds, groupIds, from, to); @@ -124,7 +125,7 @@ public class ReportResource extends BaseResource { @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("type") final List types, @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { - permissionsService.checkReports(getUserId()); + permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds); return Events.getObjects(getUserId(), deviceIds, groupIds, types, from, to); } @@ -137,7 +138,7 @@ public class ReportResource extends BaseResource { @QueryParam("type") final List types, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail) throws StorageException, IOException { - permissionsService.checkReports(getUserId()); + permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds); Events.getExcel(stream, getUserId(), deviceIds, groupIds, types, from, to); @@ -150,7 +151,7 @@ public class ReportResource extends BaseResource { @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("daily") boolean daily) throws StorageException { - permissionsService.checkReports(getUserId()); + permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds); return Summary.getObjects(getUserId(), deviceIds, groupIds, from, to, daily); } @@ -163,7 +164,7 @@ public class ReportResource extends BaseResource { @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("daily") boolean daily, @QueryParam("mail") boolean mail) throws StorageException, IOException { - permissionsService.checkReports(getUserId()); + permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds); Summary.getExcel(stream, getUserId(), deviceIds, groupIds, from, to, daily); @@ -176,7 +177,7 @@ public class ReportResource extends BaseResource { public Collection getTrips( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { - permissionsService.checkReports(getUserId()); + permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds); return Trips.getObjects(getUserId(), deviceIds, groupIds, from, to); } @@ -188,7 +189,7 @@ public class ReportResource extends BaseResource { @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail) throws StorageException, IOException { - permissionsService.checkReports(getUserId()); + permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds); Trips.getExcel(stream, getUserId(), deviceIds, groupIds, from, to); @@ -201,7 +202,7 @@ public class ReportResource extends BaseResource { public Collection getStops( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { - permissionsService.checkReports(getUserId()); + permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds); return Stops.getObjects(getUserId(), deviceIds, groupIds, from, to); } @@ -213,7 +214,7 @@ public class ReportResource extends BaseResource { @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail) throws StorageException, IOException { - permissionsService.checkReports(getUserId()); + permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds); Stops.getExcel(stream, getUserId(), deviceIds, groupIds, from, to); diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java index 9daef355e..b4a375109 100644 --- a/src/main/java/org/traccar/api/security/PermissionsService.java +++ b/src/main/java/org/traccar/api/security/PermissionsService.java @@ -25,6 +25,7 @@ import org.traccar.model.ManagedUser; import org.traccar.model.ScheduledModel; import org.traccar.model.Server; import org.traccar.model.User; +import org.traccar.model.UserRestrictions; import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; @@ -71,10 +72,15 @@ public class PermissionsService { } } - public void checkReports(long userId) throws StorageException, SecurityException { + public interface CheckRestrictionCallback { + boolean denied(UserRestrictions userRestrictions); + } + + public void checkRestriction( + long userId, CheckRestrictionCallback callback) throws StorageException, SecurityException { if (!getUser(userId).getAdministrator() - && (getServer().getDisableReports() || getUser(userId).getDisableReports())) { - throw new SecurityException("Reports are disabled"); + && (callback.denied(getServer()) || callback.denied(getUser(userId)))) { + throw new SecurityException("Operation restricted"); } } -- cgit v1.2.3