feat(dav): add custom classification levels for events in public calendars

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>
This commit is contained in:
Thomas Citharel 2025-05-23 10:53:02 +02:00 committed by SebastianKrupinski
parent 927beefae2
commit e401fe5bc9
7 changed files with 144 additions and 49 deletions

View file

@ -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),

View file

@ -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'];
}

View file

@ -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

View file

@ -6,8 +6,35 @@
*/
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

View file

@ -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"],

View file

@ -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]
];
}

View file

@ -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);
}
}