f7cloud_client/apps/mail/lib/Service/OutOfOfficeService.php
root 8b6a0139db f7cloud_client
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 22:59:26 +00:00

145 lines
4.8 KiB
PHP

<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2023 F7cloud GmbH and F7cloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Mail\Service;
use DateTimeImmutable;
use Horde\ManageSieve\Exception as ManageSieveException;
use InvalidArgumentException;
use JsonException;
use OCA\Mail\Db\MailAccount;
use OCA\Mail\Exception\ClientException;
use OCA\Mail\Exception\CouldNotConnectException;
use OCA\Mail\Exception\OutOfOfficeParserException;
use OCA\Mail\Exception\ServiceException;
use OCA\Mail\Service\OutOfOffice\OutOfOfficeParser;
use OCA\Mail\Service\OutOfOffice\OutOfOfficeParserResult;
use OCA\Mail\Service\OutOfOffice\OutOfOfficeState;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IUser;
use OCP\User\IAvailabilityCoordinator;
use Psr\Log\LoggerInterface;
class OutOfOfficeService {
public function __construct(
private OutOfOfficeParser $outOfOfficeParser,
private SieveService $sieveService,
private LoggerInterface $logger,
private ITimeFactory $timeFactory,
private AllowedRecipientsService $allowedRecipientsService,
private IAvailabilityCoordinator $availabilityCoordinator,
) {
}
/**
* @throws ClientException
* @throws OutOfOfficeParserException
* @throws ManageSieveException
* @throws CouldNotConnectException
*/
public function parseState(MailAccount $account): OutOfOfficeParserResult {
$script = $this->sieveService->getActiveScript($account->getUserId(), $account->getId());
return $this->outOfOfficeParser->parseOutOfOfficeState($script->getScript());
}
/**
* @throws CouldNotConnectException
* @throws JsonException
* @throws ClientException
* @throws OutOfOfficeParserException
* @throws ManageSieveException
*/
public function update(MailAccount $account, OutOfOfficeState $state): void {
$script = $this->sieveService->getActiveScript($account->getUserId(), $account->getId());
$oldState = $this->outOfOfficeParser->parseOutOfOfficeState($script->getScript());
$newScript = $this->outOfOfficeParser->buildSieveScript(
$state,
$oldState->getUntouchedSieveScript(),
$this->allowedRecipientsService->get($account),
);
try {
$this->sieveService->updateActiveScript($account->getUserId(), $account->getId(), $newScript);
} catch (ManageSieveException $e) {
$this->logger->error('Failed to save sieve script: ' . $e->getMessage(), [
'exception' => $e,
'script' => $newScript,
]);
throw $e;
}
}
/**
* Update a mail account's autoresponder from the out-of-office system setting of the corresponding user.
* Note: This method throws if the given account doesn't follow system out-of-office settings.
*
* @param MailAccount $mailAccount The mail account to update
* @param IUser $user The user the mail account belongs to
*
* @return OutOfOfficeState|null The new out-of-office state which has been applied
* @throws ClientException
* @throws CouldNotConnectException
* @throws JsonException
* @throws ManageSieveException
* @throws OutOfOfficeParserException
* @throws ServiceException
* @throws InvalidArgumentException If the given mail account doesn't follow out-of-office settings
*/
public function updateFromSystem(MailAccount $mailAccount, IUser $user): ?OutOfOfficeState {
if (!$mailAccount->getOutOfOfficeFollowsSystem()) {
throw new InvalidArgumentException('The mail account does not follow system out-of-office settings');
}
$userId = $user->getUID();
if ($mailAccount->getUserId() !== $userId) {
$accountId = $mailAccount->getId();
throw new ServiceException("Account $accountId doesn't belong to user $userId");
}
$state = null;
$now = $this->timeFactory->getTime();
$currentOutOfOfficeData = $this->availabilityCoordinator->getCurrentOutOfOfficeData($user);
if ($currentOutOfOfficeData !== null
&& $currentOutOfOfficeData->getStartDate() <= $now
&& $currentOutOfOfficeData->getEndDate() > $now) {
// In the middle of a running absence => enable auto responder
$state = new OutOfOfficeState(
true,
new DateTimeImmutable('@' . $currentOutOfOfficeData->getStartDate()),
new DateTimeImmutable('@' . $currentOutOfOfficeData->getEndDate()),
'Re: ${subject}',
$currentOutOfOfficeData->getMessage(),
);
$this->update($mailAccount, $state);
} else {
// Absence has not yet started or has already ended => disable auto responder
$this->disable($mailAccount);
}
return $state;
}
/**
* @throws ClientException
* @throws OutOfOfficeParserException
* @throws ManageSieveException
* @throws CouldNotConnectException
* @throws JsonException
*/
public function disable(MailAccount $account): void {
$state = $this->parseState($account)->getState();
if ($state === null || !$state->isEnabled()) {
return;
}
$state->setEnabled(false);
$this->update($account, $state);
}
}