diff options
Diffstat (limited to 'apps/dav/lib/Migration')
45 files changed, 3110 insertions, 0 deletions
diff --git a/apps/dav/lib/Migration/BuildCalendarSearchIndex.php b/apps/dav/lib/Migration/BuildCalendarSearchIndex.php new file mode 100644 index 00000000000..d8f906f22ee --- /dev/null +++ b/apps/dav/lib/Migration/BuildCalendarSearchIndex.php @@ -0,0 +1,57 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCP\BackgroundJob\IJobList; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class BuildCalendarSearchIndex implements IRepairStep { + + public function __construct( + private IDBConnection $db, + private IJobList $jobList, + private IConfig $config, + ) { + } + + /** + * @return string + */ + public function getName() { + return 'Registering building of calendar search index as background job'; + } + + /** + * @param IOutput $output + */ + public function run(IOutput $output) { + // only run once + if ($this->config->getAppValue('dav', 'buildCalendarSearchIndex') === 'yes') { + $output->info('Repair step already executed'); + return; + } + + $query = $this->db->getQueryBuilder(); + $query->select($query->createFunction('MAX(' . $query->getColumnName('id') . ')')) + ->from('calendarobjects'); + $result = $query->executeQuery(); + $maxId = (int)$result->fetchOne(); + $result->closeCursor(); + + $output->info('Add background job'); + $this->jobList->add(BuildCalendarSearchIndexBackgroundJob::class, [ + 'offset' => 0, + 'stopAt' => $maxId + ]); + + // if all were done, no need to redo the repair during next upgrade + $this->config->setAppValue('dav', 'buildCalendarSearchIndex', 'yes'); + } +} diff --git a/apps/dav/lib/Migration/BuildCalendarSearchIndexBackgroundJob.php b/apps/dav/lib/Migration/BuildCalendarSearchIndexBackgroundJob.php new file mode 100644 index 00000000000..da8f31e7d3d --- /dev/null +++ b/apps/dav/lib/Migration/BuildCalendarSearchIndexBackgroundJob.php @@ -0,0 +1,82 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCA\DAV\CalDAV\CalDavBackend; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\IJobList; +use OCP\BackgroundJob\QueuedJob; +use OCP\IDBConnection; +use Psr\Log\LoggerInterface; + +class BuildCalendarSearchIndexBackgroundJob extends QueuedJob { + public function __construct( + private IDBConnection $db, + private CalDavBackend $calDavBackend, + private LoggerInterface $logger, + private IJobList $jobList, + ITimeFactory $timeFactory, + ) { + parent::__construct($timeFactory); + } + + public function run($arguments) { + $offset = (int)$arguments['offset']; + $stopAt = (int)$arguments['stopAt']; + + $this->logger->info('Building calendar index (' . $offset . '/' . $stopAt . ')'); + + $startTime = $this->time->getTime(); + while (($this->time->getTime() - $startTime) < 15) { + $offset = $this->buildIndex($offset, $stopAt); + if ($offset >= $stopAt) { + break; + } + } + + if ($offset >= $stopAt) { + $this->logger->info('Building calendar index done'); + } else { + $this->jobList->add(self::class, [ + 'offset' => $offset, + 'stopAt' => $stopAt + ]); + $this->logger->info('New building calendar index job scheduled with offset ' . $offset); + } + } + + /** + * @param int $offset + * @param int $stopAt + * @return int + */ + private function buildIndex(int $offset, int $stopAt): int { + $query = $this->db->getQueryBuilder(); + $query->select(['id', 'calendarid', 'uri', 'calendardata']) + ->from('calendarobjects') + ->where($query->expr()->lte('id', $query->createNamedParameter($stopAt))) + ->andWhere($query->expr()->gt('id', $query->createNamedParameter($offset))) + ->orderBy('id', 'ASC') + ->setMaxResults(500); + + $result = $query->executeQuery(); + while ($row = $result->fetch(\PDO::FETCH_ASSOC)) { + $offset = $row['id']; + + $calendarData = $row['calendardata']; + if (is_resource($calendarData)) { + $calendarData = stream_get_contents($calendarData); + } + + $this->calDavBackend->updateProperties($row['calendarid'], $row['uri'], $calendarData); + } + + return $offset; + } +} diff --git a/apps/dav/lib/Migration/BuildSocialSearchIndex.php b/apps/dav/lib/Migration/BuildSocialSearchIndex.php new file mode 100644 index 00000000000..a808034365a --- /dev/null +++ b/apps/dav/lib/Migration/BuildSocialSearchIndex.php @@ -0,0 +1,65 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCP\BackgroundJob\IJobList; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class BuildSocialSearchIndex implements IRepairStep { + + /** + * @param IDBConnection $db + * @param IJobList $jobList + * @param IConfig $config + */ + public function __construct( + private IDBConnection $db, + private IJobList $jobList, + private IConfig $config, + ) { + } + + /** + * @return string + */ + public function getName() { + return 'Register building of social profile search index as background job'; + } + + /** + * @param IOutput $output + */ + public function run(IOutput $output) { + // only run once + if ($this->config->getAppValue('dav', 'builtSocialSearchIndex') === 'yes') { + $output->info('Repair step already executed'); + return; + } + + $query = $this->db->getQueryBuilder(); + $query->select($query->func()->max('cardid')) + ->from('cards_properties') + ->where($query->expr()->eq('name', $query->createNamedParameter('X-SOCIALPROFILE'))); + $maxId = (int)$query->execute()->fetchOne(); + + if ($maxId === 0) { + return; + } + + $output->info('Add background job'); + $this->jobList->add(BuildSocialSearchIndexBackgroundJob::class, [ + 'offset' => 0, + 'stopAt' => $maxId + ]); + + // no need to redo the repair during next upgrade + $this->config->setAppValue('dav', 'builtSocialSearchIndex', 'yes'); + } +} diff --git a/apps/dav/lib/Migration/BuildSocialSearchIndexBackgroundJob.php b/apps/dav/lib/Migration/BuildSocialSearchIndexBackgroundJob.php new file mode 100644 index 00000000000..fab61d56fd6 --- /dev/null +++ b/apps/dav/lib/Migration/BuildSocialSearchIndexBackgroundJob.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCA\DAV\CardDAV\CardDavBackend; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\IJobList; +use OCP\BackgroundJob\QueuedJob; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use Psr\Log\LoggerInterface; + +class BuildSocialSearchIndexBackgroundJob extends QueuedJob { + public function __construct( + private IDBConnection $db, + private CardDavBackend $davBackend, + private LoggerInterface $logger, + private IJobList $jobList, + ITimeFactory $timeFactory, + ) { + parent::__construct($timeFactory); + } + + public function run($arguments) { + $offset = $arguments['offset']; + $stopAt = $arguments['stopAt']; + + $this->logger->info('Indexing social profile data (' . $offset . '/' . $stopAt . ')'); + + $offset = $this->buildIndex($offset, $stopAt); + + if ($offset >= $stopAt) { + $this->logger->info('All contacts with social profiles indexed'); + } else { + $this->jobList->add(self::class, [ + 'offset' => $offset, + 'stopAt' => $stopAt + ]); + $this->logger->info('New social profile indexing job scheduled with offset ' . $offset); + } + } + + /** + * @param int $offset + * @param int $stopAt + * @return int + */ + private function buildIndex($offset, $stopAt) { + $startTime = $this->time->getTime(); + + // get contacts with social profiles + $query = $this->db->getQueryBuilder(); + $query->select('id', 'addressbookid', 'uri', 'carddata') + ->from('cards', 'c') + ->orderBy('id', 'ASC') + ->where($query->expr()->like('carddata', $query->createNamedParameter('%SOCIALPROFILE%'))) + ->andWhere($query->expr()->gt('id', $query->createNamedParameter((int)$offset, IQueryBuilder::PARAM_INT))) + ->setMaxResults(100); + $social_cards = $query->executeQuery()->fetchAll(); + + if (empty($social_cards)) { + return $stopAt; + } + + // refresh identified contacts in order to re-index + foreach ($social_cards as $contact) { + $offset = $contact['id']; + $cardData = $contact['carddata']; + if (is_resource($cardData) && (get_resource_type($cardData) === 'stream')) { + $cardData = stream_get_contents($cardData); + } + $this->davBackend->updateCard($contact['addressbookid'], $contact['uri'], $cardData); + + // stop after 15sec (to be continued with next chunk) + if (($this->time->getTime() - $startTime) > 15) { + break; + } + } + + return $offset; + } +} diff --git a/apps/dav/lib/Migration/CalDAVRemoveEmptyValue.php b/apps/dav/lib/Migration/CalDAVRemoveEmptyValue.php new file mode 100644 index 00000000000..24e182e46eb --- /dev/null +++ b/apps/dav/lib/Migration/CalDAVRemoveEmptyValue.php @@ -0,0 +1,120 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCA\DAV\CalDAV\CalDavBackend; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; +use Psr\Log\LoggerInterface; +use Sabre\VObject\InvalidDataException; + +class CalDAVRemoveEmptyValue implements IRepairStep { + + public function __construct( + private IDBConnection $db, + private CalDavBackend $calDavBackend, + private LoggerInterface $logger, + ) { + } + + public function getName() { + return 'Fix broken values of calendar objects'; + } + + public function run(IOutput $output) { + $pattern = ';VALUE=:'; + $count = $warnings = 0; + + $objects = $this->getInvalidObjects($pattern); + + $output->startProgress(count($objects)); + foreach ($objects as $row) { + $calObject = $this->calDavBackend->getCalendarObject((int)$row['calendarid'], $row['uri']); + $data = preg_replace('/' . $pattern . '/', ':', $calObject['calendardata']); + + if ($data !== $calObject['calendardata']) { + $output->advance(); + + try { + $this->calDavBackend->getDenormalizedData($data); + } catch (InvalidDataException $e) { + $this->logger->info('Calendar object for calendar {cal} with uri {uri} still invalid', [ + 'app' => 'dav', + 'cal' => (int)$row['calendarid'], + 'uri' => $row['uri'], + ]); + $warnings++; + continue; + } + + $this->calDavBackend->updateCalendarObject((int)$row['calendarid'], $row['uri'], $data); + $count++; + } + } + $output->finishProgress(); + + if ($warnings > 0) { + $output->warning(sprintf('%d events could not be updated, see log file for more information', $warnings)); + } + if ($count > 0) { + $output->info(sprintf('Updated %d events', $count)); + } + } + + protected function getInvalidObjects($pattern) { + if ($this->db->getDatabaseProvider() === IDBConnection::PLATFORM_ORACLE) { + $rows = []; + $chunkSize = 500; + $query = $this->db->getQueryBuilder(); + $query->select($query->func()->count('*', 'num_entries')) + ->from('calendarobjects'); + $result = $query->executeQuery(); + $count = $result->fetchOne(); + $result->closeCursor(); + + $numChunks = ceil($count / $chunkSize); + + $query = $this->db->getQueryBuilder(); + $query->select(['calendarid', 'uri', 'calendardata']) + ->from('calendarobjects') + ->setMaxResults($chunkSize); + for ($chunk = 0; $chunk < $numChunks; $chunk++) { + $query->setFirstResult($chunk * $chunkSize); + $result = $query->executeQuery(); + + while ($row = $result->fetch()) { + if (mb_strpos($row['calendardata'], $pattern) !== false) { + unset($row['calendardata']); + $rows[] = $row; + } + } + $result->closeCursor(); + } + return $rows; + } + + $query = $this->db->getQueryBuilder(); + $query->select(['calendarid', 'uri']) + ->from('calendarobjects') + ->where($query->expr()->like( + 'calendardata', + $query->createNamedParameter( + '%' . $this->db->escapeLikeParameter($pattern) . '%', + IQueryBuilder::PARAM_STR + ), + IQueryBuilder::PARAM_STR + )); + + $result = $query->executeQuery(); + $rows = $result->fetchAll(); + $result->closeCursor(); + + return $rows; + } +} diff --git a/apps/dav/lib/Migration/ChunkCleanup.php b/apps/dav/lib/Migration/ChunkCleanup.php new file mode 100644 index 00000000000..edd9a26109e --- /dev/null +++ b/apps/dav/lib/Migration/ChunkCleanup.php @@ -0,0 +1,68 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCA\DAV\BackgroundJob\UploadCleanup; +use OCP\BackgroundJob\IJobList; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; +use OCP\Files\NotFoundException; +use OCP\IConfig; +use OCP\IUser; +use OCP\IUserManager; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class ChunkCleanup implements IRepairStep { + + public function __construct( + private IConfig $config, + private IUserManager $userManager, + private IRootFolder $rootFolder, + private IJobList $jobList, + ) { + } + + public function getName(): string { + return 'Chunk cleanup scheduler'; + } + + public function run(IOutput $output) { + // If we already ran this onec there is no need to run it again + if ($this->config->getAppValue('dav', 'chunks_migrated', '0') === '1') { + $output->info('Cleanup not required'); + return; + } + + $output->startProgress(); + // Loop over all seen users + $this->userManager->callForSeenUsers(function (IUser $user) use ($output): void { + try { + $userFolder = $this->rootFolder->getUserFolder($user->getUID()); + $userRoot = $userFolder->getParent(); + /** @var Folder $uploadFolder */ + $uploadFolder = $userRoot->get('uploads'); + } catch (NotFoundException $e) { + // No folder so skipping + return; + } + + // Insert a cleanup job for each folder we find + $uploads = $uploadFolder->getDirectoryListing(); + foreach ($uploads as $upload) { + $this->jobList->add(UploadCleanup::class, ['uid' => $user->getUID(), 'folder' => $upload->getName()]); + } + $output->advance(); + }); + $output->finishProgress(); + + + $this->config->setAppValue('dav', 'chunks_migrated', '1'); + } +} diff --git a/apps/dav/lib/Migration/CreateSystemAddressBookStep.php b/apps/dav/lib/Migration/CreateSystemAddressBookStep.php new file mode 100644 index 00000000000..ec07c72e7a7 --- /dev/null +++ b/apps/dav/lib/Migration/CreateSystemAddressBookStep.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\DAV\Migration; + +use OCA\DAV\CardDAV\SyncService; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class CreateSystemAddressBookStep implements IRepairStep { + + public function __construct( + private SyncService $syncService, + ) { + } + + public function getName(): string { + return 'Create system address book'; + } + + public function run(IOutput $output): void { + $this->syncService->ensureLocalSystemAddressBookExists(); + } +} diff --git a/apps/dav/lib/Migration/DeleteSchedulingObjects.php b/apps/dav/lib/Migration/DeleteSchedulingObjects.php new file mode 100644 index 00000000000..3cb3c9c9b10 --- /dev/null +++ b/apps/dav/lib/Migration/DeleteSchedulingObjects.php @@ -0,0 +1,39 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCA\DAV\BackgroundJob\DeleteOutdatedSchedulingObjects; +use OCA\DAV\CalDAV\CalDavBackend; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\IJobList; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class DeleteSchedulingObjects implements IRepairStep { + public function __construct( + private IJobList $jobList, + private ITimeFactory $time, + private CalDavBackend $calDavBackend, + ) { + } + + public function getName(): string { + return 'Handle outdated scheduling events'; + } + + public function run(IOutput $output): void { + $output->info('Cleaning up old scheduling events'); + $time = $this->time->getTime() - (60 * 60); + $this->calDavBackend->deleteOutdatedSchedulingObjects($time, 50000); + if (!$this->jobList->has(DeleteOutdatedSchedulingObjects::class, null)) { + $output->info('Adding background job to delete old scheduling objects'); + $this->jobList->add(DeleteOutdatedSchedulingObjects::class, null); + } + } +} diff --git a/apps/dav/lib/Migration/FixBirthdayCalendarComponent.php b/apps/dav/lib/Migration/FixBirthdayCalendarComponent.php new file mode 100644 index 00000000000..6833ca2ffa6 --- /dev/null +++ b/apps/dav/lib/Migration/FixBirthdayCalendarComponent.php @@ -0,0 +1,40 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016 ownCloud GmbH. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\DAV\Migration; + +use OCA\DAV\CalDAV\BirthdayService; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class FixBirthdayCalendarComponent implements IRepairStep { + + public function __construct( + private IDBConnection $connection, + ) { + } + + /** + * @inheritdoc + */ + public function getName() { + return 'Fix component of birthday calendars'; + } + + /** + * @inheritdoc + */ + public function run(IOutput $output) { + $query = $this->connection->getQueryBuilder(); + $updated = $query->update('calendars') + ->set('components', $query->createNamedParameter('VEVENT')) + ->where($query->expr()->eq('uri', $query->createNamedParameter(BirthdayService::BIRTHDAY_CALENDAR_URI))) + ->executeStatement(); + + $output->info("$updated birthday calendars updated."); + } +} diff --git a/apps/dav/lib/Migration/RefreshWebcalJobRegistrar.php b/apps/dav/lib/Migration/RefreshWebcalJobRegistrar.php new file mode 100644 index 00000000000..cd4b8b31f4d --- /dev/null +++ b/apps/dav/lib/Migration/RefreshWebcalJobRegistrar.php @@ -0,0 +1,62 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +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 { + + /** + * FixBirthdayCalendarComponent constructor. + * + * @param IDBConnection $connection + * @param IJobList $jobList + */ + public function __construct( + private IDBConnection $connection, + private IJobList $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"); + } +} diff --git a/apps/dav/lib/Migration/RegenerateBirthdayCalendars.php b/apps/dav/lib/Migration/RegenerateBirthdayCalendars.php new file mode 100644 index 00000000000..ef8e9002e9d --- /dev/null +++ b/apps/dav/lib/Migration/RegenerateBirthdayCalendars.php @@ -0,0 +1,50 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCA\DAV\BackgroundJob\RegisterRegenerateBirthdayCalendars; +use OCP\BackgroundJob\IJobList; +use OCP\IConfig; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class RegenerateBirthdayCalendars implements IRepairStep { + + /** + * @param IJobList $jobList + * @param IConfig $config + */ + public function __construct( + private IJobList $jobList, + private IConfig $config, + ) { + } + + /** + * @return string + */ + public function getName() { + return 'Regenerating birthday calendars to use new icons and fix old birthday events without year'; + } + + /** + * @param IOutput $output + */ + public function run(IOutput $output) { + // only run once + if ($this->config->getAppValue('dav', 'regeneratedBirthdayCalendarsForYearFix') === 'yes') { + $output->info('Repair step already executed'); + return; + } + + $output->info('Adding background jobs to regenerate birthday calendar'); + $this->jobList->add(RegisterRegenerateBirthdayCalendars::class); + + // if all were done, no need to redo the repair during next upgrade + $this->config->setAppValue('dav', 'regeneratedBirthdayCalendarsForYearFix', 'yes'); + } +} diff --git a/apps/dav/lib/Migration/RegisterBuildReminderIndexBackgroundJob.php b/apps/dav/lib/Migration/RegisterBuildReminderIndexBackgroundJob.php new file mode 100644 index 00000000000..7f74390f883 --- /dev/null +++ b/apps/dav/lib/Migration/RegisterBuildReminderIndexBackgroundJob.php @@ -0,0 +1,73 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCA\DAV\BackgroundJob\BuildReminderIndexBackgroundJob; +use OCP\BackgroundJob\IJobList; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +/** + * Class RegisterBuildReminderIndexBackgroundJob + * + * @package OCA\DAV\Migration + */ +class RegisterBuildReminderIndexBackgroundJob implements IRepairStep { + + /** @var string */ + private const CONFIG_KEY = 'buildCalendarReminderIndex'; + + /** + * @param IDBConnection $db + * @param IJobList $jobList + * @param IConfig $config + */ + public function __construct( + private IDBConnection $db, + private IJobList $jobList, + private IConfig $config, + ) { + } + + /** + * @return string + */ + public function getName() { + return 'Registering building of calendar reminder index as background job'; + } + + /** + * @param IOutput $output + */ + public function run(IOutput $output) { + // only run once + if ($this->config->getAppValue('dav', self::CONFIG_KEY) === 'yes') { + $output->info('Repair step already executed'); + return; + } + + $query = $this->db->getQueryBuilder(); + $query->select($query->createFunction('MAX(' . $query->getColumnName('id') . ')')) + ->from('calendarobjects'); + $result = $query->executeQuery(); + $maxId = (int)$result->fetchOne(); + $result->closeCursor(); + + $output->info('Add background job'); + $this->jobList->add(BuildReminderIndexBackgroundJob::class, [ + 'offset' => 0, + 'stopAt' => $maxId + ]); + + // if all were done, no need to redo the repair during next upgrade + $this->config->setAppValue('dav', self::CONFIG_KEY, 'yes'); + } +} diff --git a/apps/dav/lib/Migration/RegisterUpdateCalendarResourcesRoomBackgroundJob.php b/apps/dav/lib/Migration/RegisterUpdateCalendarResourcesRoomBackgroundJob.php new file mode 100644 index 00000000000..9d77aefafd2 --- /dev/null +++ b/apps/dav/lib/Migration/RegisterUpdateCalendarResourcesRoomBackgroundJob.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\DAV\Migration; + +use OCA\DAV\BackgroundJob\UpdateCalendarResourcesRoomsBackgroundJob; +use OCP\BackgroundJob\IJobList; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class RegisterUpdateCalendarResourcesRoomBackgroundJob implements IRepairStep { + public function __construct( + private readonly IJobList $jobList, + ) { + } + + public function getName() { + return 'Register a background job to update rooms and resources'; + } + + public function run(IOutput $output) { + $this->jobList->add(UpdateCalendarResourcesRoomsBackgroundJob::class); + } +} diff --git a/apps/dav/lib/Migration/RemoveClassifiedEventActivity.php b/apps/dav/lib/Migration/RemoveClassifiedEventActivity.php new file mode 100644 index 00000000000..f0d208f4f33 --- /dev/null +++ b/apps/dav/lib/Migration/RemoveClassifiedEventActivity.php @@ -0,0 +1,116 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCA\DAV\CalDAV\CalDavBackend; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class RemoveClassifiedEventActivity implements IRepairStep { + + public function __construct( + private IDBConnection $connection, + ) { + } + + /** + * @inheritdoc + */ + public function getName() { + return 'Remove activity entries of private events'; + } + + /** + * @inheritdoc + */ + public function run(IOutput $output) { + if (!$this->connection->tableExists('activity')) { + return; + } + + $deletedEvents = $this->removePrivateEventActivity(); + $deletedEvents += $this->removeConfidentialUncensoredEventActivity(); + + $output->info("Removed $deletedEvents activity entries"); + } + + protected function removePrivateEventActivity(): int { + $deletedEvents = 0; + + $delete = $this->connection->getQueryBuilder(); + $delete->delete('activity') + ->where($delete->expr()->neq('affecteduser', $delete->createParameter('owner'))) + ->andWhere($delete->expr()->eq('object_type', $delete->createParameter('type'))) + ->andWhere($delete->expr()->eq('object_id', $delete->createParameter('calendar_id'))) + ->andWhere($delete->expr()->like('subjectparams', $delete->createParameter('event_uid'))); + + $query = $this->connection->getQueryBuilder(); + $query->select('c.principaluri', 'o.calendarid', 'o.uid') + ->from('calendarobjects', 'o') + ->leftJoin('o', 'calendars', 'c', $query->expr()->eq('c.id', 'o.calendarid')) + ->where($query->expr()->eq('o.classification', $query->createNamedParameter(CalDavBackend::CLASSIFICATION_PRIVATE))); + $result = $query->executeQuery(); + + while ($row = $result->fetch()) { + if ($row['principaluri'] === null) { + continue; + } + + $delete->setParameter('owner', $this->getPrincipal($row['principaluri'])) + ->setParameter('type', 'calendar') + ->setParameter('calendar_id', $row['calendarid']) + ->setParameter('event_uid', '%' . $this->connection->escapeLikeParameter('{"id":"' . $row['uid'] . '"') . '%'); + $deletedEvents += $delete->executeStatement(); + } + $result->closeCursor(); + + return $deletedEvents; + } + + protected function removeConfidentialUncensoredEventActivity(): int { + $deletedEvents = 0; + + $delete = $this->connection->getQueryBuilder(); + $delete->delete('activity') + ->where($delete->expr()->neq('affecteduser', $delete->createParameter('owner'))) + ->andWhere($delete->expr()->eq('object_type', $delete->createParameter('type'))) + ->andWhere($delete->expr()->eq('object_id', $delete->createParameter('calendar_id'))) + ->andWhere($delete->expr()->like('subjectparams', $delete->createParameter('event_uid'))) + ->andWhere($delete->expr()->notLike('subjectparams', $delete->createParameter('filtered_name'))); + + $query = $this->connection->getQueryBuilder(); + $query->select('c.principaluri', 'o.calendarid', 'o.uid') + ->from('calendarobjects', 'o') + ->leftJoin('o', 'calendars', 'c', $query->expr()->eq('c.id', 'o.calendarid')) + ->where($query->expr()->eq('o.classification', $query->createNamedParameter(CalDavBackend::CLASSIFICATION_CONFIDENTIAL))); + $result = $query->executeQuery(); + + while ($row = $result->fetch()) { + if ($row['principaluri'] === null) { + continue; + } + + $delete->setParameter('owner', $this->getPrincipal($row['principaluri'])) + ->setParameter('type', 'calendar') + ->setParameter('calendar_id', $row['calendarid']) + ->setParameter('event_uid', '%' . $this->connection->escapeLikeParameter('{"id":"' . $row['uid'] . '"') . '%') + ->setParameter('filtered_name', '%' . $this->connection->escapeLikeParameter('{"id":"' . $row['uid'] . '","name":"Busy"') . '%'); + $deletedEvents += $delete->executeStatement(); + } + $result->closeCursor(); + + return $deletedEvents; + } + + protected function getPrincipal(string $principalUri): string { + $uri = explode('/', $principalUri); + return array_pop($uri); + } +} diff --git a/apps/dav/lib/Migration/RemoveDeletedUsersCalendarSubscriptions.php b/apps/dav/lib/Migration/RemoveDeletedUsersCalendarSubscriptions.php new file mode 100644 index 00000000000..e2b2b701e74 --- /dev/null +++ b/apps/dav/lib/Migration/RemoveDeletedUsersCalendarSubscriptions.php @@ -0,0 +1,123 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCP\DB\Exception; +use OCP\IDBConnection; +use OCP\IUserManager; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class RemoveDeletedUsersCalendarSubscriptions implements IRepairStep { + /** @var int */ + private $progress = 0; + + /** @var int[] */ + private $orphanSubscriptionIds = []; + + private const SUBSCRIPTIONS_CHUNK_SIZE = 1000; + + public function __construct( + private IDBConnection $connection, + private IUserManager $userManager, + ) { + } + + /** + * @inheritdoc + */ + public function getName(): string { + return 'Clean up old calendar subscriptions from deleted users that were not cleaned-up'; + } + + /** + * @inheritdoc + */ + public function run(IOutput $output) { + $nbSubscriptions = $this->countSubscriptions(); + + $output->startProgress($nbSubscriptions); + + while ($this->progress < $nbSubscriptions) { + $this->checkSubscriptions(); + + $this->progress += self::SUBSCRIPTIONS_CHUNK_SIZE; + $output->advance(min(self::SUBSCRIPTIONS_CHUNK_SIZE, $nbSubscriptions)); + } + $output->finishProgress(); + $this->deleteOrphanSubscriptions(); + + $output->info(sprintf('%d calendar subscriptions without an user have been cleaned up', count($this->orphanSubscriptionIds))); + } + + /** + * @throws Exception + */ + private function countSubscriptions(): int { + $qb = $this->connection->getQueryBuilder(); + $query = $qb->select($qb->func()->count('*')) + ->from('calendarsubscriptions'); + + $result = $query->execute(); + $count = $result->fetchOne(); + $result->closeCursor(); + + if ($count !== false) { + $count = (int)$count; + } else { + $count = 0; + } + + return $count; + } + + /** + * @throws Exception + */ + private function checkSubscriptions(): void { + $qb = $this->connection->getQueryBuilder(); + $query = $qb->selectDistinct(['id', 'principaluri']) + ->from('calendarsubscriptions') + ->setMaxResults(self::SUBSCRIPTIONS_CHUNK_SIZE) + ->setFirstResult($this->progress); + + $result = $query->execute(); + while ($row = $result->fetch()) { + $username = $this->getPrincipal($row['principaluri']); + if (!$this->userManager->userExists($username)) { + $this->orphanSubscriptionIds[] = (int)$row['id']; + } + } + $result->closeCursor(); + } + + /** + * @throws Exception + */ + private function deleteOrphanSubscriptions(): void { + foreach ($this->orphanSubscriptionIds as $orphanSubscriptionID) { + $this->deleteOrphanSubscription($orphanSubscriptionID); + } + } + + /** + * @throws Exception + */ + private function deleteOrphanSubscription(int $orphanSubscriptionID): void { + $qb = $this->connection->getQueryBuilder(); + $qb->delete('calendarsubscriptions') + ->where($qb->expr()->eq('id', $qb->createNamedParameter($orphanSubscriptionID))) + ->executeStatement(); + } + + private function getPrincipal(string $principalUri): string { + $uri = explode('/', $principalUri); + return array_pop($uri); + } +} diff --git a/apps/dav/lib/Migration/RemoveObjectProperties.php b/apps/dav/lib/Migration/RemoveObjectProperties.php new file mode 100644 index 00000000000..f09293ae0bb --- /dev/null +++ b/apps/dav/lib/Migration/RemoveObjectProperties.php @@ -0,0 +1,48 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\DAV\Migration; + +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class RemoveObjectProperties implements IRepairStep { + private const RESOURCE_TYPE_PROPERTY = '{DAV:}resourcetype'; + private const ME_CARD_PROPERTY = '{http://calendarserver.org/ns/}me-card'; + private const CALENDAR_TRANSP_PROPERTY = '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp'; + + /** + * RemoveObjectProperties constructor. + * + * @param IDBConnection $connection + */ + public function __construct( + private IDBConnection $connection, + ) { + } + + /** + * @inheritdoc + */ + public function getName() { + return 'Remove invalid object properties'; + } + + /** + * @inheritdoc + */ + public function run(IOutput $output) { + $query = $this->connection->getQueryBuilder(); + $updated = $query->delete('properties') + ->where($query->expr()->in('propertyname', $query->createNamedParameter([self::RESOURCE_TYPE_PROPERTY, self::ME_CARD_PROPERTY, self::CALENDAR_TRANSP_PROPERTY], IQueryBuilder::PARAM_STR_ARRAY))) + ->andWhere($query->expr()->eq('propertyvalue', $query->createNamedParameter('Object'), IQueryBuilder::PARAM_STR)) + ->executeStatement(); + + $output->info("$updated invalid object properties removed."); + } +} diff --git a/apps/dav/lib/Migration/RemoveOrphanEventsAndContacts.php b/apps/dav/lib/Migration/RemoveOrphanEventsAndContacts.php new file mode 100644 index 00000000000..143dc3cd1e6 --- /dev/null +++ b/apps/dav/lib/Migration/RemoveOrphanEventsAndContacts.php @@ -0,0 +1,52 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCA\DAV\BackgroundJob\CleanupOrphanedChildrenJob; +use OCP\BackgroundJob\IJobList; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class RemoveOrphanEventsAndContacts implements IRepairStep { + public function __construct( + private readonly IJobList $jobList, + ) { + } + + public function getName(): string { + return 'Queue jobs to clean up orphan event and contact data'; + } + + public function run(IOutput $output): void { + $this->queueJob('calendarobjects', 'calendars', 'calendarid', '%d events without a calendar have been cleaned up'); + $this->queueJob('calendarobjects_props', 'calendarobjects', 'objectid', '%d properties without an events have been cleaned up'); + $this->queueJob('calendarchanges', 'calendars', 'calendarid', '%d changes without a calendar have been cleaned up'); + + $this->queueJob('calendarobjects', 'calendarsubscriptions', 'calendarid', '%d cached events without a calendar subscription have been cleaned up'); + $this->queueJob('calendarchanges', 'calendarsubscriptions', 'calendarid', '%d changes without a calendar subscription have been cleaned up'); + + $this->queueJob('cards', 'addressbooks', 'addressbookid', '%d contacts without an addressbook have been cleaned up'); + $this->queueJob('cards_properties', 'cards', 'cardid', '%d properties without a contact have been cleaned up'); + $this->queueJob('addressbookchanges', 'addressbooks', 'addressbookid', '%d changes without an addressbook have been cleaned up'); + } + + private function queueJob( + string $childTable, + string $parentTable, + string $parentId, + string $logMessage, + ): void { + $this->jobList->add(CleanupOrphanedChildrenJob::class, [ + CleanupOrphanedChildrenJob::ARGUMENT_CHILD_TABLE => $childTable, + CleanupOrphanedChildrenJob::ARGUMENT_PARENT_TABLE => $parentTable, + CleanupOrphanedChildrenJob::ARGUMENT_PARENT_ID => $parentId, + CleanupOrphanedChildrenJob::ARGUMENT_LOG_MESSAGE => $logMessage, + ]); + } +} diff --git a/apps/dav/lib/Migration/Version1004Date20170825134824.php b/apps/dav/lib/Migration/Version1004Date20170825134824.php new file mode 100644 index 00000000000..4bf9637b697 --- /dev/null +++ b/apps/dav/lib/Migration/Version1004Date20170825134824.php @@ -0,0 +1,481 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1004Date20170825134824 extends SimpleMigrationStep { + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + * @since 13.0.0 + */ + public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + if (!$schema->hasTable('addressbooks')) { + $table = $schema->createTable('addressbooks'); + $table->addColumn('id', 'bigint', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('principaluri', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('displayname', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('uri', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('description', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('synctoken', 'integer', [ + 'notnull' => true, + 'default' => 1, + 'length' => 10, + 'unsigned' => true, + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['principaluri', 'uri'], 'addressbook_index'); + } + + if (!$schema->hasTable('cards')) { + $table = $schema->createTable('cards'); + $table->addColumn('id', 'bigint', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('addressbookid', 'integer', [ + 'notnull' => true, + 'default' => 0, + ]); + $table->addColumn('carddata', 'blob', [ + 'notnull' => false, + ]); + $table->addColumn('uri', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('lastmodified', 'bigint', [ + 'notnull' => false, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('etag', 'string', [ + 'notnull' => false, + 'length' => 32, + ]); + $table->addColumn('size', 'bigint', [ + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->setPrimaryKey(['id']); + } + + if (!$schema->hasTable('addressbookchanges')) { + $table = $schema->createTable('addressbookchanges'); + $table->addColumn('id', 'bigint', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('uri', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('synctoken', 'integer', [ + 'notnull' => true, + 'default' => 1, + 'length' => 10, + 'unsigned' => true, + ]); + $table->addColumn('addressbookid', 'integer', [ + 'notnull' => true, + ]); + $table->addColumn('operation', 'smallint', [ + 'notnull' => true, + 'length' => 1, + ]); + $table->setPrimaryKey(['id']); + $table->addIndex(['addressbookid', 'synctoken'], 'addressbookid_synctoken'); + } + + if (!$schema->hasTable('calendarobjects')) { + $table = $schema->createTable('calendarobjects'); + $table->addColumn('id', 'bigint', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('calendardata', 'blob', [ + 'notnull' => false, + ]); + $table->addColumn('uri', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('calendarid', 'integer', [ + 'notnull' => true, + 'length' => 10, + 'unsigned' => true, + ]); + $table->addColumn('lastmodified', 'integer', [ + 'notnull' => false, + 'length' => 10, + 'unsigned' => true, + ]); + $table->addColumn('etag', 'string', [ + 'notnull' => false, + 'length' => 32, + ]); + $table->addColumn('size', 'bigint', [ + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('componenttype', 'string', [ + 'notnull' => false, + 'length' => 8, + ]); + $table->addColumn('firstoccurence', 'bigint', [ + 'notnull' => false, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('lastoccurence', 'bigint', [ + 'notnull' => false, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('uid', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('classification', 'integer', [ + 'notnull' => false, + 'default' => 0, + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['calendarid', 'uri'], 'calobjects_index'); + } + + if (!$schema->hasTable('calendars')) { + $table = $schema->createTable('calendars'); + $table->addColumn('id', 'bigint', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('principaluri', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('displayname', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('uri', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('synctoken', 'integer', [ + 'notnull' => true, + 'default' => 1, + 'unsigned' => true, + ]); + $table->addColumn('description', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('calendarorder', 'integer', [ + 'notnull' => true, + 'default' => 0, + 'unsigned' => true, + ]); + $table->addColumn('calendarcolor', 'string', [ + 'notnull' => false, + ]); + $table->addColumn('timezone', 'text', [ + 'notnull' => false, + ]); + $table->addColumn('components', 'string', [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('transparent', 'smallint', [ + 'notnull' => true, + 'length' => 1, + 'default' => 0, + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['principaluri', 'uri'], 'calendars_index'); + } else { + $table = $schema->getTable('calendars'); + $table->changeColumn('components', [ + 'notnull' => false, + 'length' => 64, + ]); + } + + if (!$schema->hasTable('calendarchanges')) { + $table = $schema->createTable('calendarchanges'); + $table->addColumn('id', 'bigint', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('uri', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('synctoken', 'integer', [ + 'notnull' => true, + 'default' => 1, + 'length' => 10, + 'unsigned' => true, + ]); + $table->addColumn('calendarid', 'integer', [ + 'notnull' => true, + ]); + $table->addColumn('operation', 'smallint', [ + 'notnull' => true, + 'length' => 1, + ]); + $table->setPrimaryKey(['id']); + $table->addIndex(['calendarid', 'synctoken'], 'calendarid_synctoken'); + } + + if (!$schema->hasTable('calendarsubscriptions')) { + $table = $schema->createTable('calendarsubscriptions'); + $table->addColumn('id', 'bigint', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('uri', 'string', [ + 'notnull' => false, + ]); + $table->addColumn('principaluri', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('source', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('displayname', 'string', [ + 'notnull' => false, + 'length' => 100, + ]); + $table->addColumn('refreshrate', 'string', [ + 'notnull' => false, + 'length' => 10, + ]); + $table->addColumn('calendarorder', 'integer', [ + 'notnull' => true, + 'default' => 0, + 'unsigned' => true, + ]); + $table->addColumn('calendarcolor', 'string', [ + 'notnull' => false, + ]); + $table->addColumn('striptodos', 'smallint', [ + 'notnull' => false, + 'length' => 1, + ]); + $table->addColumn('stripalarms', 'smallint', [ + 'notnull' => false, + 'length' => 1, + ]); + $table->addColumn('stripattachments', 'smallint', [ + 'notnull' => false, + 'length' => 1, + ]); + $table->addColumn('lastmodified', 'integer', [ + 'notnull' => false, + 'unsigned' => true, + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['principaluri', 'uri'], 'calsub_index'); + } else { + $table = $schema->getTable('calendarsubscriptions'); + $table->changeColumn('lastmodified', [ + 'notnull' => false, + 'unsigned' => true, + ]); + } + + if (!$schema->hasTable('schedulingobjects')) { + $table = $schema->createTable('schedulingobjects'); + $table->addColumn('id', 'bigint', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('principaluri', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('calendardata', 'blob', [ + 'notnull' => false, + ]); + $table->addColumn('uri', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('lastmodified', 'integer', [ + 'notnull' => false, + 'unsigned' => true, + ]); + $table->addColumn('etag', 'string', [ + 'notnull' => false, + 'length' => 32, + ]); + $table->addColumn('size', 'bigint', [ + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->setPrimaryKey(['id']); + $table->addIndex(['principaluri'], 'schedulobj_principuri_index'); + $table->addIndex(['lastmodified'], 'schedulobj_lastmodified_idx'); + } + + if (!$schema->hasTable('cards_properties')) { + $table = $schema->createTable('cards_properties'); + $table->addColumn('id', 'bigint', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('addressbookid', 'bigint', [ + 'notnull' => true, + 'length' => 11, + 'default' => 0, + ]); + $table->addColumn('cardid', 'bigint', [ + 'notnull' => true, + 'length' => 11, + 'default' => 0, + 'unsigned' => true, + ]); + $table->addColumn('name', 'string', [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('value', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('preferred', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 1, + ]); + $table->setPrimaryKey(['id']); + $table->addIndex(['cardid'], 'card_contactid_index'); + $table->addIndex(['name'], 'card_name_index'); + $table->addIndex(['value'], 'card_value_index'); + } + + if (!$schema->hasTable('calendarobjects_props')) { + $table = $schema->createTable('calendarobjects_props'); + $table->addColumn('id', 'bigint', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('calendarid', 'bigint', [ + 'notnull' => true, + 'length' => 11, + 'default' => 0, + ]); + $table->addColumn('objectid', 'bigint', [ + 'notnull' => true, + 'length' => 11, + 'default' => 0, + 'unsigned' => true, + ]); + $table->addColumn('name', 'string', [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('parameter', 'string', [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('value', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->setPrimaryKey(['id']); + $table->addIndex(['objectid'], 'calendarobject_index'); + $table->addIndex(['name'], 'calendarobject_name_index'); + $table->addIndex(['value'], 'calendarobject_value_index'); + } + + if (!$schema->hasTable('dav_shares')) { + $table = $schema->createTable('dav_shares'); + $table->addColumn('id', 'bigint', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('principaluri', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('type', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('access', 'smallint', [ + 'notnull' => false, + 'length' => 1, + ]); + $table->addColumn('resourceid', 'integer', [ + 'notnull' => true, + 'unsigned' => true, + ]); + $table->addColumn('publicuri', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['principaluri', 'resourceid', 'type', 'publicuri'], 'dav_shares_index'); + // modified on 2024-6-21 to add performance improving indices on new instances + $table->addIndex(['resourceid', 'type'], 'dav_shares_resourceid_type'); + $table->addIndex(['resourceid', 'access'], 'dav_shares_resourceid_access'); + } + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1004Date20170919104507.php b/apps/dav/lib/Migration/Version1004Date20170919104507.php new file mode 100644 index 00000000000..678d92d2b83 --- /dev/null +++ b/apps/dav/lib/Migration/Version1004Date20170919104507.php @@ -0,0 +1,40 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1004Date20170919104507 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + * @since 13.0.0 + */ + public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $table = $schema->getTable('addressbooks'); + $column = $table->getColumn('id'); + $column->setUnsigned(true); + + $table = $schema->getTable('calendarobjects'); + $column = $table->getColumn('id'); + $column->setUnsigned(true); + + $table = $schema->getTable('calendarchanges'); + $column = $table->getColumn('id'); + $column->setUnsigned(true); + + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1004Date20170924124212.php b/apps/dav/lib/Migration/Version1004Date20170924124212.php new file mode 100644 index 00000000000..4d221e91132 --- /dev/null +++ b/apps/dav/lib/Migration/Version1004Date20170924124212.php @@ -0,0 +1,39 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1004Date20170924124212 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + * @since 13.0.0 + */ + public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $table = $schema->getTable('cards'); + // Dropped in Version1030Date20240205103243 because cards_abid is redundant with cards_abiduri + // $table->addIndex(['addressbookid'], 'cards_abid'); + $table->addIndex(['addressbookid', 'uri'], 'cards_abiduri'); + + $table = $schema->getTable('cards_properties'); + // Removed later on + // $table->addIndex(['addressbookid'], 'cards_prop_abid'); + // Added later on + $table->addIndex(['addressbookid', 'name', 'value'], 'cards_prop_abid_name_value', ); + + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1004Date20170926103422.php b/apps/dav/lib/Migration/Version1004Date20170926103422.php new file mode 100644 index 00000000000..ec56e035006 --- /dev/null +++ b/apps/dav/lib/Migration/Version1004Date20170926103422.php @@ -0,0 +1,36 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCP\Migration\BigIntMigration; + +/** + * Auto-generated migration step: Please modify to your needs! + */ +class Version1004Date20170926103422 extends BigIntMigration { + + /** + * @return array Returns an array with the following structure + * ['table1' => ['column1', 'column2'], ...] + * @since 13.0.0 + */ + protected function getColumnsByTable() { + return [ + 'addressbooks' => ['id'], + 'addressbookchanges' => ['id', 'addressbookid'], + 'calendars' => ['id'], + 'calendarchanges' => ['id', 'calendarid'], + 'calendarobjects' => ['id', 'calendarid'], + 'calendarobjects_props' => ['id', 'calendarid', 'objectid'], + 'calendarsubscriptions' => ['id'], + 'cards' => ['id', 'addressbookid'], + 'cards_properties' => ['id', 'addressbookid', 'cardid'], + 'dav_shares' => ['id', 'resourceid'], + 'schedulingobjects' => ['id'], + ]; + } +} diff --git a/apps/dav/lib/Migration/Version1005Date20180413093149.php b/apps/dav/lib/Migration/Version1005Date20180413093149.php new file mode 100644 index 00000000000..db071c65d98 --- /dev/null +++ b/apps/dav/lib/Migration/Version1005Date20180413093149.php @@ -0,0 +1,64 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1005Date20180413093149 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('directlink')) { + $table = $schema->createTable('directlink'); + + $table->addColumn('id', Types::BIGINT, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('user_id', Types::STRING, [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('file_id', Types::BIGINT, [ + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('token', Types::STRING, [ + 'notnull' => false, + 'length' => 60, + ]); + $table->addColumn('expiration', Types::BIGINT, [ + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + + $table->setPrimaryKey(['id'], 'directlink_id_idx'); + $table->addIndex(['token'], 'directlink_token_idx'); + $table->addIndex(['expiration'], 'directlink_expiration_idx'); + + return $schema; + } + } +} diff --git a/apps/dav/lib/Migration/Version1005Date20180530124431.php b/apps/dav/lib/Migration/Version1005Date20180530124431.php new file mode 100644 index 00000000000..b5f9ff26962 --- /dev/null +++ b/apps/dav/lib/Migration/Version1005Date20180530124431.php @@ -0,0 +1,68 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1005Date20180530124431 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + * @since 13.0.0 + */ + public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $types = ['resources', 'rooms']; + foreach ($types as $type) { + if (!$schema->hasTable('calendar_' . $type)) { + $table = $schema->createTable('calendar_' . $type); + + $table->addColumn('id', Types::BIGINT, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('backend_id', Types::STRING, [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('resource_id', Types::STRING, [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('email', Types::STRING, [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('displayname', Types::STRING, [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('group_restrictions', Types::STRING, [ + 'notnull' => false, + 'length' => 4000, + ]); + + $table->setPrimaryKey(['id']); + $table->addIndex(['backend_id', 'resource_id'], 'calendar_' . $type . '_bkdrsc'); + $table->addIndex(['email'], 'calendar_' . $type . '_email'); + $table->addIndex(['displayname'], 'calendar_' . $type . '_name'); + } + } + + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1006Date20180619154313.php b/apps/dav/lib/Migration/Version1006Date20180619154313.php new file mode 100644 index 00000000000..231861a68c4 --- /dev/null +++ b/apps/dav/lib/Migration/Version1006Date20180619154313.php @@ -0,0 +1,76 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Auto-generated migration step: Please modify to your needs! + */ +class Version1006Date20180619154313 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + * @since 13.0.0 + */ + public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + if (!$schema->hasTable('calendar_invitations')) { + $table = $schema->createTable('calendar_invitations'); + + $table->addColumn('id', Types::BIGINT, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('uid', Types::STRING, [ + 'notnull' => true, + 'length' => 255, + ]); + $table->addColumn('recurrenceid', Types::STRING, [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('attendee', Types::STRING, [ + 'notnull' => true, + 'length' => 255, + ]); + $table->addColumn('organizer', Types::STRING, [ + 'notnull' => true, + 'length' => 255, + ]); + $table->addColumn('sequence', Types::BIGINT, [ + 'notnull' => false, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('token', Types::STRING, [ + 'notnull' => true, + 'length' => 60, + ]); + $table->addColumn('expiration', Types::BIGINT, [ + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + + $table->setPrimaryKey(['id']); + $table->addIndex(['token'], 'calendar_invitation_tokens'); + + return $schema; + } + } +} diff --git a/apps/dav/lib/Migration/Version1006Date20180628111625.php b/apps/dav/lib/Migration/Version1006Date20180628111625.php new file mode 100644 index 00000000000..f4be26e6ad0 --- /dev/null +++ b/apps/dav/lib/Migration/Version1006Date20180628111625.php @@ -0,0 +1,91 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +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', Types::INTEGER, [ + 'notnull' => true, + 'default' => 0, + ]); + + if ($calendarChangesTable->hasIndex('calendarid_synctoken')) { + $calendarChangesTable->dropIndex('calendarid_synctoken'); + } + $calendarChangesTable->addIndex(['calendarid', 'calendartype', 'synctoken'], 'calid_type_synctoken'); + } + + if ($schema->hasTable('calendarobjects')) { + $calendarObjectsTable = $schema->getTable('calendarobjects'); + $calendarObjectsTable->addColumn('calendartype', Types::INTEGER, [ + 'notnull' => true, + 'default' => 0, + ]); + + if ($calendarObjectsTable->hasIndex('calobjects_index')) { + $calendarObjectsTable->dropIndex('calobjects_index'); + } + $calendarObjectsTable->addUniqueIndex(['calendarid', 'calendartype', 'uri'], 'calobjects_index'); + $calendarObjectsTable->addUniqueIndex(['calendarid', 'calendartype', 'uid'], 'calobjects_by_uid_index'); + } + + if ($schema->hasTable('calendarobjects_props')) { + $calendarObjectsPropsTable = $schema->getTable('calendarobjects_props'); + $calendarObjectsPropsTable->addColumn('calendartype', Types::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'); + $calendarObjectsPropsTable->addIndex(['calendarid', 'calendartype'], 'calendarobject_calid_index'); + } + + if ($schema->hasTable('calendarsubscriptions')) { + $calendarSubscriptionsTable = $schema->getTable('calendarsubscriptions'); + $calendarSubscriptionsTable->addColumn('synctoken', 'integer', [ + 'notnull' => true, + 'default' => 1, + 'length' => 10, + 'unsigned' => true, + ]); + } + + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1008Date20181030113700.php b/apps/dav/lib/Migration/Version1008Date20181030113700.php new file mode 100644 index 00000000000..d2354a185df --- /dev/null +++ b/apps/dav/lib/Migration/Version1008Date20181030113700.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use Closure; + +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1008Date20181030113700 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(); + + $table = $schema->getTable('cards'); + $table->addColumn('uid', Types::STRING, [ + 'notnull' => false, + 'length' => 255 + ]); + + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1008Date20181105104826.php b/apps/dav/lib/Migration/Version1008Date20181105104826.php new file mode 100644 index 00000000000..82612307cbb --- /dev/null +++ b/apps/dav/lib/Migration/Version1008Date20181105104826.php @@ -0,0 +1,60 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1008Date20181105104826 extends SimpleMigrationStep { + + /** + * Version1008Date20181105104826 constructor. + * + * @param IDBConnection $connection + */ + public function __construct( + private IDBConnection $connection, + ) { + } + + /** + * @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(); + $table = $schema->getTable('calendarsubscriptions'); + + $table->addColumn('source_copy', Types::TEXT, [ + 'notnull' => false, + 'length' => null, + ]); + + return $schema; + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + */ + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { + $qb = $this->connection->getQueryBuilder(); + $qb->update('calendarsubscriptions') + ->set('source_copy', 'source') + ->execute(); + } +} diff --git a/apps/dav/lib/Migration/Version1008Date20181105104833.php b/apps/dav/lib/Migration/Version1008Date20181105104833.php new file mode 100644 index 00000000000..3d4094d8072 --- /dev/null +++ b/apps/dav/lib/Migration/Version1008Date20181105104833.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1008Date20181105104833 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(); + $table = $schema->getTable('calendarsubscriptions'); + $table->dropColumn('source'); + + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1008Date20181105110300.php b/apps/dav/lib/Migration/Version1008Date20181105110300.php new file mode 100644 index 00000000000..72e8dee1bf8 --- /dev/null +++ b/apps/dav/lib/Migration/Version1008Date20181105110300.php @@ -0,0 +1,59 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1008Date20181105110300 extends SimpleMigrationStep { + + /** + * Version1008Date20181105110300 constructor. + * + * @param IDBConnection $connection + */ + public function __construct( + private IDBConnection $connection, + ) { + } + + /** + * @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(); + $table = $schema->getTable('calendarsubscriptions'); + $table->addColumn('source', Types::TEXT, [ + 'notnull' => false, + 'length' => null, + ]); + + return $schema; + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + */ + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { + $qb = $this->connection->getQueryBuilder(); + $qb->update('calendarsubscriptions') + ->set('source', 'source_copy') + ->execute(); + } +} diff --git a/apps/dav/lib/Migration/Version1008Date20181105112049.php b/apps/dav/lib/Migration/Version1008Date20181105112049.php new file mode 100644 index 00000000000..eb18eacb0b1 --- /dev/null +++ b/apps/dav/lib/Migration/Version1008Date20181105112049.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1008Date20181105112049 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(); + $table = $schema->getTable('calendarsubscriptions'); + $table->dropColumn('source_copy'); + + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1008Date20181114084440.php b/apps/dav/lib/Migration/Version1008Date20181114084440.php new file mode 100644 index 00000000000..3718f16f54a --- /dev/null +++ b/apps/dav/lib/Migration/Version1008Date20181114084440.php @@ -0,0 +1,42 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1008Date20181114084440 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'); + if ($calendarChangesTable->hasIndex('calendarid_calendartype_synctoken')) { + $calendarChangesTable->dropIndex('calendarid_calendartype_synctoken'); + } + + if (!$calendarChangesTable->hasIndex('calid_type_synctoken')) { + $calendarChangesTable->addIndex(['calendarid', 'calendartype', 'synctoken'], 'calid_type_synctoken'); + } + } + + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1011Date20190725113607.php b/apps/dav/lib/Migration/Version1011Date20190725113607.php new file mode 100644 index 00000000000..4524dca9c83 --- /dev/null +++ b/apps/dav/lib/Migration/Version1011Date20190725113607.php @@ -0,0 +1,72 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Auto-generated migration step: Please modify to your needs! + */ +class Version1011Date20190725113607 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + * @since 13.0.0 + */ + public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $types = ['resource', 'room']; + foreach ($types as $type) { + if (!$schema->hasTable($this->getMetadataTableName($type))) { + $table = $schema->createTable($this->getMetadataTableName($type)); + + $table->addColumn('id', Types::BIGINT, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn($type . '_id', Types::BIGINT, [ + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('key', Types::STRING, [ + 'notnull' => true, + 'length' => 255, + ]); + $table->addColumn('value', Types::STRING, [ + 'notnull' => false, + 'length' => 4000, + ]); + + $table->setPrimaryKey(['id']); + $table->addIndex([$type . '_id', 'key'], $this->getMetadataTableName($type) . '_idk'); + } + } + + return $schema; + } + + /** + * @param string $type + * @return string + */ + private function getMetadataTableName(string $type):string { + return 'calendar_' . $type . 's_md'; + } +} diff --git a/apps/dav/lib/Migration/Version1011Date20190806104428.php b/apps/dav/lib/Migration/Version1011Date20190806104428.php new file mode 100644 index 00000000000..183dcd4bf1e --- /dev/null +++ b/apps/dav/lib/Migration/Version1011Date20190806104428.php @@ -0,0 +1,58 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Auto-generated migration step: Please modify to your needs! + */ +class Version1011Date20190806104428 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(); + + $table = $schema->createTable('dav_cal_proxy'); + $table->addColumn('id', Types::BIGINT, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('owner_id', Types::STRING, [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('proxy_id', Types::STRING, [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('permissions', Types::INTEGER, [ + 'notnull' => false, + 'length' => 4, + 'unsigned' => true, + ]); + + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['owner_id', 'proxy_id', 'permissions'], 'dav_cal_proxy_uidx'); + $table->addIndex(['proxy_id'], 'dav_cal_proxy_ipid'); + + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1012Date20190808122342.php b/apps/dav/lib/Migration/Version1012Date20190808122342.php new file mode 100644 index 00000000000..717bcbc1119 --- /dev/null +++ b/apps/dav/lib/Migration/Version1012Date20190808122342.php @@ -0,0 +1,103 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Auto-generated migration step: Please modify to your needs! + */ +class Version1012Date20190808122342 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + * @since 17.0.0 + */ + public function changeSchema(IOutput $output, + \Closure $schemaClosure, + array $options):?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + if (!$schema->hasTable('calendar_reminders')) { + $table = $schema->createTable('calendar_reminders'); + + $table->addColumn('id', Types::BIGINT, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('calendar_id', Types::BIGINT, [ + 'notnull' => true, + 'length' => 11, + ]); + $table->addColumn('object_id', Types::BIGINT, [ + 'notnull' => true, + 'length' => 11, + ]); + $table->addColumn('is_recurring', Types::SMALLINT, [ + 'notnull' => false, + 'length' => 1, + ]); + $table->addColumn('uid', Types::STRING, [ + 'notnull' => true, + 'length' => 255, + ]); + $table->addColumn('recurrence_id', Types::BIGINT, [ + 'notnull' => false, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('is_recurrence_exception', Types::SMALLINT, [ + 'notnull' => true, + 'length' => 1, + ]); + $table->addColumn('event_hash', Types::STRING, [ + 'notnull' => true, + 'length' => 255, + ]); + $table->addColumn('alarm_hash', Types::STRING, [ + 'notnull' => true, + 'length' => 255, + ]); + $table->addColumn('type', Types::STRING, [ + 'notnull' => true, + 'length' => 255, + ]); + $table->addColumn('is_relative', Types::SMALLINT, [ + 'notnull' => true, + 'length' => 1, + ]); + $table->addColumn('notification_date', Types::BIGINT, [ + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ]); + $table->addColumn('is_repeat_based', Types::SMALLINT, [ + 'notnull' => true, + 'length' => 1, + ]); + + $table->setPrimaryKey(['id']); + $table->addIndex(['object_id'], 'calendar_reminder_objid'); + $table->addIndex(['uid', 'recurrence_id'], 'calendar_reminder_uidrec'); + + return $schema; + } + + return null; + } +} diff --git a/apps/dav/lib/Migration/Version1016Date20201109085907.php b/apps/dav/lib/Migration/Version1016Date20201109085907.php new file mode 100644 index 00000000000..f0f4b8b77c1 --- /dev/null +++ b/apps/dav/lib/Migration/Version1016Date20201109085907.php @@ -0,0 +1,43 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1016Date20201109085907 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): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $result = $this->ensureColumnIsNullable($schema, 'calendar_reminders', 'is_recurring'); + + return $result ? $schema : null; + } + + protected function ensureColumnIsNullable(ISchemaWrapper $schema, string $tableName, string $columnName): bool { + $table = $schema->getTable($tableName); + $column = $table->getColumn($columnName); + + if ($column->getNotnull()) { + $column->setNotnull(false); + return true; + } + + return false; + } +} diff --git a/apps/dav/lib/Migration/Version1017Date20210216083742.php b/apps/dav/lib/Migration/Version1017Date20210216083742.php new file mode 100644 index 00000000000..43bece200b8 --- /dev/null +++ b/apps/dav/lib/Migration/Version1017Date20210216083742.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Auto-generated migration step: Please modify to your needs! + */ +class Version1017Date20210216083742 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): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $table = $schema->getTable('dav_cal_proxy'); + if ($table->hasIndex('dav_cal_proxy_ioid')) { + $table->dropIndex('dav_cal_proxy_ioid'); + } + + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1018Date20210312100735.php b/apps/dav/lib/Migration/Version1018Date20210312100735.php new file mode 100644 index 00000000000..8199d3e9cd2 --- /dev/null +++ b/apps/dav/lib/Migration/Version1018Date20210312100735.php @@ -0,0 +1,49 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1018Date20210312100735 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $calendarsTable = $schema->getTable('calendars'); + $calendarsTable->addColumn('deleted_at', Types::INTEGER, [ + 'notnull' => false, + 'length' => 4, + 'unsigned' => true, + ]); + $calendarsTable->addIndex([ + 'principaluri', + 'deleted_at', + ], 'cals_princ_del_idx'); + + $calendarObjectsTable = $schema->getTable('calendarobjects'); + $calendarObjectsTable->addColumn('deleted_at', Types::INTEGER, [ + 'notnull' => false, + 'length' => 4, + 'unsigned' => true, + ]); + + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1024Date20211221144219.php b/apps/dav/lib/Migration/Version1024Date20211221144219.php new file mode 100644 index 00000000000..656a50809cd --- /dev/null +++ b/apps/dav/lib/Migration/Version1024Date20211221144219.php @@ -0,0 +1,61 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\DAV\Migration; + +use Closure; +use Doctrine\DBAL\Schema\SchemaException; +use OCA\DAV\DAV\CustomPropertiesBackend; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Auto-generated migration step: Please modify to your needs! + */ +class Version1024Date20211221144219 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + */ + public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + * @throws SchemaException + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + $propertiesTable = $schema->getTable('properties'); + + if ($propertiesTable->hasColumn('valuetype')) { + return null; + } + $propertiesTable->addColumn('valuetype', Types::SMALLINT, [ + 'notnull' => false, + 'default' => CustomPropertiesBackend::PROPERTY_TYPE_STRING + ]); + + return $schema; + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + */ + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + } +} diff --git a/apps/dav/lib/Migration/Version1025Date20240308063933.php b/apps/dav/lib/Migration/Version1025Date20240308063933.php new file mode 100644 index 00000000000..d84acf8fea9 --- /dev/null +++ b/apps/dav/lib/Migration/Version1025Date20240308063933.php @@ -0,0 +1,91 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\DAV\Migration; + +use Closure; +use OCP\AppFramework\Services\IAppConfig; +use OCP\DB\ISchemaWrapper; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\DB\Types; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1025Date20240308063933 extends SimpleMigrationStep { + + public function __construct( + private IAppConfig $appConfig, + private IDBConnection $db, + ) { + } + + /** + * @param IOutput $output + * @param Closure(): ISchemaWrapper $schemaClosure + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + foreach (['addressbookchanges', 'calendarchanges'] as $tableName) { + $table = $schema->getTable($tableName); + if (!$table->hasColumn('created_at')) { + $table->addColumn('created_at', Types::INTEGER, [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + } + } + + return $schema; + } + + public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options): void { + // The threshold is higher than the default of \OCA\DAV\BackgroundJob\PruneOutdatedSyncTokensJob + // but small enough to fit into a cluster transaction size. + // For a 50k users instance that would still keep 10 changes on average. + $limit = max(1, (int)$this->appConfig->getAppValue('totalNumberOfSyncTokensToKeep', '500000')); + + foreach (['addressbookchanges', 'calendarchanges'] as $tableName) { + $thresholdSelect = $this->db->getQueryBuilder(); + $thresholdSelect->select('id') + ->from($tableName) + ->orderBy('id', 'desc') + ->setFirstResult($limit) + ->setMaxResults(1); + $oldestIdResult = $thresholdSelect->executeQuery(); + $oldestId = $oldestIdResult->fetchColumn(); + $oldestIdResult->closeCursor(); + + $qb = $this->db->getQueryBuilder(); + + $update = $qb->update($tableName) + ->set('created_at', $qb->createNamedParameter(time(), IQueryBuilder::PARAM_INT)) + ->where( + $qb->expr()->eq('created_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)), + ); + + // If there is a lot of data we only set timestamp for the most recent rows + // because the rest will be deleted by \OCA\DAV\BackgroundJob\PruneOutdatedSyncTokensJob + // anyway. + if ($oldestId !== false) { + $update->andWhere($qb->expr()->gt('id', $qb->createNamedParameter($oldestId, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT)); + } + + $updated = $update->executeStatement(); + + $output->debug('Added a default creation timestamp to ' . $updated . ' rows in ' . $tableName); + } + } + +} diff --git a/apps/dav/lib/Migration/Version1027Date20230504122946.php b/apps/dav/lib/Migration/Version1027Date20230504122946.php new file mode 100644 index 00000000000..89c192a8419 --- /dev/null +++ b/apps/dav/lib/Migration/Version1027Date20230504122946.php @@ -0,0 +1,53 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\DAV\Migration; + +use Closure; +use OCA\DAV\CardDAV\SyncService; +use OCP\DB\ISchemaWrapper; +use OCP\IConfig; +use OCP\IUserManager; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; +use Psr\Log\LoggerInterface; +use Throwable; + +class Version1027Date20230504122946 extends SimpleMigrationStep { + public function __construct( + private SyncService $syncService, + private LoggerInterface $logger, + private IUserManager $userManager, + private IConfig $config, + ) { + } + /** + * @param IOutput $output + * @param Closure(): ISchemaWrapper $schemaClosure + * @param array $options + */ + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + if ($this->userManager->countSeenUsers() > 100 || $this->userManager->countUsersTotal(100) >= 100) { + $this->config->setAppValue('dav', 'needs_system_address_book_sync', 'yes'); + $output->info('Could not sync system address books during update - too many user records have been found. Please call occ dav:sync-system-addressbook manually.'); + return; + } + + try { + $this->syncService->syncInstance(); + $this->config->setAppValue('dav', 'needs_system_address_book_sync', 'no'); + } catch (Throwable $e) { + $this->config->setAppValue('dav', 'needs_system_address_book_sync', 'yes'); + $this->logger->error('Could not sync system address books during update', [ + 'exception' => $e, + ]); + $output->warning('System address book sync failed. See logs for details'); + } + } +} diff --git a/apps/dav/lib/Migration/Version1029Date20221114151721.php b/apps/dav/lib/Migration/Version1029Date20221114151721.php new file mode 100644 index 00000000000..dba5e0b1a48 --- /dev/null +++ b/apps/dav/lib/Migration/Version1029Date20221114151721.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\DAV\Migration; + +use Closure; +use Doctrine\DBAL\Schema\SchemaException; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1029Date20221114151721 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + * @throws SchemaException + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + $calendarObjectsTable = $schema->getTable('calendarobjects'); + if (!$calendarObjectsTable->hasIndex('calobj_clssfction_index')) { + $calendarObjectsTable->addIndex(['classification'], 'calobj_clssfction_index'); + return $schema; + } + return null; + } + +} diff --git a/apps/dav/lib/Migration/Version1029Date20231004091403.php b/apps/dav/lib/Migration/Version1029Date20231004091403.php new file mode 100644 index 00000000000..1dcbf9c5dfc --- /dev/null +++ b/apps/dav/lib/Migration/Version1029Date20231004091403.php @@ -0,0 +1,66 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\DAV\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1029Date20231004091403 extends SimpleMigrationStep { + /** + * @param IOutput $output + * @param Closure(): ISchemaWrapper $schemaClosure + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + if (!$schema->hasTable('dav_absence')) { + $table = $schema->createTable('dav_absence'); + $table->addColumn('id', Types::INTEGER, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('user_id', Types::STRING, [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('first_day', Types::STRING, [ + 'length' => 10, + 'notnull' => true, + ]); + $table->addColumn('last_day', Types::STRING, [ + 'length' => 10, + 'notnull' => true, + ]); + $table->addColumn('status', Types::STRING, [ + 'length' => 100, + 'notnull' => true, + ]); + $table->addColumn('message', Types::TEXT, [ + 'notnull' => true, + ]); + $table->addUniqueIndex(['user_id'], 'dav_absence_uid_idx'); + } else { + $table = $schema->getTable('dav_absence'); + } + + if ($table->getPrimaryKey() === null) { + $table->setPrimaryKey(['id'], 'dav_absence_id_idx'); + } + + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1030Date20240205103243.php b/apps/dav/lib/Migration/Version1030Date20240205103243.php new file mode 100644 index 00000000000..72cbcafc444 --- /dev/null +++ b/apps/dav/lib/Migration/Version1030Date20240205103243.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\DAV\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1030Date20240205103243 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param Closure(): ISchemaWrapper $schemaClosure + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $tableCards = $schema->getTable('cards'); + + if ($tableCards->hasIndex('cards_abiduri') && $tableCards->hasIndex('cards_abid')) { + $tableCards->dropIndex('cards_abid'); + } + + return $schema; + } +} diff --git a/apps/dav/lib/Migration/Version1031Date20240610134258.php b/apps/dav/lib/Migration/Version1031Date20240610134258.php new file mode 100644 index 00000000000..c1242ceb7db --- /dev/null +++ b/apps/dav/lib/Migration/Version1031Date20240610134258.php @@ -0,0 +1,48 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\DAV\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\Attributes\AddColumn; +use OCP\Migration\Attributes\ColumnType; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +#[AddColumn(table: 'dav_absence', name: 'replacement_user_id', type: ColumnType::STRING)] +#[AddColumn(table: 'dav_absence', name: 'replacement_user_display_name', type: ColumnType::STRING)] +class Version1031Date20240610134258 extends SimpleMigrationStep { + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $tableDavAbsence = $schema->getTable('dav_absence'); + + if (!$tableDavAbsence->hasColumn('replacement_user_id')) { + $tableDavAbsence->addColumn('replacement_user_id', Types::STRING, [ + 'notnull' => false, + 'default' => '', + 'length' => 64, + ]); + } + + if (!$tableDavAbsence->hasColumn('replacement_user_display_name')) { + $tableDavAbsence->addColumn('replacement_user_display_name', Types::STRING, [ + 'notnull' => false, + 'default' => '', + 'length' => 64, + ]); + } + + return $schema; + } + +} diff --git a/apps/dav/lib/Migration/Version1034Date20250813093701.php b/apps/dav/lib/Migration/Version1034Date20250813093701.php new file mode 100644 index 00000000000..10be71f067b --- /dev/null +++ b/apps/dav/lib/Migration/Version1034Date20250813093701.php @@ -0,0 +1,53 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\DAV\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; +use Override; + +class Version1034Date20250813093701 extends SimpleMigrationStep { + public function __construct( + private IDBConnection $db, + ) { + } + + /** + * @param IOutput $output + * @param Closure(): ISchemaWrapper $schemaClosure + * @param array $options + */ + #[Override] + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + $qb = $this->db->getQueryBuilder(); + $qb->delete('properties') + ->where($qb->expr()->eq( + 'propertyname', + $qb->createNamedParameter( + '{http://owncloud.org/ns}calendar-enabled', + IQueryBuilder::PARAM_STR, + ), + IQueryBuilder::PARAM_STR, + )) + ->andWhere($qb->expr()->eq( + 'propertyvalue', + $qb->createNamedParameter( + '1', + IQueryBuilder::PARAM_STR, + ), + IQueryBuilder::PARAM_STR, + )) + ->executeStatement(); + } +} |