mirror of
https://github.com/nextcloud/server.git
synced 2026-05-28 04:32:30 -04:00
Merge pull request #32361 from nextcloud/dav-scheduling-default-calendar
Put calendar invites into the user's first available calendar
This commit is contained in:
commit
dcfdcf991f
4 changed files with 115 additions and 25 deletions
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class PublicCalendar extends Calendar {
|
|||
* public calendars are always shared
|
||||
* @return bool
|
||||
*/
|
||||
protected function isShared() {
|
||||
public function isShared() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -177,6 +186,15 @@ class PluginTest extends TestCase {
|
|||
CalDavBackend::PERSONAL_CALENDAR_NAME,
|
||||
true
|
||||
],
|
||||
[
|
||||
'principals/users/myuser',
|
||||
'calendars/myuser',
|
||||
false,
|
||||
CalDavBackend::PERSONAL_CALENDAR_URI,
|
||||
CalDavBackend::PERSONAL_CALENDAR_NAME,
|
||||
false,
|
||||
true
|
||||
],
|
||||
[
|
||||
'principals/users/myuser',
|
||||
'calendars/myuser',
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in a new issue