Files
StefanandClaude Opus 5.5 4443bba63c
Playwright Tests / test (push) Canceled after 0s
fix(forms): never submit an invalid form; unlock password-change dialog
serializeObject() returns null for an invalid form, but most callers sent
the result anyway. Add $.fn.rejectInvalid (stop the spinner, let the
browser report the offending field) and use it at every call site.

Bugs fixed:
- Password change: on a mismatch the spinner kept running, and the custom
  validity on "npw" was never cleared, so the browser blocked every later
  submit even after the passwords matched. It is now cleared as soon as
  either password field is edited.
- sendForm: options.complete referenced an undefined jqXHR (ReferenceError)
  and an invalid form was posted with partial data.
- login.send: an invalid form threw a TypeError on qs.loginaccount.
- postXT({ form }): an invalid form was posted with empty data.
- Form dialogs without required fields had no "Bitte überprüfen Sie Ihre
  Eingaben" note, so a rejected submit showed nothing.

Hardening: null guards for the user, user-group, re-login, SMS password,
admin specialties and report-parameter submits.

Add e2e_tests/form-validation.cjs covering each path against the real
scripts; it fails on the previous code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 18:11:05 +02:00

1 line
7.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
let $uct={mdl:"Benutzerverwaltung",rel:"Neu Laden",col_name:"Name",col_email:"E-Mail",col_groups:"Gruppen",col_status:"Status",active:"Aktiv",disabled:"Deaktiviert",loadfail:"Die Benutzerliste konnte nicht geladen werden.",empty:"Es sind keine Benutzerkonten vorhanden.",newuser:"Neuer Benutzer",newuser_btn:"Neuer Benutzer",firstname_field:"Vorname",name_field:"Nachname",title_field:"Titel",gender_field:"Anrede",gender_m:"Herr",gender_f:"Frau",mobile_field:"Mobil",create_sent:"Das Benutzerkonto wurde angelegt, die Zugangsdaten wurden per E-Mail versendet.",create_noemail:"Das Benutzerkonto wurde angelegt, die Zugangsdaten konnten aber nicht per E-Mail zugestellt werden.",delete:"Benutzer löschen",delete_confirm:'Soll der Benutzer "{0}" wirklich gelöscht werden?',pwdreset:"Passwort zurücksetzen",pwdreset_btn:"Zurücksetzen",pwd_field:"Neues Passwort",pwd_hint:"Leer lassen, um automatisch ein Passwort zu generieren. In jedem Fall wird das neue Passwort per E-Mail an den Benutzer gesendet.",pwdreset_sent:"Das neue Passwort wurde per E-Mail an den Benutzer gesendet.",pwdreset_noemail:"Das Passwort wurde zurückgesetzt, konnte aber nicht per E-Mail zugestellt werden.",email:"E-Mail-Adresse ändern",email_field:"E-Mail-Adresse",groups:"Gruppenzugehörigkeit",groups_title:"Gruppen – {0}",err:{requirements:"Das Passwort erfüllt nicht die Mindestanforderungen (mind. 6 Zeichen).",duplicate_email:"Diese E-Mail-Adresse ist bereits einem anderen Benutzerkonto zugeordnet.",reset_failed:"Das Passwort konnte nicht zurückgesetzt werden.",change_failed:"Die Änderung konnte nicht gespeichert werden.",create_failed:"Das Benutzerkonto konnte nicht angelegt werden.",delete_failed:"Der Benutzer konnte nicht gelöscht werden.",cannot_delete_self:"Das eigene Benutzerkonto kann nicht gelöscht werden."},err_generic:"Die Änderung konnte nicht gespeichert werden."},$usr={init2:function(){$ocms.getScript([],(function(){$usr.init3()}))},init3:function(){$fis.cf(!0),$fis.lf(!0),$("#activemodule").text($uct.mdl),$usr.eM(),$usr.renderLst()},eM:function(e){let t=[{lbl:$uct.newuser_btn,fnc:$usr.createDlg}];return!0===bool(e,!1)&&t.push({lbl:$uct.rel,fnc:$usr.renderLst}),$("#topbar").ocmsmenu(t)},iMn:function(e){return $("#topbar").ocmsmenu([{lbl:$uct.pwdreset,fnc:function(){$usr.pwdResetDlg(e)}},{lbl:$uct.email,fnc:function(){$usr.emailDlg(e)}},{lbl:$uct.groups,fnc:function(){$usr.groupsDlg(e)}},{lbl:$uct.delete,fnc:function(){$usr.deleteUser(e)}}])},initials:function(e,t){return((e||"").trim().charAt(0)+(t||"").trim().charAt(0)).toUpperCase()||"?"},buildRow:function(e){let t=!0===bool(e.disabled,!1),r=$$.dc("usr_row",{id:"usr"+e.useraccount_id});return $$.dc("usr_avatar",r).text($usr.initials(e.firstname,e.name)),$$.dc("usr_col_name",r).text(`${e.firstname||""} ${e.name||""}`.trim()),$$.dc("usr_col_email",r).text(e.email||""),$$.dc("usr_col_groups",r).text(e.groups||"").attr("title",e.groups||""),$$.dc("usr_col_status",r).append($$.dc(t?"usr_pill usr_pill_off":"usr_pill usr_pill_on").text(t?$uct.disabled:$uct.active)),r.click((function(){r.toggleClass("selected").siblings().rC("selected"),!0===r.is(".selected")?$usr.iMn(e):$usr.eM(!0)})),r},refreshRow:function(e){0!==$("#usr"+e.useraccount_id).length?$ocms.postXT({url:$ocms.url("usr/list"),data:{useraccount_id:e.useraccount_id},success:function(t){let r=(t.users||[])[0],n=$("#usr"+e.useraccount_id);if(!r||0===n.length)return void $usr.renderLst();let s=n.is(".selected"),u=$usr.buildRow(r).toggleClass("selected",s);n.replaceWith(u),s&&$usr.iMn(r)},error:function(){$usr.renderLst()}}):$usr.renderLst()},renderLst:function(){let e=$fis.frm_list(!0,!0).ldng(1),t=$$.dc("usrfrm",e);$usr.eM(!0),$ocms.postXT({url:$ocms.url("usr/list"),success:function(e){t.empty();let r=$$.dc("usr_grid",t),n=$$.dc("usr_row usr_row_hd",r);$$.dc("usr_col_avatar",n),$$.dc("usr_col_name",n).text($uct.col_name),$$.dc("usr_col_email",n).text($uct.col_email),$$.dc("usr_col_groups",n).text($uct.col_groups),$$.dc("usr_col_status",n).text($uct.col_status),0!==(e.users||[]).length?$.each(e.users||[],(function(e,t){r.append($usr.buildRow(t))})):$$.dc("usr_empty",r).text($uct.empty)},error:function(){t.empty(),$$.dc("usr_err",t).text($uct.loadfail)},complete:function(){e.ldng(0)}})},createDlg:function(){$ocms.dlgform([{name:"firstname",label:$uct.firstname_field,type:"string",required:!0},{name:"name",label:$uct.name_field,type:"string",required:!0},{name:"email",label:$uct.email_field,type:"email",required:!0},{name:"title",label:$uct.title_field,type:"string"},{name:"gender",label:$uct.gender_field,type:"select",url:[["",""],["m",$uct.gender_m],["f",$uct.gender_f]]},{name:"mobile",label:$uct.mobile_field,type:"string"}],{title:$uct.newuser,button:$uct.newuser_btn,submit:function(e){let t=$(this).ldng(1),r=t.serializeObject(!0,{typedvalues:!0});null!==r?$ocms.postXT({url:$ocms.url("usr/create"),data:r,success:function(e){alert(!0===e.emailed?$uct.create_sent:$uct.create_noemail),t.trigger("modal_close")},error:function(e){let t=((e||{}).responseJSON||{}).error;alert($uct.err[t]||$uct.err_generic)},complete:function(){t.ldng(0),$usr.renderLst()}}):t.rejectInvalid()}})},deleteUser:function(e){let t=`${e.firstname||""} ${e.name||""}`.trim();confirm(string($uct.delete_confirm,[t]))&&$ocms.postXT({url:$ocms.url("usr/delete"),data:{useraccount_id:e.useraccount_id},success:function(){$usr.eM(!0)},error:function(e){let t=((e||{}).responseJSON||{}).error;alert($uct.err[t]||$uct.err_generic)},complete:function(){$usr.renderLst()}})},pwdResetDlg:function(e){$ocms.dlgform([{name:"useraccount_id",type:"hidden",value:e.useraccount_id},{name:"newpassword",label:$uct.pwd_field,type:"string",note:$uct.pwd_hint}],{title:$uct.pwdreset,button:$uct.pwdreset_btn,submit:function(e){let t=$(this).ldng(1),r=t.serializeObject(!0,{typedvalues:!0});null!==r?$ocms.postXT({url:$ocms.url("usr/pwdreset"),data:r,success:function(e){alert(!0===e.emailed?$uct.pwdreset_sent:$uct.pwdreset_noemail),t.trigger("modal_close")},error:function(e){let t=((e||{}).responseJSON||{}).error;alert($uct.err[t]||$uct.err_generic)},complete:function(){t.ldng(0),$usr.renderLst()}}):t.rejectInvalid()}})},emailDlg:function(e){$ocms.dlgform([{name:"useraccount_id",type:"hidden",value:e.useraccount_id},{name:"email",label:$uct.email_field,type:"email",required:!0,value:e.email}],{title:$uct.email,submit:function(t){let r=$(this).ldng(1),n=r.serializeObject(!0,{typedvalues:!0});null!==n?$ocms.postXT({url:$ocms.url("usr/email"),data:n,success:function(){r.trigger("modal_close")},error:function(e){let t=((e||{}).responseJSON||{}).error;alert($uct.err[t]||$uct.err_generic)},complete:function(){r.ldng(0),$usr.refreshRow(e)}}):r.rejectInvalid()}})},groupsDlg:function(e){let t=$$.dc("usr_groups_dlg");$ocms.postXT({url:$ocms.url("usr/groups"),data:{useraccount_id:e.useraccount_id},success:function(r){$.each(r.groups||[],(function(r,n){let s=$$.dc("usr_group_row",t),u="usrg"+n.usergroup_id,l=$$.i({type:"checkbox",id:u}).prop("checked",bool(n.member,!1)).appendTo(s);$$.lbl(n.name,{for:u}).appendTo(s),l.change((function(){let t=l.prop("checked");$ocms.postXT({url:$ocms.url("usr/groupset"),data:{useraccount_id:e.useraccount_id,usergroup_id:n.usergroup_id,member:t},success:function(){$usr.refreshRow(e)},error:function(){l.prop("checked",!t),alert($uct.err_generic)}})}))}))}}),$ocms.dlg(t,{title:string($uct.groups_title,[`${e.firstname||""} ${e.name||""}`.trim()]),size:[420,380]})}},$$usr={init2:$usr.init2,auth:{}};export default $$usr;