From 1f99c1b9a12110b4bd15ddfc337f43b39b104e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20M=C3=B6ller?= Date: Fri, 1 Mar 2019 14:18:06 +0100 Subject: [PATCH 1/6] Task: emailFinisher sends multipart email --- Classes/Finishers/EmailFinisher.php | 96 +++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 19 deletions(-) diff --git a/Classes/Finishers/EmailFinisher.php b/Classes/Finishers/EmailFinisher.php index 05bb91c..61c868d 100644 --- a/Classes/Finishers/EmailFinisher.php +++ b/Classes/Finishers/EmailFinisher.php @@ -27,6 +27,10 @@ * * - templatePathAndFilename (mandatory if "templateSource" option is not set): Template path and filename for the mail body * - templateSource (mandatory if "templatePathAndFilename" option is not set): The raw Fluid template + * - htmlTemplatePathAndFilename (mandatory if "htmlTemplateSource" option is not set): Template path and filename for the html mail body + * - htmlTemplateSource (mandatory if "htmlTemplatePathAndFilename" option is not set): The raw Fluid template for html mail body + * - plaintextTemplatePathAndFilename (mandatory if "plaintextTemplateSource" option is not set): Template path and filename for the plaintext mail body + * - plaintextTemplateSource (mandatory if "plaintextTemplatePathAndFilename" option is not set): The raw Fluid template for plaintext mail body * - layoutRootPath: root path for the layouts * - partialRootPath: root path for the partials * - variables: associative array of variables which are available inside the Fluid template @@ -54,6 +58,9 @@ class EmailFinisher extends AbstractFinisher { const FORMAT_PLAINTEXT = 'plaintext'; const FORMAT_HTML = 'html'; + const FORMAT_MULTIPART = 'multipart'; + const CONTENT_TYPE_PLAINTEXT = 'text/plain'; + const CONTENT_TYPE_HTML = 'text/html'; /** * @var Service @@ -61,6 +68,11 @@ class EmailFinisher extends AbstractFinisher */ protected $i18nService; + protected $formatContentTypes = [ + self::FORMAT_HTML => self::CONTENT_TYPE_HTML, + self::FORMAT_PLAINTEXT => self::CONTENT_TYPE_PLAINTEXT, + ]; + /** * @var array */ @@ -85,13 +97,6 @@ protected function executeInternal() if (!class_exists(SwiftMailerMessage::class)) { throw new FinisherException('The "neos/swiftmailer" doesn\'t seem to be installed, but is required for the EmailFinisher to work!', 1503392532); } - $formRuntime = $this->finisherContext->getFormRuntime(); - $standaloneView = $this->initializeStandaloneView(); - $standaloneView->assign('form', $formRuntime); - $referrer = $formRuntime->getRequest()->getHttpRequest()->getUri(); - $standaloneView->assign('referrer', $referrer); - $message = $standaloneView->render(); - $subject = $this->parseOption('subject'); $recipientAddress = $this->parseOption('recipientAddress'); $recipientName = $this->parseOption('recipientName'); @@ -102,6 +107,7 @@ protected function executeInternal() $blindCarbonCopyAddress = $this->parseOption('blindCarbonCopyAddress'); $format = $this->parseOption('format'); $testMode = $this->parseOption('testMode'); + $messages = $this->getMessages($format); if ($subject === null) { throw new FinisherException('The option "subject" must be set for the EmailFinisher.', 1327060320); @@ -140,11 +146,7 @@ protected function executeInternal() $mail->setBcc($blindCarbonCopyAddress); } - if ($format === self::FORMAT_PLAINTEXT) { - $mail->setBody($message, 'text/plain'); - } else { - $mail->setBody($message, 'text/html'); - } + $this->addMessages($mail, $messages); $this->addAttachments($mail); if ($testMode === true) { @@ -155,7 +157,7 @@ protected function executeInternal() 'replyToAddress' => $replyToAddress, 'carbonCopyAddress' => $carbonCopyAddress, 'blindCarbonCopyAddress' => $blindCarbonCopyAddress, - 'message' => $message, + 'message' => $messages, 'format' => $format, ), 'E-Mail "' . $subject . '"' @@ -165,20 +167,76 @@ protected function executeInternal() } } + protected function addMessages(SwiftMailerMessage $mail, $messages): void + { + foreach ($messages as $messageFormat => $message) { + if (count($messages) === 1) { + $mail->setBody($message, $this->formatContentTypes[$messageFormat]); + } else { + $mail->addPart($message, $this->formatContentTypes[$messageFormat]); + } + } + } + + protected function getMessages(string $format): array + { + $messages = []; + if ($format === self::FORMAT_MULTIPART) { + $messages[self::FORMAT_HTML] = $this->createMessage(self::FORMAT_HTML); + $messages[self::FORMAT_PLAINTEXT] = $this->createMessage(self::FORMAT_PLAINTEXT); + } else if ($format === self::FORMAT_PLAINTEXT) { + $messages[self::FORMAT_PLAINTEXT] = $this->createMessage(self::FORMAT_PLAINTEXT); + } else { + $messages[self::FORMAT_HTML] = $this->createMessage(self::FORMAT_HTML); + } + + return $messages; + } + + protected function createMessage(string $format): string + { + $formRuntime = $this->finisherContext->getFormRuntime(); + $standaloneView = $this->initializeStandaloneView($format); + $standaloneView->assign('form', $formRuntime); + $referrer = $formRuntime->getRequest()->getHttpRequest()->getUri(); + $standaloneView->assign('referrer', $referrer); + + return $standaloneView->render(); + } + /** + * @param string $format * @return StandaloneView * @throws FinisherException + * @throws \Neos\FluidAdaptor\Exception */ - protected function initializeStandaloneView() + protected function initializeStandaloneView(string $format = ''): StandaloneView { + $templatePathAndFilenameOption = 'templatePathAndFilename'; + $templateSourceOption = 'templateSource'; + $isSingleTemplate = isset($this->options[$templatePathAndFilenameOption]) || isset($this->options[$templateSourceOption]); + + if (!$isSingleTemplate && in_array($format, [self::FORMAT_PLAINTEXT, self::FORMAT_HTML])) { + $templatePathAndFilenameOption = $format . ucfirst($templatePathAndFilenameOption); + $templateSourceOption = $format . ucfirst($templateSourceOption); + } + $standaloneView = new StandaloneView(); - if (isset($this->options['templatePathAndFilename'])) { - $templatePathAndFilename = $this->i18nService->getLocalizedFilename($this->options['templatePathAndFilename']); + if (isset($this->options[$templatePathAndFilenameOption])) { + $templatePathAndFilename = $this->i18nService->getLocalizedFilename($this->options[$templatePathAndFilenameOption]); $standaloneView->setTemplatePathAndFilename($templatePathAndFilename[0]); - } elseif (isset($this->options['templateSource'])) { - $standaloneView->setTemplateSource($this->options['templateSource']); + } elseif (isset($this->options[$templateSourceOption])) { + $standaloneView->setTemplateSource($this->options[$templateSourceOption]); } else { - throw new FinisherException('The option "templatePathAndFilename" or "templateSource" must be set for the EmailFinisher.', 1327058829); + $options = [ + 'templatePathAndFilename', + 'templateSource', + self::FORMAT_PLAINTEXT . 'TemplatePathAndFilename', + self::FORMAT_PLAINTEXT . 'TemplateSource', + self::FORMAT_HTML . 'TemplatePathAndFilename', + self::FORMAT_HTML . 'TemplateSource' + ]; + throw new FinisherException(sprintf('One of the option "%s" must be set for the EmailFinisher.', implode('", "', $options)), 1551371435); } From 39d0af17e86a39002dd197242d5f7a21310892f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20M=C3=B6ller?= Date: Fri, 1 Mar 2019 14:22:27 +0100 Subject: [PATCH 2/6] Task: fix attribute type --- Classes/Finishers/EmailFinisher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Finishers/EmailFinisher.php b/Classes/Finishers/EmailFinisher.php index 61c868d..3f481ba 100644 --- a/Classes/Finishers/EmailFinisher.php +++ b/Classes/Finishers/EmailFinisher.php @@ -167,7 +167,7 @@ protected function executeInternal() } } - protected function addMessages(SwiftMailerMessage $mail, $messages): void + protected function addMessages(SwiftMailerMessage $mail, array $messages): void { foreach ($messages as $messageFormat => $message) { if (count($messages) === 1) { From bb50859d8ac66ef0ec06427544bf75ba20044f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20M=C3=B6ller?= Date: Fri, 1 Mar 2019 14:41:00 +0100 Subject: [PATCH 3/6] Task: Fix ci style --- Classes/Finishers/EmailFinisher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Finishers/EmailFinisher.php b/Classes/Finishers/EmailFinisher.php index 3f481ba..0e1b924 100644 --- a/Classes/Finishers/EmailFinisher.php +++ b/Classes/Finishers/EmailFinisher.php @@ -184,7 +184,7 @@ protected function getMessages(string $format): array if ($format === self::FORMAT_MULTIPART) { $messages[self::FORMAT_HTML] = $this->createMessage(self::FORMAT_HTML); $messages[self::FORMAT_PLAINTEXT] = $this->createMessage(self::FORMAT_PLAINTEXT); - } else if ($format === self::FORMAT_PLAINTEXT) { + } elseif ($format === self::FORMAT_PLAINTEXT) { $messages[self::FORMAT_PLAINTEXT] = $this->createMessage(self::FORMAT_PLAINTEXT); } else { $messages[self::FORMAT_HTML] = $this->createMessage(self::FORMAT_HTML); From d2a78802dd9e425719e1cb187b6dd153dee21b46 Mon Sep 17 00:00:00 2001 From: Jenkins Date: Tue, 14 Apr 2020 00:10:50 +0000 Subject: [PATCH 4/6] TASK: Update translations from translation tool --- Resources/Private/Translations/fr/Main.xlf | 4 ++-- Resources/Private/Translations/id_ID/Main.xlf | 4 ++-- Resources/Private/Translations/ro/Main.xlf | 2 +- Resources/Private/Translations/ru/Main.xlf | 2 +- Resources/Private/Translations/tr/Main.xlf | 4 ++-- Resources/Private/Translations/uk/Main.xlf | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Resources/Private/Translations/fr/Main.xlf b/Resources/Private/Translations/fr/Main.xlf index a91cd72..b9597b1 100644 --- a/Resources/Private/Translations/fr/Main.xlf +++ b/Resources/Private/Translations/fr/Main.xlf @@ -4,13 +4,13 @@ Previous page - Page précédenteContexte de la requête + Page précédente Next page Page suivante Submit - SoumettreEnvoyer + Soumettre Label Libellé diff --git a/Resources/Private/Translations/id_ID/Main.xlf b/Resources/Private/Translations/id_ID/Main.xlf index 3c27350..df1c3db 100644 --- a/Resources/Private/Translations/id_ID/Main.xlf +++ b/Resources/Private/Translations/id_ID/Main.xlf @@ -4,13 +4,13 @@ Previous page - Halaman sebelumnyaPrevious pageHalaman Sebelumnya + Halaman sebelumnya Next page Halaman berikutnya Submit - KirimMasukkan + Kirim Label Label diff --git a/Resources/Private/Translations/ro/Main.xlf b/Resources/Private/Translations/ro/Main.xlf index fb92805..fa92532 100644 --- a/Resources/Private/Translations/ro/Main.xlf +++ b/Resources/Private/Translations/ro/Main.xlf @@ -4,7 +4,7 @@ Previous page - Pagina precedentăPagina precedenta + Pagina precedentă Next page Pagina următoare diff --git a/Resources/Private/Translations/ru/Main.xlf b/Resources/Private/Translations/ru/Main.xlf index 2ca2569..e224f8c 100644 --- a/Resources/Private/Translations/ru/Main.xlf +++ b/Resources/Private/Translations/ru/Main.xlf @@ -13,7 +13,7 @@ Отправить Label - ОбозначениеЭтикеткаПодписьМетка + Обозначение Value Значение diff --git a/Resources/Private/Translations/tr/Main.xlf b/Resources/Private/Translations/tr/Main.xlf index 637aa30..b8dfa68 100644 --- a/Resources/Private/Translations/tr/Main.xlf +++ b/Resources/Private/Translations/tr/Main.xlf @@ -4,10 +4,10 @@ Previous page - Önceki sayfaya gitmek için tıklayınızÖnceki sayfa + Önceki sayfaya gitmek için tıklayınız Next page - Sonraki sayfaya gitmek için tıklayınızSonraki sayfa + Sonraki sayfaya gitmek için tıklayınız Submit Gönder diff --git a/Resources/Private/Translations/uk/Main.xlf b/Resources/Private/Translations/uk/Main.xlf index 1e43b90..39339f6 100644 --- a/Resources/Private/Translations/uk/Main.xlf +++ b/Resources/Private/Translations/uk/Main.xlf @@ -10,7 +10,7 @@ Next page Submit - Надіслатиотправить + Надіслати Label Label From f1d273377da2b0ff503448466c9c13886c6540ba Mon Sep 17 00:00:00 2001 From: bwaidelich Date: Tue, 16 Jun 2020 12:41:39 +0200 Subject: [PATCH 5/6] FEATURE: Support SwiftMailer 6.x Previously the `EmailFinisher` threw an exception when using attachments and a `swiftmailer/swiftmailer` version 6+: Call to undefined method Swift_Attachment::newInstance() This is fixed with this change. Older SwiftMailer versions are still supported. Resolves: #112 --- Classes/Finishers/EmailFinisher.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/Finishers/EmailFinisher.php b/Classes/Finishers/EmailFinisher.php index 05bb91c..454f7d4 100644 --- a/Classes/Finishers/EmailFinisher.php +++ b/Classes/Finishers/EmailFinisher.php @@ -46,7 +46,7 @@ * - carbonCopyAddress: Email address of the copy recipient (use multiple addresses with an array) * - blindCarbonCopyAddress: Email address of the blind copy recipient (use multiple addresses with an array) * - format: format of the email (one of the FORMAT_* constants). By default mails are sent as HTML - * - attachAllPersistentResources: if TRUE all FormElements that are converted to a PersistendResource (e.g. the FileUpload element) are added to the mail as attachments + * - attachAllPersistentResources: if TRUE all FormElements that are converted to a PersistentResource (e.g. the FileUpload element) are added to the mail as attachments * - attachments: array of explicit files to be attached. Every item in the array has to be either "resource" being the path to a file, or "formElement" referring to the identifier of an Form Element that contains the PersistentResource to attach. This can be combined with the "attachAllPersistentResources" option * - testMode: if TRUE the email is not actually sent but outputted for debugging purposes. Defaults to FALSE */ @@ -209,7 +209,7 @@ protected function addAttachments(SwiftMailerMessage $mail) if ($this->parseOption('attachAllPersistentResources')) { foreach ($formValues as $formValue) { if ($formValue instanceof PersistentResource) { - $mail->attach(\Swift_Attachment::newInstance(stream_get_contents($formValue->getStream()), $formValue->getFilename(), $formValue->getMediaType())); + $mail->attach(new \Swift_Attachment(stream_get_contents($formValue->getStream()), $formValue->getFilename(), $formValue->getMediaType())); } } } @@ -227,7 +227,7 @@ protected function addAttachments(SwiftMailerMessage $mail) if (!$resource instanceof PersistentResource) { continue; } - $mail->attach(\Swift_Attachment::newInstance(stream_get_contents($resource->getStream()), $resource->getFilename(), $resource->getMediaType())); + $mail->attach(new \Swift_Attachment(stream_get_contents($resource->getStream()), $resource->getFilename(), $resource->getMediaType())); } } } From 035f399658419cff1c00cea7ba84205963ec2a10 Mon Sep 17 00:00:00 2001 From: bwaidelich Date: Tue, 16 Jun 2020 13:08:39 +0200 Subject: [PATCH 6/6] FEATURE: Configurable Resource Collection for file uploads This feature extends the `FileUpload` Form element such that the target Resource Collection can be configured. This can be useful for example in order to prevent uploaded files to end up in the public "persistent" collection: Neos: Flow: resource: targets: 'formUploadTarget': target: 'Some\Package\SomeProtectedResourceTarget' collections: 'formUploads': storage: 'defaultPersistentResourcesStorage' target: 'formUploadTarget' Form: presets: 'default': formElementTypes: 'Neos.Form:FileUpload': properties: # use our custom resource collection for all "FileUpload" form elements resourceCollection: 'formUploads' # Prevent preview link to be created in order to avoid publishing of the Presistent Resource createLinkToFilePreview: false Thanks to internezzo ag for sponsoring this feature! Resolves: #114 --- Classes/FormElements/FileUpload.php | 10 ++++++++++ Configuration/Settings.yaml | 4 ++++ Resources/Private/Form/FileUpload.html | 8 +++++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Classes/FormElements/FileUpload.php b/Classes/FormElements/FileUpload.php index 2fac7f1..1c36142 100644 --- a/Classes/FormElements/FileUpload.php +++ b/Classes/FormElements/FileUpload.php @@ -11,9 +11,13 @@ * source code. */ +use Neos\Flow\Property\PropertyMappingConfiguration; use Neos\Flow\ResourceManagement\PersistentResource; +use Neos\Flow\ResourceManagement\ResourceTypeConverter; +use Neos\Flow\Validation\Exception\InvalidValidationOptionsException; use Neos\Form\Core\Model\AbstractFormElement; use Neos\Form\Core\Runtime\FormRuntime; +use Neos\Form\Exception\FormDefinitionConsistencyException; use Neos\Form\Validation\FileTypeValidator; /** @@ -35,9 +39,15 @@ public function initializeFormElement() * @param FormRuntime $formRuntime * @param mixed $elementValue * @return void + * @throws InvalidValidationOptionsException | FormDefinitionConsistencyException */ public function onSubmit(FormRuntime $formRuntime, &$elementValue) { + if (isset($this->properties['resourceCollection'])) { + /** @var PropertyMappingConfiguration $propertyMappingConfiguration */ + $propertyMappingConfiguration = $this->getRootForm()->getProcessingRule($this->getIdentifier())->getPropertyMappingConfiguration(); + $propertyMappingConfiguration->setTypeConverterOption(ResourceTypeConverter::class, ResourceTypeConverter::CONFIGURATION_COLLECTION_NAME, $this->properties['resourceCollection']); + } $fileTypeValidator = new FileTypeValidator(array('allowedExtensions' => $this->properties['allowedExtensions'])); $this->addValidator($fileTypeValidator); } diff --git a/Configuration/Settings.yaml b/Configuration/Settings.yaml index 1b9b582..f76073d 100644 --- a/Configuration/Settings.yaml +++ b/Configuration/Settings.yaml @@ -137,6 +137,10 @@ Neos: 'Neos.Form:FormElement': true implementationClassName: Neos\Form\FormElements\FileUpload properties: + # target collection of the uploaded PersistentResource + resourceCollection: 'persistent' + # set this to "false" if you don't want to create a link to the uploaded file (required for non-public resource collections) + createLinkToFilePreview: true allowedExtensions: - pdf - doc diff --git a/Resources/Private/Form/FileUpload.html b/Resources/Private/Form/FileUpload.html index a63e8c7..7d5652a 100644 --- a/Resources/Private/Form/FileUpload.html +++ b/Resources/Private/Form/FileUpload.html @@ -12,9 +12,11 @@