diff options
author | Anton Tananaev <anton.tananaev@gmail.com> | 2017-07-14 21:19:53 +1200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-07-14 21:19:53 +1200 |
commit | 26f1cf12867d6f8bfe86d562a3beecb590b3a9b5 (patch) | |
tree | ef3b8d2644aae5c5263241640ebb2e2b251f7b0c | |
parent | a2e1f56adf50746425565557dd38f0e2c81a0222 (diff) | |
parent | b6a318daabbaf485e327cab77adba98413462516 (diff) | |
download | trackermap-server-26f1cf12867d6f8bfe86d562a3beecb590b3a9b5.tar.gz trackermap-server-26f1cf12867d6f8bfe86d562a3beecb590b3a9b5.tar.bz2 trackermap-server-26f1cf12867d6f8bfe86d562a3beecb590b3a9b5.zip |
Merge pull request #3349 from Abyss777/drivers
Drivers implementation
48 files changed, 1060 insertions, 25 deletions
diff --git a/schema/changelog-3.14.xml b/schema/changelog-3.14.xml new file mode 100644 index 000000000..7965bc020 --- /dev/null +++ b/schema/changelog-3.14.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> +<databaseChangeLog + xmlns="http://www.liquibase.org/xml/ns/dbchangelog" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog + http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd" + logicalFilePath="changelog-3.14"> + + <changeSet author="author" id="changelog-3.14"> + + <createTable tableName="drivers"> + <column name="id" type="INT" autoIncrement="true"> + <constraints primaryKey="true" /> + </column> + <column name="name" type="VARCHAR(128)"> + <constraints nullable="false" /> + </column> + <column name="uniqueid" type="VARCHAR(128)"> + <constraints nullable="false" /> + </column> + <column name="attributes" type="VARCHAR(4000)"> + <constraints nullable="false" /> + </column> + </createTable> + + <addUniqueConstraint tableName="drivers" columnNames="uniqueid" constraintName="uk_driver_uniqueid" /> + + <createTable tableName="user_driver"> + <column name="userid" type="INT"> + <constraints nullable="false" /> + </column> + <column name="driverid" type="INT"> + <constraints nullable="false" /> + </column> + </createTable> + + <addForeignKeyConstraint baseTableName="user_driver" baseColumnNames="userid" constraintName="fk_user_driver_userid" referencedTableName="users" referencedColumnNames="id" onDelete="CASCADE" /> + <addForeignKeyConstraint baseTableName="user_driver" baseColumnNames="driverid" constraintName="fk_user_driver_driverid" referencedTableName="drivers" referencedColumnNames="id" onDelete="CASCADE" /> + + <createTable tableName="group_driver"> + <column name="groupid" type="INT"> + <constraints nullable="false" /> + </column> + <column name="driverid" type="INT"> + <constraints nullable="false" /> + </column> + </createTable> + + <addForeignKeyConstraint baseTableName="group_driver" baseColumnNames="groupid" constraintName="fk_group_driver_groupid" referencedTableName="groups" referencedColumnNames="id" onDelete="CASCADE" /> + <addForeignKeyConstraint baseTableName="group_driver" baseColumnNames="driverid" constraintName="fk_group_driver_driverid" referencedTableName="drivers" referencedColumnNames="id" onDelete="CASCADE" /> + + <createTable tableName="device_driver"> + <column name="deviceid" type="INT"> + <constraints nullable="false" /> + </column> + <column name="driverid" type="INT"> + <constraints nullable="false" /> + </column> + </createTable> + + <addForeignKeyConstraint baseTableName="device_driver" baseColumnNames="deviceid" constraintName="fk_device_driver_deviceid" referencedTableName="devices" referencedColumnNames="id" onDelete="CASCADE" /> + <addForeignKeyConstraint baseTableName="device_driver" baseColumnNames="driverid" constraintName="fk_device_driver_driverid" referencedTableName="drivers" referencedColumnNames="id" onDelete="CASCADE" /> + + </changeSet> +</databaseChangeLog>
\ No newline at end of file diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml index ba93d105f..d1b51b40e 100644 --- a/schema/changelog-master.xml +++ b/schema/changelog-master.xml @@ -14,4 +14,5 @@ <include file="changelog-3.10.xml" relativeToChangelogFile="true" /> <include file="changelog-3.11.xml" relativeToChangelogFile="true" /> <include file="changelog-3.12.xml" relativeToChangelogFile="true" /> + <include file="changelog-3.14.xml" relativeToChangelogFile="true" /> </databaseChangeLog> diff --git a/setup/default.xml b/setup/default.xml index 2fc6c3cf0..04530104a 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -431,6 +431,63 @@ DELETE FROM device_attribute WHERE deviceId = :deviceId AND attributeId = :attributeId </entry> + <entry key='database.selectDrivers'> + SELECT * FROM drivers + </entry> + + <entry key='database.insertDriver'> + INSERT INTO drivers (name, uniqueId, attributes) + VALUES (:name, :uniqueId, :attributes) + </entry> + + <entry key='database.updateDriver'> + UPDATE drivers SET + name = :name, + uniqueId = :uniqueId, + attributes = :attributes + WHERE id = :id + </entry> + + <entry key='database.deleteDriver'> + DELETE FROM drivers WHERE id = :id + </entry> + + <entry key='database.selectDriverPermissions'> + SELECT userId, driverId FROM user_driver + </entry> + + <entry key='database.linkDriver'> + INSERT INTO user_driver (userId, driverId) VALUES (:userId, :driverId) + </entry> + + <entry key='database.unlinkDriver'> + DELETE FROM user_driver WHERE userId = :userId AND driverId = :driverId + </entry> + + <entry key='database.selectGroupDrivers'> + SELECT groupId, driverId FROM group_driver + </entry> + + <entry key='database.linkGroupDriver'> + INSERT INTO group_driver (groupId, driverId) VALUES (:groupId, :driverId) + </entry> + + <entry key='database.unlinkGroupDriver'> + DELETE FROM group_driver WHERE groupId = :groupId AND driverId = :driverId + </entry> + + <entry key='database.selectDeviceDrivers'> + SELECT deviceId, driverId FROM device_driver + </entry> + + <entry key='database.linkDeviceDriver'> + INSERT INTO device_driver (deviceId, driverId) VALUES (:deviceId, :driverId) + </entry> + + <entry key='database.unlinkDeviceDriver'> + DELETE FROM device_driver WHERE deviceId = :deviceId AND driverId = :driverId + </entry> + <!-- PROTOCOL CONFIG --> <entry key='gps103.port'>5001</entry> diff --git a/src/org/traccar/BasePipelineFactory.java b/src/org/traccar/BasePipelineFactory.java index bde4b558b..b368c800d 100644 --- a/src/org/traccar/BasePipelineFactory.java +++ b/src/org/traccar/BasePipelineFactory.java @@ -30,6 +30,7 @@ import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.handler.logging.LoggingHandler; import org.jboss.netty.handler.timeout.IdleStateHandler; import org.traccar.events.CommandResultEventHandler; +import org.traccar.events.DriverEventHandler; import org.traccar.events.FuelDropEventHandler; import org.traccar.events.GeofenceEventHandler; import org.traccar.events.IgnitionEventHandler; @@ -65,6 +66,7 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory { private AlertEventHandler alertEventHandler; private IgnitionEventHandler ignitionEventHandler; private MaintenanceEventHandler maintenanceEventHandler; + private DriverEventHandler driverEventHandler; private static final class OpenChannelHandler extends SimpleChannelHandler { @@ -170,6 +172,7 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory { alertEventHandler = new AlertEventHandler(); ignitionEventHandler = new IgnitionEventHandler(); maintenanceEventHandler = new MaintenanceEventHandler(); + driverEventHandler = new DriverEventHandler(); } } @@ -263,6 +266,10 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory { pipeline.addLast("MaintenanceEventHandler", maintenanceEventHandler); } + if (driverEventHandler != null) { + pipeline.addLast("DriverEventHandler", driverEventHandler); + } + pipeline.addLast("mainHandler", new MainEventHandler()); return pipeline; } diff --git a/src/org/traccar/Context.java b/src/org/traccar/Context.java index 9626d949c..a4fc5b679 100644 --- a/src/org/traccar/Context.java +++ b/src/org/traccar/Context.java @@ -31,6 +31,7 @@ import org.traccar.database.AttributesManager; import org.traccar.database.ConnectionManager; import org.traccar.database.DataManager; import org.traccar.database.DeviceManager; +import org.traccar.database.DriversManager; import org.traccar.database.IdentityManager; import org.traccar.database.MediaManager; import org.traccar.database.NotificationManager; @@ -187,6 +188,12 @@ public final class Context { return attributesManager; } + private static DriversManager driversManager; + + public static DriversManager getDriversManager() { + return driversManager; + } + private static StatisticsManager statisticsManager; public static StatisticsManager getStatisticsManager() { @@ -330,6 +337,8 @@ public final class Context { attributesManager = new AttributesManager(dataManager); + driversManager = new DriversManager(dataManager); + statisticsManager = new StatisticsManager(); if (config.getBoolean("sms.smpp.enable")) { diff --git a/src/org/traccar/api/resource/DeviceDriverResource.java b/src/org/traccar/api/resource/DeviceDriverResource.java new file mode 100644 index 000000000..341c50909 --- /dev/null +++ b/src/org/traccar/api/resource/DeviceDriverResource.java @@ -0,0 +1,58 @@ +/* + * 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 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.model.DeviceDriver; + +@Path("devices/drivers") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class DeviceDriverResource extends BaseResource { + + @POST + public Response add(DeviceDriver entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkDevice(getUserId(), entity.getDeviceId()); + Context.getPermissionsManager().checkDriver(getUserId(), entity.getDriverId()); + Context.getDataManager().linkDeviceDriver(entity.getDeviceId(), entity.getDriverId()); + Context.getDriversManager().refresh(); + return Response.ok(entity).build(); + } + + @DELETE + public Response remove(DeviceDriver entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkDevice(getUserId(), entity.getDeviceId()); + Context.getPermissionsManager().checkDriver(getUserId(), entity.getDriverId()); + Context.getDataManager().unlinkDeviceDriver(entity.getDeviceId(), entity.getDriverId()); + Context.getDriversManager().refresh(); + return Response.noContent().build(); + } + +} diff --git a/src/org/traccar/api/resource/DriverPermissionResource.java b/src/org/traccar/api/resource/DriverPermissionResource.java new file mode 100644 index 000000000..fd1ca7c6d --- /dev/null +++ b/src/org/traccar/api/resource/DriverPermissionResource.java @@ -0,0 +1,59 @@ +/* + * 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 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.model.DriverPermission; + +@Path("permissions/drivers") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class DriverPermissionResource extends BaseResource { + + @POST + public Response add(DriverPermission entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkUser(getUserId(), entity.getUserId()); + Context.getPermissionsManager().checkDriver(getUserId(), entity.getDriverId()); + Context.getDataManager().linkDriver(entity.getUserId(), entity.getDriverId()); + Context.getDriversManager().refreshUserDrivers(); + return Response.ok(entity).build(); + } + + @DELETE + public Response remove(DriverPermission entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkUser(getUserId(), entity.getUserId()); + Context.getPermissionsManager().checkDriver(getUserId(), entity.getDriverId()); + Context.getDataManager().unlinkDriver(entity.getUserId(), entity.getDriverId()); + Context.getDriversManager().refreshUserDrivers(); + return Response.noContent().build(); + } + +} diff --git a/src/org/traccar/api/resource/DriverResource.java b/src/org/traccar/api/resource/DriverResource.java new file mode 100644 index 000000000..7fe0af473 --- /dev/null +++ b/src/org/traccar/api/resource/DriverResource.java @@ -0,0 +1,112 @@ +/* + * 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.Collection; +import java.util.HashSet; +import java.util.Set; + +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 org.traccar.Context; +import org.traccar.api.BaseResource; +import org.traccar.database.DriversManager; +import org.traccar.model.Driver; + +@Path("drivers") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class DriverResource extends BaseResource { + + @GET + public Collection<Driver> get( + @QueryParam("all") boolean all, @QueryParam("userId") long userId, @QueryParam("groupId") long groupId, + @QueryParam("deviceId") long deviceId, @QueryParam("refresh") boolean refresh) throws SQLException { + + DriversManager driversManager = Context.getDriversManager(); + if (refresh) { + driversManager.refreshDrivers(); + } + + Set<Long> result = new HashSet<>(); + if (all) { + if (Context.getPermissionsManager().isAdmin(getUserId())) { + result.addAll(driversManager.getAllDrivers()); + } else { + Context.getPermissionsManager().checkManager(getUserId()); + result.addAll(driversManager.getManagedDrivers(getUserId())); + } + } else { + if (userId == 0) { + userId = getUserId(); + } + Context.getPermissionsManager().checkUser(getUserId(), userId); + result.addAll(driversManager.getUserDrivers(userId)); + } + + if (groupId != 0) { + Context.getPermissionsManager().checkGroup(getUserId(), groupId); + result.retainAll(driversManager.getGroupDrivers(groupId)); + } + + if (deviceId != 0) { + Context.getPermissionsManager().checkDevice(getUserId(), deviceId); + result.retainAll(driversManager.getDeviceDrivers(deviceId)); + } + return driversManager.getDrivers(result); + + } + + @POST + public Response add(Driver entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getDriversManager().addDriver(entity); + Context.getDataManager().linkDriver(getUserId(), entity.getId()); + Context.getDriversManager().refreshUserDrivers(); + return Response.ok(entity).build(); + } + + @Path("{id}") + @PUT + public Response update(Driver entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkDriver(getUserId(), entity.getId()); + Context.getDriversManager().updateDriver(entity); + return Response.ok(entity).build(); + } + + @Path("{id}") + @DELETE + public Response remove(@PathParam("id") long id) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkDriver(getUserId(), id); + Context.getDriversManager().removeDriver(id); + return Response.noContent().build(); + } + +} diff --git a/src/org/traccar/api/resource/GroupDriverResource.java b/src/org/traccar/api/resource/GroupDriverResource.java new file mode 100644 index 000000000..76fc2892c --- /dev/null +++ b/src/org/traccar/api/resource/GroupDriverResource.java @@ -0,0 +1,58 @@ +/* + * 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 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.model.GroupDriver; + +@Path("groups/drivers") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class GroupDriverResource extends BaseResource { + + @POST + public Response add(GroupDriver entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkGroup(getUserId(), entity.getGroupId()); + Context.getPermissionsManager().checkDriver(getUserId(), entity.getDriverId()); + Context.getDataManager().linkGroupDriver(entity.getGroupId(), entity.getDriverId()); + Context.getDriversManager().refresh(); + return Response.ok(entity).build(); + } + + @DELETE + public Response remove(GroupDriver entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkGroup(getUserId(), entity.getGroupId()); + Context.getPermissionsManager().checkDriver(getUserId(), entity.getDriverId()); + Context.getDataManager().unlinkGroupDriver(entity.getGroupId(), entity.getDriverId()); + Context.getDriversManager().refresh(); + return Response.noContent().build(); + } + +} diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java index dd65289e4..1c2a66bcf 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -44,11 +44,15 @@ import org.traccar.model.CalendarPermission; import org.traccar.model.Attribute; import org.traccar.model.Device; import org.traccar.model.DeviceAttribute; +import org.traccar.model.DeviceDriver; import org.traccar.model.DevicePermission; +import org.traccar.model.Driver; +import org.traccar.model.DriverPermission; import org.traccar.model.Event; import org.traccar.model.Geofence; import org.traccar.model.Group; import org.traccar.model.GroupAttribute; +import org.traccar.model.GroupDriver; import org.traccar.model.GroupGeofence; import org.traccar.model.GroupPermission; import org.traccar.model.Notification; @@ -638,4 +642,84 @@ public class DataManager { .executeUpdate(); } + public Collection<Driver> getDrivers() throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectDrivers")) + .executeQuery(Driver.class); + } + + public void addDriver(Driver driver) throws SQLException { + driver.setId(QueryBuilder.create(dataSource, getQuery("database.insertDriver"), true) + .setObject(driver) + .executeUpdate()); + } + + public void updateDriver(Driver driver) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.updateDriver")) + .setObject(driver) + .executeUpdate(); + } + + public void removeDriver(long driverId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.deleteDriver")) + .setLong("id", driverId) + .executeUpdate(); + } + + public Collection<DriverPermission> getDriverPermissions() throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectDriverPermissions")) + .executeQuery(DriverPermission.class); + } + + public void linkDriver(long userId, long driverId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.linkDriver")) + .setLong("userId", userId) + .setLong("driverId", driverId) + .executeUpdate(); + } + + public void unlinkDriver(long userId, long driverId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.unlinkDriver")) + .setLong("userId", userId) + .setLong("driverId", driverId) + .executeUpdate(); + } + + public Collection<GroupDriver> getGroupDrivers() throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectGroupDrivers")) + .executeQuery(GroupDriver.class); + } + + public void linkGroupDriver(long groupId, long driverId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.linkGroupDriver")) + .setLong("groupId", groupId) + .setLong("driverId", driverId) + .executeUpdate(); + } + + public void unlinkGroupDriver(long groupId, long driverId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.unlinkGroupDriver")) + .setLong("groupId", groupId) + .setLong("driverId", driverId) + .executeUpdate(); + } + + public Collection<DeviceDriver> getDeviceDrivers() throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectDeviceDrivers")) + .executeQuery(DeviceDriver.class); + } + + public void linkDeviceDriver(long deviceId, long driverId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.linkDeviceDriver")) + .setLong("deviceId", deviceId) + .setLong("driverId", driverId) + .executeUpdate(); + } + + public void unlinkDeviceDriver(long deviceId, long driverId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.unlinkDeviceDriver")) + .setLong("deviceId", deviceId) + .setLong("driverId", driverId) + .executeUpdate(); + } + } diff --git a/src/org/traccar/database/DriversManager.java b/src/org/traccar/database/DriversManager.java new file mode 100644 index 000000000..e89d59311 --- /dev/null +++ b/src/org/traccar/database/DriversManager.java @@ -0,0 +1,213 @@ +/* + * 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.database; + +import java.sql.SQLException; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.traccar.Context; +import org.traccar.helper.Log; +import org.traccar.model.Device; +import org.traccar.model.DeviceDriver; +import org.traccar.model.Driver; +import org.traccar.model.DriverPermission; +import org.traccar.model.GroupDriver; + +public class DriversManager { + + private final DataManager dataManager; + + private final Map<Long, Driver> drivers = new ConcurrentHashMap<>(); + private final Map<String, Driver> driversByUniqueId = new ConcurrentHashMap<>(); + private final Map<Long, Set<Long>> deviceDrivers = new ConcurrentHashMap<>(); + private final Map<Long, Set<Long>> deviceDriversWithGroups = new ConcurrentHashMap<>(); + private final Map<Long, Set<Long>> groupDrivers = new ConcurrentHashMap<>(); + private final Map<Long, Set<Long>> userDrivers = new ConcurrentHashMap<>(); + + public DriversManager(DataManager dataManager) { + this.dataManager = dataManager; + refreshDrivers(); + } + + public Set<Long> getUserDrivers(long userId) { + if (!userDrivers.containsKey(userId)) { + userDrivers.put(userId, new HashSet<Long>()); + } + return userDrivers.get(userId); + } + + public Set<Long> getGroupDrivers(long groupId) { + if (!groupDrivers.containsKey(groupId)) { + groupDrivers.put(groupId, new HashSet<Long>()); + } + return groupDrivers.get(groupId); + } + + public Set<Long> getDeviceDrivers(long deviceId) { + return getDeviceDrivers(deviceDrivers, deviceId); + } + + public Set<Long> getAllDeviceDrivers(long deviceId) { + return getDeviceDrivers(deviceDriversWithGroups, deviceId); + } + + private Set<Long> getDeviceDrivers(Map<Long, Set<Long>> deviceDrivers, long deviceId) { + if (!deviceDrivers.containsKey(deviceId)) { + deviceDrivers.put(deviceId, new HashSet<Long>()); + } + return deviceDrivers.get(deviceId); + } + + public final void refreshDrivers() { + if (dataManager != null) { + try { + drivers.clear(); + driversByUniqueId.clear(); + for (Driver driver : dataManager.getDrivers()) { + drivers.put(driver.getId(), driver); + driversByUniqueId.put(driver.getUniqueId(), driver); + } + } catch (SQLException error) { + Log.warning(error); + } + } + refreshUserDrivers(); + refresh(); + } + + public final void refreshUserDrivers() { + if (dataManager != null) { + try { + userDrivers.clear(); + for (DriverPermission driverPermission : dataManager.getDriverPermissions()) { + getUserDrivers(driverPermission.getUserId()).add(driverPermission.getDriverId()); + } + } catch (SQLException error) { + Log.warning(error); + } + } + } + + public final void refresh() { + if (dataManager != null) { + try { + + Collection<GroupDriver> databaseGroupDrivers = dataManager.getGroupDrivers(); + + groupDrivers.clear(); + for (GroupDriver groupDriver : databaseGroupDrivers) { + getGroupDrivers(groupDriver.getGroupId()).add(groupDriver.getDriverId()); + } + + Collection<DeviceDriver> databaseDeviceDrivers = dataManager.getDeviceDrivers(); + Collection<Device> allDevices = Context.getDeviceManager().getAllDevices(); + + deviceDrivers.clear(); + deviceDriversWithGroups.clear(); + + for (DeviceDriver deviceAttribute : databaseDeviceDrivers) { + getDeviceDrivers(deviceAttribute.getDeviceId()) + .add(deviceAttribute.getDriverId()); + getAllDeviceDrivers(deviceAttribute.getDeviceId()) + .add(deviceAttribute.getDriverId()); + } + + for (Device device : allDevices) { + long groupId = device.getGroupId(); + while (groupId != 0) { + getAllDeviceDrivers(device.getId()).addAll(getGroupDrivers(groupId)); + if (Context.getDeviceManager().getGroupById(groupId) != null) { + groupId = Context.getDeviceManager().getGroupById(groupId).getGroupId(); + } else { + groupId = 0; + } + } + } + + } catch (SQLException error) { + Log.warning(error); + } + } + } + + public void addDriver(Driver driver) throws SQLException { + dataManager.addDriver(driver); + drivers.put(driver.getId(), driver); + driversByUniqueId.put(driver.getUniqueId(), driver); + } + + public void updateDriver(Driver driver) throws SQLException { + dataManager.updateDriver(driver); + Driver cachedDriver = drivers.get(driver.getId()); + cachedDriver.setName(driver.getName()); + if (!driver.getUniqueId().equals(cachedDriver.getUniqueId())) { + driversByUniqueId.remove(cachedDriver.getUniqueId()); + cachedDriver.setUniqueId(driver.getUniqueId()); + driversByUniqueId.put(cachedDriver.getUniqueId(), cachedDriver); + } + cachedDriver.setAttributes(driver.getAttributes()); + } + + public void removeDriver(long driverId) throws SQLException { + dataManager.removeDriver(driverId); + if (drivers.containsKey(driverId)) { + String driverUniqueId = drivers.get(driverId).getUniqueId(); + drivers.remove(driverId); + driversByUniqueId.remove(driverUniqueId); + } + refreshUserDrivers(); + refresh(); + } + + public boolean checkDriver(long userId, long driverId) { + return getUserDrivers(userId).contains(driverId); + } + + public Driver getDriver(long id) { + return drivers.get(id); + } + + public Driver getDriverByUniqueId(String uniqueId) { + return driversByUniqueId.get(uniqueId); + } + + public final Collection<Driver> getDrivers(Set<Long> driverIds) { + Collection<Driver> result = new LinkedList<>(); + for (long driverId : driverIds) { + result.add(getDriver(driverId)); + } + return result; + } + + public final Set<Long> getAllDrivers() { + return drivers.keySet(); + } + + public final Set<Long> getManagedDrivers(long userId) { + Set<Long> drivers = new HashSet<>(); + drivers.addAll(getUserDrivers(userId)); + for (long managedUserId : Context.getPermissionsManager().getUserPermissions(userId)) { + drivers.addAll(getUserDrivers(managedUserId)); + } + return drivers; + } +} diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java index 9a82efd48..82ca6af49 100644 --- a/src/org/traccar/database/PermissionsManager.java +++ b/src/org/traccar/database/PermissionsManager.java @@ -322,6 +322,19 @@ public class PermissionsManager { } } + public void checkDriver(long userId, long driverId) throws SecurityException { + if (!Context.getDriversManager().checkDriver(userId, driverId) && !isAdmin(userId)) { + checkManager(userId); + for (long managedUserId : getUserPermissions(userId)) { + if (Context.getDriversManager().checkDriver(managedUserId, driverId)) { + return; + } + } + throw new SecurityException("Driver access denied"); + } + } + + public void checkCalendar(long userId, long calendarId) throws SecurityException { if (!Context.getCalendarManager().checkCalendar(userId, calendarId) && !isAdmin(userId)) { checkManager(userId); diff --git a/src/org/traccar/events/DriverEventHandler.java b/src/org/traccar/events/DriverEventHandler.java new file mode 100644 index 000000000..eb5f2a301 --- /dev/null +++ b/src/org/traccar/events/DriverEventHandler.java @@ -0,0 +1,50 @@ +/* + * 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.events; + +import java.util.Collection; +import java.util.Collections; + +import org.traccar.BaseEventHandler; +import org.traccar.Context; +import org.traccar.model.Event; +import org.traccar.model.Position; + +public class DriverEventHandler extends BaseEventHandler { + + @Override + protected Collection<Event> analyzePosition(Position position) { + if (!Context.getIdentityManager().isLatestPosition(position)) { + return null; + } + String driverUniqueId = position.getString(Position.KEY_DRIVER_UNIQUE_ID); + if (driverUniqueId != null) { + String oldDriverUniqueId = null; + Position lastPosition = Context.getIdentityManager().getLastPosition(position.getDeviceId()); + if (lastPosition != null) { + oldDriverUniqueId = lastPosition.getString(Position.KEY_DRIVER_UNIQUE_ID); + } + if (!driverUniqueId.equals(oldDriverUniqueId)) { + Event event = new Event(Event.TYPE_DRIVER_CHANGED, position.getDeviceId(), position.getId()); + event.set(Position.KEY_DRIVER_UNIQUE_ID, driverUniqueId); + return Collections.singleton(event); + } + } + return null; + } + +} diff --git a/src/org/traccar/model/DeviceDriver.java b/src/org/traccar/model/DeviceDriver.java new file mode 100644 index 000000000..2008aaddf --- /dev/null +++ b/src/org/traccar/model/DeviceDriver.java @@ -0,0 +1,41 @@ +/* + * 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.model; + +public class DeviceDriver { + + private long deviceId; + + public long getDeviceId() { + return deviceId; + } + + public void setDeviceId(long deviceId) { + this.deviceId = deviceId; + } + + private long driverId; + + public long getDriverId() { + return driverId; + } + + public void setDriverId(long driverId) { + this.driverId = driverId; + } + +} diff --git a/src/org/traccar/model/Driver.java b/src/org/traccar/model/Driver.java new file mode 100644 index 000000000..7a51d9151 --- /dev/null +++ b/src/org/traccar/model/Driver.java @@ -0,0 +1,40 @@ +/* + * 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.model; + +public class Driver extends Extensible { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + private String uniqueId; + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } +} diff --git a/src/org/traccar/model/DriverPermission.java b/src/org/traccar/model/DriverPermission.java new file mode 100644 index 000000000..cdbcc4a50 --- /dev/null +++ b/src/org/traccar/model/DriverPermission.java @@ -0,0 +1,40 @@ +/* + * 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.model; + +public class DriverPermission { + + private long userId; + + public long getUserId() { + return userId; + } + + public void setUserId(long userId) { + this.userId = userId; + } + + private long driverId; + + public long getDriverId() { + return driverId; + } + + public void setDriverId(long driverId) { + this.driverId = driverId; + } +} diff --git a/src/org/traccar/model/Event.java b/src/org/traccar/model/Event.java index 6a24d91c6..2d836abeb 100644 --- a/src/org/traccar/model/Event.java +++ b/src/org/traccar/model/Event.java @@ -61,6 +61,8 @@ public class Event extends Message { public static final String TYPE_TEXT_MESSAGE = "textMessage"; + public static final String TYPE_DRIVER_CHANGED = "driverChanged"; + private Date serverTime; public Date getServerTime() { diff --git a/src/org/traccar/model/GroupDriver.java b/src/org/traccar/model/GroupDriver.java new file mode 100644 index 000000000..91b205923 --- /dev/null +++ b/src/org/traccar/model/GroupDriver.java @@ -0,0 +1,41 @@ +/* + * 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.model; + +public class GroupDriver { + + private long groupId; + + public long getGroupId() { + return groupId; + } + + public void setGroupId(long groupId) { + this.groupId = groupId; + } + + private long driverId; + + public long getDriverId() { + return driverId; + } + + public void setDriverId(long driverId) { + this.driverId = driverId; + } + +} diff --git a/src/org/traccar/model/Position.java b/src/org/traccar/model/Position.java index 5835310ae..9e7bac932 100644 --- a/src/org/traccar/model/Position.java +++ b/src/org/traccar/model/Position.java @@ -49,7 +49,6 @@ public class Position extends Message { public static final String KEY_FUEL_LEVEL = "fuel"; // liters public static final String KEY_FUEL_CONSUMPTION = "fuelConsumption"; // liters/hour - public static final String KEY_RFID = "rfid"; public static final String KEY_VERSION_FW = "versionFw"; public static final String KEY_VERSION_HW = "versionHw"; public static final String KEY_TYPE = "type"; @@ -81,6 +80,8 @@ public class Position extends Message { public static final String KEY_RESULT = "result"; + public static final String KEY_DRIVER_UNIQUE_ID = "driverUniqueId"; + // Start with 1 not 0 public static final String PREFIX_TEMP = "temp"; public static final String PREFIX_ADC = "adc"; diff --git a/src/org/traccar/notification/NotificationFormatter.java b/src/org/traccar/notification/NotificationFormatter.java index 96337ecaa..a30023fdc 100644 --- a/src/org/traccar/notification/NotificationFormatter.java +++ b/src/org/traccar/notification/NotificationFormatter.java @@ -30,6 +30,7 @@ import org.traccar.helper.Log; import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.model.User; import org.traccar.reports.ReportUtils; public final class NotificationFormatter { @@ -38,9 +39,11 @@ public final class NotificationFormatter { } public static VelocityContext prepareContext(long userId, Event event, Position position) { + User user = Context.getPermissionsManager().getUser(userId); Device device = Context.getIdentityManager().getDeviceById(event.getDeviceId()); VelocityContext velocityContext = new VelocityContext(); + velocityContext.put("user", user); velocityContext.put("device", device); velocityContext.put("event", event); if (position != null) { @@ -50,6 +53,10 @@ public final class NotificationFormatter { if (event.getGeofenceId() != 0) { velocityContext.put("geofence", Context.getGeofenceManager().getGeofence(event.getGeofenceId())); } + String driverUniqueId = event.getString(Position.KEY_DRIVER_UNIQUE_ID); + if (driverUniqueId != null) { + velocityContext.put("driver", Context.getDriversManager().getDriverByUniqueId(driverUniqueId)); + } velocityContext.put("webUrl", Context.getVelocityEngine().getProperty("web.url")); velocityContext.put("dateTool", new DateTool()); velocityContext.put("numberTool", new NumberTool()); diff --git a/src/org/traccar/processing/CopyAttributesHandler.java b/src/org/traccar/processing/CopyAttributesHandler.java index 3a96ca98d..9fbcfa73f 100644 --- a/src/org/traccar/processing/CopyAttributesHandler.java +++ b/src/org/traccar/processing/CopyAttributesHandler.java @@ -32,9 +32,14 @@ public class CopyAttributesHandler extends BaseDataHandler { @Override protected Position handlePosition(Position position) { String attributesString = Context.getDeviceManager().lookupAttributeString( - position.getDeviceId(), "processing.copyAttributes", null, true); + position.getDeviceId(), "processing.copyAttributes", "", true); Position last = getLastPosition(position.getDeviceId()); - if (attributesString != null && last != null) { + if (attributesString.isEmpty()) { + attributesString = Position.KEY_DRIVER_UNIQUE_ID; + } else { + attributesString += "," + Position.KEY_DRIVER_UNIQUE_ID; + } + if (last != null) { for (String attribute : attributesString.split("[ ,]")) { if (last.getAttributes().containsKey(attribute) && !position.getAttributes().containsKey(attribute)) { position.getAttributes().put(attribute, last.getAttributes().get(attribute)); diff --git a/src/org/traccar/protocol/AplicomProtocolDecoder.java b/src/org/traccar/protocol/AplicomProtocolDecoder.java index eb8d77011..6f63d0c17 100644 --- a/src/org/traccar/protocol/AplicomProtocolDecoder.java +++ b/src/org/traccar/protocol/AplicomProtocolDecoder.java @@ -263,7 +263,8 @@ public class AplicomProtocolDecoder extends BaseProtocolDecoder { } if ((selector & 0x0200) != 0) { - position.set(Position.KEY_RFID, (((long) buf.readUnsignedShort()) << 32) + buf.readUnsignedInt()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, + String.valueOf(((long) buf.readUnsignedShort()) << 32) + buf.readUnsignedInt()); } if ((selector & 0x0400) != 0) { diff --git a/src/org/traccar/protocol/AstraProtocolDecoder.java b/src/org/traccar/protocol/AstraProtocolDecoder.java index ea6aa7b30..8d86cd2be 100644 --- a/src/org/traccar/protocol/AstraProtocolDecoder.java +++ b/src/org/traccar/protocol/AstraProtocolDecoder.java @@ -105,7 +105,7 @@ public class AstraProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // geofence events if (BitUtil.check(status, 8)) { - position.set(Position.KEY_RFID, buf.readBytes(7).toString(StandardCharsets.US_ASCII)); + position.set(Position.KEY_DRIVER_UNIQUE_ID, buf.readBytes(7).toString(StandardCharsets.US_ASCII)); position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium() * 1000); position.set(Position.KEY_HOURS, buf.readUnsignedShort()); } diff --git a/src/org/traccar/protocol/AtrackProtocolDecoder.java b/src/org/traccar/protocol/AtrackProtocolDecoder.java index 79b3c36cc..23cb67e15 100644 --- a/src/org/traccar/protocol/AtrackProtocolDecoder.java +++ b/src/org/traccar/protocol/AtrackProtocolDecoder.java @@ -327,7 +327,7 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort() * 0.001); - position.set("driver", readString(buf)); + position.set(Position.KEY_DRIVER_UNIQUE_ID, readString(buf)); position.set(Position.PREFIX_TEMP + 1, buf.readShort() * 0.1); position.set(Position.PREFIX_TEMP + 2, buf.readShort() * 0.1); diff --git a/src/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/org/traccar/protocol/FifotrackProtocolDecoder.java index f8f4fb078..304f6a2c3 100644 --- a/src/org/traccar/protocol/FifotrackProtocolDecoder.java +++ b/src/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -110,7 +110,7 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_ADC + (i + 1), Integer.parseInt(adc[i], 16)); } - position.set(Position.KEY_RFID, parser.next()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); if (parser.hasNext()) { String[] sensors = parser.next().split("\\|"); diff --git a/src/org/traccar/protocol/Gl200ProtocolDecoder.java b/src/org/traccar/protocol/Gl200ProtocolDecoder.java index a3062c942..140d3300a 100644 --- a/src/org/traccar/protocol/Gl200ProtocolDecoder.java +++ b/src/org/traccar/protocol/Gl200ProtocolDecoder.java @@ -644,7 +644,7 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder { return null; } - position.set(Position.KEY_RFID, parser.next()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); decodeLocation(position, parser); diff --git a/src/org/traccar/protocol/GnxProtocolDecoder.java b/src/org/traccar/protocol/GnxProtocolDecoder.java index 070d394e8..2274ec164 100644 --- a/src/org/traccar/protocol/GnxProtocolDecoder.java +++ b/src/org/traccar/protocol/GnxProtocolDecoder.java @@ -102,7 +102,7 @@ public class GnxProtocolDecoder extends BaseProtocolDecoder { position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); if (type.equals("MIF")) { - position.set(Position.KEY_RFID, parser.next()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); } return position; diff --git a/src/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/org/traccar/protocol/Gps103ProtocolDecoder.java index f5ba3cff7..a9a72b110 100644 --- a/src/org/traccar/protocol/Gps103ProtocolDecoder.java +++ b/src/org/traccar/protocol/Gps103ProtocolDecoder.java @@ -258,7 +258,7 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder { String rfid = parser.next(); if (alarm.equals("rfid")) { - position.set(Position.KEY_RFID, rfid); + position.set(Position.KEY_DRIVER_UNIQUE_ID, rfid); } String utcHours = parser.next(); diff --git a/src/org/traccar/protocol/MegastekProtocolDecoder.java b/src/org/traccar/protocol/MegastekProtocolDecoder.java index 15a384cc0..994e2d983 100644 --- a/src/org/traccar/protocol/MegastekProtocolDecoder.java +++ b/src/org/traccar/protocol/MegastekProtocolDecoder.java @@ -327,7 +327,7 @@ public class MegastekProtocolDecoder extends BaseProtocolDecoder { } } - position.set(Position.KEY_RFID, parser.next()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); String battery = parser.next(); if (battery != null) { diff --git a/src/org/traccar/protocol/MeiligaoProtocolDecoder.java b/src/org/traccar/protocol/MeiligaoProtocolDecoder.java index 44e01d5e0..dbbf61f71 100644 --- a/src/org/traccar/protocol/MeiligaoProtocolDecoder.java +++ b/src/org/traccar/protocol/MeiligaoProtocolDecoder.java @@ -253,7 +253,7 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder { } if (parser.hasNext()) { - position.set(Position.KEY_RFID, parser.nextHexInt(0)); + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(parser.nextHexInt(0))); } return position; @@ -370,7 +370,7 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder { if (rfid != 0) { String card = String.format("%010d", rfid); position.set("card" + (i + 1), card); - position.set(Position.KEY_RFID, card); + position.set(Position.KEY_DRIVER_UNIQUE_ID, card); } } } diff --git a/src/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/org/traccar/protocol/MeitrackProtocolDecoder.java index 38ecde519..711697fc4 100644 --- a/src/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -201,7 +201,7 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { if (eventData != null && !eventData.isEmpty()) { switch (event) { case 37: - position.set(Position.KEY_RFID, eventData); + position.set(Position.KEY_DRIVER_UNIQUE_ID, eventData); break; default: position.set("eventData", eventData); diff --git a/src/org/traccar/protocol/MxtProtocolDecoder.java b/src/org/traccar/protocol/MxtProtocolDecoder.java index 49987ce57..6d82e4a4b 100644 --- a/src/org/traccar/protocol/MxtProtocolDecoder.java +++ b/src/org/traccar/protocol/MxtProtocolDecoder.java @@ -159,7 +159,7 @@ public class MxtProtocolDecoder extends BaseProtocolDecoder { } if (BitUtil.check(infoGroups, 7)) { - position.set(Position.KEY_RFID, buf.readUnsignedInt()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(buf.readUnsignedInt())); } buf.readerIndex(buf.writerIndex() - 3); diff --git a/src/org/traccar/protocol/OsmAndProtocolDecoder.java b/src/org/traccar/protocol/OsmAndProtocolDecoder.java index 15f6f40b8..6f8513c41 100644 --- a/src/org/traccar/protocol/OsmAndProtocolDecoder.java +++ b/src/org/traccar/protocol/OsmAndProtocolDecoder.java @@ -128,6 +128,9 @@ public class OsmAndProtocolDecoder extends BaseProtocolDecoder { case "batt": position.set(Position.KEY_BATTERY_LEVEL, Double.parseDouble(value)); break; + case "driverUniqueId": + position.set(Position.KEY_DRIVER_UNIQUE_ID, value); + break; default: try { position.set(entry.getKey(), Double.parseDouble(value)); diff --git a/src/org/traccar/protocol/Pt502ProtocolDecoder.java b/src/org/traccar/protocol/Pt502ProtocolDecoder.java index b1851f8ca..e12bbdf28 100644 --- a/src/org/traccar/protocol/Pt502ProtocolDecoder.java +++ b/src/org/traccar/protocol/Pt502ProtocolDecoder.java @@ -129,7 +129,7 @@ public class Pt502ProtocolDecoder extends BaseProtocolDecoder { }
position.set(Position.KEY_ODOMETER, parser.nextInt(0));
- position.set(Position.KEY_RFID, parser.next());
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next());
if (parser.hasNext()) {
int value = parser.nextHexInt(0);
diff --git a/src/org/traccar/protocol/StarLinkProtocolDecoder.java b/src/org/traccar/protocol/StarLinkProtocolDecoder.java index e90dde455..38f6980f6 100644 --- a/src/org/traccar/protocol/StarLinkProtocolDecoder.java +++ b/src/org/traccar/protocol/StarLinkProtocolDecoder.java @@ -196,7 +196,7 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder { if (rfid.matches("0+")) { rfid = data[data.length - 2]; } - position.set(Position.KEY_RFID, rfid); + position.set(Position.KEY_DRIVER_UNIQUE_ID, rfid); } return position; diff --git a/src/org/traccar/protocol/Stl060ProtocolDecoder.java b/src/org/traccar/protocol/Stl060ProtocolDecoder.java index c81e83aab..26817a5c8 100644 --- a/src/org/traccar/protocol/Stl060ProtocolDecoder.java +++ b/src/org/traccar/protocol/Stl060ProtocolDecoder.java @@ -104,7 +104,7 @@ public class Stl060ProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_CHARGE, parser.nextInt(0) == 1); position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); position.set(Position.KEY_INPUT, parser.nextInt(0)); - position.set(Position.KEY_RFID, parser.next()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); position.set(Position.KEY_ODOMETER, parser.nextInt(0)); position.set(Position.PREFIX_TEMP + 1, parser.nextInt(0)); position.set(Position.KEY_FUEL_LEVEL, parser.nextInt(0)); diff --git a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java index c8c2e4002..15c5b8e80 100644 --- a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -123,7 +123,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_TEMP + 3, readValue(buf, length, true) * 0.1); break; case 78: - position.set(Position.KEY_RFID, readValue(buf, length, false)); + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(readValue(buf, length, false))); break; case 182: position.set(Position.KEY_HDOP, readValue(buf, length, false) * 0.1); diff --git a/src/org/traccar/protocol/TmgProtocolDecoder.java b/src/org/traccar/protocol/TmgProtocolDecoder.java index c10523117..b8458dd52 100644 --- a/src/org/traccar/protocol/TmgProtocolDecoder.java +++ b/src/org/traccar/protocol/TmgProtocolDecoder.java @@ -144,7 +144,7 @@ public class TmgProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_ADC + 1, parser.nextDouble(0)); position.set(Position.PREFIX_ADC + 2, parser.nextDouble(0)); position.set(Position.KEY_VERSION_FW, parser.next()); - position.set(Position.KEY_RFID, parser.next()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); return position; } diff --git a/src/org/traccar/protocol/UlbotechProtocolDecoder.java b/src/org/traccar/protocol/UlbotechProtocolDecoder.java index 1b22eeb75..31a3d2cfe 100644 --- a/src/org/traccar/protocol/UlbotechProtocolDecoder.java +++ b/src/org/traccar/protocol/UlbotechProtocolDecoder.java @@ -308,7 +308,8 @@ public class UlbotechProtocolDecoder extends BaseProtocolDecoder { break; case DATA_RFID: - position.set(Position.KEY_RFID, buf.readBytes(length - 1).toString(StandardCharsets.US_ASCII)); + position.set(Position.KEY_DRIVER_UNIQUE_ID, + buf.readBytes(length - 1).toString(StandardCharsets.US_ASCII)); position.set("authorized", buf.readUnsignedByte() != 0); break; diff --git a/src/org/traccar/protocol/VisiontekProtocolDecoder.java b/src/org/traccar/protocol/VisiontekProtocolDecoder.java index 636a3d640..f32c9fbfe 100644 --- a/src/org/traccar/protocol/VisiontekProtocolDecoder.java +++ b/src/org/traccar/protocol/VisiontekProtocolDecoder.java @@ -130,7 +130,7 @@ public class VisiontekProtocolDecoder extends BaseProtocolDecoder { position.setValid(parser.next().equals("A")); - position.set(Position.KEY_RFID, parser.next()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); return position; } diff --git a/src/org/traccar/protocol/WialonProtocolDecoder.java b/src/org/traccar/protocol/WialonProtocolDecoder.java index 82098413b..4eb3b9b8e 100644 --- a/src/org/traccar/protocol/WialonProtocolDecoder.java +++ b/src/org/traccar/protocol/WialonProtocolDecoder.java @@ -109,7 +109,7 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { } } - position.set(Position.KEY_RFID, parser.next()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); if (parser.hasNext()) { String[] values = parser.next().split(","); diff --git a/src/org/traccar/reports/ReportUtils.java b/src/org/traccar/reports/ReportUtils.java index 71c567c29..bc58d28df 100644 --- a/src/org/traccar/reports/ReportUtils.java +++ b/src/org/traccar/reports/ReportUtils.java @@ -26,6 +26,7 @@ import org.jxls.transform.Transformer; import org.jxls.transform.poi.PoiTransformer; import org.jxls.util.TransformerFactory; import org.traccar.Context; +import org.traccar.model.Driver; import org.traccar.model.Position; import org.traccar.reports.model.BaseReport; import org.traccar.reports.model.StopReport; @@ -101,6 +102,25 @@ public final class ReportUtils { return 0; } + public static String findDriver(Position firstPosition, Position lastPosition) { + if (firstPosition.getAttributes().containsKey(Position.KEY_DRIVER_UNIQUE_ID)) { + return firstPosition.getString(Position.KEY_DRIVER_UNIQUE_ID); + } else if (lastPosition.getAttributes().containsKey(Position.KEY_DRIVER_UNIQUE_ID)) { + return lastPosition.getString(Position.KEY_DRIVER_UNIQUE_ID); + } + return null; + } + + public static String findDriverName(String driverUniqueId) { + if (driverUniqueId != null && Context.getDriversManager() != null) { + Driver driver = Context.getDriversManager().getDriverByUniqueId(driverUniqueId); + if (driver != null) { + return driver.getName(); + } + } + return null; + } + public static org.jxls.common.Context initializeContext(long userId) { org.jxls.common.Context jxlsContext = PoiTransformer.createInitialContext(); jxlsContext.putVar("distanceUnit", getDistanceUnit(userId)); @@ -176,6 +196,9 @@ public final class ReportUtils { trip.setMaxSpeed(speedMax); trip.setSpentFuel(calculateFuel(startTrip, endTrip)); + trip.setDriverUniqueId(findDriver(startTrip, endTrip)); + trip.setDriverName(findDriverName(trip.getDriverUniqueId())); + return trip; } diff --git a/src/org/traccar/reports/model/TripReport.java b/src/org/traccar/reports/model/TripReport.java index efe556f79..42a4240b7 100644 --- a/src/org/traccar/reports/model/TripReport.java +++ b/src/org/traccar/reports/model/TripReport.java @@ -145,4 +145,24 @@ public class TripReport extends BaseReport { public void setDuration(long duration) { this.duration = duration; } + + private String driverUniqueId; + + public String getDriverUniqueId() { + return driverUniqueId; + } + + public void setDriverUniqueId(String driverUniqueId) { + this.driverUniqueId = driverUniqueId; + } + + private String driverName; + + public String getDriverName() { + return driverName; + } + + public void setDriverName(String driverName) { + this.driverName = driverName; + } } diff --git a/templates/export/trips.xlsx b/templates/export/trips.xlsx Binary files differindex 0e0ab4494..4a6734850 100644 --- a/templates/export/trips.xlsx +++ b/templates/export/trips.xlsx diff --git a/templates/mail/driverChanged.vm b/templates/mail/driverChanged.vm new file mode 100644 index 000000000..ba1e68661 --- /dev/null +++ b/templates/mail/driverChanged.vm @@ -0,0 +1,10 @@ +#set($subject = "$device.name: driver has changed") +<!DOCTYPE html> +<html> +<body> +Device: $device.name<br> +Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.serverTime, $locale, $timezone)<br> +Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude°, $position.longitude°#{end}</a><br> +Driver: #{if}($driver)$driver.name#{else}$event.getString("driverUniqueId")#{end} +</body> +</html> diff --git a/templates/sms/driverChanged.vm b/templates/sms/driverChanged.vm new file mode 100644 index 000000000..50849df7c --- /dev/null +++ b/templates/sms/driverChanged.vm @@ -0,0 +1,6 @@ +#if($driver) +#set($driverName = $driver.name) +#else +#set($driverName = $event.getString("driverUniqueId")) +#end +Driver $driverName has changed in $device.name at $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.serverTime, $locale, $timezone) diff --git a/test/org/traccar/ProtocolTest.java b/test/org/traccar/ProtocolTest.java index 3b801c6eb..cb9cdf759 100644 --- a/test/org/traccar/ProtocolTest.java +++ b/test/org/traccar/ProtocolTest.java @@ -245,6 +245,10 @@ public class ProtocolTest extends BaseTest { Assert.assertTrue(attributes.get(Position.KEY_ARCHIVE) instanceof Boolean); } + if (attributes.containsKey(Position.KEY_DRIVER_UNIQUE_ID)) { + Assert.assertTrue(attributes.get(Position.KEY_DRIVER_UNIQUE_ID) instanceof String); + } + if (position.getNetwork() != null && position.getNetwork().getCellTowers() != null) { for (CellTower cellTower : position.getNetwork().getCellTowers()) { checkInteger(cellTower.getMobileCountryCode(), 0, 999); diff --git a/tools/test-generator.py b/tools/test-generator.py index 9e9cf892e..41ec5a2fa 100755 --- a/tools/test-generator.py +++ b/tools/test-generator.py @@ -12,6 +12,7 @@ server = 'localhost:5055' period = 1 step = 0.001 device_speed = 40 +driver_id = '123456' waypoints = [ (40.722412, -74.006288), @@ -34,7 +35,7 @@ for i in range(0, len(waypoints)): lon = lon1 + (lon2 - lon1) * j / count points.append((lat, lon)) -def send(conn, lat, lon, course, speed, alarm, ignition, accuracy, rpm, fuel): +def send(conn, lat, lon, course, speed, alarm, ignition, accuracy, rpm, fuel, driverUniqueId): params = (('id', id), ('timestamp', int(time.time())), ('lat', lat), ('lon', lon), ('bearing', course), ('speed', speed)) if alarm: params = params + (('alarm', 'sos'),) @@ -46,6 +47,8 @@ def send(conn, lat, lon, course, speed, alarm, ignition, accuracy, rpm, fuel): params = params + (('rpm', rpm),) if fuel: params = params + (('fuel', fuel),) + if driverUniqueId: + params = params + (('driverUniqueId', driverUniqueId),) conn.request('GET', '?' + urllib.urlencode(params)) conn.getresponse().read() @@ -71,6 +74,7 @@ while True: accuracy = 100 if (index % 10) == 0 else 0 rpm = random.randint(500, 4000) fuel = random.randint(0, 80) - send(conn, lat1, lon1, course(lat1, lon1, lat2, lon2), speed, alarm, ignition, accuracy, rpm, fuel) + driverUniqueId = driver_id if (index % len(points)) == 0 else False + send(conn, lat1, lon1, course(lat1, lon1, lat2, lon2), speed, alarm, ignition, accuracy, rpm, fuel, driverUniqueId) time.sleep(period) index += 1 |