This is an automated email from the ASF dual-hosted git repository. riemer pushed a commit to branch add-optional-terms-acknowledgment in repository https://gitbox.apache.org/repos/asf/streampipes.git
commit fa10c95cd464953b49ddfa6ff0fc7458b41e7f12 Author: Dominik Riemer <[email protected]> AuthorDate: Thu Aug 28 09:19:43 2025 +0200 fix bug in user form --- .../edit-user-dialog.component.html | 342 +++++++++++---------- .../edit-user-dialog/edit-user-dialog.component.ts | 145 ++++++--- 2 files changed, 269 insertions(+), 218 deletions(-) diff --git a/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.html b/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.html index d46527b426..9b057f8c88 100644 --- a/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.html +++ b/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.html @@ -16,185 +16,193 @@ ~ --> -<div class="sp-dialog-container"> - <div class="sp-dialog-content"> - <div fxFlex="100" fxLayout="column" class="p-15"> - <sp-warning-box *ngIf="isUserAccount && isExternalProvider"> - Settings of externally-managed users cannot be changed. - </sp-warning-box> - <form [formGroup]="parentForm" fxFlex="100" fxLayout="column"> - <div class="general-options-panel" fxLayout="column"> - <span class="general-options-header">Basics</span> - <mat-error *ngIf="registrationError">{{ - registrationError - }}</mat-error> - <mat-form-field color="accent" *ngIf="!isUserAccount"> - <mat-label>Username</mat-label> - <input - formControlName="username" - fxFlex - matInput - required - /> - </mat-form-field> - <mat-form-field color="accent" *ngIf="isUserAccount"> - <mat-label>Email</mat-label> - <input - formControlName="username" - fxFlex - type="email" - matInput - data-cy="new-user-email" - /> - <mat-error>Must be a valid email address.</mat-error> - </mat-form-field> - <div class="email-changed" *ngIf="emailChanged"> - Changing the current user's email will require a - re-login. +@if (formAvailable) { + <div class="sp-dialog-container"> + <div class="sp-dialog-content"> + <div fxFlex="100" fxLayout="column" class="p-15"> + <sp-warning-box *ngIf="isUserAccount && isExternalProvider"> + Settings of externally-managed users cannot be changed. + </sp-warning-box> + <form [formGroup]="parentForm" fxFlex="100" fxLayout="column"> + <div class="general-options-panel" fxLayout="column"> + <span class="general-options-header">Basics</span> + <mat-error *ngIf="registrationError">{{ + registrationError + }}</mat-error> + <mat-form-field color="accent" *ngIf="!isUserAccount"> + <mat-label>Username</mat-label> + <input + formControlName="username" + fxFlex + matInput + required + /> + </mat-form-field> + <mat-form-field color="accent" *ngIf="isUserAccount"> + <mat-label>Email</mat-label> + <input + formControlName="username" + fxFlex + type="email" + matInput + data-cy="new-user-email" + /> + <mat-error + >Must be a valid email address.</mat-error + > + </mat-form-field> + <div class="email-changed" *ngIf="emailChanged"> + Changing the current user's email will require a + re-login. + </div> + <mat-form-field color="accent" *ngIf="isUserAccount"> + <mat-label>Full Name</mat-label> + <input + formControlName="fullName" + fxFlex + matInput + data-cy="new-user-full-name" + /> + </mat-form-field> </div> - <mat-form-field color="accent" *ngIf="isUserAccount"> - <mat-label>Full Name</mat-label> - <input - formControlName="fullName" - fxFlex - matInput - data-cy="new-user-full-name" - /> - </mat-form-field> - </div> - <div - fxLayout="column" - class="general-options-panel" - *ngIf="!editMode && isUserAccount" - > - <span class="general-options-header">Password</span> - <mat-checkbox - formControlName="sendPasswordToUser" - *ngIf="emailConfigured" - >Auto-create password and send to user</mat-checkbox - > - <mat-form-field color="accent" *ngIf="!sendPasswordToUser"> - <mat-label>Initial password</mat-label> - <input - formControlName="password" - fxFlex - type="password" - matInput - required - data-cy="new-user-password" - /> - </mat-form-field> - <mat-form-field color="accent" *ngIf="!sendPasswordToUser"> - <mat-label>Repeat password</mat-label> - <input - formControlName="repeatPassword" - fxFlex - type="password" - matInput - required - data-cy="new-user-password-repeat" - /> - </mat-form-field> - <mat-error *ngIf="parentForm.hasError('notMatching')" - >Passwords do not match.</mat-error - > - </div> - <div - fxLayout="column" - class="general-options-panel" - *ngIf="!isUserAccount" - > - <span class="general-options-header">Authentication</span> - <mat-form-field color="accent"> - <mat-label>Client Secret</mat-label> - <input - formControlName="clientSecret" - fxFlex - type="password" - matInput - required - /> - </mat-form-field> - <mat-error *ngIf="parentForm.controls.clientSecret.errors" - >Minimum length 35 characters.</mat-error - > - </div> - <div fxLayout="column" class="general-options-panel"> - <span class="general-options-header">Groups</span> - <mat-checkbox - *ngFor="let group of availableGroups" - [disabled]=" - isExternalProvider && isExternallyManagedRoles - " - [value]="group.groupId" - [checked]="user.groups.indexOf(group.groupId) > -1" - (change)="changeGroupAssignment($event)" + <div + fxLayout="column" + class="general-options-panel" + *ngIf="!editMode && isUserAccount" > - {{ group.groupName }} - </mat-checkbox> - </div> - <div fxLayout="column" class="general-options-panel"> - <span class="general-options-header">Roles</span> - <mat-checkbox - *ngFor="let role of availableRoles$ | async" - [value]="role.elementId" - [disabled]=" - isExternalProvider && isExternallyManagedRoles - " - [checked]="user.roles.indexOf(role.elementId) > -1" - (change)="changeRoleAssignment($event)" - [attr.data-cy]="'role-' + role.elementId" + <span class="general-options-header">Password</span> + <mat-checkbox + formControlName="sendPasswordToUser" + *ngIf="emailConfigured" + >Auto-create password and send to user</mat-checkbox + > + <mat-form-field color="accent"> + <mat-label>Initial password</mat-label> + <input + formControlName="password" + fxFlex + type="password" + matInput + required + data-cy="new-user-password" + /> + </mat-form-field> + <mat-form-field color="accent"> + <mat-label>Repeat password</mat-label> + <input + formControlName="repeatPassword" + fxFlex + type="password" + matInput + required + data-cy="new-user-password-repeat" + /> + </mat-form-field> + <mat-error *ngIf="parentForm.hasError('notMatching')" + >Passwords do not match.</mat-error + > + </div> + <div + fxLayout="column" + class="general-options-panel" + *ngIf="!isUserAccount" > - {{ role.label }} - </mat-checkbox> - </div> - @if (!isExternalProvider) { + <span class="general-options-header" + >Authentication</span + > + <mat-form-field color="accent"> + <mat-label>Client Secret</mat-label> + <input + formControlName="clientSecret" + fxFlex + type="password" + matInput + required + /> + </mat-form-field> + <mat-error + *ngIf="parentForm.controls.clientSecret.errors" + >Minimum length 35 characters.</mat-error + > + </div> <div fxLayout="column" class="general-options-panel"> - <span class="general-options-header">Account</span> + <span class="general-options-header">Groups</span> <mat-checkbox - formControlName="accountEnabled" - data-cy="new-user-enabled" + *ngFor="let group of availableGroups" + [disabled]=" + isExternalProvider && isExternallyManagedRoles + " + [value]="group.groupId" + [checked]="user.groups.indexOf(group.groupId) > -1" + (change)="changeGroupAssignment($event)" > - Enabled + {{ group.groupName }} </mat-checkbox> + </div> + <div fxLayout="column" class="general-options-panel"> + <span class="general-options-header">Roles</span> <mat-checkbox - formControlName="accountLocked" - data-cy="new-user-locked" + *ngFor="let role of availableRoles$ | async" + [value]="role.elementId" + [disabled]=" + isExternalProvider && isExternallyManagedRoles + " + [checked]="user.roles.indexOf(role.elementId) > -1" + (change)="changeRoleAssignment($event)" + [attr.data-cy]="'role-' + role.elementId" > - Locked + {{ role.label }} </mat-checkbox> </div> - } - </form> + @if (!isExternalProvider) { + <div fxLayout="column" class="general-options-panel"> + <span class="general-options-header">Account</span> + <mat-checkbox + formControlName="accountEnabled" + data-cy="new-user-enabled" + > + Enabled + </mat-checkbox> + <mat-checkbox + formControlName="accountLocked" + data-cy="new-user-locked" + > + Locked + </mat-checkbox> + </div> + } + </form> + </div> </div> - </div> - <mat-divider></mat-divider> - <div class="sp-dialog-actions"> - <div fxLayout="column"> - <div fxLayout="row"> - <button - mat-button - mat-raised-button - color="accent" - (click)="save()" - style="margin-right: 10px" - [disabled]=" - parentForm.invalid || - (isExternalProvider && isExternallyManagedRoles) - " - data-cy="sp-element-edit-user-save" - > - <i class="material-icons">save</i><span> Save</span> - </button> - <button - mat-button - mat-raised-button - class="mat-basic" - (click)="close(false)" - > - Cancel - </button> + <mat-divider></mat-divider> + <div class="sp-dialog-actions"> + <div fxLayout="column"> + <div fxLayout="row"> + <button + mat-button + mat-raised-button + color="accent" + (click)="save()" + style="margin-right: 10px" + [disabled]=" + parentForm.invalid || + (isExternalProvider && isExternallyManagedRoles) + " + data-cy="sp-element-edit-user-save" + > + <i class="material-icons">save</i + ><span> Save</span> + </button> + <button + mat-button + mat-raised-button + class="mat-basic" + (click)="close(false)" + > + Cancel + </button> + </div> </div> </div> </div> -</div> +} diff --git a/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.ts b/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.ts index a6ff998ed0..b00a75a65c 100644 --- a/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.ts +++ b/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.ts @@ -29,6 +29,7 @@ import { } from '@streampipes/platform-services'; import { AbstractControl, + FormControl, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, @@ -72,6 +73,7 @@ export class EditUserDialogComponent implements OnInit { sendPasswordToUser = false; emailChanged = false; emailConfigured = false; + formAvailable = false; constructor( private dialogRef: DialogRef<EditUserDialogComponent>, @@ -89,8 +91,6 @@ export class EditUserDialogComponent implements OnInit { this.initRoleFilter(); this.loadInitialData(); this.cloneUser(); - this.initForm(); - this.handleFormChanges(); } save() { @@ -103,6 +103,48 @@ export class EditUserDialogComponent implements OnInit { : 'Unknown error'; }; + if (!this.isUserAccount || !this.isExternalProvider) { + this.clonedUser.username = this.parentForm.get('username').value; + } + + if (!this.isExternalProvider) { + this.clonedUser.accountLocked = + this.parentForm.get('accountLocked').value; + this.clonedUser.accountEnabled = + this.parentForm.get('accountEnabled').value; + } + + if (this.clonedUser instanceof UserAccount) { + this.emailChanged = + this.clonedUser.username !== this.user.username && + this.user.username === + this.currentUserService.getCurrentUser().username && + this.editMode; + + if (!this.isExternalProvider) { + this.clonedUser.fullName = + this.parentForm.get('fullName').value; + } + if (!this.editMode) { + if ( + this.emailConfigured && + this.parentForm.get('sendPasswordToUser').value + ) { + this.sendPasswordToUser = + this.parentForm.get('sendPasswordToUser').value; + } else { + this.clonedUser.password = + this.parentForm.get('password').value; + } + } + } else { + const clientSecret = this.parentForm.get('clientSecret').value; + if (this.user.clientSecret !== clientSecret) { + this.clonedUser.clientSecret = clientSecret; + this.clonedUser.secretEncrypted = false; + } + } + if (this.editMode) { const update$ = this.isUserAccount ? this.userService.updateUser(this.clonedUser as UserAccount) @@ -150,6 +192,9 @@ export class EditUserDialogComponent implements OnInit { private loadInitialData(): void { this.mailConfigService.getMailConfig().subscribe(config => { this.emailConfigured = config.emailConfigured; + this.initForm(); + this.handleFormChanges(); + this.formAvailable = true; }); this.userGroupService.getAllUserGroups().subscribe(groups => { @@ -193,12 +238,6 @@ export class EditUserDialogComponent implements OnInit { ]; } - if (!this.editMode && this.clonedUser instanceof UserAccount) { - form['password'] = [this.clonedUser.password, Validators.required]; - form['repeatPassword'] = ['']; - form['sendPasswordToUser'] = [this.sendPasswordToUser]; - } - this.parentForm = this.fb.group(form, { validators: this.editMode || !this.isUserAccount @@ -206,6 +245,20 @@ export class EditUserDialogComponent implements OnInit { : this.checkPasswords, }); + if (!this.editMode && this.clonedUser instanceof UserAccount) { + if (this.emailConfigured) { + this.parentForm.addControl( + 'sendPasswordToUser', + new FormControl(this.sendPasswordToUser), + ); + } + this.parentForm.addControl( + 'password', + new FormControl(null, [Validators.required]), + ); + this.parentForm.addControl('repeatPassword', new FormControl(null)); + } + if (this.isExternalProvider) { this.parentForm.get('username')?.disable(); this.parentForm.get('fullName')?.disable(); @@ -214,67 +267,57 @@ export class EditUserDialogComponent implements OnInit { private handleFormChanges(): void { this.parentForm.valueChanges.subscribe(v => { - const raw = this.parentForm.getRawValue(); - if (!this.isUserAccount || !this.isExternalProvider) { - this.clonedUser.username = v.username; - } - - if (!this.isExternalProvider) { - this.clonedUser.accountLocked = raw.accountLocked; - this.clonedUser.accountEnabled = raw.accountEnabled; - } - - if (this.clonedUser instanceof UserAccount) { - this.emailChanged = - this.clonedUser.username !== this.user.username && - this.user.username === - this.currentUserService.getCurrentUser().username && - this.editMode; - - if (!this.isExternalProvider) { - this.clonedUser.fullName = v.fullName; - } - - if (!this.editMode) { + if (this.clonedUser instanceof UserAccount && !this.editMode) { + if (this.sendPasswordToUser !== v.sendPasswordToUser) { this.sendPasswordToUser = v.sendPasswordToUser; - if (this.sendPasswordToUser) { this.removePasswordControls(); } else { this.addPasswordControlsIfMissing(); - this.clonedUser.password = v.password; } } - } else { - if (this.user.clientSecret !== v.clientSecret) { - this.clonedUser.clientSecret = v.clientSecret; - this.clonedUser.secretEncrypted = false; - } } }); } private removePasswordControls(): void { - this.parentForm.removeControl('password'); - this.parentForm.removeControl('repeatPassword'); - this.parentForm.clearValidators(); + const pw = this.parentForm.get('password'); + const rp = this.parentForm.get('repeatPassword'); + pw.setValue(null); + rp.setValue(null); + + pw?.clearValidators(); + rp?.clearValidators(); + + pw?.disable({ emitEvent: false }); + rp?.disable({ emitEvent: false }); + + pw?.updateValueAndValidity({ emitEvent: false }); + rp?.updateValueAndValidity({ emitEvent: false }); + + this.parentForm.setValidators(null); + this.parentForm.updateValueAndValidity({ emitEvent: false }); + if (this.clonedUser instanceof UserAccount) { this.clonedUser.password = undefined; } } private addPasswordControlsIfMissing(): void { - if (!this.parentForm.get('password')) { - this.parentForm.addControl( - 'password', - new UntypedFormControl('', Validators.required), - ); - this.parentForm.addControl( - 'repeatPassword', - new UntypedFormControl(), - ); - this.parentForm.setValidators(this.checkPasswords); - } + const pw = this.parentForm.get('password'); + const rp = this.parentForm.get('repeatPassword'); + + pw?.enable({ emitEvent: false }); + rp?.enable({ emitEvent: false }); + + pw?.setValidators([Validators.required]); + rp?.setValidators([Validators.required]); + + this.parentForm.addValidators(this.checkPasswords); + + pw?.updateValueAndValidity({ emitEvent: false }); + rp?.updateValueAndValidity({ emitEvent: false }); + this.parentForm.updateValueAndValidity({ emitEvent: false }); } private getUsernameValidators(): ValidatorFn[] {
