parent
73d46afc3c
commit
c9187cc820
@ -0,0 +1,157 @@ |
||||
<?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); |
||||
if (is_null($calendarData)) { |
||||
$this->calDavBackEnd->deleteCalendarObject($calendar['id'], $objectUri); |
||||
} else { |
||||
$existing = $this->calDavBackEnd->getCalendarObject($calendar['id'], $objectUri); |
||||
if (is_null($existing)) { |
||||
$this->calDavBackEnd->createCalendarObject($calendar['id'], $objectUri, $calendarData->serialize()); |
||||
} else { |
||||
$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'; |
||||
// $lm = new \DateTime('@' . $this->lastModified()); |
||||
// $lm->setTimeZone(new \DateTimeZone('UTC')); |
||||
// $vEvent->DTSTAMP->setDateTime($lm); |
||||
$vEvent->{'UID'} = $doc->UID; |
||||
$vEvent->{'RRULE'} = 'FREQ=YEARLY'; |
||||
$vEvent->{'SUMMARY'} = $title . ' (' . $date->format('Y') . ')'; |
||||
$vEvent->{'TRANSP'} = 'TRANSPARENT'; |
||||
// $appInfo = \OCP\App::getAppInfo('contacts'); |
||||
// $appVersion = \OCP\App::getAppVersion('contacts'); |
||||
// $vCal->PRODID = '-//ownCloud//NONSGML ' . $appInfo['name'] . ' ' . $appVersion . '//EN'; |
||||
$vCal->add($vEvent); |
||||
return $vCal; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,139 @@ |
||||
<?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\Tests\Unit\CardDAV; |
||||
|
||||
use OCA\DAV\CalDAV\BirthdayService; |
||||
use OCA\DAV\CalDAV\CalDavBackend; |
||||
use OCA\DAV\CardDAV\CardDavBackend; |
||||
use Sabre\VObject\Component\VCalendar; |
||||
use Test\TestCase; |
||||
|
||||
class BirthdayServiceTest extends TestCase { |
||||
|
||||
/** @var BirthdayService */ |
||||
private $service; |
||||
/** @var CalDavBackend | \PHPUnit_Framework_MockObject_MockObject */ |
||||
private $calDav; |
||||
/** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject */ |
||||
private $cardDav; |
||||
|
||||
public function setUp() { |
||||
parent::setUp(); |
||||
|
||||
$this->calDav = $this->getMockBuilder('OCA\DAV\CalDAV\CalDavBackend')->disableOriginalConstructor()->getMock(); |
||||
$this->cardDav = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')->disableOriginalConstructor()->getMock(); |
||||
|
||||
$this->service = new BirthdayService($this->calDav, $this->cardDav); |
||||
} |
||||
|
||||
/** |
||||
* @dataProvider providesVCards |
||||
* @param boolean $nullExpected |
||||
* @param string | null $data |
||||
*/ |
||||
public function testBuildBirthdayFromContact($nullExpected, $data) { |
||||
$cal = $this->service->buildBirthdayFromContact($data); |
||||
if ($nullExpected) { |
||||
$this->assertNull($cal); |
||||
} else { |
||||
$this->assertInstanceOf('Sabre\VObject\Component\VCalendar', $cal); |
||||
$this->assertTrue(isset($cal->VEVENT)); |
||||
$this->assertEquals('FREQ=YEARLY', $cal->VEVENT->RRULE->getValue()); |
||||
$this->assertEquals('12345\'s Birthday (1900)', $cal->VEVENT->SUMMARY->getValue()); |
||||
$this->assertEquals('TRANSPARENT', $cal->VEVENT->TRANSP->getValue()); |
||||
} |
||||
} |
||||
|
||||
public function testOnCardDeleted() { |
||||
$this->cardDav->expects($this->once())->method('getAddressBookById') |
||||
->with(666) |
||||
->willReturn([ |
||||
'principaluri' => 'principals/users/user01', |
||||
'uri' => 'default' |
||||
]); |
||||
$this->calDav->expects($this->once())->method('getCalendarByUri') |
||||
->with('principals/users/user01', 'contact_birthdays') |
||||
->willReturn([ |
||||
'id' => 1234 |
||||
]); |
||||
$this->calDav->expects($this->once())->method('deleteCalendarObject')->with(1234, 'default-gump.vcf.ics'); |
||||
|
||||
$this->service->onCardDeleted(666, 'gump.vcf'); |
||||
} |
||||
|
||||
/** |
||||
* @dataProvider providesCardChanges |
||||
*/ |
||||
public function testOnCardChanged($expectedOp) { |
||||
$this->cardDav->expects($this->once())->method('getAddressBookById') |
||||
->with(666) |
||||
->willReturn([ |
||||
'principaluri' => 'principals/users/user01', |
||||
'uri' => 'default' |
||||
]); |
||||
$this->calDav->expects($this->once())->method('getCalendarByUri') |
||||
->with('principals/users/user01', 'contact_birthdays') |
||||
->willReturn([ |
||||
'id' => 1234 |
||||
]); |
||||
|
||||
/** @var BirthdayService | \PHPUnit_Framework_MockObject_MockObject $service */ |
||||
$service = $this->getMock('\OCA\DAV\CalDAV\BirthdayService', |
||||
['buildBirthdayFromContact'], [$this->calDav, $this->cardDav]); |
||||
|
||||
if ($expectedOp === 'delete') { |
||||
$service->expects($this->once())->method('buildBirthdayFromContact')->willReturn(null); |
||||
$this->calDav->expects($this->once())->method('deleteCalendarObject')->with(1234, 'default-gump.vcf.ics'); |
||||
} |
||||
if ($expectedOp === 'create') { |
||||
$service->expects($this->once())->method('buildBirthdayFromContact')->willReturn(new VCalendar()); |
||||
$this->calDav->expects($this->once())->method('createCalendarObject')->with(1234, 'default-gump.vcf.ics', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nEND:VCALENDAR\r\n"); |
||||
} |
||||
if ($expectedOp === 'update') { |
||||
$service->expects($this->once())->method('buildBirthdayFromContact')->willReturn(new VCalendar()); |
||||
$this->calDav->expects($this->once())->method('getCalendarObject')->willReturn(''); |
||||
$this->calDav->expects($this->once())->method('updateCalendarObject')->with(1234, 'default-gump.vcf.ics', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nEND:VCALENDAR\r\n"); |
||||
} |
||||
|
||||
$service->onCardChanged(666, 'gump.vcf', ''); |
||||
} |
||||
|
||||
public function providesCardChanges(){ |
||||
return[ |
||||
['delete'], |
||||
['create'], |
||||
['update'] |
||||
]; |
||||
} |
||||
|
||||
public function providesVCards() { |
||||
return [ |
||||
[true, null], |
||||
[true, ''], |
||||
[true, 'yasfewf'], |
||||
[true, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nEND:VCARD\r\n", "Dr. Foo Bar"], |
||||
[true, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:\r\nEND:VCARD\r\n", "Dr. Foo Bar"], |
||||
[true, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:someday\r\nEND:VCARD\r\n", "Dr. Foo Bar"], |
||||
[false, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:1900-01-01\r\nEND:VCARD\r\n", "Dr. Foo Bar"], |
||||
]; |
||||
} |
||||
} |
||||
Loading…
Reference in new issue