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
1 change: 1 addition & 0 deletions apps/dav/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
'OCA\\DAV\\CalDAV\\CalendarProvider' => $baseDir . '/../lib/CalDAV/CalendarProvider.php',
'OCA\\DAV\\CalDAV\\CalendarRoot' => $baseDir . '/../lib/CalDAV/CalendarRoot.php',
'OCA\\DAV\\CalDAV\\DefaultCalendarValidator' => $baseDir . '/../lib/CalDAV/DefaultCalendarValidator.php',
'OCA\\DAV\\CalDAV\\EmbeddedCalDavServer' => $baseDir . '/../lib/CalDAV/EmbeddedCalDavServer.php',
'OCA\\DAV\\CalDAV\\EventComparisonService' => $baseDir . '/../lib/CalDAV/EventComparisonService.php',
'OCA\\DAV\\CalDAV\\EventReader' => $baseDir . '/../lib/CalDAV/EventReader.php',
'OCA\\DAV\\CalDAV\\EventReaderRDate' => $baseDir . '/../lib/CalDAV/EventReaderRDate.php',
Expand Down
1 change: 1 addition & 0 deletions apps/dav/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\CalDAV\\CalendarProvider' => __DIR__ . '/..' . '/../lib/CalDAV/CalendarProvider.php',
'OCA\\DAV\\CalDAV\\CalendarRoot' => __DIR__ . '/..' . '/../lib/CalDAV/CalendarRoot.php',
'OCA\\DAV\\CalDAV\\DefaultCalendarValidator' => __DIR__ . '/..' . '/../lib/CalDAV/DefaultCalendarValidator.php',
'OCA\\DAV\\CalDAV\\EmbeddedCalDavServer' => __DIR__ . '/..' . '/../lib/CalDAV/EmbeddedCalDavServer.php',
'OCA\\DAV\\CalDAV\\EventComparisonService' => __DIR__ . '/..' . '/../lib/CalDAV/EventComparisonService.php',
'OCA\\DAV\\CalDAV\\EventReader' => __DIR__ . '/..' . '/../lib/CalDAV/EventReader.php',
'OCA\\DAV\\CalDAV\\EventReaderRDate' => __DIR__ . '/..' . '/../lib/CalDAV/EventReaderRDate.php',
Expand Down
30 changes: 18 additions & 12 deletions apps/dav/lib/CalDAV/CalendarImpl.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,19 +156,15 @@ public function isShared(): bool {
}

/**
* Create a new calendar event for this calendar
* by way of an ICS string
*
* @param string $name the file name - needs to contain the .ics ending
* @param string $calendarData a string containing a valid VEVENT ics
*
* @throws CalendarException
*/
public function createFromString(string $name, string $calendarData): void {
$server = new InvitationResponseServer(false);

private function createFromStringInServer(
string $name,
string $calendarData,
\OCA\DAV\Connector\Sabre\Server $server,
): void {
/** @var CustomPrincipalPlugin $plugin */
$plugin = $server->getServer()->getPlugin('auth');
$plugin = $server->getPlugin('auth');
// we're working around the previous implementation
// that only allowed the public system principal to be used
// so set the custom principal here
Expand All @@ -184,21 +180,31 @@ public function createFromString(string $name, string $calendarData): void {

// Force calendar change URI
/** @var Schedule\Plugin $schedulingPlugin */
$schedulingPlugin = $server->getServer()->getPlugin('caldav-schedule');
$schedulingPlugin = $server->getPlugin('caldav-schedule');
$schedulingPlugin->setPathOfCalendarObjectChange($fullCalendarFilename);

$stream = fopen('php://memory', 'rb+');
fwrite($stream, $calendarData);
rewind($stream);
try {
$server->getServer()->createFile($fullCalendarFilename, $stream);
$server->createFile($fullCalendarFilename, $stream);
} catch (Conflict $e) {
throw new CalendarException('Could not create new calendar event: ' . $e->getMessage(), 0, $e);
} finally {
fclose($stream);
}
}

public function createFromString(string $name, string $calendarData): void {
$server = new EmbeddedCalDavServer(false);
$this->createFromStringInServer($name, $calendarData, $server->getServer());
}

public function createFromStringMinimal(string $name, string $calendarData): void {
$server = new InvitationResponseServer(false);
$this->createFromStringInServer($name, $calendarData, $server->getServer());
}

/**
* @throws CalendarException
*/
Expand Down
118 changes: 118 additions & 0 deletions apps/dav/lib/CalDAV/EmbeddedCalDavServer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

declare(strict_types=1);

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

namespace OCA\DAV\CalDAV;

use OCA\DAV\AppInfo\PluginManager;
use OCA\DAV\CalDAV\Auth\CustomPrincipalPlugin;
use OCA\DAV\CalDAV\Auth\PublicPrincipalPlugin;
use OCA\DAV\CalDAV\Publishing\PublishPlugin;
use OCA\DAV\Connector\Sabre\AnonymousOptionsPlugin;
use OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin;
use OCA\DAV\Connector\Sabre\CachingTree;
use OCA\DAV\Connector\Sabre\DavAclPlugin;
use OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin;
use OCA\DAV\Connector\Sabre\LockPlugin;
use OCA\DAV\Connector\Sabre\MaintenancePlugin;
use OCA\DAV\Events\SabrePluginAuthInitEvent;
use OCA\DAV\RootCollection;
use OCA\Theming\ThemingDefaults;
use OCP\App\IAppManager;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IURLGenerator;
use OCP\L10N\IFactory as IL10NFactory;
use OCP\Server;
use Psr\Log\LoggerInterface;

class EmbeddedCalDavServer {
private readonly \OCA\DAV\Connector\Sabre\Server $server;

public function __construct(bool $public = true) {
$baseUri = \OC::$WEBROOT . '/remote.php/dav/';
$logger = Server::get(LoggerInterface::class);
$dispatcher = Server::get(IEventDispatcher::class);
$appConfig = Server::get(IAppConfig::class);
$l10nFactory = Server::get(IL10NFactory::class);
$l10n = $l10nFactory->get('dav');

$root = new RootCollection();
$this->server = new \OCA\DAV\Connector\Sabre\Server(new CachingTree($root));

// Add maintenance plugin
$this->server->addPlugin(new MaintenancePlugin(Server::get(IConfig::class), $l10n));

// Set URL explicitly due to reverse-proxy situations
$this->server->httpRequest->setUrl($baseUri);
$this->server->setBaseUri($baseUri);

$this->server->addPlugin(new BlockLegacyClientPlugin(
Server::get(IConfig::class),
Server::get(ThemingDefaults::class),
));
$this->server->addPlugin(new AnonymousOptionsPlugin());

// allow custom principal uri option
if ($public) {
$this->server->addPlugin(new PublicPrincipalPlugin());
} else {
$this->server->addPlugin(new CustomPrincipalPlugin());
}

// allow setup of additional auth backends
$event = new SabrePluginAuthInitEvent($this->server);
$dispatcher->dispatchTyped($event);

$this->server->addPlugin(new ExceptionLoggerPlugin('webdav', $logger));
$this->server->addPlugin(new LockPlugin());
$this->server->addPlugin(new \Sabre\DAV\Sync\Plugin());

// acl
$acl = new DavAclPlugin();
$acl->principalCollectionSet = [
'principals/users', 'principals/groups'
];
$this->server->addPlugin($acl);

// calendar plugins
$this->server->addPlugin(new \OCA\DAV\CalDAV\Plugin());
$this->server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
$this->server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin(Server::get(IConfig::class), Server::get(LoggerInterface::class), Server::get(DefaultCalendarValidator::class)));
$this->server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin());
$this->server->addPlugin(new \Sabre\CalDAV\Notifications\Plugin());
//$this->server->addPlugin(new \OCA\DAV\DAV\Sharing\Plugin($authBackend, \OC::$server->getRequest()));
$this->server->addPlugin(new PublishPlugin(
Server::get(IConfig::class),
Server::get(IURLGenerator::class)
));
if ($appConfig->getValueString('dav', 'sendInvitations', 'yes') === 'yes') {
$this->server->addPlugin(Server::get(\OCA\DAV\CalDAV\Schedule\IMipPlugin::class));
}

// wait with registering these until auth is handled and the filesystem is setup
$this->server->on('beforeMethod:*', function () use ($root): void {
// register plugins from apps
$pluginManager = new PluginManager(
\OC::$server,
Server::get(IAppManager::class)
);
foreach ($pluginManager->getAppPlugins() as $appPlugin) {
$this->server->addPlugin($appPlugin);
}
foreach ($pluginManager->getAppCollections() as $appCollection) {
$root->addChild($appCollection);
}
});
}

public function getServer(): \OCA\DAV\Connector\Sabre\Server {
return $this->server;
}
}
24 changes: 23 additions & 1 deletion lib/public/Calendar/ICreateFromString.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,31 @@
*/
interface ICreateFromString extends ICalendar {
/**
* @since 23.0.0
* Create an event in this calendar from an ICS string.
*
* @param string $name the file name - needs to contain the .ics ending
* @param string $calendarData a string containing a valid VEVENT ics
*
* @throws CalendarException
*
* @since 23.0.0
*
*/
public function createFromString(string $name, string $calendarData): void;

/**
* Create an event in this calendar from an ICS string using a minimal CalDAV server.
* Usually, the createFromString() method should be preferred.
*
* However, in some cases it is useful to not set up a full CalDAV server.
* Missing features include no iMIP plugin, no invitation emails amongst others.
*
* @param string $name the file name - needs to contain the .ics ending
* @param string $calendarData a string containing a valid VEVENT ics
*
* @throws CalendarException
*
* @since 32.0.0
*/
public function createFromStringMinimal(string $name, string $calendarData): void;
}
Loading