← Back
Editing: SubmitContentJob.php
<?php declare(strict_types=1); /** * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\Mail\BackgroundJob\ContextChat; use OCA\Mail\ContextChat\ContextChatProvider; use OCA\Mail\Db\MailboxMapper; use OCA\Mail\Db\Message; use OCA\Mail\Db\MessageMapper; use OCA\Mail\Exception\ServiceException; use OCA\Mail\Exception\SmimeDecryptException; use OCA\Mail\IMAP\IMAPClientFactory; use OCA\Mail\Service\AccountService; use OCA\Mail\Service\ContextChat\TaskService; use OCA\Mail\Service\MailManager; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\IJob; use OCP\BackgroundJob\TimedJob; use OCP\ContextChat\ContentItem; use OCP\ContextChat\IContentManager; use OCP\DB\Exception; use Psr\Log\LoggerInterface; class SubmitContentJob extends TimedJob { public function __construct( ITimeFactory $time, private TaskService $taskService, private AccountService $accountService, private MailManager $mailManager, private MessageMapper $messageMapper, private IMAPClientFactory $clientFactory, private ContextChatProvider $contextChatProvider, private IContentManager $contentManager, private LoggerInterface $logger, private MailboxMapper $mailboxMapper, ) { parent::__construct($time); $this->setAllowParallelRuns(false); $this->setInterval(ContextChatProvider::CONTEXT_CHAT_JOB_INTERVAL); $this->setTimeSensitivity(IJob::TIME_INSENSITIVE); } #[\Override] protected function run($argument): void { if (!$this->contentManager->isContextChatAvailable()) { return; } try { $task = $this->taskService->findNext(); } catch (Exception $e) { $this->logger->warning('Exception occurred when trying to fetch next task', ['exception' => $e]); return; } catch (DoesNotExistException $e) { // nothing to be done, let's defer to the next iteration of this job return; } catch (MultipleObjectsReturnedException $e) { $this->logger->warning('Multiple tasks found for context chat. This is unexpected.', ['exception' => $e]); return; } try { $mailbox = $this->mailboxMapper->findById($task->getMailboxId()); } catch (ServiceException $e) { $this->logger->warning('Multiple mailboxes found for context chat task, but only one expected. ERROR!', ['exception' => $e]); return; } catch (DoesNotExistException $e) { // mailbox does not exist, lets wait for this task to be removed return; } $processMailsAfter = $this->time->getTime() - ContextChatProvider::CONTEXT_CHAT_MESSAGE_MAX_AGE; $messageIds = $this->messageMapper->findIdsAfter($mailbox, $task->getLastMessageId(), $processMailsAfter, ContextChatProvider::CONTEXT_CHAT_IMPORT_MAX_ITEMS); if (empty($messageIds)) { try { $this->taskService->delete($task->getId()); } catch (MultipleObjectsReturnedException|Exception $e) { $this->logger->warning('Exception occurred when trying to delete task', ['exception' => $e]); } return; } try { $account = $this->accountService->findById($mailbox->getAccountId()); } catch (DoesNotExistException $e) { // well, what do you know. Then let's just skip this and wait for the next iteration of this job. tasks should be cascade deleted anyway return; } $messages = $this->messageMapper->findByIds($account->getUserId(), $messageIds, 'asc', 'id'); if (empty($messages)) { try { $this->taskService->delete($task->getId()); } catch (MultipleObjectsReturnedException|Exception $e) { $this->logger->warning('Exception occurred when trying to delete task', ['exception' => $e]); } return; } $client = $this->clientFactory->getClient($account); $items = []; try { $startTime = $this->time->getTime(); foreach ($messages as $message) { if ($this->time->getTime() - $startTime > ContextChatProvider::CONTEXT_CHAT_JOB_INTERVAL) { break; } try { $imapMessage = $this->mailManager->getImapMessage($client, $account, $mailbox, $message->getUid(), true); } catch (ServiceException $e) { // couldn't load message, let's skip it. Retrying would be too costly continue; } catch (SmimeDecryptException $e) { // encryption problem, skip this message continue; } // Skip encrypted messages if ($imapMessage->isEncrypted()) { continue; } $fullMessage = $imapMessage->getFullMessage($imapMessage->getUid(), true); $items[] = new ContentItem( "{$mailbox->getId()}:{$message->getId()}", $this->contextChatProvider->getId(), $imapMessage->getSubject(), $fullMessage['body'] ?? '', 'E-Mail', $imapMessage->getSentDate(), [$account->getUserId()], ); } } catch (\Throwable $e) { $this->logger->warning('Exception occurred when trying to fetch messages for context chat', ['exception' => $e]); } finally { try { $client->close(); } catch (\Horde_Imap_Client_Exception $e) { $this->logger->debug('Failed to close IMAP client', ['exception' => $e]); } } if (count($items) > 0) { $this->contentManager->submitContent($this->contextChatProvider->getAppId(), $items); } try { $this->taskService->setLastMessage($task->getMailboxId(), $message?->getId() ?? $messageIds[0]); } catch (MultipleObjectsReturnedException|Exception $e) { $this->logger->warning('Exception occurred when trying to update task', ['exception' => $e]); } } }
Save File
Cancel