migrate therinaldos.com data
Build & Deploy to DigitalOcean Space / build (push) Failing after 2m38s

This commit is contained in:
2024-05-05 15:50:45 -04:00
commit ef1ff240d4
23182 changed files with 3801898 additions and 0 deletions
@@ -0,0 +1,131 @@
<?php
declare(strict_types=1);
/**
* @copyright 2019 Georg Ehrke <oc.list@georgehrke.com>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\BackgroundJob;
use OCA\DAV\CalDAV\Reminder\ReminderService;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\BackgroundJob\QueuedJob;
use OCP\IDBConnection;
use Psr\Log\LoggerInterface;
/**
* Class BuildReminderIndexBackgroundJob
*
* @package OCA\DAV\BackgroundJob
*/
class BuildReminderIndexBackgroundJob extends QueuedJob {
/** @var IDBConnection */
private $db;
/** @var ReminderService */
private $reminderService;
private LoggerInterface $logger;
/** @var IJobList */
private $jobList;
/** @var ITimeFactory */
private $timeFactory;
/**
* BuildReminderIndexBackgroundJob constructor.
*/
public function __construct(IDBConnection $db,
ReminderService $reminderService,
LoggerInterface $logger,
IJobList $jobList,
ITimeFactory $timeFactory) {
parent::__construct($timeFactory);
$this->db = $db;
$this->reminderService = $reminderService;
$this->logger = $logger;
$this->jobList = $jobList;
$this->timeFactory = $timeFactory;
}
public function run($argument) {
$offset = (int) $argument['offset'];
$stopAt = (int) $argument['stopAt'];
$this->logger->info('Building calendar reminder index (' . $offset .'/' . $stopAt . ')');
$offset = $this->buildIndex($offset, $stopAt);
if ($offset >= $stopAt) {
$this->logger->info('Building calendar reminder index done');
} else {
$this->jobList->add(self::class, [
'offset' => $offset,
'stopAt' => $stopAt
]);
$this->logger->info('Scheduled a new BuildReminderIndexBackgroundJob with offset ' . $offset);
}
}
/**
* @param int $offset
* @param int $stopAt
* @return int
*/
private function buildIndex(int $offset, int $stopAt):int {
$startTime = $this->timeFactory->getTime();
$query = $this->db->getQueryBuilder();
$query->select('*')
->from('calendarobjects')
->where($query->expr()->lte('id', $query->createNamedParameter($stopAt)))
->andWhere($query->expr()->gt('id', $query->createNamedParameter($offset)))
->orderBy('id', 'ASC');
$result = $query->executeQuery();
while ($row = $result->fetch(\PDO::FETCH_ASSOC)) {
$offset = (int) $row['id'];
if (is_resource($row['calendardata'])) {
$row['calendardata'] = stream_get_contents($row['calendardata']);
}
$row['component'] = $row['componenttype'];
try {
$this->reminderService->onCalendarObjectCreate($row);
} catch (\Exception $ex) {
$this->logger->error($ex->getMessage(), ['exception' => $ex]);
}
if (($this->timeFactory->getTime() - $startTime) > 15) {
$result->closeCursor();
return $offset;
}
}
$result->closeCursor();
return $stopAt;
}
}
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
/**
* @copyright 2021 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\BackgroundJob;
use OCA\DAV\CalDAV\RetentionService;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob;
class CalendarRetentionJob extends TimedJob {
/** @var RetentionService */
private $service;
public function __construct(ITimeFactory $time,
RetentionService $service) {
parent::__construct($time);
$this->service = $service;
// Run four times a day
$this->setInterval(6 * 60 * 60);
$this->setTimeSensitivity(self::TIME_SENSITIVE);
}
protected function run($argument): void {
$this->service->cleanUp();
}
}
@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
/**
* @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\BackgroundJob;
use OCA\DAV\Db\DirectMapper;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob;
class CleanupDirectLinksJob extends TimedJob {
/** @var DirectMapper */
private $mapper;
public function __construct(ITimeFactory $timeFactory, DirectMapper $mapper) {
parent::__construct($timeFactory);
$this->mapper = $mapper;
// Run once a day at off-peak time
$this->setInterval(24 * 60 * 60);
$this->setTimeSensitivity(self::TIME_INSENSITIVE);
}
protected function run($argument) {
// Delete all shares expired 24 hours ago
$this->mapper->deleteExpired($this->time->getTime() - 60 * 60 * 24);
}
}
@@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
/**
* @copyright 2018, Georg Ehrke <oc.list@georgehrke.com>
*
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\BackgroundJob;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob;
use OCP\IDBConnection;
class CleanupInvitationTokenJob extends TimedJob {
/** @var IDBConnection */
private $db;
public function __construct(IDBConnection $db, ITimeFactory $time) {
parent::__construct($time);
$this->db = $db;
// Run once a day at off-peak time
$this->setInterval(24 * 60 * 60);
$this->setTimeSensitivity(self::TIME_INSENSITIVE);
}
public function run($argument) {
$query = $this->db->getQueryBuilder();
$query->delete('calendar_invitations')
->where($query->expr()->lt('expiration',
$query->createNamedParameter($this->time->getTime())))
->execute();
}
}
@@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Thomas Citharel <nextcloud@tcit.fr>
*
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Thomas Citharel <nextcloud@tcit.fr>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\BackgroundJob;
use OCA\DAV\CalDAV\Reminder\ReminderService;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob;
use OCP\IConfig;
class EventReminderJob extends TimedJob {
/** @var ReminderService */
private $reminderService;
/** @var IConfig */
private $config;
public function __construct(ITimeFactory $time,
ReminderService $reminderService,
IConfig $config) {
parent::__construct($time);
$this->reminderService = $reminderService;
$this->config = $config;
// Run every 5 minutes
$this->setInterval(5 * 60);
$this->setTimeSensitivity(self::TIME_SENSITIVE);
}
/**
* @throws \OCA\DAV\CalDAV\Reminder\NotificationProvider\ProviderNotAvailableException
* @throws \OCA\DAV\CalDAV\Reminder\NotificationTypeDoesNotExistException
* @throws \OC\User\NoUserException
*/
public function run($argument):void {
if ($this->config->getAppValue('dav', 'sendEventReminders', 'yes') !== 'yes') {
return;
}
if ($this->config->getAppValue('dav', 'sendEventRemindersMode', 'backgroundjob') !== 'backgroundjob') {
return;
}
$this->reminderService->processReminders();
}
}
@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
/**
* @copyright 2017 Georg Ehrke <oc.list@georgehrke.com>
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\BackgroundJob;
use OCA\DAV\CalDAV\BirthdayService;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\QueuedJob;
use OCP\IConfig;
class GenerateBirthdayCalendarBackgroundJob extends QueuedJob {
/** @var BirthdayService */
private $birthdayService;
/** @var IConfig */
private $config;
public function __construct(ITimeFactory $time,
BirthdayService $birthdayService,
IConfig $config) {
parent::__construct($time);
$this->birthdayService = $birthdayService;
$this->config = $config;
}
public function run($argument) {
$userId = $argument['userId'];
$purgeBeforeGenerating = $argument['purgeBeforeGenerating'] ?? false;
// make sure admin didn't change his mind
$isGloballyEnabled = $this->config->getAppValue('dav', 'generateBirthdayCalendar', 'yes');
if ($isGloballyEnabled !== 'yes') {
return;
}
// did the user opt out?
$isUserEnabled = $this->config->getUserValue($userId, 'dav', 'generateBirthdayCalendar', 'yes');
if ($isUserEnabled !== 'yes') {
return;
}
if ($purgeBeforeGenerating) {
$this->birthdayService->resetForUser($userId);
}
$this->birthdayService->syncUser($userId);
}
}
@@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2023 Richard Steinmetz <richard@steinmetz.cloud>
*
* @author Richard Steinmetz <richard@steinmetz.cloud>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\BackgroundJob;
use OCA\DAV\CalDAV\TimezoneService;
use OCA\DAV\Db\AbsenceMapper;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\QueuedJob;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IUserManager;
use OCP\User\Events\OutOfOfficeEndedEvent;
use OCP\User\Events\OutOfOfficeStartedEvent;
use Psr\Log\LoggerInterface;
class OutOfOfficeEventDispatcherJob extends QueuedJob {
public const EVENT_START = 'start';
public const EVENT_END = 'end';
public function __construct(
ITimeFactory $time,
private AbsenceMapper $absenceMapper,
private LoggerInterface $logger,
private IEventDispatcher $eventDispatcher,
private IUserManager $userManager,
private TimezoneService $timezoneService,
) {
parent::__construct($time);
}
public function run($argument): void {
$id = $argument['id'];
$event = $argument['event'];
try {
$absence = $this->absenceMapper->findById($id);
} catch (DoesNotExistException | \OCP\DB\Exception $e) {
$this->logger->error('Failed to dispatch out-of-office event: ' . $e->getMessage(), [
'exception' => $e,
'argument' => $argument,
]);
return;
}
$userId = $absence->getUserId();
$user = $this->userManager->get($userId);
if ($user === null) {
$this->logger->error("Failed to dispatch out-of-office event: User $userId does not exist", [
'argument' => $argument,
]);
return;
}
$data = $absence->toOutOufOfficeData(
$user,
$this->timezoneService->getUserTimezone($userId) ?? $this->timezoneService->getDefaultTimezone(),
);
if ($event === self::EVENT_START) {
$this->eventDispatcher->dispatchTyped(new OutOfOfficeStartedEvent($data));
} elseif ($event === self::EVENT_END) {
$this->eventDispatcher->dispatchTyped(new OutOfOfficeEndedEvent($data));
} else {
$this->logger->error("Invalid out-of-office event: $event", [
'argument' => $argument,
]);
}
}
}
@@ -0,0 +1,64 @@
<?php
declare(strict_types=1);
/**
* @copyright 2022 Thomas Citharel <nextcloud@tcit.fr>
*
* @author Thomas Citharel <nextcloud@tcit.fr>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\BackgroundJob;
use OCA\DAV\AppInfo\Application;
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CardDAV\CardDavBackend;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob;
use OCP\IConfig;
use Psr\Log\LoggerInterface;
class PruneOutdatedSyncTokensJob extends TimedJob {
private IConfig $config;
private LoggerInterface $logger;
private CardDavBackend $cardDavBackend;
private CalDavBackend $calDavBackend;
public function __construct(ITimeFactory $timeFactory, CalDavBackend $calDavBackend, CardDavBackend $cardDavBackend, IConfig $config, LoggerInterface $logger) {
parent::__construct($timeFactory);
$this->calDavBackend = $calDavBackend;
$this->cardDavBackend = $cardDavBackend;
$this->config = $config;
$this->logger = $logger;
$this->setInterval(60 * 60 * 24); // One day
$this->setTimeSensitivity(self::TIME_INSENSITIVE);
}
public function run($argument) {
$limit = max(1, (int) $this->config->getAppValue(Application::APP_ID, 'totalNumberOfSyncTokensToKeep', '10000'));
$prunedCalendarSyncTokens = $this->calDavBackend->pruneOutdatedSyncTokens($limit);
$prunedAddressBookSyncTokens = $this->cardDavBackend->pruneOutdatedSyncTokens($limit);
$this->logger->info('Pruned {calendarSyncTokensNumber} calendar sync tokens and {addressBooksSyncTokensNumber} address book sync tokens', [
'calendarSyncTokensNumber' => $prunedCalendarSyncTokens,
'addressBooksSyncTokensNumber' => $prunedAddressBookSyncTokens
]);
}
}
@@ -0,0 +1,153 @@
<?php
declare(strict_types=1);
/**
* @copyright 2018 Georg Ehrke <oc.list@georgehrke.com>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Citharel <nextcloud@tcit.fr>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\BackgroundJob;
use DateInterval;
use OCA\DAV\CalDAV\WebcalCaching\RefreshWebcalService;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\BackgroundJob\Job;
use OCP\IConfig;
use OCP\ILogger;
use Sabre\VObject\DateTimeParser;
use Sabre\VObject\InvalidDataException;
class RefreshWebcalJob extends Job {
/**
* @var RefreshWebcalService
*/
private $refreshWebcalService;
/**
* @var IConfig
*/
private $config;
/** @var ILogger */
private $logger;
/** @var ITimeFactory */
private $timeFactory;
/**
* RefreshWebcalJob constructor.
*
* @param RefreshWebcalService $refreshWebcalService
* @param IConfig $config
* @param ILogger $logger
* @param ITimeFactory $timeFactory
*/
public function __construct(RefreshWebcalService $refreshWebcalService, IConfig $config, ILogger $logger, ITimeFactory $timeFactory) {
parent::__construct($timeFactory);
$this->refreshWebcalService = $refreshWebcalService;
$this->config = $config;
$this->logger = $logger;
$this->timeFactory = $timeFactory;
}
/**
* this function is called at most every hour
*
* @inheritdoc
*/
public function execute(IJobList $jobList, ILogger $logger = null) {
$subscription = $this->refreshWebcalService->getSubscription($this->argument['principaluri'], $this->argument['uri']);
if (!$subscription) {
return;
}
$this->fixSubscriptionRowTyping($subscription);
// if no refresh rate was configured, just refresh once a week
$defaultRefreshRate = $this->config->getAppValue('dav', 'calendarSubscriptionRefreshRate', 'P1W');
$refreshRate = $subscription[RefreshWebcalService::REFRESH_RATE] ?? $defaultRefreshRate;
$subscriptionId = $subscription['id'];
try {
/** @var DateInterval $dateInterval */
$dateInterval = DateTimeParser::parseDuration($refreshRate);
} catch (InvalidDataException $ex) {
$this->logger->logException($ex);
$this->logger->warning("Subscription $subscriptionId could not be refreshed, refreshrate in database is invalid");
return;
}
$interval = $this->getIntervalFromDateInterval($dateInterval);
if (($this->timeFactory->getTime() - $this->lastRun) <= $interval) {
return;
}
parent::execute($jobList, $logger);
}
/**
* @param array $argument
*/
protected function run($argument) {
$this->refreshWebcalService->refreshSubscription($argument['principaluri'], $argument['uri']);
}
/**
* get total number of seconds from DateInterval object
*
* @param DateInterval $interval
* @return int
*/
private function getIntervalFromDateInterval(DateInterval $interval):int {
return $interval->s
+ ($interval->i * 60)
+ ($interval->h * 60 * 60)
+ ($interval->d * 60 * 60 * 24)
+ ($interval->m * 60 * 60 * 24 * 30)
+ ($interval->y * 60 * 60 * 24 * 365);
}
/**
* Fixes types of rows
*
* @param array $row
*/
private function fixSubscriptionRowTyping(array &$row):void {
$forceInt = [
'id',
'lastmodified',
RefreshWebcalService::STRIP_ALARMS,
RefreshWebcalService::STRIP_ATTACHMENTS,
RefreshWebcalService::STRIP_TODOS,
];
foreach ($forceInt as $column) {
if (isset($row[$column])) {
$row[$column] = (int) $row[$column];
}
}
}
}
@@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
/**
* @copyright 2019 Georg Ehrke <oc.list@georgehrke.com>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\BackgroundJob;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\BackgroundJob\QueuedJob;
use OCP\IUser;
use OCP\IUserManager;
class RegisterRegenerateBirthdayCalendars extends QueuedJob {
/** @var IUserManager */
private $userManager;
/** @var IJobList */
private $jobList;
/**
* RegisterRegenerateBirthdayCalendars constructor.
*
* @param ITimeFactory $time
* @param IUserManager $userManager
* @param IJobList $jobList
*/
public function __construct(ITimeFactory $time,
IUserManager $userManager,
IJobList $jobList) {
parent::__construct($time);
$this->userManager = $userManager;
$this->jobList = $jobList;
}
/**
* @inheritDoc
*/
public function run($argument) {
$this->userManager->callForSeenUsers(function (IUser $user) {
$this->jobList->add(GenerateBirthdayCalendarBackgroundJob::class, [
'userId' => $user->getUID(),
'purgeBeforeGenerating' => true
]);
});
}
}
@@ -0,0 +1,454 @@
<?php
declare(strict_types=1);
/**
* @copyright 2019, Georg Ehrke <oc.list@georgehrke.com>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\BackgroundJob;
use OCA\DAV\CalDAV\CalDavBackend;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob;
use OCP\Calendar\BackendTemporarilyUnavailableException;
use OCP\Calendar\IMetadataProvider;
use OCP\Calendar\Resource\IBackend as IResourceBackend;
use OCP\Calendar\Resource\IManager as IResourceManager;
use OCP\Calendar\Resource\IResource;
use OCP\Calendar\Room\IManager as IRoomManager;
use OCP\Calendar\Room\IRoom;
use OCP\IDBConnection;
class UpdateCalendarResourcesRoomsBackgroundJob extends TimedJob {
/** @var IResourceManager */
private $resourceManager;
/** @var IRoomManager */
private $roomManager;
/** @var IDBConnection */
private $dbConnection;
/** @var CalDavBackend */
private $calDavBackend;
public function __construct(ITimeFactory $time,
IResourceManager $resourceManager,
IRoomManager $roomManager,
IDBConnection $dbConnection,
CalDavBackend $calDavBackend) {
parent::__construct($time);
$this->resourceManager = $resourceManager;
$this->roomManager = $roomManager;
$this->dbConnection = $dbConnection;
$this->calDavBackend = $calDavBackend;
// Run once an hour
$this->setInterval(60 * 60);
$this->setTimeSensitivity(self::TIME_SENSITIVE);
}
/**
* @param $argument
*/
public function run($argument): void {
$this->runForBackend(
$this->resourceManager,
'calendar_resources',
'calendar_resources_md',
'resource_id',
'principals/calendar-resources'
);
$this->runForBackend(
$this->roomManager,
'calendar_rooms',
'calendar_rooms_md',
'room_id',
'principals/calendar-rooms'
);
}
/**
* Run background-job for one specific backendManager
* either ResourceManager or RoomManager
*
* @param IResourceManager|IRoomManager $backendManager
* @param string $dbTable
* @param string $dbTableMetadata
* @param string $foreignKey
* @param string $principalPrefix
*/
private function runForBackend($backendManager,
string $dbTable,
string $dbTableMetadata,
string $foreignKey,
string $principalPrefix): void {
$backends = $backendManager->getBackends();
foreach ($backends as $backend) {
$backendId = $backend->getBackendIdentifier();
try {
if ($backend instanceof IResourceBackend) {
$list = $backend->listAllResources();
} else {
$list = $backend->listAllRooms();
}
} catch (BackendTemporarilyUnavailableException $ex) {
continue;
}
$cachedList = $this->getAllCachedByBackend($dbTable, $backendId);
$newIds = array_diff($list, $cachedList);
$deletedIds = array_diff($cachedList, $list);
$editedIds = array_intersect($list, $cachedList);
foreach ($newIds as $newId) {
try {
if ($backend instanceof IResourceBackend) {
$resource = $backend->getResource($newId);
} else {
$resource = $backend->getRoom($newId);
}
$metadata = [];
if ($resource instanceof IMetadataProvider) {
$metadata = $this->getAllMetadataOfBackend($resource);
}
} catch (BackendTemporarilyUnavailableException $ex) {
continue;
}
$id = $this->addToCache($dbTable, $backendId, $resource);
$this->addMetadataToCache($dbTableMetadata, $foreignKey, $id, $metadata);
// we don't create the calendar here, it is created lazily
// when an event is actually scheduled with this resource / room
}
foreach ($deletedIds as $deletedId) {
$id = $this->getIdForBackendAndResource($dbTable, $backendId, $deletedId);
$this->deleteFromCache($dbTable, $id);
$this->deleteMetadataFromCache($dbTableMetadata, $foreignKey, $id);
$principalName = implode('-', [$backendId, $deletedId]);
$this->deleteCalendarDataForResource($principalPrefix, $principalName);
}
foreach ($editedIds as $editedId) {
$id = $this->getIdForBackendAndResource($dbTable, $backendId, $editedId);
try {
if ($backend instanceof IResourceBackend) {
$resource = $backend->getResource($editedId);
} else {
$resource = $backend->getRoom($editedId);
}
$metadata = [];
if ($resource instanceof IMetadataProvider) {
$metadata = $this->getAllMetadataOfBackend($resource);
}
} catch (BackendTemporarilyUnavailableException $ex) {
continue;
}
$this->updateCache($dbTable, $id, $resource);
if ($resource instanceof IMetadataProvider) {
$cachedMetadata = $this->getAllMetadataOfCache($dbTableMetadata, $foreignKey, $id);
$this->updateMetadataCache($dbTableMetadata, $foreignKey, $id, $metadata, $cachedMetadata);
}
}
}
}
/**
* add entry to cache that exists remotely but not yet in cache
*
* @param string $table
* @param string $backendId
* @param IResource|IRoom $remote
*
* @return int Insert id
*/
private function addToCache(string $table,
string $backendId,
$remote): int {
$query = $this->dbConnection->getQueryBuilder();
$query->insert($table)
->values([
'backend_id' => $query->createNamedParameter($backendId),
'resource_id' => $query->createNamedParameter($remote->getId()),
'email' => $query->createNamedParameter($remote->getEMail()),
'displayname' => $query->createNamedParameter($remote->getDisplayName()),
'group_restrictions' => $query->createNamedParameter(
$this->serializeGroupRestrictions(
$remote->getGroupRestrictions()
))
])
->executeStatement();
return $query->getLastInsertId();
}
/**
* @param string $table
* @param string $foreignKey
* @param int $foreignId
* @param array $metadata
*/
private function addMetadataToCache(string $table,
string $foreignKey,
int $foreignId,
array $metadata): void {
foreach ($metadata as $key => $value) {
$query = $this->dbConnection->getQueryBuilder();
$query->insert($table)
->values([
$foreignKey => $query->createNamedParameter($foreignId),
'key' => $query->createNamedParameter($key),
'value' => $query->createNamedParameter($value),
])
->executeStatement();
}
}
/**
* delete entry from cache that does not exist anymore remotely
*
* @param string $table
* @param int $id
*/
private function deleteFromCache(string $table,
int $id): void {
$query = $this->dbConnection->getQueryBuilder();
$query->delete($table)
->where($query->expr()->eq('id', $query->createNamedParameter($id)))
->executeStatement();
}
/**
* @param string $table
* @param string $foreignKey
* @param int $id
*/
private function deleteMetadataFromCache(string $table,
string $foreignKey,
int $id): void {
$query = $this->dbConnection->getQueryBuilder();
$query->delete($table)
->where($query->expr()->eq($foreignKey, $query->createNamedParameter($id)))
->executeStatement();
}
/**
* update an existing entry in cache
*
* @param string $table
* @param int $id
* @param IResource|IRoom $remote
*/
private function updateCache(string $table,
int $id,
$remote): void {
$query = $this->dbConnection->getQueryBuilder();
$query->update($table)
->set('email', $query->createNamedParameter($remote->getEMail()))
->set('displayname', $query->createNamedParameter($remote->getDisplayName()))
->set('group_restrictions', $query->createNamedParameter(
$this->serializeGroupRestrictions(
$remote->getGroupRestrictions()
)))
->where($query->expr()->eq('id', $query->createNamedParameter($id)))
->executeStatement();
}
/**
* @param string $dbTable
* @param string $foreignKey
* @param int $id
* @param array $metadata
* @param array $cachedMetadata
*/
private function updateMetadataCache(string $dbTable,
string $foreignKey,
int $id,
array $metadata,
array $cachedMetadata): void {
$newMetadata = array_diff_key($metadata, $cachedMetadata);
$deletedMetadata = array_diff_key($cachedMetadata, $metadata);
foreach ($newMetadata as $key => $value) {
$query = $this->dbConnection->getQueryBuilder();
$query->insert($dbTable)
->values([
$foreignKey => $query->createNamedParameter($id),
'key' => $query->createNamedParameter($key),
'value' => $query->createNamedParameter($value),
])
->executeStatement();
}
foreach ($deletedMetadata as $key => $value) {
$query = $this->dbConnection->getQueryBuilder();
$query->delete($dbTable)
->where($query->expr()->eq($foreignKey, $query->createNamedParameter($id)))
->andWhere($query->expr()->eq('key', $query->createNamedParameter($key)))
->executeStatement();
}
$existingKeys = array_keys(array_intersect_key($metadata, $cachedMetadata));
foreach ($existingKeys as $existingKey) {
if ($metadata[$existingKey] !== $cachedMetadata[$existingKey]) {
$query = $this->dbConnection->getQueryBuilder();
$query->update($dbTable)
->set('value', $query->createNamedParameter($metadata[$existingKey]))
->where($query->expr()->eq($foreignKey, $query->createNamedParameter($id)))
->andWhere($query->expr()->eq('key', $query->createNamedParameter($existingKey)))
->executeStatement();
}
}
}
/**
* serialize array of group restrictions to store them in database
*
* @param array $groups
*
* @return string
*/
private function serializeGroupRestrictions(array $groups): string {
return \json_encode($groups, JSON_THROW_ON_ERROR);
}
/**
* Gets all metadata of a backend
*
* @param IResource|IRoom $resource
*
* @return array
*/
private function getAllMetadataOfBackend($resource): array {
if (!($resource instanceof IMetadataProvider)) {
return [];
}
$keys = $resource->getAllAvailableMetadataKeys();
$metadata = [];
foreach ($keys as $key) {
$metadata[$key] = $resource->getMetadataForKey($key);
}
return $metadata;
}
/**
* @param string $table
* @param string $foreignKey
* @param int $id
*
* @return array
*/
private function getAllMetadataOfCache(string $table,
string $foreignKey,
int $id): array {
$query = $this->dbConnection->getQueryBuilder();
$query->select(['key', 'value'])
->from($table)
->where($query->expr()->eq($foreignKey, $query->createNamedParameter($id)));
$result = $query->executeQuery();
$rows = $result->fetchAll();
$result->closeCursor();
$metadata = [];
foreach ($rows as $row) {
$metadata[$row['key']] = $row['value'];
}
return $metadata;
}
/**
* Gets all cached rooms / resources by backend
*
* @param $tableName
* @param $backendId
*
* @return array
*/
private function getAllCachedByBackend(string $tableName,
string $backendId): array {
$query = $this->dbConnection->getQueryBuilder();
$query->select('resource_id')
->from($tableName)
->where($query->expr()->eq('backend_id', $query->createNamedParameter($backendId)));
$result = $query->executeQuery();
$rows = $result->fetchAll();
$result->closeCursor();
return array_map(function ($row): string {
return $row['resource_id'];
}, $rows);
}
/**
* @param $principalPrefix
* @param $principalUri
*/
private function deleteCalendarDataForResource(string $principalPrefix,
string $principalUri): void {
$calendar = $this->calDavBackend->getCalendarByUri(
implode('/', [$principalPrefix, $principalUri]),
CalDavBackend::RESOURCE_BOOKING_CALENDAR_URI);
if ($calendar !== null) {
$this->calDavBackend->deleteCalendar(
$calendar['id'],
true // Because this wasn't deleted by a user
);
}
}
/**
* @param $table
* @param $backendId
* @param $resourceId
*
* @return int
*/
private function getIdForBackendAndResource(string $table,
string $backendId,
string $resourceId): int {
$query = $this->dbConnection->getQueryBuilder();
$query->select('id')
->from($table)
->where($query->expr()->eq('backend_id', $query->createNamedParameter($backendId)))
->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resourceId)));
$result = $query->executeQuery();
$id = (int) $result->fetchOne();
$result->closeCursor();
return $id;
}
}
@@ -0,0 +1,99 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2018, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Julius Härtl <jus@bitgrid.net>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\BackgroundJob;
use OC\User\NoUserException;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJob;
use OCP\BackgroundJob\IJobList;
use OCP\BackgroundJob\TimedJob;
use OCP\Files\File;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use Psr\Log\LoggerInterface;
class UploadCleanup extends TimedJob {
private IRootFolder $rootFolder;
private IJobList $jobList;
private LoggerInterface $logger;
public function __construct(ITimeFactory $time, IRootFolder $rootFolder, IJobList $jobList, LoggerInterface $logger) {
parent::__construct($time);
$this->rootFolder = $rootFolder;
$this->jobList = $jobList;
$this->logger = $logger;
// Run once a day
$this->setInterval(60 * 60 * 24);
$this->setTimeSensitivity(IJob::TIME_INSENSITIVE);
}
protected function run($argument) {
$uid = $argument['uid'];
$folder = $argument['folder'];
try {
$userFolder = $this->rootFolder->getUserFolder($uid);
$userRoot = $userFolder->getParent();
/** @var Folder $uploads */
$uploads = $userRoot->get('uploads');
$uploadFolder = $uploads->get($folder);
} catch (NotFoundException | NoUserException $e) {
$this->jobList->remove(self::class, $argument);
return;
}
// Remove if all files have an mtime of more than a day
$time = $this->time->getTime() - 60 * 60 * 24;
if (!($uploadFolder instanceof Folder)) {
$this->logger->error("Found a file inside the uploads folder. Uid: " . $uid . ' folder: ' . $folder);
if ($uploadFolder->getMTime() < $time) {
$uploadFolder->delete();
}
$this->jobList->remove(self::class, $argument);
return;
}
/** @var File[] $files */
$files = $uploadFolder->getDirectoryListing();
// The folder has to be more than a day old
$initial = $uploadFolder->getMTime() < $time;
$expire = array_reduce($files, function (bool $carry, File $file) use ($time) {
return $carry && $file->getMTime() < $time;
}, $initial);
if ($expire) {
$uploadFolder->delete();
$this->jobList->remove(self::class, $argument);
}
}
}
@@ -0,0 +1,259 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\BackgroundJob;
use OCA\DAV\CalDAV\Schedule\Plugin;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\BackgroundJob\TimedJob;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IUser;
use OCP\IUserManager;
use OCP\User\IAvailabilityCoordinator;
use OCP\User\IOutOfOfficeData;
use OCP\UserStatus\IManager;
use OCP\UserStatus\IUserStatus;
use Psr\Log\LoggerInterface;
use Sabre\VObject\Component\Available;
use Sabre\VObject\Component\VAvailability;
use Sabre\VObject\Reader;
use Sabre\VObject\Recur\RRuleIterator;
class UserStatusAutomation extends TimedJob {
public function __construct(private ITimeFactory $timeFactory,
private IDBConnection $connection,
private IJobList $jobList,
private LoggerInterface $logger,
private IManager $manager,
private IConfig $config,
private IAvailabilityCoordinator $coordinator,
private IUserManager $userManager) {
parent::__construct($timeFactory);
// Interval 0 might look weird, but the last_checked is always moved
// to the next time we need this and then it's 0 seconds ago.
$this->setInterval(0);
}
/**
* @inheritDoc
*/
protected function run($argument) {
if (!isset($argument['userId'])) {
$this->jobList->remove(self::class, $argument);
$this->logger->info('Removing invalid ' . self::class . ' background job');
return;
}
$userId = $argument['userId'];
$user = $this->userManager->get($userId);
if($user === null) {
return;
}
$ooo = $this->coordinator->getCurrentOutOfOfficeData($user);
$continue = $this->processOutOfOfficeData($user, $ooo);
if($continue === false) {
return;
}
$property = $this->getAvailabilityFromPropertiesTable($userId);
$hasDndForOfficeHours = $this->config->getUserValue($userId, 'dav', 'user_status_automation', 'no') === 'yes';
if (!$property) {
// We found no ooo data and no availability settings, so we need to delete the job because there is no next runtime
$this->logger->info('Removing ' . self::class . ' background job for user "' . $userId . '" because the user has no valid availability rules and no OOO data set');
$this->jobList->remove(self::class, $argument);
$this->manager->revertUserStatus($user->getUID(), IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND);
$this->manager->revertUserStatus($user->getUID(), IUserStatus::MESSAGE_OUT_OF_OFFICE, IUserStatus::DND);
return;
}
$this->processAvailability($property, $user->getUID(), $hasDndForOfficeHours);
}
protected function setLastRunToNextToggleTime(string $userId, int $timestamp): void {
$query = $this->connection->getQueryBuilder();
$query->update('jobs')
->set('last_run', $query->createNamedParameter($timestamp, IQueryBuilder::PARAM_INT))
->where($query->expr()->eq('id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)));
$query->executeStatement();
$this->logger->debug('Updated user status automation last_run to ' . $timestamp . ' for user ' . $userId);
}
/**
* @param string $userId
* @return false|string
*/
protected function getAvailabilityFromPropertiesTable(string $userId) {
$propertyPath = 'calendars/' . $userId . '/inbox';
$propertyName = '{' . Plugin::NS_CALDAV . '}calendar-availability';
$query = $this->connection->getQueryBuilder();
$query->select('propertyvalue')
->from('properties')
->where($query->expr()->eq('userid', $query->createNamedParameter($userId)))
->andWhere($query->expr()->eq('propertypath', $query->createNamedParameter($propertyPath)))
->andWhere($query->expr()->eq('propertyname', $query->createNamedParameter($propertyName)))
->setMaxResults(1);
$result = $query->executeQuery();
$property = $result->fetchOne();
$result->closeCursor();
return $property;
}
/**
* @param string $property
* @param $userId
* @param $argument
* @return void
*/
private function processAvailability(string $property, string $userId, bool $hasDndForOfficeHours): void {
$isCurrentlyAvailable = false;
$nextPotentialToggles = [];
$now = $this->time->getDateTime();
$lastMidnight = (clone $now)->setTime(0, 0);
$vObject = Reader::read($property);
foreach ($vObject->getComponents() as $component) {
if ($component->name !== 'VAVAILABILITY') {
continue;
}
/** @var VAvailability $component */
$availables = $component->getComponents();
foreach ($availables as $available) {
/** @var Available $available */
if ($available->name === 'AVAILABLE') {
/** @var \DateTimeImmutable $originalStart */
/** @var \DateTimeImmutable $originalEnd */
[$originalStart, $originalEnd] = $available->getEffectiveStartEnd();
// Little shenanigans to fix the automation on the day the rules were adjusted
// Otherwise the $originalStart would match rules for Thursdays on a Friday, etc.
// So we simply wind back a week and then fastForward to the next occurrence
// since today's midnight, which then also accounts for the week days.
$effectiveStart = \DateTime::createFromImmutable($originalStart)->sub(new \DateInterval('P7D'));
$effectiveEnd = \DateTime::createFromImmutable($originalEnd)->sub(new \DateInterval('P7D'));
try {
$it = new RRuleIterator((string)$available->RRULE, $effectiveStart);
$it->fastForward($lastMidnight);
$startToday = $it->current();
if ($startToday && $startToday <= $now) {
$duration = $effectiveStart->diff($effectiveEnd);
$endToday = $startToday->add($duration);
if ($endToday > $now) {
// User is currently available
// Also queuing the end time as next status toggle
$isCurrentlyAvailable = true;
$nextPotentialToggles[] = $endToday->getTimestamp();
}
// Availability enabling already done for today,
// so jump to the next recurrence to find the next status toggle
$it->next();
}
if ($it->current()) {
$nextPotentialToggles[] = $it->current()->getTimestamp();
}
} catch (\Exception $e) {
$this->logger->error($e->getMessage(), ['exception' => $e]);
}
}
}
}
if (empty($nextPotentialToggles)) {
$this->logger->info('Removing ' . self::class . ' background job for user "' . $userId . '" because the user has no valid availability rules set');
$this->jobList->remove(self::class, ['userId' => $userId]);
$this->manager->revertUserStatus($userId, IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND);
return;
}
$nextAutomaticToggle = min($nextPotentialToggles);
$this->setLastRunToNextToggleTime($userId, $nextAutomaticToggle - 1);
if ($isCurrentlyAvailable) {
$this->logger->debug('User is currently available, reverting DND status if applicable');
$this->manager->revertUserStatus($userId, IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND);
$this->logger->debug('User status automation ran');
return;
}
if(!$hasDndForOfficeHours) {
// Office hours are not set to DND, so there is nothing to do.
return;
}
$this->logger->debug('User is currently NOT available, reverting call status if applicable and then setting DND');
// The DND status automation is more important than the "Away - In call" so we also restore that one if it exists.
$this->manager->revertUserStatus($userId, IUserStatus::MESSAGE_CALL, IUserStatus::AWAY);
$this->manager->setUserStatus($userId, IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND, true);
$this->logger->debug('User status automation ran');
}
private function processOutOfOfficeData(IUser $user, ?IOutOfOfficeData $ooo): bool {
if(empty($ooo)) {
// Reset the user status if the absence doesn't exist
$this->logger->debug('User has no OOO period in effect, reverting DND status if applicable');
$this->manager->revertUserStatus($user->getUID(), IUserStatus::MESSAGE_OUT_OF_OFFICE, IUserStatus::DND);
// We need to also run the availability automation
return true;
}
if(!$this->coordinator->isInEffect($ooo)) {
// Reset the user status if the absence is (no longer) in effect
$this->logger->debug('User has no OOO period in effect, reverting DND status if applicable');
$this->manager->revertUserStatus($user->getUID(), IUserStatus::MESSAGE_OUT_OF_OFFICE, IUserStatus::DND);
if($ooo->getStartDate() > $this->time->getTime()) {
// Set the next run to take place at the start of the ooo period if it is in the future
// This might be overwritten if there is an availability setting, but we can't determine
// if this is the case here
$this->setLastRunToNextToggleTime($user->getUID(), $ooo->getStartDate());
}
return true;
}
$this->logger->debug('User is currently in an OOO period, reverting other automated status and setting OOO DND status');
// Revert both a possible 'CALL - away' and 'office hours - DND' status
$this->manager->revertUserStatus($user->getUID(), IUserStatus::MESSAGE_CALL, IUserStatus::DND);
$this->manager->revertUserStatus($user->getUID(), IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND);
$this->manager->setUserStatus($user->getUID(), IUserStatus::MESSAGE_OUT_OF_OFFICE, IUserStatus::DND, true, $ooo->getShortMessage());
// Run at the end of an ooo period to return to availability / regular user status
// If it's overwritten by a custom status in the meantime, there's nothing we can do about it
$this->setLastRunToNextToggleTime($user->getUID(), $ooo->getEndDate());
return false;
}
}