diff --git a/apps/dav/lib/CalDAV/CalendarObject.php b/apps/dav/lib/CalDAV/CalendarObject.php index 86aa2c98e8..c268b7410c 100644 --- a/apps/dav/lib/CalDAV/CalendarObject.php +++ b/apps/dav/lib/CalDAV/CalendarObject.php @@ -37,10 +37,24 @@ class CalendarObject extends \Sabre\CalDAV\CalendarObject { */ function get() { $data = parent::get(); - if ($this->isShared() && $this->objectData['classification'] === CalDavBackend::CLASSIFICATION_CONFIDENTIAL) { - return $this->createConfidentialObject($data); + + if (!$this->isShared()) { + return $data; } - return $data; + + $vObject = Reader::read($data); + + // remove VAlarms if calendar is shared read-only + if (!$this->canWrite()) { + $this->removeVAlarms($vObject); + } + + // shows as busy if event is declared confidential + if ($this->objectData['classification'] === CalDavBackend::CLASSIFICATION_CONFIDENTIAL) { + $this->createConfidentialObject($vObject); + } + + return $vObject->serialize(); } protected function isShared() { @@ -52,13 +66,10 @@ class CalendarObject extends \Sabre\CalDAV\CalendarObject { } /** - * @param string $calData - * @return string + * @param Component\VCalendar $vObject + * @return void */ - private static function createConfidentialObject($calData) { - - $vObject = Reader::read($calData); - + private static function createConfidentialObject(Component\VCalendar $vObject) { /** @var Component $vElement */ $vElement = null; if(isset($vObject->VEVENT)) { @@ -92,8 +103,27 @@ class CalendarObject extends \Sabre\CalDAV\CalendarObject { } } } - - return $vObject->serialize(); } + /** + * @param Component\VCalendar $vObject + * @return void + */ + private function removeVAlarms(Component\VCalendar $vObject) { + $subcomponents = $vObject->getComponents(); + + foreach($subcomponents as $subcomponent) { + unset($subcomponent->VALARM); + } + } + + /** + * @return bool + */ + private function canWrite() { + if (isset($this->calendarInfo['{http://owncloud.org/ns}read-only'])) { + return !$this->calendarInfo['{http://owncloud.org/ns}read-only']; + } + return true; + } } diff --git a/apps/dav/tests/unit/CalDAV/CalendarTest.php b/apps/dav/tests/unit/CalDAV/CalendarTest.php index 9ad773dd74..3fb29fd0c6 100644 --- a/apps/dav/tests/unit/CalDAV/CalendarTest.php +++ b/apps/dav/tests/unit/CalDAV/CalendarTest.php @@ -381,4 +381,184 @@ EOD; [2, true] ]; } + + public function testRemoveVAlarms() { + $publicObjectData = << 'event-0', + 'classification' => CalDavBackend::CLASSIFICATION_PUBLIC, + 'calendardata' => $publicObjectData]; + + $confidentialObject = ['uri' => 'event-1', + 'classification' => CalDavBackend::CLASSIFICATION_CONFIDENTIAL, + 'calendardata' => $confidentialObjectData]; + + /** @var \PHPUnit_Framework_MockObject_MockObject | CalDavBackend $backend */ + $backend = $this->createMock(CalDavBackend::class); + $backend->expects($this->any()) + ->method('getCalendarObjects') + ->willReturn([$publicObject, $confidentialObject]); + + $backend->expects($this->any()) + ->method('getMultipleCalendarObjects') + ->with(666, ['event-0', 'event-1']) + ->willReturn([$publicObject, $confidentialObject]); + + $backend->expects($this->any()) + ->method('getCalendarObject') + ->will($this->returnCallback(function($cId, $uri) use($publicObject, $confidentialObject) { + switch($uri) { + case 'event-0': + return $publicObject; + + case 'event-1': + return $confidentialObject; + + default: + throw new \Exception('unexpected uri'); + } + })); + + $backend->expects($this->any()) + ->method('applyShareAcl') + ->willReturnArgument(1); + + $calendarInfoOwner = [ + '{http://owncloud.org/ns}owner-principal' => 'user1', + 'principaluri' => 'user1', + 'id' => 666, + 'uri' => 'cal', + ]; + $calendarInfoSharedRW = [ + '{http://owncloud.org/ns}owner-principal' => 'user1', + 'principaluri' => 'user2', + 'id' => 666, + 'uri' => 'cal', + ]; + $calendarInfoSharedRO = [ + '{http://owncloud.org/ns}owner-principal' => 'user1', + '{http://owncloud.org/ns}read-only' => true, + 'principaluri' => 'user2', + 'id' => 666, + 'uri' => 'cal', + ]; + + $ownerCalendar = new Calendar($backend, $calendarInfoOwner, $this->l10n); + $rwCalendar = new Calendar($backend, $calendarInfoSharedRW, $this->l10n); + $roCalendar = new Calendar($backend, $calendarInfoSharedRO, $this->l10n); + + $this->assertEquals(count($ownerCalendar->getChildren()), 2); + $this->assertEquals(count($rwCalendar->getChildren()), 2); + $this->assertEquals(count($roCalendar->getChildren()), 2); + + // calendar data shall not be altered for the owner + $this->assertEquals($ownerCalendar->getChild('event-0')->get(), $publicObjectData); + $this->assertEquals($ownerCalendar->getChild('event-1')->get(), $confidentialObjectData); + + // valarms shall not be removed for read-write shares + $this->assertEquals( + $this->fixLinebreak($rwCalendar->getChild('event-0')->get()), + $this->fixLinebreak($publicObjectData)); + $this->assertEquals( + $this->fixLinebreak($rwCalendar->getChild('event-1')->get()), + $this->fixLinebreak($confidentialObjectCleaned)); + + // valarms shall be removed for read-only shares + $this->assertEquals( + $this->fixLinebreak($roCalendar->getChild('event-0')->get()), + $this->fixLinebreak($publicObjectDataWithoutVAlarm)); + $this->assertEquals( + $this->fixLinebreak($roCalendar->getChild('event-1')->get()), + $this->fixLinebreak($confidentialObjectCleaned)); + + } + + private function fixLinebreak($str) { + return preg_replace('~(*BSR_ANYCRLF)\R~', "\r\n", $str); + } }