From b1f6e45311b19c1af7ca463b9b2b5d0c22bd479d Mon Sep 17 00:00:00 2001 From: SebastianKrupinski Date: Thu, 16 May 2024 19:06:34 -0400 Subject: [PATCH] feat: mail provider backend Signed-off-by: SebastianKrupinski --- apps/dav/lib/CalDAV/Schedule/IMipPlugin.php | 82 +++-- apps/dav/lib/Server.php | 3 +- .../unit/CalDAV/Schedule/IMipPluginTest.php | 9 +- lib/composer/composer/autoload_classmap.php | 13 + lib/composer/composer/autoload_static.php | 13 + .../Bootstrap/RegistrationContext.php | 24 ++ lib/private/Mail/Provider/Manager.php | 255 +++++++++++++ lib/private/Server.php | 3 + .../Bootstrap/IRegistrationContext.php | 11 + lib/public/Mail/Provider/Address.php | 85 +++++ lib/public/Mail/Provider/Attachment.php | 139 +++++++ lib/public/Mail/Provider/IAddress.php | 61 ++++ lib/public/Mail/Provider/IAttachment.php | 101 ++++++ lib/public/Mail/Provider/IManager.php | 106 ++++++ lib/public/Mail/Provider/IMessage.php | 232 ++++++++++++ lib/public/Mail/Provider/IMessageSend.php | 31 ++ lib/public/Mail/Provider/IProvider.php | 130 +++++++ lib/public/Mail/Provider/IService.php | 150 ++++++++ lib/public/Mail/Provider/IServiceIdentity.php | 30 ++ lib/public/Mail/Provider/IServiceLocation.php | 30 ++ lib/public/Mail/Provider/Message.php | 338 ++++++++++++++++++ tests/lib/Mail/Provider/AddressTest.php | 46 +++ tests/lib/Mail/Provider/AttachmentTest.php | 71 ++++ tests/lib/Mail/Provider/ManagerTest.php | 189 ++++++++++ tests/lib/Mail/Provider/MessageTest.php | 163 +++++++++ 25 files changed, 2288 insertions(+), 27 deletions(-) create mode 100644 lib/private/Mail/Provider/Manager.php create mode 100644 lib/public/Mail/Provider/Address.php create mode 100644 lib/public/Mail/Provider/Attachment.php create mode 100644 lib/public/Mail/Provider/IAddress.php create mode 100644 lib/public/Mail/Provider/IAttachment.php create mode 100644 lib/public/Mail/Provider/IManager.php create mode 100644 lib/public/Mail/Provider/IMessage.php create mode 100644 lib/public/Mail/Provider/IMessageSend.php create mode 100644 lib/public/Mail/Provider/IProvider.php create mode 100644 lib/public/Mail/Provider/IService.php create mode 100644 lib/public/Mail/Provider/IServiceIdentity.php create mode 100644 lib/public/Mail/Provider/IServiceLocation.php create mode 100644 lib/public/Mail/Provider/Message.php create mode 100644 tests/lib/Mail/Provider/AddressTest.php create mode 100644 tests/lib/Mail/Provider/AttachmentTest.php create mode 100644 tests/lib/Mail/Provider/ManagerTest.php create mode 100644 tests/lib/Mail/Provider/MessageTest.php diff --git a/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php b/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php index ef506d1593c28..1958531630ade 100644 --- a/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php +++ b/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php @@ -15,6 +15,8 @@ use OCP\IConfig; use OCP\IUserSession; use OCP\Mail\IMailer; +use OCP\Mail\Provider\IManager as IMailManager; +use OCP\Mail\Provider\IMessageSend; use OCP\Util; use Psr\Log\LoggerInterface; use Sabre\CalDAV\Schedule\IMipPlugin as SabreIMipPlugin; @@ -55,6 +57,7 @@ class IMipPlugin extends SabreIMipPlugin { public const METHOD_CANCEL = 'cancel'; public const IMIP_INDENT = 15; // Enough for the length of all body bullet items, in all languages private EventComparisonService $eventComparisonService; + private IMailManager $mailManager; public function __construct(IConfig $config, IMailer $mailer, @@ -63,7 +66,8 @@ public function __construct(IConfig $config, Defaults $defaults, IUserSession $userSession, IMipService $imipService, - EventComparisonService $eventComparisonService) { + EventComparisonService $eventComparisonService, + IMailManager $mailManager) { parent::__construct(''); $this->userSession = $userSession; $this->config = $config; @@ -73,6 +77,7 @@ public function __construct(IConfig $config, $this->defaults = $defaults; $this->imipService = $imipService; $this->eventComparisonService = $eventComparisonService; + $this->mailManager = $mailManager; } public function initialize(DAV\Server $server): void { @@ -212,21 +217,6 @@ public function schedule(Message $iTipMessage) { $fromEMail = Util::getDefaultEmailAddress('invitations-noreply'); $fromName = $this->imipService->getFrom($senderName, $this->defaults->getName()); - $message = $this->mailer->createMessage() - ->setFrom([$fromEMail => $fromName]); - - if ($recipientName !== null) { - $message->setTo([$recipient => $recipientName]); - } else { - $message->setTo([$recipient]); - } - - if ($senderName !== null) { - $message->setReplyTo([$sender => $senderName]); - } else { - $message->setReplyTo([$sender]); - } - $template = $this->mailer->createEMailTemplate('dav.calendarInvite.' . $method, $data); $template->addHeader(); @@ -268,18 +258,60 @@ public function schedule(Message $iTipMessage) { } $template->addFooter(); - - $message->useTemplate($template); - + // convert iTip Message to string $itip_msg = $iTipMessage->message->serialize(); - $message->attachInline( - $itip_msg, - 'event.ics', - 'text/calendar; method=' . $iTipMessage->method, - ); + + $user = null; + $mailService = null; try { - $failed = $this->mailer->send($message); + // retrieve user object + $user = $this->userSession->getUser(); + // evaluate if user object exist + if ($user !== null) { + // retrieve appropriate service with the same address as sender + $mailService = $this->mailManager->findServiceByAddress($user->getUID(), $sender); + } + // evaluate if a mail service was found and has sending capabilities + if ($mailService !== null && $mailService instanceof IMessageSend) { + // construct mail message and set required parameters + $message = $mailService->initiateMessage(); + $message->setFrom( + (new \OCP\Mail\Provider\Address($sender, $fromName)) + ); + $message->setTo( + (new \OCP\Mail\Provider\Address($recipient, $recipientName)) + ); + $message->setSubject($template->renderSubject()); + $message->setBodyPlain($template->renderText()); + $message->setBodyHtml($template->renderHtml()); + $message->setAttachments((new \OCP\Mail\Provider\Attachment( + $itip_msg, + 'event.ics', + 'text/calendar; method=' . $iTipMessage->method, + true + ))); + // send message + $mailService->sendMessage($message); + } else { + // construct symfony mailer message and set required parameters + $message = $this->mailer->createMessage(); + $message->setFrom([$fromEMail => $fromName]); + $message->setTo( + (($recipientName !== null) ? [$recipient => $recipientName] : [$recipient]) + ); + $message->setReplyTo( + (($senderName !== null) ? [$sender => $senderName] : [$sender]) + ); + $message->useTemplate($template); + $message->attachInline( + $itip_msg, + 'event.ics', + 'text/calendar; method=' . $iTipMessage->method + ); + $failed = $this->mailer->send($message); + } + $iTipMessage->scheduleStatus = '1.1; Scheduling message is sent via iMip'; if (!empty($failed)) { $this->logger->error('Unable to deliver message to {failed}', ['app' => 'dav', 'failed' => implode(', ', $failed)]); diff --git a/apps/dav/lib/Server.php b/apps/dav/lib/Server.php index b2ffef27a9ddd..b09d47376e891 100644 --- a/apps/dav/lib/Server.php +++ b/apps/dav/lib/Server.php @@ -290,7 +290,8 @@ public function __construct(IRequest $request, string $baseUri) { \OC::$server->get(\OCP\Defaults::class), $userSession, \OC::$server->get(\OCA\DAV\CalDAV\Schedule\IMipService::class), - \OC::$server->get(\OCA\DAV\CalDAV\EventComparisonService::class) + \OC::$server->get(\OCA\DAV\CalDAV\EventComparisonService::class), + \OC::$server->get(\OCP\Mail\Provider\IManager::class) )); } $this->server->addPlugin(new \OCA\DAV\CalDAV\Search\SearchPlugin()); diff --git a/apps/dav/tests/unit/CalDAV/Schedule/IMipPluginTest.php b/apps/dav/tests/unit/CalDAV/Schedule/IMipPluginTest.php index eb6bd204bdd62..783e83ebc93ed 100644 --- a/apps/dav/tests/unit/CalDAV/Schedule/IMipPluginTest.php +++ b/apps/dav/tests/unit/CalDAV/Schedule/IMipPluginTest.php @@ -18,6 +18,7 @@ use OCP\Mail\IEMailTemplate; use OCP\Mail\IMailer; use OCP\Mail\IMessage; +use OCP\Mail\Provider\IManager as IMailManager; use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; use Sabre\VObject\Component\VCalendar; @@ -67,6 +68,9 @@ class IMipPluginTest extends TestCase { /** @var EventComparisonService|MockObject */ private $eventComparisonService; + /** @var MailManager|MockObject */ + private $mailManager; + protected function setUp(): void { $this->mailMessage = $this->createMock(IMessage::class); $this->mailMessage->method('setFrom')->willReturn($this->mailMessage); @@ -107,6 +111,8 @@ protected function setUp(): void { $this->eventComparisonService = $this->createMock(EventComparisonService::class); + $this->mailManager = $this->createMock(IMailManager::class); + $this->plugin = new IMipPlugin( $this->config, $this->mailer, @@ -115,7 +121,8 @@ protected function setUp(): void { $this->defaults, $this->userSession, $this->service, - $this->eventComparisonService + $this->eventComparisonService, + $this->mailManager, ); } diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 4ee453f026002..c64dba8c4c142 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -566,6 +566,18 @@ 'OCP\\Mail\\IEMailTemplate' => $baseDir . '/lib/public/Mail/IEMailTemplate.php', 'OCP\\Mail\\IMailer' => $baseDir . '/lib/public/Mail/IMailer.php', 'OCP\\Mail\\IMessage' => $baseDir . '/lib/public/Mail/IMessage.php', + 'OCP\\Mail\\Provider\\Address' => $baseDir . '/lib/public/Mail/Provider/Address.php', + 'OCP\\Mail\\Provider\\Attachment' => $baseDir . '/lib/public/Mail/Provider/Attachment.php', + 'OCP\\Mail\\Provider\\IAddress' => $baseDir . '/lib/public/Mail/Provider/IAddress.php', + 'OCP\\Mail\\Provider\\IAttachment' => $baseDir . '/lib/public/Mail/Provider/IAttachment.php', + 'OCP\\Mail\\Provider\\IManager' => $baseDir . '/lib/public/Mail/Provider/IManager.php', + 'OCP\\Mail\\Provider\\IMessage' => $baseDir . '/lib/public/Mail/Provider/IMessage.php', + 'OCP\\Mail\\Provider\\IMessageSend' => $baseDir . '/lib/public/Mail/Provider/IMessageSend.php', + 'OCP\\Mail\\Provider\\IProvider' => $baseDir . '/lib/public/Mail/Provider/IProvider.php', + 'OCP\\Mail\\Provider\\IService' => $baseDir . '/lib/public/Mail/Provider/IService.php', + 'OCP\\Mail\\Provider\\IServiceIdentity' => $baseDir . '/lib/public/Mail/Provider/IServiceIdentity.php', + 'OCP\\Mail\\Provider\\IServiceLocation' => $baseDir . '/lib/public/Mail/Provider/IServiceLocation.php', + 'OCP\\Mail\\Provider\\Message' => $baseDir . '/lib/public/Mail/Provider/Message.php', 'OCP\\Migration\\BigIntMigration' => $baseDir . '/lib/public/Migration/BigIntMigration.php', 'OCP\\Migration\\IMigrationStep' => $baseDir . '/lib/public/Migration/IMigrationStep.php', 'OCP\\Migration\\IOutput' => $baseDir . '/lib/public/Migration/IOutput.php', @@ -1605,6 +1617,7 @@ 'OC\\Mail\\EMailTemplate' => $baseDir . '/lib/private/Mail/EMailTemplate.php', 'OC\\Mail\\Mailer' => $baseDir . '/lib/private/Mail/Mailer.php', 'OC\\Mail\\Message' => $baseDir . '/lib/private/Mail/Message.php', + 'OC\\Mail\\Provider\\Manager' => $baseDir . '/lib/private/Mail/Provider/Manager.php', 'OC\\Memcache\\APCu' => $baseDir . '/lib/private/Memcache/APCu.php', 'OC\\Memcache\\ArrayCache' => $baseDir . '/lib/private/Memcache/ArrayCache.php', 'OC\\Memcache\\CADTrait' => $baseDir . '/lib/private/Memcache/CADTrait.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index d6cbb1ac886f4..7c340449fcdf5 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -599,6 +599,18 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Mail\\IEMailTemplate' => __DIR__ . '/../../..' . '/lib/public/Mail/IEMailTemplate.php', 'OCP\\Mail\\IMailer' => __DIR__ . '/../../..' . '/lib/public/Mail/IMailer.php', 'OCP\\Mail\\IMessage' => __DIR__ . '/../../..' . '/lib/public/Mail/IMessage.php', + 'OCP\\Mail\\Provider\\Address' => __DIR__ . '/../../..' . '/lib/public/Mail/Provider/Address.php', + 'OCP\\Mail\\Provider\\Attachment' => __DIR__ . '/../../..' . '/lib/public/Mail/Provider/Attachment.php', + 'OCP\\Mail\\Provider\\IAddress' => __DIR__ . '/../../..' . '/lib/public/Mail/Provider/IAddress.php', + 'OCP\\Mail\\Provider\\IAttachment' => __DIR__ . '/../../..' . '/lib/public/Mail/Provider/IAttachment.php', + 'OCP\\Mail\\Provider\\IManager' => __DIR__ . '/../../..' . '/lib/public/Mail/Provider/IManager.php', + 'OCP\\Mail\\Provider\\IMessage' => __DIR__ . '/../../..' . '/lib/public/Mail/Provider/IMessage.php', + 'OCP\\Mail\\Provider\\IMessageSend' => __DIR__ . '/../../..' . '/lib/public/Mail/Provider/IMessageSend.php', + 'OCP\\Mail\\Provider\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Mail/Provider/IProvider.php', + 'OCP\\Mail\\Provider\\IService' => __DIR__ . '/../../..' . '/lib/public/Mail/Provider/IService.php', + 'OCP\\Mail\\Provider\\IServiceIdentity' => __DIR__ . '/../../..' . '/lib/public/Mail/Provider/IServiceIdentity.php', + 'OCP\\Mail\\Provider\\IServiceLocation' => __DIR__ . '/../../..' . '/lib/public/Mail/Provider/IServiceLocation.php', + 'OCP\\Mail\\Provider\\Message' => __DIR__ . '/../../..' . '/lib/public/Mail/Provider/Message.php', 'OCP\\Migration\\BigIntMigration' => __DIR__ . '/../../..' . '/lib/public/Migration/BigIntMigration.php', 'OCP\\Migration\\IMigrationStep' => __DIR__ . '/../../..' . '/lib/public/Migration/IMigrationStep.php', 'OCP\\Migration\\IOutput' => __DIR__ . '/../../..' . '/lib/public/Migration/IOutput.php', @@ -1638,6 +1650,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Mail\\EMailTemplate' => __DIR__ . '/../../..' . '/lib/private/Mail/EMailTemplate.php', 'OC\\Mail\\Mailer' => __DIR__ . '/../../..' . '/lib/private/Mail/Mailer.php', 'OC\\Mail\\Message' => __DIR__ . '/../../..' . '/lib/private/Mail/Message.php', + 'OC\\Mail\\Provider\\Manager' => __DIR__ . '/../../..' . '/lib/private/Mail/Provider/Manager.php', 'OC\\Memcache\\APCu' => __DIR__ . '/../../..' . '/lib/private/Memcache/APCu.php', 'OC\\Memcache\\ArrayCache' => __DIR__ . '/../../..' . '/lib/private/Memcache/ArrayCache.php', 'OC\\Memcache\\CADTrait' => __DIR__ . '/../../..' . '/lib/private/Memcache/CADTrait.php', diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php index df03d59ebfafe..f59d5b557064b 100644 --- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php +++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php @@ -26,6 +26,7 @@ use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Template\ICustomTemplateProvider; use OCP\Http\WellKnown\IHandler; +use OCP\Mail\Provider\IProvider as IMailProvider; use OCP\Notification\INotifier; use OCP\Profile\ILinkAction; use OCP\Search\IProvider; @@ -148,6 +149,9 @@ class RegistrationContext { /** @var ServiceRegistration<\OCP\TaskProcessing\ITaskType>[] */ private array $taskProcessingTaskTypes = []; + + /** @var ServiceRegistration[] */ + private $mailProviders = []; public function __construct(LoggerInterface $logger) { $this->logger = $logger; @@ -411,6 +415,13 @@ public function registerTaskProcessingTaskType(string $taskProcessingTaskTypeCla $taskProcessingTaskTypeClass ); } + + public function registerMailProvider(string $class): void { + $this->context->registerMailProvider( + $this->appId, + $class + ); + } }; } @@ -603,6 +614,12 @@ public function registerTaskProcessingProvider(string $appId, string $taskProces public function registerTaskProcessingTaskType(string $appId, string $taskProcessingTaskTypeClass) { $this->taskProcessingTaskTypes[] = new ServiceRegistration($appId, $taskProcessingTaskTypeClass); } + /** + * @psalm-param class-string $migratorClass + */ + public function registerMailProvider(string $appId, string $class): void { + $this->mailProviders[] = new ServiceRegistration($appId, $class); + } /** * @param App[] $apps @@ -948,4 +965,11 @@ public function getTaskProcessingProviders(): array { public function getTaskProcessingTaskTypes(): array { return $this->taskProcessingTaskTypes; } + + /** + * @return ServiceRegistration[] + */ + public function getMailProviders(): array { + return $this->mailProviders; + } } diff --git a/lib/private/Mail/Provider/Manager.php b/lib/private/Mail/Provider/Manager.php new file mode 100644 index 0000000000000..bf5ae37321ccd --- /dev/null +++ b/lib/private/Mail/Provider/Manager.php @@ -0,0 +1,255 @@ +providers()); + + } + + /** + * Retrieve a count of how many mail providers are registered + * + * @since 30.0.0 + * + * @return int + */ + public function count(): int { + + // return count of providers in collection + return count($this->providers()); + + } + + /** + * Retrieve which mail providers are registered + * + * @since 30.0.0 + * + * @return array collection of provider id and label ['jmap' => 'JMap Connector'] + */ + public function types(): array { + + // construct types collection + $types = []; + // extract id and name from providers collection + foreach ($this->providers() as $entry) { + $types[$entry->id()] = $entry->label(); + } + // return types collection + return $types; + + } + + /** + * Retrieve all registered mail providers + * + * @since 30.0.0 + * + * @return array collection of provider id and object ['jmap' => IProviderObject] + */ + public function providers(): array { + + // evaluate if we already have a cached collection of providers and return the collection if we do + if (is_array($this->providersCollection)) { + return $this->providersCollection; + } + // retrieve server registration context + $context = $this->coordinator->getRegistrationContext(); + // evaluate if registration context was returned + if ($context === null) { + return []; + } + // initilize cached collection + $this->providersCollection = []; + // iterate through all registered mail providers + foreach ($context->getMailProviders() as $entry) { + try { + /** @var IProvider $provider */ + // object provider + $provider = $this->container->get($entry->getService()); + // add provider to cache collection + $this->providersCollection[$provider->id()] = $provider; + } catch (Throwable $e) { + $this->logger->error( + 'Could not load mail provider ' . $entry->getService() . ': ' . $e->getMessage(), + ['exception' => $e] + ); + } + } + // return mail provider collection + return $this->providersCollection; + + } + + /** + * Retrieve a provider with a specific id + * + * @since 30.0.0 + * + * @param string $providerId provider id + * + * @return IProvider|null + */ + public function findProviderById(string $id): IProvider | null { + + // evaluate if we already have a cached collection of providers + if (!is_array($this->providersCollection)) { + $this->providers(); + } + + if (isset($this->providersCollection[$id])) { + return $this->providersCollection[$id]; + } + // return null if provider was not found + return null; + + } + + /** + * Retrieve all services for all registered mail providers + * + * @since 30.0.0 + * + * @param string $userId user id + * + * @return array> collection of provider id, service id and object ['jmap' => ['Service1' => IServiceObject]] + */ + public function services(string $userId): array { + + // initilize collection + $services = []; + // retrieve and iterate through mail providers + foreach ($this->providers() as $entry) { + // retrieve collection of services + $mailServices = $entry->listServices($userId); + // evaluate if mail services collection is not empty and add results to services collection + if (!empty($mailServices)) { + $services[$entry->id()] = $mailServices; + } + } + // return collection + return $services; + + } + + /** + * Retrieve a service with a specific id + * + * @since 30.0.0 + * + * @param string $userId user id + * @param string $serviceId service id + * @param string $providerId provider id + * + * @return IService|null returns service object or null if none found + */ + public function findServiceById(string $userId, string $serviceId, ?string $providerId = null): IService | null { + + // evaluate if provider id was specified + if ($providerId !== null) { + // find provider + $provider = $this->findProviderById($providerId); + // evaluate if provider was found + if ($provider instanceof IProvider) { + // find service with specific id + $service = $provider->findServiceById($userId, $serviceId); + // evaluate if mail service was found + if ($service instanceof IService) { + return $service; + } + } + } else { + // retrieve and iterate through mail providers + foreach ($this->providers() as $provider) { + // find service with specific id + $service = $provider->findServiceById($userId, $serviceId); + // evaluate if mail service was found + if ($service instanceof IService) { + return $service; + } + } + } + + // return null if no match was found + return null; + + } + + /** + * Retrieve a service for a specific mail address + * returns first service with specific primary address + * + * @since 30.0.0 + * + * @param string $userId user id + * @param string $address mail address (e.g. test@example.com) + * @param string $providerId provider id + * + * @return IService|null returns service object or null if none found + */ + public function findServiceByAddress(string $userId, string $address, ?string $providerId = null): IService | null { + + // evaluate if provider id was specified + if ($providerId !== null) { + // find provider + $provider = $this->findProviderById($providerId); + // evaluate if provider was found + if ($provider instanceof IProvider) { + // find service with specific mail address + $service = $provider->findServiceByAddress($userId, $address); + // evaluate if mail service was found + if ($service instanceof IService) { + return $service; + } + } + } else { + // retrieve and iterate through mail providers + foreach ($this->providers() as $provider) { + // find service with specific mail address + $service = $provider->findServiceByAddress($userId, $address); + // evaluate if mail service was found + if ($service instanceof IService) { + return $service; + } + } + } + // return null if no match was found + return null; + + } +} diff --git a/lib/private/Server.php b/lib/private/Server.php index 4d549918a8fb1..fd12850a63681 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -1023,6 +1023,9 @@ public function __construct($webRoot, \OC\Config $config) { /** @deprecated 19.0.0 */ $this->registerDeprecatedAlias('Mailer', IMailer::class); + /** @since 30.0.0 */ + $this->registerAlias(\OCP\Mail\Provider\IManager::class, \OC\Mail\Provider\Manager::class); + /** @deprecated 21.0.0 */ $this->registerDeprecatedAlias('LDAPProvider', ILDAPProvider::class); diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php index b86f7bcd76d71..57e76f268d986 100644 --- a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php +++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php @@ -17,6 +17,7 @@ use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Template\ICustomTemplateProvider; use OCP\IContainer; +use OCP\Mail\Provider\IProvider as IMailProvider; use OCP\Notification\INotifier; use OCP\Preview\IProviderV2; use OCP\SpeechToText\ISpeechToTextProvider; @@ -412,4 +413,14 @@ public function registerTaskProcessingProvider(string $taskProcessingProviderCla * @since 30.0.0 */ public function registerTaskProcessingTaskType(string $taskProcessingTaskTypeClass): void; + + /** + * Register a mail provider + * + * @param string $class + * @psalm-param class-string $class + * @since 30.0.0 + */ + public function registerMailProvider(string $class): void; + } diff --git a/lib/public/Mail/Provider/Address.php b/lib/public/Mail/Provider/Address.php new file mode 100644 index 0000000000000..9cd2859a8a583 --- /dev/null +++ b/lib/public/Mail/Provider/Address.php @@ -0,0 +1,85 @@ +address = $value; + return $this; + } + + /** + * gets the mail address + * + * @since 30.0.0 + * + * @return string|null returns the mail address or null if one is not set + */ + public function getAddress(): string | null { + return $this->address; + } + + /** + * sets the mail address label/name + * + * @since 30.0.0 + * + * @param string $value mail address label/name + * + * @return self return this object for command chaining + */ + public function setLabel(string $value): self { + $this->label = $value; + return $this; + } + + /** + * gets the mail address label/name + * + * @since 30.0.0 + * + * @return string|null returns the mail address label/name or null if one is not set + */ + public function getLabel(): string | null { + return $this->label; + } + +} diff --git a/lib/public/Mail/Provider/Attachment.php b/lib/public/Mail/Provider/Attachment.php new file mode 100644 index 0000000000000..d7790a3bbc6d3 --- /dev/null +++ b/lib/public/Mail/Provider/Attachment.php @@ -0,0 +1,139 @@ +name = $value; + return $this; + } + + /** + * gets the attachment file name + * + * @since 30.0.0 + * + * @return string | null returns the attachment file name or null if not set + */ + public function getName(): string | null { + return $this->name; + } + + /** + * sets the attachment mime type + * + * @since 30.0.0 + * + * @param string $value mime type (e.g. text/plain) + * + * @return self return this object for command chaining + */ + public function setType(string $value): self { + $this->type = $value; + return $this; + } + + /** + * gets the attachment mime type + * + * @since 30.0.0 + * + * @return string | null returns the attachment mime type or null if not set + */ + public function getType(): string | null { + return $this->type; + } + + /** + * sets the attachment contents (actual data) + * + * @since 30.0.0 + * + * @param string $value binary contents of file + * + * @return self return this object for command chaining + */ + public function setContents(string $value): self { + $this->contents = $value; + return $this; + } + + /** + * gets the attachment contents (actual data) + * + * @since 30.0.0 + * + * @return string | null returns the attachment contents or null if not set + */ + public function getContents(): string | null { + return $this->contents; + } + + /** + * sets the embedded status of the attachment + * + * @since 30.0.0 + * + * @param bool $value true - embedded / false - not embedded + * + * @return self return this object for command chaining + */ + public function setEmbedded(bool $value): self { + $this->embedded = $value; + return $this; + } + + /** + * gets the embedded status of the attachment + * + * @since 30.0.0 + * + * @return bool embedded status of the attachment + */ + public function getEmbedded(): bool { + return $this->embedded; + } + +} diff --git a/lib/public/Mail/Provider/IAddress.php b/lib/public/Mail/Provider/IAddress.php new file mode 100644 index 0000000000000..b980f31150b37 --- /dev/null +++ b/lib/public/Mail/Provider/IAddress.php @@ -0,0 +1,61 @@ + collection of provider id and label ['jmap' => 'JMap Connector'] + */ + public function types(): array; + + /** + * retrieve all registered mail providers + * + * @since 30.0.0 + * + * @return array collection of provider id and object ['jmap' => IProviderObject] + */ + public function providers(): array; + + /** + * retrieve a provider with a specific id + * + * @since 30.0.0 + * + * @param string $providerId provider id + * + * @return IProvider|null + */ + public function findProviderById(string $providerId): IProvider | null; + + /** + * retrieve all services for all registered mail providers + * + * @since 30.0.0 + * + * @param string $userId user id + * + * @return array> collection of provider id, service id and object ['jmap' => ['Service1' => IServiceObject]] + */ + public function services(string $userId): array; + + /** + * retrieve a service with a specific id + * + * @since 30.0.0 + * + * @param string $userId user id + * @param string $serviceId service id + * @param string $providerId provider id + * + * @return IService|null returns service object or null if none found + */ + public function findServiceById(string $userId, string $serviceId, ?string $providerId = null): IService | null; + + /** + * retrieve a service for a specific mail address + * returns first service with specific primary address + * + * @since 30.0.0 + * + * @param string $userId user id + * @param string $address mail address (e.g. test@example.com) + * @param string $providerId provider id + * + * @return IService|null returns service object or null if none found + */ + public function findServiceByAddress(string $userId, string $address, ?string $providerId = null): IService | null; + +} diff --git a/lib/public/Mail/Provider/IMessage.php b/lib/public/Mail/Provider/IMessage.php new file mode 100644 index 0000000000000..b17ec0a4bc32d --- /dev/null +++ b/lib/public/Mail/Provider/IMessage.php @@ -0,0 +1,232 @@ +|null collection of all recipient mail address objects + */ + public function getTo(): array | null; + + /** + * sets the copy to recipient(s) of this message + * + * @since 30.0.0 + * + * @param IAddress ...$value collection of or one or more mail address objects + * + * @return self return this object for command chaining + */ + public function setCc(IAddress ...$value): self; + + /** + * gets the copy to recipient(s) of this message + * + * @since 30.0.0 + * + * @param array|null collection of all copied recipient mail address objects + */ + public function getCc(): array | null; + + /** + * sets the blind copy to recipient(s) of this message + * + * @since 30.0.0 + * + * @param IAddress ...$value collection of or one or more mail address objects + * + * @return self return this object for command chaining + */ + public function setBcc(IAddress ...$value): self; + + /** + * gets the blind copy to recipient(s) of this message + * + * @since 30.0.0 + * + * @param array|null collection of all blind copied recipient mail address objects + */ + public function getBcc(): array | null; + + /** + * sets the subject of this message + * + * @since 30.0.0 + * + * @param string $value subject of mail message + * + * @return self return this object for command chaining + */ + public function setSubject(string $value): self; + + /** + * gets the subject of this message + * + * @since 30.0.0 + * + * @param string|null subject of message or null if one is not set + */ + public function getSubject(): string | null; + + /** + * sets the plain text or html body of this message + * + * @since 30.0.0 + * + * @param string $value text or html body of message + * @param bool $html html flag - true for html + * + * @return self return this object for command chaining + */ + public function setBody(string $value, bool $html): self; + + /** + * gets either the html or plain text body of this message + * + * html body will be returned over plain text if html body exists + * + * @since 30.0.0 + * + * @param string|null html/plain body of this message or null if one is not set + */ + public function getBody(): string | null; + + /** + * sets the html body of this message + * + * @since 30.0.0 + * + * @param string $value html body of message + * + * @return self return this object for command chaining + */ + public function setBodyHtml(string $value): self; + + /** + * gets the html body of this message + * + * @since 30.0.0 + * + * @param string|null html body of this message or null if one is not set + */ + public function getBodyHtml(): string | null; + + /** + * sets the plain text body of this message + * + * @since 30.0.0 + * + * @param string $value plain text body of message + * + * @return self return this object for command chaining + */ + public function setBodyPlain(string $value): self; + + /** + * gets the plain text body of this message + * + * @since 30.0.0 + * + * @param string|null plain text body of this message or null if one is not set + */ + public function getBodyPlain(): string | null; + + /** + * sets the attachments of this message + * + * @since 30.0.0 + * + * @param IAttachment ...$value collection of or one or more mail attachment objects + * + * @return self return this object for command chaining + */ + public function setAttachments(IAttachment ...$value): self; + + /** + * gets the attachments of this message + * + * @since 30.0.0 + * + * @return array|null collection of all mail attachment objects + */ + public function getAttachments(): array | null; +} diff --git a/lib/public/Mail/Provider/IMessageSend.php b/lib/public/Mail/Provider/IMessageSend.php new file mode 100644 index 0000000000000..e68f18cf95cdf --- /dev/null +++ b/lib/public/Mail/Provider/IMessageSend.php @@ -0,0 +1,31 @@ + collection of service id and object ['1' => IServiceObject] + */ + public function listServices(string $userId): array; + + /** + * retrieve a service with a specific id + * + * @since 30.0.0 + * + * @param string $userId user id + * @param string $serviceId service id + * + * @return IService|null returns service object or null if none found + */ + public function findServiceById(string $userId, string $serviceId): IService | null; + + /** + * retrieve a service for a specific mail address + * + * @since 30.0.0 + * + * @param string $userId user id + * @param string $address mail address (e.g. test@example.com) + * + * @return IService|null returns service object or null if none found + */ + public function findServiceByAddress(string $userId, string $address): IService | null; + + /** + * construct a new empty service object + * + * @since 30.0.0 + * + * @return IService blank service object + */ + public function initiateService(): IService; + + /** + * Create a service configuration for a specific user + * + * @since 30.0.0 + * + * @param string $userId user id + * @param IService $service service object + * + * @return string id of created service + */ + public function createService(string $userId, IService $service): string; + + /** + * Modify a service configuration for a specific user + * + * @since 30.0.0 + * + * @param string $userId user id + * @param IService $service service object + * + * @return string id of modifided service + */ + public function modifyService(string $userId, IService $service): string; + + /** + * delete a service configuration for a specific user + * + * @since 30.0.0 + * + * @param string $userId user id + * @param IService $service service object + * + * @return bool status of delete action + */ + public function deleteService(string $userId, IService $service): bool; + +} diff --git a/lib/public/Mail/Provider/IService.php b/lib/public/Mail/Provider/IService.php new file mode 100644 index 0000000000000..65056418c6798 --- /dev/null +++ b/lib/public/Mail/Provider/IService.php @@ -0,0 +1,150 @@ + collection of mail address objects + */ + public function getSecondaryAddresses(): array; + + /** + * sets the secondary mailing addresses (aliases) for this service + * + * @since 30.0.0 + * + * @param IAddress ...$value collection of one or more mail address objects + * + * @return self return this object for command chaining + */ + public function setSecondaryAddresses(IAddress ...$value): self; + + /** + * construct a new empty message object + * + * @since 30.0.0 + * + * @return IMessage blank message object + */ + public function initiateMessage(): IMessage; + +} diff --git a/lib/public/Mail/Provider/IServiceIdentity.php b/lib/public/Mail/Provider/IServiceIdentity.php new file mode 100644 index 0000000000000..7b52dec9dcd44 --- /dev/null +++ b/lib/public/Mail/Provider/IServiceIdentity.php @@ -0,0 +1,30 @@ +data['id'])) ? $this->data['id'] : null; + } + + /** + * sets the sender of this message + * + * @since 30.0.0 + * + * @param IAddress $value sender's mail address object + * + * @return self return this object for command chaining + */ + public function setFrom(IAddress $value): self { + // create or update field in data store with value + $this->data['from'] = $value; + // return this object for command chaining + return $this; + } + + /** + * gets the sender of this message + * + * @since 30.0.0 + * + * @param IAddress|null sender's mail address object + */ + public function getFrom(): IAddress | null { + // evaluate if data store field exists and return value(s) or null otherwise + return (isset($this->data['from'])) ? $this->data['from'] : null; + } + + /** + * sets the sender's reply to address of this message + * + * @since 30.0.0 + * + * @param IAddress $value senders's reply to mail address object + * + * @return self return this object for command chaining + */ + public function setReplyTo(IAddress $value): self { + // create or update field in data store with value + $this->data['replyTo'] = $value; + // return this object for command chaining + return $this; + } + + /** + * gets the sender's reply to address of this message + * + * @since 30.0.0 + * + * @param IAddress|null sender's mail address object + */ + public function getReplyTo(): IAddress | null { + // evaluate if data store field exists and return value(s) or null otherwise + return (isset($this->data['replyTo'])) ? $this->data['replyTo'] : null; + } + + /** + * sets the recipient(s) of this message + * + * @since 30.0.0 + * + * @param IAddress ...$value collection of or one or more mail address objects + * + * @return self return this object for command chaining + */ + public function setTo(IAddress ...$value): self { + // create or update field in data store with value + $this->data['to'] = $value; + // return this object for command chaining + return $this; + } + + /** + * gets the recipient(s) of this message + * + * @since 30.0.0 + * + * @param array|null collection of all recipient mail address objects + */ + public function getTo(): array | null { + // evaluate if data store field exists and return value(s) or null otherwise + return (isset($this->data['to'])) ? $this->data['to'] : null; + } + + /** + * sets the copy to recipient(s) of this message + * + * @since 30.0.0 + * + * @param IAddress ...$value collection of or one or more mail address objects + * + * @return self return this object for command chaining + */ + public function setCc(IAddress ...$value): self { + // create or update field in data store with value + $this->data['cc'] = $value; + // return this object for command chaining + return $this; + } + + /** + * gets the copy to recipient(s) of this message + * + * @since 30.0.0 + * + * @param array|null collection of all copied recipient mail address objects + */ + public function getCc(): array | null { + // evaluate if data store field exists and return value(s) or null otherwise + return (isset($this->data['cc'])) ? $this->data['cc'] : null; + } + + /** + * sets the blind copy to recipient(s) of this message + * + * @since 30.0.0 + * + * @param IAddress ...$value collection of or one or more mail address objects + * + * @return self return this object for command chaining + */ + public function setBcc(IAddress ...$value): self { + // create or update field in data store with value + $this->data['bcc'] = $value; + // return this object for command chaining + return $this; + } + + /** + * gets the blind copy to recipient(s) of this message + * + * @since 30.0.0 + * + * @param array|null collection of all blind copied recipient mail address objects + */ + public function getBcc(): array | null { + // evaluate if data store field exists and return value(s) or null otherwise + return (isset($this->data['bcc'])) ? $this->data['bcc'] : null; + } + + /** + * sets the subject of this message + * + * @since 30.0.0 + * + * @param string $value subject of mail message + * + * @return self return this object for command chaining + */ + public function setSubject(string $value): self { + // create or update field in data store with value + $this->data['subject'] = $value; + // return this object for command chaining + return $this; + } + + /** + * gets the subject of this message + * + * @since 30.0.0 + * + * @param string|null subject of message or null if one is not set + */ + public function getSubject(): string | null { + // evaluate if data store field exists and return value(s) or null otherwise + return (isset($this->data['subject'])) ? $this->data['subject'] : null; + } + + /** + * sets the plain text or html body of this message + * + * @since 30.0.0 + * + * @param string $value text or html body of message + * @param bool $html html flag - true for html + * + * @return self return this object for command chaining + */ + public function setBody(string $value, bool $html = false): self { + // evaluate html flag and create or update appropriate field in data store with value + if ($html) { + $this->data['bodyHtml'] = $value; + } else { + $this->data['bodyPlain'] = $value; + } + // return this object for command chaining + return $this; + } + + /** + * gets either the html or plain text body of this message + * + * html body will be returned over plain text if html body exists + * + * @since 30.0.0 + * + * @param string|null html/plain body of this message or null if one is not set + */ + public function getBody(): string | null { + // evaluate if data store field(s) exists and return value + if (isset($this->data['bodyHtml'])) { + return $this->data['bodyHtml']; + } elseif (isset($this->data['bodyPlain'])) { + return $this->data['bodyPlain']; + } + // return null if data fields did not exist in data store + return null; + } + + /** + * sets the html body of this message + * + * @since 30.0.0 + * + * @param string $value html body of message + * + * @return self return this object for command chaining + */ + public function setBodyHtml(string $value): self { + // create or update field in data store with value + $this->data['bodyHtml'] = $value; + // return this object for command chaining + return $this; + } + + /** + * gets the html body of this message + * + * @since 30.0.0 + * + * @param string|null html body of this message or null if one is not set + */ + public function getBodyHtml(): string | null { + // evaluate if data store field exists and return value(s) or null otherwise + return (isset($this->data['bodyHtml'])) ? $this->data['bodyHtml'] : null; + } + + /** + * sets the plain text body of this message + * + * @since 30.0.0 + * + * @param string $value plain text body of message + * + * @return self return this object for command chaining + */ + public function setBodyPlain(string $value): self { + // create or update field in data store with value + $this->data['bodyPlain'] = $value; + // return this object for command chaining + return $this; + } + + /** + * gets the plain text body of this message + * + * @since 30.0.0 + * + * @param string|null plain text body of this message or null if one is not set + */ + public function getBodyPlain(): string | null { + // evaluate if data store field exists and return value(s) or null otherwise + return (isset($this->data['bodyPlain'])) ? $this->data['bodyPlain'] : null; + } + + /** + * sets the attachments of this message + * + * @since 30.0.0 + * + * @param IAttachment ...$value collection of or one or more mail attachment objects + * + * @return self return this object for command chaining + */ + public function setAttachments(IAttachment ...$value): self { + // create or update field in data store with value + $this->data['attachments'] = $value; + // return this object for command chaining + return $this; + } + + /** + * gets the attachments of this message + * + * @since 30.0.0 + * + * @return array collection of all mail attachment objects + */ + public function getAttachments(): array { + // evaluate if data store field exists and return value(s) or null otherwise + return (isset($this->data['attachments'])) ? $this->data['attachments'] : []; + } + +} diff --git a/tests/lib/Mail/Provider/AddressTest.php b/tests/lib/Mail/Provider/AddressTest.php new file mode 100644 index 0000000000000..5df22977bff2f --- /dev/null +++ b/tests/lib/Mail/Provider/AddressTest.php @@ -0,0 +1,46 @@ +address = new Address('user1@testing.com', 'User One'); + + } + + public function testAddress(): void { + + // test set by constructor + $this->assertEquals('user1@testing.com', $this->address->getAddress()); + // test set by setter + $this->address->setAddress('user2@testing.com'); + $this->assertEquals('user2@testing.com', $this->address->getAddress()); + + } + + public function testLabel(): void { + + // test set by constructor + $this->assertEquals('User One', $this->address->getLabel()); + // test set by setter + $this->address->setLabel('User Two'); + $this->assertEquals('User Two', $this->address->getLabel()); + + } + +} diff --git a/tests/lib/Mail/Provider/AttachmentTest.php b/tests/lib/Mail/Provider/AttachmentTest.php new file mode 100644 index 0000000000000..e5b254aacb96b --- /dev/null +++ b/tests/lib/Mail/Provider/AttachmentTest.php @@ -0,0 +1,71 @@ +attachment = new Attachment( + 'This is the contents of a file', + 'example1.txt', + 'text/plain', + false + ); + + } + + public function testName(): void { + + // test set by constructor + $this->assertEquals('example1.txt', $this->attachment->getName()); + // test set by setter + $this->attachment->setName('example2.txt'); + $this->assertEquals('example2.txt', $this->attachment->getName()); + + } + + public function testType(): void { + + // test set by constructor + $this->assertEquals('text/plain', $this->attachment->getType()); + // test set by setter + $this->attachment->setType('text/html'); + $this->assertEquals('text/html', $this->attachment->getType()); + + } + + public function testContents(): void { + + // test set by constructor + $this->assertEquals('This is the contents of a file', $this->attachment->getContents()); + // test set by setter + $this->attachment->setContents('This is the modified contents of a file'); + $this->assertEquals('This is the modified contents of a file', $this->attachment->getContents()); + + } + + public function testEmbedded(): void { + + // test set by constructor + $this->assertEquals(false, $this->attachment->getEmbedded()); + // test set by setter + $this->attachment->setEmbedded(true); + $this->assertEquals(true, $this->attachment->getEmbedded()); + + } + +} diff --git a/tests/lib/Mail/Provider/ManagerTest.php b/tests/lib/Mail/Provider/ManagerTest.php new file mode 100644 index 0000000000000..76ed953cfda20 --- /dev/null +++ b/tests/lib/Mail/Provider/ManagerTest.php @@ -0,0 +1,189 @@ +logger = $this->createMock(LoggerInterface::class); + + // construct service registration + $registration = $this->createMock(ServiceRegistration::class); + $registration + ->method('getService') + ->willReturn('Mock\Provider\MailProvider'); + // construct registration context + $context = $this->createMock(RegistrationContext::class); + $context + ->method('getMailProviders') + ->willReturn([$registration]); + // construct coordinator + $this->coordinator = $this->createMock(Coordinator::class); + $this->coordinator + ->method('getRegistrationContext') + ->willReturn($context); + + // construct mail service + $this->service = $this->createMock(IService::class); + $this->service + ->method('id') + ->willReturn('100'); + $this->service + ->method('getLabel') + ->willReturn('Mock Mail Service'); + $this->service + ->method('getPrimaryAddress') + ->willReturn((new Address('user1@testing.com', 'User One'))); + // construct mail provider + $this->provider = $this->createMock(IProvider::class); + $this->provider + ->method('id') + ->willReturn('mock-provider'); + $this->provider + ->method('label') + ->willReturn('Mock Provider'); + $this->provider + ->method('listServices') + ->willReturnMap([ + ['user0', []], + ['user1', [$this->service->id() => $this->service]] + ]); + $this->provider + ->method('findServiceById') + ->willReturnMap([ + ['user0', '100', null], + ['user1', '100', $this->service] + ]); + $this->provider + ->method('findServiceByAddress') + ->willReturnMap([ + ['user0', 'user0@testing.com', null], + ['user1', 'user1@testing.com', $this->service] + ]); + // construct container interface + $this->container = $this->createMock(ContainerInterface::class); + $this->container + ->method('get') + ->willReturnMap([ + ['Mock\Provider\MailProvider', $this->provider] + ]); + + } + + public function testHas(): void { + + // construct mail manager + $manager = new Manager($this->coordinator, $this->container, $this->logger); + // test result with providers found + $this->assertTrue($manager->has()); + + } + + public function testCount(): void { + + // construct mail manager + $manager = new Manager($this->coordinator, $this->container, $this->logger); + // test result with providers found + $this->assertGreaterThan(0, $manager->count()); + + } + + public function testTypes(): void { + + // construct mail manager + $manager = new Manager($this->coordinator, $this->container, $this->logger); + // test result with providers found + $this->assertEquals(['mock-provider' => 'Mock Provider'], $manager->types()); + + } + + public function testProviders(): void { + + // construct mail manager + $manager = new Manager($this->coordinator, $this->container, $this->logger); + // test result with providers found + $this->assertEquals([$this->provider->id() => $this->provider], $manager->providers()); + + } + + public function testFindProviderById(): void { + + // construct mail manager + $manager = new Manager($this->coordinator, $this->container, $this->logger); + // test result with providers found + $this->assertEquals($this->provider, $manager->findProviderById($this->provider->id())); + + } + + public function testServices(): void { + + // construct mail manager + $manager = new Manager($this->coordinator, $this->container, $this->logger); + // test result with no services found + $this->assertEquals([], $manager->services('user0')); + // test result with services found + $this->assertEquals([$this->provider->id() => [$this->service->id() => $this->service]], $manager->services('user1')); + + } + + public function testFindServiceById(): void { + + // construct mail manager + $manager = new Manager($this->coordinator, $this->container, $this->logger); + // test result with no services found and not provider specified + $this->assertEquals(null, $manager->findServiceById('user0', '100')); + // test result with no services found and provider specified + $this->assertEquals(null, $manager->findServiceById('user0', '100', $this->provider->id())); + // test result with services found and not provider specified + $this->assertEquals($this->service, $manager->findServiceById('user1', '100')); + // test result with services found and provider specified + $this->assertEquals($this->service, $manager->findServiceById('user1', '100', $this->provider->id())); + + } + + public function testFindServiceByAddress(): void { + + // construct mail manager + $manager = new Manager($this->coordinator, $this->container, $this->logger); + // test result with no services found and not provider specified + $this->assertEquals(null, $manager->findServiceByAddress('user0', 'user0@testing.com')); + // test result with no services found and provider specified + $this->assertEquals(null, $manager->findServiceByAddress('user0', 'user0@testing.com', $this->provider->id())); + // test result with services found and not provider specified + $this->assertEquals($this->service, $manager->findServiceByAddress('user1', 'user1@testing.com')); + // test result with services found and provider specified + $this->assertEquals($this->service, $manager->findServiceByAddress('user1', 'user1@testing.com', $this->provider->id())); + + } + +} diff --git a/tests/lib/Mail/Provider/MessageTest.php b/tests/lib/Mail/Provider/MessageTest.php new file mode 100644 index 0000000000000..546d1f87e32b6 --- /dev/null +++ b/tests/lib/Mail/Provider/MessageTest.php @@ -0,0 +1,163 @@ +message = new Message( + ['id' => 'cd02ea42-feac-4863-b9d8-484d16a587ea'] + ); + $this->address1 = new Address( + 'user1@testing.com', + 'User One' + ); + $this->address2 = new Address( + 'user2@testing.com', + 'User Two' + ); + $this->attachment1 = new Attachment( + 'This is the contents of the first attachment', + 'example1.txt', + 'text/plain', + false + ); + $this->attachment2 = new Attachment( + 'This is the contents of the second attachment', + 'example1.txt', + 'text/plain', + false + ); + + } + + public function testId(): void { + + // test set by constructor + $this->assertEquals('cd02ea42-feac-4863-b9d8-484d16a587ea', $this->message->id()); + + } + + public function testFrom(): void { + + // test not set + $this->assertNull($this->message->getFrom()); + // test set by setter + $this->message->setFrom($this->address1); + $this->assertEquals($this->address1, $this->message->getFrom()); + + } + + public function testReplyTo(): void { + + // test not set + $this->assertNull($this->message->getReplyTo()); + // test set by setter + $this->message->setReplyTo($this->address1); + $this->assertEquals($this->address1, $this->message->getReplyTo()); + + } + + public function testTo(): void { + + // test not set + $this->assertNull($this->message->getTo()); + // test set by setter single + $this->message->setTo($this->address1); + $this->assertEquals([$this->address1], $this->message->getTo()); + // test set by setter multiple + $this->message->setTo($this->address1, $this->address2); + $this->assertEquals([$this->address1, $this->address2], $this->message->getTo()); + + } + + public function testCc(): void { + + // test not set + $this->assertNull($this->message->getCc()); + // test set by setter single + $this->message->setCc($this->address1); + $this->assertEquals([$this->address1], $this->message->getCc()); + // test set by setter multiple + $this->message->setCc($this->address1, $this->address2); + $this->assertEquals([$this->address1, $this->address2], $this->message->getCc()); + + } + + public function testBcc(): void { + + // test not set + $this->assertNull($this->message->getBcc()); + // test set by setter single + $this->message->setBcc($this->address1); + $this->assertEquals([$this->address1], $this->message->getBcc()); + // test set by setter multiple + $this->message->setBcc($this->address1, $this->address2); + $this->assertEquals([$this->address1, $this->address2], $this->message->getBcc()); + + } + + public function testSubject(): void { + + // test not set + $this->assertNull($this->message->getSubject()); + // test set by setter + $this->message->setSubject('Testing Mail Subject'); + $this->assertEquals('Testing Mail Subject', $this->message->getSubject()); + + } + + public function testBody(): void { + + // test not set + $this->assertNull($this->message->getBody()); + // test set by setter - text body + $this->message->setBody('Testing Text Body', false); + $this->assertEquals('Testing Text Body', $this->message->getBody()); + $this->message->setBodyPlain('Testing Text Body Again', false); + $this->assertEquals('Testing Text Body Again', $this->message->getBodyPlain()); + // test set by setter - html body + $this->message->setBody('Testing HTML Body', true); + $this->assertEquals('Testing HTML Body', $this->message->getBody()); + $this->message->setBodyHtml('Testing HTML Body Again', false); + $this->assertEquals('Testing HTML Body Again', $this->message->getBodyHtml()); + + } + + public function testAttachments(): void { + + // test not set + $this->assertEquals([], $this->message->getAttachments()); + // test set by setter single + $this->message->setAttachments($this->attachment1); + $this->assertEquals([$this->attachment1], $this->message->getAttachments()); + // test set by setter multiple + $this->message->setAttachments($this->attachment1, $this->attachment2); + $this->assertEquals([$this->attachment1, $this->attachment2], $this->message->getAttachments()); + + } +}