Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion apps/dav/lib/CalDAV/CalendarObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ public function get() {
}

// shows as busy if event is declared confidential
if ($this->objectData['classification'] === CalDavBackend::CLASSIFICATION_CONFIDENTIAL) {
if ($this->objectData['classification'] === CalDavBackend::CLASSIFICATION_CONFIDENTIAL
&& ($this->isPublic() || !$this->canWrite())) {
$this->createConfidentialObject($vObject);
}

Expand Down Expand Up @@ -137,6 +138,10 @@ private function canWrite() {
return true;
}

private function isPublic(): bool {
return $this->calendarInfo['{http://owncloud.org/ns}public'] ?? false;
}

public function getCalendarId(): int {
return (int) $this->objectData['calendarid'];
}
Expand Down
139 changes: 139 additions & 0 deletions apps/dav/tests/unit/CalDAV/CalendarObjectTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\DAV\Tests\unit\CalDAV;

use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CalDAV\CalendarObject;
use OCP\IL10N;
use PHPUnit\Framework\MockObject\MockObject;
use Sabre\VObject\Component\VCalendar;
use Sabre\VObject\Component\VEvent;
use Sabre\VObject\Reader as VObjectReader;
use Test\TestCase;

class CalendarObjectTest extends TestCase {
private readonly CalDavBackend&MockObject $calDavBackend;
private readonly IL10N&MockObject $l10n;

protected function setUp(): void {
parent::setUp();

$this->calDavBackend = $this->createMock(CalDavBackend::class);
$this->l10n = $this->createMock(IL10N::class);

$this->l10n->method('t')
->willReturnArgument(0);
}

public static function provideConfidentialObjectData(): array {
return [
// Shared writable
[
false,
[
'principaluri' => 'user1',
'{http://owncloud.org/ns}owner-principal' => 'user2',
],
],
[
false,
[
'principaluri' => 'user1',
'{http://owncloud.org/ns}owner-principal' => 'user2',
'{http://owncloud.org/ns}read-only' => 0,
],
],
[
false,
[
'principaluri' => 'user1',
'{http://owncloud.org/ns}owner-principal' => 'user2',
'{http://owncloud.org/ns}read-only' => false,
],
],
// Shared read-only
[
true,
[
'principaluri' => 'user1',
'{http://owncloud.org/ns}owner-principal' => 'user2',
'{http://owncloud.org/ns}read-only' => 1,
],
],
[
true,
[
'principaluri' => 'user1',
'{http://owncloud.org/ns}owner-principal' => 'user2',
'{http://owncloud.org/ns}read-only' => true,
],
],
];
}

/**
* @dataProvider provideConfidentialObjectData
*/
public function testGetWithConfidentialObject(
bool $expectConfidential,
array $calendarInfo,
): void {
$ics = <<<EOF
BEGIN:VCALENDAR
CALSCALE:GREGORIAN
VERSION:2.0
PRODID:-//IDN nextcloud.com//Calendar app 5.5.0-dev.1//EN
BEGIN:VEVENT
CREATED:20250820T102647Z
DTSTAMP:20250820T103038Z
LAST-MODIFIED:20250820T103038Z
SEQUENCE:4
UID:a0f55f1f-4f0e-4db8-a54b-1e8b53846591
DTSTART;TZID=Europe/Berlin:20250822T110000
DTEND;TZID=Europe/Berlin:20250822T170000
STATUS:CONFIRMED
SUMMARY:confidential-event
CLASS:CONFIDENTIAL
LOCATION:A location
DESCRIPTION:A description
END:VEVENT
END:VCALENDAR
EOF;
VObjectReader::read($ics);

$calendarObject = new CalendarObject(
$this->calDavBackend,
$this->l10n,
$calendarInfo,
[
'uri' => 'a0f55f1f-4f0e-4db8-a54b-1e8b53846591.ics',
'calendardata' => $ics,
'classification' => 2, // CalDavBackend::CLASSIFICATION_CONFIDENTIAL
],
);

$actualIcs = $calendarObject->get();
$vObject = VObjectReader::read($actualIcs);

$this->assertInstanceOf(VCalendar::class, $vObject);
$vEvent = $vObject->getBaseComponent('VEVENT');
$this->assertInstanceOf(VEvent::class, $vEvent);

if ($expectConfidential) {
$this->assertEquals('Busy', $vEvent->SUMMARY?->getValue());
$this->assertNull($vEvent->DESCRIPTION);
$this->assertNull($vEvent->LOCATION);
} else {
$this->assertEquals('confidential-event', $vEvent->SUMMARY?->getValue());
$this->assertNotNull($vEvent->DESCRIPTION);
$this->assertNotNull($vEvent->LOCATION);
}
}
}
30 changes: 17 additions & 13 deletions apps/dav/tests/unit/CalDAV/CalendarTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,9 @@ public function testPrivateClassification($expectedChildren, $isShared): void {
}
$c = new Calendar($backend, $calendarInfo, $this->l10n, $this->config, $this->logger);
$children = $c->getChildren();
$this->assertEquals($expectedChildren, count($children));
$this->assertCount($expectedChildren, $children);
$children = $c->getMultipleChildren(['event-0', 'event-1', 'event-2']);
$this->assertEquals($expectedChildren, count($children));
$this->assertCount($expectedChildren, $children);

$this->assertEquals(!$isShared, $c->childExists('event-2'));
}
Expand Down Expand Up @@ -393,9 +393,13 @@ public function testConfidentialClassification($expectedChildren, $isShared): vo
'id' => 666,
'uri' => 'cal',
];

if ($isShared) {
$calendarInfo['{http://owncloud.org/ns}read-only'] = true;
}
$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');
Expand Down Expand Up @@ -600,24 +604,24 @@ public function testRemoveVAlarms() {
$this->assertCount(2, $roCalendar->getChildren());

// 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);
$this->assertEquals($publicObjectData, $ownerCalendar->getChild('event-0')->get());
$this->assertEquals($confidentialObjectData, $ownerCalendar->getChild('event-1')->get());

// valarms shall not be removed for read-write shares
$this->assertEquals(
$this->fixLinebreak($rwCalendar->getChild('event-0')->get()),
$this->fixLinebreak($publicObjectData));
$this->fixLinebreak($publicObjectData),
$this->fixLinebreak($rwCalendar->getChild('event-0')->get()));
$this->assertEquals(
$this->fixLinebreak($rwCalendar->getChild('event-1')->get()),
$this->fixLinebreak($confidentialObjectCleaned));
$this->fixLinebreak($confidentialObjectData),
$this->fixLinebreak($rwCalendar->getChild('event-1')->get()));

// valarms shall be removed for read-only shares
$this->assertEquals(
$this->fixLinebreak($roCalendar->getChild('event-0')->get()),
$this->fixLinebreak($publicObjectDataWithoutVAlarm));
$this->fixLinebreak($publicObjectDataWithoutVAlarm),
$this->fixLinebreak($roCalendar->getChild('event-0')->get()));
$this->assertEquals(
$this->fixLinebreak($roCalendar->getChild('event-1')->get()),
$this->fixLinebreak($confidentialObjectCleaned));
$this->fixLinebreak($confidentialObjectCleaned),
$this->fixLinebreak($roCalendar->getChild('event-1')->get()));
}

private function fixLinebreak($str) {
Expand Down
115 changes: 115 additions & 0 deletions apps/dav/tests/unit/CalDAV/PublicCalendarObjectTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\DAV\Tests\unit\CalDAV;

use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CalDAV\PublicCalendarObject;
use OCP\IL10N;
use PHPUnit\Framework\MockObject\MockObject;
use Sabre\VObject\Component\VCalendar;
use Sabre\VObject\Component\VEvent;
use Sabre\VObject\Reader as VObjectReader;
use Test\TestCase;

class PublicCalendarObjectTest extends TestCase {
private readonly CalDavBackend&MockObject $calDavBackend;
private readonly IL10N&MockObject $l10n;

protected function setUp(): void {
parent::setUp();

$this->calDavBackend = $this->createMock(CalDavBackend::class);
$this->l10n = $this->createMock(IL10N::class);

$this->l10n->method('t')
->willReturnArgument(0);
}

public static function provideConfidentialObjectData(): array {
// For some reason, the CalDavBackend always sets read-only to false. Hence, we test for
// both cases as the property should not matter anyway.
// Ref \OCA\DAV\CalDAV\CalDavBackend::getPublicCalendars (approximately in line 538)
return [
[
[
'{http://owncloud.org/ns}read-only' => true,
'{http://owncloud.org/ns}public' => true,
],
],
[
[
'{http://owncloud.org/ns}read-only' => false,
'{http://owncloud.org/ns}public' => true,
],
],
[
[
'{http://owncloud.org/ns}read-only' => 1,
'{http://owncloud.org/ns}public' => true,
],
],
[
[
'{http://owncloud.org/ns}read-only' => 0,
'{http://owncloud.org/ns}public' => true,
],
],
];
}

/**
* @dataProvider provideConfidentialObjectData
*/
public function testGetWithConfidentialObject(array $calendarInfo): void {
$ics = <<<EOF
BEGIN:VCALENDAR
CALSCALE:GREGORIAN
VERSION:2.0
PRODID:-//IDN nextcloud.com//Calendar app 5.5.0-dev.1//EN
BEGIN:VEVENT
CREATED:20250820T102647Z
DTSTAMP:20250820T103038Z
LAST-MODIFIED:20250820T103038Z
SEQUENCE:4
UID:a0f55f1f-4f0e-4db8-a54b-1e8b53846591
DTSTART;TZID=Europe/Berlin:20250822T110000
DTEND;TZID=Europe/Berlin:20250822T170000
STATUS:CONFIRMED
SUMMARY:confidential-event
CLASS:CONFIDENTIAL
LOCATION:A location
DESCRIPTION:A description
END:VEVENT
END:VCALENDAR
EOF;

$calendarObject = new PublicCalendarObject(
$this->calDavBackend,
$this->l10n,
$calendarInfo,
[
'uri' => 'a0f55f1f-4f0e-4db8-a54b-1e8b53846591.ics',
'calendardata' => $ics,
'classification' => 2, // CalDavBackend::CLASSIFICATION_CONFIDENTIAL
],
);

$actualIcs = $calendarObject->get();
$vObject = VObjectReader::read($actualIcs);

$this->assertInstanceOf(VCalendar::class, $vObject);
$vEvent = $vObject->getBaseComponent('VEVENT');
$this->assertInstanceOf(VEvent::class, $vEvent);

$this->assertEquals('Busy', $vEvent->SUMMARY?->getValue());
$this->assertNull($vEvent->DESCRIPTION);
$this->assertNull($vEvent->LOCATION);
}
}
7 changes: 4 additions & 3 deletions apps/dav/tests/unit/CalDAV/PublicCalendarTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ public function testPrivateClassification($expectedChildren, $isShared): void {
$logger = $this->createMock(LoggerInterface::class);
$c = new PublicCalendar($backend, $calendarInfo, $this->l10n, $config, $logger);
$children = $c->getChildren();
$this->assertEquals(2, count($children));
$this->assertCount(2, $children);
$children = $c->getMultipleChildren(['event-0', 'event-1', 'event-2']);
$this->assertEquals(2, count($children));
$this->assertCount(2, $children);

$this->assertFalse($c->childExists('event-2'));
}
Expand Down Expand Up @@ -132,14 +132,15 @@ public function testConfidentialClassification($expectedChildren, $isShared): vo
'principaluri' => 'user2',
'id' => 666,
'uri' => 'cal',
'{http://owncloud.org/ns}public' => true,
];
/** @var MockObject | IConfig $config */
$config = $this->createMock(IConfig::class);
/** @var MockObject | LoggerInterface $logger */
$logger = $this->createMock(LoggerInterface::class);
$c = new PublicCalendar($backend, $calendarInfo, $this->l10n, $config, $logger);

$this->assertEquals(count($c->getChildren()), 2);
$this->assertCount(2, $c->getChildren());

// test private event
$privateEvent = $c->getChild('event-1');
Expand Down
Loading