Feature 10941: User Management Enhancements 85/13285/4
authorSANDHYA.JS <sandhya.j@tataelxsi.co.in>
Wed, 26 Apr 2023 12:24:57 +0000 (17:54 +0530)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Thu, 8 Jun 2023 15:31:21 +0000 (17:31 +0200)
- 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 <sandhya.j@tataelxsi.co.in>
24 files changed:
package.json
src/app/AppModule.ts
src/app/layouts/header/HeaderComponent.html
src/app/layouts/header/HeaderComponent.scss
src/app/layouts/header/HeaderComponent.ts
src/app/login/LoginComponent.scss
src/app/login/LoginComponent.ts
src/app/users/add-user/AddEditUserComponent.ts
src/app/users/user-details/UserDetailsComponent.html
src/app/users/user-details/UserDetailsComponent.ts
src/app/utilities/users-action/UsersActionComponent.html
src/app/utilities/users-action/UsersActionComponent.ts
src/app/utilities/warning/WarningComponent.html
src/app/utilities/warning/WarningComponent.ts
src/assets/i18n/de.json
src/assets/i18n/en.json
src/assets/i18n/es.json
src/assets/i18n/pt.json
src/assets/scss/style.scss
src/models/CommonModel.ts
src/models/UserModel.ts
src/models/VNFDModel.ts
src/services/AuthenticationService.ts
src/services/SharedService.ts

index d4b4cb4..bb99e9b 100644 (file)
@@ -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",
index 8a4ebaf..d260784 100644 (file)
@@ -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: [
         {
index 4725920..042f720 100644 (file)
@@ -62,6 +62,11 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i
                         <span>{{'PAGE.DASHBOARD.USERSETTINGS' | translate}}</span>
                         <i class="fas fa-users-cog"></i>
                     </a>
+                    <a *ngIf="!isSystemAdmin" ngbDropdownItem class="dropdown-item project-item"
+                        (click)="changePassword()">
+                        <span>{{'PAGE.USERS.EDITCREDENTIALS' | translate}}</span>
+                        <i class="fas fa-edit icons"></i>
+                    </a>
                     <a ngbDropdownItem class="dropdown-item project-item" (click)="logout()">
                         <span>{{'PAGE.DASHBOARD.LOGOUT' | translate}}</span>
                         <i class="fas fa-sign-out-alt"></i>
index 86200b7..81f90c1 100644 (file)
@@ -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);
index 9b4fca6..9392177 100644 (file)
  * @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
+        });
+    }
 }
index 293e50c..dc1a51b 100644 (file)
       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
index fae3d20..db842d8 100644 (file)
@@ -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 + ':' + '&nbsp' + this.lastLogin +
+                '</br>' + this.failedAttemptsMessage + ':' + '&nbsp' + this.failedAttempts +
+                '</br>' + this.passwordExpireMessage + '&nbsp' + this.passwordNoOfDays + '&nbsp' + this.daysMessage +
+                '</br>' + this.accountExpireMessage + '&nbsp' + this.accountNoOfDays + '&nbsp' + 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 + ':' + '&nbsp' + this.lastLogin +
+                    '</br>' + this.failedAttemptsMessage + ':' + '&nbsp' + this.failedAttempts +
+                    '</br>' + this.passwordExpireMessage + '&nbsp' + this.passwordNoOfDays + '&nbsp' + this.daysMessage,
+                    this.translateService.instant('PAGE.LOGIN.LOGINHISTORY'), this.toasterSettings);
+            } else if (!isNullOrUndefined(this.accountNoOfDays)) {
+                this.toaster.info(
+                    this.lastLoginMessage + ':' + '&nbsp' + this.lastLogin +
+                    '</br>' + this.failedAttemptsMessage + ':' + '&nbsp' + this.failedAttempts +
+                    '</br>' + this.accountExpireMessage + '&nbsp' + this.accountNoOfDays + '&nbsp' + this.daysMessage,
+                    this.translateService.instant('PAGE.LOGIN.LOGINHISTORY'), this.toasterSettings);
+            }
+        } else {
+            this.toaster.info(this.lastLoginMessage + ':' + '&nbsp' + this.lastLogin +
+                '</br>' + this.failedAttemptsMessage + ':' + '&nbsp' + this.failedAttempts,
+                this.translateService.instant('PAGE.LOGIN.LOGINHISTORY'), this.toasterSettings);
+        }
+    }
 }
index 076cfba..e7592e4 100644 (file)
@@ -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'));
             }
index 9d11186..49661cb 100644 (file)
@@ -26,6 +26,14 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i
   </span>
 </div>
 <div class="row mt-2 mb-0 form-group justify-content-end list-utilites-actions">
+  <div *ngIf="isAdminShow" class="col-auto mr-auto">
+    <nav class="custom-items-config">
+      <span><i class="fas fa-user-check text-success"></i>{{userActive}}</span>
+      <span><i class="fas fa-user-lock text-danger"></i>{{userLocked}}</span>
+      <span><i class="fas fa-user-times text-warning"></i>{{userExpired}}</span>
+      <span><i class="fas fa-user-shield text-info"></i>{{userAlwaysActive}}</span>
+    </nav>
+  </div>
   <page-per-row class="mr-2" (pagePerRow)="onChange($event)"></page-per-row>
   <page-reload></page-reload>
 </div>
index ba24454..51047ba 100644 (file)
@@ -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 `<span class="icon-label" title="${row.user_status}">
+                 <i class="fas fa-user-check text-success"></i>
+                 </span>`;
+          } else if (row.user_status === this.userLocked) {
+            return `<span class="icon-label" title="${row.user_status}">
+                 <i class="fas fa-user-lock text-danger"></i>
+                 </span>`;
+          } else if (row.user_status === this.userExpired) {
+            return `<span class="icon-label" title="${row.user_status}">
+                 <i class="fas fa-user-times text-warning"></i>
+                 </span>`;
+          } else if (row.user_status === this.userAlwaysActive) {
+            return `<span class="icon-label" title="${row.user_status}">
+                 <i class="fas fa-user-shield text-info"></i>
+                 </span>`;
+          } else {
+            return `<span>${row.user_status}</span>`;
+          }
+        }
+      },
+      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);
   }
index 90559f9..c108655 100644 (file)
@@ -21,20 +21,32 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i
             {{'ACTION' | translate}}
         </button>
         <div class="dropdown-menu list-action-dropdown" ngbDropdownMenu>
-            <button type="button" class="btn btn-primary dropdown-item" (click)="editUserModal('editPassword')" placement="left" container="body"
-                ngbTooltip="{{'PAGE.USERS.EDITCREDENTIALS' | translate}}">
+            <button *ngIf="isAdminShow" type="button" class="btn btn-primary dropdown-item" (click)="editUserModal('editPassword')"
+                placement="left" container="body" ngbTooltip="{{'PAGE.USERS.EDITCREDENTIALS' | translate}}">
                 <i class="fa fa-edit icons"></i> {{'PAGE.USERS.EDITCREDENTIALS' | translate}}
             </button>
-            <button type="button" class="btn btn-primary dropdown-item" (click)="editUserModal('editUserName')" placement="left" container="body"
-                ngbTooltip="{{'PAGE.USERS.EDITUSERNAME' | translate}}">
+            <button *ngIf="!isAdminShow && !isUserShow" type="button" class="btn btn-primary dropdown-item" (click)="editUserModal('editPassword')"
+            placement="left" container="body" ngbTooltip="{{'PAGE.USERS.EDITCREDENTIALS' | translate}}">
+            <i class="fa fa-edit icons"></i> {{'PAGE.USERS.EDITCREDENTIALS' | translate}}
+           </button>
+            <button type="button" class="btn btn-primary dropdown-item" (click)="editUserModal('editUserName')"
+                placement="left" container="body" ngbTooltip="{{'PAGE.USERS.EDITUSERNAME' | translate}}">
                 <i class="fas fa-user-edit"></i> {{'PAGE.USERS.EDITUSERNAME' | translate}}
             </button>
-            <button type="button" class="btn btn-primary dropdown-item" (click)="projectRolesModal()" placement="left" container="body"
-                ngbTooltip="{{'PAGE.USERS.PROJECTSROLES' | translate}}">
+            <button type="button" class="btn btn-primary dropdown-item" (click)="projectRolesModal()" placement="left"
+                container="body" ngbTooltip="{{'PAGE.USERS.PROJECTSROLES' | translate}}">
                 <i class="fas fa-user-check"></i> {{'PAGE.USERS.PROJECTSROLES' | translate}}
             </button>
-            <button type="button" class="btn btn-primary dropdown-item" (click)="deleteUser()" placement="left" container="body"
-                ngbTooltip="{{'DELETE' | translate}}">
+            <button [hidden] ="!isAdminShow || isUserStatus !== 'expired'" type="button" class="btn btn-primary dropdown-item" (click)="unlockRenewUser('renew')" placement="left"
+                container="body" ngbTooltip="{{'PAGE.USERS.RENEW' | translate}}">
+                <i class="fas fa-user-clock"></i> {{'PAGE.USERS.RENEW' | translate}}
+            </button>
+            <button [hidden] ="!isAdminShow || isUserStatus !== 'locked'" type="button" class="btn btn-primary dropdown-item" (click)="unlockRenewUser('unlock')" placement="left"
+                container="body" ngbTooltip="{{'PAGE.USERS.UNLOCK' | translate}}">
+                <i class="fas fa-unlock"></i> {{'PAGE.USERS.UNLOCK' | translate}}
+            </button>
+            <button type="button" class="btn btn-primary dropdown-item" (click)="deleteUser()" placement="left"
+                container="body" ngbTooltip="{{'DELETE' | translate}}">
                 <i class="far fa-trash-alt icons" title="delete"></i> {{'DELETE' | translate}}
             </button>
         </div>
index cb0b462..04fd58a 100644 (file)
@@ -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
+        });
+    }
 }
index 9be2656..92adccb 100644 (file)
@@ -28,6 +28,7 @@ Author: SANDHYA JS (sandhya.j@tataelxsi.co.in)
 </div>
 <div class="modal-footer">
     <button (click)="closeModal('close')" class="btn btn-danger">{{'CANCEL' | translate }}</button>
-    <button (click)="closeModal('done')" class="btn btn-success">{{submitMessage}}</button>
+    <button *ngIf="!action" (click)="closeModal('done')" class="btn btn-success">{{submitMessage}}</button>
+    <button *ngIf="action" (click)="onSubmit()" class="btn btn-success">{{submitMessage}}</button>
 </div>
 <app-loader [waitingMessage]="message" *ngIf="isLoad"></app-loader>
\ No newline at end of file
index 0ccb888..c687fb0 100644 (file)
 /**
  * @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;
+        });
+    }
 }
index 5070068..2bf6386 100644 (file)
             "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",
             "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",
index 659c0f5..0f8b581 100644 (file)
             "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",
             "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",
index f8dfce6..f76eef7 100644 (file)
             "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",
             "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",
index a37d187..3617fd4 100644 (file)
             "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",
             "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",
index 0fb1c39..40c5e16 100644 (file)
@@ -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
index ed35029..abf0cb6 100644 (file)
@@ -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;
+}
index 64626c8..e49670a 100644 (file)
@@ -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 */
index 6eafe39..530ba48 100644 (file)
@@ -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 */
index 5eda6f9..36cf476 100644 (file)
@@ -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 */
index 53078b5..8abe1d2 100644 (file)
@@ -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<string> {
+        this.lastLoginMessage = this.translateService.instant('PAGE.LOGIN.LASTACCESS');
+        this.failedAttemptsMessage = this.translateService.instant('PAGE.LOGIN.FAILED');
+        return this.toaster.info(this.lastLoginMessage + ':' + '&nbsp' + lastLogin +
+            '</br>' + this.failedAttemptsMessage + ':' + '&nbsp' + failedAttempts +
+            '</br>' + passwordExpireMessage + '&nbsp' + passwordNoOfDays + '&nbsp' + passwordMessage +
+            '</br>' + accountExpireMessage + '&nbsp' + accountNoOfDays + '&nbsp' + 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<string> {
+        this.lastLoginMessage = this.translateService.instant('PAGE.LOGIN.LASTACCESS');
+        this.failedAttemptsMessage = this.translateService.instant('PAGE.LOGIN.FAILED');
+        return this.toaster.info(this.lastLoginMessage + ':' + '&nbsp' + lastLogin +
+            '</br>' + this.failedAttemptsMessage + ':' + '&nbsp' + failedAttempts +
+            '</br>' + passwordExpireMessage + '&nbsp' + passwordNoOfDays + '&nbsp' + 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<string> {
+        this.lastLoginMessage = this.translateService.instant('PAGE.LOGIN.LASTACCESS');
+        this.failedAttemptsMessage = this.translateService.instant('PAGE.LOGIN.FAILED');
+        return this.toaster.info(this.lastLoginMessage + ':' + '&nbsp' + lastLogin +
+            '</br>' + this.failedAttemptsMessage + ':' + '&nbsp' + failedAttempts +
+            '</br>' + accountExpireMessage + '&nbsp' + accountNoOfDays + '&nbsp' + 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');