-<div cdsCol
- [columnNumbers]="{md: 4}">
+<div cdsCol [columnNumbers]="{ md: 4 }">
<ng-container *cdFormLoading="loading">
- <form #frm="ngForm"
- #formDir="ngForm"
- [formGroup]="userForm"
- novalidate>
- <div i18n="form title"
- class="form-header">{{ action | titlecase }} {{ resource | upperFirst }}
+ <form #frm="ngForm" #formDir="ngForm" [formGroup]="userForm" novalidate>
+ <div i18n="form title" class="form-header">
+ {{ action | titlecase }} {{ resource | upperFirst }}
</div>
<!-- UserName -->
<div class="form-item">
- <cds-text-label labelInputID="username"
- cdRequiredField="Username"
- [invalid]="!userForm.controls.username.valid && userForm.controls.username.dirty"
- [invalidText]="usernameError"
- i18n>Username
- <input cdsText
- placeholder="Username..."
- i18n-placeholder
- id="username"
- formControlName="username"
- [invalid]="!userForm.controls.username.valid && userForm.controls.username.dirty"
- autofocus
- ngbTooltip="White spaces at the beginning and end will be trimmed"
- i18n-ngbTooltip
- cdTrim>
+ <cds-text-label
+ labelInputID="username"
+ cdRequiredField="Username"
+ [invalid]="!userForm.controls.username.valid && userForm.controls.username.dirty"
+ [invalidText]="usernameError"
+ i18n
+ >Username
+ <input
+ cdsText
+ placeholder="Username..."
+ i18n-placeholder
+ id="username"
+ formControlName="username"
+ [invalid]="!userForm.controls.username.valid && userForm.controls.username.dirty"
+ autofocus
+ ngbTooltip="White spaces at the beginning and end will be trimmed"
+ i18n-ngbTooltip
+ cdTrim
+ />
</cds-text-label>
<ng-template #usernameError>
<span *ngIf="userForm.showError('username', formDir, 'required')">
- <ng-container i18n>
- This field is required.
- </ng-container>
+ <ng-container i18n> This field is required. </ng-container>
</span>
<span *ngIf="userForm.showError('username', formDir, 'notUnique')">
- <ng-container i18n>
- The username already exists.
- </ng-container>
+ <ng-container i18n> The username already exists. </ng-container>
</span>
</ng-template>
</div>
<!-- Password -->
<div class="form-item">
- <cds-password-label labelInputID="password"
- label="Password..."
- [invalid]="!userForm.controls.password.valid && userForm.controls.password.dirty"
- [invalidText]="passwordError"
- i18n>Password
- <cd-helper *ngIf="passwordPolicyHelpText.length > 0"
- class="text-pre-wrap"
- html="{{ passwordPolicyHelpText }}">
- </cd-helper>
- <input cdsPassword
- type="password"
- placeholder="Password..."
- id="password"
- autocomplete="new-password"
- formControlName="password"
- >
+ <cds-password-label
+ labelInputID="password"
+ label="Password..."
+ [cdRequiredField]="mode !== userFormMode.editing && !isSSO ? 'Password' : ''"
+ [invalid]="!userForm.controls.password.valid && userForm.controls.password.dirty"
+ [invalidText]="passwordError"
+ i18n
+ >Password
+ <cd-helper
+ *ngIf="passwordPolicyHelpText.length > 0"
+ class="text-pre-wrap"
+ html="{{ passwordPolicyHelpText }}"
+ >
+ </cd-helper>
+ <input
+ cdsPassword
+ type="password"
+ placeholder="Password..."
+ id="password"
+ autocomplete="new-password"
+ formControlName="password"
+ />
</cds-password-label>
<ng-template #passwordError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('password', formDir, 'match')"
- i18n>Password confirmation doesn't match the password.
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('password', formDir, 'match')"
+ i18n
+ >Password confirmation doesn't match the password.
</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('password', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('password', formDir, 'passwordPolicy')">
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('password', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('password', formDir, 'passwordPolicy')"
+ >
{{ passwordValuation }}
</span>
</ng-template>
<!-- Confirm password -->
<div class="form-item">
- <cds-password-label labelInputID="confirmpassword"
- label="Confirm password..."
- [invalid]="!userForm.controls.confirmpassword.valid && userForm.controls.confirmpassword.dirty"
- [invalidText]="confirmpasswordError"
- i18n> Confirm password
- <input cdsPassword
- type="password"
- placeholder="Confirm password..."
- id="confirmpassword"
- formControlName="confirmpassword">
+ <cds-password-label
+ labelInputID="confirmpassword"
+ label="Confirm password..."
+ [cdRequiredField]="mode !== userFormMode.editing && !isSSO ? 'Confirm password' : ''"
+ [invalid]="
+ !userForm.controls.confirmpassword.valid && userForm.controls.confirmpassword.dirty
+ "
+ [invalidText]="confirmpasswordError"
+ i18n
+ >
+ Confirm password
+ <input
+ cdsPassword
+ type="password"
+ placeholder="Confirm password..."
+ id="confirmpassword"
+ formControlName="confirmpassword"
+ />
</cds-password-label>
<ng-template #confirmpasswordError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('confirmpassword', formDir, 'match')"
- i18n>Password confirmation doesn't match the password.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('confirmpassword', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('confirmpassword', formDir, 'match')"
+ i18n
+ >Password confirmation doesn't match the password.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('confirmpassword', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- Password expiration date -->
- <div class="form-item"
- *ngIf="!authStorageService.isSSO()">
- <cds-text-label [ngClass]="{'required': pwdExpirationSettings.pwdExpirationSpan > 0}">{{'Password Expiration Date'}}
- <cd-helper class="text-pre-wrap"
- *ngIf="pwdExpirationSettings.pwdExpirationSpan == 0">
+ <div class="form-item" *ngIf="!isSSO">
+ <cds-text-label [ngClass]="{ required: pwdExpirationSettings.pwdExpirationSpan > 0 }"
+ >{{ 'Password Expiration Date' }}
+ <cd-helper class="text-pre-wrap" *ngIf="pwdExpirationSettings.pwdExpirationSpan == 0">
<span>
- The Dashboard setting defining the expiration interval of
- passwords is currently set to <strong>0</strong>. This means
- if a date is set, the user password will only expire once.
+ The Dashboard setting defining the expiration interval of passwords is currently set
+ to <strong>0</strong>. This means if a date is set, the user password will only expire
+ once.
</span>
- <span>Consider configuring the Dashboard setting
- <a routerLink="/mgr-modules/edit/dashboard"
- class="alert-link">USER_PWD_EXPIRATION_SPAN</a>
- in order to let passwords expire periodically.
+ <span
+ >Consider configuring the Dashboard setting
+ <a routerLink="/mgr-modules/edit/dashboard" class="alert-link"
+ >USER_PWD_EXPIRATION_SPAN</a
+ >
+ in order to let passwords expire periodically.
</span>
</cd-helper>
- <cd-date-time-picker [control]="userForm.get('pwdExpirationDate')"
- placeHolder="Password expiration date"
- [hasTime]="false"
- [defaultDate]="passwordexp"
- i18n-name
- >
- </cd-date-time-picker>
- </cds-text-label>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('pwdExpirationDate', formDir, 'required')"
- i18n>This field is required.
+ <cd-date-time-picker
+ [control]="userForm.get('pwdExpirationDate')"
+ placeHolder="Password expiration date"
+ [hasTime]="false"
+ [defaultDate]="passwordexp"
+ i18n-name
+ >
+ </cd-date-time-picker>
+ </cds-text-label>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('pwdExpirationDate', formDir, 'required')"
+ i18n
+ >This field is required.
</span>
</div>
<!--Full Name-->
<div class="form-item">
- <cds-text-label for="name"
- i18n> Full Name
- <input cdsText
- type="text"
- placeholder="Full Name..."
- id="name"
- formControlName="name">
+ <cds-text-label for="name" i18n>
+ Full Name
+ <input cdsText type="text" placeholder="Full Name..." id="name" formControlName="name" />
</cds-text-label>
</div>
<!-- Email -->
<div class="form-item">
- <cds-text-label for="email"
- [invalid]="!userForm.controls.email.valid && userForm.controls.email.dirty"
- [invalidText]="emailError"
- i18n>
+ <cds-text-label
+ for="email"
+ [invalid]="!userForm.controls.email.valid && userForm.controls.email.dirty"
+ [invalidText]="emailError"
+ i18n
+ >
Email
- <input cdsText
- type="email"
- placeholder="Email..."
- id="email"
- formControlName="email">
+ <input cdsText type="email" placeholder="Email..." id="email" formControlName="email" />
</cds-text-label>
<ng-template #emailError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('email', formDir, 'email')"
- i18n>Invalid email.
+ <span class="invalid-feedback" *ngIf="userForm.showError('email', formDir, 'email')" i18n
+ >Invalid email.
</span>
</ng-template>
</div>
<!-- Roles -->
- <div class="form-item"
- *ngIf="allRoles">
- <cds-combo-box label="Roles"
- type="multi"
- selectionFeedback="top-after-reopen"
- for="roles"
- formControlName="roles"
- id="roles"
- placeholder="Select Roles..."
- i18n-placeholder
- [appendInline]="true"
- [items]="allRoles"
- itemValueKey="name"
- i18n>
+ <div class="form-item" *ngIf="allRoles">
+ <cds-combo-box
+ label="Roles"
+ type="multi"
+ selectionFeedback="top-after-reopen"
+ for="roles"
+ formControlName="roles"
+ id="roles"
+ placeholder="Select Roles..."
+ i18n-placeholder
+ [appendInline]="true"
+ [items]="allRoles"
+ itemValueKey="name"
+ [cdRequiredField]="!isSSO ? 'Roles' : ''"
+ [invalid]="!userForm.controls.roles.valid && userForm.controls.roles.dirty"
+ [invalidText]="rolesError"
+ i18n
+ >
<cds-dropdown-list></cds-dropdown-list>
</cds-combo-box>
+ <ng-template #rolesError>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('roles', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </ng-template>
</div>
<!-- Enabled -->
- <div class="form-item"
- *ngIf="!isCurrentUser()">
- <cds-checkbox id="enabled"
- formControlName="enabled"
- name="enabled"
- i18n>Enabled
+ <div class="form-item" *ngIf="!isCurrentUser()">
+ <cds-checkbox id="enabled" formControlName="enabled" name="enabled" i18n
+ >Enabled
</cds-checkbox>
</div>
<!-- Force change password -->
- <div class="form-item"
- *ngIf="!isCurrentUser() && !authStorageService.isSSO()">
- <cds-checkbox id="pwdUpdateRequired"
- formControlName="pwdUpdateRequired"
- name="pwdUpdateRequired"
- i18n>User must change password at next login
+ <div class="form-item" *ngIf="!isCurrentUser() && !isSSO">
+ <cds-checkbox
+ id="pwdUpdateRequired"
+ formControlName="pwdUpdateRequired"
+ name="pwdUpdateRequired"
+ i18n
+ >User must change password at next login
</cds-checkbox>
</div>
<!--Submit Button-->
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="userForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- wrappingClass="text-right">
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="userForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"
+ >
</cd-form-button-panel>
</form>
</ng-container>
</div>
<ng-template #removeSelfUserReadUpdatePermissionTpl>
- <p><strong i18n>You are about to remove "user read / update" permissions from your own user.</strong></p>
- <br>
+ <p>
+ <strong i18n
+ >You are about to remove "user read / update" permissions from your own user.</strong
+ >
+ </p>
+ <br />
<p i18n>If you continue, you will no longer be able to add or remove roles from any user.</p>
<ng-container i18n>Are you sure you want to continue?</ng-container>
</ng-template>
<ng-template #popContent>
- <cd-date-time-picker [control]="userForm.get('pwdExpirationDate')"
- [hasTime]="false"></cd-date-time-picker>
+ <cd-date-time-picker
+ [control]="userForm.get('pwdExpirationDate')"
+ [hasTime]="false"
+ ></cd-date-time-picker>
</ng-template>
form = component.userForm;
httpTesting = TestBed.inject(HttpTestingController);
userService = TestBed.inject(UserService);
+ spyOn(userService, 'validatePassword').and.returnValue(
+ of({ valid: true, credits: 10, valuation: 'strong' })
+ );
modalService = TestBed.inject(ModalCdsService);
router = TestBed.inject(Router);
spyOn(router, 'navigate');
fixture.detectChanges();
const notify = TestBed.inject(NotificationService);
spyOn(notify, 'show');
+ spyOn(TestBed.inject(AuthStorageService), 'isSSO').and.returnValue(false);
formHelper = new FormHelper(form);
});
formHelper.expectErrorChange('email', 'aaa', 'email');
});
+ it('should validate password required in create mode', () => {
+ formHelper.expectErrorChange('password', '', 'required');
+ formHelper.expectValidChange('password', 'pass123');
+ });
+
+ it('should validate confirmpassword required in create mode', () => {
+ formHelper.setValue('password', 'pass123');
+ formHelper.expectErrorChange('confirmpassword', '', 'required');
+ formHelper.expectValidChange('confirmpassword', 'pass123');
+ });
+
+ it('should validate roles required in create mode', () => {
+ formHelper.expectErrorChange('roles', [], 'required');
+ formHelper.expectValidChange('roles', ['administrator']);
+ });
+
+ it('should not validate password and roles if SSO is enabled', () => {
+ component.isSSO = true;
+ component.createForm();
+ form = component.userForm;
+ form.get('password').updateValueAndValidity();
+ expect(form.get('password').valid).toBeTruthy();
+ form.get('confirmpassword').updateValueAndValidity();
+ expect(form.get('confirmpassword').valid).toBeTruthy();
+ form.get('roles').updateValueAndValidity();
+ expect(form.get('roles').valid).toBeTruthy();
+ });
+
it('should set mode', () => {
expect(component.mode).toBeUndefined();
});
expect(component.mode).toBe('editing');
});
+ it('should not validate password required in edit mode', () => {
+ form.get('password').setValue('');
+ expect(form.get('password').valid).toBeTruthy();
+ form.get('confirmpassword').setValue('');
+ expect(form.get('confirmpassword').valid).toBeTruthy();
+ });
+
it('should alert if user is removing needed role permission', () => {
spyOn(TestBed.inject(AuthStorageService), 'getUsername').and.callFake(() => user.username);
let modalBodyTpl = null;