diff options
17 files changed, 241 insertions, 209 deletions
diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java index 71ef686fa..5b3f129de 100644 --- a/src/main/java/org/traccar/BaseProtocolDecoder.java +++ b/src/main/java/org/traccar/BaseProtocolDecoder.java @@ -15,7 +15,6 @@ */ package org.traccar; -import com.google.inject.Inject; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import org.traccar.config.Config; @@ -32,6 +31,7 @@ import org.traccar.session.ConnectionManager; import org.traccar.session.DeviceSession; import org.traccar.storage.StorageException; +import javax.inject.Inject; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Collection; @@ -51,6 +51,7 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { private ConnectionManager connectionManager; private StatisticsManager statisticsManager; private MediaManager mediaManager; + private CommandsManager commandsManager; public BaseProtocolDecoder(Protocol protocol) { this.protocol = protocol; @@ -96,6 +97,15 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { this.mediaManager = mediaManager; } + @Inject + public void setCommandsManager(CommandsManager commandsManager) { + this.commandsManager = commandsManager; + } + + public CommandsManager getCommandsManager() { + return commandsManager; + } + public String writeMediaFile(String uniqueId, ByteBuf buf, String extension) { return mediaManager.writeFile(uniqueId, buf, extension); } @@ -204,11 +214,8 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { } protected void sendQueuedCommands(Channel channel, SocketAddress remoteAddress, long deviceId) { - CommandsManager commandsManager = Context.getCommandsManager(); - if (commandsManager != null) { - for (Command command : commandsManager.readQueuedCommands(deviceId)) { - protocol.sendDataCommand(channel, remoteAddress, command); - } + for (Command command : commandsManager.readQueuedCommands(deviceId)) { + protocol.sendDataCommand(channel, remoteAddress, command); } } diff --git a/src/main/java/org/traccar/Context.java b/src/main/java/org/traccar/Context.java index 4eab36a89..6ee8344ce 100644 --- a/src/main/java/org/traccar/Context.java +++ b/src/main/java/org/traccar/Context.java @@ -25,7 +25,6 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.database.BaseObjectManager; import org.traccar.database.CalendarManager; -import org.traccar.database.CommandsManager; import org.traccar.session.ConnectionManager; import org.traccar.database.DataManager; import org.traccar.database.DeviceManager; @@ -45,7 +44,6 @@ import org.traccar.helper.Log; import org.traccar.helper.SanitizerModule; import org.traccar.model.BaseModel; import org.traccar.model.Calendar; -import org.traccar.model.Command; import org.traccar.model.Device; import org.traccar.model.Driver; import org.traccar.model.Geofence; @@ -217,12 +215,6 @@ public final class Context { return driversManager; } - private static CommandsManager commandsManager; - - public static CommandsManager getCommandsManager() { - return commandsManager; - } - private static MaintenancesManager maintenancesManager; public static MaintenancesManager getMaintenancesManager() { @@ -337,8 +329,6 @@ public final class Context { driversManager = new DriversManager(dataManager); - commandsManager = new CommandsManager(dataManager, config.getBoolean(Keys.COMMANDS_QUEUEING)); - orderManager = new OrderManager(dataManager); } @@ -392,8 +382,6 @@ public final class Context { return (BaseObjectManager<T>) geofenceManager; } else if (clazz.equals(Driver.class)) { return (BaseObjectManager<T>) driversManager; - } else if (clazz.equals(Command.class)) { - return (BaseObjectManager<T>) commandsManager; } else if (clazz.equals(Maintenance.class)) { return (BaseObjectManager<T>) maintenancesManager; } else if (clazz.equals(Notification.class)) { diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index f46312221..7b46656b3 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -60,6 +60,7 @@ import org.traccar.handler.GeocoderHandler; import org.traccar.handler.GeolocationHandler; import org.traccar.handler.SpeedLimitHandler; import org.traccar.reports.model.TripsConfig; +import org.traccar.sms.SmsManager; import org.traccar.speedlimit.OverpassSpeedLimitProvider; import org.traccar.speedlimit.SpeedLimitProvider; import org.traccar.storage.Storage; @@ -134,6 +135,11 @@ public class MainModule extends AbstractModule { return Context.getMaintenancesManager(); } + @Provides + public static SmsManager provideSmsManager() { + return Context.getSmsManager(); + } + @Singleton @Provides public static Geocoder provideGeocoder(Config config) { 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<Command> { + 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<Command> get(@QueryParam("deviceId") long deviceId) { - 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); + public Collection<Command> 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<Command> { @Path("types") public Collection<Typed> 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<Typed> 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<Position> getRoute( @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> 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<Long> deviceIds, @QueryParam("groupId") final List<Long> 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<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds, @QueryParam("type") final List<String> 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<String> 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<Long> deviceIds, @QueryParam("groupId") final List<Long> 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<TripReport> getTrips( @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> 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<Long> deviceIds, @QueryParam("groupId") final List<Long> 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<StopReport> getStops( @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> 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<Long> deviceIds, @QueryParam("groupId") final List<Long> 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"); } } diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java index 57ce0f9a4..d440755f7 100644 --- a/src/main/java/org/traccar/database/CommandsManager.java +++ b/src/main/java/org/traccar/database/CommandsManager.java @@ -16,66 +16,75 @@ */ package org.traccar.database; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; +import org.traccar.BaseProtocol; +import org.traccar.ServerManager; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.Command; +import org.traccar.model.Device; +import org.traccar.model.Position; +import org.traccar.session.ConnectionManager; +import org.traccar.session.DeviceSession; +import org.traccar.sms.SmsManager; +import org.traccar.storage.Storage; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Singleton; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.BaseProtocol; -import org.traccar.Context; -import org.traccar.model.Command; -import org.traccar.model.Typed; -import org.traccar.model.Position; -import org.traccar.session.DeviceSession; - -public class CommandsManager extends ExtendedObjectManager<Command> { +@Singleton +public class CommandsManager { - private static final Logger LOGGER = LoggerFactory.getLogger(CommandsManager.class); + private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final Map<Long, Queue<Command>> deviceQueues = new ConcurrentHashMap<>(); - private final boolean queueing; + private final Storage storage; + private final ServerManager serverManager; + private final SmsManager smsManager; + private final ConnectionManager connectionManager; - public CommandsManager(DataManager dataManager, boolean queueing) { - super(dataManager, Command.class); - this.queueing = queueing; - } + private final boolean queueing; - public boolean checkDeviceCommand(long deviceId, long commandId) { - return !getAllDeviceItems(deviceId).contains(commandId); + @Inject + public CommandsManager( + Storage storage, ServerManager serverManager, @Nullable SmsManager smsManager, + ConnectionManager connectionManager, Config config) { + this.storage = storage; + this.serverManager = serverManager; + this.smsManager = smsManager; + this.connectionManager = connectionManager; + queueing = config.getBoolean(Keys.COMMANDS_QUEUEING); } public boolean sendCommand(Command command) throws Exception { long deviceId = command.getDeviceId(); - if (command.getId() != 0) { - command = getById(command.getId()).clone(); - command.setDeviceId(deviceId); - } if (command.getTextChannel()) { - Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId); - String phone = Context.getIdentityManager().getById(deviceId).getPhone(); - if (lastPosition != null) { - BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol()); - protocol.sendTextCommand(phone, command); + Device device = storage.getObject(Device.class, new Request( + new Columns.All(), new Condition.Equals("id", "id", deviceId))); + Position position = storage.getObject(Position.class, new Request( + new Columns.All(), new Condition.Equals("id", "id", device.getPositionId()))); + if (position != null) { + BaseProtocol protocol = serverManager.getProtocol(position.getProtocol()); + protocol.sendTextCommand(device.getPhone(), command); } else if (command.getType().equals(Command.TYPE_CUSTOM)) { - if (Context.getSmsManager() != null) { - Context.getSmsManager().sendMessageSync(phone, command.getString(Command.KEY_DATA), true); - } else { - throw new RuntimeException("SMS is not enabled"); - } + smsManager.sendMessageSync(device.getPhone(), command.getString(Command.KEY_DATA), true); } else { throw new RuntimeException("Command " + command.getType() + " is not supported"); } } else { - DeviceSession deviceSession = Context.getConnectionManager().getDeviceSession(deviceId); + DeviceSession deviceSession = connectionManager.getDeviceSession(deviceId); if (deviceSession != null) { if (deviceSession.supportsLiveCommands()) { deviceSession.sendCommand(command); @@ -93,76 +102,22 @@ public class CommandsManager extends ExtendedObjectManager<Command> { return true; } - public Collection<Long> getSupportedCommands(long deviceId) { - List<Long> result = new ArrayList<>(); - Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId); - for (long commandId : getAllDeviceItems(deviceId)) { - Command command = getById(commandId); - if (lastPosition != null) { - BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol()); - if (command.getTextChannel() && protocol.getSupportedTextCommands().contains(command.getType()) - || !command.getTextChannel() - && protocol.getSupportedDataCommands().contains(command.getType())) { - result.add(commandId); - } - } else if (command.getType().equals(Command.TYPE_CUSTOM)) { - result.add(commandId); - } - } - return result; - } - - public Collection<Typed> getCommandTypes(long deviceId, boolean textChannel) { - Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId); - if (lastPosition != null) { - return getCommandTypes(lastPosition.getProtocol(), textChannel); - } else { - return Collections.singletonList(new Typed(Command.TYPE_CUSTOM)); - } - } - - public Collection<Typed> getCommandTypes(String protocolName, boolean textChannel) { - List<Typed> result = new ArrayList<>(); - BaseProtocol protocol = Context.getServerManager().getProtocol(protocolName); - Collection<String> commands; - commands = textChannel ? protocol.getSupportedTextCommands() : protocol.getSupportedDataCommands(); - for (String commandKey : commands) { - result.add(new Typed(commandKey)); - } - return result; - } - - public Collection<Typed> getAllCommandTypes() { - List<Typed> 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; - } - private Queue<Command> getDeviceQueue(long deviceId) { Queue<Command> deviceQueue; try { - readLock(); + lock.readLock().lock(); deviceQueue = deviceQueues.get(deviceId); } finally { - readUnlock(); + lock.readLock().unlock(); } if (deviceQueue != null) { return deviceQueue; } else { try { - writeLock(); + lock.writeLock().lock(); return deviceQueues.computeIfAbsent(deviceId, key -> new ConcurrentLinkedQueue<>()); } finally { - writeUnlock(); + lock.writeLock().unlock(); } } } @@ -174,10 +129,10 @@ public class CommandsManager extends ExtendedObjectManager<Command> { public Collection<Command> readQueuedCommands(long deviceId, int count) { Queue<Command> deviceQueue; try { - readLock(); + lock.readLock().lock(); deviceQueue = deviceQueues.get(deviceId); } finally { - readUnlock(); + lock.readLock().unlock(); } Collection<Command> result = new ArrayList<>(); if (deviceQueue != null) { diff --git a/src/main/java/org/traccar/database/DataManager.java b/src/main/java/org/traccar/database/DataManager.java index b5966ca9e..1426daea3 100644 --- a/src/main/java/org/traccar/database/DataManager.java +++ b/src/main/java/org/traccar/database/DataManager.java @@ -50,8 +50,6 @@ import java.lang.reflect.Method; import java.net.URL; import java.util.Collection; import java.util.Date; -import java.util.LinkedList; -import java.util.List; public class DataManager { @@ -205,14 +203,9 @@ public class DataManager { } public Collection<Position> getLatestPositions() throws StorageException { - List<Position> positions = new LinkedList<>(); - List<Device> devices = storage.getObjects(Device.class, new Request(new Columns.Include("positionId"))); - for (Device device : devices) { - positions.addAll(storage.getObjects(Position.class, new Request( - new Columns.All(), - new Condition.Equals("id", "id", device.getPositionId())))); - } - return positions; + return storage.getObjects(Position.class, new Request( + new Columns.All(), + new Condition.LatestPositions())); } public Server getServer() throws StorageException { diff --git a/src/main/java/org/traccar/database/PermissionsManager.java b/src/main/java/org/traccar/database/PermissionsManager.java index 29bb8a27b..4d5c59fcc 100644 --- a/src/main/java/org/traccar/database/PermissionsManager.java +++ b/src/main/java/org/traccar/database/PermissionsManager.java @@ -20,7 +20,6 @@ import org.slf4j.LoggerFactory; import org.traccar.Context; import org.traccar.model.BaseModel; import org.traccar.model.Calendar; -import org.traccar.model.Command; import org.traccar.model.Device; import org.traccar.model.Driver; import org.traccar.model.Geofence; @@ -274,18 +273,6 @@ public class PermissionsManager { } } - public void checkLimitCommands(long userId) throws SecurityException { - if (!getUserAdmin(userId) && (server.getLimitCommands() || getUserLimitCommands(userId))) { - throw new SecurityException("Account has limit sending commands"); - } - } - - public void checkUserDeviceCommand(long userId, long deviceId, long commandId) throws SecurityException { - if (!getUserAdmin(userId) && Context.getCommandsManager().checkDeviceCommand(deviceId, commandId)) { - throw new SecurityException("Command can not be sent to this device"); - } - } - public void checkUserEnabled(long userId) throws SecurityException { User user = getUser(userId); if (user == null) { @@ -367,21 +354,9 @@ public class PermissionsManager { if (object.equals(Device.class)) { checkDevice(userId, objectId); - } else if (object.equals(Command.class)) { - manager = Context.getCommandsManager(); } else { throw new IllegalArgumentException("Unknown object type"); } - - if (manager != null && !manager.checkItemPermission(userId, objectId) && !getUserAdmin(userId)) { - checkManager(userId); - for (long managedUserId : usersManager.getManagedItems(userId)) { - if (manager.checkItemPermission(managedUserId, objectId)) { - return; - } - } - throw new SecurityException("Type " + object + " access denied"); - } } public void refreshAllUsersPermissions() { @@ -390,7 +365,6 @@ public class PermissionsManager { } Context.getCalendarManager().refreshUserItems(); Context.getDriversManager().refreshUserItems(); - Context.getCommandsManager().refreshUserItems(); Context.getMaintenancesManager().refreshUserItems(); if (Context.getNotificationManager() != null) { Context.getNotificationManager().refreshUserItems(); @@ -402,7 +376,6 @@ public class PermissionsManager { Context.getGeofenceManager().refreshExtendedPermissions(); } Context.getDriversManager().refreshExtendedPermissions(); - Context.getCommandsManager().refreshExtendedPermissions(); Context.getMaintenancesManager().refreshExtendedPermissions(); } @@ -420,8 +393,6 @@ public class PermissionsManager { Context.getDriversManager().refreshUserItems(); } else if (permission.getPropertyClass().equals(Calendar.class)) { Context.getCalendarManager().refreshUserItems(); - } else if (permission.getPropertyClass().equals(Command.class)) { - Context.getCommandsManager().refreshUserItems(); } else if (permission.getPropertyClass().equals(Maintenance.class)) { Context.getMaintenancesManager().refreshUserItems(); } else if (permission.getPropertyClass().equals(Order.class)) { @@ -435,8 +406,6 @@ public class PermissionsManager { Context.getGeofenceManager().refreshExtendedPermissions(); } else if (permission.getPropertyClass().equals(Driver.class)) { Context.getDriversManager().refreshExtendedPermissions(); - } else if (permission.getPropertyClass().equals(Command.class)) { - Context.getCommandsManager().refreshExtendedPermissions(); } else if (permission.getPropertyClass().equals(Maintenance.class)) { Context.getMaintenancesManager().refreshExtendedPermissions(); } else if (permission.getPropertyClass().equals(Order.class)) { diff --git a/src/main/java/org/traccar/model/Server.java b/src/main/java/org/traccar/model/Server.java index b48e84939..7cffd7eac 100644 --- a/src/main/java/org/traccar/model/Server.java +++ b/src/main/java/org/traccar/model/Server.java @@ -22,7 +22,7 @@ import org.traccar.storage.StorageName; @StorageName("tc_servers") @JsonIgnoreProperties(ignoreUnknown = true) -public class Server extends ExtendedModel { +public class Server extends ExtendedModel implements UserRestrictions { private boolean registration; @@ -36,6 +36,7 @@ public class Server extends ExtendedModel { private boolean readonly; + @Override public boolean getReadonly() { return readonly; } @@ -46,6 +47,7 @@ public class Server extends ExtendedModel { private boolean deviceReadonly; + @Override public boolean getDeviceReadonly() { return deviceReadonly; } @@ -146,6 +148,7 @@ public class Server extends ExtendedModel { private boolean limitCommands; + @Override public boolean getLimitCommands() { return limitCommands; } @@ -156,6 +159,7 @@ public class Server extends ExtendedModel { private boolean disableReports; + @Override public boolean getDisableReports() { return disableReports; } diff --git a/src/main/java/org/traccar/model/User.java b/src/main/java/org/traccar/model/User.java index 6a67f3276..12fd03d45 100644 --- a/src/main/java/org/traccar/model/User.java +++ b/src/main/java/org/traccar/model/User.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2022 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. @@ -25,7 +25,7 @@ import org.traccar.storage.StorageName; import java.util.Date; @StorageName("tc_users") -public class User extends ExtendedModel { +public class User extends ExtendedModel implements UserRestrictions { private String name; @@ -69,6 +69,7 @@ public class User extends ExtendedModel { private boolean readonly; + @Override public boolean getReadonly() { return readonly; } @@ -195,6 +196,7 @@ public class User extends ExtendedModel { private boolean deviceReadonly; + @Override public boolean getDeviceReadonly() { return deviceReadonly; } @@ -222,6 +224,7 @@ public class User extends ExtendedModel { private boolean limitCommands; + @Override public boolean getLimitCommands() { return limitCommands; } @@ -234,6 +237,7 @@ public class User extends ExtendedModel { private boolean disableReports; + @Override public boolean getDisableReports() { return disableReports; } diff --git a/src/main/java/org/traccar/model/UserRestrictions.java b/src/main/java/org/traccar/model/UserRestrictions.java new file mode 100644 index 000000000..2e4e5e363 --- /dev/null +++ b/src/main/java/org/traccar/model/UserRestrictions.java @@ -0,0 +1,23 @@ +/* + * Copyright 2022 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.model; + +public interface UserRestrictions { + boolean getReadonly(); + boolean getDeviceReadonly(); + boolean getLimitCommands(); + boolean getDisableReports(); +} diff --git a/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java b/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java index 178ec344f..3574dd2a3 100644 --- a/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java @@ -21,10 +21,8 @@ import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.QueryStringDecoder; import org.traccar.BaseHttpProtocolDecoder; -import org.traccar.Context; import org.traccar.session.DeviceSession; import org.traccar.Protocol; -import org.traccar.database.CommandsManager; import org.traccar.helper.DateUtil; import org.traccar.model.CellTower; import org.traccar.model.Command; @@ -178,11 +176,8 @@ public class OsmAndProtocolDecoder extends BaseHttpProtocolDecoder { if (position.getDeviceId() != 0) { String response = null; - CommandsManager commandsManager = Context.getCommandsManager(); - if (commandsManager != null) { - for (Command command : commandsManager.readQueuedCommands(position.getDeviceId(), 1)) { - response = command.getString(Command.KEY_DATA); - } + for (Command command : getCommandsManager().readQueuedCommands(position.getDeviceId(), 1)) { + response = command.getString(Command.KEY_DATA); } if (response != null) { sendResponse(channel, HttpResponseStatus.OK, Unpooled.copiedBuffer(response, StandardCharsets.UTF_8)); diff --git a/src/main/java/org/traccar/storage/DatabaseStorage.java b/src/main/java/org/traccar/storage/DatabaseStorage.java index 91dd6b077..fc468182e 100644 --- a/src/main/java/org/traccar/storage/DatabaseStorage.java +++ b/src/main/java/org/traccar/storage/DatabaseStorage.java @@ -209,6 +209,11 @@ public class DatabaseStorage extends Storage { } else { results.put(Permission.getKey(condition.getPropertyClass()), condition.getPropertyId()); } + } else if (genericCondition instanceof Condition.LatestPositions) { + var condition = (Condition.LatestPositions) genericCondition; + if (condition.getDeviceId() > 0) { + results.put("deviceId", condition.getDeviceId()); + } } return results; } @@ -262,6 +267,17 @@ public class DatabaseStorage extends Storage { result.append(formatPermissionQuery(condition)); result.append(")"); + } else if (genericCondition instanceof Condition.LatestPositions) { + + var condition = (Condition.LatestPositions) genericCondition; + result.append("id IN ("); + result.append("SELECT positionId FROM "); + result.append(getStorageName(Device.class)); + if (condition.getDeviceId() > 0) { + result.append(" WHERE id = :deviceId"); + } + result.append(")"); + } } return result.toString(); diff --git a/src/main/java/org/traccar/storage/query/Condition.java b/src/main/java/org/traccar/storage/query/Condition.java index 91ede236c..136b0402b 100644 --- a/src/main/java/org/traccar/storage/query/Condition.java +++ b/src/main/java/org/traccar/storage/query/Condition.java @@ -196,4 +196,20 @@ public interface Condition { } } + class LatestPositions implements Condition { + private final long deviceId; + + public LatestPositions(long deviceId) { + this.deviceId = deviceId; + } + + public LatestPositions() { + this(0); + } + + public long getDeviceId() { + return deviceId; + } + } + } diff --git a/src/test/java/org/traccar/BaseTest.java b/src/test/java/org/traccar/BaseTest.java index a34524c43..1652a6694 100644 --- a/src/test/java/org/traccar/BaseTest.java +++ b/src/test/java/org/traccar/BaseTest.java @@ -2,6 +2,7 @@ package org.traccar; import io.netty.channel.Channel; import org.traccar.config.Config; +import org.traccar.database.CommandsManager; import org.traccar.database.IdentityManager; import org.traccar.database.MediaManager; import org.traccar.database.StatisticsManager; @@ -52,6 +53,7 @@ public class BaseTest { decoder.setConnectionManager(connectionManager); decoder.setStatisticsManager(mock(StatisticsManager.class)); decoder.setMediaManager(mock(MediaManager.class)); + decoder.setCommandsManager(mock(CommandsManager.class)); return decoder; } |