Passed
Push — master ( 58e4a8...07b9db )
by Blizzz
28:52 queued 14:18
created

EventComparisonService::findModified()   B

Complexity

Conditions 9
Paths 9

Size

Total Lines 27
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 15
c 1
b 0
f 0
nc 9
nop 2
dl 0
loc 27
rs 8.0555
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
}
124