From 5403bf522ddafc881b28d381f5f22cac1dc50dba Mon Sep 17 00:00:00 2001 From: KreativeKrise Date: Fri, 26 Mar 2021 15:07:09 +0100 Subject: [PATCH 1/2] [BUGFIX] Fixes errors that occur when the same form is used multiple times on the same page --- Classes/Controller/FormController.php | 77 ++++++++++++++++++- .../Misc/PrefillFieldViewHelper.php | 37 ++++++++- .../Misc/PrefillMultiFieldViewHelper.php | 37 ++++++++- .../EnableParsleyAndAjaxViewHelper.php | 2 + .../Private/JavaScript/Powermail/Form.js | 6 +- .../Private/Templates/Form/Confirmation.html | 3 +- Resources/Private/Templates/Form/Create.html | 2 +- Resources/Private/Templates/Form/Form.html | 3 +- .../Public/JavaScript/Powermail/Form.min.js | 2 +- 9 files changed, 154 insertions(+), 15 deletions(-) diff --git a/Classes/Controller/FormController.php b/Classes/Controller/FormController.php index 279e3cfa2..979ad704f 100644 --- a/Classes/Controller/FormController.php +++ b/Classes/Controller/FormController.php @@ -70,7 +70,7 @@ public function formAction(): void $this->view->assignMultiple( [ 'form' => $form, - 'ttContentData' => $this->contentObject->data, + 'ttContentData' => $this->getCurrentContentObjectData(), 'messageClass' => $this->messageClass, 'action' => ($this->settings['main']['confirmation'] ? 'confirmation' : 'create') ] @@ -95,6 +95,7 @@ public function formAction(): void */ public function initializeConfirmationAction(): void { + $this->forwardIfTtContentUidDoesNotMatch(); $this->forwardIfFormParamsDoNotMatch(); $this->forwardIfMailParamEmpty(); $this->reformatParamsForAction(); @@ -152,6 +153,7 @@ public function confirmationAction(Mail $mail): void */ public function initializeCreateAction(): void { + $this->forwardIfTtContentUidDoesNotMatch(); $this->forwardIfFormParamsDoNotMatch(); $this->forwardIfMailParamEmpty(); $this->reformatParamsForAction(); @@ -202,7 +204,7 @@ public function createAction(Mail $mail, string $hash = ''): void $this->settings, $this->conf ); - $mailPreflight->sendOptinConfirmationMail($mail); + $mailPreflight->sendOptinConfirmationMail($mail, $this->contentObject->data); $this->view->assign('optinActive', true); } if ($this->isPersistActive()) { @@ -238,7 +240,7 @@ protected function sendMailPreflight(Mail $mail, string $hash = ''): void $this->settings, $this->conf ); - $mailPreflight->sendSenderMail($mail); + $mailPreflight->sendSenderMail($mail, $this->contentObject->data); } if ($this->isReceiverMailEnabled()) { $mailPreflight = $this->objectManager->get(SendReceiverMailPreflight::class, $this->settings); @@ -275,7 +277,7 @@ protected function prepareOutput(Mail $mail): void 'mail' => $mail, 'marketingInfos' => SessionUtility::getMarketingInfos(), 'messageClass' => $this->messageClass, - 'ttContentData' => $this->contentObject->data, + 'ttContentData' => $this->getCurrentContentObjectData(), 'uploadService' => $this->uploadService, 'powermail_rte' => $this->settings['thx']['body'], 'powermail_all' => TemplateUtility::powermailAll($mail, 'web', $this->settings, $this->actionMethodName) @@ -403,6 +405,37 @@ public function initializeObject() $this->signalDispatch(__CLASS__, __FUNCTION__ . 'Settings', [$this, &$this->settings]); } + /** + * Initialize Action + * + * @return void + * @codeCoverageIgnore + */ + public function initializeAction(): void + { + parent::initializeAction(); + + $this->storeCurrentContentObjectData(); + } + + /** + * Forward to formAction if content element uids do not match + * used for createAction() and confirmationAction() + * + * @return void + */ + protected function forwardIfTtContentUidDoesNotMatch() + { + $arguments = $this->request->getArguments(); + $currentContentObjectData = $this->getCurrentContentObjectData(); + + if (isset($arguments['field']['__ttcontentuid']) && isset($currentContentObjectData['uid']) + && (int) $arguments['field']['__ttcontentuid'] !== (int) $currentContentObjectData['uid'] + ) { + $this->forward('form'); + } + } + /** * Forward to formAction if wrong form in plugin variables given * used for createAction() and confirmationAction() @@ -555,4 +588,40 @@ public function injectPersistenceManager(PersistenceManager $persistenceManager) { $this->persistenceManager = $persistenceManager; } + + /** + * Storing the current content object data to a global variable. That is necessary + * because content object data gets lost after a request is being forwarded to its + * referring request after an errorAction + * + * @return void + */ + protected function storeCurrentContentObjectData(): void + { + if (!empty($this->contentObject->data)) { + $tsfe = ObjectUtility::getTyposcriptFrontendController(); + + if (!is_array($tsfe->applicationData['tx_powermail'])) { + $tsfe->applicationData['tx_powermail'] = []; + } + + $tsfe->applicationData['tx_powermail']['currentContentObjectData'] = $this->contentObject->data; + } + } + + /** + * Retrieving data of content object that is currently being rendered + * + * @return array + */ + protected function getCurrentContentObjectData(): array + { + $tsfe = ObjectUtility::getTyposcriptFrontendController(); + + if (isset($tsfe->applicationData['tx_powermail']['currentContentObjectData'])) { + return $tsfe->applicationData['tx_powermail']['currentContentObjectData']; + } + + return []; + } } diff --git a/Classes/ViewHelpers/Misc/PrefillFieldViewHelper.php b/Classes/ViewHelpers/Misc/PrefillFieldViewHelper.php index 6c19863ff..1f073fe79 100644 --- a/Classes/ViewHelpers/Misc/PrefillFieldViewHelper.php +++ b/Classes/ViewHelpers/Misc/PrefillFieldViewHelper.php @@ -151,7 +151,7 @@ protected function getFromMail(string $value) */ protected function getFromMarker($value) { - if (empty($value) && isset($this->variables['field'][$this->getMarker()])) { + if (empty($value) && isset($this->variables['field'][$this->getMarker()]) && $this->isSameContentElement()) { $value = $this->variables['field'][$this->getMarker()]; } return $value; @@ -165,7 +165,7 @@ protected function getFromMarker($value) */ protected function getFromRawMarker($value) { - if (empty($value) && isset($this->variables[$this->getMarker()])) { + if (empty($value) && isset($this->variables[$this->getMarker()]) && $this->isSameContentElement()) { $value = $this->variables[$this->getMarker()]; } return $value; @@ -392,4 +392,37 @@ public function initialize() $configurationService = ObjectUtility::getObjectManager()->get(ConfigurationService::class); $this->configuration = $configurationService->getTypoScriptConfiguration(); } + + /** + * Check whether GET / POST values may be used by this form, + * because they are from the same content element as the form was submitted + * + * @return bool + */ + protected function isSameContentElement(): bool + { + $currentContentObjectData = $this->getCurrentContentObjectData(); + + if (isset($currentContentObjectData['uid']) && isset($this->variables['field']['__ttcontentuid'])) { + return (int) $currentContentObjectData['uid'] === (int) $this->variables['field']['__ttcontentuid']; + } + + return true; + } + + /** + * Retrieving data of content object that is currently being rendered + * + * @return array + */ + protected function getCurrentContentObjectData(): array + { + $tsfe = ObjectUtility::getTyposcriptFrontendController(); + + if (isset($tsfe->applicationData['tx_powermail']['currentContentObjectData'])) { + return $tsfe->applicationData['tx_powermail']['currentContentObjectData']; + } + + return []; + } } diff --git a/Classes/ViewHelpers/Misc/PrefillMultiFieldViewHelper.php b/Classes/ViewHelpers/Misc/PrefillMultiFieldViewHelper.php index dc13dbdac..3bfec26c6 100644 --- a/Classes/ViewHelpers/Misc/PrefillMultiFieldViewHelper.php +++ b/Classes/ViewHelpers/Misc/PrefillMultiFieldViewHelper.php @@ -194,7 +194,7 @@ protected function isFromMail(): bool protected function isFromMarker(): bool { $selected = false; - if (isset($this->variables['field'][$this->getMarker()])) { + if (isset($this->variables['field'][$this->getMarker()]) && $this->isSameContentElement()) { if (is_array($this->variables['field'][$this->getMarker()])) { foreach (array_keys($this->variables['field'][$this->getMarker()]) as $key) { if ($this->variables['field'][$this->getMarker()][$key] === $this->options[$this->index]['value'] || @@ -225,7 +225,7 @@ protected function isFromMarker(): bool protected function isFromRawMarker(): bool { $selected = false; - if (isset($this->variables[$this->getMarker()])) { + if (isset($this->variables[$this->getMarker()]) && $this->isSameContentElement()) { if (is_array($this->variables[$this->getMarker()])) { foreach (array_keys($this->variables[$this->getMarker()]) as $key) { if ($this->variables[$this->getMarker()][$key] === $this->options[$this->index]['value'] || @@ -539,4 +539,37 @@ public function initialize(): void $configurationService = ObjectUtility::getObjectManager()->get(ConfigurationService::class); $this->configuration = $configurationService->getTypoScriptConfiguration(); } + + /** + * Check whether GET / POST values may be used by this form, + * because they are from the same content element as the form was submitted + * + * @return bool + */ + protected function isSameContentElement(): bool + { + $currentContentObjectData = $this->getCurrentContentObjectData(); + + if (isset($currentContentObjectData['uid']) && isset($this->variables['field']['__ttcontentuid'])) { + return (int) $currentContentObjectData['uid'] === (int) $this->variables['field']['__ttcontentuid']; + } + + return true; + } + + /** + * Retrieving data of content object that is currently being rendered + * + * @return array + */ + protected function getCurrentContentObjectData(): array + { + $tsfe = ObjectUtility::getTyposcriptFrontendController(); + + if (isset($tsfe->applicationData['tx_powermail']['currentContentObjectData'])) { + return $tsfe->applicationData['tx_powermail']['currentContentObjectData']; + } + + return []; + } } diff --git a/Classes/ViewHelpers/Validation/EnableParsleyAndAjaxViewHelper.php b/Classes/ViewHelpers/Validation/EnableParsleyAndAjaxViewHelper.php index a755aaac3..194a35ca9 100644 --- a/Classes/ViewHelpers/Validation/EnableParsleyAndAjaxViewHelper.php +++ b/Classes/ViewHelpers/Validation/EnableParsleyAndAjaxViewHelper.php @@ -28,6 +28,7 @@ public function initializeArguments() parent::initializeArguments(); $this->registerArgument('form', Form::class, 'Form', true); $this->registerArgument('additionalAttributes', 'array', 'additionalAttributes', false, []); + $this->registerArgument('ttContentData', 'array', 'ttContentData', false, []); } /** @@ -52,6 +53,7 @@ public function render(): array if ($this->settings['misc']['ajaxSubmit'] === '1') { $additionalAttributes['data-powermail-ajax'] = 'true'; $additionalAttributes['data-powermail-form'] = $form->getUid(); + $additionalAttributes['data-powermail-ttcontentuid'] = $this->arguments['ttContentData']['uid']; if ($this->addRedirectUri) { /** @var RedirectUriService $redirectService */ diff --git a/Resources/Private/JavaScript/Powermail/Form.js b/Resources/Private/JavaScript/Powermail/Form.js index e88cdae87..1aacd1823 100644 --- a/Resources/Private/JavaScript/Powermail/Form.js +++ b/Resources/Private/JavaScript/Powermail/Form.js @@ -189,7 +189,7 @@ function PowermailForm($) { if ($this.data('powermail-ajax-uri')) { redirectUri = $this.data('powermail-ajax-uri'); } - var formUid = $this.data('powermail-form'); + var ttContentUid = $this.data('powermail-ttcontentuid'); if (!regularSubmitOnAjax) { $.ajax({ @@ -207,9 +207,9 @@ function PowermailForm($) { fireAjaxCompleteEvent($txPowermail); }, success: function(data) { - var html = $('*[data-powermail-form="' + formUid + '"]:first', data); + var html = $('*[data-powermail-ttcontentuid="' + ttContentUid + '"]:first', data); if (html.length) { - $('*[data-powermail-form="' + formUid + '"]:first').closest('.tx-powermail').html(html); + $('*[data-powermail-ttcontentuid="' + ttContentUid + '"]:first').closest('.tx-powermail').html(html); // fire tabs and parsley again if ($.fn.powermailTabs) { $('.powermail_morestep').powermailTabs(); diff --git a/Resources/Private/Templates/Form/Confirmation.html b/Resources/Private/Templates/Form/Confirmation.html index 7fce19b19..66e063d46 100644 --- a/Resources/Private/Templates/Form/Confirmation.html +++ b/Resources/Private/Templates/Form/Confirmation.html @@ -27,7 +27,7 @@

enctype="multipart/form-data" class="visible-xs-inline-block visible-sm-inline-block visible-md-inline-block visible-lg-inline-block" addQueryString="{settings.misc.addQueryString}" - additionalAttributes="{vh:validation.enableParsleyAndAjax(form: mail.form)}"> + additionalAttributes="{vh:Validation.EnableParsleyAndAjax(form: mail.form, ttContentData: ttContentData)}"> + diff --git a/Resources/Private/Templates/Form/Create.html b/Resources/Private/Templates/Form/Create.html index dd30979a7..b4adffaf7 100644 --- a/Resources/Private/Templates/Form/Create.html +++ b/Resources/Private/Templates/Form/Create.html @@ -19,7 +19,7 @@ -
+
diff --git a/Resources/Private/Templates/Form/Form.html b/Resources/Private/Templates/Form/Form.html index 926240bcf..4d9b4ec9f 100644 --- a/Resources/Private/Templates/Form/Form.html +++ b/Resources/Private/Templates/Form/Form.html @@ -20,7 +20,7 @@ section="c{ttContentData.uid}" name="field" enctype="multipart/form-data" - additionalAttributes="{vh:validation.enableParsleyAndAjax(form:form)}" + additionalAttributes="{vh:Validation.EnableParsleyAndAjax(form:form, ttContentData:ttContentData)}" addQueryString="{settings.misc.addQueryString}" class="powermail_form powermail_form_{form.uid} {form.css} {settings.styles.framework.formClasses} {vh:misc.morestepClass(activate:settings.main.moresteps)}"> @@ -33,6 +33,7 @@

{form.title}

+ diff --git a/Resources/Public/JavaScript/Powermail/Form.min.js b/Resources/Public/JavaScript/Powermail/Form.min.js index 0fd52a761..bfab536fa 100644 --- a/Resources/Public/JavaScript/Powermail/Form.min.js +++ b/Resources/Public/JavaScript/Powermail/Form.min.js @@ -1 +1 @@ -function PowermailForm(e){"use strict";this.initialize=function(){t(),a(),i(),r(),o(),n(),f(),l()};var t=function(){e.fn.powermailTabs&&e(".powermail_morestep").each(function(){e(this).powermailTabs()})},a=function(){e("form[data-powermail-ajax]").length&&p()},i=function(){if(e('*[data-powermail-location="prefill"]').length&&navigator.geolocation){e(this);navigator.geolocation.getCurrentPosition(function(t){var a=t.coords.latitude,i=t.coords.longitude,r=C()+"/index.php?eID=powermailEidGetLocation";jQuery.ajax({url:r,data:"lat="+a+"&lng="+i,cache:!1,success:function(t){t&&e('*[data-powermail-location="prefill"]').val(t)}})})}},r=function(){e.fn.datetimepicker&&e(".powermail_date").each(function(){var t=e(this);if("date"===t.prop("type")||"datetime-local"===t.prop("type")||"time"===t.prop("type")){if(!t.data("datepicker-force")){if(e(this).data("date-value")){var a=g(e(this).data("date-value"),e(this).data("datepicker-format"),t.prop("type"));null!==a&&e(this).val(a)}return}t.prop("type","text"),t.val(e(this).data("date-value"))}var i=!0,r=!0;"date"===t.data("datepicker-settings")?r=!1:"time"===t.data("datepicker-settings")&&(i=!1),t.datetimepicker({format:t.data("datepicker-format"),timepicker:r,datepicker:i,lang:"en",i18n:{en:{months:t.data("datepicker-months").split(","),dayOfWeek:t.data("datepicker-days").split(",")}}})})},o=function(){e(".powermail_all_type_password.powermail_all_value").html("********")},n=function(){e.fn.parsley&&e(".powermail_reset").on("click","",function(){e('form[data-parsley-validate="data-parsley-validate"]').parsley().reset()})},l=function(){window.Parsley&&(x(),b())},p=function(){var t,a=!1;e(document).on("submit","form[data-powermail-ajax]",function(i){var r=e(this),o=r.closest(".tx-powermail");r.data("powermail-ajax-uri")&&(t=r.data("powermail-ajax-uri"));var n=r.data("powermail-form");a||(e.ajax({type:"POST",url:r.prop("action"),data:new FormData(r.get(0)),contentType:!1,processData:!1,beforeSend:function(){s(r)},complete:function(){d(r),f(),c(o)},success:function(i){var o=e('*[data-powermail-form="'+n+'"]:first',i);o.length?(e('*[data-powermail-form="'+n+'"]:first').closest(".tx-powermail").html(o),e.fn.powermailTabs&&e(".powermail_morestep").powermailTabs(),e.fn.parsley&&e('form[data-parsley-validate="data-parsley-validate"]').parsley(),w()):(t?D(t):r.submit(),a=!0)}}),i.preventDefault())})},s=function(t){d(t),e(".powermail_submit",t).length?e(".powermail_submit",t).parent().append(y()):t.closest(".tx-powermail").append(y())},d=function(e){e.closest(".tx-powermail").find(".powermail_progressbar").remove()},c=function(t){var a=e.Event("submitted.powermail.form");t.trigger(a)},f=function(){e(".powermail_fieldwrap_file").find(".deleteAllFiles").each(function(){u(e(this).closest(".powermail_fieldwrap_file").find('input[type="file"]'))}),e(".deleteAllFiles").click(function(){m(e(this).closest(".powermail_fieldwrap_file").find('input[type="hidden"]')),e(this).closest("ul").fadeOut(function(){e(this).remove()})})},u=function(e){e.prop("disabled","disabled").addClass("hide").prop("type","hidden")},m=function(e){e.prop("disabled",!1).removeClass("hide").prop("type","file")},w=function(){e("img.powermail_captchaimage").each(function(){var t=h(e(this).prop("src"));e(this).prop("src",t+"?hash="+v(5))})},h=function(e){var t=e.split("?");return t[0]},v=function(e){for(var t="",a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",i=0;i").addClass("powermail_progressbar").html(e("
").addClass("powermail_progress").html(e("
").addClass("powermail_progress_inner")))},_=function(e){for(var t=e.get(0),a=0,i=0;ia&&(a=r.size)}return parseInt(a)},x=function(){window.Parsley.addValidator("powermailfilesize",function(t,a){if(a.indexOf(",")!==-1){var i=a.split(","),r=parseInt(i[0]),o=e('*[name="tx_powermail_pi1[field]['+i[1]+'][]"]');if(o.length&&_(o)>r)return!1}return!0},32).addMessage("en","powermailfilesize","Error")},b=function(){window.Parsley.addValidator("powermailfileextensions",function(t,a){var i=e('*[name="tx_powermail_pi1[field]['+a+'][]"]');return!i.length||k(j(t),i.prop("accept"))},32).addMessage("en","powermailfileextensions","Error")},k=function(e,t){return t.indexOf("."+e)!==-1},j=function(e){return e.split(".").pop().toLowerCase()},D=function(e){e.indexOf("http")!==-1?window.location=e:window.location.pathname=e},C=function(){var t;return t=e("base").length>0?jQuery("base").prop("href"):"https:"!=window.location.protocol?"http://"+window.location.hostname:"https://"+window.location.hostname}}jQuery(document).ready(function(e){"use strict";var t=new window.PowermailForm(e);t.initialize()}); \ No newline at end of file +function PowermailForm(a){this.initialize=function(){n();a("form[data-powermail-ajax]").length&&p();q();r();a(".powermail_all_type_password.powermail_all_value").html("********");t();k();window.Parsley&&(u(),v())};var n=function(){a.fn.powermailTabs&&a(".powermail_morestep").each(function(){a(this).powermailTabs()})},q=function(){a('*[data-powermail-location="prefill"]').length&&navigator.geolocation&&(a(this),navigator.geolocation.getCurrentPosition(function(b){var d=b.coords.latitude;b=b.coords.longitude;var c=(0g;g++)e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".charAt(Math.floor(62*Math.random()));c.call(d,"src",b+"?hash="+e)})},m=function(){return a("
").addClass("powermail_progressbar").html(a("
").addClass("powermail_progress").html(a("
").addClass("powermail_progress_inner")))},u=function(){window.Parsley.addValidator("powermailfilesize",function(b,d){if(-1!==d.indexOf(",")){var c=d.split(","),e=parseInt(c[0]);c=a('*[name="tx_powermail_pi1[field]['+c[1]+'][]"]');if(c.length){c=c.get(0);for(var g=0,h=0;hg&&(g=f.size)}if(parseInt(g)>e)return!1}}return!0},32).addMessage("en","powermailfilesize","Error")},v=function(){window.Parsley.addValidator("powermailfileextensions",function(b,d){var c=a('*[name="tx_powermail_pi1[field]['+d+'][]"]');if(c.length){var e=b.split(".").pop().toLowerCase();return-1!==c.prop("accept").indexOf("."+e)}return!0},32).addMessage("en","powermailfileextensions","Error")}}jQuery(document).ready(function(a){(new window.PowermailForm(a)).initialize()}); \ No newline at end of file From c8e27e76252f3fcba1fd32dba032eb2659851600 Mon Sep 17 00:00:00 2001 From: KreativeKrise Date: Fri, 26 Mar 2021 15:29:43 +0100 Subject: [PATCH 2/2] [TASK] Some tweaks --- Classes/Controller/FormController.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Classes/Controller/FormController.php b/Classes/Controller/FormController.php index 979ad704f..ffa6e8756 100644 --- a/Classes/Controller/FormController.php +++ b/Classes/Controller/FormController.php @@ -413,8 +413,6 @@ public function initializeObject() */ public function initializeAction(): void { - parent::initializeAction(); - $this->storeCurrentContentObjectData(); } @@ -424,7 +422,7 @@ public function initializeAction(): void * * @return void */ - protected function forwardIfTtContentUidDoesNotMatch() + protected function forwardIfTtContentUidDoesNotMatch(): void { $arguments = $this->request->getArguments(); $currentContentObjectData = $this->getCurrentContentObjectData();