Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorVincent Petry <vincent@nextcloud.com>2022-06-10 17:03:09 +0300
committerGitHub <noreply@github.com>2022-06-10 17:03:09 +0300
commitdcfdcf991f7bd7c3f8c9ce91a44088838bcb6657 (patch)
treecec6c9f407cbce8ad84395b4ca3ab0904dc7e380 /apps
parent8e61671b828ec5b963bf9e05ed6f6c443b933af2 (diff)
parenta7b2e8a593ef218ca4218d0633932b15a5bfca76 (diff)
Merge pull request #32361 from nextcloud/dav-scheduling-default-calendar
Put calendar invites into the user's first available calendar
Diffstat (limited to 'apps')
-rw-r--r--apps/dav/lib/CalDAV/Calendar.php9
-rw-r--r--apps/dav/lib/CalDAV/PublicCalendar.php2
-rw-r--r--apps/dav/lib/CalDAV/Schedule/Plugin.php44
-rw-r--r--apps/dav/tests/unit/CalDAV/Schedule/PluginTest.php85
4 files changed, 115 insertions, 25 deletions
diff --git a/apps/dav/lib/CalDAV/Calendar.php b/apps/dav/lib/CalDAV/Calendar.php
index 75c815c3b0a..79d2244b42c 100644
--- a/apps/dav/lib/CalDAV/Calendar.php
+++ b/apps/dav/lib/CalDAV/Calendar.php
@@ -400,7 +400,7 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IRestorable, IShareable
return isset($this->calendarInfo['{http://owncloud.org/ns}public']);
}
- protected function isShared() {
+ public function isShared() {
if (!isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal'])) {
return false;
}
@@ -412,6 +412,13 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IRestorable, IShareable
return isset($this->calendarInfo['{http://calendarserver.org/ns/}source']);
}
+ public function isDeleted(): bool {
+ if (!isset($this->calendarInfo[TrashbinPlugin::PROPERTY_DELETED_AT])) {
+ return false;
+ }
+ return $this->calendarInfo[TrashbinPlugin::PROPERTY_DELETED_AT] !== null;
+ }
+
/**
* @inheritDoc
*/
diff --git a/apps/dav/lib/CalDAV/PublicCalendar.php b/apps/dav/lib/CalDAV/PublicCalendar.php
index 4a29c8d237a..16c7f86917d 100644
--- a/apps/dav/lib/CalDAV/PublicCalendar.php
+++ b/apps/dav/lib/CalDAV/PublicCalendar.php
@@ -84,7 +84,7 @@ class PublicCalendar extends Calendar {
* public calendars are always shared
* @return bool
*/
- protected function isShared() {
+ public function isShared() {
return true;
}
}
diff --git a/apps/dav/lib/CalDAV/Schedule/Plugin.php b/apps/dav/lib/CalDAV/Schedule/Plugin.php
index 96bacce4454..74865297944 100644
--- a/apps/dav/lib/CalDAV/Schedule/Plugin.php
+++ b/apps/dav/lib/CalDAV/Schedule/Plugin.php
@@ -30,6 +30,7 @@ namespace OCA\DAV\CalDAV\Schedule;
use DateTimeZone;
use OCA\DAV\CalDAV\CalDavBackend;
+use OCA\DAV\CalDAV\Calendar;
use OCA\DAV\CalDAV\CalendarHome;
use OCP\IConfig;
use Sabre\CalDAV\ICalendar;
@@ -299,12 +300,14 @@ EOF;
return null;
}
+ $isResourceOrRoom = strpos($principalUrl, 'principals/calendar-resources') === 0 ||
+ strpos($principalUrl, 'principals/calendar-rooms') === 0;
+
if (strpos($principalUrl, 'principals/users') === 0) {
[, $userId] = split($principalUrl);
$uri = $this->config->getUserValue($userId, 'dav', 'defaultCalendar', CalDavBackend::PERSONAL_CALENDAR_URI);
$displayName = CalDavBackend::PERSONAL_CALENDAR_NAME;
- } elseif (strpos($principalUrl, 'principals/calendar-resources') === 0 ||
- strpos($principalUrl, 'principals/calendar-rooms') === 0) {
+ } elseif ($isResourceOrRoom) {
$uri = CalDavBackend::RESOURCE_BOOKING_CALENDAR_URI;
$displayName = CalDavBackend::RESOURCE_BOOKING_CALENDAR_NAME;
} else {
@@ -316,9 +319,40 @@ EOF;
/** @var CalendarHome $calendarHome */
$calendarHome = $this->server->tree->getNodeForPath($calendarHomePath);
if (!$calendarHome->childExists($uri)) {
- $calendarHome->getCalDAVBackend()->createCalendar($principalUrl, $uri, [
- '{DAV:}displayname' => $displayName,
- ]);
+ // If the default calendar doesn't exist
+ if ($isResourceOrRoom) {
+ $calendarHome->getCalDAVBackend()->createCalendar($principalUrl, $uri, [
+ '{DAV:}displayname' => $displayName,
+ ]);
+ } else {
+ // And we're not handling scheduling on resource/room booking
+ $userCalendars = [];
+ /**
+ * If the default calendar of the user isn't set and the
+ * fallback doesn't match any of the user's calendar
+ * try to find the first "personal" calendar we can write to
+ * instead of creating a new one.
+ * A appropriate personal calendar to receive invites:
+ * - isn't a calendar subscription
+ * - user can write to it (no virtual/3rd-party calendars)
+ * - calendar isn't a share
+ */
+ foreach ($calendarHome->getChildren() as $node) {
+ if ($node instanceof Calendar && !$node->isSubscription() && $node->canWrite() && !$node->isShared() && !$node->isDeleted()) {
+ $userCalendars[] = $node;
+ }
+ }
+
+ if (count($userCalendars) > 0) {
+ // Calendar backend returns calendar by calendarorder property
+ $uri = $userCalendars[0]->getName();
+ } else {
+ // Otherwise if we have really nothing, create a new calendar
+ $calendarHome->getCalDAVBackend()->createCalendar($principalUrl, $uri, [
+ '{DAV:}displayname' => $displayName,
+ ]);
+ }
+ }
}
$result = $this->server->getPropertiesForPath($calendarHomePath . '/' . $uri, [], 1);
diff --git a/apps/dav/tests/unit/CalDAV/Schedule/PluginTest.php b/apps/dav/tests/unit/CalDAV/Schedule/PluginTest.php
index 2518cc3d91a..b651379c2bd 100644
--- a/apps/dav/tests/unit/CalDAV/Schedule/PluginTest.php
+++ b/apps/dav/tests/unit/CalDAV/Schedule/PluginTest.php
@@ -27,11 +27,15 @@
namespace OCA\DAV\Tests\unit\CalDAV\Schedule;
use OCA\DAV\CalDAV\CalDavBackend;
+use OCA\DAV\CalDAV\Calendar;
use OCA\DAV\CalDAV\CalendarHome;
use OCA\DAV\CalDAV\Plugin as CalDAVPlugin;
use OCA\DAV\CalDAV\Schedule\Plugin;
+use OCA\DAV\CalDAV\Trashbin\Plugin as TrashbinPlugin;
use OCP\IConfig;
+use OCP\IL10N;
use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\LoggerInterface;
use Sabre\DAV\PropFind;
use Sabre\DAV\Server;
use Sabre\DAV\Tree;
@@ -73,17 +77,22 @@ class PluginTest extends TestCase {
public function testInitialize() {
$plugin = new Plugin($this->config);
- $this->server->expects($this->at(7))
+ $this->server->expects($this->exactly(10))
->method('on')
- ->with('propFind', [$plugin, 'propFindDefaultCalendarUrl'], 90);
-
- $this->server->expects($this->at(8))
- ->method('on')
- ->with('afterWriteContent', [$plugin, 'dispatchSchedulingResponses']);
-
- $this->server->expects($this->at(9))
- ->method('on')
- ->with('afterCreateFile', [$plugin, 'dispatchSchedulingResponses']);
+ ->withConsecutive(
+ // Sabre\CalDAV\Schedule\Plugin events
+ ['method:POST', [$plugin, 'httpPost']],
+ ['propFind', [$plugin, 'propFind']],
+ ['propPatch', [$plugin, 'propPatch']],
+ ['calendarObjectChange', [$plugin, 'calendarObjectChange']],
+ ['beforeUnbind', [$plugin, 'beforeUnbind']],
+ ['schedule', [$plugin, 'scheduleLocalDelivery']],
+ ['getSupportedPrivilegeSet', [$plugin, 'getSupportedPrivilegeSet']],
+ // OCA\DAV\CalDAV\Schedule\Plugin events
+ ['propFind', [$plugin, 'propFindDefaultCalendarUrl'], 90],
+ ['afterWriteContent', [$plugin, 'dispatchSchedulingResponses']],
+ ['afterCreateFile', [$plugin, 'dispatchSchedulingResponses']]
+ );
$plugin->initialize($this->server);
}
@@ -183,6 +192,15 @@ class PluginTest extends TestCase {
false,
CalDavBackend::PERSONAL_CALENDAR_URI,
CalDavBackend::PERSONAL_CALENDAR_NAME,
+ false,
+ true
+ ],
+ [
+ 'principals/users/myuser',
+ 'calendars/myuser',
+ false,
+ CalDavBackend::PERSONAL_CALENDAR_URI,
+ CalDavBackend::PERSONAL_CALENDAR_NAME,
false
],
[
@@ -201,6 +219,7 @@ class PluginTest extends TestCase {
CalDavBackend::PERSONAL_CALENDAR_NAME,
true,
false,
+ false,
],
[
'principals/users/myuser',
@@ -240,14 +259,14 @@ class PluginTest extends TestCase {
/**
* @dataProvider propFindDefaultCalendarUrlProvider
* @param string $principalUri
- * @param string $calendarHome
+ * @param string|null $calendarHome
* @param bool $isResource
* @param string $calendarUri
* @param string $displayName
* @param bool $exists
* @param bool $propertiesForPath
*/
- public function testPropFindDefaultCalendarUrl(string $principalUri, ?string $calendarHome, bool $isResource, string $calendarUri, string $displayName, bool $exists, bool $propertiesForPath = true) {
+ public function testPropFindDefaultCalendarUrl(string $principalUri, ?string $calendarHome, bool $isResource, string $calendarUri, string $displayName, bool $exists, bool $hasExistingCalendars = false, bool $propertiesForPath = true) {
/** @var PropFind $propFind */
$propFind = new PropFind(
$principalUri,
@@ -290,6 +309,7 @@ class PluginTest extends TestCase {
$this->assertNull($propFind->get(Plugin::SCHEDULE_DEFAULT_CALENDAR_URL));
return;
}
+
if (!$isResource) {
$this->config->expects($this->once())
->method('getUserValue')
@@ -303,18 +323,47 @@ class PluginTest extends TestCase {
->with($calendarUri)
->willReturn($exists);
+ $calendarBackend = $this->createMock(CalDavBackend::class);
+ $calendarUri = $hasExistingCalendars ? 'custom' : $calendarUri;
+ $displayName = $hasExistingCalendars ? 'Custom Calendar' : $displayName;
+
+ $existingCalendars = $hasExistingCalendars ? [
+ new Calendar(
+ $calendarBackend,
+ ['uri' => 'deleted', '{DAV:}displayname' => 'A deleted calendar', TrashbinPlugin::PROPERTY_DELETED_AT => 42],
+ $this->createMock(IL10N::class),
+ $this->config,
+ $this->createMock(LoggerInterface::class)
+ ),
+ new Calendar(
+ $calendarBackend,
+ ['uri' => $calendarUri, '{DAV:}displayname' => $displayName],
+ $this->createMock(IL10N::class),
+ $this->config,
+ $this->createMock(LoggerInterface::class)
+ )
+ ] : [];
+
if (!$exists) {
- $calendarBackend = $this->createMock(CalDavBackend::class);
- $calendarBackend->expects($this->once())
+ if (!$hasExistingCalendars) {
+ $calendarBackend->expects($this->once())
->method('createCalendar')
->with($principalUri, $calendarUri, [
'{DAV:}displayname' => $displayName,
]);
- $calendarHomeObject->expects($this->once())
- ->method('getCalDAVBackend')
- ->with()
- ->willReturn($calendarBackend);
+ $calendarHomeObject->expects($this->once())
+ ->method('getCalDAVBackend')
+ ->with()
+ ->willReturn($calendarBackend);
+ }
+
+ if (!$isResource) {
+ $calendarHomeObject->expects($this->once())
+ ->method('getChildren')
+ ->with()
+ ->willReturn($existingCalendars);
+ }
}
/** @var Tree|MockObject $tree */