Skip to content

Commit ef0e221

Browse files
committed
fix(caldav): rename default calendar to keep it in the trashbin instead of purging it
When doing a PROPFIND on default-calendar-url, if the current default calendar (fallbacking on personal uri) is in the trashbin, it's being purged so that it's recreated. This leads to loss of data. We can simply rename the calendar URI and add a unique suffix so that it doesn't conflict with the new calendar being created. Shares are fine because they reference the resourceid and not the calendar URI. Signed-off-by: Thomas Citharel <tcit@tcit.fr>
1 parent 72e8241 commit ef0e221

2 files changed

Lines changed: 21 additions & 9 deletions

File tree

apps/dav/lib/CalDAV/Schedule/Plugin.php

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ protected function getAddressesForPrincipal($principal) {
138138
if ($result === null) {
139139
$result = [];
140140
}
141-
141+
142142
// iterate through items and html decode values
143143
foreach ($result as $key => $value) {
144144
$result[$key] = urldecode($value);
@@ -197,12 +197,12 @@ public function calendarObjectChange(RequestInterface $request, ResponseInterfac
197197
}
198198
// process request
199199
$this->processICalendarChange($currentObject, $vCal, $addresses, [], $modified);
200-
200+
201201
if ($currentObject) {
202202
// Destroy circular references so PHP will GC the object.
203203
$currentObject->destroy();
204204
}
205-
205+
206206
} catch (SameOrganizerForAllComponentsException $e) {
207207
$this->handleSameOrganizerException($e, $vCal, $calendarPath);
208208
}
@@ -430,12 +430,20 @@ public function propFindDefaultCalendarUrl(PropFind $propFind, INode $node) {
430430
} else {
431431
// Otherwise if we have really nothing, create a new calendar
432432
if ($currentCalendarDeleted) {
433-
// If the calendar exists but is deleted, we need to purge it first
434-
// This may cause some issues in a non synchronous database setup
433+
// If the calendar exists but is in the trash bin, we try to rename its uri
434+
// so that we can create the new one and still restore the previous one
435+
// otherwise we just purge the calendar by removing it before recreating it
435436
$calendar = $this->getCalendar($calendarHome, $uri);
436437
if ($calendar instanceof Calendar) {
437-
$calendar->disableTrashbin();
438-
$calendar->delete();
438+
$backend = $calendarHome->getCalDAVBackend();
439+
if ($backend instanceof CalDavBackend) {
440+
// If the CalDAV backend supports moving calendars
441+
$this->moveCalendar($backend, $principalUrl, $uri, $uri . '-back-' . time());
442+
} else {
443+
// Otherwise just purge the calendar
444+
$calendar->disableTrashbin();
445+
$calendar->delete();
446+
}
439447
}
440448
}
441449
$this->createCalendar($calendarHome, $principalUrl, $uri, $displayName);
@@ -572,7 +580,7 @@ private function isAvailableAtTime(string $email, \DateTimeInterface $start, \Da
572580
$homePath = $result[0][200]['{' . self::NS_CALDAV . '}calendar-home-set']->getHref();
573581
/** @var Calendar $node */
574582
foreach ($this->server->tree->getNodeForPath($homePath)->getChildren() as $node) {
575-
583+
576584
if (!$node instanceof ICalendar) {
577585
continue;
578586
}
@@ -704,6 +712,10 @@ private function createCalendar(CalendarHome $calendarHome, string $principalUri
704712
]);
705713
}
706714

715+
private function moveCalendar(CalDavBackend $calDavBackend, string $principalUri, string $oldUri, string $newUri): void {
716+
$calDavBackend->moveCalendar($oldUri, $principalUri, $principalUri, $newUri);
717+
}
718+
707719
/**
708720
* Try to handle the given exception gracefully or throw it if necessary.
709721
*

apps/dav/tests/unit/CalDAV/Schedule/PluginTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ public function testPropFindDefaultCalendarUrl(string $principalUri, ?string $ca
353353
'{DAV:}displayname' => $displayName,
354354
]);
355355

356-
$calendarHomeObject->expects($this->once())
356+
$calendarHomeObject->expects($this->exactly($deleted ? 2 : 1))
357357
->method('getCalDAVBackend')
358358
->with()
359359
->willReturn($calendarBackend);

0 commit comments

Comments
 (0)