Skip to content

Commit

Permalink
MOSIP-24690 : added popup for session idle logout
Browse files Browse the repository at this point in the history
Signed-off-by: sudeep <sudeep.j7353@gmail.com>
  • Loading branch information
Sudeep7353 committed Dec 14, 2023
1 parent bfcbcab commit bfd412b
Show file tree
Hide file tree
Showing 15 changed files with 297 additions and 8 deletions.
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"@stomp/rx-stomp": "^2.0.0",
"@stomp/stompjs": "^7.0.0",
"angular-cd-timer": "^1.3.0",
"angular-user-idle": "^2.2.7",
"base64-js": "1.3.0",
"crypto-js": "^4.2.0",
"js-sha256": "0.9.0",
Expand Down
14 changes: 14 additions & 0 deletions src/app/app-config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class AppConfigService {
(response: any) => {
//console.log(response);
this.appConfig = { ...this.appConfig, ...response["response"] };
this.setConfig(this.appConfig);
//console.log(this.appConfig);
},
(error) => {
Expand All @@ -31,6 +32,19 @@ export class AppConfigService {
);
}

public setConfig(configJson: any) {
localStorage.setItem('config', JSON.stringify(configJson));
}

public getConfigByKey(key: string) {
const configString = localStorage.getItem('config');
if (configString) {
const config = JSON.parse(configString);
return config[key];
}
return null;
}

getConfig() {
return this.appConfig;
}
Expand Down
26 changes: 25 additions & 1 deletion src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit, HostListener } from '@angular/core';
import { Component, OnInit, OnDestroy, HostListener } from '@angular/core';
import {
RouterEvent,
NavigationStart,
Expand All @@ -9,6 +9,8 @@ import {
} from '@angular/router';
import { filter } from 'rxjs';
import { AppConfigService } from './app-config.service';
import { SessionLogoutService } from './core/services/session-logout.service';
import { Subscription } from 'rxjs';

@Component({
selector: 'app-root',
Expand All @@ -23,9 +25,13 @@ export class AppComponent {

subscribed: any;

subscriptions: Subscription[] = [];


constructor(
private router: Router,
private appConfigService: AppConfigService,
private sessionLogoutService: SessionLogoutService

) {
this.subscribed = router.events.subscribe(event => {
Expand All @@ -34,6 +40,11 @@ export class AppComponent {

}

ngOnInit() {
this.subscriptions.push(this.sessionLogoutService.currentMessageAutoLogout.subscribe(() => { }));
this.sessionLogoutService.changeMessage({ timerFired: false });
}

navigationInterceptor(event: any): void {
if (event instanceof NavigationStart) {
//console.log("NavigationStart");
Expand All @@ -52,4 +63,17 @@ export class AppComponent {
this.loading = false;
}
}

@HostListener('mouseover')
@HostListener('keypress')
@HostListener('click')
@HostListener('document:keypress', ['$event'])
@HostListener('document:mousemove', ['$event'])
onMouseClick() {
this.sessionLogoutService.setisActive(true);
}

ngOnDestroy(): void {
this.subscriptions.forEach(subscription => subscription.unsubscribe());
}
}
5 changes: 5 additions & 0 deletions src/app/app.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,8 @@ export const REPORT_STATUS_APPROVED = "approved";
export const REPORT_STATUS_REJECTED = "rejected";
export const NO_DATA_AVAILABLE = 'no_data_available';
export const LOADING = 'loading';

//session idle values from config
export const SESSION_LOGOUT_IDLE = "sessionLogoutIdle";
export const SESSION_LOGOUT_TIMEOUT = 'sessionLogoutTimer';
export const SESSION_LOGOUT_PING = 'sessionLogoutPing';
6 changes: 6 additions & 0 deletions src/app/core/components/dialog/dialog.component.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ mat-dialog-content {
vertical-align: middle;
}

.ok-button-container {
display: flex;
align-items: center;
justify-content: flex-end;
}

.formContainer {
background-color: white;
margin-top: 10px;
Expand Down
13 changes: 13 additions & 0 deletions src/app/core/components/dialog/dialog.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -305,4 +305,17 @@ <h2 mat-dialog-title class="mat-dialog-title">{{"dialogMessages.addProject"|tran
</div>
</div>
</div>
<div *ngIf="input.case === 'SESSION_TIMEOUT_POPUP'">
<mat-dialog-content>
<p>{{ 'dialogMessages.sessionInactiveMessage' | translate }}</p>
</mat-dialog-content>
</div>
<div *ngIf="input.case === 'POSTLOGOUT_POPUP'">
<mat-dialog-content>
<p>{{ 'dialogMessages.sessionInactivityLogoutMessage' | translate }}</p>
</mat-dialog-content>
<mat-dialog-actions class="ok-button-container">
<button mat-flat-button color="accent" (click)="onOkClick()">{{ 'dialogMessages.close' | translate }}</button>
</mat-dialog-actions>
</div>
</div>
12 changes: 10 additions & 2 deletions src/app/core/components/dialog/dialog.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Router } from '@angular/router';
import { Subscription, flatMap } from 'rxjs';
import Utils from 'src/app/app.utils';
import { AppConfigService } from 'src/app/app-config.service';
import { LogoutService } from '../../services/logout.service';

@Component({
selector: 'app-dialog',
Expand Down Expand Up @@ -59,8 +60,9 @@ export class DialogComponent implements OnInit {
private dataService: DataService,
private dialog: MatDialog,
private translate: TranslateService,
private userProfileService: UserProfileService
) {
private userProfileService: UserProfileService,
private logoutservice: LogoutService
) {
dialogRef.disableClose = true;

}
Expand Down Expand Up @@ -466,4 +468,10 @@ export class DialogComponent implements OnInit {
checkHashAndWebsiteUrl() {
this.dialogRef.close(false);
}

// Close the dialog when the user clicks on the "OK" button, and initiate the logout process.
onOkClick(): void {
this.dialogRef.close();
this.logoutservice.logout();
}
}
1 change: 1 addition & 0 deletions src/app/core/services/logout.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export class LogoutService {
return true;
} else {
window.location.href = `${this.appService.getConfig().SERVICES_BASE_URL}${this.appService.getConfig().logout}?redirecturi=` + btoa(window.location.href);
localStorage.removeItem('config');
}
//let adminUrl = this.appService.getConfig().toolkitUiUrl;
/*
Expand Down
16 changes: 16 additions & 0 deletions src/app/core/services/session-logout.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { SessionLogoutService } from './session-logout.service';

describe('SessionLogoutService', () => {
let service: SessionLogoutService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(SessionLogoutService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});
161 changes: 161 additions & 0 deletions src/app/core/services/session-logout.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { Injectable } from '@angular/core';
import { UserIdleService, UserIdleConfig } from 'angular-user-idle';
import { AuthService } from './authservice.service';
import { MatDialog } from '@angular/material/dialog';
import { DialogComponent } from '../components/dialog/dialog.component';
import { BehaviorSubject } from 'rxjs';
import { AppConfigService } from 'src/app/app-config.service';
import * as appConstants from 'src/app/app.constants';
import { LogoutService } from './logout.service';
import { environment } from 'src/environments/environment';

/**
* @description This class is responsible for auto logging out user when he is inactive for a
* specified period of time.
*/

@Injectable({
providedIn: 'root'
})
export class SessionLogoutService {
private messageAutoLogout = new BehaviorSubject({});
currentMessageAutoLogout = this.messageAutoLogout.asObservable();
isActive = false;
timer = new UserIdleConfig();
isAndroidAppMode = environment.isAndroidAppMode == 'yes' ? true : false;

idle: number;
timeout: number;
ping: number;
dialogref: any;
dialogreflogout: any;

constructor(
private userIdle: UserIdleService,
private authService: AuthService,
private dialog: MatDialog,
private configservice: AppConfigService,
private logoutservice: LogoutService
) { }

/**
* @description This method gets value of idle,timeout and ping parameter from config file.
*/
getValues() {
// Convert minutes to seconds for idle, timeout, and use the ping value as it is in seconds.
(this.idle = Number(
this.configservice.getConfigByKey(appConstants.SESSION_LOGOUT_IDLE) * 60
)),
(this.timeout = Number(
this.configservice.getConfigByKey(appConstants.SESSION_LOGOUT_TIMEOUT) * 60
)),
(this.ping = Number(
this.configservice.getConfigByKey(appConstants.SESSION_LOGOUT_PING)
));
}

setisActive(value: boolean) {
this.isActive = value;
}
getisActive() {
return this.isActive;
}

changeMessage(message: object) {
this.messageAutoLogout.next(message);
}

/**
* @description This method sets value of idle,timeout and ping parameter from config file.
*/
setValues() {
this.userIdle.stopWatching();
this.timer.idle = this.idle;
this.timer.ping = this.ping;
this.timer.timeout = this.timeout;
this.userIdle.setConfigValues(this.timer);
}

/**
* @description This method is fired when dashboard gets loaded and starts the timer to watch for
* user idle. onTimerStart() is fired when user idle has been detected for specified time.
* After that onTimeout() is fired.
*/

public keepWatching() {
this.userIdle.startWatching();
this.changeMessage({ timerFired: true });

this.userIdle.onTimerStart().subscribe(
(res) => {
if (res === 1) {
this.setisActive(false);
this.openPopUp();
} else {
if (this.isActive) {
if (this.dialogref) this.dialogref.close();
this.userIdle.resetTimer();
}
}
},
() => {},
() => {}
);

this.userIdle.onTimeout().subscribe(() => {
if (!this.isActive) {
console.log(this.isAndroidAppMode);
if (!this.isAndroidAppMode) {
this.onLogOut();
} else {
this.dialogref.close();
this.userIdle.stopWatching();
}
} else {
this.userIdle.resetTimer();
}
});
}

public continueWatching() {
this.userIdle.startWatching();
}
/**
* @description This method is used to logged out the user.
*/
onLogOut() {
this.dialogref.close();
this.dialog.closeAll();
this.popUpPostLogOut();
this.userIdle.stopWatching();

/// After displaying the session logout popup for five seconds, initiate the logout process.
setTimeout(() => {
this.logoutservice.logout();
}, 5000);
}


/**
* @description This method opens a pop up when user idle has been detected for given time.id
*/

openPopUp() {
const data = {
case: 'SESSION_TIMEOUT_POPUP',
};
this.dialogref = this.dialog.open(DialogComponent, {
width: '500px',
data: data
});
}
popUpPostLogOut() {
const data = {
case: 'POSTLOGOUT_POPUP',
};
this.dialogreflogout = this.dialog.open(DialogComponent, {
width: '500px',
data: data
});
}
}
Loading

0 comments on commit bfd412b

Please sign in to comment.