Skip to content

Commit

Permalink
Merge pull request #428 from fledge-iot/FOGL-8757
Browse files Browse the repository at this point in the history
FOGL-8757: Blocked user GUI support incase of invalid password attempt
  • Loading branch information
mshariq-nerd authored Jun 24, 2024
2 parents 0f77132 + 0db740c commit 255d371
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 67 deletions.
18 changes: 10 additions & 8 deletions src/app/components/common/alert-dialog/alert-dialog.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ export class AlertDialogComponent implements OnInit, OnChanges {
@Output() deleteNotification = new EventEmitter<Object>();
@Output() deleteNotificationService = new EventEmitter<Object>();
@Output() deleteTask = new EventEmitter<Object>();
@Output() deleteUserService = new EventEmitter<Number>();

@Output() deletePipeline = new EventEmitter<Number>();
@Output() deleteCertificate = new EventEmitter<Object>();
@Output() logoutUserService = new EventEmitter<Number>();
@Output() createBackup = new EventEmitter<Number>();
@Output() restoreBackup = new EventEmitter<Number>();
@Output() deleteBackup = new EventEmitter<Number>();
@Output() logoutAllUserSessionsService = new EventEmitter<Number>();
@Output() userActionService = new EventEmitter<any>();
modalId = '';

constructor() { }
Expand Down Expand Up @@ -55,6 +55,12 @@ export class AlertDialogComponent implements OnInit, OnChanges {
this.childData.actionButtonValue = 'Deactivate';
this.childData.headerTextValue = 'Deactivate User';
}

if (this.childData.key === 'unblockUser') {
this.childData.actionButtonValue = 'Unblock';
this.childData.headerTextValue = 'Unblock User';
}

if (this.childData.key === 'logout') {
this.childData.actionButtonValue = 'Log Out';
}
Expand Down Expand Up @@ -107,8 +113,8 @@ export class AlertDialogComponent implements OnInit, OnChanges {
this.delete.emit(this.childData.id);
this.toggleModal(false);
}
if (this.childData.key === 'deactivateUser') {
this.deleteUserService.emit(this.childData.id);
if (['deactivateUser', 'enableUser', 'unblockUser', 'clearSessions'].includes(this.childData.key)) {
this.userActionService.emit({ key: this.childData.key, id: this.childData.id });
this.toggleModal(false);
}
if (this.childData.key === 'deleteCertificate') {
Expand All @@ -119,10 +125,6 @@ export class AlertDialogComponent implements OnInit, OnChanges {
this.deleteCertificate.emit({ name: this.childData.name, type: 'key' });
this.toggleModal(false);
}
if (this.childData.key === 'clearSessions') {
this.logoutAllUserSessionsService.emit(this.childData.id);
this.toggleModal(false);
}
if (this.childData.key === 'logout') {
this.logoutUserService.emit();
this.toggleModal(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,44 @@
.fa::before {
display: inline-block;
display: inline-block;
}

.tabs {
position: relative;
}

.columns {
margin-top: 10px;
}

.column {
padding-top: 0px;
position: relative;
}

.context-menu {
border: none;
}

.user-col {
vertical-align: middle;
border: none;
}

@media only screen and (min-width: 1024px) {
.user-table, .card-data {
overflow: visible;
}

.user-table,
.card-data {
overflow: visible;
}
}

.user-table {
width: 92%;
width: 92%;
}

.tags-groups {
white-space: nowrap;
white-space: nowrap;
}

.desc-col {
max-width: 18rem;
max-width: 18rem;
}

.is-hoverable.user-table tr:hover .context-menu {
background-color: #fafafa;
background-color: #fafafa;
}

.action-items {
position: absolute;
right: 0;
}

#add-user {
border-bottom-width: 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,69 @@
<header>
<div class="tabs">
<ul>
<li [ngClass]="{'is-active': seletedTab == 1}">
<li [ngClass]="{'is-active': selectedTab == 1}">
<h6 class="is-6 has-text-weight-semibold">
<a (click)="showDiv(1)">User Management</a>
</h6>
</li>
<li [ngClass]="{'is-active': seletedTab == 2}">
<li [ngClass]="{'is-active': selectedTab == 2}">
<h6 class="is-6 has-text-weight-semibold">
<a (click)="showDiv(2)">Roles</a>
</h6>
</li>
<li style="position: absolute;right: 0;">
<a class="is-light" (click)="openCreateUserModal()" style="border-bottom-width: 0">
<p *ngIf="viewPort !== 'mobile'" class="add-btn">&nbsp; Add User &nbsp;</p>
<i class="bi bi-person-plus bi-sm" aria-hidden="true"></i>
</a>
<li class="action-items">
<div class="columns is-vcentered m-0 p-0">
<div *ngIf="selectedTab == 1" class="column is-narrow px-0">
<a type="button" (click)="getUsers()" class="button is-small" title="Reload" id="refresh-check">
<i class="fa fa-sm fa-sync" aria-hidden="true"></i>
</a>
</div>
<div class="column is-narrow px-0">
<a id="add-user" class="is-light pl-0" (click)="openCreateUserModal()">
<p *ngIf="viewPort !== 'mobile'" class="add-btn">&nbsp; Add User &nbsp;</p>
<i class="bi bi-person-plus bi-sm" aria-hidden="true"></i>
</a>
</div>
</div>
</li>
</ul>
</div>
</header>
<div class="card-content card-data">
<div *ngIf="seletedTab == 1" id="user-management" #management>
<div *ngIf="selectedTab == 1" id="user-management" #management>
<div class="is-responsive">
<table class="table is-hoverable user-table">
<thead id="head">
<tr>
<!-- <th>ID</th> -->
<th>Name</th>
<th></th>
<th class="px-0">Name</th>
<th>Username</th>
<th>Role</th>
<th>Authentication Method</th>
<th>Description</th>
<th>Description</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let user of userRecord; let i = index;">
<!-- <td class="user-col">{{user.userId}}</td> -->
<td class="user-col">
<td class="pr-1">
<span
[title]="'User blocked temporarily ' + user.blockUntil + ', due to multiple login attempts with invalid credentials.'">
<i *ngIf="user?.blockUntil" class="bi bi-person-lock has-text-danger" aria-hidden="true"></i>
</span>
</td>
<td class="px-0">
{{user.realName}}
</td>
<td class="user-col">
<td>
{{user.userName}}
</td>
<td class="user-col">
<td>
{{user.roleName}}
</td>
<td class="user-col">{{getAccessMethod(user.accessMethod)}}</td>
<td class="user-col desc-col desc-text">{{user.description}}</td>
<td>{{getAccessMethod(user.accessMethod)}}</td>
<td class="desc-col desc-text">{{user.description}}</td>
<td class="tags-groups">
<span *ngIf='user.userId == 1' class="tag is-rounded">super admin</span>&nbsp;
<span *ngIf='user.userId == uid' class="tag is-rounded">active</span>
Expand Down Expand Up @@ -80,8 +94,13 @@ <h6 class="is-6 has-text-weight-semibold">
<i class="bi bi-key bi-xs" aria-hidden="true"></i>
Reset Password
</a>
<a *ngIf="user?.blockUntil" class="dropdown-item"
(click)="openModal(user.userId, user.userName, 'unblockUser', 'Are you sure, You want to unblock the user')">
<i class="bi bi-unlock bi-xs" aria-hidden="true"></i>
Unblock
</a>
<a class="dropdown-item"
(click)="openModal(user.userId, user.userName, 'deactivateUser', 'Are You sure, you want to deactivate the user')">
(click)="openModal(user.userId, user.userName, 'deactivateUser', 'Are you sure, You want to deactivate the user')">
<i class="bi bi-trash bi-xs" aria-hidden="true"></i>
Deactivate
</a>
Expand All @@ -93,7 +112,7 @@ <h6 class="is-6 has-text-weight-semibold">
<a class="dropdown-item"
(click)="openModal(user.userId, user.userName, 'clearSessions', 'Are you sure, You want to clear all active sessions for')">
<i class="bi bi-box-arrow-right bi-xs" aria-hidden="true"></i>
Logout Active Sessions
Log out active sessions
</a>
</div>
</div>
Expand All @@ -104,7 +123,7 @@ <h6 class="is-6 has-text-weight-semibold">
</table>
</div>
</div>
<div *ngIf="seletedTab == 2">
<div *ngIf="selectedTab == 2">
<table class="table scroll is-responsive">
<thead>
<tr>
Expand All @@ -124,8 +143,7 @@ <h6 class="is-6 has-text-weight-semibold">
</div>
</div>
</div>
<app-alert-dialog (enabledService)='enableUser($event)' (deleteUserService)='deleteUser($event)'
(logoutAllUserSessionsService)='clearAllSessions($event)' [childData]='childData'></app-alert-dialog>
<app-alert-dialog (userActionService)="action($event)" [childData]='childData'></app-alert-dialog>
<app-create-user [userRoles]="roles" (notify)='onNotify()'></app-create-user>
<app-update-user [userRoles]="roles" (notify)='onNotify()'></app-update-user>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';

import { AlertService, AuthService, UserService, ProgressBarService, SharedService, RolesService } from '../../../services';
import { AlertDialogComponent } from '../../common/alert-dialog/alert-dialog.component';
import { CreateUserComponent } from './create-user/create-user.component';
import { UpdateUserComponent } from './update-user/update-user.component';
import { Subscription } from 'rxjs';
import { DateFormatterPipe } from '../../../pipes';
import { User } from '../../../models';
import moment from 'moment';

@Component({
selector: 'app-user-management',
Expand All @@ -22,7 +24,7 @@ export class UserManagementComponent implements OnInit, OnDestroy {
public userRecord;
public uid: string;
public roles = [];
seletedTab: Number = 1; // 1: user-management , 2 : roles
selectedTab: Number = 1; // 1: user-management , 2 : roles
private viewPortSubscription: Subscription;
viewPort: any = '';

Expand All @@ -31,6 +33,7 @@ export class UserManagementComponent implements OnInit, OnDestroy {
private userService: UserService,
public ngProgress: ProgressBarService,
private sharedService: SharedService,
private dateFormatter: DateFormatterPipe,
private roleService: RolesService
) { }

Expand Down Expand Up @@ -76,6 +79,13 @@ export class UserManagementComponent implements OnInit, OnDestroy {
});
});
this.userRecord = users.sort();
this.userRecord = this.userRecord.map((user: User) => {
if (user.blockUntil) {
user.blockUntil = this.calculateBlockUserTime(user.blockUntil);
}
return user;
})

this.ngProgress.done();
},
error => {
Expand All @@ -90,17 +100,27 @@ export class UserManagementComponent implements OnInit, OnDestroy {
}

getAccessMethod(accessMethod) {
let method;
switch (accessMethod) {
case 'cert':
return 'Certificate';
method = 'Certificate';
break;
case 'pwd':
return 'Password';
method = 'Password';
break;
default:
return 'Any';
method = 'Any';
break;
}
return method;
}

calculateBlockUserTime(time: string): string {
const blockUntilTime = this.dateFormatter.transform(time, 'YYYY-MM-DD HH:mm:ss');
const blockUntilTimestamp = moment(blockUntilTime);
let timeDifference = blockUntilTimestamp.fromNow();
timeDifference = timeDifference.toString().replace('in', 'for')
return timeDifference;
}

/**
Expand Down Expand Up @@ -142,6 +162,18 @@ export class UserManagementComponent implements OnInit, OnDestroy {
this.updateUserModal.toggleModal(true);
}

action(userData: any) {
if (userData.key == 'deactivateUser') {
this.deleteUser(userData.id);
} else if (userData.key == 'enableUser') {
this.enableUser(userData.id);
} else if (userData.key == 'clearSessions') {
this.clearAllSessions(userData.key);
} else if (userData.key == 'unblockUser') {
this.unblockUser(userData.id);
}
}

deleteUser(userId) {
console.log('Deleting User:', userId);
/** request started */
Expand Down Expand Up @@ -192,6 +224,28 @@ export class UserManagementComponent implements OnInit, OnDestroy {
// });
}

unblockUser(userId: string) {
/** request started */
this.ngProgress.start();
this.userService.unblockUser(userId).
subscribe(
(data) => {
/** request completed */
this.ngProgress.done();
this.alertService.success(data['message']);
this.getUsers();
},
error => {
/** request completed */
this.ngProgress.done();
if (error.status === 0) {
console.log('service down ', error);
} else {
this.alertService.error(error.statusText);
}
});
}

public toggleDropdown(contextMenu) {
const id = 'dropdown-' + contextMenu;
const activeDropDowns = Array.prototype.slice.call(document.querySelectorAll('.dropdown.is-active'));
Expand Down Expand Up @@ -226,9 +280,9 @@ export class UserManagementComponent implements OnInit, OnDestroy {
}

showDiv(id) {
this.seletedTab = 1;
this.selectedTab = 1;
if (id === 2) {
this.seletedTab = id;
this.selectedTab = id;
}
}

Expand Down
Loading

0 comments on commit 255d371

Please sign in to comment.