From 6c6860802cae8fe2ae0db852476fc926ea899062 Mon Sep 17 00:00:00 2001 From: "SANDHYA.JS" Date: Mon, 10 Jun 2024 21:39:41 +0530 Subject: [PATCH] Feature 11034: Forgot Password in OSM - Added support for forgot password from UI - Added forgot password button in login page Change-Id: I058a09356c4e2ff5d5b0e883e74f0041d1aaffea Signed-off-by: SANDHYA.JS --- src/app/approutes.module.ts | 9 + src/app/login/LoginComponent.html | 4 +- src/app/login/LoginComponent.scss | 3 + .../users/add-user/AddEditUserComponent.html | 35 ++- .../users/add-user/AddEditUserComponent.ts | 209 +++++++++++++++++- .../user-details/UserDetailsComponent.ts | 3 +- .../ChangePasswordComponent.ts | 12 + .../users-action/UsersActionComponent.html | 4 + .../users-action/UsersActionComponent.ts | 3 + src/assets/i18n/de.json | 9 +- src/assets/i18n/en.json | 9 +- src/assets/i18n/es.json | 9 +- src/assets/i18n/pt.json | 9 +- src/models/CommonModel.ts | 1 + src/models/UserModel.ts | 2 + src/services/AuthGuardService.ts | 7 +- src/services/AuthenticationService.ts | 10 + src/services/RestService.ts | 3 + src/services/SharedService.ts | 3 + 19 files changed, 319 insertions(+), 25 deletions(-) diff --git a/src/app/approutes.module.ts b/src/app/approutes.module.ts index 537dc94..2412be7 100644 --- a/src/app/approutes.module.ts +++ b/src/app/approutes.module.ts @@ -121,6 +121,15 @@ export const appRoutes: Routes = [ component: ChangePasswordComponent, canActivate: [AuthGuardService] }, + { + path: 'forgotpassword', + component: ChangePasswordComponent + }, + { + path: 'forgotpassword/changepassword/:id', + component: ChangePasswordComponent, + canActivate: [AuthGuardService] + }, { path: '**', component: PageNotFoundComponent diff --git a/src/app/login/LoginComponent.html b/src/app/login/LoginComponent.html index 12c88f2..65f4a80 100644 --- a/src/app/login/LoginComponent.html +++ b/src/app/login/LoginComponent.html @@ -47,7 +47,9 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i - + diff --git a/src/app/login/LoginComponent.scss b/src/app/login/LoginComponent.scss index 895fe22..ed938b4 100644 --- a/src/app/login/LoginComponent.scss +++ b/src/app/login/LoginComponent.scss @@ -172,4 +172,7 @@ width: 400px; @include background(null, $primary, null, null, null); color: $white; +} +.forget{ + cursor: pointer; } \ No newline at end of file diff --git a/src/app/users/add-user/AddEditUserComponent.html b/src/app/users/add-user/AddEditUserComponent.html index 6ae0f32..9701665 100644 --- a/src/app/users/add-user/AddEditUserComponent.html +++ b/src/app/users/add-user/AddEditUserComponent.html @@ -20,15 +20,15 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i - +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
@@ -68,7 +91,7 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i {{'PAGE.LOGIN.PASSWORDMINLENGTHVALIDMESSAGE' | translate}}
-
+
@@ -83,7 +106,7 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i {{'PAGE.LOGIN.PASSWORDMINLENGTHVALIDMESSAGE' | translate}}
-
+
diff --git a/src/app/users/add-user/AddEditUserComponent.ts b/src/app/users/add-user/AddEditUserComponent.ts index a816c62..5226d5b 100644 --- a/src/app/users/add-user/AddEditUserComponent.ts +++ b/src/app/users/add-user/AddEditUserComponent.ts @@ -19,8 +19,9 @@ * @file Add Edit Component. */ import { HttpHeaders } from '@angular/common/http'; -import { Component, Injector, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, Injector, Input, OnInit } from '@angular/core'; import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { TranslateService } from '@ngx-translate/core'; import { NotifierService } from 'angular-notifier'; @@ -28,6 +29,7 @@ import { AuthenticationService } from 'AuthenticationService'; import { APIURLHEADER, ERRORDATA, LOGINPARAMS, MODALCLOSERESPONSEDATA, TYPESECTION } from 'CommonModel'; import { environment } from 'environment'; import { RestService } from 'RestService'; +import { Observable } from 'rxjs'; import { SharedService, isNullOrUndefined } from 'SharedService'; /** @@ -65,21 +67,45 @@ export class AddEditUserComponent implements OnInit { /** Input contains Modal dialog component Instance @public */ @Input() public userName: string; + /** Input contains Modal dialog component Instance @public */ + @Input() public email: string; + /** Check the loading results for loader status @public */ public isLoadingResults: boolean = false; /** Give the message for the loading @public */ public message: string = 'PLEASEWAIT'; + /** Contains token @public */ + public idToken: string; + /** Holds list of domains @public */ public domains: TYPESECTION[] = []; /** Variable contains type is changepassword or not @public */ public isPassword: boolean; + /** Variable contains type is forgotpassword or not @public */ + public isforgetPassword: boolean; + + /** Variable contains to show otp or not @public */ + public isOtp: boolean = false; + /** Variable holds value for first login user @public */ public isFirstLogin: boolean = Boolean(sessionStorage.getItem('firstLogin') === 'true'); + /** Observable Hold the value of subscription @public */ + public isForgotPassword$: Observable; + + /** Observable Hold the value of subscription @public */ + public forgotPassword: boolean; + + /** Variable contains payload @private */ + private payload: {}; + + /** Variable contains add user payload @private */ + private addPayload: {}; + /** Instance of the rest service @private */ private restService: RestService; @@ -104,6 +130,12 @@ export class AddEditUserComponent implements OnInit { /** Utilizes auth service for any auth operations @private */ private authService: AuthenticationService; + /** Holds the instance of router class @private */ + private router: Router; + + /** Detect changes for the User Input */ + private cd: ChangeDetectorRef; + constructor(injector: Injector) { this.injector = injector; this.formBuilder = this.injector.get(FormBuilder); @@ -113,14 +145,18 @@ export class AddEditUserComponent implements OnInit { this.translateService = this.injector.get(TranslateService); this.sharedService = this.injector.get(SharedService); this.authService = this.injector.get(AuthenticationService); + this.router = this.injector.get(Router); + this.cd = this.injector.get(ChangeDetectorRef); /** Initializing Form Action */ this.userForm = this.formBuilder.group({ userName: ['', Validators.required], + email_id: [null, [Validators.required, Validators.pattern(this.sharedService.REGX_EMAIL_PATTERN)]], password: [null, [Validators.required, Validators.pattern(this.sharedService.REGX_PASSWORD_PATTERN)]], password2: [null, Validators.required], old_password: [null, Validators.required], - domain_name: [null] + domain_name: [null], + otp: [null] }); } @@ -140,16 +176,20 @@ export class AddEditUserComponent implements OnInit { this.userForm.patchValue({ userName: this.userName }); } else if (this.isFirstLogin) { this.isPassword = true; + } else if (this.userType === 'editmail') { + this.userForm.patchValue({ email_id: this.email }); } } /** On modal submit users acction will called @public */ public userAction(userType: string): void { - if (userType === 'editPassword') { + if (userType === 'editPassword' || this.isforgetPassword || userType === 'change_password') { this.getFormControl('userName').setValidators([]); this.getFormControl('userName').updateValueAndValidity(); this.getFormControl('old_password').setValidators([]); this.getFormControl('old_password').updateValueAndValidity(); + this.getFormControl('email_id').setValidators([]); + this.getFormControl('email_id').updateValueAndValidity(); } else if (userType === 'editUserName') { this.getFormControl('password').setValidators([]); this.getFormControl('password').updateValueAndValidity(); @@ -157,13 +197,20 @@ export class AddEditUserComponent implements OnInit { this.getFormControl('password2').updateValueAndValidity(); this.getFormControl('old_password').setValidators([]); this.getFormControl('old_password').updateValueAndValidity(); + this.getFormControl('email_id').setValidators([]); + this.getFormControl('email_id').updateValueAndValidity(); } else if (userType === 'changePassword') { this.getFormControl('userName').setValidators([]); this.getFormControl('userName').updateValueAndValidity(); + this.getFormControl('email_id').setValidators([]); + this.getFormControl('email_id').updateValueAndValidity(); } else if (userType === 'add') { this.getFormControl('old_password').setValidators([]); this.getFormControl('old_password').updateValueAndValidity(); + this.getFormControl('email_id').setValidators([]); + this.getFormControl('email_id').updateValueAndValidity(); } + this.checkType(userType); this.submitted = true; this.modalData = { message: 'Done' @@ -176,25 +223,153 @@ export class AddEditUserComponent implements OnInit { } if (userType === 'add') { this.addUser(); + } else if (userType === 'forgotPassword') { + this.forgetPassword(); + } else if (userType === 'change_password') { + this.changePassword(); } else { this.editUser(); } } } + /** Used to set the validation and value and update the validation and value @public */ + public checkType(userType: string): void { + if (userType === 'forgotPassword') { + 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 === 'editmail') { + 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(); + this.getFormControl('userName').setValidators([]); + this.getFormControl('userName').updateValueAndValidity(); + } + } + + /** Forgot password @public */ + public forgetPassword(): void { + this.isLoadingResults = true; + if (isNullOrUndefined(this.userForm.value.otp)) { + this.payload = JSON.stringify({ + username: (this.userForm.value.userName).toLowerCase(), + email_id: (this.userForm.value.email_id) + }); + } else { + this.getFormControl('userName').enable(); + this.payload = JSON.stringify({ + username: (this.userForm.value.userName).toLowerCase(), + otp: (this.userForm.value.otp) + }); + } + const apiURLHeader: APIURLHEADER = { + url: environment.GENERATETOKEN_URL, + httpOptions: { headers: this.headers } + }; + this.restService.postResource(apiURLHeader, this.payload).subscribe((result: + { email: string, id: string, user_id: string, message: string, otp: string } + ): void => { + if (result.email === 'sent') { + this.getFormControl('userName').disable(); + this.getFormControl('email_id').disable(); + this.isOtp = true; + this.cd.detectChanges(); + this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.USERSUCCESSFULLY')); + } + if (result.message === 'valid_otp') { + this.activeModal.close(this.modalData); + this.getFormControl('email_id').enable(); + sessionStorage.setItem('id_token', result.id); + sessionStorage.setItem('user_id', result.user_id); + sessionStorage.setItem('mail', this.userForm.value.email_id); + this.userType = 'change_password'; + sessionStorage.setItem('usertype', this.userType); + this.idToken = sessionStorage.getItem('id_token'); + this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.OTPSUCCESSFULLY')); + if (!isNullOrUndefined(sessionStorage.getItem('id_token')) && !isNullOrUndefined(sessionStorage.getItem('mail'))) { + this.authService.forgotPassword.next(true); + this.isForgotPassword$ = this.authService.forgotPassword; + this.authService.isForgotPassword.subscribe((res: boolean): void => { + this.forgotPassword = res; + }); + if (this.forgotPassword === true) { + this.router.navigate(['/forgotpassword/changepassword/', encodeURI(this.idToken)]).catch((): void => { + // Catch Navigation Error + }); + } + } + } else if (result.otp === 'invalid') { + this.getFormControl('userName').disable(); + this.notifierService.notify('warning', this.translateService.instant('PAGE.USERS.INVALIDOTP')); + } + this.isLoadingResults = false; + }, (error: ERRORDATA): void => { + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + if (error.error.status === 401 || error.error.status === 429 || error.error.status === 404) { + this.activeModal.close(this.modalData); + this.router.navigate(['/login']).catch((): void => { + // Catch Navigation Error + }); + } + this.restService.handleError(error, 'post'); + this.isLoadingResults = false; + }); + } + + /** Change password @public */ + public changePassword(): void { + this.isLoadingResults = true; + this.userID = sessionStorage.getItem('user_id'); + const payLoad: LOGINPARAMS = {}; + payLoad.password = (this.userForm.value.password); + payLoad.email_id = (sessionStorage.getItem('mail')); + const apiURLHeader: APIURLHEADER = { + url: environment.USERS_URL + '/' + this.userID, + httpOptions: { headers: this.headers } + }; + this.restService.patchResource(apiURLHeader, payLoad).subscribe((result: {}): void => { + this.activeModal.close(this.modalData); + this.router.navigate(['/login']).catch((): void => { + // Catch Navigation Error + }); + this.authService.logoutResponse(); + this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.CHANGEDSUCCESSFULLY')); + this.isLoadingResults = false; + }, (error: ERRORDATA): void => { + this.restService.handleError(error, 'put'); + this.isLoadingResults = false; + }); + } + /** Add user @public */ public addUser(): void { this.isLoadingResults = true; - const payLoad: {} = JSON.stringify({ - username: (this.userForm.value.userName).toLowerCase(), - password: (this.userForm.value.password), - domain_name: !isNullOrUndefined(this.userForm.value.domain_name) ? this.userForm.value.domain_name : undefined - }); + if (!isNullOrUndefined(this.userForm.value.email_id) && this.userForm.value.email_id !== '') { + this.addPayload = JSON.stringify({ + username: (this.userForm.value.userName).toLowerCase(), + password: (this.userForm.value.password), + email_id: (this.userForm.value.email_id), + domain_name: !isNullOrUndefined(this.userForm.value.domain_name) ? this.userForm.value.domain_name : undefined + }); + } else { + this.addPayload = JSON.stringify({ + username: (this.userForm.value.userName).toLowerCase(), + password: (this.userForm.value.password), + domain_name: !isNullOrUndefined(this.userForm.value.domain_name) ? this.userForm.value.domain_name : undefined + }); + } const apiURLHeader: APIURLHEADER = { url: environment.USERS_URL, httpOptions: { headers: this.headers } }; - this.restService.postResource(apiURLHeader, payLoad).subscribe((result: {}): void => { + this.restService.postResource(apiURLHeader, this.addPayload).subscribe((result: {}): void => { this.activeModal.close(this.modalData); this.isLoadingResults = false; this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.CREATEDSUCCESSFULLY')); @@ -213,7 +388,10 @@ export class AddEditUserComponent implements OnInit { } else if (this.userType === 'changePassword') { payLoad.password = (this.userForm.value.password); payLoad.old_password = (this.userForm.value.old_password); - } else { + } else if (this.userType === 'editmail') { + payLoad.email_id = (this.userForm.value.email_id); + } + else { payLoad.username = this.userForm.value.userName.toLowerCase(); } const apiURLHeader: APIURLHEADER = { @@ -248,6 +426,17 @@ export class AddEditUserComponent implements OnInit { if (this.isFirstLogin) { this.activeModal.close(this.modalData); this.authService.destoryToken(); + } else if (this.userType === 'forgotPassword') { + this.activeModal.close(this.modalData); + this.router.navigate(['/login']).catch((): void => { + // Catch Navigation Error + }); + } else if (this.userType === 'change_password') { + this.authService.logoutResponse(); + this.activeModal.close(this.modalData); + this.router.navigate(['/forgotpassword']).catch((): void => { + // Catch Navigation Error + }); } else { this.activeModal.close(this.modalData); } diff --git a/src/app/users/user-details/UserDetailsComponent.ts b/src/app/users/user-details/UserDetailsComponent.ts index 65ef878..99670f0 100644 --- a/src/app/users/user-details/UserDetailsComponent.ts +++ b/src/app/users/user-details/UserDetailsComponent.ts @@ -252,7 +252,8 @@ export class UserDetailsComponent implements OnInit, OnDestroy { identifier: userData._id, user_status: userData._admin.user_status, account_expire_time: (!isNullOrUndefined(userData._admin) && !isNullOrUndefined(userData._admin.account_expire_time)) ? this.sharedService.convertEpochTime( - userData._admin.account_expire_time) : 'N/A' + userData._admin.account_expire_time) : 'N/A', + email_id: userData.email_id }; this.userData.push(userDataObj); } diff --git a/src/app/utilities/change-password/ChangePasswordComponent.ts b/src/app/utilities/change-password/ChangePasswordComponent.ts index 2b32a8b..ad2fa32 100644 --- a/src/app/utilities/change-password/ChangePasswordComponent.ts +++ b/src/app/utilities/change-password/ChangePasswordComponent.ts @@ -19,6 +19,7 @@ * @file change password component */ import { Component, Injector, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { TranslateService } from '@ngx-translate/core'; import { AddEditUserComponent } from 'AddEditUserComponent'; @@ -50,11 +51,14 @@ export class ChangePasswordComponent implements OnInit { /** Instance of the modal service @private */ private modalService: NgbModal; + /** Holds the instance of router class @private */ + private router: Router; constructor(injector: Injector) { this.injector = injector; this.translateService = this.injector.get(TranslateService); this.sharedService = this.injector.get(SharedService); this.modalService = this.injector.get(NgbModal); + this.router = this.injector.get(Router); } /** Lifecyle Hooks the trigger before component is instantiate @public */ @@ -65,6 +69,14 @@ export class ChangePasswordComponent implements OnInit { if (this.editType === 'changePassword') { modalRef.componentInstance.userTitle = this.translateService.instant('PAGE.USERS.EDITCREDENTIALS'); } + if (this.router.url === '/forgotpassword') { + this.editType = 'forgotPassword'; + modalRef.componentInstance.userTitle = this.translateService.instant('PAGE.USERS.FORGOT'); + } + if (this.router.url.startsWith('/forgotpassword/changepassword/')) { + this.editType = 'change_password'; + modalRef.componentInstance.userTitle = this.translateService.instant('PAGE.USERS.EDITCREDENTIALS'); + } modalRef.componentInstance.userType = this.editType; modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => { if (result) { diff --git a/src/app/utilities/users-action/UsersActionComponent.html b/src/app/utilities/users-action/UsersActionComponent.html index 69bf2ab..ca5affe 100644 --- a/src/app/utilities/users-action/UsersActionComponent.html +++ b/src/app/utilities/users-action/UsersActionComponent.html @@ -33,6 +33,10 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i placement="left" container="body" ngbTooltip="{{'PAGE.USERS.EDITUSERNAME' | translate}}"> {{'PAGE.USERS.EDITUSERNAME' | translate}} +