Skip to content

Commit

Permalink
feat: mail provider backend
Browse files Browse the repository at this point in the history
Signed-off-by: SebastianKrupinski <[email protected]>
  • Loading branch information
SebastianKrupinski committed Sep 8, 2024
1 parent 9d2deda commit 7f85f0d
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 79 deletions.
59 changes: 36 additions & 23 deletions lib/Provider/Command/MessageSend.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@
namespace OCA\Mail\Provider\Command;

use OCA\Mail\Db\LocalMessage;
use OCA\Mail\Exception\ClientException;
use OCA\Mail\Exception\UploadException;
use OCA\Mail\Service\AccountService;
use OCA\Mail\Service\Attachment\AttachmentService;
use OCA\Mail\Service\OutboxService;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
use OCP\Mail\Provider\Exception\SendException;
use OCP\Mail\Provider\IAddress;
use OCP\Mail\Provider\IMessage;

class MessageSend {

public function __construct(
protected IConfig $config,
protected ITimeFactory $time,
protected AccountService $accountService,
protected OutboxService $outboxService,
Expand Down Expand Up @@ -66,7 +66,7 @@ public function perform(string $userId, string $serviceId, IMessage $message, ar
// retrieve user mail account details
try {
$account = $this->accountService->find($userId, (int)$serviceId);
} catch (\Throwable $e) {
} catch (ClientException $e) {
throw new SendException('Error: occurred while retrieving mail account details', 0, $e);
}
// convert mail provider message to mail app message
Expand All @@ -79,29 +79,26 @@ public function perform(string $userId, string $serviceId, IMessage $message, ar
//$localMessage->setEditorBody($message->getBody());
$localMessage->setHtml(true);
$localMessage->setSendAt($this->time->getTime());
// convert all mail provider attachments to local attachments
// convert mail provider addresses to recipient addresses
$to = $this->convertAddressArray($message->getTo());
$cc = $this->convertAddressArray($message->getCc());
$bcc = $this->convertAddressArray($message->getBcc());
// save attachments
$attachments = [];
if (count($message->getAttachments()) > 0) {
// iterate attachments and save them
try {
foreach ($message->getAttachments() as $entry) {
// convert mail provider attachment to mail app attachment
try {
$attachments[] = $this->attachmentService->addFileFromString(
$userId,
(string)$entry->getName(),
(string)$entry->getType(),
(string)$entry->getContents()
)->jsonSerialize();
} catch (\Throwable $e) {
throw new SendException('Error: occurred while saving mail message attachment', 0, $e);
}
$attachments[] = $this->attachmentService->addFileFromString(
$userId,
(string)$entry->getName(),
(string)$entry->getType(),
(string)$entry->getContents()
)->jsonSerialize();
}
} catch (UploadException $e) {
$this->purgeSavedAttachments($attachments);
throw new SendException('Error: occurred while saving mail message attachment', 0, $e);
}
// convert recipient addresses
$to = $this->convertAddressArray($message->getTo());
$cc = $this->convertAddressArray($message->getCc());
$bcc = $this->convertAddressArray($message->getBcc());
// save message for sending
// save message
try {
$localMessage = $this->outboxService->saveMessage(
$account,
Expand All @@ -112,6 +109,7 @@ public function perform(string $userId, string $serviceId, IMessage $message, ar
$attachments
);
} catch (\Throwable $e) {
$this->purgeSavedAttachments($attachments);
throw new SendException('Error: occurred while saving mail message', 0, $e);
}
// send message
Expand All @@ -131,7 +129,7 @@ public function perform(string $userId, string $serviceId, IMessage $message, ar
*
* @param array<int,IAddress> $addresses collection of IAddress objects
*
* @return array collection of addresses and labels e.g. [[email => '[email protected]', 'User One']]
* @return array<int, array{email: string, label?: string}> collection of addresses and labels

Check failure on line 132 in lib/Provider/Command/MessageSend.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

MoreSpecificReturnType

lib/Provider/Command/MessageSend.php:132:13: MoreSpecificReturnType: The declared return type 'array<int, array{email: string, label?: string}>' for OCA\Mail\Provider\Command\MessageSend::convertAddressArray is more specific than the inferred return type 'array<int, array{email: null|string, label?: null|string}>' (see https://psalm.dev/070)
*/
protected function convertAddressArray(array $addresses): array {
return array_map(static function (IAddress $address) {

Check failure on line 135 in lib/Provider/Command/MessageSend.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

LessSpecificReturnStatement

lib/Provider/Command/MessageSend.php:135:10: LessSpecificReturnStatement: The type 'array<int, array{email: null|string, label?: null|string}>' is more general than the declared return type 'array<int, array{email: string, label?: string}>' for OCA\Mail\Provider\Command\MessageSend::convertAddressArray (see https://psalm.dev/129)
Expand All @@ -141,4 +139,19 @@ protected function convertAddressArray(array $addresses): array {
}, $addresses);
}

/**
*
*
* @since 4.0.0
*
* @param array
*
* @return array

Check failure on line 149 in lib/Provider/Command/MessageSend.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

MismatchingDocblockReturnType

lib/Provider/Command/MessageSend.php:149:13: MismatchingDocblockReturnType: Docblock has incorrect return type 'array<array-key, mixed>', should be 'void' (see https://psalm.dev/142)

Check failure on line 149 in lib/Provider/Command/MessageSend.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

InvalidReturnType

lib/Provider/Command/MessageSend.php:149:13: InvalidReturnType: No return statements were found for method OCA\Mail\Provider\Command\MessageSend::purgeSavedAttachments but return type 'array<array-key, mixed>' was expected (see https://psalm.dev/011)
*/
protected function purgeSavedAttachments(array $attachments): void {

Check failure on line 151 in lib/Provider/Command/MessageSend.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

InvalidDocblock

lib/Provider/Command/MessageSend.php:151:2: InvalidDocblock: Badly-formatted @param in docblock for OCA\Mail\Provider\Command\MessageSend::purgeSavedAttachments (see https://psalm.dev/008)
foreach ($attachments as $attachment) {
$this->attachmentService->deleteAttachment($attachment->getUserId(), $attachment->getId());
}
}

}
17 changes: 4 additions & 13 deletions lib/Provider/MailProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace OCA\Mail\Provider;

use OCA\Mail\Account;
use OCA\Mail\Exception\ClientException;
use OCA\Mail\Service\AccountService;
use OCP\IL10N;
use OCP\Mail\Provider\Address as MailAddress;
Expand Down Expand Up @@ -73,12 +74,7 @@ public function hasServices(string $userId): bool {
*/
public function listServices(string $userId): array {
// retrieve service(s) details from data store
try {
$accounts = $this->accountService->findByUserId($userId);
} catch (\Throwable $e) {
$this->logger->error('Error occurred while retrieving mail account details', [ 'exception' => $e ]);
return [];
}
$accounts = $this->accountService->findByUserId($userId);
// construct temporary collection
$services = [];
// add services to collection
Expand Down Expand Up @@ -108,7 +104,7 @@ public function findServiceById(string $userId, string $serviceId): IService|nul
// retrieve service details from data store
try {
$account = $this->accountService->find($userId, (int)$serviceId);
} catch(\Throwable $e) {
} catch(ClientException $e) {
$this->logger->error('Error occurred while retrieving mail account details', [ 'exception' => $e ]);
return null;
}
Expand All @@ -128,12 +124,7 @@ public function findServiceById(string $userId, string $serviceId): IService|nul
*/
public function findServiceByAddress(string $userId, string $address): IService|null {
// retrieve service details from data store
try {
$accounts = $this->accountService->findByUserIdAndAddress($userId, $address);
} catch(\Throwable $e) {
$this->logger->error('Error occurred while retrieving mail account details', [ 'exception' => $e ]);
return null;
}
$accounts = $this->accountService->findByUserIdAndAddress($userId, $address);
// evaluate if service details where found
if (count($accounts) > 0) {
// return mail service object
Expand Down
13 changes: 7 additions & 6 deletions tests/Unit/Provider/Command/MessageSendTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
use OCA\Mail\Db\LocalAttachment;
use OCA\Mail\Db\LocalMessage;
use OCA\Mail\Db\MailAccount;
use OCA\Mail\Exception\ClientException;
use OCA\Mail\Exception\UploadException;
use OCA\Mail\Provider\Command\MessageSend;
use OCA\Mail\Service\AccountService;
use OCA\Mail\Service\Attachment\AttachmentService;
use OCA\Mail\Service\OutboxService;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
use OCP\Mail\Provider\Address;
use OCP\Mail\Provider\Attachment;
use OCP\Mail\Provider\Exception\SendException;
Expand All @@ -32,18 +33,18 @@ class MessageSendTest extends TestCase {
private AccountService&MockObject $accountService;
private OutboxService&MockObject $outboxService;
private AttachmentService&MockObject $attachmentService;
private $commandSend;
private MessageSend $commandSend;
private Message $mailMessage;

protected function setUp(): void {
parent::setUp();
// construct mock constructor parameters
$this->config = $this->createMock(IConfig::class);
$this->time = $this->createMock(ITimeFactory::class);
$this->accountService = $this->createMock(AccountService::class);
$this->outboxService = $this->createMock(OutboxService::class);
$this->attachmentService = $this->createMock(AttachmentService::class);
// construct test object
$this->commandSend = new MessageSend($this->config, $this->time, $this->accountService, $this->outboxService, $this->attachmentService);
$this->commandSend = new MessageSend($this->time, $this->accountService, $this->outboxService, $this->attachmentService);
// construct mail provider attachment
$this->mailAttachment = new Attachment(
'This is the contents of our plan',
Expand Down Expand Up @@ -229,7 +230,7 @@ public function testPerformWithAccountServiceFailure(): void {
$this->time->method('getTime')->willReturn(1719792000);
// define account service returns
$this->accountService->method('find')->will(
$this->throwException(new \Exception('Something went wrong'))
$this->throwException(new ClientException('Something went wrong'))
);

// construct mail provider message
Expand Down Expand Up @@ -258,7 +259,7 @@ public function testPerformWithAttachmentServiceFailure(): void {
$this->mailAttachment->getType(),
$this->mailAttachment->getContents()
)->will(
$this->throwException(new \Exception('Something went wrong'))
$this->throwException(new UploadException('Something went wrong'))
);
// construct mail provider message with attachment
$mailMessage = $this->mailMessage;
Expand Down
58 changes: 21 additions & 37 deletions tests/Unit/Provider/MailProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,12 @@ public function testHasServices(): void {
'smtpUser' => '',
]));
// define account services find
$this->accountService
->expects($this->any())
->method('findByUserId')
$this->accountService->expects($this->any())->method('findByUserId')
->will(
$this->returnValueMap(
[
['user0', []],
['user1', [100 => $mailAccount]]
]
)
$this->returnValueMap([
['user0', []],
['user1', [100 => $mailAccount]]
])
);
// construct mail provider
$mailProvider = new MailProvider($this->containerInterface, $this->accountService, $this->logger, $this->l10n);
Expand Down Expand Up @@ -121,16 +117,12 @@ public function testListServices(): void {
new MailAddress('[email protected]', 'User One')
);
// define account services find
$this->accountService
->expects($this->any())
->method('findByUserId')
$this->accountService->expects($this->any())->method('findByUserId')
->will(
$this->returnValueMap(
[
['user0', []],
['user1', [$mailAccount]]
]
)
$this->returnValueMap([
['user0', []],
['user1', [$mailAccount]]
])
);
// construct mail provider
$mailProvider = new MailProvider($this->containerInterface, $this->accountService, $this->logger, $this->l10n);
Expand Down Expand Up @@ -166,16 +158,12 @@ public function testFindServiceById(): void {
new MailAddress('[email protected]', 'User One')
);
// define account services find
$this->accountService
->expects($this->any())
->method('find')
->will(
$this->returnValueMap(
[
['user0', 100, $this->throwException(new ClientException())],
['user1', 100, $mailAccount]
]
)
$this->accountService->expects($this->any())->method('find')
->willReturnCallback(
fn (string $userId, int $serviceId) => match (true) {
$userId === 'user1' && $serviceId === 100 => $mailAccount,
default => throw new ClientException()
}
);
// construct mail provider
$mailProvider = new MailProvider($this->containerInterface, $this->accountService, $this->logger, $this->l10n);
Expand Down Expand Up @@ -211,16 +199,12 @@ public function testFindServiceByAddress(): void {
new MailAddress('[email protected]', 'User One')
);
// define account services find
$this->accountService
->expects($this->any())
->method('findByUserIdAndAddress')
$this->accountService->expects($this->any())->method('findByUserIdAndAddress')
->will(
$this->returnValueMap(
[
['user0', '[email protected]', $this->throwException(new ClientException())],
['user1', '[email protected]', [$mailAccount]]
]
)
$this->returnValueMap([
['user0', '[email protected]', []],
['user1', '[email protected]', [$mailAccount]]
])
);
// construct mail provider
$mailProvider = new MailProvider($this->containerInterface, $this->accountService, $this->logger, $this->l10n);
Expand Down

0 comments on commit 7f85f0d

Please sign in to comment.