diff --git a/apps/dav/appinfo/info.xml b/apps/dav/appinfo/info.xml index 684feb89c2d..2d9f73b3f43 100644 --- a/apps/dav/appinfo/info.xml +++ b/apps/dav/appinfo/info.xml @@ -24,6 +24,7 @@ OCA\DAV\Migration\FixBirthdayCalendarComponent OCA\DAV\Migration\CalDAVRemoveEmptyValue + OCA\DAV\Migration\BuildCalendarSearchIndex diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index 4a652b16054..40155341e51 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -1968,7 +1968,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription * @param string $objectUri * @param string $calendarData */ - protected function updateProperties($calendarId, $objectUri, $calendarData) { + public function updateProperties($calendarId, $objectUri, $calendarData) { $objectId = $this->getCalendarObjectId($calendarId, $objectUri); $vCalendar = $this->readCalendarData($calendarData); diff --git a/apps/dav/lib/Migration/BuildCalendarSearchIndex.php b/apps/dav/lib/Migration/BuildCalendarSearchIndex.php new file mode 100644 index 00000000000..da4b4f4fe84 --- /dev/null +++ b/apps/dav/lib/Migration/BuildCalendarSearchIndex.php @@ -0,0 +1,86 @@ + + * + * @author Georg Ehrke + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +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 { + + /** @var IDBConnection */ + private $db; + + /** @var IJobList */ + private $jobList; + + /** @var IConfig */ + private $config; + + /** + * @param IDBConnection $db + * @param IJobList $jobList + * @param IConfig $config + */ + public function __construct(IDBConnection $db, + IJobList $jobList, + IConfig $config) { + $this->db = $db; + $this->jobList = $jobList; + $this->config = $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(id)')) + ->from('calendarobjects'); + $maxId = (int)$query->execute()->fetchColumn(); + + $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'); + } +} \ No newline at end of file diff --git a/apps/dav/lib/Migration/BuildCalendarSearchIndexBackgroundJob.php b/apps/dav/lib/Migration/BuildCalendarSearchIndexBackgroundJob.php new file mode 100644 index 00000000000..c80289c1b30 --- /dev/null +++ b/apps/dav/lib/Migration/BuildCalendarSearchIndexBackgroundJob.php @@ -0,0 +1,120 @@ + + * + * @author Georg Ehrke + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\DAV\Migration; + +use OC\BackgroundJob\QueuedJob; +use OCA\DAV\CalDAV\CalDavBackend; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\IJobList; +use OCP\IDBConnection; +use OCP\ILogger; + +class BuildCalendarSearchIndexBackgroundJob extends QueuedJob { + + /** @var IDBConnection */ + private $db; + + /** @var CalDavBackend */ + private $calDavBackend; + + /** @var ILogger */ + private $logger; + + /** @var IJobList */ + private $jobList; + + /** @var ITimeFactory */ + private $timeFactory; + + /** + * @param IDBConnection $db + * @param CalDavBackend $calDavBackend + * @param ILogger $logger + * @param IJobList $jobList + * @param ITimeFactory $timeFactory + */ + public function __construct(IDBConnection $db, + CalDavBackend $calDavBackend, + ILogger $logger, + IJobList $jobList, + ITimeFactory $timeFactory) { + $this->db = $db; + $this->calDavBackend = $calDavBackend; + $this->logger = $logger; + $this->jobList = $jobList; + $this->timeFactory = $timeFactory; + } + + public function run($arguments) { + $offset = $arguments['offset']; + $stopAt = $arguments['stopAt']; + + $this->logger->info('Building calendar index (' . $offset .'/' . $stopAt . ')'); + + $offset = $this->buildIndex($offset, $stopAt); + + 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($offset, $stopAt) { + $startTime = $this->timeFactory->getTime(); + + $query = $this->db->getQueryBuilder(); + $query->select(['id', 'calendarid', 'objecturi', 'calendardata']) + ->from('calendarobjects') + ->where($query->expr()->lte('id', $query->createNamedParameter($stopAt))) + ->andWhere($query->expr()->gt('id', $query->createNamedParameter($offset))) + ->orderBy('id', 'ASC'); + + $stmt = $query->execute(); + while($row = $stmt->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); + + if (($this->timeFactory->getTime() - $startTime) > 15) { + return $offset; + } + } + + return $stopAt; + } +}