summaryrefslogtreecommitdiffstats
path: root/apps/dav/lib
diff options
context:
space:
mode:
authorThomas Müller <thomas.mueller@tmit.eu>2016-02-19 12:33:19 +0100
committerThomas Müller <thomas.mueller@tmit.eu>2016-02-19 12:33:19 +0100
commitffc29503939ae34338108a50aaaba20e1ec1ad75 (patch)
treea791cede35c6575bf54a761a27a4c77d3c8ef2ba /apps/dav/lib
parentae2304f23f04f1d6c84f2a049a4b0fdc0c9023c6 (diff)
parentd8de7d1e73f303c71a3cf1dea43fb67f3606700d (diff)
downloadnextcloud-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.php187
-rw-r--r--apps/dav/lib/caldav/caldavbackend.php6
-rw-r--r--apps/dav/lib/caldav/calendar.php4
-rw-r--r--apps/dav/lib/carddav/carddavbackend.php34
-rw-r--r--apps/dav/lib/rootcollection.php5
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;