Signed-off-by: Georg Ehrke <developer@georgehrke.com>tags/v15.0.0beta1
} | } | ||||
); | ); | ||||
$eventDispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::createSubscription', | |||||
function(GenericEvent $event) use ($app) { | |||||
$jobList = $app->getContainer()->getServer()->getJobList(); | |||||
$subscriptionData = $event->getArgument('subscriptionData'); | |||||
$jobList->add(\OCA\DAV\BackgroundJob\RefreshWebcalJob::class, [ | |||||
'principaluri' => $subscriptionData['principaluri'], | |||||
'uri' => $subscriptionData['uri'] | |||||
]); | |||||
} | |||||
); | |||||
$eventDispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::deleteSubscription', | |||||
function(GenericEvent $event) use ($app) { | |||||
$jobList = $app->getContainer()->getServer()->getJobList(); | |||||
$subscriptionData = $event->getArgument('subscriptionData'); | |||||
$jobList->remove(\OCA\DAV\BackgroundJob\RefreshWebcalJob::class, [ | |||||
'principaluri' => $subscriptionData['principaluri'], | |||||
'uri' => $subscriptionData['uri'] | |||||
]); | |||||
/** @var \OCA\DAV\CalDAV\CalDavBackend $calDavBackend */ | |||||
$calDavBackend = $app->getContainer()->query(\OCA\DAV\CalDAV\CalDavBackend::class); | |||||
$calDavBackend->purgeAllCachedEventsForSubscription($subscriptionData['id']); | |||||
} | |||||
); | |||||
$eventHandler = function() use ($app) { | $eventHandler = function() use ($app) { | ||||
try { | try { | ||||
$job = $app->getContainer()->query(\OCA\DAV\BackgroundJob\UpdateCalendarResourcesRoomsBackgroundJob::class); | $job = $app->getContainer()->query(\OCA\DAV\BackgroundJob\UpdateCalendarResourcesRoomsBackgroundJob::class); |
<step>OCA\DAV\Migration\FixBirthdayCalendarComponent</step> | <step>OCA\DAV\Migration\FixBirthdayCalendarComponent</step> | ||||
<step>OCA\DAV\Migration\CalDAVRemoveEmptyValue</step> | <step>OCA\DAV\Migration\CalDAVRemoveEmptyValue</step> | ||||
<step>OCA\DAV\Migration\BuildCalendarSearchIndex</step> | <step>OCA\DAV\Migration\BuildCalendarSearchIndex</step> | ||||
<step>OCA\DAV\Migration\RefreshWebcalJobRegistrar</step> | |||||
</post-migration> | </post-migration> | ||||
</repair-steps> | </repair-steps> | ||||
'OCA\\DAV\\BackgroundJob\\CleanupDirectLinksJob' => $baseDir . '/../lib/BackgroundJob/CleanupDirectLinksJob.php', | 'OCA\\DAV\\BackgroundJob\\CleanupDirectLinksJob' => $baseDir . '/../lib/BackgroundJob/CleanupDirectLinksJob.php', | ||||
'OCA\\DAV\\BackgroundJob\\CleanupInvitationTokenJob' => $baseDir . '/../lib/BackgroundJob/CleanupInvitationTokenJob.php', | 'OCA\\DAV\\BackgroundJob\\CleanupInvitationTokenJob' => $baseDir . '/../lib/BackgroundJob/CleanupInvitationTokenJob.php', | ||||
'OCA\\DAV\\BackgroundJob\\GenerateBirthdayCalendarBackgroundJob' => $baseDir . '/../lib/BackgroundJob/GenerateBirthdayCalendarBackgroundJob.php', | 'OCA\\DAV\\BackgroundJob\\GenerateBirthdayCalendarBackgroundJob' => $baseDir . '/../lib/BackgroundJob/GenerateBirthdayCalendarBackgroundJob.php', | ||||
'OCA\\DAV\\BackgroundJob\\RefreshWebcalJob' => $baseDir . '/../lib/BackgroundJob/RefreshWebcalJob.php', | |||||
'OCA\\DAV\\BackgroundJob\\UpdateCalendarResourcesRoomsBackgroundJob' => $baseDir . '/../lib/BackgroundJob/UpdateCalendarResourcesRoomsBackgroundJob.php', | 'OCA\\DAV\\BackgroundJob\\UpdateCalendarResourcesRoomsBackgroundJob' => $baseDir . '/../lib/BackgroundJob/UpdateCalendarResourcesRoomsBackgroundJob.php', | ||||
'OCA\\DAV\\CalDAV\\Activity\\Backend' => $baseDir . '/../lib/CalDAV/Activity/Backend.php', | 'OCA\\DAV\\CalDAV\\Activity\\Backend' => $baseDir . '/../lib/CalDAV/Activity/Backend.php', | ||||
'OCA\\DAV\\CalDAV\\Activity\\Filter\\Calendar' => $baseDir . '/../lib/CalDAV/Activity/Filter/Calendar.php', | 'OCA\\DAV\\CalDAV\\Activity\\Filter\\Calendar' => $baseDir . '/../lib/CalDAV/Activity/Filter/Calendar.php', | ||||
'OCA\\DAV\\CalDAV\\Activity\\Setting\\Todo' => $baseDir . '/../lib/CalDAV/Activity/Setting/Todo.php', | 'OCA\\DAV\\CalDAV\\Activity\\Setting\\Todo' => $baseDir . '/../lib/CalDAV/Activity/Setting/Todo.php', | ||||
'OCA\\DAV\\CalDAV\\BirthdayCalendar\\EnablePlugin' => $baseDir . '/../lib/CalDAV/BirthdayCalendar/EnablePlugin.php', | 'OCA\\DAV\\CalDAV\\BirthdayCalendar\\EnablePlugin' => $baseDir . '/../lib/CalDAV/BirthdayCalendar/EnablePlugin.php', | ||||
'OCA\\DAV\\CalDAV\\BirthdayService' => $baseDir . '/../lib/CalDAV/BirthdayService.php', | 'OCA\\DAV\\CalDAV\\BirthdayService' => $baseDir . '/../lib/CalDAV/BirthdayService.php', | ||||
'OCA\\DAV\\CalDAV\\CachedSubscription' => $baseDir . '/../lib/CalDAV/CachedSubscription.php', | |||||
'OCA\\DAV\\CalDAV\\CachedSubscriptionObject' => $baseDir . '/../lib/CalDAV/CachedSubscriptionObject.php', | |||||
'OCA\\DAV\\CalDAV\\CalDavBackend' => $baseDir . '/../lib/CalDAV/CalDavBackend.php', | 'OCA\\DAV\\CalDAV\\CalDavBackend' => $baseDir . '/../lib/CalDAV/CalDavBackend.php', | ||||
'OCA\\DAV\\CalDAV\\Calendar' => $baseDir . '/../lib/CalDAV/Calendar.php', | 'OCA\\DAV\\CalDAV\\Calendar' => $baseDir . '/../lib/CalDAV/Calendar.php', | ||||
'OCA\\DAV\\CalDAV\\CalendarHome' => $baseDir . '/../lib/CalDAV/CalendarHome.php', | 'OCA\\DAV\\CalDAV\\CalendarHome' => $baseDir . '/../lib/CalDAV/CalendarHome.php', | ||||
'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\PropFilter' => $baseDir . '/../lib/CalDAV/Search/Xml/Filter/PropFilter.php', | 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\PropFilter' => $baseDir . '/../lib/CalDAV/Search/Xml/Filter/PropFilter.php', | ||||
'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\SearchTermFilter' => $baseDir . '/../lib/CalDAV/Search/Xml/Filter/SearchTermFilter.php', | 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\SearchTermFilter' => $baseDir . '/../lib/CalDAV/Search/Xml/Filter/SearchTermFilter.php', | ||||
'OCA\\DAV\\CalDAV\\Search\\Xml\\Request\\CalendarSearchReport' => $baseDir . '/../lib/CalDAV/Search/Xml/Request/CalendarSearchReport.php', | 'OCA\\DAV\\CalDAV\\Search\\Xml\\Request\\CalendarSearchReport' => $baseDir . '/../lib/CalDAV/Search/Xml/Request/CalendarSearchReport.php', | ||||
'OCA\\DAV\\CalDAV\\WebcalCaching\\Plugin' => $baseDir . '/../lib/CalDAV/WebcalCaching/Plugin.php', | |||||
'OCA\\DAV\\Capabilities' => $baseDir . '/../lib/Capabilities.php', | 'OCA\\DAV\\Capabilities' => $baseDir . '/../lib/Capabilities.php', | ||||
'OCA\\DAV\\CardDAV\\AddressBook' => $baseDir . '/../lib/CardDAV/AddressBook.php', | 'OCA\\DAV\\CardDAV\\AddressBook' => $baseDir . '/../lib/CardDAV/AddressBook.php', | ||||
'OCA\\DAV\\CardDAV\\AddressBookImpl' => $baseDir . '/../lib/CardDAV/AddressBookImpl.php', | 'OCA\\DAV\\CardDAV\\AddressBookImpl' => $baseDir . '/../lib/CardDAV/AddressBookImpl.php', | ||||
'OCA\\DAV\\Migration\\BuildCalendarSearchIndexBackgroundJob' => $baseDir . '/../lib/Migration/BuildCalendarSearchIndexBackgroundJob.php', | 'OCA\\DAV\\Migration\\BuildCalendarSearchIndexBackgroundJob' => $baseDir . '/../lib/Migration/BuildCalendarSearchIndexBackgroundJob.php', | ||||
'OCA\\DAV\\Migration\\CalDAVRemoveEmptyValue' => $baseDir . '/../lib/Migration/CalDAVRemoveEmptyValue.php', | 'OCA\\DAV\\Migration\\CalDAVRemoveEmptyValue' => $baseDir . '/../lib/Migration/CalDAVRemoveEmptyValue.php', | ||||
'OCA\\DAV\\Migration\\FixBirthdayCalendarComponent' => $baseDir . '/../lib/Migration/FixBirthdayCalendarComponent.php', | 'OCA\\DAV\\Migration\\FixBirthdayCalendarComponent' => $baseDir . '/../lib/Migration/FixBirthdayCalendarComponent.php', | ||||
'OCA\\DAV\\Migration\\RefreshWebcalJobRegistrar' => $baseDir . '/../lib/Migration/RefreshWebcalJobRegistrar.php', | |||||
'OCA\\DAV\\Migration\\Version1004Date20170825134824' => $baseDir . '/../lib/Migration/Version1004Date20170825134824.php', | 'OCA\\DAV\\Migration\\Version1004Date20170825134824' => $baseDir . '/../lib/Migration/Version1004Date20170825134824.php', | ||||
'OCA\\DAV\\Migration\\Version1004Date20170919104507' => $baseDir . '/../lib/Migration/Version1004Date20170919104507.php', | 'OCA\\DAV\\Migration\\Version1004Date20170919104507' => $baseDir . '/../lib/Migration/Version1004Date20170919104507.php', | ||||
'OCA\\DAV\\Migration\\Version1004Date20170924124212' => $baseDir . '/../lib/Migration/Version1004Date20170924124212.php', | 'OCA\\DAV\\Migration\\Version1004Date20170924124212' => $baseDir . '/../lib/Migration/Version1004Date20170924124212.php', | ||||
'OCA\\DAV\\Migration\\Version1005Date20180413093149' => $baseDir . '/../lib/Migration/Version1005Date20180413093149.php', | 'OCA\\DAV\\Migration\\Version1005Date20180413093149' => $baseDir . '/../lib/Migration/Version1005Date20180413093149.php', | ||||
'OCA\\DAV\\Migration\\Version1005Date20180530124431' => $baseDir . '/../lib/Migration/Version1005Date20180530124431.php', | 'OCA\\DAV\\Migration\\Version1005Date20180530124431' => $baseDir . '/../lib/Migration/Version1005Date20180530124431.php', | ||||
'OCA\\DAV\\Migration\\Version1006Date20180619154313' => $baseDir . '/../lib/Migration/Version1006Date20180619154313.php', | 'OCA\\DAV\\Migration\\Version1006Date20180619154313' => $baseDir . '/../lib/Migration/Version1006Date20180619154313.php', | ||||
'OCA\\DAV\\Migration\\Version1006Date20180628111625' => $baseDir . '/../lib/Migration/Version1006Date20180628111625.php', | |||||
'OCA\\DAV\\Migration\\Version1007Date20181007225117' => $baseDir . '/../lib/Migration/Version1007Date20181007225117.php', | 'OCA\\DAV\\Migration\\Version1007Date20181007225117' => $baseDir . '/../lib/Migration/Version1007Date20181007225117.php', | ||||
'OCA\\DAV\\Migration\\Version1008Date20181030113700' => $baseDir . '/../lib/Migration/Version1008Date20181030113700.php', | 'OCA\\DAV\\Migration\\Version1008Date20181030113700' => $baseDir . '/../lib/Migration/Version1008Date20181030113700.php', | ||||
'OCA\\DAV\\RootCollection' => $baseDir . '/../lib/RootCollection.php', | 'OCA\\DAV\\RootCollection' => $baseDir . '/../lib/RootCollection.php', |
'OCA\\DAV\\BackgroundJob\\CleanupDirectLinksJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupDirectLinksJob.php', | 'OCA\\DAV\\BackgroundJob\\CleanupDirectLinksJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupDirectLinksJob.php', | ||||
'OCA\\DAV\\BackgroundJob\\CleanupInvitationTokenJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupInvitationTokenJob.php', | 'OCA\\DAV\\BackgroundJob\\CleanupInvitationTokenJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupInvitationTokenJob.php', | ||||
'OCA\\DAV\\BackgroundJob\\GenerateBirthdayCalendarBackgroundJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/GenerateBirthdayCalendarBackgroundJob.php', | 'OCA\\DAV\\BackgroundJob\\GenerateBirthdayCalendarBackgroundJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/GenerateBirthdayCalendarBackgroundJob.php', | ||||
'OCA\\DAV\\BackgroundJob\\RefreshWebcalJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/RefreshWebcalJob.php', | |||||
'OCA\\DAV\\BackgroundJob\\UpdateCalendarResourcesRoomsBackgroundJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/UpdateCalendarResourcesRoomsBackgroundJob.php', | 'OCA\\DAV\\BackgroundJob\\UpdateCalendarResourcesRoomsBackgroundJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/UpdateCalendarResourcesRoomsBackgroundJob.php', | ||||
'OCA\\DAV\\CalDAV\\Activity\\Backend' => __DIR__ . '/..' . '/../lib/CalDAV/Activity/Backend.php', | 'OCA\\DAV\\CalDAV\\Activity\\Backend' => __DIR__ . '/..' . '/../lib/CalDAV/Activity/Backend.php', | ||||
'OCA\\DAV\\CalDAV\\Activity\\Filter\\Calendar' => __DIR__ . '/..' . '/../lib/CalDAV/Activity/Filter/Calendar.php', | 'OCA\\DAV\\CalDAV\\Activity\\Filter\\Calendar' => __DIR__ . '/..' . '/../lib/CalDAV/Activity/Filter/Calendar.php', | ||||
'OCA\\DAV\\CalDAV\\Activity\\Setting\\Todo' => __DIR__ . '/..' . '/../lib/CalDAV/Activity/Setting/Todo.php', | 'OCA\\DAV\\CalDAV\\Activity\\Setting\\Todo' => __DIR__ . '/..' . '/../lib/CalDAV/Activity/Setting/Todo.php', | ||||
'OCA\\DAV\\CalDAV\\BirthdayCalendar\\EnablePlugin' => __DIR__ . '/..' . '/../lib/CalDAV/BirthdayCalendar/EnablePlugin.php', | 'OCA\\DAV\\CalDAV\\BirthdayCalendar\\EnablePlugin' => __DIR__ . '/..' . '/../lib/CalDAV/BirthdayCalendar/EnablePlugin.php', | ||||
'OCA\\DAV\\CalDAV\\BirthdayService' => __DIR__ . '/..' . '/../lib/CalDAV/BirthdayService.php', | 'OCA\\DAV\\CalDAV\\BirthdayService' => __DIR__ . '/..' . '/../lib/CalDAV/BirthdayService.php', | ||||
'OCA\\DAV\\CalDAV\\CachedSubscription' => __DIR__ . '/..' . '/../lib/CalDAV/CachedSubscription.php', | |||||
'OCA\\DAV\\CalDAV\\CachedSubscriptionObject' => __DIR__ . '/..' . '/../lib/CalDAV/CachedSubscriptionObject.php', | |||||
'OCA\\DAV\\CalDAV\\CalDavBackend' => __DIR__ . '/..' . '/../lib/CalDAV/CalDavBackend.php', | 'OCA\\DAV\\CalDAV\\CalDavBackend' => __DIR__ . '/..' . '/../lib/CalDAV/CalDavBackend.php', | ||||
'OCA\\DAV\\CalDAV\\Calendar' => __DIR__ . '/..' . '/../lib/CalDAV/Calendar.php', | 'OCA\\DAV\\CalDAV\\Calendar' => __DIR__ . '/..' . '/../lib/CalDAV/Calendar.php', | ||||
'OCA\\DAV\\CalDAV\\CalendarHome' => __DIR__ . '/..' . '/../lib/CalDAV/CalendarHome.php', | 'OCA\\DAV\\CalDAV\\CalendarHome' => __DIR__ . '/..' . '/../lib/CalDAV/CalendarHome.php', | ||||
'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\PropFilter' => __DIR__ . '/..' . '/../lib/CalDAV/Search/Xml/Filter/PropFilter.php', | 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\PropFilter' => __DIR__ . '/..' . '/../lib/CalDAV/Search/Xml/Filter/PropFilter.php', | ||||
'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\SearchTermFilter' => __DIR__ . '/..' . '/../lib/CalDAV/Search/Xml/Filter/SearchTermFilter.php', | 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\SearchTermFilter' => __DIR__ . '/..' . '/../lib/CalDAV/Search/Xml/Filter/SearchTermFilter.php', | ||||
'OCA\\DAV\\CalDAV\\Search\\Xml\\Request\\CalendarSearchReport' => __DIR__ . '/..' . '/../lib/CalDAV/Search/Xml/Request/CalendarSearchReport.php', | 'OCA\\DAV\\CalDAV\\Search\\Xml\\Request\\CalendarSearchReport' => __DIR__ . '/..' . '/../lib/CalDAV/Search/Xml/Request/CalendarSearchReport.php', | ||||
'OCA\\DAV\\CalDAV\\WebcalCaching\\Plugin' => __DIR__ . '/..' . '/../lib/CalDAV/WebcalCaching/Plugin.php', | |||||
'OCA\\DAV\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php', | 'OCA\\DAV\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php', | ||||
'OCA\\DAV\\CardDAV\\AddressBook' => __DIR__ . '/..' . '/../lib/CardDAV/AddressBook.php', | 'OCA\\DAV\\CardDAV\\AddressBook' => __DIR__ . '/..' . '/../lib/CardDAV/AddressBook.php', | ||||
'OCA\\DAV\\CardDAV\\AddressBookImpl' => __DIR__ . '/..' . '/../lib/CardDAV/AddressBookImpl.php', | 'OCA\\DAV\\CardDAV\\AddressBookImpl' => __DIR__ . '/..' . '/../lib/CardDAV/AddressBookImpl.php', | ||||
'OCA\\DAV\\Migration\\BuildCalendarSearchIndexBackgroundJob' => __DIR__ . '/..' . '/../lib/Migration/BuildCalendarSearchIndexBackgroundJob.php', | 'OCA\\DAV\\Migration\\BuildCalendarSearchIndexBackgroundJob' => __DIR__ . '/..' . '/../lib/Migration/BuildCalendarSearchIndexBackgroundJob.php', | ||||
'OCA\\DAV\\Migration\\CalDAVRemoveEmptyValue' => __DIR__ . '/..' . '/../lib/Migration/CalDAVRemoveEmptyValue.php', | 'OCA\\DAV\\Migration\\CalDAVRemoveEmptyValue' => __DIR__ . '/..' . '/../lib/Migration/CalDAVRemoveEmptyValue.php', | ||||
'OCA\\DAV\\Migration\\FixBirthdayCalendarComponent' => __DIR__ . '/..' . '/../lib/Migration/FixBirthdayCalendarComponent.php', | 'OCA\\DAV\\Migration\\FixBirthdayCalendarComponent' => __DIR__ . '/..' . '/../lib/Migration/FixBirthdayCalendarComponent.php', | ||||
'OCA\\DAV\\Migration\\RefreshWebcalJobRegistrar' => __DIR__ . '/..' . '/../lib/Migration/RefreshWebcalJobRegistrar.php', | |||||
'OCA\\DAV\\Migration\\Version1004Date20170825134824' => __DIR__ . '/..' . '/../lib/Migration/Version1004Date20170825134824.php', | 'OCA\\DAV\\Migration\\Version1004Date20170825134824' => __DIR__ . '/..' . '/../lib/Migration/Version1004Date20170825134824.php', | ||||
'OCA\\DAV\\Migration\\Version1004Date20170919104507' => __DIR__ . '/..' . '/../lib/Migration/Version1004Date20170919104507.php', | 'OCA\\DAV\\Migration\\Version1004Date20170919104507' => __DIR__ . '/..' . '/../lib/Migration/Version1004Date20170919104507.php', | ||||
'OCA\\DAV\\Migration\\Version1004Date20170924124212' => __DIR__ . '/..' . '/../lib/Migration/Version1004Date20170924124212.php', | 'OCA\\DAV\\Migration\\Version1004Date20170924124212' => __DIR__ . '/..' . '/../lib/Migration/Version1004Date20170924124212.php', | ||||
'OCA\\DAV\\Migration\\Version1005Date20180413093149' => __DIR__ . '/..' . '/../lib/Migration/Version1005Date20180413093149.php', | 'OCA\\DAV\\Migration\\Version1005Date20180413093149' => __DIR__ . '/..' . '/../lib/Migration/Version1005Date20180413093149.php', | ||||
'OCA\\DAV\\Migration\\Version1005Date20180530124431' => __DIR__ . '/..' . '/../lib/Migration/Version1005Date20180530124431.php', | 'OCA\\DAV\\Migration\\Version1005Date20180530124431' => __DIR__ . '/..' . '/../lib/Migration/Version1005Date20180530124431.php', | ||||
'OCA\\DAV\\Migration\\Version1006Date20180619154313' => __DIR__ . '/..' . '/../lib/Migration/Version1006Date20180619154313.php', | 'OCA\\DAV\\Migration\\Version1006Date20180619154313' => __DIR__ . '/..' . '/../lib/Migration/Version1006Date20180619154313.php', | ||||
'OCA\\DAV\\Migration\\Version1006Date20180628111625' => __DIR__ . '/..' . '/../lib/Migration/Version1006Date20180628111625.php', | |||||
'OCA\\DAV\\Migration\\Version1007Date20181007225117' => __DIR__ . '/..' . '/../lib/Migration/Version1007Date20181007225117.php', | 'OCA\\DAV\\Migration\\Version1007Date20181007225117' => __DIR__ . '/..' . '/../lib/Migration/Version1007Date20181007225117.php', | ||||
'OCA\\DAV\\Migration\\Version1008Date20181030113700' => __DIR__ . '/..' . '/../lib/Migration/Version1008Date20181030113700.php', | 'OCA\\DAV\\Migration\\Version1008Date20181030113700' => __DIR__ . '/..' . '/../lib/Migration/Version1008Date20181030113700.php', | ||||
'OCA\\DAV\\RootCollection' => __DIR__ . '/..' . '/../lib/RootCollection.php', | 'OCA\\DAV\\RootCollection' => __DIR__ . '/..' . '/../lib/RootCollection.php', |
<?php | |||||
declare(strict_types=1); | |||||
/** | |||||
* @copyright 2018 Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @author Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @license GNU AGPL version 3 or any later version | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License as | |||||
* published by the Free Software Foundation, either version 3 of the | |||||
* License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
namespace OCA\DAV\BackgroundJob; | |||||
use GuzzleHttp\HandlerStack; | |||||
use GuzzleHttp\Middleware; | |||||
use OC\BackgroundJob\Job; | |||||
use OCA\DAV\CalDAV\CalDavBackend; | |||||
use OCP\AppFramework\Utility\ITimeFactory; | |||||
use OCP\Http\Client\IClientService; | |||||
use OCP\IConfig; | |||||
use OCP\ILogger; | |||||
use Psr\Http\Message\RequestInterface; | |||||
use Psr\Http\Message\ResponseInterface; | |||||
use Sabre\DAV\Exception\BadRequest; | |||||
use Sabre\DAV\PropPatch; | |||||
use Sabre\DAV\Xml\Property\Href; | |||||
use Sabre\VObject\Component; | |||||
use Sabre\VObject\DateTimeParser; | |||||
use Sabre\VObject\InvalidDataException; | |||||
use Sabre\VObject\ParseException; | |||||
use Sabre\VObject\Reader; | |||||
use Sabre\VObject\Splitter\ICalendar; | |||||
class RefreshWebcalJob extends Job { | |||||
/** @var CalDavBackend */ | |||||
private $calDavBackend; | |||||
/** @var IClientService */ | |||||
private $clientService; | |||||
/** @var IConfig */ | |||||
private $config; | |||||
/** @var ILogger */ | |||||
private $logger; | |||||
/** @var ITimeFactory */ | |||||
private $timeFactory; | |||||
/** @var array */ | |||||
private $subscription; | |||||
/** | |||||
* RefreshWebcalJob constructor. | |||||
* | |||||
* @param CalDavBackend $calDavBackend | |||||
* @param IClientService $clientService | |||||
* @param IConfig $config | |||||
* @param ILogger $logger | |||||
* @param ITimeFactory $timeFactory | |||||
*/ | |||||
public function __construct(CalDavBackend $calDavBackend, IClientService $clientService, IConfig $config, ILogger $logger, ITimeFactory $timeFactory) { | |||||
$this->calDavBackend = $calDavBackend; | |||||
$this->clientService = $clientService; | |||||
$this->config = $config; | |||||
$this->logger = $logger; | |||||
$this->timeFactory = $timeFactory; | |||||
} | |||||
/** | |||||
* this function is called at most every hour | |||||
* | |||||
* @inheritdoc | |||||
*/ | |||||
public function execute($jobList, ILogger $logger = null) { | |||||
$subscription = $this->getSubscription($this->argument['principaluri'], $this->argument['uri']); | |||||
if (!$subscription) { | |||||
return; | |||||
} | |||||
// if no refresh rate was configured, just refresh once a week | |||||
$subscriptionId = $subscription['id']; | |||||
$refreshrate = $subscription['refreshrate'] ?? 'P1W'; | |||||
try { | |||||
/** @var \DateInterval $dateInterval */ | |||||
$dateInterval = DateTimeParser::parseDuration($refreshrate); | |||||
} catch(InvalidDataException $ex) { | |||||
$this->logger->logException($ex); | |||||
$this->logger->warning("Subscription $subscriptionId could not be refreshed, refreshrate in database is invalid"); | |||||
return; | |||||
} | |||||
$interval = $this->getIntervalFromDateInterval($dateInterval); | |||||
if (($this->timeFactory->getTime() - $this->lastRun) <= $interval) { | |||||
return; | |||||
} | |||||
parent::execute($jobList, $logger); | |||||
} | |||||
/** | |||||
* @param array $argument | |||||
*/ | |||||
protected function run($argument) { | |||||
$subscription = $this->getSubscription($argument['principaluri'], $argument['uri']); | |||||
$mutations = []; | |||||
if (!$subscription) { | |||||
return; | |||||
} | |||||
$webcalData = $this->queryWebcalFeed($subscription, $mutations); | |||||
if (!$webcalData) { | |||||
return; | |||||
} | |||||
$stripTodos = $subscription['striptodos'] ?? 1; | |||||
$stripAlarms = $subscription['stripalarms'] ?? 1; | |||||
$stripAttachments = $subscription['stripattachments'] ?? 1; | |||||
try { | |||||
$splitter = new ICalendar($webcalData, Reader::OPTION_FORGIVING); | |||||
// we wait with deleting all outdated events till we parsed the new ones | |||||
// in case the new calendar is broken and `new ICalendar` throws a ParseException | |||||
// the user will still see the old data | |||||
$this->calDavBackend->purgeAllCachedEventsForSubscription($subscription['id']); | |||||
while ($vObject = $splitter->getNext()) { | |||||
/** @var Component $vObject */ | |||||
$uid = null; | |||||
$compName = null; | |||||
foreach ($vObject->getComponents() as $component) { | |||||
if ($component->name === 'VTIMEZONE') { | |||||
continue; | |||||
} | |||||
$uid = $component->{'UID'}->getValue(); | |||||
$compName = $component->name; | |||||
if ($stripAlarms) { | |||||
unset($component->{'VALARM'}); | |||||
} | |||||
if ($stripAttachments) { | |||||
unset($component->{'ATTACH'}); | |||||
} | |||||
} | |||||
if ($stripTodos && $compName === 'VTODO') { | |||||
continue; | |||||
} | |||||
$uri = $uid . '.ics'; | |||||
$calendarData = $vObject->serialize(); | |||||
try { | |||||
$this->calDavBackend->createCalendarObject($subscription['id'], $uri, $calendarData, CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION); | |||||
} catch(BadRequest $ex) { | |||||
$this->logger->logException($ex); | |||||
} | |||||
} | |||||
$newRefreshRate = $this->checkWebcalDataForRefreshRate($subscription, $webcalData); | |||||
if ($newRefreshRate) { | |||||
$mutations['{http://apple.com/ns/ical/}refreshrate'] = $newRefreshRate; | |||||
} | |||||
$this->updateSubscription($subscription, $mutations); | |||||
} catch(ParseException $ex) { | |||||
$subscriptionId = $subscription['id']; | |||||
$this->logger->logException($ex); | |||||
$this->logger->warning("Subscription $subscriptionId could not be refreshed due to a parsing error"); | |||||
} | |||||
} | |||||
/** | |||||
* gets webcal feed from remote server | |||||
* | |||||
* @param array $subscription | |||||
* @param array &$mutations | |||||
* @return null|string | |||||
*/ | |||||
private function queryWebcalFeed(array $subscription, array &$mutations) { | |||||
$client = $this->clientService->newClient(); | |||||
$didBreak301Chain = false; | |||||
$latestLocation = null; | |||||
$handlerStack = HandlerStack::create(); | |||||
$handlerStack->push(Middleware::mapRequest(function (RequestInterface $request) { | |||||
return $request | |||||
->withHeader('Accept', 'text/calendar, application/calendar+json, application/calendar+xml') | |||||
->withHeader('User-Agent', 'Nextcloud Webcal Crawler'); | |||||
})); | |||||
$handlerStack->push(Middleware::mapResponse(function(ResponseInterface $response) use (&$didBreak301Chain, &$latestLocation) { | |||||
if (!$didBreak301Chain) { | |||||
if ($response->getStatusCode() !== 301) { | |||||
$didBreak301Chain = true; | |||||
} else { | |||||
$latestLocation = $response->getHeader('Location'); | |||||
} | |||||
} | |||||
return $response; | |||||
})); | |||||
$allowLocalAccess = $this->config->getAppValue('dav', 'webcalAllowLocalAccess', 'no'); | |||||
$subscriptionId = $subscription['id']; | |||||
$url = $this->cleanURL($subscription['source']); | |||||
if ($url === null) { | |||||
return null; | |||||
} | |||||
if ($allowLocalAccess !== 'yes') { | |||||
$host = parse_url($url, PHP_URL_HOST); | |||||
// remove brackets from IPv6 addresses | |||||
if (strpos($host, '[') === 0 && substr($host, -1) === ']') { | |||||
$host = substr($host, 1, -1); | |||||
} | |||||
if ($host === 'localhost' || substr($host, -6) === '.local' || substr($host, -10) === '.localhost' || | |||||
preg_match('/(^127\.)|(^192\.168\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^::1$)|(^[fF][cCdD])/', $host)) { | |||||
$this->logger->warning("Subscription $subscriptionId was not refreshed because it violates local access rules"); | |||||
return null; | |||||
} | |||||
} | |||||
try { | |||||
$params = [ | |||||
'allow_redirects' => [ | |||||
'redirects' => 10 | |||||
], | |||||
'handler' => $handlerStack, | |||||
]; | |||||
$user = parse_url($subscription['source'], PHP_URL_USER); | |||||
$pass = parse_url($subscription['source'], PHP_URL_PASS); | |||||
if ($user !== null && $pass !== null) { | |||||
$params['auth'] = [$user, $pass]; | |||||
} | |||||
$response = $client->get($url, $params); | |||||
$body = $response->getBody(); | |||||
if ($latestLocation) { | |||||
$mutations['{http://calendarserver.org/ns/}source'] = new Href($latestLocation); | |||||
} | |||||
$contentType = $response->getHeader('Content-Type'); | |||||
$contentType = explode(';', $contentType, 2)[0]; | |||||
switch($contentType) { | |||||
case 'application/calendar+json': | |||||
try { | |||||
$jCalendar = Reader::readJson($body, Reader::OPTION_FORGIVING); | |||||
} catch(\Exception $ex) { | |||||
// In case of a parsing error return null | |||||
$this->logger->debug("Subscription $subscriptionId could not be parsed"); | |||||
return null; | |||||
} | |||||
return $jCalendar->serialize(); | |||||
case 'application/calendar+xml': | |||||
try { | |||||
$xCalendar = Reader::readXML($body); | |||||
} catch(\Exception $ex) { | |||||
// In case of a parsing error return null | |||||
$this->logger->debug("Subscription $subscriptionId could not be parsed"); | |||||
return null; | |||||
} | |||||
return $xCalendar->serialize(); | |||||
case 'text/calendar': | |||||
default: | |||||
try { | |||||
$vCalendar = Reader::read($body); | |||||
} catch(\Exception $ex) { | |||||
// In case of a parsing error return null | |||||
$this->logger->debug("Subscription $subscriptionId could not be parsed"); | |||||
return null; | |||||
} | |||||
return $vCalendar->serialize(); | |||||
} | |||||
} catch(\Exception $ex) { | |||||
$this->logger->logException($ex); | |||||
$this->logger->warning("Subscription $subscriptionId could not be refreshed due to a network error"); | |||||
return null; | |||||
} | |||||
} | |||||
/** | |||||
* loads subscription from backend | |||||
* | |||||
* @param string $principalUri | |||||
* @param string $uri | |||||
* @return array|null | |||||
*/ | |||||
private function getSubscription(string $principalUri, string $uri) { | |||||
$subscriptions = array_values(array_filter( | |||||
$this->calDavBackend->getSubscriptionsForUser($principalUri), | |||||
function($sub) use ($uri) { | |||||
return $sub['uri'] === $uri; | |||||
} | |||||
)); | |||||
if (\count($subscriptions) === 0) { | |||||
return null; | |||||
} | |||||
$this->subscription = $subscriptions[0]; | |||||
return $this->subscription; | |||||
} | |||||
/** | |||||
* get total number of seconds from DateInterval object | |||||
* | |||||
* @param \DateInterval $interval | |||||
* @return int | |||||
*/ | |||||
private function getIntervalFromDateInterval(\DateInterval $interval):int { | |||||
return $interval->s | |||||
+ ($interval->i * 60) | |||||
+ ($interval->h * 60 * 60) | |||||
+ ($interval->d * 60 * 60 * 24) | |||||
+ ($interval->m * 60 * 60 * 24 * 30) | |||||
+ ($interval->y * 60 * 60 * 24 * 365); | |||||
} | |||||
/** | |||||
* check if: | |||||
* - current subscription stores a refreshrate | |||||
* - the webcal feed suggests a refreshrate | |||||
* - return suggested refreshrate if user didn't set a custom one | |||||
* | |||||
* @param array $subscription | |||||
* @param string $webcalData | |||||
* @return string|null | |||||
*/ | |||||
private function checkWebcalDataForRefreshRate($subscription, $webcalData) { | |||||
// if there is no refreshrate stored in the database, check the webcal feed | |||||
// whether it suggests any refresh rate and store that in the database | |||||
if (isset($subscription['refreshrate']) && $subscription['refreshrate'] !== null) { | |||||
return null; | |||||
} | |||||
/** @var Component\VCalendar $vCalendar */ | |||||
$vCalendar = Reader::read($webcalData); | |||||
$newRefreshrate = null; | |||||
if (isset($vCalendar->{'X-PUBLISHED-TTL'})) { | |||||
$newRefreshrate = $vCalendar->{'X-PUBLISHED-TTL'}->getValue(); | |||||
} | |||||
if (isset($vCalendar->{'REFRESH-INTERVAL'})) { | |||||
$newRefreshrate = $vCalendar->{'REFRESH-INTERVAL'}->getValue(); | |||||
} | |||||
if (!$newRefreshrate) { | |||||
return null; | |||||
} | |||||
// check if new refresh rate is even valid | |||||
try { | |||||
DateTimeParser::parseDuration($newRefreshrate); | |||||
} catch(InvalidDataException $ex) { | |||||
return null; | |||||
} | |||||
return $newRefreshrate; | |||||
} | |||||
/** | |||||
* update subscription stored in database | |||||
* used to set: | |||||
* - refreshrate | |||||
* - source | |||||
* | |||||
* @param array $subscription | |||||
* @param array $mutations | |||||
*/ | |||||
private function updateSubscription(array $subscription, array $mutations) { | |||||
if (empty($mutations)) { | |||||
return; | |||||
} | |||||
$propPatch = new PropPatch($mutations); | |||||
$this->calDavBackend->updateSubscription($subscription['id'], $propPatch); | |||||
$propPatch->commit(); | |||||
} | |||||
/** | |||||
* This method will strip authentication information and replace the | |||||
* 'webcal' or 'webcals' protocol scheme | |||||
* | |||||
* @param string $url | |||||
* @return string|null | |||||
*/ | |||||
private function cleanURL(string $url) { | |||||
$parsed = parse_url($url); | |||||
if ($parsed === false) { | |||||
return null; | |||||
} | |||||
if (isset($parsed['scheme']) && $parsed['scheme'] === 'http') { | |||||
$scheme = 'http'; | |||||
} else { | |||||
$scheme = 'https'; | |||||
} | |||||
$host = $parsed['host'] ?? ''; | |||||
$port = isset($parsed['port']) ? ':' . $parsed['port'] : ''; | |||||
$path = $parsed['path'] ?? ''; | |||||
$query = isset($parsed['query']) ? '?' . $parsed['query'] : ''; | |||||
$fragment = isset($parsed['fragment']) ? '#' . $parsed['fragment'] : ''; | |||||
$cleanURL = "$scheme://$host$port$path$query$fragment"; | |||||
// parse_url is giving some weird results if no url and no :// is given, | |||||
// so let's test the url again | |||||
$parsedClean = parse_url($cleanURL); | |||||
if ($parsedClean === false || !isset($parsedClean['host'])) { | |||||
return null; | |||||
} | |||||
return $cleanURL; | |||||
} | |||||
} |
<?php | |||||
declare(strict_types=1); | |||||
/** | |||||
* @copyright 2018 Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @author Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @license GNU AGPL version 3 or any later version | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License as | |||||
* published by the Free Software Foundation, either version 3 of the | |||||
* License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
namespace OCA\DAV\CalDAV; | |||||
use Sabre\CalDAV\Backend\BackendInterface; | |||||
use Sabre\DAV\Exception\MethodNotAllowed; | |||||
use Sabre\DAV\Exception\NotFound; | |||||
use Sabre\DAV\PropPatch; | |||||
/** | |||||
* Class CachedSubscription | |||||
* | |||||
* @package OCA\DAV\CalDAV | |||||
* @property BackendInterface|CalDavBackend $caldavBackend | |||||
*/ | |||||
class CachedSubscription extends \Sabre\CalDAV\Calendar { | |||||
/** | |||||
* @return string | |||||
*/ | |||||
public function getPrincipalURI():string { | |||||
return $this->calendarInfo['principaluri']; | |||||
} | |||||
/** | |||||
* @return array | |||||
*/ | |||||
public function getACL():array { | |||||
return [ | |||||
[ | |||||
'privilege' => '{DAV:}read', | |||||
'principal' => $this->getOwner(), | |||||
'protected' => true, | |||||
], | |||||
[ | |||||
'privilege' => '{DAV:}read', | |||||
'principal' => $this->getOwner() . '/calendar-proxy-write', | |||||
'protected' => true, | |||||
], | |||||
[ | |||||
'privilege' => '{DAV:}read', | |||||
'principal' => $this->getOwner() . '/calendar-proxy-read', | |||||
'protected' => true, | |||||
], | |||||
[ | |||||
'privilege' => '{' . Plugin::NS_CALDAV . '}read-free-busy', | |||||
'principal' => '{DAV:}authenticated', | |||||
'protected' => true, | |||||
], | |||||
]; | |||||
} | |||||
/** | |||||
* @return array | |||||
*/ | |||||
public function getChildACL():array { | |||||
return [ | |||||
[ | |||||
'privilege' => '{DAV:}read', | |||||
'principal' => $this->getOwner(), | |||||
'protected' => true, | |||||
], | |||||
[ | |||||
'privilege' => '{DAV:}read', | |||||
'principal' => $this->getOwner() . '/calendar-proxy-write', | |||||
'protected' => true, | |||||
], | |||||
[ | |||||
'privilege' => '{DAV:}read', | |||||
'principal' => $this->getOwner() . '/calendar-proxy-read', | |||||
'protected' => true, | |||||
], | |||||
]; | |||||
} | |||||
/** | |||||
* @return null|string | |||||
*/ | |||||
public function getOwner() { | |||||
if (isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal'])) { | |||||
return $this->calendarInfo['{http://owncloud.org/ns}owner-principal']; | |||||
} | |||||
return parent::getOwner(); | |||||
} | |||||
/** | |||||
* | |||||
*/ | |||||
public function delete() { | |||||
$this->caldavBackend->deleteSubscription($this->calendarInfo['id']); | |||||
} | |||||
/** | |||||
* @param PropPatch $propPatch | |||||
*/ | |||||
public function propPatch(PropPatch $propPatch) { | |||||
$this->caldavBackend->updateSubscription($this->calendarInfo['id'], $propPatch); | |||||
} | |||||
/** | |||||
* @param string $name | |||||
* @return CalendarObject|\Sabre\CalDAV\ICalendarObject | |||||
* @throws NotFound | |||||
*/ | |||||
public function getChild($name) { | |||||
$obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $name, CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION); | |||||
if (!$obj) { | |||||
throw new NotFound('Calendar object not found'); | |||||
} | |||||
$obj['acl'] = $this->getChildACL(); | |||||
return new CachedSubscriptionObject ($this->caldavBackend, $this->calendarInfo, $obj); | |||||
} | |||||
/** | |||||
* @return array | |||||
*/ | |||||
public function getChildren():array { | |||||
$objs = $this->caldavBackend->getCalendarObjects($this->calendarInfo['id'], CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION); | |||||
$children = []; | |||||
foreach($objs as $obj) { | |||||
$children[] = new CachedSubscriptionObject($this->caldavBackend, $this->calendarInfo, $obj); | |||||
} | |||||
return $children; | |||||
} | |||||
/** | |||||
* @param array $paths | |||||
* @return array | |||||
*/ | |||||
public function getMultipleChildren(array $paths):array { | |||||
$objs = $this->caldavBackend->getMultipleCalendarObjects($this->calendarInfo['id'], $paths, CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION); | |||||
$children = []; | |||||
foreach($objs as $obj) { | |||||
$children[] = new CachedSubscriptionObject($this->caldavBackend, $this->calendarInfo, $obj); | |||||
} | |||||
return $children; | |||||
} | |||||
/** | |||||
* @param string $name | |||||
* @param null $calendarData | |||||
* @return null|string|void | |||||
* @throws MethodNotAllowed | |||||
*/ | |||||
public function createFile($name, $calendarData = null) { | |||||
throw new MethodNotAllowed('Creating objects in cached subscription is not allowed'); | |||||
} | |||||
/** | |||||
* @param string $name | |||||
* @return bool | |||||
*/ | |||||
public function childExists($name):bool { | |||||
$obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $name, CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION); | |||||
if (!$obj) { | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* @param array $filters | |||||
* @return array | |||||
*/ | |||||
public function calendarQuery(array $filters):array { | |||||
return $this->caldavBackend->calendarQuery($this->calendarInfo['id'], $filters, CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION); | |||||
} | |||||
} |
<?php | |||||
declare(strict_types=1); | |||||
/** | |||||
* @copyright 2018 Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @author Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @license GNU AGPL version 3 or any later version | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License as | |||||
* published by the Free Software Foundation, either version 3 of the | |||||
* License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
namespace OCA\DAV\CalDAV; | |||||
use Sabre\DAV\Exception\MethodNotAllowed; | |||||
/** | |||||
* Class CachedSubscriptionObject | |||||
* | |||||
* @package OCA\DAV\CalDAV | |||||
* @property CalDavBackend $caldavBackend | |||||
*/ | |||||
class CachedSubscriptionObject extends \Sabre\CalDAV\CalendarObject { | |||||
/** | |||||
* @inheritdoc | |||||
*/ | |||||
public function get() { | |||||
// Pre-populating the 'calendardata' is optional, if we don't have it | |||||
// already we fetch it from the backend. | |||||
if (!isset($this->objectData['calendardata'])) { | |||||
$this->objectData = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $this->objectData['uri'], CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION); | |||||
} | |||||
return $this->objectData['calendardata']; | |||||
} | |||||
/** | |||||
* @param resource|string $calendarData | |||||
* @return string|void | |||||
* @throws MethodNotAllowed | |||||
*/ | |||||
public function put($calendarData) { | |||||
throw new MethodNotAllowed('Creating objects in a cached subscription is not allowed'); | |||||
} | |||||
/** | |||||
* @throws MethodNotAllowed | |||||
*/ | |||||
public function delete() { | |||||
throw new MethodNotAllowed('Deleting objects in a cached subscription is not allowed'); | |||||
} | |||||
} |
<?php | <?php | ||||
/** | /** | ||||
* @copyright Copyright (c) 2016, ownCloud, Inc. | * @copyright Copyright (c) 2016, ownCloud, Inc. | ||||
* @copyright Copyright (c) 2017 Georg Ehrke | |||||
* @copyright Copyright (c) 2018 Georg Ehrke | |||||
* | * | ||||
* @author Georg Ehrke <oc.list@georgehrke.com> | * @author Georg Ehrke <oc.list@georgehrke.com> | ||||
* @author Joas Schilling <coding@schilljs.com> | * @author Joas Schilling <coding@schilljs.com> | ||||
*/ | */ | ||||
class CalDavBackend extends AbstractBackend implements SyncSupport, SubscriptionSupport, SchedulingSupport { | class CalDavBackend extends AbstractBackend implements SyncSupport, SubscriptionSupport, SchedulingSupport { | ||||
const CALENDAR_TYPE_CALENDAR = 0; | |||||
const CALENDAR_TYPE_SUBSCRIPTION = 1; | |||||
const PERSONAL_CALENDAR_URI = 'personal'; | const PERSONAL_CALENDAR_URI = 'personal'; | ||||
const PERSONAL_CALENDAR_NAME = 'Personal'; | const PERSONAL_CALENDAR_NAME = 'Personal'; | ||||
private $db; | private $db; | ||||
/** @var Backend */ | /** @var Backend */ | ||||
private $sharingBackend; | |||||
private $calendarSharingBackend; | |||||
/** @var Principal */ | /** @var Principal */ | ||||
private $principalBackend; | private $principalBackend; | ||||
$this->db = $db; | $this->db = $db; | ||||
$this->principalBackend = $principalBackend; | $this->principalBackend = $principalBackend; | ||||
$this->userManager = $userManager; | $this->userManager = $userManager; | ||||
$this->sharingBackend = new Backend($this->db, $this->userManager, $groupManager, $principalBackend, 'calendar'); | |||||
$this->calendarSharingBackend = new Backend($this->db, $this->userManager, $groupManager, $principalBackend, 'calendar'); | |||||
$this->random = $random; | $this->random = $random; | ||||
$this->logger = $logger; | $this->logger = $logger; | ||||
$this->dispatcher = $dispatcher; | $this->dispatcher = $dispatcher; | ||||
return array_values($calendars); | return array_values($calendars); | ||||
} | } | ||||
/** | |||||
* @param $principalUri | |||||
* @return array | |||||
*/ | |||||
public function getUsersOwnCalendars($principalUri) { | public function getUsersOwnCalendars($principalUri) { | ||||
$principalUri = $this->convertPrincipal($principalUri, true); | $principalUri = $this->convertPrincipal($principalUri, true); | ||||
$fields = array_values($this->propertyMap); | $fields = array_values($this->propertyMap); | ||||
} | } | ||||
/** | |||||
* @param $uid | |||||
* @return string | |||||
*/ | |||||
private function getUserDisplayName($uid) { | private function getUserDisplayName($uid) { | ||||
if (!isset($this->userDisplayNames[$uid])) { | if (!isset($this->userDisplayNames[$uid])) { | ||||
$user = $this->userManager->get($uid); | $user = $this->userManager->get($uid); | ||||
return $calendar; | return $calendar; | ||||
} | } | ||||
/** | |||||
* @param $calendarId | |||||
* @return array|null | |||||
*/ | |||||
public function getCalendarById($calendarId) { | public function getCalendarById($calendarId) { | ||||
$fields = array_values($this->propertyMap); | $fields = array_values($this->propertyMap); | ||||
$fields[] = 'id'; | $fields[] = 'id'; | ||||
return $calendar; | return $calendar; | ||||
} | } | ||||
/** | |||||
* @param $subscriptionId | |||||
*/ | |||||
public function getSubscriptionById($subscriptionId) { | |||||
$fields = array_values($this->subscriptionPropertyMap); | |||||
$fields[] = 'id'; | |||||
$fields[] = 'uri'; | |||||
$fields[] = 'source'; | |||||
$fields[] = 'synctoken'; | |||||
$fields[] = 'principaluri'; | |||||
$fields[] = 'lastmodified'; | |||||
$query = $this->db->getQueryBuilder(); | |||||
$query->select($fields) | |||||
->from('calendarsubscriptions') | |||||
->where($query->expr()->eq('id', $query->createNamedParameter($subscriptionId))) | |||||
->orderBy('calendarorder', 'asc'); | |||||
$stmt =$query->execute(); | |||||
$row = $stmt->fetch(\PDO::FETCH_ASSOC); | |||||
$stmt->closeCursor(); | |||||
if ($row === false) { | |||||
return null; | |||||
} | |||||
$subscription = [ | |||||
'id' => $row['id'], | |||||
'uri' => $row['uri'], | |||||
'principaluri' => $row['principaluri'], | |||||
'source' => $row['source'], | |||||
'lastmodified' => $row['lastmodified'], | |||||
'{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VTODO', 'VEVENT']), | |||||
'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0', | |||||
]; | |||||
foreach($this->subscriptionPropertyMap as $xmlName=>$dbName) { | |||||
if (!is_null($row[$dbName])) { | |||||
$subscription[$xmlName] = $row[$dbName]; | |||||
} | |||||
} | |||||
return $subscription; | |||||
} | |||||
/** | /** | ||||
* Creates a new calendar for a principal. | * Creates a new calendar for a principal. | ||||
* | * | ||||
'shares' => $this->getShares($calendarId), | 'shares' => $this->getShares($calendarId), | ||||
])); | ])); | ||||
$stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendarobjects` WHERE `calendarid` = ?'); | |||||
$stmt->execute([$calendarId]); | |||||
$stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendarobjects` WHERE `calendarid` = ? AND `calendartype` = ?'); | |||||
$stmt->execute([$calendarId, self::CALENDAR_TYPE_CALENDAR]); | |||||
$stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendars` WHERE `id` = ?'); | $stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendars` WHERE `id` = ?'); | ||||
$stmt->execute([$calendarId]); | $stmt->execute([$calendarId]); | ||||
$stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendarchanges` WHERE `calendarid` = ?'); | |||||
$stmt->execute([$calendarId]); | |||||
$stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendarchanges` WHERE `calendarid` = ? AND `calendartype` = ?'); | |||||
$stmt->execute([$calendarId, self::CALENDAR_TYPE_CALENDAR]); | |||||
$this->sharingBackend->deleteAllShares($calendarId); | |||||
$this->calendarSharingBackend->deleteAllShares($calendarId); | |||||
$query = $this->db->getQueryBuilder(); | $query = $this->db->getQueryBuilder(); | ||||
$query->delete($this->dbObjectPropertiesTable) | $query->delete($this->dbObjectPropertiesTable) | ||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))) | ->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))) | ||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter(self::CALENDAR_TYPE_CALENDAR))) | |||||
->execute(); | ->execute(); | ||||
} | } | ||||
* @return void | * @return void | ||||
*/ | */ | ||||
function deleteAllSharesByUser($principaluri) { | function deleteAllSharesByUser($principaluri) { | ||||
$this->sharingBackend->deleteAllSharesByUser($principaluri); | |||||
$this->calendarSharingBackend->deleteAllSharesByUser($principaluri); | |||||
} | } | ||||
/** | /** | ||||
* used/fetched to determine these numbers. If both are specified the | * used/fetched to determine these numbers. If both are specified the | ||||
* amount of times this is needed is reduced by a great degree. | * amount of times this is needed is reduced by a great degree. | ||||
* | * | ||||
* @param mixed $calendarId | |||||
* @param mixed $id | |||||
* @param int $calendarType | |||||
* @return array | * @return array | ||||
*/ | */ | ||||
function getCalendarObjects($calendarId) { | |||||
public function getCalendarObjects($id, $calendarType=self::CALENDAR_TYPE_CALENDAR):array { | |||||
$query = $this->db->getQueryBuilder(); | $query = $this->db->getQueryBuilder(); | ||||
$query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'componenttype', 'classification']) | $query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'componenttype', 'classification']) | ||||
->from('calendarobjects') | ->from('calendarobjects') | ||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))); | |||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($id))) | |||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter($calendarType))); | |||||
$stmt = $query->execute(); | $stmt = $query->execute(); | ||||
$result = []; | $result = []; | ||||
foreach($stmt->fetchAll(\PDO::FETCH_ASSOC) as $row) { | foreach($stmt->fetchAll(\PDO::FETCH_ASSOC) as $row) { | ||||
$result[] = [ | $result[] = [ | ||||
'id' => $row['id'], | |||||
'uri' => $row['uri'], | |||||
'lastmodified' => $row['lastmodified'], | |||||
'etag' => '"' . $row['etag'] . '"', | |||||
'calendarid' => $row['calendarid'], | |||||
'size' => (int)$row['size'], | |||||
'component' => strtolower($row['componenttype']), | |||||
'classification'=> (int)$row['classification'] | |||||
'id' => $row['id'], | |||||
'uri' => $row['uri'], | |||||
'lastmodified' => $row['lastmodified'], | |||||
'etag' => '"' . $row['etag'] . '"', | |||||
'calendarid' => $row['calendarid'], | |||||
'size' => (int)$row['size'], | |||||
'component' => strtolower($row['componenttype']), | |||||
'classification'=> (int)$row['classification'] | |||||
]; | ]; | ||||
} | } | ||||
* | * | ||||
* This method must return null if the object did not exist. | * This method must return null if the object did not exist. | ||||
* | * | ||||
* @param mixed $calendarId | |||||
* @param mixed $id | |||||
* @param string $objectUri | * @param string $objectUri | ||||
* @param int $calendarType | |||||
* @return array|null | * @return array|null | ||||
*/ | */ | ||||
function getCalendarObject($calendarId, $objectUri) { | |||||
public function getCalendarObject($id, $objectUri, $calendarType=self::CALENDAR_TYPE_CALENDAR) { | |||||
$query = $this->db->getQueryBuilder(); | $query = $this->db->getQueryBuilder(); | ||||
$query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype', 'classification']) | $query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype', 'classification']) | ||||
->from('calendarobjects') | |||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))) | |||||
->andWhere($query->expr()->eq('uri', $query->createNamedParameter($objectUri))); | |||||
->from('calendarobjects') | |||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($id))) | |||||
->andWhere($query->expr()->eq('uri', $query->createNamedParameter($objectUri))) | |||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter($calendarType))); | |||||
$stmt = $query->execute(); | $stmt = $query->execute(); | ||||
$row = $stmt->fetch(\PDO::FETCH_ASSOC); | $row = $stmt->fetch(\PDO::FETCH_ASSOC); | ||||
if(!$row) return null; | |||||
if(!$row) { | |||||
return null; | |||||
} | |||||
return [ | return [ | ||||
'id' => $row['id'], | |||||
'uri' => $row['uri'], | |||||
'lastmodified' => $row['lastmodified'], | |||||
'etag' => '"' . $row['etag'] . '"', | |||||
'calendarid' => $row['calendarid'], | |||||
'size' => (int)$row['size'], | |||||
'calendardata' => $this->readBlob($row['calendardata']), | |||||
'component' => strtolower($row['componenttype']), | |||||
'classification'=> (int)$row['classification'] | |||||
'id' => $row['id'], | |||||
'uri' => $row['uri'], | |||||
'lastmodified' => $row['lastmodified'], | |||||
'etag' => '"' . $row['etag'] . '"', | |||||
'calendarid' => $row['calendarid'], | |||||
'size' => (int)$row['size'], | |||||
'calendardata' => $this->readBlob($row['calendardata']), | |||||
'component' => strtolower($row['componenttype']), | |||||
'classification'=> (int)$row['classification'] | |||||
]; | ]; | ||||
} | } | ||||
* | * | ||||
* @param mixed $calendarId | * @param mixed $calendarId | ||||
* @param string[] $uris | * @param string[] $uris | ||||
* @param int $calendarType | |||||
* @return array | * @return array | ||||
*/ | */ | ||||
function getMultipleCalendarObjects($calendarId, array $uris) { | |||||
public function getMultipleCalendarObjects($id, array $uris, $calendarType=self::CALENDAR_TYPE_CALENDAR):array { | |||||
if (empty($uris)) { | if (empty($uris)) { | ||||
return []; | return []; | ||||
} | } | ||||
$query = $this->db->getQueryBuilder(); | $query = $this->db->getQueryBuilder(); | ||||
$query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype', 'classification']) | $query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype', 'classification']) | ||||
->from('calendarobjects') | ->from('calendarobjects') | ||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))) | |||||
->andWhere($query->expr()->in('uri', $query->createParameter('uri'))); | |||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($id))) | |||||
->andWhere($query->expr()->in('uri', $query->createParameter('uri'))) | |||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter($calendarType))); | |||||
foreach ($chunks as $uris) { | foreach ($chunks as $uris) { | ||||
$query->setParameter('uri', $uris, IQueryBuilder::PARAM_STR_ARRAY); | $query->setParameter('uri', $uris, IQueryBuilder::PARAM_STR_ARRAY); | ||||
} | } | ||||
$result->closeCursor(); | $result->closeCursor(); | ||||
} | } | ||||
return $objects; | return $objects; | ||||
} | } | ||||
* @param mixed $calendarId | * @param mixed $calendarId | ||||
* @param string $objectUri | * @param string $objectUri | ||||
* @param string $calendarData | * @param string $calendarData | ||||
* @param int $calendarType | |||||
* @return string | * @return string | ||||
*/ | */ | ||||
function createCalendarObject($calendarId, $objectUri, $calendarData) { | |||||
function createCalendarObject($calendarId, $objectUri, $calendarData, $calendarType=self::CALENDAR_TYPE_CALENDAR) { | |||||
$extraData = $this->getDenormalizedData($calendarData); | $extraData = $this->getDenormalizedData($calendarData); | ||||
$q = $this->db->getQueryBuilder(); | $q = $this->db->getQueryBuilder(); | ||||
$q->select($q->createFunction('COUNT(*)')) | $q->select($q->createFunction('COUNT(*)')) | ||||
->from('calendarobjects') | ->from('calendarobjects') | ||||
->where($q->expr()->eq('calendarid', $q->createNamedParameter($calendarId))) | ->where($q->expr()->eq('calendarid', $q->createNamedParameter($calendarId))) | ||||
->andWhere($q->expr()->eq('uid', $q->createNamedParameter($extraData['uid']))); | |||||
->andWhere($q->expr()->eq('uid', $q->createNamedParameter($extraData['uid']))) | |||||
->andWhere($q->expr()->eq('calendartype', $q->createNamedParameter($calendarType))); | |||||
$result = $q->execute(); | $result = $q->execute(); | ||||
$count = (int) $result->fetchColumn(); | $count = (int) $result->fetchColumn(); | ||||
'lastoccurence' => $query->createNamedParameter($extraData['lastOccurence']), | 'lastoccurence' => $query->createNamedParameter($extraData['lastOccurence']), | ||||
'classification' => $query->createNamedParameter($extraData['classification']), | 'classification' => $query->createNamedParameter($extraData['classification']), | ||||
'uid' => $query->createNamedParameter($extraData['uid']), | 'uid' => $query->createNamedParameter($extraData['uid']), | ||||
'calendartype' => $query->createNamedParameter($calendarType), | |||||
]) | ]) | ||||
->execute(); | ->execute(); | ||||
$this->updateProperties($calendarId, $objectUri, $calendarData); | |||||
$this->updateProperties($calendarId, $objectUri, $calendarData, $calendarType); | |||||
$this->dispatcher->dispatch('\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject', new GenericEvent( | |||||
'\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject', | |||||
[ | |||||
'calendarId' => $calendarId, | |||||
'calendarData' => $this->getCalendarById($calendarId), | |||||
'shares' => $this->getShares($calendarId), | |||||
'objectData' => $this->getCalendarObject($calendarId, $objectUri), | |||||
] | |||||
)); | |||||
$this->addChange($calendarId, $objectUri, 1); | |||||
if ($calendarType === self::CALENDAR_TYPE_CALENDAR) { | |||||
$this->dispatcher->dispatch('\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject', new GenericEvent( | |||||
'\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject', | |||||
[ | |||||
'calendarId' => $calendarId, | |||||
'calendarData' => $this->getCalendarById($calendarId), | |||||
'shares' => $this->getShares($calendarId), | |||||
'objectData' => $this->getCalendarObject($calendarId, $objectUri), | |||||
] | |||||
)); | |||||
} else { | |||||
$this->dispatcher->dispatch('\OCA\DAV\CalDAV\CalDavBackend::createCachedCalendarObject', new GenericEvent( | |||||
'\OCA\DAV\CalDAV\CalDavBackend::createCachedCalendarObject', | |||||
[ | |||||
'subscriptionId' => $calendarId, | |||||
'calendarData' => $this->getCalendarById($calendarId), | |||||
'shares' => $this->getShares($calendarId), | |||||
'objectData' => $this->getCalendarObject($calendarId, $objectUri), | |||||
] | |||||
)); | |||||
} | |||||
$this->addChange($calendarId, $objectUri, 1, $calendarType); | |||||
return '"' . $extraData['etag'] . '"'; | return '"' . $extraData['etag'] . '"'; | ||||
} | } | ||||
* @param mixed $calendarId | * @param mixed $calendarId | ||||
* @param string $objectUri | * @param string $objectUri | ||||
* @param string $calendarData | * @param string $calendarData | ||||
* @param int $calendarType | |||||
* @return string | * @return string | ||||
*/ | */ | ||||
function updateCalendarObject($calendarId, $objectUri, $calendarData) { | |||||
function updateCalendarObject($calendarId, $objectUri, $calendarData, $calendarType=self::CALENDAR_TYPE_CALENDAR) { | |||||
$extraData = $this->getDenormalizedData($calendarData); | $extraData = $this->getDenormalizedData($calendarData); | ||||
$query = $this->db->getQueryBuilder(); | $query = $this->db->getQueryBuilder(); | ||||
->set('uid', $query->createNamedParameter($extraData['uid'])) | ->set('uid', $query->createNamedParameter($extraData['uid'])) | ||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))) | ->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))) | ||||
->andWhere($query->expr()->eq('uri', $query->createNamedParameter($objectUri))) | ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($objectUri))) | ||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter($calendarType))) | |||||
->execute(); | ->execute(); | ||||
$this->updateProperties($calendarId, $objectUri, $calendarData); | |||||
$this->updateProperties($calendarId, $objectUri, $calendarData, $calendarType); | |||||
$data = $this->getCalendarObject($calendarId, $objectUri); | $data = $this->getCalendarObject($calendarId, $objectUri); | ||||
if (is_array($data)) { | if (is_array($data)) { | ||||
$this->dispatcher->dispatch('\OCA\DAV\CalDAV\CalDavBackend::updateCalendarObject', new GenericEvent( | |||||
'\OCA\DAV\CalDAV\CalDavBackend::updateCalendarObject', | |||||
[ | |||||
'calendarId' => $calendarId, | |||||
'calendarData' => $this->getCalendarById($calendarId), | |||||
'shares' => $this->getShares($calendarId), | |||||
'objectData' => $data, | |||||
] | |||||
)); | |||||
if ($calendarType === self::CALENDAR_TYPE_CALENDAR) { | |||||
$this->dispatcher->dispatch('\OCA\DAV\CalDAV\CalDavBackend::updateCalendarObject', new GenericEvent( | |||||
'\OCA\DAV\CalDAV\CalDavBackend::updateCalendarObject', | |||||
[ | |||||
'calendarId' => $calendarId, | |||||
'calendarData' => $this->getCalendarById($calendarId), | |||||
'shares' => $this->getShares($calendarId), | |||||
'objectData' => $data, | |||||
] | |||||
)); | |||||
} else { | |||||
$this->dispatcher->dispatch('\OCA\DAV\CalDAV\CalDavBackend::updateCachedCalendarObject', new GenericEvent( | |||||
'\OCA\DAV\CalDAV\CalDavBackend::updateCachedCalendarObject', | |||||
[ | |||||
'subscriptionId' => $calendarId, | |||||
'calendarData' => $this->getCalendarById($calendarId), | |||||
'shares' => $this->getShares($calendarId), | |||||
'objectData' => $data, | |||||
] | |||||
)); | |||||
} | |||||
} | } | ||||
$this->addChange($calendarId, $objectUri, 2); | |||||
$this->addChange($calendarId, $objectUri, 2, $calendarType); | |||||
return '"' . $extraData['etag'] . '"'; | return '"' . $extraData['etag'] . '"'; | ||||
} | } | ||||
* | * | ||||
* @param mixed $calendarId | * @param mixed $calendarId | ||||
* @param string $objectUri | * @param string $objectUri | ||||
* @param int $calendarType | |||||
* @return void | * @return void | ||||
*/ | */ | ||||
function deleteCalendarObject($calendarId, $objectUri) { | |||||
$data = $this->getCalendarObject($calendarId, $objectUri); | |||||
function deleteCalendarObject($calendarId, $objectUri, $calendarType=self::CALENDAR_TYPE_CALENDAR) { | |||||
$data = $this->getCalendarObject($calendarId, $objectUri, $calendarType); | |||||
if (is_array($data)) { | if (is_array($data)) { | ||||
$this->dispatcher->dispatch('\OCA\DAV\CalDAV\CalDavBackend::deleteCalendarObject', new GenericEvent( | |||||
'\OCA\DAV\CalDAV\CalDavBackend::deleteCalendarObject', | |||||
[ | |||||
'calendarId' => $calendarId, | |||||
'calendarData' => $this->getCalendarById($calendarId), | |||||
'shares' => $this->getShares($calendarId), | |||||
'objectData' => $data, | |||||
] | |||||
)); | |||||
if ($calendarType === self::CALENDAR_TYPE_CALENDAR) { | |||||
$this->dispatcher->dispatch('\OCA\DAV\CalDAV\CalDavBackend::deleteCalendarObject', new GenericEvent( | |||||
'\OCA\DAV\CalDAV\CalDavBackend::deleteCalendarObject', | |||||
[ | |||||
'calendarId' => $calendarId, | |||||
'calendarData' => $this->getCalendarById($calendarId), | |||||
'shares' => $this->getShares($calendarId), | |||||
'objectData' => $data, | |||||
] | |||||
)); | |||||
} else { | |||||
$this->dispatcher->dispatch('\OCA\DAV\CalDAV\CalDavBackend::deleteCachedCalendarObject', new GenericEvent( | |||||
'\OCA\DAV\CalDAV\CalDavBackend::deleteCachedCalendarObject', | |||||
[ | |||||
'subscriptionId' => $calendarId, | |||||
'calendarData' => $this->getCalendarById($calendarId), | |||||
'shares' => $this->getShares($calendarId), | |||||
'objectData' => $data, | |||||
] | |||||
)); | |||||
} | |||||
} | } | ||||
$stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendarobjects` WHERE `calendarid` = ? AND `uri` = ?'); | |||||
$stmt->execute([$calendarId, $objectUri]); | |||||
$stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendarobjects` WHERE `calendarid` = ? AND `uri` = ? AND `calendartype` = ?'); | |||||
$stmt->execute([$calendarId, $objectUri, $calendarType]); | |||||
$this->purgeProperties($calendarId, $data['id']); | |||||
$this->purgeProperties($calendarId, $data['id'], $calendarType); | |||||
$this->addChange($calendarId, $objectUri, 3); | |||||
$this->addChange($calendarId, $objectUri, 3, $calendarType); | |||||
} | } | ||||
/** | /** | ||||
* as possible, so it gives you a good idea on what type of stuff you need | * as possible, so it gives you a good idea on what type of stuff you need | ||||
* to think of. | * to think of. | ||||
* | * | ||||
* @param mixed $calendarId | |||||
* @param mixed $id | |||||
* @param array $filters | * @param array $filters | ||||
* @param int $calendarType | |||||
* @return array | * @return array | ||||
*/ | */ | ||||
function calendarQuery($calendarId, array $filters) { | |||||
public function calendarQuery($id, array $filters, $calendarType=self::CALENDAR_TYPE_CALENDAR):array { | |||||
$componentType = null; | $componentType = null; | ||||
$requirePostFilter = true; | $requirePostFilter = true; | ||||
$timeRange = null; | $timeRange = null; | ||||
$query = $this->db->getQueryBuilder(); | $query = $this->db->getQueryBuilder(); | ||||
$query->select($columns) | $query->select($columns) | ||||
->from('calendarobjects') | ->from('calendarobjects') | ||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))); | |||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($id))) | |||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter($calendarType))); | |||||
if ($componentType) { | if ($componentType) { | ||||
$query->andWhere($query->expr()->eq('componenttype', $query->createNamedParameter($componentType))); | $query->andWhere($query->expr()->eq('componenttype', $query->createNamedParameter($componentType))); | ||||
} catch(ParseException $ex) { | } catch(ParseException $ex) { | ||||
$this->logger->logException($ex, [ | $this->logger->logException($ex, [ | ||||
'app' => 'dav', | 'app' => 'dav', | ||||
'message' => 'Caught parsing exception for calendar data. This usually indicates invalid calendar data. calendar-id:'.$calendarId.' uri:'.$row['uri'] | |||||
'message' => 'Caught parsing exception for calendar data. This usually indicates invalid calendar data. calendar-id:'.$id.' uri:'.$row['uri'] | |||||
]); | ]); | ||||
continue; | continue; | ||||
} catch (InvalidDataException $ex) { | } catch (InvalidDataException $ex) { | ||||
$this->logger->logException($ex, [ | $this->logger->logException($ex, [ | ||||
'app' => 'dav', | 'app' => 'dav', | ||||
'message' => 'Caught invalid data exception for calendar data. This usually indicates invalid calendar data. calendar-id:'.$calendarId.' uri:'.$row['uri'] | |||||
'message' => 'Caught invalid data exception for calendar data. This usually indicates invalid calendar data. calendar-id:'.$id.' uri:'.$row['uri'] | |||||
]); | ]); | ||||
continue; | continue; | ||||
} | } | ||||
/** | /** | ||||
* custom Nextcloud search extension for CalDAV | * custom Nextcloud search extension for CalDAV | ||||
* | * | ||||
* TODO - this should optionally cover cached calendar objects as well | |||||
* | |||||
* @param string $principalUri | * @param string $principalUri | ||||
* @param array $filters | * @param array $filters | ||||
* @param integer|null $limit | * @param integer|null $limit | ||||
// Calendar id expressions | // Calendar id expressions | ||||
$calendarExpressions = []; | $calendarExpressions = []; | ||||
foreach($ownCalendars as $id) { | foreach($ownCalendars as $id) { | ||||
$calendarExpressions[] = $query->expr() | |||||
->eq('c.calendarid', $query->createNamedParameter($id)); | |||||
$calendarExpressions[] = $query->expr()->andX( | |||||
$query->expr()->eq('c.calendarid', | |||||
$query->createNamedParameter($id)), | |||||
$query->expr()->eq('c.calendartype', | |||||
$query->createNamedParameter(self::CALENDAR_TYPE_CALENDAR))); | |||||
} | } | ||||
foreach($sharedCalendars as $id) { | foreach($sharedCalendars as $id) { | ||||
$calendarExpressions[] = $query->expr()->andX( | $calendarExpressions[] = $query->expr()->andX( | ||||
$query->expr()->eq('c.calendarid', | $query->expr()->eq('c.calendarid', | ||||
$query->createNamedParameter($id)), | $query->createNamedParameter($id)), | ||||
$query->expr()->eq('c.classification', | $query->expr()->eq('c.classification', | ||||
$query->createNamedParameter(self::CLASSIFICATION_PUBLIC)) | |||||
); | |||||
$query->createNamedParameter(self::CLASSIFICATION_PUBLIC)), | |||||
$query->expr()->eq('c.calendartype', | |||||
$query->createNamedParameter(self::CALENDAR_TYPE_CALENDAR))); | |||||
} | } | ||||
if (count($calendarExpressions) === 1) { | if (count($calendarExpressions) === 1) { | ||||
$innerQuery->selectDistinct('op.objectid') | $innerQuery->selectDistinct('op.objectid') | ||||
->from($this->dbObjectPropertiesTable, 'op') | ->from($this->dbObjectPropertiesTable, 'op') | ||||
->andWhere($innerQuery->expr()->eq('op.calendarid', | ->andWhere($innerQuery->expr()->eq('op.calendarid', | ||||
$outerQuery->createNamedParameter($calendarInfo['id']))); | |||||
$outerQuery->createNamedParameter($calendarInfo['id']))) | |||||
->andWhere($innerQuery->expr()->eq('op.calendartype', | |||||
$outerQuery->createNamedParameter(self::CALENDAR_TYPE_CALENDAR))); | |||||
// only return public items for shared calendars for now | // only return public items for shared calendars for now | ||||
if ($calendarInfo['principaluri'] !== $calendarInfo['{http://owncloud.org/ns}owner-principal']) { | if ($calendarInfo['principaluri'] !== $calendarInfo['{http://owncloud.org/ns}owner-principal']) { | ||||
->from('calendarobjects', 'co') | ->from('calendarobjects', 'co') | ||||
->leftJoin('co', 'calendars', 'c', $query->expr()->eq('co.calendarid', 'c.id')) | ->leftJoin('co', 'calendars', 'c', $query->expr()->eq('co.calendarid', 'c.id')) | ||||
->where($query->expr()->eq('c.principaluri', $query->createNamedParameter($principalUri))) | ->where($query->expr()->eq('c.principaluri', $query->createNamedParameter($principalUri))) | ||||
->andWhere($query->expr()->eq('co.uid', $query->createNamedParameter($uid))) | |||||
->andWhere($query->expr()->eq('co.uid', $query->createNamedParameter($uid))); | ->andWhere($query->expr()->eq('co.uid', $query->createNamedParameter($uid))); | ||||
$stmt = $query->execute(); | $stmt = $query->execute(); | ||||
* @param string $syncToken | * @param string $syncToken | ||||
* @param int $syncLevel | * @param int $syncLevel | ||||
* @param int $limit | * @param int $limit | ||||
* @param int $calendarType | |||||
* @return array | * @return array | ||||
*/ | */ | ||||
function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit = null) { | |||||
function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit = null, $calendarType=self::CALENDAR_TYPE_CALENDAR) { | |||||
// Current synctoken | // Current synctoken | ||||
$stmt = $this->db->prepare('SELECT `synctoken` FROM `*PREFIX*calendars` WHERE `id` = ?'); | $stmt = $this->db->prepare('SELECT `synctoken` FROM `*PREFIX*calendars` WHERE `id` = ?'); | ||||
$stmt->execute([ $calendarId ]); | $stmt->execute([ $calendarId ]); | ||||
if ($syncToken) { | if ($syncToken) { | ||||
$query = "SELECT `uri`, `operation` FROM `*PREFIX*calendarchanges` WHERE `synctoken` >= ? AND `synctoken` < ? AND `calendarid` = ? ORDER BY `synctoken`"; | |||||
$query = "SELECT `uri`, `operation` FROM `*PREFIX*calendarchanges` WHERE `synctoken` >= ? AND `synctoken` < ? AND `calendarid` = ? AND `calendartype` = ? ORDER BY `synctoken`"; | |||||
if ($limit>0) { | if ($limit>0) { | ||||
$query.= " LIMIT " . (int)$limit; | $query.= " LIMIT " . (int)$limit; | ||||
} | } | ||||
// Fetching all changes | // Fetching all changes | ||||
$stmt = $this->db->prepare($query); | $stmt = $this->db->prepare($query); | ||||
$stmt->execute([$syncToken, $currentToken, $calendarId]); | |||||
$stmt->execute([$syncToken, $currentToken, $calendarId, $calendarType]); | |||||
$changes = []; | $changes = []; | ||||
} | } | ||||
} else { | } else { | ||||
// No synctoken supplied, this is the initial sync. | // No synctoken supplied, this is the initial sync. | ||||
$query = "SELECT `uri` FROM `*PREFIX*calendarobjects` WHERE `calendarid` = ?"; | |||||
$query = "SELECT `uri` FROM `*PREFIX*calendarobjects` WHERE `calendarid` = ? AND `calendartype` = ?"; | |||||
$stmt = $this->db->prepare($query); | $stmt = $this->db->prepare($query); | ||||
$stmt->execute([$calendarId]); | |||||
$stmt->execute([$calendarId, $calendarType]); | |||||
$result['added'] = $stmt->fetchAll(\PDO::FETCH_COLUMN); | $result['added'] = $stmt->fetchAll(\PDO::FETCH_COLUMN); | ||||
} | } | ||||
$fields[] = 'source'; | $fields[] = 'source'; | ||||
$fields[] = 'principaluri'; | $fields[] = 'principaluri'; | ||||
$fields[] = 'lastmodified'; | $fields[] = 'lastmodified'; | ||||
$fields[] = 'synctoken'; | |||||
$query = $this->db->getQueryBuilder(); | $query = $this->db->getQueryBuilder(); | ||||
$query->select($fields) | $query->select($fields) | ||||
'lastmodified' => $row['lastmodified'], | 'lastmodified' => $row['lastmodified'], | ||||
'{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VTODO', 'VEVENT']), | '{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VTODO', 'VEVENT']), | ||||
'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0', | |||||
]; | ]; | ||||
foreach($this->subscriptionPropertyMap as $xmlName=>$dbName) { | foreach($this->subscriptionPropertyMap as $xmlName=>$dbName) { | ||||
->values($valuesToInsert) | ->values($valuesToInsert) | ||||
->execute(); | ->execute(); | ||||
return $this->db->lastInsertId('*PREFIX*calendarsubscriptions'); | |||||
$subscriptionId = $this->db->lastInsertId('*PREFIX*calendarsubscriptions'); | |||||
$this->dispatcher->dispatch('\OCA\DAV\CalDAV\CalDavBackend::createSubscription', new GenericEvent( | |||||
'\OCA\DAV\CalDAV\CalDavBackend::createSubscription', | |||||
[ | |||||
'subscriptionId' => $subscriptionId, | |||||
'subscriptionData' => $this->getSubscriptionById($subscriptionId), | |||||
])); | |||||
return $subscriptionId; | |||||
} | } | ||||
/** | /** | ||||
$query->where($query->expr()->eq('id', $query->createNamedParameter($subscriptionId))) | $query->where($query->expr()->eq('id', $query->createNamedParameter($subscriptionId))) | ||||
->execute(); | ->execute(); | ||||
$this->dispatcher->dispatch('\OCA\DAV\CalDAV\CalDavBackend::updateSubscription', new GenericEvent( | |||||
'\OCA\DAV\CalDAV\CalDavBackend::updateSubscription', | |||||
[ | |||||
'subscriptionId' => $subscriptionId, | |||||
'subscriptionData' => $this->getSubscriptionById($subscriptionId), | |||||
'propertyMutations' => $mutations, | |||||
])); | |||||
return true; | return true; | ||||
}); | }); | ||||
* @return void | * @return void | ||||
*/ | */ | ||||
function deleteSubscription($subscriptionId) { | function deleteSubscription($subscriptionId) { | ||||
$this->dispatcher->dispatch('\OCA\DAV\CalDAV\CalDavBackend::deleteSubscription', new GenericEvent( | |||||
'\OCA\DAV\CalDAV\CalDavBackend::deleteSubscription', | |||||
[ | |||||
'subscriptionId' => $subscriptionId, | |||||
'subscriptionData' => $this->getSubscriptionById($subscriptionId), | |||||
])); | |||||
$query = $this->db->getQueryBuilder(); | $query = $this->db->getQueryBuilder(); | ||||
$query->delete('calendarsubscriptions') | $query->delete('calendarsubscriptions') | ||||
->where($query->expr()->eq('id', $query->createNamedParameter($subscriptionId))) | ->where($query->expr()->eq('id', $query->createNamedParameter($subscriptionId))) | ||||
->execute(); | ->execute(); | ||||
$query = $this->db->getQueryBuilder(); | |||||
$query->delete('calendarobjects') | |||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($subscriptionId))) | |||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter(self::CALENDAR_TYPE_SUBSCRIPTION))) | |||||
->execute(); | |||||
$query->delete('calendarchanges') | |||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($subscriptionId))) | |||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter(self::CALENDAR_TYPE_SUBSCRIPTION))) | |||||
->execute(); | |||||
$query->delete($this->dbObjectPropertiesTable) | |||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($subscriptionId))) | |||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter(self::CALENDAR_TYPE_SUBSCRIPTION))) | |||||
->execute(); | |||||
} | } | ||||
/** | /** | ||||
* @param mixed $calendarId | * @param mixed $calendarId | ||||
* @param string $objectUri | * @param string $objectUri | ||||
* @param int $operation 1 = add, 2 = modify, 3 = delete. | * @param int $operation 1 = add, 2 = modify, 3 = delete. | ||||
* @param int $calendarType | |||||
* @return void | * @return void | ||||
*/ | */ | ||||
protected function addChange($calendarId, $objectUri, $operation) { | |||||
protected function addChange($calendarId, $objectUri, $operation, $calendarType=self::CALENDAR_TYPE_CALENDAR) { | |||||
$table = $calendarType === self::CALENDAR_TYPE_CALENDAR ? 'calendars': 'calendarsubscriptions'; | |||||
$stmt = $this->db->prepare('INSERT INTO `*PREFIX*calendarchanges` (`uri`, `synctoken`, `calendarid`, `operation`) SELECT ?, `synctoken`, ?, ? FROM `*PREFIX*calendars` WHERE `id` = ?'); | |||||
$stmt->execute([ | |||||
$objectUri, | |||||
$calendarId, | |||||
$operation, | |||||
$calendarId | |||||
]); | |||||
$stmt = $this->db->prepare('UPDATE `*PREFIX*calendars` SET `synctoken` = `synctoken` + 1 WHERE `id` = ?'); | |||||
$query = $this->db->getQueryBuilder(); | |||||
$query->select('synctoken') | |||||
->from($table) | |||||
->where($query->expr()->eq('id', $query->createNamedParameter($calendarId))); | |||||
$syncToken = (int)$query->execute()->fetchColumn(); | |||||
$query = $this->db->getQueryBuilder(); | |||||
$query->insert('calendarchanges') | |||||
->values([ | |||||
'uri' => $query->createNamedParameter($objectUri), | |||||
'synctoken' => $query->createNamedParameter($syncToken), | |||||
'calendarid' => $query->createNamedParameter($calendarId), | |||||
'operation' => $query->createNamedParameter($operation), | |||||
'calendartype' => $query->createNamedParameter($calendarType), | |||||
]) | |||||
->execute(); | |||||
$stmt = $this->db->prepare("UPDATE `*PREFIX*$table` SET `synctoken` = `synctoken` + 1 WHERE `id` = ?"); | |||||
$stmt->execute([ | $stmt->execute([ | ||||
$calendarId | $calendarId | ||||
]); | ]); | ||||
} | } | ||||
/** | |||||
* @param $cardData | |||||
* @return bool|string | |||||
*/ | |||||
private function readBlob($cardData) { | private function readBlob($cardData) { | ||||
if (is_resource($cardData)) { | if (is_resource($cardData)) { | ||||
return stream_get_contents($cardData); | return stream_get_contents($cardData); | ||||
'add' => $add, | 'add' => $add, | ||||
'remove' => $remove, | 'remove' => $remove, | ||||
])); | ])); | ||||
$this->sharingBackend->updateShares($shareable, $add, $remove); | |||||
$this->calendarSharingBackend->updateShares($shareable, $add, $remove); | |||||
} | } | ||||
/** | /** | ||||
* @param int $resourceId | * @param int $resourceId | ||||
* @param int $calendarType | |||||
* @return array | * @return array | ||||
*/ | */ | ||||
public function getShares($resourceId) { | |||||
return $this->sharingBackend->getShares($resourceId); | |||||
public function getShares($resourceId, $calendarType=self::CALENDAR_TYPE_CALENDAR) { | |||||
return $this->calendarSharingBackend->getShares($resourceId); | |||||
} | } | ||||
/** | /** | ||||
* @return array | * @return array | ||||
*/ | */ | ||||
public function applyShareAcl($resourceId, $acl) { | public function applyShareAcl($resourceId, $acl) { | ||||
return $this->sharingBackend->applyShareAcl($resourceId, $acl); | |||||
return $this->calendarSharingBackend->applyShareAcl($resourceId, $acl); | |||||
} | } | ||||
* @param int $calendarId | * @param int $calendarId | ||||
* @param string $objectUri | * @param string $objectUri | ||||
* @param string $calendarData | * @param string $calendarData | ||||
* @param int $calendarType | |||||
*/ | */ | ||||
public function updateProperties($calendarId, $objectUri, $calendarData) { | |||||
$objectId = $this->getCalendarObjectId($calendarId, $objectUri); | |||||
public function updateProperties($calendarId, $objectUri, $calendarData, $calendarType=self::CALENDAR_TYPE_CALENDAR) { | |||||
$objectId = $this->getCalendarObjectId($calendarId, $objectUri, $calendarType); | |||||
try { | try { | ||||
$vCalendar = $this->readCalendarData($calendarData); | $vCalendar = $this->readCalendarData($calendarData); | ||||
->values( | ->values( | ||||
[ | [ | ||||
'calendarid' => $query->createNamedParameter($calendarId), | 'calendarid' => $query->createNamedParameter($calendarId), | ||||
'calendartype' => $query->createNamedParameter($calendarType), | |||||
'objectid' => $query->createNamedParameter($objectId), | 'objectid' => $query->createNamedParameter($objectId), | ||||
'name' => $query->createParameter('name'), | 'name' => $query->createParameter('name'), | ||||
'parameter' => $query->createParameter('parameter'), | 'parameter' => $query->createParameter('parameter'), | ||||
public function deleteAllBirthdayCalendars() { | public function deleteAllBirthdayCalendars() { | ||||
$query = $this->db->getQueryBuilder(); | $query = $this->db->getQueryBuilder(); | ||||
$result = $query->select(['id'])->from('calendars') | $result = $query->select(['id'])->from('calendars') | ||||
->where($query->expr()->eq('uri', | |||||
$query->createNamedParameter(BirthdayService::BIRTHDAY_CALENDAR_URI))) | |||||
->where($query->expr()->eq('uri', $query->createNamedParameter(BirthdayService::BIRTHDAY_CALENDAR_URI))) | |||||
->execute(); | ->execute(); | ||||
$ids = $result->fetchAll(); | $ids = $result->fetchAll(); | ||||
} | } | ||||
} | } | ||||
/** | |||||
* @param $subscriptionId | |||||
*/ | |||||
public function purgeAllCachedEventsForSubscription($subscriptionId) { | |||||
$query = $this->db->getQueryBuilder(); | |||||
$query->select('uri') | |||||
->from('calendarobjects') | |||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($subscriptionId))) | |||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter(self::CALENDAR_TYPE_SUBSCRIPTION))); | |||||
$stmt = $query->execute(); | |||||
$uris = []; | |||||
foreach($stmt->fetchAll(\PDO::FETCH_ASSOC) as $row) { | |||||
$uris[] = $row['uri']; | |||||
} | |||||
$stmt->closeCursor(); | |||||
$query = $this->db->getQueryBuilder(); | |||||
$query->delete('calendarobjects') | |||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($subscriptionId))) | |||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter(self::CALENDAR_TYPE_SUBSCRIPTION))) | |||||
->execute(); | |||||
$query->delete('calendarchanges') | |||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($subscriptionId))) | |||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter(self::CALENDAR_TYPE_SUBSCRIPTION))) | |||||
->execute(); | |||||
$query->delete($this->dbObjectPropertiesTable) | |||||
->where($query->expr()->eq('calendarid', $query->createNamedParameter($subscriptionId))) | |||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter(self::CALENDAR_TYPE_SUBSCRIPTION))) | |||||
->execute(); | |||||
foreach($uris as $uri) { | |||||
$this->addChange($subscriptionId, $uri, 3, self::CALENDAR_TYPE_SUBSCRIPTION); | |||||
} | |||||
} | |||||
/** | /** | ||||
* read VCalendar data into a VCalendar object | * read VCalendar data into a VCalendar object | ||||
* | * | ||||
* | * | ||||
* @param int $calendarId | * @param int $calendarId | ||||
* @param string $uri | * @param string $uri | ||||
* @param int $calendarType | |||||
* @return int | * @return int | ||||
*/ | */ | ||||
protected function getCalendarObjectId($calendarId, $uri) { | |||||
protected function getCalendarObjectId($calendarId, $uri, $calendarType):int { | |||||
$query = $this->db->getQueryBuilder(); | $query = $this->db->getQueryBuilder(); | ||||
$query->select('id')->from('calendarobjects') | |||||
$query->select('id') | |||||
->from('calendarobjects') | |||||
->where($query->expr()->eq('uri', $query->createNamedParameter($uri))) | ->where($query->expr()->eq('uri', $query->createNamedParameter($uri))) | ||||
->andWhere($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))); | |||||
->andWhere($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))) | |||||
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter($calendarType))); | |||||
$result = $query->execute(); | $result = $query->execute(); | ||||
$objectIds = $result->fetch(); | $objectIds = $result->fetch(); | ||||
return (int)$objectIds['id']; | return (int)$objectIds['id']; | ||||
} | } | ||||
/** | |||||
* return legacy endpoint principal name to new principal name | |||||
* | |||||
* @param $principalUri | |||||
* @param $toV2 | |||||
* @return string | |||||
*/ | |||||
private function convertPrincipal($principalUri, $toV2) { | private function convertPrincipal($principalUri, $toV2) { | ||||
if ($this->principalBackend->getPrincipalPrefix() === 'principals') { | if ($this->principalBackend->getPrincipalPrefix() === 'principals') { | ||||
list(, $name) = Uri\split($principalUri); | list(, $name) = Uri\split($principalUri); | ||||
return $principalUri; | return $principalUri; | ||||
} | } | ||||
/** | |||||
* adds information about an owner to the calendar data | |||||
* | |||||
* @param $calendarInfo | |||||
*/ | |||||
private function addOwnerPrincipal(&$calendarInfo) { | private function addOwnerPrincipal(&$calendarInfo) { | ||||
$ownerPrincipalKey = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal'; | $ownerPrincipalKey = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal'; | ||||
$displaynameKey = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}owner-displayname'; | $displaynameKey = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}owner-displayname'; |
/** @var \OCP\IConfig */ | /** @var \OCP\IConfig */ | ||||
private $config; | private $config; | ||||
/** @var bool */ | |||||
private $returnCachedSubscriptions=false; | |||||
public function __construct(BackendInterface $caldavBackend, $principalInfo) { | public function __construct(BackendInterface $caldavBackend, $principalInfo) { | ||||
parent::__construct($caldavBackend, $principalInfo); | parent::__construct($caldavBackend, $principalInfo); | ||||
$this->l10n = \OC::$server->getL10N('dav'); | $this->l10n = \OC::$server->getL10N('dav'); | ||||
// If the backend supports subscriptions, we'll add those as well, | // If the backend supports subscriptions, we'll add those as well, | ||||
if ($this->caldavBackend instanceof SubscriptionSupport) { | if ($this->caldavBackend instanceof SubscriptionSupport) { | ||||
foreach ($this->caldavBackend->getSubscriptionsForUser($this->principalInfo['uri']) as $subscription) { | foreach ($this->caldavBackend->getSubscriptionsForUser($this->principalInfo['uri']) as $subscription) { | ||||
$objects[] = new Subscription($this->caldavBackend, $subscription); | |||||
if ($this->returnCachedSubscriptions) { | |||||
$objects[] = new CachedSubscription($this->caldavBackend, $subscription); | |||||
} else { | |||||
$objects[] = new Subscription($this->caldavBackend, $subscription); | |||||
} | |||||
} | } | ||||
} | } | ||||
if ($this->caldavBackend instanceof SubscriptionSupport) { | if ($this->caldavBackend instanceof SubscriptionSupport) { | ||||
foreach ($this->caldavBackend->getSubscriptionsForUser($this->principalInfo['uri']) as $subscription) { | foreach ($this->caldavBackend->getSubscriptionsForUser($this->principalInfo['uri']) as $subscription) { | ||||
if ($subscription['uri'] === $name) { | if ($subscription['uri'] === $name) { | ||||
if ($this->returnCachedSubscriptions) { | |||||
return new CachedSubscription($this->caldavBackend, $subscription); | |||||
} | |||||
return new Subscription($this->caldavBackend, $subscription); | return new Subscription($this->caldavBackend, $subscription); | ||||
} | } | ||||
} | } | ||||
$principalUri = $this->principalInfo['uri']; | $principalUri = $this->principalInfo['uri']; | ||||
return $this->caldavBackend->calendarSearch($principalUri, $filters, $limit, $offset); | return $this->caldavBackend->calendarSearch($principalUri, $filters, $limit, $offset); | ||||
} | } | ||||
/** | |||||
* | |||||
*/ | |||||
public function enableCachedSubscriptionsForThisRequest() { | |||||
$this->returnCachedSubscriptions = true; | |||||
} | |||||
} | } |
<?php | |||||
declare(strict_types=1); | |||||
/** | |||||
* @copyright 2018 Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @author Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @license GNU AGPL version 3 or any later version | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License as | |||||
* published by the Free Software Foundation, either version 3 of the | |||||
* License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
namespace OCA\DAV\CalDAV\WebcalCaching; | |||||
use OCA\DAV\CalDAV\CalendarHome; | |||||
use OCP\IRequest; | |||||
use Sabre\DAV\Exception\NotFound; | |||||
use Sabre\DAV\Server; | |||||
use Sabre\DAV\ServerPlugin; | |||||
use Sabre\HTTP\RequestInterface; | |||||
use Sabre\HTTP\ResponseInterface; | |||||
class Plugin extends ServerPlugin { | |||||
/** | |||||
* list of regular expressions for calendar user agents, | |||||
* that do not support subscriptions on their own | |||||
* | |||||
* @var string[] | |||||
*/ | |||||
const ENABLE_FOR_CLIENTS = []; | |||||
/** | |||||
* @var bool | |||||
*/ | |||||
private $enabled=false; | |||||
/** | |||||
* @var Server | |||||
*/ | |||||
private $server; | |||||
/** | |||||
* Plugin constructor. | |||||
* | |||||
* @param IRequest $request | |||||
*/ | |||||
public function __construct(IRequest $request) { | |||||
if ($request->isUserAgent(self::ENABLE_FOR_CLIENTS)) { | |||||
$this->enabled = true; | |||||
} | |||||
$magicHeader = $request->getHeader('X-NC-CalDAV-Webcal-Caching'); | |||||
if ($magicHeader === 'On') { | |||||
$this->enabled = true; | |||||
} | |||||
} | |||||
/** | |||||
* This initializes the plugin. | |||||
* | |||||
* This function is called by Sabre\DAV\Server, after | |||||
* addPlugin is called. | |||||
* | |||||
* This method should set up the required event subscriptions. | |||||
* | |||||
* @param Server $server | |||||
*/ | |||||
public function initialize(Server $server) { | |||||
$this->server = $server; | |||||
$server->on('beforeMethod', [$this, 'beforeMethod']); | |||||
} | |||||
/** | |||||
* @param RequestInterface $request | |||||
* @param ResponseInterface $response | |||||
*/ | |||||
public function beforeMethod(RequestInterface $request, ResponseInterface $response) { | |||||
if (!$this->enabled) { | |||||
return; | |||||
} | |||||
$path = $request->getPath(); | |||||
$pathParts = explode('/', ltrim($path, '/')); | |||||
if (\count($pathParts) < 2) { | |||||
return; | |||||
} | |||||
// $calendarHomePath will look like: calendars/username | |||||
$calendarHomePath = $pathParts[0] . '/' . $pathParts[1]; | |||||
try { | |||||
$calendarHome = $this->server->tree->getNodeForPath($calendarHomePath); | |||||
if (!($calendarHome instanceof CalendarHome)) { | |||||
//how did we end up here? | |||||
return; | |||||
} | |||||
$calendarHome->enableCachedSubscriptionsForThisRequest(); | |||||
} catch(NotFound $ex) { | |||||
return; | |||||
} | |||||
} | |||||
/** | |||||
* @return bool | |||||
*/ | |||||
public function isCachingEnabledForThisRequest():bool { | |||||
return $this->enabled; | |||||
} | |||||
/** | |||||
* This method should return a list of server-features. | |||||
* | |||||
* This is for example 'versioning' and is added to the DAV: header | |||||
* in an OPTIONS response. | |||||
* | |||||
* @return string[] | |||||
*/ | |||||
public function getFeatures():array { | |||||
return ['nc-calendar-webcal-cache']; | |||||
} | |||||
/** | |||||
* Returns a plugin name. | |||||
* | |||||
* Using this name other plugins will be able to access other plugins | |||||
* using Sabre\DAV\Server::getPlugin | |||||
* | |||||
* @return string | |||||
*/ | |||||
public function getPluginName():string { | |||||
return 'nc-calendar-webcal-cache'; | |||||
} | |||||
} |
<?php | |||||
declare(strict_types=1); | |||||
/** | |||||
* @copyright 2018 Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @author Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @license GNU AGPL version 3 or any later version | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License as | |||||
* published by the Free Software Foundation, either version 3 of the | |||||
* License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
namespace OCA\DAV\Migration; | |||||
use OCA\DAV\BackgroundJob\RefreshWebcalJob; | |||||
use OCP\BackgroundJob\IJobList; | |||||
use OCP\IDBConnection; | |||||
use OCP\Migration\IOutput; | |||||
use OCP\Migration\IRepairStep; | |||||
class RefreshWebcalJobRegistrar implements IRepairStep { | |||||
/** @var IDBConnection */ | |||||
private $connection; | |||||
/** @var IJobList */ | |||||
private $jobList; | |||||
/** | |||||
* FixBirthdayCalendarComponent constructor. | |||||
* | |||||
* @param IDBConnection $connection | |||||
* @param IJobList $jobList | |||||
*/ | |||||
public function __construct(IDBConnection $connection, IJobList $jobList) { | |||||
$this->connection = $connection; | |||||
$this->jobList = $jobList; | |||||
} | |||||
/** | |||||
* @inheritdoc | |||||
*/ | |||||
public function getName() { | |||||
return 'Registering background jobs to update cache for webcal calendars'; | |||||
} | |||||
/** | |||||
* @inheritdoc | |||||
*/ | |||||
public function run(IOutput $output) { | |||||
$query = $this->connection->getQueryBuilder(); | |||||
$query->select(['principaluri', 'uri']) | |||||
->from('calendarsubscriptions'); | |||||
$stmt = $query->execute(); | |||||
$count = 0; | |||||
while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { | |||||
$args = [ | |||||
'principaluri' => $row['principaluri'], | |||||
'uri' => $row['uri'], | |||||
]; | |||||
if (!$this->jobList->has(RefreshWebcalJob::class, $args)) { | |||||
$this->jobList->add(RefreshWebcalJob::class, $args); | |||||
$count++; | |||||
} | |||||
} | |||||
$output->info("Added $count background jobs to update webcal calendars"); | |||||
} | |||||
} |
<?php | |||||
declare(strict_types=1); | |||||
/** | |||||
* @copyright 2018 Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @author Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @license GNU AGPL version 3 or any later version | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License as | |||||
* published by the Free Software Foundation, either version 3 of the | |||||
* License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
namespace OCA\DAV\Migration; | |||||
use Doctrine\DBAL\Types\Type; | |||||
use OCP\DB\ISchemaWrapper; | |||||
use OCP\Migration\SimpleMigrationStep; | |||||
use OCP\Migration\IOutput; | |||||
class Version1006Date20180628111625 extends SimpleMigrationStep { | |||||
/** | |||||
* @param IOutput $output | |||||
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` | |||||
* @param array $options | |||||
* @return null|ISchemaWrapper | |||||
*/ | |||||
public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { | |||||
/** @var ISchemaWrapper $schema */ | |||||
$schema = $schemaClosure(); | |||||
if ($schema->hasTable('calendarchanges')) { | |||||
$calendarChangesTable = $schema->getTable('calendarchanges'); | |||||
$calendarChangesTable->addColumn('calendartype', Type::INTEGER, [ | |||||
'notnull' => true, | |||||
'default' => 0, | |||||
]); | |||||
if ($calendarChangesTable->hasIndex('calendarid_synctoken')) { | |||||
$calendarChangesTable->dropIndex('calendarid_synctoken'); | |||||
} | |||||
$calendarChangesTable->addIndex(['calendarid', 'calendartype', 'synctoken'], 'calendarid_calendartype_synctoken'); | |||||
} | |||||
if ($schema->hasTable('calendarobjects')) { | |||||
$calendarObjectsTable = $schema->getTable('calendarobjects'); | |||||
$calendarObjectsTable->addColumn('calendartype', Type::INTEGER, [ | |||||
'notnull' => true, | |||||
'default' => 0, | |||||
]); | |||||
if ($calendarObjectsTable->hasIndex('calobjects_index')) { | |||||
$calendarObjectsTable->dropIndex('calobjects_index'); | |||||
} | |||||
$calendarObjectsTable->addUniqueIndex(['calendarid', 'calendartype', 'uri'], 'calobjects_index'); | |||||
} | |||||
if ($schema->hasTable('calendarobjects_props')) { | |||||
$calendarObjectsPropsTable = $schema->getTable('calendarobjects_props'); | |||||
$calendarObjectsPropsTable->addColumn('calendartype', Type::INTEGER, [ | |||||
'notnull' => true, | |||||
'default' => 0, | |||||
]); | |||||
if ($calendarObjectsPropsTable->hasIndex('calendarobject_index')) { | |||||
$calendarObjectsPropsTable->dropIndex('calendarobject_index'); | |||||
} | |||||
if ($calendarObjectsPropsTable->hasIndex('calendarobject_name_index')) { | |||||
$calendarObjectsPropsTable->dropIndex('calendarobject_name_index'); | |||||
} | |||||
if ($calendarObjectsPropsTable->hasIndex('calendarobject_value_index')) { | |||||
$calendarObjectsPropsTable->dropIndex('calendarobject_value_index'); | |||||
} | |||||
$calendarObjectsPropsTable->addIndex(['objectid', 'calendartype'], 'calendarobject_index'); | |||||
$calendarObjectsPropsTable->addIndex(['name', 'calendartype'], 'calendarobject_name_index'); | |||||
$calendarObjectsPropsTable->addIndex(['value', 'calendartype'], 'calendarobject_value_index'); | |||||
} | |||||
if ($schema->hasTable('calendarsubscriptions')) { | |||||
$calendarSubscriptionsTable = $schema->getTable('calendarsubscriptions'); | |||||
$calendarSubscriptionsTable->addColumn('synctoken', 'integer', [ | |||||
'notnull' => true, | |||||
'default' => 1, | |||||
'length' => 10, | |||||
'unsigned' => true, | |||||
]); | |||||
} | |||||
return $schema; | |||||
} | |||||
} |
if (\OC::$server->getConfig()->getAppValue('dav', 'sendInvitations', 'yes') === 'yes') { | if (\OC::$server->getConfig()->getAppValue('dav', 'sendInvitations', 'yes') === 'yes') { | ||||
$this->server->addPlugin(\OC::$server->query(\OCA\DAV\CalDAV\Schedule\IMipPlugin::class)); | $this->server->addPlugin(\OC::$server->query(\OCA\DAV\CalDAV\Schedule\IMipPlugin::class)); | ||||
} | } | ||||
$this->server->addPlugin(new CalDAV\WebcalCaching\Plugin($request)); | |||||
$this->server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin()); | $this->server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin()); | ||||
$this->server->addPlugin(new \Sabre\CalDAV\Notifications\Plugin()); | $this->server->addPlugin(new \Sabre\CalDAV\Notifications\Plugin()); | ||||
$this->server->addPlugin(new DAV\Sharing\Plugin($authBackend, \OC::$server->getRequest())); | $this->server->addPlugin(new DAV\Sharing\Plugin($authBackend, \OC::$server->getRequest())); | ||||
$this->server->addPlugin(new \OCA\DAV\CalDAV\Publishing\PublishPlugin( | $this->server->addPlugin(new \OCA\DAV\CalDAV\Publishing\PublishPlugin( |
<?php | |||||
/** | |||||
* @copyright Copyright (c) 2018, Georg Ehrke | |||||
* | |||||
* @author Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @license AGPL-3.0 | |||||
* | |||||
* This code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License, version 3, | |||||
* as published by the Free Software Foundation. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License, version 3, | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||||
* | |||||
*/ | |||||
namespace OCA\DAV\Tests\unit\BackgroundJob; | |||||
use GuzzleHttp\HandlerStack; | |||||
use OCA\DAV\BackgroundJob\RefreshWebcalJob; | |||||
use OCA\DAV\CalDAV\CalDavBackend; | |||||
use OCP\AppFramework\Utility\ITimeFactory; | |||||
use OCP\BackgroundJob\IJobList; | |||||
use OCP\Http\Client\IClient; | |||||
use OCP\Http\Client\IClientService; | |||||
use OCP\Http\Client\IResponse; | |||||
use OCP\IConfig; | |||||
use OCP\ILogger; | |||||
use Test\TestCase; | |||||
use Sabre\VObject; | |||||
class RefreshWebcalJobTest extends TestCase { | |||||
/** @var CalDavBackend | \PHPUnit_Framework_MockObject_MockObject */ | |||||
private $caldavBackend; | |||||
/** @var IClientService | \PHPUnit_Framework_MockObject_MockObject */ | |||||
private $clientService; | |||||
/** @var IConfig | \PHPUnit_Framework_MockObject_MockObject */ | |||||
private $config; | |||||
/** @var ILogger | \PHPUnit_Framework_MockObject_MockObject */ | |||||
private $logger; | |||||
/** @var ITimeFactory | \PHPUnit_Framework_MockObject_MockObject */ | |||||
private $timeFactory; | |||||
/** @var IJobList | \PHPUnit_Framework_MockObject_MockObject */ | |||||
private $jobList; | |||||
protected function setUp() { | |||||
parent::setUp(); | |||||
$this->caldavBackend = $this->createMock(CalDavBackend::class); | |||||
$this->clientService = $this->createMock(IClientService::class); | |||||
$this->config = $this->createMock(IConfig::class); | |||||
$this->logger = $this->createMock(ILogger::class); | |||||
$this->timeFactory = $this->createMock(ITimeFactory::class); | |||||
$this->jobList = $this->createMock(IJobList::class); | |||||
} | |||||
/** | |||||
* @param string $body | |||||
* @param string $contentType | |||||
* @param string $result | |||||
* | |||||
* @dataProvider runDataProvider | |||||
*/ | |||||
public function testRun(string $body, string $contentType, string $result) { | |||||
$backgroundJob = new RefreshWebcalJob($this->caldavBackend, | |||||
$this->clientService, $this->config, $this->logger, $this->timeFactory); | |||||
$backgroundJob->setArgument([ | |||||
'principaluri' => 'principals/users/testuser', | |||||
'uri' => 'sub123', | |||||
]); | |||||
$backgroundJob->setLastRun(0); | |||||
$this->timeFactory->expects($this->once()) | |||||
->method('getTime') | |||||
->with() | |||||
->will($this->returnValue(1000000000)); | |||||
$this->caldavBackend->expects($this->exactly(2)) | |||||
->method('getSubscriptionsForUser') | |||||
->with('principals/users/testuser') | |||||
->will($this->returnValue([ | |||||
[ | |||||
'id' => 99, | |||||
'uri' => 'sub456', | |||||
'refreshreate' => 'P1D', | |||||
'striptodos' => 1, | |||||
'stripalarms' => 1, | |||||
'stripattachments' => 1, | |||||
'source' => 'webcal://foo.bar/bla' | |||||
], | |||||
[ | |||||
'id' => 42, | |||||
'uri' => 'sub123', | |||||
'refreshreate' => 'P1H', | |||||
'striptodos' => 1, | |||||
'stripalarms' => 1, | |||||
'stripattachments' => 1, | |||||
'source' => 'webcal://foo.bar/bla2' | |||||
], | |||||
])); | |||||
$client = $this->createMock(IClient::class); | |||||
$response = $this->createMock(IResponse::class); | |||||
$this->clientService->expects($this->once()) | |||||
->method('newClient') | |||||
->with() | |||||
->will($this->returnValue($client)); | |||||
$this->config->expects($this->once()) | |||||
->method('getAppValue') | |||||
->with('dav', 'webcalAllowLocalAccess', 'no') | |||||
->will($this->returnValue('no')); | |||||
$client->expects($this->once()) | |||||
->method('get') | |||||
->with('https://foo.bar/bla2', $this->callback(function($obj) { | |||||
return $obj['allow_redirects']['redirects'] === 10 && $obj['handler'] instanceof HandlerStack; | |||||
})) | |||||
->will($this->returnValue($response)); | |||||
$response->expects($this->once()) | |||||
->method('getBody') | |||||
->with() | |||||
->will($this->returnValue($body)); | |||||
$response->expects($this->once()) | |||||
->method('getHeader') | |||||
->with('Content-Type') | |||||
->will($this->returnValue($contentType)); | |||||
$this->caldavBackend->expects($this->once()) | |||||
->method('purgeAllCachedEventsForSubscription') | |||||
->with(42); | |||||
$this->caldavBackend->expects($this->once()) | |||||
->method('createCalendarObject') | |||||
->with(42, '12345.ics', $result, 1); | |||||
$backgroundJob->execute($this->jobList, $this->logger); | |||||
} | |||||
/** | |||||
* @return array | |||||
*/ | |||||
public function runDataProvider():array { | |||||
return [ | |||||
[ | |||||
"BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:12345\r\nDTSTAMP:20160218T133704Z\r\nDTSTART;VALUE=DATE:19000101\r\nDTEND;VALUE=DATE:19000102\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:12345's Birthday (1900)\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", | |||||
'text/calendar;charset=utf8', | |||||
"BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject " . VObject\Version::VERSION . "//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:12345\r\nDTSTAMP:20160218T133704Z\r\nDTSTART;VALUE=DATE:19000101\r\nDTEND;VALUE=DATE:19000102\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:12345's Birthday (1900)\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", | |||||
], | |||||
[ | |||||
'["vcalendar",[["prodid",{},"text","-//Example Corp.//Example Client//EN"],["version",{},"text","2.0"]],[["vtimezone",[["last-modified",{},"date-time","2004-01-10T03:28:45Z"],["tzid",{},"text","US/Eastern"]],[["daylight",[["dtstart",{},"date-time","2000-04-04T02:00:00"],["rrule",{},"recur",{"freq":"YEARLY","byday":"1SU","bymonth":4}],["tzname",{},"text","EDT"],["tzoffsetfrom",{},"utc-offset","-05:00"],["tzoffsetto",{},"utc-offset","-04:00"]],[]],["standard",[["dtstart",{},"date-time","2000-10-26T02:00:00"],["rrule",{},"recur",{"freq":"YEARLY","byday":"1SU","bymonth":10}],["tzname",{},"text","EST"],["tzoffsetfrom",{},"utc-offset","-04:00"],["tzoffsetto",{},"utc-offset","-05:00"]],[]]]],["vevent",[["dtstamp",{},"date-time","2006-02-06T00:11:21Z"],["dtstart",{"tzid":"US/Eastern"},"date-time","2006-01-02T14:00:00"],["duration",{},"duration","PT1H"],["recurrence-id",{"tzid":"US/Eastern"},"date-time","2006-01-04T12:00:00"],["summary",{},"text","Event #2"],["uid",{},"text","12345"]],[]]]]', | |||||
'application/calendar+json', | |||||
"BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject " . VObject\Version::VERSION . "//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VTIMEZONE\r\nLAST-MODIFIED:20040110T032845Z\r\nTZID:US/Eastern\r\nBEGIN:DAYLIGHT\r\nDTSTART:20000404T020000\r\nRRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4\r\nTZNAME:EDT\r\nTZOFFSETFROM:-0500\r\nTZOFFSETTO:-0400\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nDTSTART:20001026T020000\r\nRRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=10\r\nTZNAME:EST\r\nTZOFFSETFROM:-0400\r\nTZOFFSETTO:-0500\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTAMP:20060206T001121Z\r\nDTSTART;TZID=US/Eastern:20060102T140000\r\nDURATION:PT1H\r\nRECURRENCE-ID;TZID=US/Eastern:20060104T120000\r\nSUMMARY:Event #2\r\nUID:12345\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n" | |||||
], | |||||
[ | |||||
'<?xml version="1.0" encoding="utf-8" ?><icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"><vcalendar><properties><prodid><text>-//Example Inc.//Example Client//EN</text></prodid><version><text>2.0</text></version></properties><components><vevent><properties><dtstamp><date-time>2006-02-06T00:11:21Z</date-time></dtstamp><dtstart><parameters><tzid><text>US/Eastern</text></tzid></parameters><date-time>2006-01-04T14:00:00</date-time></dtstart><duration><duration>PT1H</duration></duration><recurrence-id><parameters><tzid><text>US/Eastern</text></tzid></parameters><date-time>2006-01-04T12:00:00</date-time></recurrence-id><summary><text>Event #2 bis</text></summary><uid><text>12345</text></uid></properties></vevent></components></vcalendar></icalendar>', | |||||
'application/calendar+xml', | |||||
"BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject " . VObject\Version::VERSION . "//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nDTSTAMP:20060206T001121Z\r\nDTSTART;TZID=US/Eastern:20060104T140000\r\nDURATION:PT1H\r\nRECURRENCE-ID;TZID=US/Eastern:20060104T120000\r\nSUMMARY:Event #2 bis\r\nUID:12345\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n" | |||||
] | |||||
]; | |||||
} | |||||
/** | |||||
* @dataProvider runLocalURLDataProvider | |||||
* | |||||
* @param string $source | |||||
*/ | |||||
public function testRunLocalURL($source) { | |||||
$backgroundJob = new RefreshWebcalJob($this->caldavBackend, | |||||
$this->clientService, $this->config, $this->logger, $this->timeFactory); | |||||
$backgroundJob->setArgument([ | |||||
'principaluri' => 'principals/users/testuser', | |||||
'uri' => 'sub123', | |||||
]); | |||||
$backgroundJob->setLastRun(0); | |||||
$this->timeFactory->expects($this->once()) | |||||
->method('getTime') | |||||
->with() | |||||
->will($this->returnValue(1000000000)); | |||||
$this->caldavBackend->expects($this->exactly(2)) | |||||
->method('getSubscriptionsForUser') | |||||
->with('principals/users/testuser') | |||||
->will($this->returnValue([ | |||||
[ | |||||
'id' => 42, | |||||
'uri' => 'sub123', | |||||
'refreshreate' => 'P1H', | |||||
'striptodos' => 1, | |||||
'stripalarms' => 1, | |||||
'stripattachments' => 1, | |||||
'source' => $source | |||||
], | |||||
])); | |||||
$client = $this->createMock(IClient::class); | |||||
$this->clientService->expects($this->once()) | |||||
->method('newClient') | |||||
->with() | |||||
->will($this->returnValue($client)); | |||||
$this->config->expects($this->once()) | |||||
->method('getAppValue') | |||||
->with('dav', 'webcalAllowLocalAccess', 'no') | |||||
->will($this->returnValue('no')); | |||||
$client->expects($this->never()) | |||||
->method('get'); | |||||
$backgroundJob->execute($this->jobList, $this->logger); | |||||
} | |||||
public function runLocalURLDataProvider():array { | |||||
return [ | |||||
['localhost/foo.bar'], | |||||
['[::1]/bla.blub'], | |||||
['192.168.0.1'], | |||||
['10.0.0.1'], | |||||
['another-host.local'], | |||||
['service.localhost'], | |||||
['!@#$'], // test invalid url | |||||
]; | |||||
} | |||||
} |
use OCP\Security\ISecureRandom; | use OCP\Security\ISecureRandom; | ||||
use OCP\Share\IManager as ShareManager; | use OCP\Share\IManager as ShareManager; | ||||
use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet; | use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet; | ||||
use Sabre\DAV\Xml\Property\Href; | |||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||||
use Test\TestCase; | use Test\TestCase; | ||||
return $calendarId; | return $calendarId; | ||||
} | } | ||||
protected function createTestSubscription() { | |||||
$this->backend->createSubscription(self::UNIT_TEST_USER, 'Example', [ | |||||
'{http://apple.com/ns/ical/}calendar-color' => '#1C4587FF', | |||||
'{http://calendarserver.org/ns/}source' => new Href(['foo']), | |||||
]); | |||||
$calendars = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER); | |||||
$this->assertEquals(1, count($calendars)); | |||||
$this->assertEquals(self::UNIT_TEST_USER, $calendars[0]['principaluri']); | |||||
$this->assertEquals('Example', $calendars[0]['uri']); | |||||
$calendarId = $calendars[0]['id']; | |||||
return $calendarId; | |||||
} | |||||
protected function createEvent($calendarId, $start = '20130912T130000Z', $end = '20130912T140000Z') { | protected function createEvent($calendarId, $start = '20130912T130000Z', $end = '20130912T140000Z') { | ||||
$randomPart = self::getUniqueID(); | $randomPart = self::getUniqueID(); |
<?php | |||||
/** | |||||
* @copyright Copyright (c) 2018 Georg Ehrke | |||||
* | |||||
* @author Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @license AGPL-3.0 | |||||
* | |||||
* This code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License, version 3, | |||||
* as published by the Free Software Foundation. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License, version 3, | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||||
* | |||||
*/ | |||||
namespace OCA\DAV\Tests\unit\CalDAV; | |||||
use OCA\DAV\CalDAV\CachedSubscriptionObject; | |||||
use OCA\DAV\CalDAV\CalDavBackend; | |||||
use OCA\DAV\CalDAV\Calendar; | |||||
use OCA\DAV\CalDAV\CalendarImpl; | |||||
class CachedSubscriptionObjectTest extends \Test\TestCase { | |||||
public function testGet() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$objectData = [ | |||||
'uri' => 'foo123' | |||||
]; | |||||
$backend->expects($this->once()) | |||||
->method('getCalendarObject') | |||||
->with(666, 'foo123', 1) | |||||
->will($this->returnValue([ | |||||
'calendardata' => 'BEGIN...', | |||||
])); | |||||
$calendarObject = new CachedSubscriptionObject($backend, $calendarInfo, $objectData); | |||||
$this->assertEquals('BEGIN...', $calendarObject->get()); | |||||
} | |||||
/** | |||||
* @expectedException \Sabre\DAV\Exception\MethodNotAllowed | |||||
* @expectedExceptionMessage Creating objects in a cached subscription is not allowed | |||||
*/ | |||||
public function testPut() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$objectData = [ | |||||
'uri' => 'foo123' | |||||
]; | |||||
$calendarObject = new CachedSubscriptionObject($backend, $calendarInfo, $objectData); | |||||
$calendarObject->put(''); | |||||
} | |||||
/** | |||||
* @expectedException \Sabre\DAV\Exception\MethodNotAllowed | |||||
* @expectedExceptionMessage Deleting objects in a cached subscription is not allowed | |||||
*/ | |||||
public function testDelete() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$objectData = [ | |||||
'uri' => 'foo123' | |||||
]; | |||||
$calendarObject = new CachedSubscriptionObject($backend, $calendarInfo, $objectData); | |||||
$calendarObject->delete(); | |||||
} | |||||
} |
<?php | |||||
/** | |||||
* @copyright Copyright (c) 2018 Georg Ehrke | |||||
* | |||||
* @author Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @license AGPL-3.0 | |||||
* | |||||
* This code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License, version 3, | |||||
* as published by the Free Software Foundation. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License, version 3, | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||||
* | |||||
*/ | |||||
namespace OCA\DAV\Tests\unit\CalDAV; | |||||
use OCA\DAV\CalDAV\CachedSubscription; | |||||
use OCA\DAV\CalDAV\CachedSubscriptionObject; | |||||
use OCA\DAV\CalDAV\CalDavBackend; | |||||
use Sabre\DAV\PropPatch; | |||||
class CachedSubscriptionTest extends \Test\TestCase { | |||||
public function testGetACL() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$calendar = new CachedSubscription($backend, $calendarInfo); | |||||
$this->assertEquals([ | |||||
[ | |||||
'privilege' => '{DAV:}read', | |||||
'principal' => 'user1', | |||||
'protected' => true, | |||||
], | |||||
[ | |||||
'privilege' => '{DAV:}read', | |||||
'principal' => 'user1/calendar-proxy-write', | |||||
'protected' => true, | |||||
], | |||||
[ | |||||
'privilege' => '{DAV:}read', | |||||
'principal' => 'user1/calendar-proxy-read', | |||||
'protected' => true, | |||||
], | |||||
[ | |||||
'privilege' => '{urn:ietf:params:xml:ns:caldav}read-free-busy', | |||||
'principal' => '{DAV:}authenticated', | |||||
'protected' => true, | |||||
], | |||||
], $calendar->getACL()); | |||||
} | |||||
public function testGetChildACL() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$calendar = new CachedSubscription($backend, $calendarInfo); | |||||
$this->assertEquals([ | |||||
[ | |||||
'privilege' => '{DAV:}read', | |||||
'principal' => 'user1', | |||||
'protected' => true, | |||||
], | |||||
[ | |||||
'privilege' => '{DAV:}read', | |||||
'principal' => 'user1/calendar-proxy-write', | |||||
'protected' => true, | |||||
], | |||||
[ | |||||
'privilege' => '{DAV:}read', | |||||
'principal' => 'user1/calendar-proxy-read', | |||||
'protected' => true, | |||||
] | |||||
], $calendar->getChildACL()); | |||||
} | |||||
public function testGetOwner() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$calendar = new CachedSubscription($backend, $calendarInfo); | |||||
$this->assertEquals('user1', $calendar->getOwner()); | |||||
} | |||||
public function testDelete() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$backend->expects($this->once()) | |||||
->method('deleteSubscription') | |||||
->with(666); | |||||
$calendar = new CachedSubscription($backend, $calendarInfo); | |||||
$calendar->delete(); | |||||
} | |||||
public function testPropPatch() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$propPatch = $this->createMock(PropPatch::class); | |||||
$backend->expects($this->once()) | |||||
->method('updateSubscription') | |||||
->with(666, $propPatch); | |||||
$calendar = new CachedSubscription($backend, $calendarInfo); | |||||
$calendar->propPatch($propPatch); | |||||
} | |||||
/** | |||||
* @expectedException \Sabre\DAV\Exception\NotFound | |||||
* @expectedExceptionMessage Calendar object not found | |||||
*/ | |||||
public function testGetChild() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$backend->expects($this->at(0)) | |||||
->method('getCalendarObject') | |||||
->with(666, 'foo1', 1) | |||||
->will($this->returnValue([ | |||||
'id' => 99, | |||||
'uri' => 'foo1' | |||||
])); | |||||
$backend->expects($this->at(1)) | |||||
->method('getCalendarObject') | |||||
->with(666, 'foo2', 1) | |||||
->will($this->returnValue(null)); | |||||
$calendar = new CachedSubscription($backend, $calendarInfo); | |||||
$first = $calendar->getChild('foo1'); | |||||
$this->assertInstanceOf(CachedSubscriptionObject::class, $first); | |||||
$calendar->getChild('foo2'); | |||||
} | |||||
public function testGetChildren() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$backend->expects($this->at(0)) | |||||
->method('getCalendarObjects') | |||||
->with(666, 1) | |||||
->will($this->returnValue([ | |||||
[ | |||||
'id' => 99, | |||||
'uri' => 'foo1' | |||||
], | |||||
[ | |||||
'id' => 100, | |||||
'uri' => 'foo2' | |||||
], | |||||
])); | |||||
$calendar = new CachedSubscription($backend, $calendarInfo); | |||||
$res = $calendar->getChildren(); | |||||
$this->assertCount(2, $res); | |||||
$this->assertInstanceOf(CachedSubscriptionObject::class, $res[0]); | |||||
$this->assertInstanceOf(CachedSubscriptionObject::class, $res[1]); | |||||
} | |||||
public function testGetMultipleChildren() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$backend->expects($this->at(0)) | |||||
->method('getMultipleCalendarObjects') | |||||
->with(666, ['foo1', 'foo2'], 1) | |||||
->will($this->returnValue([ | |||||
[ | |||||
'id' => 99, | |||||
'uri' => 'foo1' | |||||
], | |||||
[ | |||||
'id' => 100, | |||||
'uri' => 'foo2' | |||||
], | |||||
])); | |||||
$calendar = new CachedSubscription($backend, $calendarInfo); | |||||
$res = $calendar->getMultipleChildren(['foo1', 'foo2']); | |||||
$this->assertCount(2, $res); | |||||
$this->assertInstanceOf(CachedSubscriptionObject::class, $res[0]); | |||||
$this->assertInstanceOf(CachedSubscriptionObject::class, $res[1]); | |||||
} | |||||
/** | |||||
* @expectedException \Sabre\DAV\Exception\MethodNotAllowed | |||||
* @expectedExceptionMessage Creating objects in cached subscription is not allowed | |||||
*/ | |||||
public function testCreateFile() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$calendar = new CachedSubscription($backend, $calendarInfo); | |||||
$calendar->createFile('foo', []); | |||||
} | |||||
public function testChildExists() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$backend->expects($this->at(0)) | |||||
->method('getCalendarObject') | |||||
->with(666, 'foo1', 1) | |||||
->will($this->returnValue([ | |||||
'id' => 99, | |||||
'uri' => 'foo1' | |||||
])); | |||||
$backend->expects($this->at(1)) | |||||
->method('getCalendarObject') | |||||
->with(666, 'foo2', 1) | |||||
->will($this->returnValue(null)); | |||||
$calendar = new CachedSubscription($backend, $calendarInfo); | |||||
$this->assertEquals(true, $calendar->childExists('foo1')); | |||||
$this->assertEquals(false, $calendar->childExists('foo2')); | |||||
} | |||||
public function testCalendarQuery() { | |||||
$backend = $this->createMock(CalDavBackend::class); | |||||
$calendarInfo = [ | |||||
'{http://owncloud.org/ns}owner-principal' => 'user1', | |||||
'principaluri' => 'user2', | |||||
'id' => 666, | |||||
'uri' => 'cal', | |||||
]; | |||||
$backend->expects($this->once()) | |||||
->method('calendarQuery') | |||||
->with(666, ['foo'], 1) | |||||
->will($this->returnValue([99])); | |||||
$calendar = new CachedSubscription($backend, $calendarInfo); | |||||
$this->assertEquals([99], $calendar->calendarQuery(['foo'])); | |||||
} | |||||
} |
[true, 2], | [true, 2], | ||||
]; | ]; | ||||
} | } | ||||
public function testSameUriSameIdForDifferentCalendarTypes() { | |||||
$calendarId = $this->createTestCalendar(); | |||||
$subscriptionId = $this->createTestSubscription(); | |||||
$uri = static::getUniqueID('calobj'); | |||||
$calData = <<<EOD | |||||
BEGIN:VCALENDAR | |||||
VERSION:2.0 | |||||
PRODID:ownCloud Calendar | |||||
BEGIN:VEVENT | |||||
CREATED;VALUE=DATE-TIME:20130910T125139Z | |||||
UID:47d15e3ec8 | |||||
LAST-MODIFIED;VALUE=DATE-TIME:20130910T125139Z | |||||
DTSTAMP;VALUE=DATE-TIME:20130910T125139Z | |||||
SUMMARY:Test Event | |||||
DTSTART;VALUE=DATE-TIME:20130912T130000Z | |||||
DTEND;VALUE=DATE-TIME:20130912T140000Z | |||||
CLASS:PUBLIC | |||||
END:VEVENT | |||||
END:VCALENDAR | |||||
EOD; | |||||
$calData2 = <<<EOD | |||||
BEGIN:VCALENDAR | |||||
VERSION:2.0 | |||||
PRODID:ownCloud Calendar | |||||
BEGIN:VEVENT | |||||
CREATED;VALUE=DATE-TIME:20130910T125139Z | |||||
UID:47d15e3ec8 | |||||
LAST-MODIFIED;VALUE=DATE-TIME:20130910T125139Z | |||||
DTSTAMP;VALUE=DATE-TIME:20130910T125139Z | |||||
SUMMARY:Test Event 123 | |||||
DTSTART;VALUE=DATE-TIME:20130912T130000Z | |||||
DTEND;VALUE=DATE-TIME:20130912T140000Z | |||||
CLASS:PUBLIC | |||||
END:VEVENT | |||||
END:VCALENDAR | |||||
EOD; | |||||
$this->backend->createCalendarObject($calendarId, $uri, $calData); | |||||
$this->backend->createCalendarObject($subscriptionId, $uri, $calData2, CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION); | |||||
$this->assertEquals($calData, $this->backend->getCalendarObject($calendarId, $uri, CalDavBackend::CALENDAR_TYPE_CALENDAR)['calendardata']); | |||||
$this->assertEquals($calData2, $this->backend->getCalendarObject($subscriptionId, $uri, CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION)['calendardata']); | |||||
} | |||||
public function testPurgeAllCachedEventsForSubscription() { | |||||
$subscriptionId = $this->createTestSubscription(); | |||||
$uri = static::getUniqueID('calobj'); | |||||
$calData = <<<EOD | |||||
BEGIN:VCALENDAR | |||||
VERSION:2.0 | |||||
PRODID:ownCloud Calendar | |||||
BEGIN:VEVENT | |||||
CREATED;VALUE=DATE-TIME:20130910T125139Z | |||||
UID:47d15e3ec8 | |||||
LAST-MODIFIED;VALUE=DATE-TIME:20130910T125139Z | |||||
DTSTAMP;VALUE=DATE-TIME:20130910T125139Z | |||||
SUMMARY:Test Event | |||||
DTSTART;VALUE=DATE-TIME:20130912T130000Z | |||||
DTEND;VALUE=DATE-TIME:20130912T140000Z | |||||
CLASS:PUBLIC | |||||
END:VEVENT | |||||
END:VCALENDAR | |||||
EOD; | |||||
$this->backend->createCalendarObject($subscriptionId, $uri, $calData, CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION); | |||||
$this->backend->purgeAllCachedEventsForSubscription($subscriptionId); | |||||
$this->assertEquals(null, $this->backend->getCalendarObject($subscriptionId, $uri, CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION)); | |||||
} | |||||
} | } |
<?php | |||||
/** | |||||
* @copyright Copyright (c) 2018 Georg Ehrke | |||||
* | |||||
* @author Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @license AGPL-3.0 | |||||
* | |||||
* This code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License, version 3, | |||||
* as published by the Free Software Foundation. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License, version 3, | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||||
* | |||||
*/ | |||||
namespace OCA\DAV\Tests\unit\CalDAV\WebcalCaching; | |||||
use OCA\DAV\CalDAV\WebcalCaching\Plugin; | |||||
use OCP\IRequest; | |||||
class PluginTest extends \Test\TestCase { | |||||
public function testDisabled() { | |||||
$request = $this->createMock(IRequest::class); | |||||
$request->expects($this->at(0)) | |||||
->method('isUserAgent') | |||||
->with([]) | |||||
->will($this->returnValue(false)); | |||||
$request->expects($this->at(1)) | |||||
->method('getHeader') | |||||
->with('X-NC-CalDAV-Webcal-Caching') | |||||
->will($this->returnValue('')); | |||||
$plugin = new Plugin($request); | |||||
$this->assertEquals(false, $plugin->isCachingEnabledForThisRequest()); | |||||
} | |||||
public function testEnabled() { | |||||
$request = $this->createMock(IRequest::class); | |||||
$request->expects($this->at(0)) | |||||
->method('isUserAgent') | |||||
->with([]) | |||||
->will($this->returnValue(false)); | |||||
$request->expects($this->at(1)) | |||||
->method('getHeader') | |||||
->with('X-NC-CalDAV-Webcal-Caching') | |||||
->will($this->returnValue('On')); | |||||
$plugin = new Plugin($request); | |||||
$this->assertEquals(true, $plugin->isCachingEnabledForThisRequest()); | |||||
} | |||||
} |
<?php | |||||
/** | |||||
* @copyright Copyright (c) 2018, Georg Ehrke | |||||
* | |||||
* @author Georg Ehrke <oc.list@georgehrke.com> | |||||
* | |||||
* @license AGPL-3.0 | |||||
* | |||||
* This code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License, version 3, | |||||
* as published by the Free Software Foundation. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License, version 3, | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||||
* | |||||
*/ | |||||
namespace OCA\DAV\Tests\unit\DAV\Migration; | |||||
use OCA\DAV\BackgroundJob\RefreshWebcalJob; | |||||
use OCA\DAV\Migration\RefreshWebcalJobRegistrar; | |||||
use OCP\BackgroundJob\IJobList; | |||||
use OCP\DB\QueryBuilder\IQueryBuilder; | |||||
use OCP\IDBConnection; | |||||
use OCP\Migration\IOutput; | |||||
use Test\TestCase; | |||||
class RefreshWebcalJobRegistrarTest extends TestCase { | |||||
/** @var IDBConnection | \PHPUnit_Framework_MockObject_MockObject */ | |||||
private $db; | |||||
/** @var IJobList | \PHPUnit_Framework_MockObject_MockObject */ | |||||
private $jobList; | |||||
/** @var RefreshWebcalJobRegistrar */ | |||||
private $migration; | |||||
protected function setUp() { | |||||
parent::setUp(); | |||||
$this->db = $this->createMock(IDBConnection::class); | |||||
$this->jobList = $this->createMock(IJobList::class); | |||||
$this->migration = new RefreshWebcalJobRegistrar($this->db, $this->jobList); | |||||
} | |||||
public function testGetName() { | |||||
$this->assertEquals($this->migration->getName(), 'Registering background jobs to update cache for webcal calendars'); | |||||
} | |||||
public function testRun() { | |||||
$output = $this->createMock(IOutput::class); | |||||
$queryBuilder = $this->createMock(IQueryBuilder::class); | |||||
$statement = $this->createMock(\Doctrine\DBAL\Driver\Statement::class); | |||||
$this->db->expects($this->once()) | |||||
->method('getQueryBuilder') | |||||
->will($this->returnValue($queryBuilder)); | |||||
$queryBuilder->expects($this->at(0)) | |||||
->method('select') | |||||
->with(['principaluri', 'uri']) | |||||
->will($this->returnValue($queryBuilder)); | |||||
$queryBuilder->expects($this->at(1)) | |||||
->method('from') | |||||
->with('calendarsubscriptions') | |||||
->will($this->returnValue($queryBuilder)); | |||||
$queryBuilder->expects($this->at(2)) | |||||
->method('execute') | |||||
->will($this->returnValue($statement)); | |||||
$statement->expects($this->at(0)) | |||||
->method('fetch') | |||||
->with(\PDO::FETCH_ASSOC) | |||||
->will($this->returnValue([ | |||||
'principaluri' => 'foo1', | |||||
'uri' => 'bar1', | |||||
])); | |||||
$statement->expects($this->at(1)) | |||||
->method('fetch') | |||||
->with(\PDO::FETCH_ASSOC) | |||||
->will($this->returnValue([ | |||||
'principaluri' => 'foo2', | |||||
'uri' => 'bar2', | |||||
])); | |||||
$statement->expects($this->at(2)) | |||||
->method('fetch') | |||||
->with(\PDO::FETCH_ASSOC) | |||||
->will($this->returnValue([ | |||||
'principaluri' => 'foo3', | |||||
'uri' => 'bar3', | |||||
])); | |||||
$statement->expects($this->at(0)) | |||||
->method('fetch') | |||||
->with(\PDO::FETCH_ASSOC) | |||||
->will($this->returnValue(null)); | |||||
$this->jobList->expects($this->at(0)) | |||||
->method('has') | |||||
->with(RefreshWebcalJob::class, [ | |||||
'principaluri' => 'foo1', | |||||
'uri' => 'bar1', | |||||
]) | |||||
->will($this->returnValue(false)); | |||||
$this->jobList->expects($this->at(1)) | |||||
->method('add') | |||||
->with(RefreshWebcalJob::class, [ | |||||
'principaluri' => 'foo1', | |||||
'uri' => 'bar1', | |||||
]); | |||||
$this->jobList->expects($this->at(2)) | |||||
->method('has') | |||||
->with(RefreshWebcalJob::class, [ | |||||
'principaluri' => 'foo2', | |||||
'uri' => 'bar2', | |||||
]) | |||||
->will($this->returnValue(true)); | |||||
$this->jobList->expects($this->at(3)) | |||||
->method('has') | |||||
->with(RefreshWebcalJob::class, [ | |||||
'principaluri' => 'foo3', | |||||
'uri' => 'bar3', | |||||
]) | |||||
->will($this->returnValue(false)); | |||||
$this->jobList->expects($this->at(4)) | |||||
->method('add') | |||||
->with(RefreshWebcalJob::class, [ | |||||
'principaluri' => 'foo3', | |||||
'uri' => 'bar3', | |||||
]); | |||||
$output->expects($this->once()) | |||||
->method('info') | |||||
->with('Added 2 background jobs to update webcal calendars'); | |||||
$this->migration->run($output); | |||||
} | |||||
} |