Skip to content

Commit 38e9cb6

Browse files
committed
Use recurrence instance to build iMip email
instead of the main VEVENT of a repeating event Fixes part of nextcloud/calendar#3919 Signed-off-by: Anna Larch <[email protected]>
1 parent db30974 commit 38e9cb6

File tree

8 files changed

+1711
-703
lines changed

8 files changed

+1711
-703
lines changed

apps/dav/composer/composer/autoload_classmap.php

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
'OCA\\DAV\\CalDAV\\CalendarObject' => $baseDir . '/../lib/CalDAV/CalendarObject.php',
5252
'OCA\\DAV\\CalDAV\\CalendarProvider' => $baseDir . '/../lib/CalDAV/CalendarProvider.php',
5353
'OCA\\DAV\\CalDAV\\CalendarRoot' => $baseDir . '/../lib/CalDAV/CalendarRoot.php',
54+
'OCA\\DAV\\CalDAV\\EventComparisonService' => $baseDir . '/../lib/CalDAV/EventComparisonService.php',
5455
'OCA\\DAV\\CalDAV\\ICSExportPlugin\\ICSExportPlugin' => $baseDir . '/../lib/CalDAV/ICSExportPlugin/ICSExportPlugin.php',
5556
'OCA\\DAV\\CalDAV\\IRestorable' => $baseDir . '/../lib/CalDAV/IRestorable.php',
5657
'OCA\\DAV\\CalDAV\\Integration\\ExternalCalendar' => $baseDir . '/../lib/CalDAV/Integration/ExternalCalendar.php',
@@ -83,6 +84,7 @@
8384
'OCA\\DAV\\CalDAV\\ResourceBooking\\RoomPrincipalBackend' => $baseDir . '/../lib/CalDAV/ResourceBooking/RoomPrincipalBackend.php',
8485
'OCA\\DAV\\CalDAV\\RetentionService' => $baseDir . '/../lib/CalDAV/RetentionService.php',
8586
'OCA\\DAV\\CalDAV\\Schedule\\IMipPlugin' => $baseDir . '/../lib/CalDAV/Schedule/IMipPlugin.php',
87+
'OCA\\DAV\\CalDAV\\Schedule\\IMipService' => $baseDir . '/../lib/CalDAV/Schedule/IMipService.php',
8688
'OCA\\DAV\\CalDAV\\Schedule\\Plugin' => $baseDir . '/../lib/CalDAV/Schedule/Plugin.php',
8789
'OCA\\DAV\\CalDAV\\Search\\SearchPlugin' => $baseDir . '/../lib/CalDAV/Search/SearchPlugin.php',
8890
'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\CompFilter' => $baseDir . '/../lib/CalDAV/Search/Xml/Filter/CompFilter.php',

apps/dav/composer/composer/autoload_static.php

+2
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class ComposerStaticInitDAV
6666
'OCA\\DAV\\CalDAV\\CalendarObject' => __DIR__ . '/..' . '/../lib/CalDAV/CalendarObject.php',
6767
'OCA\\DAV\\CalDAV\\CalendarProvider' => __DIR__ . '/..' . '/../lib/CalDAV/CalendarProvider.php',
6868
'OCA\\DAV\\CalDAV\\CalendarRoot' => __DIR__ . '/..' . '/../lib/CalDAV/CalendarRoot.php',
69+
'OCA\\DAV\\CalDAV\\EventComparisonService' => __DIR__ . '/..' . '/../lib/CalDAV/EventComparisonService.php',
6970
'OCA\\DAV\\CalDAV\\ICSExportPlugin\\ICSExportPlugin' => __DIR__ . '/..' . '/../lib/CalDAV/ICSExportPlugin/ICSExportPlugin.php',
7071
'OCA\\DAV\\CalDAV\\IRestorable' => __DIR__ . '/..' . '/../lib/CalDAV/IRestorable.php',
7172
'OCA\\DAV\\CalDAV\\Integration\\ExternalCalendar' => __DIR__ . '/..' . '/../lib/CalDAV/Integration/ExternalCalendar.php',
@@ -98,6 +99,7 @@ class ComposerStaticInitDAV
9899
'OCA\\DAV\\CalDAV\\ResourceBooking\\RoomPrincipalBackend' => __DIR__ . '/..' . '/../lib/CalDAV/ResourceBooking/RoomPrincipalBackend.php',
99100
'OCA\\DAV\\CalDAV\\RetentionService' => __DIR__ . '/..' . '/../lib/CalDAV/RetentionService.php',
100101
'OCA\\DAV\\CalDAV\\Schedule\\IMipPlugin' => __DIR__ . '/..' . '/../lib/CalDAV/Schedule/IMipPlugin.php',
102+
'OCA\\DAV\\CalDAV\\Schedule\\IMipService' => __DIR__ . '/..' . '/../lib/CalDAV/Schedule/IMipService.php',
101103
'OCA\\DAV\\CalDAV\\Schedule\\Plugin' => __DIR__ . '/..' . '/../lib/CalDAV/Schedule/Plugin.php',
102104
'OCA\\DAV\\CalDAV\\Search\\SearchPlugin' => __DIR__ . '/..' . '/../lib/CalDAV/Search/SearchPlugin.php',
103105
'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\CompFilter' => __DIR__ . '/..' . '/../lib/CalDAV/Search/Xml/Filter/CompFilter.php',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* @copyright 2022 Anna Larch <[email protected]>
7+
*
8+
* @author 2022 Anna Larch <[email protected]>
9+
*
10+
* @license GNU AGPL version 3 or any later version
11+
*
12+
* This program is free software: you can redistribute it and/or modify
13+
* it under the terms of the GNU Affero General Public License as
14+
* published by the Free Software Foundation, either version 3 of the
15+
* License, or (at your option) any later version.
16+
*
17+
* This program is distributed in the hope that it will be useful,
18+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
* GNU Affero General Public License for more details.
21+
*
22+
* You should have received a copy of the GNU Affero General Public License
23+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
24+
*
25+
*/
26+
namespace OCA\DAV\CalDAV;
27+
28+
use OCA\DAV\AppInfo\Application;
29+
use OCA\DAV\CalDAV\Schedule\IMipService;
30+
use OCP\AppFramework\Utility\ITimeFactory;
31+
use OCP\IConfig;
32+
use Sabre\VObject\Component\VCalendar;
33+
use Sabre\VObject\Component\VEvent;
34+
use Sabre\VObject\Component\VTimeZone;
35+
use Sabre\VObject\Component\VTodo;
36+
use function max;
37+
38+
class EventComparisonService {
39+
40+
/** @var string[] */
41+
private const EVENT_DIFF = [
42+
'RECURRENCE-ID',
43+
'RRULE',
44+
'SEQUENCE',
45+
'LAST-MODIFIED'
46+
];
47+
48+
49+
/**
50+
* If found, remove the event from $eventsToFilter that
51+
* is identical to the passed $filterEvent
52+
* and return whether an identical event was found
53+
*
54+
* This function takes into account the SEQUENCE,
55+
* RRULE, RECURRENCE-ID and LAST-MODIFIED parameters
56+
*
57+
* @param VEvent $filterEvent
58+
* @param array $eventsToFilter
59+
* @return bool true if there was an identical event found and removed, false if there wasn't
60+
*/
61+
private function removeIfUnchanged(VEvent $filterEvent, array &$eventsToFilter): bool {
62+
$filterEventData = [];
63+
foreach(self::EVENT_DIFF as $eventDiff) {
64+
$filterEventData[] = IMipService::readPropertyWithDefault($filterEvent, $eventDiff, '');
65+
}
66+
67+
/** @var VEvent $component */
68+
foreach ($eventsToFilter as $k => $eventToFilter) {
69+
$eventToFilterData = [];
70+
foreach(self::EVENT_DIFF as $eventDiff) {
71+
$eventToFilterData[] = IMipService::readPropertyWithDefault($eventToFilter, $eventDiff, '');
72+
}
73+
// events are identical and can be removed
74+
if (empty(array_diff($filterEventData, $eventToFilterData))) {
75+
unset($eventsToFilter[$k]);
76+
return true;
77+
}
78+
}
79+
return false;
80+
}
81+
82+
/**
83+
* Compare two VCalendars with each other and find all changed elements
84+
*
85+
* Returns an array of old and new events
86+
*
87+
* Old events are only detected if they are also changed
88+
* If there is no corresponding old event for a VEvent, it
89+
* has been newly created
90+
*
91+
* @param VCalendar $new
92+
* @param VCalendar|null $old
93+
* @return array<string, VEvent[]>
94+
*/
95+
public function findModified(VCalendar $new, ?VCalendar $old): array {
96+
$newEventComponents = $new->getComponents();
97+
98+
foreach ($newEventComponents as $k => $event) {
99+
if(!$event instanceof VEvent) {
100+
unset($newEventComponents[$k]);
101+
}
102+
}
103+
104+
if(empty($old)) {
105+
return ['old' => null, 'new' => $newEventComponents];
106+
}
107+
108+
$oldEventComponents = $old->getComponents();
109+
if(is_array($oldEventComponents) && !empty($oldEventComponents)) {
110+
foreach ($oldEventComponents as $k => $event) {
111+
if(!$event instanceof VEvent) {
112+
unset($oldEventComponents[$k]);
113+
continue;
114+
}
115+
if($this->removeIfUnchanged($event, $newEventComponents)) {
116+
unset($oldEventComponents[$k]);
117+
}
118+
}
119+
}
120+
121+
return ['old' => array_values($oldEventComponents), 'new' => array_values($newEventComponents)];
122+
}
123+
}

0 commit comments

Comments
 (0)