diff options
| -rw-r--r-- | lib/models/CaptchaChallenge.php | 2 | ||||
| -rw-r--r-- | resources/assets/javascripts/bootstrap/forms.js | 166 | ||||
| -rw-r--r-- | webpack.common.js | 7 |
3 files changed, 86 insertions, 89 deletions
diff --git a/lib/models/CaptchaChallenge.php b/lib/models/CaptchaChallenge.php index 446985d..20b0fdf 100644 --- a/lib/models/CaptchaChallenge.php +++ b/lib/models/CaptchaChallenge.php @@ -38,7 +38,7 @@ final class CaptchaChallenge extends SimpleORMap public static function createNewChallenge(): array { do { - $salt = time() . '-' . bin2hex(random_bytes(12)); + $salt = md5(time() . '-' . bin2hex(random_bytes(12))); $number = random_int(1e3, 1e5); } while (self::countBySql('salt = ? AND number = ?', [$salt, $number]) > 0); diff --git a/resources/assets/javascripts/bootstrap/forms.js b/resources/assets/javascripts/bootstrap/forms.js index a658cb7..9d7a63b 100644 --- a/resources/assets/javascripts/bootstrap/forms.js +++ b/resources/assets/javascripts/bootstrap/forms.js @@ -278,41 +278,30 @@ STUDIP.ready(function () { this.STUDIPFORM_VALIDATIONNOTES = []; this.STUDIPFORM_DISPLAYVALIDATION = true; - //validation: - let validation_promise = this.validate(); - validation_promise.then(validated => { - if (!validated) { - this.$el.scrollIntoView({ - behavior: 'smooth' - }); - return; - } - - if (this.STUDIPFORM_AUTOSAVEURL) { - let params = this.getFormValues(); - params.STUDIPFORM_AUTOSTORE = 1; + // validation: + this.validate() + .then(() => { + if (this.STUDIPFORM_AUTOSAVEURL) { + let params = this.getFormValues(); + params.STUDIPFORM_AUTOSTORE = 1; - let submit = function (url, params, redirect) { - $.ajax({ - url: url, - data: params, - type: 'post', - success(output) { - if (output === 'STUDIPFORM_STORE_SUCCESS' && redirect) { - //The form has been stored successfully: - window.location.href = redirect; - } else if (output !== 'STUDIPFORM_STORE_SUCCESS') { - Report.error($gettext('Es ist ein Fehler aufgetreten'), output); - } + $.post(this.STUDIPFORM_AUTOSAVEURL, params).done((output) => { + if (output === 'STUDIPFORM_STORE_SUCCESS' && this.STUDIPFORM_REDIRECTURL) { + //The form has been stored successfully: + window.location.href = this.STUDIPFORM_REDIRECTURL; + } else if (output !== 'STUDIPFORM_STORE_SUCCESS') { + Report.error($gettext('Es ist ein Fehler aufgetreten'), output); } }); - }; - submit(this.STUDIPFORM_AUTOSAVEURL, params, this.STUDIPFORM_REDIRECTURL); - } else { - this.STUDIPFORM_VALIDATED = true; - this.$el.submit(); + } else { + this.STUDIPFORM_VALIDATED = true; + this.$el.submit(); + } + }).catch(errors => { + this.STUDIPFORM_VALIDATIONNOTES = errors; + this.$el.scrollIntoView({behavior: 'smooth'}); } - }); + ); e.preventDefault(); }, getFormValues() { @@ -330,71 +319,72 @@ STUDIP.ready(function () { }); return params; }, - validate() { - this.STUDIPFORM_VALIDATIONNOTES = []; + async validate() { + this.$el.checkValidity(); + + // Check inputs + const inputs = this.$el.querySelectorAll('input,select,textarea'); + let notes = Array.from(inputs) + .filter(node => !node.validity.valid) + .map(node => { + const note = { + name: node.name, + label: node.labels[0].querySelector('.textlabel').innerText, + description: node.dataset.validation_requirement ?? $gettext('Fehler!'), + describedby: node.id + }; - return new Promise((resolve) => { - let validated = this.$el.checkValidity(); - - $(this.$el).find('input, select, textarea').each(function () { - if (!this.validity.valid) { - let note = { - name: this.name, - label: $(this.labels[0]).find('.textlabel').text(), - description: $gettext('Fehler!'), - describedby: this.id - }; - if ($(this).data('validation_requirement')) { - note.description = $(this).data('validation_requirement'); - } - if (this.validity.tooShort) { + if (node.validity.tooShort) { + note.description = $gettext( + 'Geben Sie mindestens %{min} Zeichen ein.', + { min: node.minLength } + ); + } + if (node.validity.valueMissing) { + if (node.type === 'checkbox') { + note.description = $gettext('Dieses Feld muss ausgewählt sein.'); + } else if (node.minLength > 0) { note.description = $gettext( - 'Geben Sie mindestens %{min} Zeichen ein.', - { min: this.minLength } + 'Hier muss ein Wert mit mindestens %{min} Zeichen eingetragen werden.', + { min: node.minLength } ); + } else { + note.description = $gettext('Hier muss ein Wert eingetragen werden.'); } - if (this.validity.valueMissing) { - if (this.type === 'checkbox') { - note.description = $gettext('Dieses Feld muss ausgewählt sein.'); - } else { - if (this.minLength > 0) { - note.description = $gettext( - 'Hier muss ein Wert mit mindestens %{min} Zeichen eingetragen werden.', - { min: this.minLength } - ); - } else { - note.description = $gettext('Hier muss ein Wert eingetragen werden.'); - } - - } - } - this.STUDIPFORM_VALIDATIONNOTES.push(note); } + + return note; }); - if (this.STUDIPFORM_SERVERVALIDATION) { - let params = this.getFormValues(); - if (this.STUDIPFORM_AUTOSAVEURL) { - params.STUDIPFORM_AUTOSTORE = 1; - } - params.STUDIPFORM_SERVERVALIDATION = 1; - - $.post(this.STUDIPFORM_VALIDATION_URL, params).done((output) => { - for (let i in output) { - this.STUDIPFORM_VALIDATIONNOTES.push({ - name: output[i].name, - label: output[i].label, - description: output[i].error, - describedby: null - }); - } - validated = this.STUDIPFORM_VALIDATIONNOTES.length < 1; - resolve(validated); - }); - } else { - resolve(validated); + // Optional server validation + if (this.STUDIPFORM_SERVERVALIDATION) { + let params = this.getFormValues(); + if (this.STUDIPFORM_AUTOSAVEURL) { + params.STUDIPFORM_AUTOSTORE = 1; } - }); + params.STUDIPFORM_SERVERVALIDATION = 1; + + const output = await fetch(this.STUDIPFORM_VALIDATION_URL, { + method: 'POST', + body: new URLSearchParams(params), + headers: {'X-Requested-With': 'XMLHttpRequest'} + }).then(response => response.json()); + notes.push( + ...output.map(item => ({ + name: item.name, + label: item.label, + description: item.error, + describedby: null + })) + ); + } + + // Resolve or reject based on present error notes + if (notes.length > 0) { + return Promise.reject(notes); + } else { + return Promise.resolve(); + } }, setInputs(inputs) { for (const [key, value] of Object.entries(inputs)) { diff --git a/webpack.common.js b/webpack.common.js index 91ead2a..825dc89 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -104,6 +104,13 @@ module.exports = { { test: /\.vue$/, loader: 'vue-loader', + options: { + compilerOptions: { + isCustomElement(tag) { + return ['altcha-widget'].includes(tag); + } + } + } } ] }, |
