diff --git a/.gitignore b/.gitignore index cedb3757fe..43fc5345e5 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ Thumbs.db .sass-cache .Build composer.lock +package-lock.json diff --git a/Classes/Controller/AbstractController.php b/Classes/Controller/AbstractController.php index f454f946eb..f4fd2937db 100644 --- a/Classes/Controller/AbstractController.php +++ b/Classes/Controller/AbstractController.php @@ -343,7 +343,8 @@ public function assignForAll() [ 'languageUid' => FrontendUtility::getFrontendLanguageUid(), 'storagePid' => $this->allConfig['persistence']['storagePid'], - 'Pid' => FrontendUtility::getCurrentPid() + 'Pid' => FrontendUtility::getCurrentPid(), + 'data' => $this->contentObject->data ] ); } diff --git a/Classes/Controller/UserController.php b/Classes/Controller/UserController.php index 04b2e202be..c41062fc56 100644 --- a/Classes/Controller/UserController.php +++ b/Classes/Controller/UserController.php @@ -87,6 +87,8 @@ public function imageDeleteAction(User $user) * @param string $field Fieldname like "username" or "email" * @param User $user Existing User * @param string $additionalValue Additional Values + * @param int $plugin tt_content.uid of the femanager plugin + * @param string $action current action name * @return void */ public function validateAction( @@ -94,7 +96,9 @@ public function validateAction( $value = null, $field = null, User $user = null, - $additionalValue = '' + $additionalValue = '', + int $plugin = 0, + string $action = '' ) { $clientsideValidator = $this->objectManager->get(ClientsideValidator::class); $result = $clientsideValidator @@ -103,6 +107,8 @@ public function validateAction( ->setFieldName($field) ->setUser($user) ->setAdditionalValue($additionalValue) + ->setPlugin($plugin) + ->setActionName($action) ->validateField(); $this->view->assignMultiple( diff --git a/Classes/Domain/Repository/PluginRepository.php b/Classes/Domain/Repository/PluginRepository.php index b373f66941..f627577143 100644 --- a/Classes/Domain/Repository/PluginRepository.php +++ b/Classes/Domain/Repository/PluginRepository.php @@ -3,6 +3,7 @@ namespace In2code\Femanager\Domain\Repository; use In2code\Femanager\Utility\ObjectUtility; +use TYPO3\CMS\Extbase\Service\FlexFormService; /** * Class PluginRepository @@ -21,6 +22,22 @@ class PluginRepository . 'Invitation->update;Invitation->delete;Invitation->status;', ]; + /** + * @param int $contentIdentifier + * @return string + */ + public function getControllerNameByPluginSettings(int $contentIdentifier): string + { + $queryBuilder = ObjectUtility::getQueryBuilder(self::TABLE_NAME); + $flexForm = (string)$queryBuilder + ->select('pi_flexform') + ->from(self::TABLE_NAME) + ->where('uid=' . (int)$contentIdentifier) + ->execute() + ->fetchColumn(0); + return $this->getViewFromFlexForm($flexForm); + } + /** * @param string $view can be "new", "edit" or "invitation" * @param int $pageIdentifier @@ -43,6 +60,22 @@ public function isPluginWithViewOnGivenPage(string $view, int $pageIdentifier): return false; } + /** + * @param string $flexForm + * @return string + */ + protected function getViewFromFlexForm(string $flexForm): string + { + $view = ''; + $flexFormService = ObjectUtility::getObjectManager()->get(FlexFormService::class); + $settings = $flexFormService->convertFlexFormContentToArray($flexForm); + if (!empty($settings['switchableControllerActions']) + && in_array($settings['switchableControllerActions'], $this->scaString)) { + $view = array_search($settings['switchableControllerActions'], $this->scaString); + } + return $view; + } + /** * @param string $view * @param string $pluginConfiguration diff --git a/Classes/Domain/Service/ValidationSettingsService.php b/Classes/Domain/Service/ValidationSettingsService.php index 5a65d97807..b3466319c7 100644 --- a/Classes/Domain/Service/ValidationSettingsService.php +++ b/Classes/Domain/Service/ValidationSettingsService.php @@ -63,11 +63,13 @@ public function getValidationStringForField(string $fieldName): string { $string = ''; $validationSettings = $this->getSettings()[$this->controllerName][$this->validationName][$fieldName]; - foreach ($validationSettings as $validation => $configuration) { - if (!empty($string)) { - $string .= ','; + if (is_array($validationSettings)) { + foreach ($validationSettings as $validation => $configuration) { + if (!empty($string)) { + $string .= ','; + } + $string .= $this->getSingleValidationString($validation, $configuration); } - $string .= $this->getSingleValidationString($validation, $configuration); } return $string; } @@ -105,7 +107,7 @@ protected function getSingleValidationString($validation, $configuration) * @param string $validation * @return bool */ - protected function isSimpleValidation($validation) + protected function isSimpleValidation($validation): bool { if (in_array($validation, $this->simpleValidations)) { return true; diff --git a/Classes/Domain/Validator/ClientsideValidator.php b/Classes/Domain/Validator/ClientsideValidator.php index bd9a285afa..8b561c51ac 100644 --- a/Classes/Domain/Validator/ClientsideValidator.php +++ b/Classes/Domain/Validator/ClientsideValidator.php @@ -3,6 +3,9 @@ namespace In2code\Femanager\Domain\Validator; use In2code\Femanager\Domain\Model\User; +use In2code\Femanager\Domain\Repository\PluginRepository; +use In2code\Femanager\Domain\Service\ValidationSettingsService; +use In2code\Femanager\Utility\ObjectUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use In2code\Femanager\Utility\LocalizationUtility; use In2code\Femanager\Utility\StringUtility; @@ -59,6 +62,16 @@ class ClientsideValidator extends AbstractValidator */ protected $additionalValue; + /** + * @var int + */ + protected $plugin = 0; + + /** + * @var string + */ + protected $actionName = ''; + /** * Validate Field * @@ -66,10 +79,12 @@ class ClientsideValidator extends AbstractValidator */ public function validateField() { - $validationSettings = GeneralUtility::trimExplode(',', $this->validationSettingsString, true); - $validationSettings = str_replace('|', ',', $validationSettings); + if ($this->isValidationSettingsDifferentToGlobalSettings()) { + $this->addMessage('validationErrorGeneral'); + return false; + } - foreach ($validationSettings as $validationSetting) { + foreach ($this->getValidationSettings() as $validationSetting) { switch ($validationSetting) { case 'required': if (!$this->validateRequired($this->getValue())) { @@ -193,10 +208,9 @@ public function validateField() $mainSetting = StringUtility::getValuesBeforeBrackets($validationSetting); if (method_exists($this, 'validate' . ucfirst($mainSetting))) { if (!$this->{'validate' . ucfirst($mainSetting)}( - $this->getValue(), - StringUtility::getValuesInBrackets($validationSetting) - ) - ) { + $this->getValue(), + StringUtility::getValuesInBrackets($validationSetting) + )) { $this->addMessage('validationError' . ucfirst($mainSetting)); $this->isValid = false; } @@ -207,6 +221,18 @@ public function validateField() return $this->isValid; } + /** + * This function checks the given validation string from user input against settings in TypoScript. If both strings + * do not match, it could be possible that there is a manipulation. In this case, we stop validation and return a + * global error message + * + * @return bool + */ + protected function isValidationSettingsDifferentToGlobalSettings(): bool + { + return $this->getValidationSettingsString() !== $this->getValidationSettingsFromTypoScript(); + } + /** * Set validation * @@ -220,8 +246,6 @@ public function setValidationSettingsString($validationSettingsString) } /** - * Get validation - * * @return string */ public function getValidationSettingsString() @@ -229,6 +253,30 @@ public function getValidationSettingsString() return $this->validationSettingsString; } + /** + * @return string + */ + public function getValidationSettingsFromTypoScript(): string + { + $controllerName = $this->getControllerName(); + $validationService = ObjectUtility::getObjectManager()->get( + ValidationSettingsService::class, + $controllerName, + $this->getValidationName() + ); + return $validationService->getValidationStringForField($this->fieldName); + } + + /** + * @return array + */ + protected function getValidationSettings(): array + { + $validationSettings = GeneralUtility::trimExplode(',', $this->validationSettingsString, true); + $validationSettings = str_replace('|', ',', $validationSettings); + return $validationSettings; + } + /** * @param string $value * @return ClientsideValidator @@ -330,6 +378,64 @@ public function getAdditionalValue() return $this->additionalValue; } + /** + * @return int + */ + public function getPlugin(): int + { + return $this->plugin; + } + + /** + * @param int $plugin + * @return ClientsideValidator + */ + public function setPlugin(int $plugin) + { + $this->plugin = $plugin; + return $this; + } + + /** + * @return string + */ + public function getActionName(): string + { + return $this->actionName; + } + + /** + * @param string $actionName + * @return ClientsideValidator + */ + public function setActionName(string $actionName) + { + $this->actionName = $actionName; + return $this; + } + + /** + * @return string + */ + protected function getValidationName(): string + { + $validationName = 'validation'; + if ($this->getControllerName() === 'invitation' && $this->getActionName() === 'edit') { + $validationName = 'validationEdit'; + } + return $validationName; + } + + /** + * @return string + */ + protected function getControllerName(): string + { + $pluginRepository = ObjectUtility::getObjectManager()->get(PluginRepository::class); + $controllerName = $pluginRepository->getControllerNameByPluginSettings($this->getPlugin()); + return $controllerName; + } + /** * @param mixed $value */ diff --git a/Resources/Private/JavaScript/Validation.js b/Resources/Private/JavaScript/Validation.js index f192e3c238..44684a4405 100644 --- a/Resources/Private/JavaScript/Validation.js +++ b/Resources/Private/JavaScript/Validation.js @@ -84,7 +84,9 @@ jQuery.fn.femanagerValidation = function($) { * @return void */ function validateField(element, countForSubmit) { - var user = element.closest('form').find('div:first').find('input[name="tx_femanager_pi1[user][__identity]"]').val(); + var $form = element.closest('form'); + var user = $form.find('div:first').find('input[name="tx_femanager_pi1[user][__identity]"]').val(); + var action = $form.find('div:first').find('input[name="tx_femanager_pi1[__referrer][@action]"]').val(); var url = Femanager.getBaseUrl() + 'index.php' + '?eID=' + 'femanagerValidate'; var validations = getValidations(element); var elementValue = element.val(); @@ -110,6 +112,8 @@ jQuery.fn.femanagerValidation = function($) { 'tx_femanager_pi1[field]': getFieldName(element), 'tx_femanager_pi1[user]': (user !== undefined ? user : ''), 'tx_femanager_pi1[additionalValue]=': (additionalValue ? additionalValue : ''), + 'tx_femanager_pi1[plugin]=': $form.data('femanager-plugin'), + 'tx_femanager_pi1[action]=': action, 'storagePid': $('#femanagerStoragePid').val(), 'L': $('#femanagerLanguage').val(), 'id': $('#femanagerPid').val() diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf index 3571ce2a12..e6a281d501 100644 --- a/Resources/Private/Language/locallang.xlf +++ b/Resources/Private/Language/locallang.xlf @@ -245,6 +245,9 @@ Wrong Captcha code + + Field could not be validated + Please confirm a new registration diff --git a/Resources/Private/Templates/Edit/Edit.html b/Resources/Private/Templates/Edit/Edit.html index 597ad4a9cd..c1cefc3676 100644 --- a/Resources/Private/Templates/Edit/Edit.html +++ b/Resources/Private/Templates/Edit/Edit.html @@ -19,6 +19,7 @@ object="{user}" action="update" enctype="multipart/form-data" + additionalAttributes="{data-femanager-plugin:data.uid}" class="form-horizontal {f:if(condition:'{settings.edit.validation._enable.client}',then:'feManagerValidation',else:'')}"> diff --git a/Resources/Private/Templates/Invitation/Edit.html b/Resources/Private/Templates/Invitation/Edit.html index 7e528dd13b..8a7593070f 100644 --- a/Resources/Private/Templates/Invitation/Edit.html +++ b/Resources/Private/Templates/Invitation/Edit.html @@ -12,7 +12,12 @@ - + diff --git a/Resources/Private/Templates/Invitation/New.html b/Resources/Private/Templates/Invitation/New.html index 5062c452b1..7833c37ab8 100644 --- a/Resources/Private/Templates/Invitation/New.html +++ b/Resources/Private/Templates/Invitation/New.html @@ -14,7 +14,12 @@ - + diff --git a/Resources/Private/Templates/New/New.html b/Resources/Private/Templates/New/New.html index 32fed8d623..094575ea57 100644 --- a/Resources/Private/Templates/New/New.html +++ b/Resources/Private/Templates/New/New.html @@ -16,6 +16,7 @@ object="{user}" action="create" enctype="multipart/form-data" + additionalAttributes="{data-femanager-plugin:data.uid}" class="form-horizontal {f:if(condition:'{settings.new.validation._enable.client}',then:'feManagerValidation',else:'')}"> diff --git a/Resources/Public/JavaScript/Validation.min.js b/Resources/Public/JavaScript/Validation.min.js index aa75130a56..31563cf1c5 100644 --- a/Resources/Public/JavaScript/Validation.min.js +++ b/Resources/Public/JavaScript/Validation.min.js @@ -1 +1 @@ -jQuery.fn.femanagerValidation=function(e){function a(a){c=new m({numRequest:a.find("*[data-validation]").length,element:a}),a.find("*[data-validation]").each(function(){t(e(this),!0)})}function t(a,t){var o=a.closest("form").find("div:first").find('input[name="tx_femanager_pi1[user][__identity]"]').val(),d=Femanager.getBaseUrl()+"index.php?eID=femanagerValidate",p=l(a),m=a.val();"checkbox"==a.prop("type")&&0==a.prop("checked")&&(m="");var v="";if(s(p,"sameAs")){var g=s(p,"sameAs"),h=f(g),b=e('input[name="tx_femanager_pi1[user]['+h+']"]');v=b.val(),"checkbox"==b.prop("type")&&0==b.prop("checked")&&(v="")}e.ajax({url:d,data:{"tx_femanager_pi1[validation]":a.attr("data-validation"),"tx_femanager_pi1[value]":m,"tx_femanager_pi1[field]":n(a),"tx_femanager_pi1[user]":void 0!==o?o:"","tx_femanager_pi1[additionalValue]=":v?v:"",storagePid:e("#femanagerStoragePid").val(),L:e("#femanagerLanguage").val(),id:e("#femanagerPid").val()},type:"POST",cache:!1,success:function(n){if(t&&c.addCallbackToQueue(!0),n)try{var o=e.parseJSON(n);o.validate?i(a):r(a,o.message)}catch(s){a.before(n)}},error:function(){u()}})}function n(e){var a="",t=e.prop("name").split("[");return void 0!==t[2]&&(a=t[2].replace("]","")),a}function r(a,t){i(a);var n=e(".femanager_validation_container").html().replace("###messages###",t);a.before(n),a.closest(".form-group").addClass("has-error"),a.addClass("error")}function i(e){e.closest(".form-group").removeClass("has-error"),e.siblings(".alert").remove(),e.removeClass("error")}function o(a){0==a.find(".error").length?(p=!0,a.submit()):e("html,body").animate({scrollTop:a.find(".error:first").offset().top})}function s(e,a){for(var t=0;t