From 0e88470b75d9abaac4147c51e7fcbb956b9471f3 Mon Sep 17 00:00:00 2001 From: Christian Weiske Date: Tue, 11 Aug 2020 22:13:55 +0200 Subject: [PATCH] Delete old birthday calendar object when moving contact to another address book When an contact is moved to another address book, the contact is copied to the second address book. During copying, the birthday event is created - but it gets the same UID as the contact's birthday event in the first address book. To prevent the "Calendar object with uid already exists" error that followed, we need to delete the old entry before the new one is created. Resolves: https://github.com/nextcloud/server/issues/20492 Signed-off-by: Christian Weiske --- apps/dav/lib/CalDAV/BirthdayService.php | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/dav/lib/CalDAV/BirthdayService.php b/apps/dav/lib/CalDAV/BirthdayService.php index c4163ceef6..7ec296ee15 100644 --- a/apps/dav/lib/CalDAV/BirthdayService.php +++ b/apps/dav/lib/CalDAV/BirthdayService.php @@ -380,12 +380,26 @@ class BirthdayService { $objectUri = $book['uri'] . '-' . $cardUri . $type['postfix'] . '.ics'; $calendarData = $this->buildDateFromContact($cardData, $type['field'], $type['postfix']); $existing = $this->calDavBackEnd->getCalendarObject($calendarId, $objectUri); - if (is_null($calendarData)) { - if (!is_null($existing)) { + if ($calendarData === null) { + if ($existing !== null) { $this->calDavBackEnd->deleteCalendarObject($calendarId, $objectUri); } } else { - if (is_null($existing)) { + if ($existing === null) { + // not found by URI, but maybe by UID + // happens when a contact with birthday is moved to a different address book + $calendarInfo = $this->calDavBackEnd->getCalendarById($calendarId); + $extraData = $this->calDavBackEnd->getDenormalizedData($calendarData->serialize()); + + if ($calendarInfo && array_key_exists('principaluri', $calendarInfo)) { + $existing2path = $this->calDavBackEnd->getCalendarObjectByUID($calendarInfo['principaluri'], $extraData['uid']); + if ($existing2path !== null && array_key_exists('uri', $calendarInfo)) { + // delete the old birthday entry first so that we do not get duplicate UIDs + $existing2objectUri = substr($existing2path, strlen($calendarInfo['uri']) + 1); + $this->calDavBackEnd->deleteCalendarObject($calendarId, $existing2objectUri); + } + } + $this->calDavBackEnd->createCalendarObject($calendarId, $objectUri, $calendarData->serialize()); } else { if ($this->birthdayEvenChanged($existing['calendardata'], $calendarData)) {