diff options
author | Thomas Müller <thomas.mueller@tmit.eu> | 2016-02-19 12:33:19 +0100 |
---|---|---|
committer | Thomas Müller <thomas.mueller@tmit.eu> | 2016-02-19 12:33:19 +0100 |
commit | ffc29503939ae34338108a50aaaba20e1ec1ad75 (patch) | |
tree | a791cede35c6575bf54a761a27a4c77d3c8ef2ba /apps/dav/lib | |
parent | ae2304f23f04f1d6c84f2a049a4b0fdc0c9023c6 (diff) | |
parent | d8de7d1e73f303c71a3cf1dea43fb67f3606700d (diff) | |
download | nextcloud-server-ffc29503939ae34338108a50aaaba20e1ec1ad75.tar.gz nextcloud-server-ffc29503939ae34338108a50aaaba20e1ec1ad75.zip |
Merge pull request #22198 from owncloud/birthday-calendar
Sync a users contacts birthday to the users birthday calendar
Diffstat (limited to 'apps/dav/lib')
-rw-r--r-- | apps/dav/lib/caldav/birthdayservice.php | 187 | ||||
-rw-r--r-- | apps/dav/lib/caldav/caldavbackend.php | 6 | ||||
-rw-r--r-- | apps/dav/lib/caldav/calendar.php | 4 | ||||
-rw-r--r-- | apps/dav/lib/carddav/carddavbackend.php | 34 | ||||
-rw-r--r-- | apps/dav/lib/rootcollection.php | 5 |
5 files changed, 233 insertions, 3 deletions
diff --git a/apps/dav/lib/caldav/birthdayservice.php b/apps/dav/lib/caldav/birthdayservice.php new file mode 100644 index 00000000000..3b0a2a10e1c --- /dev/null +++ b/apps/dav/lib/caldav/birthdayservice.php @@ -0,0 +1,187 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCA\DAV\CalDAV; + +use Exception; +use OCA\DAV\CardDAV\CardDavBackend; +use Sabre\VObject\Component\VCalendar; +use Sabre\VObject\Reader; + +class BirthdayService { + + const BIRTHDAY_CALENDAR_URI = 'contact_birthdays'; + + /** + * BirthdayService constructor. + * + * @param CalDavBackend $calDavBackEnd + * @param CardDavBackend $cardDavBackEnd + */ + public function __construct($calDavBackEnd, $cardDavBackEnd) { + $this->calDavBackEnd = $calDavBackEnd; + $this->cardDavBackEnd = $cardDavBackEnd; + } + + /** + * @param int $addressBookId + * @param string $cardUri + * @param string $cardData + */ + public function onCardChanged($addressBookId, $cardUri, $cardData) { + + $book = $this->cardDavBackEnd->getAddressBookById($addressBookId); + $principalUri = $book['principaluri']; + $calendarUri = self::BIRTHDAY_CALENDAR_URI; + $calendar = $this->ensureCalendarExists($principalUri, $calendarUri, []); + $objectUri = $book['uri'] . '-' . $cardUri. '.ics'; + $calendarData = $this->buildBirthdayFromContact($cardData); + $existing = $this->calDavBackEnd->getCalendarObject($calendar['id'], $objectUri); + if (is_null($calendarData)) { + if (!is_null($existing)) { + $this->calDavBackEnd->deleteCalendarObject($calendar['id'], $objectUri); + } + } else { + if (is_null($existing)) { + $this->calDavBackEnd->createCalendarObject($calendar['id'], $objectUri, $calendarData->serialize()); + } else { + if ($this->birthdayEvenChanged($existing['calendardata'], $calendarData)) { + $this->calDavBackEnd->updateCalendarObject($calendar['id'], $objectUri, $calendarData->serialize()); + } + } + } + } + + /** + * @param int $addressBookId + * @param string $cardUri + */ + public function onCardDeleted($addressBookId, $cardUri) { + $book = $this->cardDavBackEnd->getAddressBookById($addressBookId); + $principalUri = $book['principaluri']; + $calendarUri = self::BIRTHDAY_CALENDAR_URI; + $calendar = $this->ensureCalendarExists($principalUri, $calendarUri, []); + $objectUri = $book['uri'] . '-' . $cardUri. '.ics'; + $this->calDavBackEnd->deleteCalendarObject($calendar['id'], $objectUri); + } + + /** + * @param string $principal + * @param string $id + * @param array $properties + * @return array|null + * @throws \Sabre\DAV\Exception\BadRequest + */ + public function ensureCalendarExists($principal, $id, $properties) { + $book = $this->calDavBackEnd->getCalendarByUri($principal, $id); + if (!is_null($book)) { + return $book; + } + $this->calDavBackEnd->createCalendar($principal, $id, $properties); + + return $this->calDavBackEnd->getCalendarByUri($principal, $id); + } + + /** + * @param string $cardData + * @return null|VCalendar + */ + public function buildBirthdayFromContact($cardData) { + if (empty($cardData)) { + return null; + } + try { + $doc = Reader::read($cardData); + } catch (Exception $e) { + return null; + } + + if (!isset($doc->BDAY)) { + return null; + } + $birthday = $doc->BDAY; + if (!(string)$birthday) { + return null; + } + $title = str_replace('{name}', + strtr((string)$doc->FN, array('\,' => ',', '\;' => ';')), + '{name}\'s Birthday' + ); + try { + $date = new \DateTime($birthday); + } catch (Exception $e) { + return null; + } + $vCal = new VCalendar(); + $vCal->VERSION = '2.0'; + $vEvent = $vCal->createComponent('VEVENT'); + $vEvent->add('DTSTART'); + $vEvent->DTSTART->setDateTime( + $date + ); + $vEvent->DTSTART['VALUE'] = 'DATE'; + $vEvent->add('DTEND'); + $date->add(new \DateInterval('P1D')); + $vEvent->DTEND->setDateTime( + $date + ); + $vEvent->DTEND['VALUE'] = 'DATE'; + $vEvent->{'UID'} = $doc->UID; + $vEvent->{'RRULE'} = 'FREQ=YEARLY'; + $vEvent->{'SUMMARY'} = $title . ' (' . $date->format('Y') . ')'; + $vEvent->{'TRANSP'} = 'TRANSPARENT'; + $vCal->add($vEvent); + return $vCal; + } + + /** + * @param string $user + */ + public function syncUser($user) { + $books = $this->cardDavBackEnd->getAddressBooksForUser('principals/users/'.$user); + foreach($books as $book) { + $cards = $this->cardDavBackEnd->getCards($book['id']); + foreach($cards as $card) { + $this->onCardChanged($book['id'], $card['uri'], $card['carddata']); + } + } + } + + /** + * @param string $existingCalendarData + * @param VCalendar $newCalendarData + * @return bool + */ + public function birthdayEvenChanged($existingCalendarData, $newCalendarData) { + try { + $existingBirthday = Reader::read($existingCalendarData); + } catch (Exception $ex) { + return true; + } + if ($newCalendarData->VEVENT->DTSTART->getValue() !== $existingBirthday->VEVENT->DTSTART->getValue() || + $newCalendarData->VEVENT->SUMMARY->getValue() !== $existingBirthday->VEVENT->SUMMARY->getValue() + ) { + return true; + } + return false; + } + +} diff --git a/apps/dav/lib/caldav/caldavbackend.php b/apps/dav/lib/caldav/caldavbackend.php index 775612487f9..c674876598d 100644 --- a/apps/dav/lib/caldav/caldavbackend.php +++ b/apps/dav/lib/caldav/caldavbackend.php @@ -235,6 +235,11 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription return array_values($calendars); } + /** + * @param string $principal + * @param string $uri + * @return array|null + */ public function getCalendarByUri($principal, $uri) { $fields = array_values($this->propertyMap); $fields[] = 'id'; @@ -1367,4 +1372,5 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription public function applyShareAcl($resourceId, $acl) { return $this->sharingBackend->applyShareAcl($resourceId, $acl); } + } diff --git a/apps/dav/lib/caldav/calendar.php b/apps/dav/lib/caldav/calendar.php index 8ed5b6563d0..6b34d570eb3 100644 --- a/apps/dav/lib/caldav/calendar.php +++ b/apps/dav/lib/caldav/calendar.php @@ -80,6 +80,10 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable { } function delete() { + if ($this->getName() === BirthdayService::BIRTHDAY_CALENDAR_URI) { + throw new Forbidden(); + } + if (isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal'])) { $principal = 'principal:' . parent::getOwner(); $shares = $this->getShares(); diff --git a/apps/dav/lib/carddav/carddavbackend.php b/apps/dav/lib/carddav/carddavbackend.php index 78706ae6bff..56fa652d798 100644 --- a/apps/dav/lib/carddav/carddavbackend.php +++ b/apps/dav/lib/carddav/carddavbackend.php @@ -37,6 +37,8 @@ use Sabre\DAV\Exception\BadRequest; use Sabre\HTTP\URLUtil; use Sabre\VObject\Component\VCard; use Sabre\VObject\Reader; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\GenericEvent; class CardDavBackend implements BackendInterface, SyncSupport { @@ -64,15 +66,22 @@ class CardDavBackend implements BackendInterface, SyncSupport { const ACCESS_READ_WRITE = 2; const ACCESS_READ = 3; + /** @var EventDispatcherInterface */ + private $dispatcher; + /** * CardDavBackend constructor. * * @param IDBConnection $db * @param Principal $principalBackend + * @param EventDispatcherInterface $dispatcher */ - public function __construct(IDBConnection $db, Principal $principalBackend) { + public function __construct(IDBConnection $db, + Principal $principalBackend, + $dispatcher ) { $this->db = $db; $this->principalBackend = $principalBackend; + $this->dispatcher = $dispatcher; $this->sharingBackend = new Backend($this->db, $principalBackend, 'addressbook'); } @@ -492,6 +501,14 @@ class CardDavBackend implements BackendInterface, SyncSupport { $this->addChange($addressBookId, $cardUri, 1); $this->updateProperties($addressBookId, $cardUri, $cardData); + if (!is_null($this->dispatcher)) { + $this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::createCard', + new GenericEvent(null, [ + 'addressBookId' => $addressBookId, + 'cardUri' => $cardUri, + 'cardData' => $cardData])); + } + return '"' . $etag . '"'; } @@ -536,6 +553,14 @@ class CardDavBackend implements BackendInterface, SyncSupport { $this->addChange($addressBookId, $cardUri, 2); $this->updateProperties($addressBookId, $cardUri, $cardData); + if (!is_null($this->dispatcher)) { + $this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::updateCard', + new GenericEvent(null, [ + 'addressBookId' => $addressBookId, + 'cardUri' => $cardUri, + 'cardData' => $cardData])); + } + return '"' . $etag . '"'; } @@ -560,6 +585,13 @@ class CardDavBackend implements BackendInterface, SyncSupport { $this->addChange($addressBookId, $cardUri, 3); + if (!is_null($this->dispatcher)) { + $this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::deleteCard', + new GenericEvent(null, [ + 'addressBookId' => $addressBookId, + 'cardUri' => $cardUri])); + } + if ($ret === 1) { if ($cardId !== null) { $this->purgeProperties($addressBookId, $cardId); diff --git a/apps/dav/lib/rootcollection.php b/apps/dav/lib/rootcollection.php index 2a8f63a2270..b3648e7ba38 100644 --- a/apps/dav/lib/rootcollection.php +++ b/apps/dav/lib/rootcollection.php @@ -36,6 +36,7 @@ class RootCollection extends SimpleCollection { public function __construct() { $config = \OC::$server->getConfig(); $db = \OC::$server->getDatabaseConnection(); + $dispatcher = \OC::$server->getEventDispatcher(); $userPrincipalBackend = new Principal( \OC::$server->getUserManager(), \OC::$server->getGroupManager() @@ -79,11 +80,11 @@ class RootCollection extends SimpleCollection { \OC::$server->getLogger() ); - $usersCardDavBackend = new CardDavBackend($db, $userPrincipalBackend); + $usersCardDavBackend = new CardDavBackend($db, $userPrincipalBackend, $dispatcher); $usersAddressBookRoot = new AddressBookRoot($userPrincipalBackend, $usersCardDavBackend, 'principals/users'); $usersAddressBookRoot->disableListing = $disableListing; - $systemCardDavBackend = new CardDavBackend($db, $userPrincipalBackend); + $systemCardDavBackend = new CardDavBackend($db, $userPrincipalBackend, $dispatcher); $systemAddressBookRoot = new AddressBookRoot(new SystemPrincipalBackend(), $systemCardDavBackend, 'principals/system'); $systemAddressBookRoot->disableListing = $disableListing; |