diff options
author | Thomas Citharel <tcit@tcit.fr> | 2025-05-23 10:53:02 +0200 |
---|---|---|
committer | SebastianKrupinski <krupinskis05@gmail.com> | 2025-07-04 10:30:56 -0400 |
commit | e401fe5bc9ce22d94273f729c516b70f2322d83d (patch) | |
tree | bcb0f3562c0a8e67064b41f0d582aa179caa35f2 | |
parent | 927beefae2a79882dbe89ed643689bb6ee033edb (diff) | |
download | nextcloud-server-introduce-publish-classification-levels.tar.gz nextcloud-server-introduce-publish-classification-levels.zip |
feat(dav): add custom classification levels for events in public calendarsintroduce-publish-classification-levels
The CLASS:PRIVATE and CLASS:CONFIDENTIAL apply to events shared as well as published ones. This adds
two new custom CLASS values: X-NEXTCLOUD-CLASS-PUBLISHED-PRIVATE and
X-NEXTCLOUD-CLASS-PUBLISHED-CONFIDENTIAL, which work the same as the standard values, but only when
they are published into a public calendar. Therefore, you can set an event to be public (fully
visible) for people who you shared internally the event's calendar, but private when the calendar
is published.
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
-rw-r--r-- | apps/dav/lib/CalDAV/CalDavBackend.php | 18 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CalendarObject.php | 6 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/PublicCalendar.php | 18 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/PublicCalendarObject.php | 27 | ||||
-rw-r--r-- | apps/dav/tests/unit/CalDAV/CalDavBackendTest.php | 4 | ||||
-rw-r--r-- | apps/dav/tests/unit/CalDAV/CalendarTest.php | 55 | ||||
-rw-r--r-- | apps/dav/tests/unit/CalDAV/PublicCalendarTest.php | 65 |
7 files changed, 144 insertions, 49 deletions
diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index 27750913105..7d7dea86600 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -131,6 +131,8 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription public const CLASSIFICATION_PUBLIC = 0; public const CLASSIFICATION_PRIVATE = 1; public const CLASSIFICATION_CONFIDENTIAL = 2; + public const CLASSIFICATION_PUBLISHED_PRIVATE = 3; + public const CLASSIFICATION_PUBLISHED_CONFIDENTIAL = 4; /** * List of CalDAV properties, and how they map to database field names and their type @@ -3133,15 +3135,13 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription } if ($component->CLASS) { - $classification = CalDavBackend::CLASSIFICATION_PRIVATE; - switch ($component->CLASS->getValue()) { - case 'PUBLIC': - $classification = CalDavBackend::CLASSIFICATION_PUBLIC; - break; - case 'CONFIDENTIAL': - $classification = CalDavBackend::CLASSIFICATION_CONFIDENTIAL; - break; - } + $classification = match ($component->CLASS->getValue()) { + 'PUBLIC' => CalDavBackend::CLASSIFICATION_PUBLIC, + 'CONFIDENTIAL' => CalDavBackend::CLASSIFICATION_CONFIDENTIAL, + 'X-NEXTCLOUD-CLASS-PUBLISHED-PRIVATE' => CalDavBackend::CLASSIFICATION_PUBLISHED_PRIVATE, + 'X-NEXTCLOUD-CLASS-PUBLISHED-CONFIDENTIAL' => CalDavBackend::CLASSIFICATION_PUBLISHED_CONFIDENTIAL, + default => CalDavBackend::CLASSIFICATION_PRIVATE, + }; } return [ 'etag' => md5($calendarData), diff --git a/apps/dav/lib/CalDAV/CalendarObject.php b/apps/dav/lib/CalDAV/CalendarObject.php index 02178b4236f..253f85e88e3 100644 --- a/apps/dav/lib/CalDAV/CalendarObject.php +++ b/apps/dav/lib/CalDAV/CalendarObject.php @@ -76,7 +76,7 @@ class CalendarObject extends \Sabre\CalDAV\CalendarObject { * @param Component\VCalendar $vObject * @return void */ - private function createConfidentialObject(Component\VCalendar $vObject): void { + protected function createConfidentialObject(Component\VCalendar $vObject): void { /** @var Component $vElement */ $vElements = array_filter($vObject->getComponents(), static function ($vElement) { return $vElement instanceof Component\VEvent || $vElement instanceof Component\VJournal || $vElement instanceof Component\VTodo; @@ -117,7 +117,7 @@ class CalendarObject extends \Sabre\CalDAV\CalendarObject { * @param Component\VCalendar $vObject * @return void */ - private function removeVAlarms(Component\VCalendar $vObject) { + protected function removeVAlarms(Component\VCalendar $vObject) { $subcomponents = $vObject->getComponents(); foreach ($subcomponents as $subcomponent) { @@ -128,7 +128,7 @@ class CalendarObject extends \Sabre\CalDAV\CalendarObject { /** * @return bool */ - private function canWrite() { + protected function canWrite() { if (isset($this->calendarInfo['{http://owncloud.org/ns}read-only'])) { return !$this->calendarInfo['{http://owncloud.org/ns}read-only']; } diff --git a/apps/dav/lib/CalDAV/PublicCalendar.php b/apps/dav/lib/CalDAV/PublicCalendar.php index 9af6e544165..2697861c23f 100644 --- a/apps/dav/lib/CalDAV/PublicCalendar.php +++ b/apps/dav/lib/CalDAV/PublicCalendar.php @@ -21,7 +21,7 @@ class PublicCalendar extends Calendar { if (!$obj) { throw new NotFound('Calendar object not found'); } - if ($obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE) { + if (in_array($obj['classification'], [CalDavBackend::CLASSIFICATION_PRIVATE, CalDavBackend::CLASSIFICATION_PUBLISHED_PRIVATE], true)) { throw new NotFound('Calendar object not found'); } $obj['acl'] = $this->getChildACL(); @@ -36,7 +36,7 @@ class PublicCalendar extends Calendar { $objs = $this->caldavBackend->getCalendarObjects($this->calendarInfo['id']); $children = []; foreach ($objs as $obj) { - if ($obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE) { + if (in_array($obj['classification'], [CalDavBackend::CLASSIFICATION_PRIVATE, CalDavBackend::CLASSIFICATION_PUBLISHED_PRIVATE], true)) { continue; } $obj['acl'] = $this->getChildACL(); @@ -53,7 +53,7 @@ class PublicCalendar extends Calendar { $objs = $this->caldavBackend->getMultipleCalendarObjects($this->calendarInfo['id'], $paths); $children = []; foreach ($objs as $obj) { - if ($obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE) { + if (in_array($obj['classification'], [CalDavBackend::CLASSIFICATION_PRIVATE, CalDavBackend::CLASSIFICATION_PUBLISHED_PRIVATE], true)) { continue; } $obj['acl'] = $this->getChildACL(); @@ -62,6 +62,18 @@ class PublicCalendar extends Calendar { return $children; } + public function childExists($name) { + $obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $name); + if (!$obj) { + return false; + } + if (in_array($obj['classification'], [CalDavBackend::CLASSIFICATION_PRIVATE, CalDavBackend::CLASSIFICATION_PUBLISHED_PRIVATE], true) && $this->isShared()) { + return false; + } + + return true; + } + /** * public calendars are always shared * @return bool diff --git a/apps/dav/lib/CalDAV/PublicCalendarObject.php b/apps/dav/lib/CalDAV/PublicCalendarObject.php index 2ab40b94347..40eefc35600 100644 --- a/apps/dav/lib/CalDAV/PublicCalendarObject.php +++ b/apps/dav/lib/CalDAV/PublicCalendarObject.php @@ -6,9 +6,36 @@ */ namespace OCA\DAV\CalDAV; +use Sabre\VObject\Reader; + class PublicCalendarObject extends CalendarObject { /** + * @inheritdoc + */ + public function get() { + $data = parent::get(); + + if (!$this->isShared()) { + 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 or external confidential + if (in_array($this->objectData['classification'], [CalDavBackend::CLASSIFICATION_CONFIDENTIAL, CalDavBackend::CLASSIFICATION_PUBLISHED_CONFIDENTIAL], true)) { + $this->createConfidentialObject($vObject); + } + + return $vObject->serialize(); + } + + /** * public calendars are always shared * @return bool */ diff --git a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php index f9205d5d322..33211e8e52d 100644 --- a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php +++ b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php @@ -736,6 +736,10 @@ EOS; 'CLASS:CONFIDENTIAL' => [CalDavBackend::CLASSIFICATION_CONFIDENTIAL, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nCLASS:CONFIDENTIAL\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"], + 'CLASS:X-NEXTCLOUD-CLASS-PUBLISHED-PRIVATE' => [CalDavBackend::CLASSIFICATION_PUBLISHED_PRIVATE, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nCLASS:X-NEXTCLOUD-CLASS-PUBLISHED-PRIVATE\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"], + + 'CLASS:X-NEXTCLOUD-CLASS-PUBLISHED-CONFIDENTIAL' => [CalDavBackend::CLASSIFICATION_PUBLISHED_CONFIDENTIAL, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nCLASS:X-NEXTCLOUD-CLASS-PUBLISHED-CONFIDENTIAL\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"], + 'no class set -> public' => [CalDavBackend::CLASSIFICATION_PUBLIC, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nTRANSP:OPAQUE\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"], 'unknown class -> private' => [CalDavBackend::CLASSIFICATION_PRIVATE, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nCLASS:VERTRAULICH\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"], diff --git a/apps/dav/tests/unit/CalDAV/CalendarTest.php b/apps/dav/tests/unit/CalDAV/CalendarTest.php index b0d3c35bfe7..d6f91af8fa4 100644 --- a/apps/dav/tests/unit/CalDAV/CalendarTest.php +++ b/apps/dav/tests/unit/CalDAV/CalendarTest.php @@ -271,19 +271,26 @@ class CalendarTest extends TestCase { $calObject0 = ['uri' => 'event-0', 'classification' => CalDavBackend::CLASSIFICATION_PUBLIC]; $calObject1 = ['uri' => 'event-1', 'classification' => CalDavBackend::CLASSIFICATION_CONFIDENTIAL]; $calObject2 = ['uri' => 'event-2', 'classification' => CalDavBackend::CLASSIFICATION_PRIVATE]; + $calObject3 = ['uri' => 'event-3', 'classification' => CalDavBackend::CLASSIFICATION_PUBLISHED_PRIVATE]; + $calObject4 = ['uri' => 'event-4', 'classification' => CalDavBackend::CLASSIFICATION_PUBLISHED_CONFIDENTIAL]; /** @var CalDavBackend&MockObject $backend */ $backend = $this->createMock(CalDavBackend::class); $backend->expects($this->any())->method('getCalendarObjects')->willReturn([ - $calObject0, $calObject1, $calObject2 + $calObject0, $calObject1, $calObject2, $calObject3, $calObject4 ]); $backend->expects($this->any())->method('getMultipleCalendarObjects') - ->with(666, ['event-0', 'event-1', 'event-2']) + ->with(666, ['event-0', 'event-1', 'event-2', 'event-3', 'event-4']) ->willReturn([ - $calObject0, $calObject1, $calObject2 + $calObject0, $calObject1, $calObject2, $calObject3, $calObject4 ]); - $backend->expects($this->any())->method('getCalendarObject') - ->willReturn($calObject2)->with(666, 'event-2'); + $matcher = $this->exactly(2); + $backend->expects($matcher)->method('getCalendarObject') + ->willReturnCallback(fn (int $key, string $uri) => + match ([$key, $uri]) { + [666, 'event-2'] => $calObject2, + [666, 'event-3'] => $calObject3, + }); $backend->expects($this->any())->method('applyShareAcl')->willReturnArgument(1); $calendarInfo = [ @@ -297,11 +304,12 @@ class CalendarTest extends TestCase { } $c = new Calendar($backend, $calendarInfo, $this->l10n, $this->config, $this->logger); $children = $c->getChildren(); - $this->assertEquals($expectedChildren, count($children)); - $children = $c->getMultipleChildren(['event-0', 'event-1', 'event-2']); - $this->assertEquals($expectedChildren, count($children)); + $this->assertCount($expectedChildren, $children); + $children = $c->getMultipleChildren(['event-0', 'event-1', 'event-2', 'event-3', 'event-4']); + $this->assertCount($expectedChildren, $children); $this->assertEquals(!$isShared, $c->childExists('event-2')); + $this->assertTrue($c->childExists('event-3')); } #[\PHPUnit\Framework\Attributes\DataProvider('providesConfidentialClassificationData')] @@ -354,19 +362,26 @@ EOD; $calObject0 = ['uri' => 'event-0', 'classification' => CalDavBackend::CLASSIFICATION_PUBLIC]; $calObject1 = ['uri' => 'event-1', 'classification' => CalDavBackend::CLASSIFICATION_CONFIDENTIAL, 'calendardata' => $calData]; $calObject2 = ['uri' => 'event-2', 'classification' => CalDavBackend::CLASSIFICATION_PRIVATE]; + $calObject3 = ['uri' => 'event-3', 'classification' => CalDavBackend::CLASSIFICATION_PUBLISHED_CONFIDENTIAL, 'calendardata' => $calData]; + $calObject4 = ['uri' => 'event-2', 'classification' => CalDavBackend::CLASSIFICATION_PUBLISHED_PRIVATE]; /** @var CalDavBackend&MockObject $backend */ $backend = $this->createMock(CalDavBackend::class); $backend->expects($this->any())->method('getCalendarObjects')->willReturn([ - $calObject0, $calObject1, $calObject2 + $calObject0, $calObject1, $calObject2, $calObject3, $calObject4 ]); $backend->expects($this->any())->method('getMultipleCalendarObjects') - ->with(666, ['event-0', 'event-1', 'event-2']) + ->with(666, ['event-0', 'event-1', 'event-2', 'event-3', 'event-4']) ->willReturn([ - $calObject0, $calObject1, $calObject2 + $calObject0, $calObject1, $calObject2, $calObject3, $calObject4 ]); - $backend->expects($this->any())->method('getCalendarObject') - ->willReturn($calObject1)->with(666, 'event-1'); + $matcher = $this->exactly(3); + $backend->expects($matcher)->method('getCalendarObject') + ->willReturnCallback(fn (int $key, string $uri) => + match ([$key, $uri]) { + [666, 'event-1'] => $calObject1, + [666, 'event-3'] => $calObject3, + }); $backend->expects($this->any())->method('applyShareAcl')->willReturnArgument(1); $calendarInfo = [ @@ -377,7 +392,7 @@ EOD; ]; $c = new Calendar($backend, $calendarInfo, $this->l10n, $this->config, $this->logger); - $this->assertEquals(count($c->getChildren()), $expectedChildren); + $this->assertCount($expectedChildren, $c->getChildren()); // test private event $privateEvent = $c->getChild('event-1'); @@ -397,6 +412,14 @@ EOD; $this->assertEquals('Test Event', $event->VEVENT->SUMMARY->getValue()); } + // test published private event + $publishedPrivateEvent = $c->getChild('event-3'); + $publishedCalData = $publishedPrivateEvent->get(); + $publishedEvent = Reader::read($publishedCalData); + + $this->assertNotEquals('Busy', $publishedEvent->VEVENT->SUMMARY->getValue()); + $this->assertEquals('Test Event', $publishedEvent->VEVENT->SUMMARY->getValue()); + // Test l10n $l10n = $this->createMock(IL10N::class); if ($isShared) { @@ -422,8 +445,8 @@ EOD; public static function providesConfidentialClassificationData(): array { return [ - [3, false], - [2, true] + [5, false], + [4, true] ]; } diff --git a/apps/dav/tests/unit/CalDAV/PublicCalendarTest.php b/apps/dav/tests/unit/CalDAV/PublicCalendarTest.php index 98153a067fb..b2489f5dc0b 100644 --- a/apps/dav/tests/unit/CalDAV/PublicCalendarTest.php +++ b/apps/dav/tests/unit/CalDAV/PublicCalendarTest.php @@ -17,23 +17,30 @@ use Sabre\VObject\Reader; class PublicCalendarTest extends CalendarTest { #[\PHPUnit\Framework\Attributes\DataProvider('providesConfidentialClassificationData')] - public function testPrivateClassification(int $expectedChildren, bool $isShared): void { + public function testPrivateClassification(int int $expectedChildren, bool bool $isShared): void { $calObject0 = ['uri' => 'event-0', 'classification' => CalDavBackend::CLASSIFICATION_PUBLIC]; $calObject1 = ['uri' => 'event-1', 'classification' => CalDavBackend::CLASSIFICATION_CONFIDENTIAL]; $calObject2 = ['uri' => 'event-2', 'classification' => CalDavBackend::CLASSIFICATION_PRIVATE]; + $calObject3 = ['uri' => 'event-3', 'classification' => CalDavBackend::CLASSIFICATION_PUBLISHED_PRIVATE]; + $calObject4 = ['uri' => 'event-4', 'classification' => CalDavBackend::CLASSIFICATION_PUBLISHED_CONFIDENTIAL]; - /** @var CalDavBackend&MockObject $backend */ - $backend = $this->getMockBuilder(CalDavBackend::class)->disableOriginalConstructor()->getMock(); + /** @var MockObject | CalDavBackend $backend */ + $backend = $this->createMock(CalDavBackend::class); $backend->expects($this->any())->method('getCalendarObjects')->willReturn([ - $calObject0, $calObject1, $calObject2 + $calObject0, $calObject1, $calObject2, $calObject3, $calObject4 ]); $backend->expects($this->any())->method('getMultipleCalendarObjects') - ->with(666, ['event-0', 'event-1', 'event-2']) + ->with(666, ['event-0', 'event-1', 'event-2', 'event-3', 'event-4']) ->willReturn([ - $calObject0, $calObject1, $calObject2 + $calObject0, $calObject1, $calObject2, $calObject3, $calObject4 ]); - $backend->expects($this->any())->method('getCalendarObject') - ->willReturn($calObject2)->with(666, 'event-2'); + $matcher = $this->exactly(2); + $backend->expects($matcher)->method('getCalendarObject') + ->willReturnCallback(fn (int $key, string $uri) => + match ([$key, $uri]) { + [666, 'event-2'] => $calObject2, + [666, 'event-3'] => $calObject3, + }); $backend->expects($this->any())->method('applyShareAcl')->willReturnArgument(1); $calendarInfo = [ @@ -48,15 +55,16 @@ class PublicCalendarTest extends CalendarTest { $logger = $this->createMock(LoggerInterface::class); $c = new PublicCalendar($backend, $calendarInfo, $this->l10n, $config, $logger); $children = $c->getChildren(); - $this->assertEquals(2, count($children)); - $children = $c->getMultipleChildren(['event-0', 'event-1', 'event-2']); - $this->assertEquals(2, count($children)); + $this->assertEquals(3, count($children)); + $children = $c->getMultipleChildren(['event-0', 'event-1', 'event-2', 'event-3', 'event-4']); + $this->assertEquals(3, count($children)); $this->assertFalse($c->childExists('event-2')); + $this->assertFalse($c->childExists('event-3')); } #[\PHPUnit\Framework\Attributes\DataProvider('providesConfidentialClassificationData')] - public function testConfidentialClassification(int $expectedChildren, bool $isShared): void { + public function testConfidentialClassification(int int $expectedChildren, bool bool $isShared): void { $start = '20160609'; $end = '20160610'; @@ -105,19 +113,26 @@ EOD; $calObject0 = ['uri' => 'event-0', 'classification' => CalDavBackend::CLASSIFICATION_PUBLIC]; $calObject1 = ['uri' => 'event-1', 'classification' => CalDavBackend::CLASSIFICATION_CONFIDENTIAL, 'calendardata' => $calData]; $calObject2 = ['uri' => 'event-2', 'classification' => CalDavBackend::CLASSIFICATION_PRIVATE]; + $calObject3 = ['uri' => 'event-3', 'classification' => CalDavBackend::CLASSIFICATION_PUBLISHED_CONFIDENTIAL, 'calendardata' => $calData]; + $calObject4 = ['uri' => 'event-2', 'classification' => CalDavBackend::CLASSIFICATION_PUBLISHED_PRIVATE]; /** @var CalDavBackend&MockObject $backend */ $backend = $this->getMockBuilder(CalDavBackend::class)->disableOriginalConstructor()->getMock(); $backend->expects($this->any())->method('getCalendarObjects')->willReturn([ - $calObject0, $calObject1, $calObject2 + $calObject0, $calObject1, $calObject2, $calObject3, $calObject4 ]); $backend->expects($this->any())->method('getMultipleCalendarObjects') - ->with(666, ['event-0', 'event-1', 'event-2']) + ->with(666, ['event-0', 'event-1', 'event-2', 'event-3', 'event-4']) ->willReturn([ - $calObject0, $calObject1, $calObject2 + $calObject0, $calObject1, $calObject2, $calObject3, $calObject4 ]); - $backend->expects($this->any())->method('getCalendarObject') - ->willReturn($calObject1)->with(666, 'event-1'); + $matcher = $this->exactly(2); + $backend->expects($matcher)->method('getCalendarObject') + ->willReturnCallback(fn (int $key, string $uri) => + match ([$key, $uri]) { + [666, 'event-1'] => $calObject1, + [666, 'event-3'] => $calObject3, + }); $backend->expects($this->any())->method('applyShareAcl')->willReturnArgument(1); $calendarInfo = [ @@ -132,7 +147,7 @@ EOD; $logger = $this->createMock(LoggerInterface::class); $c = new PublicCalendar($backend, $calendarInfo, $this->l10n, $config, $logger); - $this->assertEquals(count($c->getChildren()), 2); + $this->assertCount(3, $c->getChildren()); // test private event $privateEvent = $c->getChild('event-1'); @@ -147,5 +162,19 @@ EOD; $this->assertArrayNotHasKey('LOCATION', $event->VEVENT); $this->assertArrayNotHasKey('DESCRIPTION', $event->VEVENT); $this->assertArrayNotHasKey('ORGANIZER', $event->VEVENT); + + // test published private event + $privateEvent = $c->getChild('event-3'); + $calData = $privateEvent->get(); + $event = Reader::read($calData); + + $this->assertEquals($start, $event->VEVENT->DTSTART->getValue()); + $this->assertEquals($end, $event->VEVENT->DTEND->getValue()); + + $this->assertEquals('Busy', $event->VEVENT->SUMMARY->getValue()); + $this->assertArrayNotHasKey('ATTENDEE', $event->VEVENT); + $this->assertArrayNotHasKey('LOCATION', $event->VEVENT); + $this->assertArrayNotHasKey('DESCRIPTION', $event->VEVENT); + $this->assertArrayNotHasKey('ORGANIZER', $event->VEVENT); } } |