diff options
author | Anton Tananaev <anton.tananaev@gmail.com> | 2016-12-16 00:28:26 +1300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-16 00:28:26 +1300 |
commit | 835853422ce9f1c1fde15a6464c6f0f7eda4fed7 (patch) | |
tree | 049fa09050caec98242a0f642d478a533cee5898 | |
parent | f76c78a68f249ddb45a2bbae11dd95dd6db743b6 (diff) | |
parent | ef9148eea8dd404aba5707898f244a4b7bc26feb (diff) | |
download | traccar-server-835853422ce9f1c1fde15a6464c6f0f7eda4fed7.tar.gz traccar-server-835853422ce9f1c1fde15a6464c6f0f7eda4fed7.tar.bz2 traccar-server-835853422ce9f1c1fde15a6464c6f0f7eda4fed7.zip |
Merge pull request #2686 from Abyss777/calendars
Calendars implementation
-rw-r--r-- | pom.xml | 5 | ||||
-rw-r--r-- | schema/changelog-3.10.xml | 45 | ||||
-rw-r--r-- | schema/changelog-master.xml | 1 | ||||
-rw-r--r-- | setup/default.xml | 38 | ||||
-rw-r--r-- | src/org/traccar/Context.java | 8 | ||||
-rw-r--r-- | src/org/traccar/api/resource/CalendarPermissionResource.java | 57 | ||||
-rw-r--r-- | src/org/traccar/api/resource/CalendarResource.java | 85 | ||||
-rw-r--r-- | src/org/traccar/database/CalendarManager.java | 112 | ||||
-rw-r--r-- | src/org/traccar/database/DataManager.java | 43 | ||||
-rw-r--r-- | src/org/traccar/database/PermissionsManager.java | 6 | ||||
-rw-r--r-- | src/org/traccar/database/QueryBuilder.java | 30 | ||||
-rw-r--r-- | src/org/traccar/events/GeofenceEventHandler.java | 20 | ||||
-rw-r--r-- | src/org/traccar/model/Calendar.java | 82 | ||||
-rw-r--r-- | src/org/traccar/model/CalendarPermission.java | 40 | ||||
-rw-r--r-- | src/org/traccar/model/Geofence.java | 9 | ||||
-rw-r--r-- | test/org/traccar/calendar/CalendarTest.java | 58 |
16 files changed, 631 insertions, 8 deletions
@@ -143,6 +143,11 @@ <artifactId>velocity</artifactId> <version>1.7</version> </dependency> + <dependency> + <groupId>org.mnode.ical4j</groupId> + <artifactId>ical4j</artifactId> + <version>2.0.0</version> + </dependency> </dependencies> <build> diff --git a/schema/changelog-3.10.xml b/schema/changelog-3.10.xml new file mode 100644 index 000000000..8cd7b3704 --- /dev/null +++ b/schema/changelog-3.10.xml @@ -0,0 +1,45 @@ +<?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.10"> + + <changeSet author="author" id="changelog-3.10"> + + <createTable tableName="calendars"> + <column name="id" type="INT" autoIncrement="true"> + <constraints primaryKey="true" /> + </column> + <column name="name" type="VARCHAR(128)"> + <constraints nullable="false" /> + </column> + <column name="calendardata" type="BLOB"> + <constraints nullable="false" /> + </column> + <column name="attributes" type="VARCHAR(4000)"> + <constraints nullable="false" /> + </column> + </createTable> + + <createTable tableName="user_calendar"> + <column name="userid" type="INT"> + <constraints nullable="false" /> + </column> + <column name="calendarid" type="INT"> + <constraints nullable="false" /> + </column> + </createTable> + + <addForeignKeyConstraint baseTableName="user_calendar" baseColumnNames="userid" constraintName="fk_user_calendar_userid" referencedTableName="users" referencedColumnNames="id" onDelete="CASCADE" /> + <addForeignKeyConstraint baseTableName="user_calendar" baseColumnNames="calendarid" constraintName="fk_user_calendar_geofenceid" referencedTableName="calendars" referencedColumnNames="id" onDelete="CASCADE" /> + + <addColumn tableName="geofences"> + <column name="calendarid" type="INT" /> + </addColumn> + + <addForeignKeyConstraint baseColumnNames="calendarid" baseTableName="geofences" constraintName="fk_geofence_calendar_calendarid" onDelete="SET NULL" onUpdate="RESTRICT" referencedColumnNames="id" referencedTableName="calendars"/> + + </changeSet> +</databaseChangeLog> diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml index 448015568..2aed50e72 100644 --- a/schema/changelog-master.xml +++ b/schema/changelog-master.xml @@ -11,4 +11,5 @@ <include file="changelog-3.7.xml" relativeToChangelogFile="true" /> <include file="changelog-3.8.xml" relativeToChangelogFile="true" /> <include file="changelog-3.9.xml" relativeToChangelogFile="true" /> + <include file="changelog-3.10.xml" relativeToChangelogFile="true" /> </databaseChangeLog> diff --git a/setup/default.xml b/setup/default.xml index ad23d7bd3..aeb8fbe54 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -206,14 +206,15 @@ </entry> <entry key='database.insertGeofence'> - INSERT INTO geofences (name, description, area, attributes) - VALUES (:name, :description, :area, :attributes) + INSERT INTO geofences (name, description, calendarid, area, attributes) + VALUES (:name, :description, :calendarid, :area, :attributes) </entry> <entry key='database.updateGeofence'> UPDATE geofences SET name = :name, description = :description, + calendarid = :calendarid, area = :area, attributes = :attributes WHERE id = :id @@ -315,6 +316,39 @@ INSERT INTO statistics (captureTime, activeUsers, activeDevices, requests, messagesReceived, messagesStored, attributes) VALUES (:captureTime, :activeUsers, :activeDevices, :requests, :messagesReceived, :messagesStored, :attributes) </entry> + + <entry key='database.selectCalendarsAll'> + SELECT * FROM calendars + </entry> + + <entry key='database.insertCalendar'> + INSERT INTO calendars (name, calendarData, attributes) + VALUES (:name, :calendarData, :attributes) + </entry> + + <entry key='database.updateCalendar'> + UPDATE calendars SET + name = :name, + calendarData = :calendarData, + attributes = :attributes + WHERE id = :id + </entry> + + <entry key='database.deleteCalendar'> + DELETE FROM calendars WHERE id = :id + </entry> + + <entry key='database.selectCalendarPermissions'> + SELECT userId, calendarId FROM user_calendar + </entry> + + <entry key='database.linkCalendar'> + INSERT INTO user_calendar (userId, calendarId) VALUES (:userId, :calendarId) + </entry> + + <entry key='database.unlinkCalendar'> + DELETE FROM user_calendar WHERE userId = :userId AND calendarId = :calendarId + </entry> <!-- PROTOCOL CONFIG --> diff --git a/src/org/traccar/Context.java b/src/org/traccar/Context.java index 2b8860187..03e4635b6 100644 --- a/src/org/traccar/Context.java +++ b/src/org/traccar/Context.java @@ -23,6 +23,7 @@ import java.util.Properties; import org.apache.velocity.app.VelocityEngine; import org.eclipse.jetty.util.URIUtil; import org.traccar.database.AliasesManager; +import org.traccar.database.CalendarManager; import org.traccar.database.ConnectionManager; import org.traccar.database.DataManager; import org.traccar.database.DeviceManager; @@ -124,6 +125,12 @@ public final class Context { return geofenceManager; } + private static CalendarManager calendarManager; + + public static CalendarManager getCalendarManager() { + return calendarManager; + } + private static NotificationManager notificationManager; public static NotificationManager getNotificationManager() { @@ -253,6 +260,7 @@ public final class Context { if (config.getBoolean("event.geofenceHandler")) { geofenceManager = new GeofenceManager(dataManager); + calendarManager = new CalendarManager(dataManager); } if (config.getBoolean("event.enable")) { diff --git a/src/org/traccar/api/resource/CalendarPermissionResource.java b/src/org/traccar/api/resource/CalendarPermissionResource.java new file mode 100644 index 000000000..a49254b6b --- /dev/null +++ b/src/org/traccar/api/resource/CalendarPermissionResource.java @@ -0,0 +1,57 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 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.CalendarPermission; + +@Path("permissions/calendars") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class CalendarPermissionResource extends BaseResource { + + @POST + public Response add(CalendarPermission entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkUser(getUserId(), entity.getUserId()); + Context.getPermissionsManager().checkCalendar(getUserId(), entity.getCalendarId()); + Context.getDataManager().linkCalendar(entity.getUserId(), entity.getCalendarId()); + Context.getCalendarManager().refreshUserCalendars(); + return Response.ok(entity).build(); + } + + @DELETE + public Response remove(CalendarPermission entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkUser(getUserId(), entity.getUserId()); + Context.getPermissionsManager().checkCalendar(getUserId(), entity.getCalendarId()); + Context.getDataManager().unlinkCalendar(entity.getUserId(), entity.getCalendarId()); + Context.getCalendarManager().refreshUserCalendars(); + return Response.noContent().build(); + } +} diff --git a/src/org/traccar/api/resource/CalendarResource.java b/src/org/traccar/api/resource/CalendarResource.java new file mode 100644 index 000000000..0a9bb5daf --- /dev/null +++ b/src/org/traccar/api/resource/CalendarResource.java @@ -0,0 +1,85 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 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 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.model.Calendar; + +@Path("calendars") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class CalendarResource extends BaseResource { + + @GET + public Collection<Calendar> get( + @QueryParam("all") boolean all, @QueryParam("userId") long userId) throws SQLException { + + if (all) { + Context.getPermissionsManager().checkAdmin(getUserId()); + return Context.getCalendarManager().getAllCalendars(); + } else { + if (userId == 0) { + userId = getUserId(); + } + Context.getPermissionsManager().checkUser(getUserId(), userId); + return Context.getCalendarManager().getUserCalendars(userId); + } + } + + @POST + public Response add(Calendar entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getCalendarManager().addCalendar(entity); + Context.getDataManager().linkCalendar(getUserId(), entity.getId()); + Context.getCalendarManager().refreshUserCalendars(); + return Response.ok(entity).build(); + } + + @Path("{id}") + @PUT + public Response update(Calendar entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkCalendar(getUserId(), entity.getId()); + Context.getCalendarManager().updateCalendar(entity); + return Response.ok(entity).build(); + } + + @Path("{id}") + @DELETE + public Response remove(@PathParam("id") long id) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkCalendar(getUserId(), id); + Context.getCalendarManager().removeCalendar(id); + return Response.noContent().build(); + } +} diff --git a/src/org/traccar/database/CalendarManager.java b/src/org/traccar/database/CalendarManager.java new file mode 100644 index 000000000..3e95f6698 --- /dev/null +++ b/src/org/traccar/database/CalendarManager.java @@ -0,0 +1,112 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 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.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.traccar.helper.Log; +import org.traccar.model.Calendar; +import org.traccar.model.CalendarPermission; + +public class CalendarManager { + + private final DataManager dataManager; + + private final Map<Long, Calendar> calendars = new ConcurrentHashMap<>(); + private final Map<Long, Set<Long>> userCalendars = new ConcurrentHashMap<>(); + + public CalendarManager(DataManager dataManager) { + this.dataManager = dataManager; + refreshCalendars(); + } + + public final void refreshCalendars() { + if (dataManager != null) { + try { + calendars.clear(); + for (Calendar calendar : dataManager.getCalendars()) { + calendars.put(calendar.getId(), calendar); + } + } catch (SQLException error) { + Log.warning(error); + } + } + refreshUserCalendars(); + } + + private Set<Long> getUserCalendarIds(long userId) { + if (!userCalendars.containsKey(userId)) { + userCalendars.put(userId, new HashSet<Long>()); + } + return userCalendars.get(userId); + } + + public Collection<Calendar> getUserCalendars(long userId) { + ArrayList<Calendar> result = new ArrayList<>(); + for (long calendarId : getUserCalendarIds(userId)) { + result.add(calendars.get(calendarId)); + } + return result; + } + + public final void refreshUserCalendars() { + if (dataManager != null) { + try { + userCalendars.clear(); + for (CalendarPermission calendarsPermission : dataManager.getCalendarPermissions()) { + getUserCalendarIds(calendarsPermission.getUserId()).add(calendarsPermission.getCalendarId()); + } + } catch (SQLException error) { + Log.warning(error); + } + } + } + + public Calendar getCalendar(long calendarId) { + return calendars.get(calendarId); + } + + public final void addCalendar(Calendar calendar) throws SQLException { + dataManager.addCalendar(calendar); + calendars.put(calendar.getId(), calendar); + } + + public final void updateCalendar(Calendar calendar) throws SQLException { + dataManager.updateCalendar(calendar); + calendars.put(calendar.getId(), calendar); + } + + public final void removeCalendar(long calendarId) throws SQLException { + dataManager.removeCalendar(calendarId); + calendars.remove(calendarId); + refreshUserCalendars(); + } + + public Collection<Calendar> getAllCalendars() { + return calendars.values(); + } + + public boolean checkCalendar(long userId, long calendarId) { + return getUserCalendarIds(userId).contains(calendarId); + } +} diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java index 8be53ad7b..278109229 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -37,6 +37,8 @@ import liquibase.resource.ResourceAccessor; import org.traccar.Config; import org.traccar.helper.Log; import org.traccar.model.AttributeAlias; +import org.traccar.model.Calendar; +import org.traccar.model.CalendarPermission; import org.traccar.model.Device; import org.traccar.model.DevicePermission; import org.traccar.model.Event; @@ -484,4 +486,45 @@ public class DataManager { .executeUpdate()); } + public Collection<Calendar> getCalendars() throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectCalendarsAll")) + .executeQuery(Calendar.class); + } + + public void addCalendar(Calendar calendar) throws SQLException { + calendar.setId(QueryBuilder.create(dataSource, getQuery("database.insertCalendar"), true) + .setObject(calendar) + .executeUpdate()); + } + + public void updateCalendar(Calendar calendar) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.updateCalendar")) + .setObject(calendar) + .executeUpdate(); + } + + public void removeCalendar(long calendarId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.deleteCalendar")) + .setLong("id", calendarId) + .executeUpdate(); + } + + public Collection<CalendarPermission> getCalendarPermissions() throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectCalendarPermissions")) + .executeQuery(CalendarPermission.class); + } + + public void linkCalendar(long userId, long calendarId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.linkCalendar")) + .setLong("userId", userId) + .setLong("calendarId", calendarId) + .executeUpdate(); + } + + public void unlinkCalendar(long userId, long calendarId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.unlinkCalendar")) + .setLong("userId", userId) + .setLong("calendarId", calendarId) + .executeUpdate(); + } } diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java index 078a5f935..6c0610655 100644 --- a/src/org/traccar/database/PermissionsManager.java +++ b/src/org/traccar/database/PermissionsManager.java @@ -207,6 +207,12 @@ public class PermissionsManager { } } + public void checkCalendar(long userId, long calendarId) throws SecurityException { + if (!Context.getCalendarManager().checkCalendar(userId, calendarId) && !isAdmin(userId)) { + throw new SecurityException("Calendar access denied"); + } + } + public Server getServer() { return server; } diff --git a/src/org/traccar/database/QueryBuilder.java b/src/org/traccar/database/QueryBuilder.java index 50d689a2a..201240f2f 100644 --- a/src/org/traccar/database/QueryBuilder.java +++ b/src/org/traccar/database/QueryBuilder.java @@ -240,6 +240,23 @@ public final class QueryBuilder { return this; } + public QueryBuilder setBlob(String name, byte[] value) throws SQLException { + for (int i : indexes(name)) { + try { + if (value == null) { + statement.setNull(i, Types.BLOB); + } else { + statement.setBytes(i, value); + } + } catch (SQLException error) { + statement.close(); + connection.close(); + throw error; + } + } + return this; + } + public QueryBuilder setObject(Object object) throws SQLException { Method[] methods = object.getClass().getMethods(); @@ -260,6 +277,8 @@ public final class QueryBuilder { setString(name, (String) method.invoke(object)); } else if (method.getReturnType().equals(Date.class)) { setDate(name, (Date) method.invoke(object)); + } else if (method.getReturnType().equals(byte[].class)) { + setBlob(name, (byte[]) method.invoke(object)); } else if (method.getReturnType().equals(Map.class)) { if (Context.getConfig().getBoolean("database.xml")) { setString(name, MiscFormatter.toXmlString((Map) method.invoke(object))); @@ -375,6 +394,17 @@ public final class QueryBuilder { } } }); + } else if (parameterType.equals(byte[].class)) { + processors.add(new ResultSetProcessor<T>() { + @Override + public void process(T object, ResultSet resultSet) throws SQLException { + try { + method.invoke(object, resultSet.getBytes(name)); + } catch (IllegalAccessException | InvocationTargetException error) { + Log.warning(error); + } + } + }); } } diff --git a/src/org/traccar/events/GeofenceEventHandler.java b/src/org/traccar/events/GeofenceEventHandler.java index d31e516ef..fbec932b1 100644 --- a/src/org/traccar/events/GeofenceEventHandler.java +++ b/src/org/traccar/events/GeofenceEventHandler.java @@ -57,14 +57,22 @@ public class GeofenceEventHandler extends BaseEventHandler { Collection<Event> events = new ArrayList<>(); for (long geofenceId : newGeofences) { - Event event = new Event(Event.TYPE_GEOFENCE_ENTER, position.getDeviceId(), position.getId()); - event.setGeofenceId(geofenceId); - events.add(event); + long calendarId = geofenceManager.getGeofence(geofenceId).getCalendarId(); + if (calendarId == 0 || Context.getCalendarManager().getCalendar(calendarId) == null + || Context.getCalendarManager().getCalendar(calendarId).checkMoment(position.getFixTime())) { + Event event = new Event(Event.TYPE_GEOFENCE_ENTER, position.getDeviceId(), position.getId()); + event.setGeofenceId(geofenceId); + events.add(event); + } } for (long geofenceId : oldGeofences) { - Event event = new Event(Event.TYPE_GEOFENCE_EXIT, position.getDeviceId(), position.getId()); - event.setGeofenceId(geofenceId); - events.add(event); + long calendarId = geofenceManager.getGeofence(geofenceId).getCalendarId(); + if (calendarId == 0 || Context.getCalendarManager().getCalendar(calendarId) == null + || Context.getCalendarManager().getCalendar(calendarId).checkMoment(position.getFixTime())) { + Event event = new Event(Event.TYPE_GEOFENCE_EXIT, position.getDeviceId(), position.getId()); + event.setGeofenceId(geofenceId); + events.add(event); + } } return events; } diff --git a/src/org/traccar/model/Calendar.java b/src/org/traccar/model/Calendar.java new file mode 100644 index 000000000..19b5fde16 --- /dev/null +++ b/src/org/traccar/model/Calendar.java @@ -0,0 +1,82 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 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; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Collection; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import net.fortuna.ical4j.data.CalendarBuilder; +import net.fortuna.ical4j.data.ParserException; +import net.fortuna.ical4j.filter.Filter; +import net.fortuna.ical4j.filter.PeriodRule; +import net.fortuna.ical4j.filter.Rule; +import net.fortuna.ical4j.model.Component; +import net.fortuna.ical4j.model.DateTime; +import net.fortuna.ical4j.model.Dur; +import net.fortuna.ical4j.model.Period; +import net.fortuna.ical4j.model.component.CalendarComponent; +import net.fortuna.ical4j.validate.ValidationException; + +public class Calendar extends Extensible { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + private byte[] calendarData; + + public byte[] getCalendarData() throws ValidationException, IOException { + return calendarData.clone(); + } + + public void setCalendarData(byte[] calendarData) throws IOException, ParserException, SQLException { + CalendarBuilder builder = new CalendarBuilder(); + calendar = builder.build(new ByteArrayInputStream(calendarData)); + this.calendarData = calendarData.clone(); + } + + private net.fortuna.ical4j.model.Calendar calendar; + + @JsonIgnore + public net.fortuna.ical4j.model.Calendar getCalendar() { + return calendar; + } + + public boolean checkMoment(Date date) { + if (calendar != null) { + Period period = new Period(new DateTime(date), new Dur(0, 0, 0, 0)); + Rule<Component> periodRule = new PeriodRule<Component>(period); + Filter<CalendarComponent> filter = new Filter<CalendarComponent>(new Rule[] {periodRule}, Filter.MATCH_ANY); + Collection<CalendarComponent> events = filter.filter(calendar.getComponents(Component.VEVENT)); + if (events != null && !events.isEmpty()) { + return true; + } + } + return false; + } +} diff --git a/src/org/traccar/model/CalendarPermission.java b/src/org/traccar/model/CalendarPermission.java new file mode 100644 index 000000000..59f54e07b --- /dev/null +++ b/src/org/traccar/model/CalendarPermission.java @@ -0,0 +1,40 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 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 CalendarPermission { + + private long userId; + + public long getUserId() { + return userId; + } + + public void setUserId(long userId) { + this.userId = userId; + } + + private long calendarId; + + public long getCalendarId() { + return calendarId; + } + + public void setCalendarId(long calendarId) { + this.calendarId = calendarId; + } +} diff --git a/src/org/traccar/model/Geofence.java b/src/org/traccar/model/Geofence.java index 326c45b5f..f10ce6862 100644 --- a/src/org/traccar/model/Geofence.java +++ b/src/org/traccar/model/Geofence.java @@ -84,4 +84,13 @@ public class Geofence extends Extensible { this.geometry = geometry; } + private long calendarId; + + public long getCalendarId() { + return calendarId; + } + + public void setCalendarId(long calendarId) { + this.calendarId = calendarId; + } } diff --git a/test/org/traccar/calendar/CalendarTest.java b/test/org/traccar/calendar/CalendarTest.java new file mode 100644 index 000000000..7f5bd7d29 --- /dev/null +++ b/test/org/traccar/calendar/CalendarTest.java @@ -0,0 +1,58 @@ +package org.traccar.calendar; + +import java.io.IOException; +import java.sql.SQLException; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.junit.Assert; +import org.junit.Test; +import org.traccar.model.Calendar; + +import net.fortuna.ical4j.data.ParserException; + +public class CalendarTest { + + @Test + public void testCalendar() throws IOException, ParserException, ParseException, SQLException { + String calendarString = "BEGIN:VCALENDAR\n" + + "PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN\n" + + "VERSION:2.0\n" + + "BEGIN:VTIMEZONE\n" + + "TZID:Asia/Yekaterinburg\n" + + "BEGIN:STANDARD\n" + + "TZOFFSETFROM:+0500\n" + + "TZOFFSETTO:+0500\n" + + "TZNAME:YEKT\n" + + "DTSTART:19700101T000000\n" + + "END:STANDARD\n" + + "END:VTIMEZONE\n" + + "BEGIN:VEVENT\n" + + "CREATED:20161213T045151Z\n" + + "LAST-MODIFIED:20161213T045242Z\n" + + "DTSTAMP:20161213T045242Z\n" + + "UID:9d000df0-6354-479d-a407-218dac62c7c9\n" + + "SUMMARY:Every night\n" + + "RRULE:FREQ=DAILY\n" + + "DTSTART;TZID=Asia/Yekaterinburg:20161130T230000\n" + + "DTEND;TZID=Asia/Yekaterinburg:20161201T070000\n" + + "TRANSP:OPAQUE\n" + + "END:VEVENT\n" + + "END:VCALENDAR"; + Calendar calendar = new Calendar(); + calendar.setCalendarData(calendarString.getBytes()); + DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ssX"); + + Date date = format.parse("2016-12-13 22:59:59+05"); + Assert.assertTrue(!calendar.checkMoment(date)); + date = format.parse("2016-12-13 23:00:01+05"); + Assert.assertTrue(calendar.checkMoment(date)); + + date = format.parse("2016-12-13 06:59:59+05"); + Assert.assertTrue(calendar.checkMoment(date)); + date = format.parse("2016-12-13 07:00:01+05"); + Assert.assertTrue(!calendar.checkMoment(date)); + } +} |