From: SANDHYA.JS Date: Wed, 26 Apr 2023 12:24:57 +0000 (+0530) Subject: Feature 10941: User Management Enhancements X-Git-Tag: release-v14.0-start~1 X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=refs%2Fchanges%2F85%2F13285%2F4;p=osm%2FNG-UI.git Feature 10941: User Management Enhancements - Added NG-UI support for user management enhancements - It includes login history along with password expiry & account expiry warnings, unlock & renew user for admin users - Change password field for admin: visible at user actions field Change password field for users: visible at header of UI Change-Id: If952069b62efd6226b633b35b3634cf3f7848096 Signed-off-by: SANDHYA.JS --- diff --git a/package.json b/package.json index d4b4cb4..bb99e9b 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,8 @@ "tslib": "^2.5.0", "util": "^0.12.4", "zone.js": "~0.11.8", - "@popperjs/core": "~2.10.1" + "@popperjs/core": "~2.10.1", + "ngx-toastr": "^13.2.1" }, "devDependencies": { "@angular-devkit/build-angular": "^14.2.10", diff --git a/src/app/AppModule.ts b/src/app/AppModule.ts index 8a4ebaf..d260784 100644 --- a/src/app/AppModule.ts +++ b/src/app/AppModule.ts @@ -53,6 +53,7 @@ import { LoginComponent } from 'LoginComponent'; import { NetsliceInstancesActionComponent } from 'NetsliceInstancesActionComponent'; import { NetslicePackagesActionComponent } from 'NetslicePackagesAction'; import { Ng2SmartTableModule } from 'ng2-smart-table'; +import { ToastrModule } from 'ngx-toastr'; import { NSInstancesActionComponent } from 'NSInstancesActionComponent'; import { NsPackagesActionComponent } from 'NsPackagesAction'; import { NsUpdateComponent } from 'NsUpdateComponent'; @@ -159,7 +160,11 @@ const customNotifierOptions: NotifierOptions = { NgIdleKeepaliveModule.forRoot(), LoaderModule, SharedModule, - ChangePasswordModule + ChangePasswordModule, + ToastrModule.forRoot({ + timeOut: 500, + positionClass: 'toast-bottom-right' + }) ], providers: [ { diff --git a/src/app/layouts/header/HeaderComponent.html b/src/app/layouts/header/HeaderComponent.html index 4725920..042f720 100644 --- a/src/app/layouts/header/HeaderComponent.html +++ b/src/app/layouts/header/HeaderComponent.html @@ -62,6 +62,11 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i {{'PAGE.DASHBOARD.USERSETTINGS' | translate}} + + {{'PAGE.USERS.EDITCREDENTIALS' | translate}} + + {{'PAGE.DASHBOARD.LOGOUT' | translate}} diff --git a/src/app/layouts/header/HeaderComponent.scss b/src/app/layouts/header/HeaderComponent.scss index 86200b7..81f90c1 100644 --- a/src/app/layouts/header/HeaderComponent.scss +++ b/src/app/layouts/header/HeaderComponent.scss @@ -28,6 +28,7 @@ .dropdown-item{ &.project-item{ @include flexbox(flex, space-between, row, null, center, null); + @include padding-value(10, 5, 10, 5); } &:active, &:hover, &.active{ @include background(null, $theme-bg-color, null, null, null); diff --git a/src/app/layouts/header/HeaderComponent.ts b/src/app/layouts/header/HeaderComponent.ts index 9b4fca6..9392177 100644 --- a/src/app/layouts/header/HeaderComponent.ts +++ b/src/app/layouts/header/HeaderComponent.ts @@ -20,8 +20,11 @@ * @file Header Component */ import { Component, Injector, OnInit } from '@angular/core'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { AddEditUserComponent } from 'AddEditUserComponent'; import { AuthenticationService } from 'AuthenticationService'; +import { MODALCLOSERESPONSEDATA } from 'CommonModel'; import { environment } from 'environment'; import { ProjectService } from 'ProjectService'; import { Observable } from 'rxjs'; @@ -60,12 +63,18 @@ export class HeaderComponent implements OnInit { /** Version holds packages version @public */ public PACKAGEVERSION: string; + /** To check the role of the user is systemadmin or not @public */ + public isSystemAdmin: boolean; + /** Contains all methods related to shared @public */ public sharedService: SharedService; /** Property contains to show new version tag shared @public */ public toShowNewTag: Boolean = false; + /** handle translate @public */ + public translateService: TranslateService; + /** Utilizes auth service for any auth operations @private */ private authService: AuthenticationService; @@ -81,11 +90,13 @@ export class HeaderComponent implements OnInit { this.modalService = this.injector.get(NgbModal); this.projectService = this.injector.get(ProjectService); this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); } /** Lifecyle Hooks the trigger before component is instantiate @public */ public ngOnInit(): void { this.isAdmin = (localStorage.getItem('isAdmin') === 'true') ? true : false; + this.isSystemAdmin = localStorage.getItem('admin_show') === 'true' ? true : false; this.selectedProject = this.authService.ProjectName; this.authService.ProjectName.subscribe((projectNameFinal: string): void => { this.getSelectedProject = projectNameFinal; @@ -123,4 +134,20 @@ export class HeaderComponent implements OnInit { // eslint-disable-next-line security/detect-non-literal-fs-filename this.modalService.open(UserSettingsComponent, { backdrop: 'static' }); } + + /** ChangePassword Function @public */ + public changePassword(): void { + // eslint-disable-next-line security/detect-non-literal-fs-filename + const modalRef: NgbModalRef = this.modalService.open(AddEditUserComponent, { backdrop: 'static' }); + modalRef.componentInstance.userID = localStorage.getItem('user_id'); + modalRef.componentInstance.userTitle = this.translateService.instant('PAGE.USERS.EDITCREDENTIALS'); + modalRef.componentInstance.userType = 'changePassword'; + modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => { + if (result) { + this.sharedService.callData(); + } + }).catch((): void => { + // Catch Navigation Error + }); + } } diff --git a/src/app/login/LoginComponent.scss b/src/app/login/LoginComponent.scss index 293e50c..dc1a51b 100644 --- a/src/app/login/LoginComponent.scss +++ b/src/app/login/LoginComponent.scss @@ -153,4 +153,9 @@ text-decoration: underline; } } +} +::ng-deep #toast-container > div { + width: 400px; + @include background(null, $primary, null, null, null); + color: $white; } \ No newline at end of file diff --git a/src/app/login/LoginComponent.ts b/src/app/login/LoginComponent.ts index fae3d20..db842d8 100644 --- a/src/app/login/LoginComponent.ts +++ b/src/app/login/LoginComponent.ts @@ -24,10 +24,15 @@ import { HttpErrorResponse } from '@angular/common/http'; import { Component, Injector, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; import { AuthenticationService } from 'AuthenticationService'; +import { ERRORDATA } from 'CommonModel'; +import { environment } from 'environment'; +import { ToastrService } from 'ngx-toastr'; import { RestService } from 'RestService'; import { Observable } from 'rxjs'; import { SharedService } from 'SharedService'; +import { UserDetail } from 'UserModel'; /** * Creating component @@ -76,6 +81,48 @@ export class LoginComponent implements OnInit { /** contains the loggedIn observable value @public */ public loggedIn: boolean; + /** Contains Last Login information @public */ + public lastLogin: string; + + /** Holds Last Login Toaster Message @public */ + public lastLoginMessage: string; + + /** Holds Failed Attempts Toaster Message @public */ + public failedAttemptsMessage: string; + + /** Holds Password Expire Toaster Message @public */ + public passwordExpireMessage: string; + + /** Holds Account Expire Toaster Message @public */ + public accountExpireMessage: string; + + /** Holds password & account Toaster Message @public */ + public daysMessage: string; + + /** Holds account Days Toaster Message @public */ + public accountMessage: string; + + /** Holds password Days Toaster Message @public */ + public passwordMessage: string; + + /** Contains user details information @public */ + public userDetails: UserDetail; + + /** contains No of failed attempts values @public */ + public failedAttempts: string; + + /** contains No of days to expire account @public */ + public accountNoOfDays: string; + + /** contains No of days to expire password @public */ + public passwordNoOfDays: string; + + /** User Visibility Check @public */ + public isUserShow: boolean; + + /** Admin Visibility Check @public */ + public isAdminShow: boolean; + /** contains the passwordIn observable value @public */ public changePassword: boolean; @@ -88,6 +135,27 @@ export class LoginComponent implements OnInit { /** Holds teh instance of AuthService class of type AuthService @private */ private router: Router; + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Contains toaster instance @private */ + private toaster: ToastrService; + + /** express number for expire days @private */ + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + private expireDays: number = 5; + + /** express number for time manupulation 1000 */ + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + private epochTime1000: number = 1000; + + /** contains toaster settings */ + private toasterSettings: {} = { + enableHtml: true, + closeButton: true, + timeOut: 2000 + }; + // creates instance of login component constructor(injector: Injector) { this.injector = injector; @@ -96,6 +164,8 @@ export class LoginComponent implements OnInit { this.formBuilder = this.injector.get(FormBuilder); this.router = this.injector.get(Router); this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); + this.toaster = this.injector.get(ToastrService); } /** @@ -138,6 +208,14 @@ export class LoginComponent implements OnInit { } this.isLoadingResults = true; this.sharedService.cleanForm(this.loginForm); + this.isLoadingResults = false; + if (!this.loginForm.invalid) { + this.loginUser(); + } + } + + /** Login User @public */ + public loginUser(): void { this.authService.login(this.loginForm.value.userName, this.loginForm.value.password).subscribe( (data: {}): void => { this.isLoadingResults = false; @@ -149,6 +227,13 @@ export class LoginComponent implements OnInit { this.router.navigate([this.returnUrl]).catch((): void => { // Catch Navigation Error }); + this.isAdminShow = localStorage.getItem('admin_show') === 'true' ? true : false; + this.isUserShow = localStorage.getItem('user_show') === 'true' ? true : false; + setTimeout((): void => { + if (this.isAdminShow === true || this.isUserShow === true) { + this.generateData(); + } + }, this.epochTime1000); } localStorage.removeItem('returnUrl'); }, (err: HttpErrorResponse): void => { @@ -156,4 +241,164 @@ export class LoginComponent implements OnInit { this.restService.handleError(err, 'post'); }); } + + /** Fetching the data from server to load it in toaster @public */ + public generateData(): void { + const userID: string = localStorage.getItem('user_id'); + if (userID !== '') { + this.isLoadingResults = true; + this.restService.getResource(environment.USERS_URL + '/' + userID).subscribe((userDetails: UserDetail): void => { + this.userDetails = userDetails; + if (!isNullOrUndefined(userDetails)) { + const account: string = this.sharedService.convertEpochTime(!isNullOrUndefined(userDetails._admin) ? + userDetails._admin.account_expire_time : null); + const password: string = this.sharedService.convertEpochTime(!isNullOrUndefined(userDetails._admin) ? + userDetails._admin.password_expire_time : null); + const accountExpire: number = this.sharedService.converEpochToDays(account); + const passwordExpire: number = this.sharedService.converEpochToDays(password); + if (accountExpire >= 0 && accountExpire <= this.expireDays) { + this.accountNoOfDays = String(accountExpire); + } + if (passwordExpire >= 0 && passwordExpire <= this.expireDays) { + this.passwordNoOfDays = String(passwordExpire); + } + this.lastLoginMessage = this.translateService.instant('PAGE.LOGIN.LASTACCESS'); + this.failedAttemptsMessage = this.translateService.instant('PAGE.LOGIN.FAILED'); + this.accountExpireMessage = this.translateService.instant('PAGE.LOGIN.ACCOUNTEXPIRE'); + this.passwordExpireMessage = this.translateService.instant('PAGE.LOGIN.PASSWORDEXPIRE'); + this.daysMessage = this.translateService.instant('PAGE.LOGIN.DAYS'); + this.lastLogin = localStorage.getItem('last_login'); + this.failedAttempts = localStorage.getItem('failed_count'); + if (this.accountNoOfDays !== '0' && this.passwordNoOfDays !== '0' && + this.accountNoOfDays !== '1' && this.passwordNoOfDays !== '1') { + this.showToaster(); + } + this.passwordExpiryToaster(); + this.accountExpiryToaster(); + } + this.isLoadingResults = false; + }, (error: ERRORDATA): void => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }); + } + } + + /** To display password expiry Toaster with required data @public */ + public passwordExpiryToaster(): void { + if ((this.accountNoOfDays === '1' && this.passwordNoOfDays === '1') || + (this.accountNoOfDays === '0' && this.passwordNoOfDays === '0')) { + this.passwordExpireMessage = this.translateService.instant('PAGE.LOGIN.PASSWORDEXPIRETODAY'); + this.accountExpireMessage = this.translateService.instant('PAGE.LOGIN.ACCOUNTEXPIRETODAY'); + if (this.accountNoOfDays === '1') { + this.passwordExpireMessage = this.translateService.instant('PAGE.LOGIN.PASSWORDEXPIRETOMORROW'); + this.accountExpireMessage = this.translateService.instant('PAGE.LOGIN.ACCOUNTEXPIRETOMORROW'); + } + this.passwordMessage = ''; + this.accountMessage = ''; + this.accountNoOfDays = ''; + this.passwordNoOfDays = ''; + this.sharedService.showToaster(this.lastLogin, this.failedAttempts, this.passwordNoOfDays, this.accountNoOfDays, + this.passwordExpireMessage, this.accountExpireMessage, this.passwordMessage, this.accountMessage); + } else if (!isNullOrUndefined(this.passwordNoOfDays)) { + if ((this.passwordNoOfDays === '0') || this.passwordNoOfDays === '1' || + (this.passwordNoOfDays === '0' && (isNullOrUndefined(this.accountNoOfDays) || !isNullOrUndefined(this.accountNoOfDays))) || + (this.passwordNoOfDays === '1' && (isNullOrUndefined(this.accountNoOfDays) || !isNullOrUndefined(this.accountNoOfDays))) + ) { + if (this.passwordNoOfDays === '1') { + this.passwordExpireMessage = this.translateService.instant('PAGE.LOGIN.PASSWORDEXPIRETOMORROW'); + this.passwordMessage = ''; + this.passwordNoOfDays = ''; + } else if (this.passwordNoOfDays === '0') { + this.passwordExpireMessage = this.translateService.instant('PAGE.LOGIN.PASSWORDEXPIRETODAY'); + this.passwordMessage = ''; + this.passwordNoOfDays = ''; + } + if (isNullOrUndefined(this.accountNoOfDays)) { + this.sharedService.passwordToaster(this.lastLogin, this.failedAttempts, this.passwordNoOfDays, + this.passwordExpireMessage, this.passwordMessage); + } else { + if (this.accountNoOfDays === '1') { + this.accountExpireMessage = this.translateService.instant('PAGE.LOGIN.ACCOUNTEXPIRETOMORROW'); + this.accountMessage = ''; + this.accountNoOfDays = ''; + } else if (this.accountNoOfDays === '0') { + this.accountExpireMessage = this.translateService.instant('PAGE.LOGIN.ACCOUNTEXPIRETODAY'); + this.accountMessage = ''; + this.accountNoOfDays = ''; + } else { + this.accountExpireMessage = this.accountExpireMessage = this.translateService.instant('PAGE.LOGIN.ACCOUNTEXPIRE'); + this.accountMessage = this.translateService.instant('PAGE.LOGIN.DAYS'); + } + this.sharedService.showToaster(this.lastLogin, this.failedAttempts, this.passwordNoOfDays, this.accountNoOfDays, + this.passwordExpireMessage, this.accountExpireMessage, this.passwordMessage, this.accountMessage); + } + } + } + } + /** To display account expiry Toaster with required data @public */ + public accountExpiryToaster(): void { + if (!isNullOrUndefined(this.accountNoOfDays)) { + if ((this.accountNoOfDays === '0') || (this.accountNoOfDays === '1') || ((this.accountNoOfDays === '0') && + (isNullOrUndefined(this.passwordNoOfDays) || !isNullOrUndefined(this.passwordNoOfDays))) || + ((this.accountNoOfDays === '1') && (isNullOrUndefined(this.passwordNoOfDays) || !isNullOrUndefined(this.passwordNoOfDays))) + && this.passwordNoOfDays !== '0' && this.passwordNoOfDays !== '1') { + if (this.accountNoOfDays === '1') { + this.accountExpireMessage = this.translateService.instant('PAGE.LOGIN.ACCOUNTEXPIRETOMORROW'); + this.accountMessage = ''; + this.accountNoOfDays = ''; + } else if (this.accountNoOfDays === '0') { + this.accountExpireMessage = this.translateService.instant('PAGE.LOGIN.ACCOUNTEXPIRETODAY'); + this.accountMessage = ''; + this.accountNoOfDays = ''; + } + if (isNullOrUndefined(this.passwordNoOfDays)) { + this.sharedService.accountToaster(this.lastLogin, this.failedAttempts, + this.accountNoOfDays, this.accountExpireMessage, this.accountMessage); + } else { + if (this.passwordNoOfDays === '1') { + this.passwordExpireMessage = this.translateService.instant('PAGE.LOGIN.PASSWORDEXPIRETOMORROW'); + this.passwordMessage = ''; + this.passwordNoOfDays = ''; + } else if (this.passwordNoOfDays === '0') { + this.passwordExpireMessage = this.translateService.instant('PAGE.LOGIN.PASSWORDEXPIRETODAY'); + this.passwordMessage = ''; + this.passwordNoOfDays = ''; + } else { + this.passwordExpireMessage = this.translateService.instant('PAGE.LOGIN.PASSWORDEXPIRE'); + this.passwordMessage = this.translateService.instant('PAGE.LOGIN.DAYS'); + } + this.sharedService.showToaster(this.lastLogin, this.failedAttempts, this.passwordNoOfDays, this.accountNoOfDays, + this.passwordExpireMessage, this.accountExpireMessage, this.passwordMessage, this.accountMessage); + } + } + } + } + /** To display password & account expiry Toaster with required data @public */ + public showToaster(): void { + if (!isNullOrUndefined(this.accountNoOfDays) && !isNullOrUndefined(this.passwordNoOfDays)) { + this.toaster.info(this.lastLoginMessage + ':' + ' ' + this.lastLogin + + '
' + this.failedAttemptsMessage + ':' + ' ' + this.failedAttempts + + '
' + this.passwordExpireMessage + ' ' + this.passwordNoOfDays + ' ' + this.daysMessage + + '
' + this.accountExpireMessage + ' ' + this.accountNoOfDays + ' ' + this.daysMessage, + this.translateService.instant('PAGE.LOGIN.LOGINHISTORY'), this.toasterSettings); + } else if (!isNullOrUndefined(this.accountNoOfDays) || !isNullOrUndefined(this.passwordNoOfDays)) { + if (!isNullOrUndefined(this.passwordNoOfDays)) { + this.toaster.info(this.lastLoginMessage + ':' + ' ' + this.lastLogin + + '
' + this.failedAttemptsMessage + ':' + ' ' + this.failedAttempts + + '
' + this.passwordExpireMessage + ' ' + this.passwordNoOfDays + ' ' + this.daysMessage, + this.translateService.instant('PAGE.LOGIN.LOGINHISTORY'), this.toasterSettings); + } else if (!isNullOrUndefined(this.accountNoOfDays)) { + this.toaster.info( + this.lastLoginMessage + ':' + ' ' + this.lastLogin + + '
' + this.failedAttemptsMessage + ':' + ' ' + this.failedAttempts + + '
' + this.accountExpireMessage + ' ' + this.accountNoOfDays + ' ' + this.daysMessage, + this.translateService.instant('PAGE.LOGIN.LOGINHISTORY'), this.toasterSettings); + } + } else { + this.toaster.info(this.lastLoginMessage + ':' + ' ' + this.lastLogin + + '
' + this.failedAttemptsMessage + ':' + ' ' + this.failedAttempts, + this.translateService.instant('PAGE.LOGIN.LOGINHISTORY'), this.toasterSettings); + } + } } diff --git a/src/app/users/add-user/AddEditUserComponent.ts b/src/app/users/add-user/AddEditUserComponent.ts index 076cfba..e7592e4 100644 --- a/src/app/users/add-user/AddEditUserComponent.ts +++ b/src/app/users/add-user/AddEditUserComponent.ts @@ -227,6 +227,8 @@ export class AddEditUserComponent implements OnInit { if (this.isFirstLogin) { this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.CHANGEPASSWORD')); this.authService.destoryToken(); + } else if (this.userType === 'changePassword' && (!this.isFirstLogin)) { + this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.CHANGEDSUCCESSFULLY')); } else { this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.EDITEDSUCCESSFULLY')); } diff --git a/src/app/users/user-details/UserDetailsComponent.html b/src/app/users/user-details/UserDetailsComponent.html index 9d11186..49661cb 100644 --- a/src/app/users/user-details/UserDetailsComponent.html +++ b/src/app/users/user-details/UserDetailsComponent.html @@ -26,6 +26,14 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i
+
+ +
diff --git a/src/app/users/user-details/UserDetailsComponent.ts b/src/app/users/user-details/UserDetailsComponent.ts index ba24454..51047ba 100644 --- a/src/app/users/user-details/UserDetailsComponent.ts +++ b/src/app/users/user-details/UserDetailsComponent.ts @@ -15,6 +15,7 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) */ +/* eslint-disable security/detect-object-injection */ /** * @file users details Component. */ @@ -23,7 +24,7 @@ import { Component, Injector, OnDestroy, OnInit } from '@angular/core'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { TranslateService } from '@ngx-translate/core'; import { AddEditUserComponent } from 'AddEditUserComponent'; -import { ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; import { DataService } from 'DataService'; import { environment } from 'environment'; import { LocalDataSource } from 'ng2-smart-table'; @@ -65,6 +66,21 @@ export class UserDetailsComponent implements OnInit, OnDestroy { /** Class for empty and present data @public */ public checkDataClass: string; + /** user active data @public */ + public userActive: string = CONFIGCONSTANT.userActive; + + /** user locked data @public */ + public userLocked: string = CONFIGCONSTANT.userLocked; + + /** user expired data @public */ + public userExpired: string = CONFIGCONSTANT.userExpired; + + /** user always-active data @public */ + public userAlwaysActive: string = CONFIGCONSTANT.userAlwaysActive; + + /** Admin Visibility Check @public */ + public isAdminShow: boolean; + /** Instance of the rest service @private */ private restService: RestService; @@ -109,20 +125,61 @@ export class UserDetailsComponent implements OnInit, OnDestroy { this.projectService.getAllProjects().subscribe((projects: {}[]) => { this.projectList = projects; }); + this.isAdminShow = localStorage.getItem('admin_show') === 'true' ? true : false; this.generateColumns(); this.generateSettings(); this.generateData(); + this.hideColumnForUser(); this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); } /** smart table Header Colums @public */ public generateColumns(): void { this.columnLists = { - username: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' }, - projects: { title: this.translateService.instant('PAGE.DASHBOARD.PROJECTS'), width: '25%' }, - identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' }, - modified: { title: this.translateService.instant('MODIFIED'), width: '15%' }, - created: { title: this.translateService.instant('CREATED'), width: '15%' }, + username: { title: this.translateService.instant('NAME'), width: '10%', sortDirection: 'asc' }, + projects: { title: this.translateService.instant('PAGE.DASHBOARD.PROJECTS'), width: '15%' }, + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '10%' }, + user_status: { + type: 'html', + title: this.translateService.instant('STATUS'), + width: '15%', + filter: { + type: 'list', + config: { + selectText: 'Select', + list: [ + { value: this.userActive, title: this.userActive }, + { value: this.userLocked, title: this.userLocked }, + { value: this.userExpired, title: this.userExpired }, + { value: this.userAlwaysActive, title: this.userAlwaysActive } + ] + } + }, + valuePrepareFunction: (cell: UserData, row: UserData): string => { + if (row.user_status === this.userActive) { + return ` + + `; + } else if (row.user_status === this.userLocked) { + return ` + + `; + } else if (row.user_status === this.userExpired) { + return ` + + `; + } else if (row.user_status === this.userAlwaysActive) { + return ` + + `; + } else { + return `${row.user_status}`; + } + } + }, + account_expire_time: { title: this.translateService.instant('Expires in'), width: '10%' }, + modified: { title: this.translateService.instant('MODIFIED'), width: '10%' }, + created: { title: this.translateService.instant('CREATED'), width: '10%' }, Actions: { name: 'Action', width: '5%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom', valuePrepareFunction: (cell: UserData, row: UserData): UserData => row, @@ -144,6 +201,22 @@ export class UserDetailsComponent implements OnInit, OnDestroy { }; } + /** To hide coulmns in smart table @public */ + public hideColumnForUser(): void { + if (!this.isAdminShow) { + const userStatus: string = 'user_status'; + const expire: string = 'account_expire_time'; + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete this.columnLists[userStatus]; + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete this.columnLists[expire]; + } else { + const modified: string = 'modified'; + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete this.columnLists[modified]; + } + } + /** on Navigate to Composer Page @public */ public composeUser(): void { // eslint-disable-next-line security/detect-non-literal-fs-filename @@ -177,7 +250,10 @@ export class UserDetailsComponent implements OnInit, OnDestroy { modified: this.sharedService.convertEpochTime(!isNullOrUndefined(userData._admin) ? userData._admin.modified : null), created: this.sharedService.convertEpochTime(!isNullOrUndefined(userData._admin) ? userData._admin.created : null), projects: userData.projectListName, - identifier: userData._id + identifier: userData._id, + user_status: userData._admin.user_status, + account_expire_time: this.sharedService.convertEpochTime(!isNullOrUndefined(userData._admin) ? + userData._admin.account_expire_time : null) }; this.userData.push(userDataObj); } diff --git a/src/app/utilities/users-action/UsersActionComponent.html b/src/app/utilities/users-action/UsersActionComponent.html index 90559f9..c108655 100644 --- a/src/app/utilities/users-action/UsersActionComponent.html +++ b/src/app/utilities/users-action/UsersActionComponent.html @@ -21,20 +21,32 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i {{'ACTION' | translate}} diff --git a/src/app/utilities/users-action/UsersActionComponent.ts b/src/app/utilities/users-action/UsersActionComponent.ts index cb0b462..04fd58a 100644 --- a/src/app/utilities/users-action/UsersActionComponent.ts +++ b/src/app/utilities/users-action/UsersActionComponent.ts @@ -18,6 +18,7 @@ /** * @file Users Action Component */ +import { isNullOrUndefined } from 'util'; import { Component, Injector } from '@angular/core'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { TranslateService } from '@ngx-translate/core'; @@ -27,6 +28,7 @@ import { DeleteComponent } from 'DeleteComponent'; import { ProjectRoleComponent } from 'ProjectRoleComponent'; import { SharedService } from 'SharedService'; import { UserData } from 'UserModel'; +import { WarningComponent } from 'WarningComponent'; /** * Creating component * @Component takes UsersActionComponent.html as template url @@ -46,6 +48,15 @@ export class UsersActionComponent { /** handle translate @public */ public translateService: TranslateService; + /** Admin Visibility Check @public */ + public isAdminShow: boolean; + + /** User Visibility Check @public */ + public isUserShow: boolean; + + /** User Status Check @public */ + public isUserStatus: string; + /** Instance of the modal service @private */ private modalService: NgbModal; @@ -59,6 +70,17 @@ export class UsersActionComponent { this.translateService = this.injector.get(TranslateService); } + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.isAdminShow = localStorage.getItem('admin_show') === 'true' ? true : false; + this.isUserShow = localStorage.getItem('user_show') === 'true' ? true : false; + if (!isNullOrUndefined(this.value.user_status)) { + this.isUserStatus = this.value.user_status; + } + } + /** Delete User Account @public */ public deleteUser(): void { // eslint-disable-next-line security/detect-non-literal-fs-filename @@ -107,4 +129,34 @@ export class UsersActionComponent { // Catch Navigation Error }); } + + /** To Unlock or Renew User @public */ + public unlockRenewUser(editType: string): void { + // eslint-disable-next-line security/detect-non-literal-fs-filename + const modalRef: NgbModalRef = this.modalService.open(WarningComponent, { backdrop: 'static' }); + localStorage.setItem('renew', 'true'); + const id: string = localStorage.getItem('user_id'); + if (editType === 'unlock') { + modalRef.componentInstance.heading = this.translateService.instant('Unlock User'); + modalRef.componentInstance.confirmationMessage = this.translateService.instant('Are you sure want to unlock this user'); + modalRef.componentInstance.submitMessage = this.translateService.instant('Unlock'); + modalRef.componentInstance.action = Boolean(true); + modalRef.componentInstance.editType = editType; + modalRef.componentInstance.id = this.value.identifier; + } else { + modalRef.componentInstance.heading = this.translateService.instant('Renew User'); + modalRef.componentInstance.confirmationMessage = this.translateService.instant('Are you sure want to renew this user'); + modalRef.componentInstance.submitMessage = this.translateService.instant('Renew'); + modalRef.componentInstance.action = Boolean(true); + modalRef.componentInstance.editType = editType; + modalRef.componentInstance.id = this.value.identifier; + } + modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => { + if (result) { + this.sharedService.callData(); + } + }).catch((): void => { + // Catch Navigation Error + }); + } } diff --git a/src/app/utilities/warning/WarningComponent.html b/src/app/utilities/warning/WarningComponent.html index 9be2656..92adccb 100644 --- a/src/app/utilities/warning/WarningComponent.html +++ b/src/app/utilities/warning/WarningComponent.html @@ -28,6 +28,7 @@ Author: SANDHYA JS (sandhya.j@tataelxsi.co.in) \ No newline at end of file diff --git a/src/app/utilities/warning/WarningComponent.ts b/src/app/utilities/warning/WarningComponent.ts index 0ccb888..c687fb0 100644 --- a/src/app/utilities/warning/WarningComponent.ts +++ b/src/app/utilities/warning/WarningComponent.ts @@ -18,8 +18,14 @@ /** * @file WarningConfiguration Model */ +import { HttpHeaders } from '@angular/common/http'; import { Component, Injector, Input } from '@angular/core'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA, UNLOCKPARAMS } from 'CommonModel'; +import { environment } from 'environment'; +import { RestService } from 'RestService'; /** * Creating component * @Component takes WarningComponent.html as template url @@ -55,9 +61,36 @@ export class WarningComponent { /** Give the message for the loading @public */ public message: string = 'PLEASEWAIT'; + /** Contains id of the admin user @public */ + @Input() + public id: string; + + /** Holds which action to perform @public */ + @Input() + public action: boolean = false; + + /** Contains editType data @public */ + @Input() + public editType: string; + + /** handle translate @public */ + public translateService: TranslateService; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + constructor(injector: Injector) { this.injector = injector; this.activeModal = this.injector.get(NgbActiveModal); + this.restService = this.injector.get(RestService); + this.translateService = this.injector.get(TranslateService); + this.notifierService = this.injector.get(NotifierService); } /** @@ -71,4 +104,41 @@ export class WarningComponent { public closeModal(getMessage: string): void { this.activeModal.close({ message: getMessage }); } + + /** + * called on submit @private onSubmit + */ + public onSubmit(): void { + this.isLoad = true; + const modalData: MODALCLOSERESPONSEDATA = { + message: 'Done' + }; + const id: string = localStorage.getItem('user_id'); + const payLoad: UNLOCKPARAMS = {}; + if (this.editType === 'unlock') { + payLoad.system_admin_id = id; + payLoad.unlock = true; + } else { + payLoad.system_admin_id = id; + payLoad.renew = true; + } + const apiURLHeader: APIURLHEADER = { + url: environment.USERS_URL + '/' + this.id, + httpOptions: { headers: this.headers } + }; + this.restService.patchResource(apiURLHeader, payLoad).subscribe((result: {}): void => { + this.activeModal.close(modalData); + this.isLoad = false; + if (this.editType === 'unlock') { + this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.UNLOCKUSER')); + } else { + this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.RENEWUSER')); + } + }, (error: ERRORDATA): void => { + this.restService.handleError(error, 'put'); + this.isLoad = false; + }, (): void => { + this.isLoad = false; + }); + } } diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 5070068..2bf6386 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -220,7 +220,17 @@ "USERNAMEVALIDMESSAGE": "Ein Benutzername wird benötigt", "SIGNINMSG": "Melden Sie sich an, um Ihre Sitzung zu starten", "PASSWORDMINLENGTHVALIDMESSAGE": "Das Passwort muss aus 8 Zeichen bestehen und mindestens ein Groß-, Klein-, Ziffern- und Sonderzeichen enthalten", - "USERNAMEMINLENGTHVALIDMESSAGE": "Der Benutzername muss aus mindestens 5 Zeichen bestehen" + "USERNAMEMINLENGTHVALIDMESSAGE": "Der Benutzername muss aus mindestens 5 Zeichen bestehen", + "LASTACCESS": "Zeit des letzten Zugriffs", + "FAILED": "Fehlgeschlagene Anmeldeversuche", + "PASSWORDEXPIRE": "Passwort läuft ab in", + "ACCOUNTEXPIRE": "Konto läuft ab in", + "PASSWORDEXPIRETODAY": "Passwort läuft heute ab", + "ACCOUNTEXPIRETODAY": "Konto läuft heute ab", + "LOGINHISTORY": "Anmeldeverlauf", + "DAYS": "Tage", + "PASSWORDEXPIRETOMORROW": "Passwort läuft morgen ab", + "ACCOUNTEXPIRETOMORROW": "Konto läuft morgen ab" }, "INSTANCEINSTANTIATE": { "NEWINSTANCE": "Neue Instanz", @@ -325,7 +335,12 @@ "EDITPROJECTROLEMAPPING": "Projektrollenzuordnung bearbeiten", "ADDMAPPINGS": "Mappings hinzufügen", "EDITPROJECTROLEERROR": "Bitte geben Sie mindestens eine Projektrollenzuordnung an, um fortzufahren", - "CHANGEPASSWORD": "Passwort wurde geändert. Melden Sie sich an, um Ihre Sitzung zu starten" + "CHANGEPASSWORD": "Passwort wurde geändert. Melden Sie sich an, um Ihre Sitzung zu starten", + "UNLOCK": "Benutzer entsperren", + "RENEW": "Benutzer erneuern", + "CHANGEDSUCCESSFULLY": "Das Passwort wurde erfolgreich geändert", + "UNLOCKUSER": "Der Benutzer wurde erfolgreich entsperrt", + "RENEWUSER": "Der Benutzer wurde erfolgreich erneuert" }, "TOPOLOGY": { "SELECTELEMENT": "Element auswählen", diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 659c0f5..0f8b581 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -220,7 +220,17 @@ "USERNAMEVALIDMESSAGE": "Username is required", "SIGNINMSG": "Sign in to start your session", "PASSWORDMINLENGTHVALIDMESSAGE": "Password must be 8 characters and contains at least one upper case, lower case, numeric & special character", - "USERNAMEMINLENGTHVALIDMESSAGE": "Username must be at least 5 characters" + "USERNAMEMINLENGTHVALIDMESSAGE": "Username must be at least 5 characters", + "LASTACCESS": "Last Access Time", + "FAILED": "Failed Login Attempts", + "PASSWORDEXPIRE": "Password Expires in", + "ACCOUNTEXPIRE": "Account Expires in", + "PASSWORDEXPIRETODAY": "Password Expires Today", + "ACCOUNTEXPIRETODAY": "Account Expires Today", + "LOGINHISTORY": "Login History", + "DAYS": "days", + "PASSWORDEXPIRETOMORROW": "Password Expires Tomorrow", + "ACCOUNTEXPIRETOMORROW": "Account Expires Tomorrow" }, "INSTANCEINSTANTIATE": { "NEWINSTANCE": "New Instance", @@ -325,7 +335,12 @@ "EDITPROJECTROLEMAPPING": "Edit Project Role Mapping", "ADDMAPPINGS": "Add Mappings", "EDITPROJECTROLEERROR": "Please provide at least one project role mapping to continue", - "CHANGEPASSWORD": "Password is changed, Sign in to start your session" + "CHANGEPASSWORD": "Password is changed, Sign in to start your session", + "UNLOCK": "Unlock User", + "RENEW": "Renew User", + "CHANGEDSUCCESSFULLY": "Password has been changed successfully", + "UNLOCKUSER": "User has been unlocked successfully", + "RENEWUSER": "User has been renewed successfully" }, "TOPOLOGY": { "SELECTELEMENT": "Select Element", diff --git a/src/assets/i18n/es.json b/src/assets/i18n/es.json index f8dfce6..f76eef7 100644 --- a/src/assets/i18n/es.json +++ b/src/assets/i18n/es.json @@ -220,7 +220,17 @@ "USERNAMEVALIDMESSAGE": "Se requiere nombre de usuario", "SIGNINMSG": "Inicie la sesión para comenzar", "PASSWORDMINLENGTHVALIDMESSAGE": "La contraseña debe tener 8 caracteres y al menos una mayúscula, una minúscula, un número y un carácter especial", - "USERNAMEMINLENGTHVALIDMESSAGE": "El nombre de usuario debe tener al menos 5 caracteres" + "USERNAMEMINLENGTHVALIDMESSAGE": "El nombre de usuario debe tener al menos 5 caracteres", + "LASTACCESS": "Última hora de acceso", + "FAILED": "Intentos de inicio de sesión fallidos", + "PASSWORDEXPIRE": "La contraseña caduca en", + "ACCOUNTEXPIRE": "La cuenta caduca en", + "PASSWORDEXPIRETODAY": "La contraseña caduca hoy", + "ACCOUNTEXPIRETODAY": "La cuenta vence hoy", + "LOGINHISTORY": "Historial de inicio de sesión", + "DAYS": "días", + "PASSWORDEXPIRETOMORROW": "La contraseña caduca mañana", + "ACCOUNTEXPIRETOMORROW": "La cuenta vence mañana" }, "INSTANCEINSTANTIATE": { "NEWINSTANCE": "Nueva instancia", @@ -325,7 +335,12 @@ "EDITPROJECTROLEMAPPING": "Editar asignación de roles de proyecto", "ADDMAPPINGS": "Agregar asignaciones", "EDITPROJECTROLEERROR": "Proporcione al menos un mapeo de roles del proyecto para continuar", - "CHANGEPASSWORD": "Se cambió la contraseña, inicie sesión para iniciar su sesión" + "CHANGEPASSWORD": "Se cambió la contraseña, inicie sesión para iniciar su sesión", + "UNLOCK": "Desbloquear usuario", + "RENEW": "Renovar usuario", + "CHANGEDSUCCESSFULLY": "La contraseña ha sido cambiada con éxito", + "UNLOCKUSER": "El usuario ha sido desbloqueado con éxito", + "RENEWUSER": "El usuario ha sido renovado con éxito" }, "TOPOLOGY": { "SELECTELEMENT": "Seleccionar elemento", diff --git a/src/assets/i18n/pt.json b/src/assets/i18n/pt.json index a37d187..3617fd4 100644 --- a/src/assets/i18n/pt.json +++ b/src/assets/i18n/pt.json @@ -220,7 +220,17 @@ "USERNAMEVALIDMESSAGE": "Nome de usuário é requerido", "SIGNINMSG": "Faça login para iniciar sua sessão", "PASSWORDMINLENGTHVALIDMESSAGE": "A senha deve ter 8 caracteres e conter pelo menos um caractere maiúsculo, minúsculo, numérico e especial", - "USERNAMEMINLENGTHVALIDMESSAGE": "O nome de usuário deve ter pelo menos 5 caracteres" + "USERNAMEMINLENGTHVALIDMESSAGE": "O nome de usuário deve ter pelo menos 5 caracteres", + "LASTACCESS": "Hora do último acesso", + "FAILED": "Tentativas de login com falha", + "PASSWORDEXPIRE": "A senha expira em", + "ACCOUNTEXPIRE": "Conta expira em", + "PASSWORDEXPIRETODAY": "A senha expira hoje", + "ACCOUNTEXPIRETODAY": "A conta expira hoje", + "LOGINHISTORY": "Histórico de login", + "DAYS": "dias", + "PASSWORDEXPIRETOMORROW": "A senha expira amanhã", + "ACCOUNTEXPIRETOMORROW": "A conta expira amanhã" }, "INSTANCEINSTANTIATE": { "NEWINSTANCE": "Nova Instância", @@ -325,7 +335,12 @@ "EDITPROJECTROLEMAPPING": "Editar mapeamento de função do projeto", "ADDMAPPINGS": "Adicionar mapeamentos", "EDITPROJECTROLEERROR": "Forneça pelo menos um mapeamento de função do projeto para continuar", - "CHANGEPASSWORD": "A senha foi alterada, faça login para iniciar sua sessão" + "CHANGEPASSWORD": "A senha foi alterada, faça login para iniciar sua sessão", + "UNLOCK": "Desbloquear usuário", + "RENEW": "Renovar usuário", + "CHANGEDSUCCESSFULLY": "A senha foi alterada com sucesso", + "UNLOCKUSER": "O usuário foi desbloqueado com sucesso", + "RENEWUSER": "O usuário foi renovado com sucesso" }, "TOPOLOGY": { "SELECTELEMENT": "Selecionar elemento", diff --git a/src/assets/scss/style.scss b/src/assets/scss/style.scss index 0fb1c39..40c5e16 100644 --- a/src/assets/scss/style.scss +++ b/src/assets/scss/style.scss @@ -43,4 +43,6 @@ $roboto-font-path: "~roboto-fontface/fonts" !default; @import "../../../node_modules/angular-notifier/styles/types/type-error.scss"; @import "../../../node_modules/angular-notifier/styles/types/type-warning.scss"; @import "../../../node_modules/angular-notifier/styles/types/type-default.scss"; -@import "../../../node_modules/angular-notifier/styles/types/type-info.scss"; \ No newline at end of file +@import "../../../node_modules/angular-notifier/styles/types/type-info.scss"; +/*toastr styles*/ +@import '~ngx-toastr/toastr.css'; \ No newline at end of file diff --git a/src/models/CommonModel.ts b/src/models/CommonModel.ts index ed35029..abf0cb6 100644 --- a/src/models/CommonModel.ts +++ b/src/models/CommonModel.ts @@ -73,7 +73,11 @@ export enum CONFIGCONSTANT { k8OperationalStateStateSecondStep = 'ENABLED', k8OperationalStateThirdStep = 'ERROR', done = 'done', - close = 'close' + close = 'close', + userActive = 'active', + userLocked = 'locked', + userExpired = 'expired', + userAlwaysActive = 'always-active' } /** Interface for Post options */ export interface POSTAPIRESOURCE { @@ -342,3 +346,9 @@ export interface LABELVALUE { label: string; value: string; } +/** Interface for Login */ +export interface UNLOCKPARAMS { + system_admin_id?: string; + unlock?: boolean; + renew?: boolean; +} diff --git a/src/models/UserModel.ts b/src/models/UserModel.ts index 64626c8..e49670a 100644 --- a/src/models/UserModel.ts +++ b/src/models/UserModel.ts @@ -37,6 +37,8 @@ export interface UserDetail { identifier: string; projectListName?: string; project_role_mappings?: ProjectRoleMappings[]; + account_expire_time: string; + password_expire_time?: string; } /** Interface for user role mappings */ @@ -50,6 +52,9 @@ interface Admin { salt: string; created: number; modified: number; + user_status?: string; + account_expire_time?: number; + password_expire_time?: number; } /** Interface for UserDetail */ export interface UserData { @@ -58,6 +63,8 @@ export interface UserData { modified: string; created: string; identifier: string; + user_status: string; + account_expire_time?: string; } /** Interface for Project Roles Mappings */ diff --git a/src/models/VNFDModel.ts b/src/models/VNFDModel.ts index 6eafe39..530ba48 100644 --- a/src/models/VNFDModel.ts +++ b/src/models/VNFDModel.ts @@ -33,6 +33,17 @@ export interface ProjectModel { admin: boolean; message?: string; user_id?: string; + roles?: RolesData[]; + last_login?: number; + login_count?: string; + user_show?: boolean; + admin_show?: boolean; +} + +/** Interface for Roles */ +export interface RolesData { + name?: string; + id?: string; } /** Interface for ProjectDetails */ diff --git a/src/services/AuthenticationService.ts b/src/services/AuthenticationService.ts index 5eda6f9..36cf476 100644 --- a/src/services/AuthenticationService.ts +++ b/src/services/AuthenticationService.ts @@ -28,6 +28,7 @@ import { APIURLHEADER, ERRORDATA } from 'CommonModel'; import { environment } from 'environment'; import { BehaviorSubject, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; +import { SharedService } from 'SharedService'; import { ProjectModel } from '../models/VNFDModel'; import { RestService } from './RestService'; @@ -76,6 +77,9 @@ export class AuthenticationService { /** handle idle time out service @private */ private idle: Idle; + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + /** create the instance of the component */ constructor(injector: Injector) { this.injector = injector; @@ -83,6 +87,7 @@ export class AuthenticationService { this.restService = this.injector.get(RestService); this.modalService = this.injector.get(NgbModal); this.idle = this.injector.get(Idle); + this.sharedService = this.injector.get(SharedService); if (localStorage.getItem('username') !== null) { this.loggedIn.next(true); this.changePassword.next(false); @@ -181,6 +186,11 @@ export class AuthenticationService { localStorage.setItem('project_id', data.project_id); localStorage.setItem('project', data.project_name); localStorage.setItem('token_state', data.id); + localStorage.setItem('user_id', data.user_id); + localStorage.setItem('user_show', String(data.user_show)); + localStorage.setItem('admin_show', String(data.admin_show)); + localStorage.setItem('last_login', this.sharedService.convertEpochTime(!isNullOrUndefined(data.last_login) ? data.last_login : null)); + localStorage.setItem('failed_count', data.login_count); this.projectName$.next(data.project_name); } /** Destory tokens API response handling @public */ diff --git a/src/services/SharedService.ts b/src/services/SharedService.ts index 53078b5..8abe1d2 100644 --- a/src/services/SharedService.ts +++ b/src/services/SharedService.ts @@ -39,6 +39,7 @@ import { import { environment } from 'environment'; import * as HttpStatus from 'http-status-codes'; import * as untar from 'js-untar'; +import { ActiveToast, ToastrService } from 'ngx-toastr'; import * as pako from 'pako'; import { RestService } from 'RestService'; import { Observable } from 'rxjs'; @@ -98,6 +99,15 @@ export class SharedService { /** Holds OSM Version value @public */ public osmVersion: string; + /** Holds Last Login Toaster Message @public */ + public lastLoginMessage: string; + + /** Holds Failed Attempts Toaster Message @public */ + public failedAttemptsMessage: string; + + /** Holds No Of Days Toaster Message @public */ + public daysMessage: string; + /** express number for time manupulation -2 */ // eslint-disable-next-line @typescript-eslint/no-magic-numbers private epochTimeMinus2: number = -2; @@ -106,10 +116,22 @@ export class SharedService { // eslint-disable-next-line @typescript-eslint/no-magic-numbers private epochTime1000: number = 1000; + /** express number for time manupulation 60 */ + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + private epochTime60: number = 60; + + /** express number for time manupulation 24 */ + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + private epochTime24: number = 24; + /** Random string generator length */ // eslint-disable-next-line @typescript-eslint/no-magic-numbers private randomStringLength: number = 4; + /** Max length of Uint8Array */ + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + private unit8Array: number = 255; + /** Instance of the rest service @private */ private restService: RestService; @@ -124,13 +146,24 @@ export class SharedService { // eslint-disable-next-line @typescript-eslint/no-magic-numbers private directoryCount: number = 2; + /** express number for time manupulation 1000 */ + private toasterSettings: {} = { + enableHtml: true, + closeButton: true, + timeOut: 2000 + }; + /** Contains tranlsate instance @private */ private translateService: TranslateService; - constructor(restService: RestService, router: Router, translateService: TranslateService) { + /** Contains toaster instance @private */ + private toaster: ToastrService; + + constructor(restService: RestService, router: Router, translateService: TranslateService, toaster: ToastrService) { this.restService = restService; this.router = router; this.translateService = translateService; + this.toaster = toaster; } /** convert epoch time function @public */ @@ -153,6 +186,52 @@ export class SharedService { return this.translateService.instant('NODATE'); } + /** convert epoch time function to No of days @public */ + public converEpochToDays(date: string): number { + if (!isNullOrUndefined(date)) { + const today: Date = new Date(); + const accountDate: Date = new Date(date); + return Math.floor((accountDate.getTime() - + today.getTime()) / this.epochTime1000 / this.epochTime60 / this.epochTime60 / this.epochTime24); + } + return this.translateService.instant('N/A'); + } + + /** show toaster for password & account expiry @public */ + public showToaster(lastLogin: string, failedAttempts: string, passwordNoOfDays: string, + accountNoOfDays: string, passwordExpireMessage: string, accountExpireMessage: string, + passwordMessage: string, accountMessage: string): ActiveToast { + this.lastLoginMessage = this.translateService.instant('PAGE.LOGIN.LASTACCESS'); + this.failedAttemptsMessage = this.translateService.instant('PAGE.LOGIN.FAILED'); + return this.toaster.info(this.lastLoginMessage + ':' + ' ' + lastLogin + + '
' + this.failedAttemptsMessage + ':' + ' ' + failedAttempts + + '
' + passwordExpireMessage + ' ' + passwordNoOfDays + ' ' + passwordMessage + + '
' + accountExpireMessage + ' ' + accountNoOfDays + ' ' + accountMessage, + this.translateService.instant('PAGE.LOGIN.LOGINHISTORY'), this.toasterSettings); + } + + /** show toaster for password expiry @public */ + public passwordToaster(lastLogin: string, failedAttempts: string, passwordNoOfDays: string, + passwordExpireMessage: string, passwordMessage: string): ActiveToast { + this.lastLoginMessage = this.translateService.instant('PAGE.LOGIN.LASTACCESS'); + this.failedAttemptsMessage = this.translateService.instant('PAGE.LOGIN.FAILED'); + return this.toaster.info(this.lastLoginMessage + ':' + ' ' + lastLogin + + '
' + this.failedAttemptsMessage + ':' + ' ' + failedAttempts + + '
' + passwordExpireMessage + ' ' + passwordNoOfDays + ' ' + passwordMessage, + this.translateService.instant('PAGE.LOGIN.LOGINHISTORY'), this.toasterSettings); + } + + /** show toaster for account expiry @public */ + public accountToaster(lastLogin: string, failedAttempts: string, + accountNoOfDays: string, accountExpireMessage: string, accountMessage: string): ActiveToast { + this.lastLoginMessage = this.translateService.instant('PAGE.LOGIN.LASTACCESS'); + this.failedAttemptsMessage = this.translateService.instant('PAGE.LOGIN.FAILED'); + return this.toaster.info(this.lastLoginMessage + ':' + ' ' + lastLogin + + '
' + this.failedAttemptsMessage + ':' + ' ' + failedAttempts + + '
' + accountExpireMessage + ' ' + accountNoOfDays + ' ' + accountMessage, + this.translateService.instant('PAGE.LOGIN.LOGINHISTORY'), this.toasterSettings); + } + /** Download Files function @public */ public downloadFiles(name: string, binaryData: Blob[], filetype: string): void { const downloadLink: HTMLAnchorElement = document.createElement('a');