Feature 10914: Enforce Password change on First login
* Added NG-UI support to Enforce Password change on First login
* A popup will be opened on First login with current password, new password and confirm password fields
* Once new password is entered, Click apply button
* The popup is closed & redirected to Login page.
* Sign in using the new password.
Change-Id: I9ee6bf923e897b40d06a1781cdd7d044b171c825
Signed-off-by: SANDHYA.JS <sandhya.j@tataelxsi.co.in>
diff --git a/src/app/users/UsersModule.ts b/src/app/users/UsersModule.ts
index 2014c48..8b5f316 100644
--- a/src/app/users/UsersModule.ts
+++ b/src/app/users/UsersModule.ts
@@ -28,7 +28,7 @@
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { NgSelectModule } from '@ng-select/ng-select';
import { TranslateModule } from '@ngx-translate/core';
-import { AddEditUserComponent } from 'AddEditUserComponent';
+import { ChangePasswordModule } from 'ChangePasswordModule';
import { DataService } from 'DataService';
import { LoaderModule } from 'LoaderModule';
import { Ng2SmartTableModule } from 'ng2-smart-table';
@@ -60,10 +60,11 @@
*/
@NgModule({
imports: [ReactiveFormsModule, FormsModule, CommonModule, HttpClientModule, Ng2SmartTableModule, TranslateModule,
- FlexLayoutModule, NgSelectModule, NgbModule, RouterModule.forChild(routes), PagePerRowModule, LoaderModule, PageReloadModule],
- declarations: [UsersComponent, UserDetailsComponent, AddEditUserComponent, ProjectRoleComponent],
+ FlexLayoutModule, NgSelectModule, NgbModule, RouterModule.forChild(routes), PagePerRowModule, LoaderModule,
+ PageReloadModule, ChangePasswordModule],
+ declarations: [UsersComponent, UserDetailsComponent, ProjectRoleComponent],
providers: [DataService],
- entryComponents: [AddEditUserComponent, ProjectRoleComponent]
+ entryComponents: [ProjectRoleComponent]
})
/** Exporting a class @exports UsersModule */
export class UsersModule {
diff --git a/src/app/users/add-user/AddEditUserComponent.html b/src/app/users/add-user/AddEditUserComponent.html
index 8c496cc..d3a0b08 100644
--- a/src/app/users/add-user/AddEditUserComponent.html
+++ b/src/app/users/add-user/AddEditUserComponent.html
@@ -15,75 +15,105 @@
Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
-->
-<form [formGroup]="userForm" (ngSubmit)="userAction(userType)" autocomplete="off">
- <div class="modal-header">
- <h4 class="modal-title" id="modal-basic-title">{{userTitle}}</h4>
- <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
- <i class="fas fa-times-circle text-danger"></i>
- </button>
- </div>
- <div class="modal-body">
- <label class="col-sm-12 col-form-label mandatory-label"
- [ngClass]="{'text-danger': userForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' | translate}}</label>
- <div class="row form-group" *ngIf="userType === 'add' || userType === 'editUserName'">
- <div class="col-sm-4">
- <label for="userName">{{'PAGE.USERS.USERNAME' | translate}} *</label>
- </div>
- <div class="col-sm-8">
- <input class="form-control" placeholder="{{'PAGE.USERS.USERNAME' | translate}}" type="text"
- formControlName="userName" id="userName" [ngClass]="{ 'is-invalid': submitted && f.userName.errors }"
- required>
- </div>
- <div *ngIf="submitted && f.userName.errors" class="input-validation-msg">
- <div *ngIf="f.userName.errors.minlength">
- {{'PAGE.LOGIN.USERNAMEMINLENGTHVALIDMESSAGE' | translate}} </div>
- </div>
+<div class="wrap-user" [ngClass]="{'change-password': isPassword}">
+ <form [formGroup]="userForm" (ngSubmit)="userAction(userType)" autocomplete="off">
+ <div class="modal-header">
+ <h4 class="modal-title" id="modal-basic-title">{{userTitle}}</h4>
+ <button *ngIf="!isFirstLogin" class="button-xs" type="button" class="close" aria-label="Close"
+ (click)="activeModal.close()">
+ <i class="fas fa-times-circle text-danger"></i>
+ </button>
</div>
- <ng-container *ngIf="userType === 'add' || userType === 'editPassword'">
- <div class="row form-group">
+ <div class="modal-body">
+ <label class="col-sm-12 col-form-label mandatory-label"
+ [ngClass]="{'text-danger': userForm.invalid === true && submitted === true,'message': isPassword && userForm.invalid === true && submitted }">{{'MANDATORYCHECK'|
+ translate}}</label>
+ <div class="row form-group" *ngIf="userType === 'add' || userType === 'editUserName'">
<div class="col-sm-4">
- <label for="password">{{'PAGE.USERS.PASSWORD' | translate}} *</label>
+ <label for="userName">{{'PAGE.USERS.USERNAME' | translate}} *</label>
</div>
<div class="col-sm-8">
- <input class="form-control" placeholder="{{'PAGE.USERS.PASSWORD' | translate}}" minlength="8" maxlength="50"
- type="password" formControlName="password" id="password" autocomplete="new-password"
- [ngClass]="{ 'is-invalid': submitted && f.password.errors }" required>
+ <input class="form-control" placeholder="{{'PAGE.USERS.USERNAME' | translate}}" type="text"
+ formControlName="userName" id="userName" [ngClass]="{ 'is-invalid': submitted && f.userName.errors }"
+ required>
</div>
- <div class="input-validation-msg">
- <div *ngIf="userForm?.controls.password.hasError('minlength') || userForm?.controls.password.errors?.pattern">
- {{'PAGE.LOGIN.PASSWORDMINLENGTHVALIDMESSAGE' | translate}} </div>
+ <div *ngIf="submitted && f.userName.errors" class="input-validation-msg">
+ <div *ngIf="f.userName.errors.minlength">
+ {{'PAGE.LOGIN.USERNAMEMINLENGTHVALIDMESSAGE' | translate}} </div>
</div>
</div>
- <div class="row form-group">
- <div class="col-sm-4">
- <label for="password2">{{'PAGE.USERS.CONFPASSWORD' | translate}} *</label>
- </div>
- <div class="col-sm-8">
- <input class="form-control" placeholder="{{'PAGE.USERS.CONFPASSWORD' | translate}}" type="password"
- formControlName="password2" id="password2" autocomplete="new-password"
- [ngClass]="{ 'is-invalid': submitted && f.password2.errors }" required>
- <div class="mr-top-5" *ngIf="userForm?.controls.password.value && userForm?.controls.password2.value">
- <i class="far"
- [ngClass]="{'fa-times-circle text-danger':userForm?.controls.password.value !== userForm?.controls.password2.value,
- 'fa-check-circle text-success':userForm?.controls.password.value === userForm?.controls.password2.value}"></i>
- {{'PAGE.USERS.PASSWORDMATCH' | translate}}
+ <ng-container *ngIf="userType === 'add' || userType === 'editPassword' || userType === 'changePassword'">
+ <div class="row form-group" *ngIf=" userType === 'changePassword'">
+ <div class="col-sm-4">
+ <label for="oldpassword">{{'PAGE.USERS.OLDPASSWORD' | translate}} *</label>
+ </div>
+ <div class="col-sm-8">
+ <input class="form-control" placeholder="{{'PAGE.USERS.OLDPASSWORD' | translate}}" type="password"
+ formControlName="old_password" id="old_password" autocomplete="old-password"
+ [ngClass]="{ 'is-invalid': submitted && f.old_password.errors }" required>
</div>
</div>
- </div>
- </ng-container>
- <div class="form-group row" *ngIf="userType === 'add'">
- <label class="col-sm-4 col-form-label">{{'DOMAIN' | translate}} {{'NAME' | translate}}</label>
- <div class="col-sm-8">
- <ng-select [clearable]="false" placeholder="{{'SELECT' | translate}}" [items]="domains" bindLabel="title"
- bindValue="value" formControlName="domain_name" id="domain_name"
- [ngClass]="{ 'is-invalid': submitted && f.domain_name.errors }"></ng-select>
+ <div class="row form-group" *ngIf="userType === 'add' || userType === 'editPassword'">
+ <div class="col-sm-4">
+ <label for="password">{{'PAGE.USERS.PASSWORD' | translate}} *</label>
+ </div>
+ <div class="col-sm-8">
+ <input class="form-control" placeholder="{{'PAGE.USERS.PASSWORD' | translate}}" minlength="8" maxlength="50"
+ type="password" formControlName="password" id="password" autocomplete="new-password"
+ [ngClass]="{ 'is-invalid': submitted && f.password.errors }" required>
+ </div>
+ <div class="input-validation-msg" [ngClass]="{'message': isPassword}">
+ <div
+ *ngIf="userForm?.controls.password.hasError('minlength') || userForm?.controls.password.errors?.pattern">
+ {{'PAGE.LOGIN.PASSWORDMINLENGTHVALIDMESSAGE' | translate}} </div>
+ </div>
+ </div>
+ <div class="row form-group" *ngIf="userType === 'changePassword'">
+ <div class="col-sm-4">
+ <label for="password">{{'PAGE.USERS.NEWPASSWORD' | translate}} *</label>
+ </div>
+ <div class="col-sm-8">
+ <input class="form-control" placeholder="{{'PAGE.USERS.NEWPASSWORD' | translate}}" minlength="8"
+ maxlength="50" type="password" formControlName="password" id="password" autocomplete="new-password"
+ [ngClass]="{ 'is-invalid': submitted && f.password.errors }" required>
+ </div>
+ <div class="input-validation-msg" [ngClass]="{'message': isPassword}">
+ <div
+ *ngIf="userForm?.controls.password.hasError('minlength') || userForm?.controls.password.errors?.pattern">
+ {{'PAGE.LOGIN.PASSWORDMINLENGTHVALIDMESSAGE' | translate}} </div>
+ </div>
+ </div>
+ <div class="row form-group">
+ <div class="col-sm-4">
+ <label for="password2">{{'PAGE.USERS.CONFPASSWORD' | translate}} *</label>
+ </div>
+ <div class="col-sm-8">
+ <input class="form-control" placeholder="{{'PAGE.USERS.CONFPASSWORD' | translate}}" type="password"
+ formControlName="password2" id="password2" autocomplete="new-password"
+ [ngClass]="{ 'is-invalid': submitted && f.password2.errors }" required>
+ <div class="mr-top-5" *ngIf="userForm?.controls.password.value && userForm?.controls.password2.value">
+ <i class="far"
+ [ngClass]="{'fa-times-circle text-danger':userForm?.controls.password.value !== userForm?.controls.password2.value,
+ 'fa-check-circle text-success':userForm?.controls.password.value === userForm?.controls.password2.value}"></i>
+ {{'PAGE.USERS.PASSWORDMATCH' | translate}}
+ </div>
+ </div>
+ </div>
+ </ng-container>
+ <div class="form-group row" *ngIf="userType === 'add'">
+ <label class="col-sm-4 col-form-label">{{'DOMAIN' | translate}} {{'NAME' | translate}}</label>
+ <div class="col-sm-8">
+ <ng-select [clearable]="false" placeholder="{{'SELECT' | translate}}" [items]="domains" bindLabel="title"
+ bindValue="value" formControlName="domain_name" id="domain_name"
+ [ngClass]="{ 'is-invalid': submitted && f.domain_name.errors }"></ng-select>
+ </div>
</div>
</div>
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
- <button *ngIf="userType==='add'" type="submit" class="btn btn-primary">{{'CREATE' | translate}}</button>
- <button *ngIf="userType!=='add'" type="submit" class="btn btn-primary">{{'APPLY' | translate}}</button>
- </div>
-</form>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-danger" (click)="close()">{{'CANCEL' | translate}}</button>
+ <button *ngIf="userType==='add'" type="submit" class="btn btn-primary">{{'CREATE' | translate}}</button>
+ <button *ngIf="userType!=='add'" type="submit" class="btn btn-primary">{{'APPLY' | translate}}</button>
+ </div>
+ </form>
+</div>
<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/users/add-user/AddEditUserComponent.scss b/src/app/users/add-user/AddEditUserComponent.scss
index 05f2819..3520b4e 100644
--- a/src/app/users/add-user/AddEditUserComponent.scss
+++ b/src/app/users/add-user/AddEditUserComponent.scss
@@ -15,11 +15,46 @@
Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
*/
-@import '../../../assets/scss/mixins/mixin';
-@import '../../../assets/scss/variable';
-.input-validation-msg{
- color:$red;
- text-align:left;
+@import "../../../assets/scss/mixins/mixin";
+@import "../../../assets/scss/variable";
+.input-validation-msg {
+ color: $red;
+ text-align: left;
@include padding-value(0, 0, 0, 10);
@include font(null, 11px, null);
+}
+.change-password {
+ @include background(
+ linear-gradient(
+ to left bottom,
+ #00c0ef,
+ #00b3f9,
+ #3ea3fd,
+ #7190f8,
+ #9c78e8,
+ #a86cdd,
+ #b25fd1,
+ #bb51c3,
+ #b151c4,
+ #a652c6,
+ #9b53c6,
+ #9053c7
+ ),
+ null,
+ null,
+ null,
+ null
+ );
+ color: $white;
+ overflow: visible;
+ @include box-shadow(0px, 3px, 10px, 0px, rgba($black, 0.5));
+}
+.message {
+ @include roundedCorners(25);
+ @include background(null, $cerise-pink, null, null, null);
+ color: $white !important;
+ text-align: left;
+ @include padding-value(0, 0, 0, 10);
+ @include margin-value(0, 0, 10, 0);
+ @include font(null, 11px, null);
}
\ No newline at end of file
diff --git a/src/app/users/add-user/AddEditUserComponent.ts b/src/app/users/add-user/AddEditUserComponent.ts
index d988548..0e9456a 100644
--- a/src/app/users/add-user/AddEditUserComponent.ts
+++ b/src/app/users/add-user/AddEditUserComponent.ts
@@ -36,6 +36,7 @@
* @Component takes AddEditUserComponent.html as template url
*/
@Component({
+ selector: 'app-add-edit-user',
templateUrl: './AddEditUserComponent.html',
styleUrls: ['./AddEditUserComponent.scss']
})
@@ -74,6 +75,12 @@
/** Holds list of domains @public */
public domains: TYPESECTION[] = [];
+ /** Variable contains type is changepassword or not @public */
+ public isPassword: boolean;
+
+ /** Variable holds value for first login user @public */
+ public isFirstLogin: boolean = Boolean(localStorage.getItem('firstLogin') === 'true');
+
/** Instance of the rest service @private */
private restService: RestService;
@@ -113,6 +120,7 @@
userName: ['', Validators.required],
password: [null, [Validators.required, Validators.pattern(this.sharedService.REGX_PASSWORD_PATTERN)]],
password2: [null, Validators.required],
+ old_password: [null, Validators.required],
domain_name: [null]
});
}
@@ -131,6 +139,8 @@
this.getDomainList();
} else if (this.userType === 'editUserName') {
this.userForm.patchValue({ userName: this.userName });
+ } else if (this.isFirstLogin) {
+ this.isPassword = true;
}
}
@@ -139,11 +149,21 @@
if (userType === 'editPassword') {
this.getFormControl('userName').setValidators([]);
this.getFormControl('userName').updateValueAndValidity();
+ this.getFormControl('old_password').setValidators([]);
+ this.getFormControl('old_password').updateValueAndValidity();
} else if (userType === 'editUserName') {
this.getFormControl('password').setValidators([]);
this.getFormControl('password').updateValueAndValidity();
this.getFormControl('password2').setValidators([]);
this.getFormControl('password2').updateValueAndValidity();
+ this.getFormControl('old_password').setValidators([]);
+ this.getFormControl('old_password').updateValueAndValidity();
+ } else if (userType === 'changePassword') {
+ this.getFormControl('userName').setValidators([]);
+ this.getFormControl('userName').updateValueAndValidity();
+ } else if (userType === 'add') {
+ this.getFormControl('old_password').setValidators([]);
+ this.getFormControl('old_password').updateValueAndValidity();
}
this.submitted = true;
this.modalData = {
@@ -157,7 +177,7 @@
}
if (userType === 'add') {
this.addUser();
- } else if (userType === 'editUserName' || userType === 'editPassword') {
+ } else {
this.editUser();
}
}
@@ -191,6 +211,9 @@
const payLoad: LOGINPARAMS = {};
if (this.userType === 'editPassword') {
payLoad.password = (this.userForm.value.password);
+ } else if (this.userType === 'changePassword') {
+ payLoad.password = (this.userForm.value.password);
+ payLoad.old_password = (this.userForm.value.old_password);
} else {
payLoad.username = this.userForm.value.userName.toLowerCase();
}
@@ -201,13 +224,33 @@
this.restService.patchResource(apiURLHeader, payLoad).subscribe((result: {}): void => {
this.checkUsername(payLoad);
this.activeModal.close(this.modalData);
+ if (this.isFirstLogin) {
+ this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.CHANGEPASSWORD'));
+ this.authService.destoryToken();
+ } else {
+ this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.EDITEDSUCCESSFULLY'));
+ }
this.isLoadingResults = false;
- this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.EDITEDSUCCESSFULLY'));
}, (error: ERRORDATA): void => {
- this.restService.handleError(error, 'put');
+ if (this.isFirstLogin) {
+ this.notifierService.notify('error', error.error.detail);
+ this.activeModal.close(this.modalData);
+ this.authService.destoryToken();
+ } else {
+ this.restService.handleError(error, 'put');
+ }
this.isLoadingResults = false;
});
}
+ /** Close the modal and destroy subscribe @public */
+ public close(): void {
+ if (this.isFirstLogin) {
+ this.activeModal.close(this.modalData);
+ this.authService.destoryToken();
+ } else {
+ this.activeModal.close(this.modalData);
+ }
+ }
/** Get domain name list @private */
private getDomainList(): void {
this.isLoadingResults = true;