Merge pull request #26826 from nextcloud/refactor/dav-typed-calendar-deleted-events

Exclusively use the typed calendar deletion events for DAV
This commit is contained in:
Morris Jobke 2021-04-29 16:14:10 +02:00 committed by GitHub
commit 22ba8fa78d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 276 additions and 63 deletions

View File

@ -206,6 +206,9 @@ return array(
'OCA\\DAV\\Files\\Sharing\\PublicLinkCheckPlugin' => $baseDir . '/../lib/Files/Sharing/PublicLinkCheckPlugin.php',
'OCA\\DAV\\HookManager' => $baseDir . '/../lib/HookManager.php',
'OCA\\DAV\\Listener\\CalendarContactInteractionListener' => $baseDir . '/../lib/Listener/CalendarContactInteractionListener.php',
'OCA\\DAV\\Listener\\CalendarDeletionActivityUpdaterListener' => $baseDir . '/../lib/Listener/CalendarDeletionActivityUpdaterListener.php',
'OCA\\DAV\\Listener\\CalendarDeletionDefaultUpdaterListener' => $baseDir . '/../lib/Listener/CalendarDeletionDefaultUpdaterListener.php',
'OCA\\DAV\\Listener\\CalendarDeletionReminderUpdaterListener' => $baseDir . '/../lib/Listener/CalendarDeletionReminderUpdaterListener.php',
'OCA\\DAV\\Migration\\BuildCalendarSearchIndex' => $baseDir . '/../lib/Migration/BuildCalendarSearchIndex.php',
'OCA\\DAV\\Migration\\BuildCalendarSearchIndexBackgroundJob' => $baseDir . '/../lib/Migration/BuildCalendarSearchIndexBackgroundJob.php',
'OCA\\DAV\\Migration\\BuildSocialSearchIndex' => $baseDir . '/../lib/Migration/BuildSocialSearchIndex.php',

View File

@ -221,6 +221,9 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Files\\Sharing\\PublicLinkCheckPlugin' => __DIR__ . '/..' . '/../lib/Files/Sharing/PublicLinkCheckPlugin.php',
'OCA\\DAV\\HookManager' => __DIR__ . '/..' . '/../lib/HookManager.php',
'OCA\\DAV\\Listener\\CalendarContactInteractionListener' => __DIR__ . '/..' . '/../lib/Listener/CalendarContactInteractionListener.php',
'OCA\\DAV\\Listener\\CalendarDeletionActivityUpdaterListener' => __DIR__ . '/..' . '/../lib/Listener/CalendarDeletionActivityUpdaterListener.php',
'OCA\\DAV\\Listener\\CalendarDeletionDefaultUpdaterListener' => __DIR__ . '/..' . '/../lib/Listener/CalendarDeletionDefaultUpdaterListener.php',
'OCA\\DAV\\Listener\\CalendarDeletionReminderUpdaterListener' => __DIR__ . '/..' . '/../lib/Listener/CalendarDeletionReminderUpdaterListener.php',
'OCA\\DAV\\Migration\\BuildCalendarSearchIndex' => __DIR__ . '/..' . '/../lib/Migration/BuildCalendarSearchIndex.php',
'OCA\\DAV\\Migration\\BuildCalendarSearchIndexBackgroundJob' => __DIR__ . '/..' . '/../lib/Migration/BuildCalendarSearchIndexBackgroundJob.php',
'OCA\\DAV\\Migration\\BuildSocialSearchIndex' => __DIR__ . '/..' . '/../lib/Migration/BuildSocialSearchIndex.php',

View File

@ -40,7 +40,6 @@ use OCA\DAV\CalDAV\Activity\Provider\Event;
use OCA\DAV\CalDAV\BirthdayService;
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CalDAV\CalendarManager;
use OCA\DAV\CalDAV\Reminder\Backend as ReminderBackend;
use OCA\DAV\CalDAV\Reminder\NotificationProvider\AudioProvider;
use OCA\DAV\CalDAV\Reminder\NotificationProvider\EmailProvider;
use OCA\DAV\CalDAV\Reminder\NotificationProvider\PushProvider;
@ -53,11 +52,15 @@ use OCA\DAV\CardDAV\CardDavBackend;
use OCA\DAV\CardDAV\ContactsManager;
use OCA\DAV\CardDAV\PhotoCache;
use OCA\DAV\CardDAV\SyncService;
use OCA\DAV\Events\CalendarDeletedEvent;
use OCA\DAV\Events\CalendarObjectCreatedEvent;
use OCA\DAV\Events\CalendarObjectUpdatedEvent;
use OCA\DAV\Events\CalendarShareUpdatedEvent;
use OCA\DAV\HookManager;
use OCA\DAV\Listener\CalendarContactInteractionListener;
use OCA\DAV\Listener\CalendarDeletionActivityUpdaterListener;
use OCA\DAV\Listener\CalendarDeletionDefaultUpdaterListener;
use OCA\DAV\Listener\CalendarDeletionReminderUpdaterListener;
use OCA\DAV\Search\ContactsSearchProvider;
use OCA\DAV\Search\EventsSearchProvider;
use OCA\DAV\Search\TasksSearchProvider;
@ -68,7 +71,6 @@ use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\AppFramework\IAppContainer;
use OCP\Calendar\IManager as ICalendarManager;
use OCP\Contacts\IManager as IContactsManager;
use OCP\IConfig;
use OCP\ILogger;
use OCP\IServerContainer;
use OCP\IUser;
@ -77,7 +79,6 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use Throwable;
use function is_null;
use function strpos;
class Application extends App implements IBootstrap {
public const APP_ID = 'dav';
@ -113,6 +114,9 @@ class Application extends App implements IBootstrap {
/**
* Register event listeners
*/
$context->registerEventListener(CalendarDeletedEvent::class, CalendarDeletionActivityUpdaterListener::class);
$context->registerEventListener(CalendarDeletedEvent::class, CalendarDeletionReminderUpdaterListener::class);
$context->registerEventListener(CalendarDeletedEvent::class, CalendarDeletionDefaultUpdaterListener::class);
$context->registerEventListener(CalendarObjectCreatedEvent::class, CalendarContactInteractionListener::class);
$context->registerEventListener(CalendarObjectUpdatedEvent::class, CalendarContactInteractionListener::class);
$context->registerEventListener(CalendarShareUpdatedEvent::class, CalendarContactInteractionListener::class);
@ -204,20 +208,6 @@ class Application extends App implements IBootstrap {
$event->getArgument('propertyMutations')
);
});
$dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::deleteCalendar', function (GenericEvent $event) use ($container) {
/** @var Backend $backend */
$backend = $container->query(Backend::class);
$backend->onCalendarDelete(
$event->getArgument('calendarData'),
$event->getArgument('shares')
);
/** @var ReminderBackend $reminderBackend */
$reminderBackend = $container->query(ReminderBackend::class);
$reminderBackend->cleanRemindersForCalendar(
(int) $event->getArgument('calendarId')
);
});
$dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::updateShares', function (GenericEvent $event) use ($container) {
/** @var Backend $backend */
$backend = $container->query(Backend::class);
@ -269,22 +259,6 @@ class Application extends App implements IBootstrap {
$dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::updateCalendarObject', $listener);
$dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::deleteCalendarObject', $listener);
/**
* In case the user has set their default calendar to this one
*/
$dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::deleteCalendar', function (GenericEvent $event) use ($serverContainer) {
/** @var IConfig $config */
$config = $serverContainer->getConfig();
$principalUri = $event->getArgument('calendarData')['principaluri'];
if (strpos($principalUri, 'principals/users') === 0) {
[, $UID] = \Sabre\Uri\split($principalUri);
$uri = $event->getArgument('calendarData')['uri'];
if ($config->getUserValue($UID, 'dav', 'defaultCalendar') === $uri) {
$config->deleteUserValue($UID, 'dav', 'defaultCalendar');
}
}
});
$dispatcher->addListener('OCP\Federation\TrustedServerEvent::remove',
function (GenericEvent $event) {
/** @var CardDavBackend $cardDavBackend */

View File

@ -890,14 +890,6 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$calendarData = $this->getCalendarById($calendarId);
$shares = $this->getShares($calendarId);
$this->legacyDispatcher->dispatch('\OCA\DAV\CalDAV\CalDavBackend::deleteCalendar', new GenericEvent(
'\OCA\DAV\CalDAV\CalDavBackend::deleteCalendar',
[
'calendarId' => $calendarId,
'calendarData' => $calendarData,
'shares' => $shares,
]));
$stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendarobjects` WHERE `calendarid` = ? AND `calendartype` = ?');
$stmt->execute([$calendarId, self::CALENDAR_TYPE_CALENDAR]);
@ -915,6 +907,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
->andWhere($query->expr()->eq('calendartype', $query->createNamedParameter(self::CALENDAR_TYPE_CALENDAR)))
->executeUpdate();
// Only dispatch if we actually deleted anything
if ($calendarData) {
$this->dispatcher->dispatchTyped(new CalendarDeletedEvent((int)$calendarId, $calendarData, $shares));
}

View File

@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
/*
* @copyright 2021 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2021 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @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\Listener;
use OCA\DAV\CalDAV\Activity\Backend as ActivityBackend;
use OCA\DAV\Events\CalendarDeletedEvent;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use Psr\Log\LoggerInterface;
use Throwable;
use function sprintf;
/**
* @template-implements IEventListener<\OCA\DAV\Events\CalendarDeletedEvent>
*/
class CalendarDeletionActivityUpdaterListener implements IEventListener {
/** @var ActivityBackend */
private $activityBackend;
/** @var LoggerInterface */
private $logger;
public function __construct(ActivityBackend $activityBackend,
LoggerInterface $logger) {
$this->activityBackend = $activityBackend;
$this->logger = $logger;
}
public function handle(Event $event): void {
if (!($event instanceof CalendarDeletedEvent)) {
// Not what we subscribed to
return;
}
try {
$this->activityBackend->onCalendarDelete(
$event->getCalendarData(),
$event->getShares()
);
$this->logger->debug(
sprintf('Activity generated for deleted calendar %d', $event->getCalendarId())
);
} catch (Throwable $e) {
// Any error with activities shouldn't abort the calendar deletion, so we just log it
$this->logger->error('Error generating activities for a deleted calendar: ' . $e->getMessage(), [
'exception' => $e,
]);
}
}
}

View File

@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
/*
* @copyright 2021 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2021 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @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\Listener;
use OCA\DAV\Events\CalendarDeletedEvent;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\IConfig;
use Psr\Log\LoggerInterface;
use Throwable;
use function strpos;
/**
* @template-implements IEventListener<\OCA\DAV\Events\CalendarDeletedEvent>
*/
class CalendarDeletionDefaultUpdaterListener implements IEventListener {
/** @var IConfig */
private $config;
/** @var LoggerInterface */
private $logger;
public function __construct(IConfig $config,
LoggerInterface $logger) {
$this->config = $config;
$this->logger = $logger;
}
/**
* In case the user has set their default calendar to the deleted one
*/
public function handle(Event $event): void {
if (!($event instanceof CalendarDeletedEvent)) {
// Not what we subscribed to
return;
}
try {
$principalUri = $event->getCalendarData()['principaluri'];
if (strpos($principalUri, 'principals/users') !== 0) {
$this->logger->debug('Default calendar needs no update because the deleted calendar does not belong to a user principal');
return;
}
[, $uid] = \Sabre\Uri\split($principalUri);
$uri = $event->getCalendarData()['uri'];
if ($this->config->getUserValue($uid, 'dav', 'defaultCalendar') !== $uri) {
$this->logger->debug('Default calendar needs no update because the deleted calendar is no the user\'s default one');
return;
}
$this->config->deleteUserValue($uid, 'dav', 'defaultCalendar');
$this->logger->debug('Default user calendar reset');
} catch (Throwable $e) {
// Any error with activities shouldn't abort the calendar deletion, so we just log it
$this->logger->error('Error generating activities for a deleted calendar: ' . $e->getMessage(), [
'exception' => $e,
]);
}
}
}

View File

@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
/*
* @copyright 2021 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2021 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @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\Listener;
use OCA\DAV\CalDAV\Reminder\Backend as ReminderBackend;
use OCA\DAV\Events\CalendarDeletedEvent;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use Psr\Log\LoggerInterface;
use Throwable;
use function sprintf;
/**
* @template-implements IEventListener<\OCA\DAV\Events\CalendarDeletedEvent>
*/
class CalendarDeletionReminderUpdaterListener implements IEventListener {
/** @var ReminderBackend */
private $reminderBackend;
/** @var LoggerInterface */
private $logger;
public function __construct(ReminderBackend $reminderBackend,
LoggerInterface $logger) {
$this->reminderBackend = $reminderBackend;
$this->logger = $logger;
}
public function handle(Event $event): void {
if (!($event instanceof CalendarDeletedEvent)) {
// Not what we subscribed to
return;
}
try {
$this->reminderBackend->cleanRemindersForCalendar(
$event->getCalendarId()
);
$this->logger->debug(
sprintf('Reminders of calendar %d cleaned up', $event->getCalendarId())
);
} catch (Throwable $e) {
// Any error with activities shouldn't abort the calendar deletion, so we just log it
$this->logger->error('Error cleaning up reminders of a deleted calendar: ' . $e->getMessage(), [
'exception' => $e,
]);
}
}
}

View File

@ -31,6 +31,7 @@ use OC\KnownUser\KnownUserService;
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CalDAV\Proxy\ProxyMapper;
use OCA\DAV\Connector\Sabre\Principal;
use OCA\DAV\Events\CalendarDeletedEvent;
use OCP\App\IAppManager;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
@ -133,11 +134,12 @@ abstract class AbstractCalDavBackend extends TestCase {
private function cleanupForPrincipal($principal): void {
$calendars = $this->backend->getCalendarsForUser($principal);
$this->legacyDispatcher->expects(self::exactly(count($calendars)))
->method('dispatchTyped')
->with(self::callback(function ($event) {
return $event instanceof CalendarDeletedEvent;
}));
foreach ($calendars as $calendar) {
$this->legacyDispatcher->expects($this->at(0))
->method('dispatch')
->with('\OCA\DAV\CalDAV\CalDavBackend::deleteCalendar');
$this->backend->deleteCalendar($calendar['id']);
}
$subscriptions = $this->backend->getSubscriptionsForUser($principal);

View File

@ -36,6 +36,7 @@ use DateTime;
use DateTimeZone;
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CalDAV\Calendar;
use OCA\DAV\Events\CalendarDeletedEvent;
use OCP\IConfig;
use OCP\IL10N;
use Sabre\DAV\Exception\NotFound;
@ -72,12 +73,14 @@ class CalDavBackendTest extends AbstractCalDavBackend {
$this->assertEquals('User\'s displayname', $calendars[0]['{http://nextcloud.com/ns}owner-displayname']);
// delete the address book
$this->legacyDispatcher->expects($this->at(0))
->method('dispatch')
->with('\OCA\DAV\CalDAV\CalDavBackend::deleteCalendar');
$this->dispatcher->expects(self::once())
->method('dispatchTyped')
->with(self::callback(function ($event) {
return $event instanceof CalendarDeletedEvent;
}));
$this->backend->deleteCalendar($calendars[0]['id']);
$calendars = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
$this->assertCount(0, $calendars);
self::assertEmpty($calendars);
}
public function providesSharingData() {
@ -196,13 +199,15 @@ EOD;
$this->assertAccess($userCanRead, self::UNIT_TEST_USER1, '{DAV:}read', $acl);
$this->assertAccess($userCanWrite, self::UNIT_TEST_USER1, '{DAV:}write', $acl);
// delete the address book
$this->legacyDispatcher->expects($this->at(0))
->method('dispatch')
->with('\OCA\DAV\CalDAV\CalDavBackend::deleteCalendar');
// delete the calendar
$this->dispatcher->expects(self::once())
->method('dispatchTyped')
->with(self::callback(function ($event) {
return $event instanceof CalendarDeletedEvent;
}));
$this->backend->deleteCalendar($calendars[0]['id']);
$calendars = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
$this->assertCount(0, $calendars);
self::assertEmpty($calendars);
}
public function testCalendarObjectsOperations() {

View File

@ -112,9 +112,6 @@
</MissingFile>
</file>
<file src="apps/dav/lib/AppInfo/Application.php">
<UndefinedFunction occurrences="1">
<code>\Sabre\Uri\split($principalUri)</code>
</UndefinedFunction>
<UndefinedInterfaceMethod occurrences="1">
<code>getAppDataDir</code>
</UndefinedInterfaceMethod>
@ -164,13 +161,12 @@
</NullableReturnStatement>
</file>
<file src="apps/dav/lib/CalDAV/CalDavBackend.php">
<InvalidArgument occurrences="14">
<InvalidArgument occurrences="13">
<code>'\OCA\DAV\CalDAV\CalDavBackend::createCachedCalendarObject'</code>
<code>'\OCA\DAV\CalDAV\CalDavBackend::createCalendar'</code>
<code>'\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject'</code>
<code>'\OCA\DAV\CalDAV\CalDavBackend::createSubscription'</code>
<code>'\OCA\DAV\CalDAV\CalDavBackend::deleteCachedCalendarObject'</code>
<code>'\OCA\DAV\CalDAV\CalDavBackend::deleteCalendar'</code>
<code>'\OCA\DAV\CalDAV\CalDavBackend::deleteCalendarObject'</code>
<code>'\OCA\DAV\CalDAV\CalDavBackend::deleteSubscription'</code>
<code>'\OCA\DAV\CalDAV\CalDavBackend::publishCalendar'</code>
@ -195,8 +191,7 @@
<RedundantCast occurrences="1">
<code>(int)$calendarId</code>
</RedundantCast>
<TooManyArguments occurrences="15">
<code>dispatch</code>
<TooManyArguments occurrences="14">
<code>dispatch</code>
<code>dispatch</code>
<code>dispatch</code>
@ -860,6 +855,11 @@
<code>$this-&gt;usersToDelete</code>
</InvalidPropertyAssignmentValue>
</file>
<file src="apps/dav/lib/Listener/CalendarDeletionDefaultUpdaterListener.php">
<UndefinedFunction occurrences="1">
<code>\Sabre\Uri\split($principalUri)</code>
</UndefinedFunction>
</file>
<file src="apps/dav/lib/RootCollection.php">
<UndefinedPropertyAssignment occurrences="1">
<code>$publicCalendarRoot-&gt;disableListing</code>
@ -1087,7 +1087,6 @@
<code>$id</code>
<code>$id</code>
<code>$id</code>
<code>$id</code>
<code>(int)$share['id']</code>
</InvalidScalarArgument>
</file>
@ -3164,7 +3163,6 @@
</InvalidArgument>
<TooManyArguments occurrences="1">
<code>dispatch</code>
<code>dispatch</code>
</TooManyArguments>
</file>
<file src="lib/private/DB/OracleConnection.php">