aboutsummaryrefslogtreecommitdiffstats
path: root/apps/dav/lib/CalDAV/EventComparisonService.php
diff options
context:
space:
mode:
authorAnna Larch <anna@nextcloud.com>2022-12-12 20:46:37 +0100
committerAnna Larch <anna@nextcloud.com>2023-02-02 16:25:59 +0100
commit38e9cb6a052f4d0bc4e34293febbe9f132055a83 (patch)
treec634406b31b3d0c19b28a3c1684bdcd0325e7d03 /apps/dav/lib/CalDAV/EventComparisonService.php
parentdb30974348ee88fbf81d9cc0f1a1071d1adcbd09 (diff)
downloadnextcloud-server-38e9cb6a052f4d0bc4e34293febbe9f132055a83.tar.gz
nextcloud-server-38e9cb6a052f4d0bc4e34293febbe9f132055a83.zip
Use recurrence instance to build iMip email
instead of the main VEVENT of a repeating event Fixes part of https://github.com/nextcloud/calendar/issues/3919 Signed-off-by: Anna Larch <anna@nextcloud.com>
Diffstat (limited to 'apps/dav/lib/CalDAV/EventComparisonService.php')
-rw-r--r--apps/dav/lib/CalDAV/EventComparisonService.php123
1 files changed, 123 insertions, 0 deletions
diff --git a/apps/dav/lib/CalDAV/EventComparisonService.php b/apps/dav/lib/CalDAV/EventComparisonService.php
new file mode 100644
index 00000000000..0fd4d08e83e
--- /dev/null
+++ b/apps/dav/lib/CalDAV/EventComparisonService.php
@@ -0,0 +1,123 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2022 Anna Larch <anna.larch@gmx.net>
+ *
+ * @author 2022 Anna Larch <anna.larch@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\DAV\CalDAV;
+
+use OCA\DAV\AppInfo\Application;
+use OCA\DAV\CalDAV\Schedule\IMipService;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\IConfig;
+use Sabre\VObject\Component\VCalendar;
+use Sabre\VObject\Component\VEvent;
+use Sabre\VObject\Component\VTimeZone;
+use Sabre\VObject\Component\VTodo;
+use function max;
+
+class EventComparisonService {
+
+ /** @var string[] */
+ private const EVENT_DIFF = [
+ 'RECURRENCE-ID',
+ 'RRULE',
+ 'SEQUENCE',
+ 'LAST-MODIFIED'
+ ];
+
+
+ /**
+ * If found, remove the event from $eventsToFilter that
+ * is identical to the passed $filterEvent
+ * and return whether an identical event was found
+ *
+ * This function takes into account the SEQUENCE,
+ * RRULE, RECURRENCE-ID and LAST-MODIFIED parameters
+ *
+ * @param VEvent $filterEvent
+ * @param array $eventsToFilter
+ * @return bool true if there was an identical event found and removed, false if there wasn't
+ */
+ private function removeIfUnchanged(VEvent $filterEvent, array &$eventsToFilter): bool {
+ $filterEventData = [];
+ foreach(self::EVENT_DIFF as $eventDiff) {
+ $filterEventData[] = IMipService::readPropertyWithDefault($filterEvent, $eventDiff, '');
+ }
+
+ /** @var VEvent $component */
+ foreach ($eventsToFilter as $k => $eventToFilter) {
+ $eventToFilterData = [];
+ foreach(self::EVENT_DIFF as $eventDiff) {
+ $eventToFilterData[] = IMipService::readPropertyWithDefault($eventToFilter, $eventDiff, '');
+ }
+ // events are identical and can be removed
+ if (empty(array_diff($filterEventData, $eventToFilterData))) {
+ unset($eventsToFilter[$k]);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Compare two VCalendars with each other and find all changed elements
+ *
+ * Returns an array of old and new events
+ *
+ * Old events are only detected if they are also changed
+ * If there is no corresponding old event for a VEvent, it
+ * has been newly created
+ *
+ * @param VCalendar $new
+ * @param VCalendar|null $old
+ * @return array<string, VEvent[]>
+ */
+ public function findModified(VCalendar $new, ?VCalendar $old): array {
+ $newEventComponents = $new->getComponents();
+
+ foreach ($newEventComponents as $k => $event) {
+ if(!$event instanceof VEvent) {
+ unset($newEventComponents[$k]);
+ }
+ }
+
+ if(empty($old)) {
+ return ['old' => null, 'new' => $newEventComponents];
+ }
+
+ $oldEventComponents = $old->getComponents();
+ if(is_array($oldEventComponents) && !empty($oldEventComponents)) {
+ foreach ($oldEventComponents as $k => $event) {
+ if(!$event instanceof VEvent) {
+ unset($oldEventComponents[$k]);
+ continue;
+ }
+ if($this->removeIfUnchanged($event, $newEventComponents)) {
+ unset($oldEventComponents[$k]);
+ }
+ }
+ }
+
+ return ['old' => array_values($oldEventComponents), 'new' => array_values($newEventComponents)];
+ }
+}