diff --git a/application/Espo/Classes/MassAction/Email/MoveToFolder.php b/application/Espo/Classes/MassAction/Email/MoveToFolder.php index 845b0fe9ce..b5d748f0eb 100644 --- a/application/Espo/Classes/MassAction/Email/MoveToFolder.php +++ b/application/Espo/Classes/MassAction/Email/MoveToFolder.php @@ -41,7 +41,7 @@ use Espo\Entities\EmailFolder; use Espo\Entities\GroupEmailFolder; use Espo\Entities\User; use Espo\ORM\EntityManager; -use Espo\Tools\Email\Service as EmailService; +use Espo\Tools\Email\InboxService as EmailService; use Exception; class MoveToFolder implements MassAction diff --git a/application/Espo/Controllers/Email.php b/application/Espo/Controllers/Email.php index d7609a681c..ab2d3a755f 100644 --- a/application/Espo/Controllers/Email.php +++ b/application/Espo/Controllers/Email.php @@ -40,10 +40,11 @@ use Espo\Core\Api\Request; use Espo\Core\Mail\SmtpParams; use Espo\Entities\Email as EmailEntity; -use Espo\Services\Email as Service; +use Espo\Tools\Attachment\FieldData; use Espo\Tools\Email\SendService; -use Espo\Tools\Email\Service as ToolService; +use Espo\Tools\Email\InboxService as InboxService; +use Espo\Tools\Email\Service; use Espo\Tools\Email\TestSendData; use Espo\Tools\EmailTemplate\InsertField\Service as InsertFieldService; use stdClass; @@ -59,15 +60,45 @@ class Email extends Record { $data = $request->getParsedBody(); - if (empty($data->id)) { - throw new BadRequest(); + $id = $data->id ?? null; + $field = $data->field ?? null; + $parentType = $data->parentType ?? null; + $relatedType = $data->relatedType ?? null; + + if (!$id || !$field) { + throw new BadRequest("No `id` or `field`."); } - $id = $data->id; - $parentType = $data->parentType ?? null; - $field = $data->field ?? null; + try { + $fieldData = new FieldData( + $field, + $parentType, + $relatedType + ); + } + catch (Error $e) { + throw new BadRequest($e->getMessage()); + } - return $this->getEmailService()->getCopiedAttachments($id, $parentType, null, $field); + $list = $this->injectableFactory + ->create(Service::class) + ->copyAttachments($id, $fieldData); + + $ids = array_map( + fn ($item) => $item->getId(), + $list + ); + + $names = (object) []; + + foreach ($list as $item) { + $names->{$item->getId()} = $item->getName(); + } + + return (object) [ + 'ids' => $ids, + 'names' => $names, + ]; } /** @@ -151,7 +182,7 @@ class Email extends Record } } - $this->getEmailToolService()->markAsReadIdList($idList); + $this->getInboxService()->markAsReadIdList($idList); return true; } @@ -175,14 +206,14 @@ class Email extends Record } } - $this->getEmailToolService()->markAsNotReadIdList($idList); + $this->getInboxService()->markAsNotReadIdList($idList); return true; } public function postActionMarkAllAsRead(): bool { - $this->getEmailToolService()->markAllAsRead(); + $this->getInboxService()->markAllAsRead(); return true; } @@ -206,7 +237,7 @@ class Email extends Record } } - $this->getEmailToolService()->markAsImportantIdList($idList); + $this->getInboxService()->markAsImportantIdList($idList); return true; } @@ -230,7 +261,7 @@ class Email extends Record } } - $this->getEmailToolService()->markAsNotImportantIdList($idList); + $this->getInboxService()->markAsNotImportantIdList($idList); return true; } @@ -254,7 +285,7 @@ class Email extends Record } } - $this->getEmailToolService()->moveToTrashIdList($idList); + $this->getInboxService()->moveToTrashIdList($idList); return true; } @@ -278,14 +309,14 @@ class Email extends Record } } - $this->getEmailToolService()->retrieveFromTrashIdList($idList); + $this->getInboxService()->retrieveFromTrashIdList($idList); return true; } public function getActionGetFoldersNotReadCounts(): stdClass { - return (object) $this->getEmailToolService()->getFoldersNotReadCounts(); + return (object) $this->getInboxService()->getFoldersNotReadCounts(); } /** @@ -312,13 +343,13 @@ class Email extends Record } if (count($idList) === 1) { - $this->getEmailToolService()->moveToFolder($idList[0], $data->folderId); + $this->getInboxService()->moveToFolder($idList[0], $data->folderId); return true; } - $this->getEmailToolService()->moveToFolderIdList($idList, $data->folderId); + $this->getInboxService()->moveToFolderIdList($idList, $data->folderId); return true; } @@ -341,19 +372,13 @@ class Email extends Record ); } - private function getEmailToolService(): ToolService + private function getInboxService(): InboxService { - return $this->injectableFactory->create(ToolService::class); + return $this->injectableFactory->create(InboxService::class); } private function getSendService(): SendService { return $this->injectableFactory->create(SendService::class); } - - private function getEmailService(): Service - { - /** @var Service */ - return $this->getRecordService(); - } } diff --git a/application/Espo/Entities/Email.php b/application/Espo/Entities/Email.php index 1fe076844a..9d9a58b010 100644 --- a/application/Espo/Entities/Email.php +++ b/application/Espo/Entities/Email.php @@ -605,6 +605,15 @@ class Email extends Entity return $this->getValueObject('replied'); } + /** + * @return string[] + */ + public function getAttachmentIdList(): array + { + /** @var string[] */ + return $this->getLinkMultipleIdList('attachments'); + } + private function getEmailRepository(): EmailRepository { if (!$this->entityManager) { diff --git a/application/Espo/Entities/EmailTemplate.php b/application/Espo/Entities/EmailTemplate.php index 3cb95dd137..49449a8f56 100644 --- a/application/Espo/Entities/EmailTemplate.php +++ b/application/Espo/Entities/EmailTemplate.php @@ -49,4 +49,13 @@ class EmailTemplate extends Entity { return (bool) $this->get('isHtml'); } + + /** + * @return string[] + */ + public function getAttachmentIdList(): array + { + /** @var string[] */ + return $this->getLinkMultipleIdList('attachments'); + } } diff --git a/application/Espo/Modules/Crm/Entities/CaseObj.php b/application/Espo/Modules/Crm/Entities/CaseObj.php index 95271a0bd9..e685714131 100644 --- a/application/Espo/Modules/Crm/Entities/CaseObj.php +++ b/application/Espo/Modules/Crm/Entities/CaseObj.php @@ -98,4 +98,13 @@ class CaseObj extends \Espo\Core\ORM\Entity /** @var LinkMultiple */ return $this->getValueObject('teams'); } + + /** + * @return string[] + */ + public function getAttachmentIdList(): array + { + /** @var string[] */ + return $this->getLinkMultipleIdList('attachments'); + } } diff --git a/application/Espo/Modules/Crm/Entities/Task.php b/application/Espo/Modules/Crm/Entities/Task.php index 04a0455b19..a873006f89 100644 --- a/application/Espo/Modules/Crm/Entities/Task.php +++ b/application/Espo/Modules/Crm/Entities/Task.php @@ -84,4 +84,13 @@ class Task extends Entity /** @var LinkMultiple */ return $this->getValueObject('teams'); } + + /** + * @return string[] + */ + public function getAttachmentIdList(): array + { + /** @var string[] */ + return $this->getLinkMultipleIdList('attachments'); + } } diff --git a/application/Espo/Services/Email.php b/application/Espo/Services/Email.php index f1a1e6ce1b..b41379e003 100644 --- a/application/Espo/Services/Email.php +++ b/application/Espo/Services/Email.php @@ -30,20 +30,14 @@ namespace Espo\Services; use Espo\Tools\Email\SendService; - use Espo\ORM\Entity; use Espo\Entities\User; use Espo\Entities\Email as EmailEntity; -use Espo\Tools\Email\Service; - -use Espo\Entities\Attachment; - +use Espo\Tools\Email\InboxService; use Espo\Core\Exceptions\Error; use Espo\Core\Exceptions\Conflict; use Espo\Core\Exceptions\Forbidden; -use Espo\Core\Exceptions\NotFound; use Espo\Core\Exceptions\BadRequest; -use Espo\Core\Di; use Espo\Core\Mail\Exceptions\SendingError; use Espo\Core\Mail\Sender; use Espo\Core\Mail\SmtpParams; @@ -53,19 +47,14 @@ use Espo\Tools\Email\Util; use stdClass; /** - * @extends Record<\Espo\Entities\Email> + * @extends Record */ -class Email extends Record implements - - Di\FileStorageManagerAware +class Email extends Record { - use Di\FileStorageManagerSetter; protected $getEntityBeforeUpdate = true; - /** - * @var string[] - */ + /** @var string[] */ protected $allowedForUpdateFieldList = [ 'parent', 'teams', @@ -105,6 +94,7 @@ class Email extends Record implements /** * @deprecated Use `Espo\Tools\Email\SendService`. + * * @throws BadRequest * @throws SendingError * @throws Error @@ -190,7 +180,7 @@ class Email extends Record implements private function markAsRead(string $id, ?string $userId = null): void { - $service = $this->injectableFactory->create(Service::class); + $service = $this->injectableFactory->create(InboxService::class); $service->markAsRead($id, $userId); } @@ -211,88 +201,6 @@ class Email extends Record implements return Util::parseFromAddress($string); } - /** - * @throws BadRequest - * @throws Forbidden - * @throws NotFound - */ - public function getCopiedAttachments( - string $id, - ?string $parentType = null, - ?string $parentId = null, - ?string $field = null - ): stdClass { - - $ids = []; - $names = (object) []; - - if (empty($id)) { - throw new BadRequest(); - } - - /** @var ?EmailEntity $email */ - $email = $this->entityManager->getEntityById(EmailEntity::ENTITY_TYPE, $id); - - if (!$email) { - throw new NotFound(); - } - - if (!$this->acl->checkEntityRead($email)) { - throw new Forbidden(); - } - - $email->loadLinkMultipleField('attachments'); - - $attachmentsIds = $email->get('attachmentsIds'); - - foreach ($attachmentsIds as $attachmentId) { - /** @var ?Attachment $source */ - $source = $this->entityManager->getEntityById(Attachment::ENTITY_TYPE, $attachmentId); - - if ($source) { - /** @var Attachment $attachment */ - $attachment = $this->entityManager->getNewEntity(Attachment::ENTITY_TYPE); - - $attachment->set('role', Attachment::ROLE_ATTACHMENT); - $attachment->set('type', $source->getType()); - $attachment->set('size', $source->getSize()); - $attachment->set('global', $source->get('global')); - $attachment->set('name', $source->getName()); - $attachment->set('sourceId', $source->getSourceId()); - $attachment->set('storage', $source->getStorage()); - - if ($field) { - $attachment->set('field', $field); - } - - if ($parentType) { - $attachment->set('parentType', $parentType); - } - - if ($parentType && $parentId) { - $attachment->set('parentId', $parentId); - } - - if ($this->fileStorageManager->exists($source)) { - $this->entityManager->saveEntity($attachment); - - $contents = $this->fileStorageManager->getContents($source); - - $this->fileStorageManager->putContents($attachment, $contents); - - $ids[] = $attachment->getId(); - - $names->{$attachment->getId()} = $attachment->getName(); - } - } - } - - return (object) [ - 'ids' => $ids, - 'names' => $names, - ]; - } - protected function beforeUpdateEntity(Entity $entity, $data) { /** @var EmailEntity $entity */ diff --git a/application/Espo/Tools/Email/InboxService.php b/application/Espo/Tools/Email/InboxService.php index 68e5f8513c..645cf0064a 100644 --- a/application/Espo/Tools/Email/InboxService.php +++ b/application/Espo/Tools/Email/InboxService.php @@ -44,7 +44,7 @@ use Espo\Entities\User; use Espo\ORM\EntityManager; use Exception; -class Service +class InboxService { private const FOLDER_INBOX = 'inbox'; private const FOLDER_DRAFTS = 'drafts'; diff --git a/application/Espo/Tools/Email/Service.php b/application/Espo/Tools/Email/Service.php new file mode 100644 index 0000000000..c22101fe15 --- /dev/null +++ b/application/Espo/Tools/Email/Service.php @@ -0,0 +1,119 @@ +entityManager = $entityManager; + $this->attachmentAccessChecker = $attachmentAccessChecker; + $this->serviceContainer = $serviceContainer; + } + + /** + * Copy article attachments for re-using (e.g. in an email). + * + * @return Attachment[] + * @throws NotFound + * @throws Forbidden + */ + public function copyAttachments(string $id, FieldData $fieldData): array + { + /** @var ?Email $entity */ + $entity = $this->serviceContainer + ->get(Email::ENTITY_TYPE) + ->getEntity($id); + + if (!$entity) { + throw new NotFound(); + } + + $this->attachmentAccessChecker->check($fieldData); + + $list = []; + + foreach ($entity->getAttachmentIdList() as $attachmentId) { + $attachment = $this->copyAttachment($attachmentId, $fieldData); + + if ($attachment) { + $list[] = $attachment; + } + } + + return $list; + } + + private function copyAttachment(string $attachmentId, FieldData $fieldData): ?Attachment + { + /** @var ?Attachment $attachment */ + $attachment = $this->entityManager + ->getRDBRepositoryByClass(Attachment::class) + ->getById($attachmentId); + + if (!$attachment) { + return null; + } + + $copied = $this->getAttachmentRepository()->getCopiedAttachment($attachment); + + $copied->set('parentType', $fieldData->getParentType()); + $copied->set('relatedType', $fieldData->getRelatedType()); + $copied->setTargetField($fieldData->getField()); + $copied->setRole(Attachment::ROLE_ATTACHMENT); + + $this->getAttachmentRepository()->save($copied); + + return $copied; + } + + private function getAttachmentRepository(): AttachmentRepository + { + /** @var AttachmentRepository */ + return $this->entityManager->getRepositoryByClass(Attachment::class); + } +}