Skip to content

Commit ca8fdd0

Browse files
Merge pull request #202 from OS2iot/feature/IOT-46-Time-limited-access
IOT-46: Time limited access
2 parents a786104 + a07990a commit ca8fdd0

File tree

13 files changed

+251
-152
lines changed

13 files changed

+251
-152
lines changed

src/app/admin/api-key/api-key-edit/api-key-edit.component.html

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,18 @@
1414
<label class="form-label" for="name">{{ "API-KEY.EDIT.NAME" | translate }}</label
1515
>*
1616
<input
17-
type="text"
18-
class="form-control"
19-
id="name"
20-
name="name"
21-
[placeholder]="'API-KEY.EDIT.NAME-PLACEHOLDER' | translate"
22-
maxlength="50"
23-
required
2417
[(ngModel)]="apiKeyRequest.name"
2518
[ngClass]="{
2619
'is-invalid': formFailedSubmit && errorFields.includes('name'),
2720
'is-valid': formFailedSubmit && !errorFields.includes('name')
2821
}"
22+
[placeholder]="'API-KEY.EDIT.NAME-PLACEHOLDER' | translate"
23+
class="form-control"
24+
id="name"
25+
maxlength="50"
26+
name="name"
27+
required
28+
type="text"
2929
/>
3030
</div>
3131
</div>
@@ -35,11 +35,11 @@
3535
<label class="form-label" for="permissions">{{ "QUESTION.PERMISSION.SELECT-PERMISSION" | translate }}</label
3636
>*
3737
<mat-select
38-
class="form-control"
39-
name="permissions"
40-
[compareWith]="compare"
4138
[(ngModel)]="apiKeyRequest.permissionIds"
39+
[compareWith]="compare"
4240
[multiple]="true"
41+
class="form-control"
42+
name="permissions"
4343
>
4444
<mat-option *ngFor="let permission of permissions" [value]="permission.id">
4545
{{ permission.name }}
@@ -48,6 +48,21 @@
4848
</div>
4949
</div>
5050

51+
<div class="row form-group mt-3">
52+
<label class="form-label">{{ "API-KEY.EDIT.EXPIRATION-DATE" | translate }}</label>
53+
<mat-form-field appearance="outline">
54+
<mat-label>{{ "API-KEY.EDIT.EXPIRATION-DATE-PLACEHOLDER" | translate }}</mat-label>
55+
<input
56+
[formControl]="serializedExpirationDate"
57+
[matDatepicker]="expirationDatePicker"
58+
matInput
59+
/>
60+
<mat-datepicker-toggle [for]="expirationDatePicker" matSuffix></mat-datepicker-toggle>
61+
<mat-datepicker #expirationDatePicker panelClass="datepicker-table-fix"></mat-datepicker>
62+
<mat-hint>{{ "API-KEY.EDIT.EXPIRATION-DATE-DESCRIPTION" | translate }}</mat-hint>
63+
</mat-form-field>
64+
</div>
65+
5166
<div class="form-group mt-5">
5267
<button (click)="routeBack()" class="btn btn-secondary" type="button">
5368
{{ "GEN.CANCEL" | translate }}

src/app/admin/api-key/api-key-edit/api-key-edit.component.ts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { BackButton } from "@shared/models/back-button.model";
1010
import { SharedVariableService } from "@shared/shared-variable/shared-variable.service";
1111
import { ApiKeyRequest } from "../api-key.model";
1212
import { ApiKeyService } from "../api-key.service";
13+
import { FormControl } from "@angular/forms";
1314

1415
@Component({
1516
selector: "app-api-key-edit",
@@ -29,6 +30,8 @@ export class ApiKeyEditComponent implements OnInit {
2930
public errorFields: string[];
3031
public formFailedSubmit = false;
3132
public permissions: PermissionResponse[] = [];
33+
34+
serializedExpirationDate = new FormControl<Date | undefined>(undefined);
3235
private organizationId: number;
3336
private id: number;
3437

@@ -59,6 +62,24 @@ export class ApiKeyEditComponent implements OnInit {
5962
this.organizationId = this.sharedVariableService.getSelectedOrganisationId();
6063
}
6164

65+
onSubmit(): void {
66+
this.id ? this.update() : this.create();
67+
}
68+
69+
public compare(matOptionValue: number, ngModelObject: number): boolean {
70+
return matOptionValue === ngModelObject;
71+
}
72+
73+
showError(err: HttpErrorResponse) {
74+
const result = this.errorMessageService.handleErrorMessageWithFields(err);
75+
this.errorFields = result.errorFields;
76+
this.errorMessages = result.errorMessages;
77+
}
78+
79+
routeBack(): void {
80+
this.location.back();
81+
}
82+
6283
private getPermissions() {
6384
this.permissionService
6485
.getPermissions(undefined, undefined, undefined, undefined, undefined, this.organizationId)
@@ -77,38 +98,25 @@ export class ApiKeyEditComponent implements OnInit {
7798
this.apiKeyRequest.id = key.id;
7899
this.apiKeyRequest.name = key.name;
79100
this.apiKeyRequest.permissionIds = key.permissions.map(pm => pm.id);
101+
if (key.expiresOn) {
102+
this.serializedExpirationDate.setValue(key.expiresOn);
103+
}
80104
});
81105
}
82106

83-
onSubmit(): void {
84-
this.id ? this.update() : this.create();
85-
}
86-
87107
private create(): void {
108+
this.apiKeyRequest.expiresOn = this.serializedExpirationDate.value;
88109
this.apiKeyService.create(this.apiKeyRequest).subscribe(
89110
() => this.routeBack(),
90111
err => this.showError(err)
91112
);
92113
}
93114

94115
private update(): void {
116+
this.apiKeyRequest.expiresOn = this.serializedExpirationDate.value;
95117
this.apiKeyService.update(this.apiKeyRequest, this.id).subscribe(
96118
() => this.routeBack(),
97119
err => this.showError(err)
98120
);
99121
}
100-
101-
public compare(matOptionValue: number, ngModelObject: number): boolean {
102-
return matOptionValue === ngModelObject;
103-
}
104-
105-
showError(err: HttpErrorResponse) {
106-
const result = this.errorMessageService.handleErrorMessageWithFields(err);
107-
this.errorFields = result.errorFields;
108-
this.errorMessages = result.errorMessages;
109-
}
110-
111-
routeBack(): void {
112-
this.location.back();
113-
}
114122
}

src/app/admin/api-key/api-key-list/api-key-table/api-key-table.component.html

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
<div class="mat-elevation-z8">
2-
<div class="loading-shade" *ngIf="isLoadingResults">
2+
<div *ngIf="isLoadingResults" class="loading-shade">
33
<mat-spinner *ngIf="isLoadingResults"></mat-spinner>
44
</div>
5-
<table mat-table [dataSource]="data" matSort matSortActive="name" matSortDirection="asc" matSortDisableClear>
5+
<table [dataSource]="data" mat-table matSort matSortActive="name" matSortDirection="asc" matSortDisableClear>
66
<!-- Name Column -->
77
<ng-container matColumnDef="name">
8-
<th mat-header-cell *matHeaderCellDef mat-sort-header>
8+
<th *matHeaderCellDef mat-header-cell mat-sort-header>
99
{{ "API-KEY.NAME" | translate }}
1010
</th>
11-
<td mat-cell *matCellDef="let element">
11+
<td *matCellDef="let element" mat-cell>
1212
{{ element.name }}
1313
</td>
1414
</ng-container>
1515

1616
<!-- User Groups Column -->
1717
<ng-container matColumnDef="permissions">
18-
<th mat-header-cell *matHeaderCellDef>
18+
<th *matHeaderCellDef mat-header-cell>
1919
{{ "API-KEY.PERMISSIONS" | translate }}
2020
</th>
21-
<td mat-cell *matCellDef="let element">
21+
<td *matCellDef="let element" mat-cell>
2222
<ng-container *ngIf="element.permissions; else noUsers">
2323
<ng-container *ngFor="let pm of element.permissions">
2424
<span>{{ pm.name }}</span>
25-
<br />
25+
<br/>
2626
</ng-container>
2727
</ng-container>
2828
<ng-template #noUsers>{{ "NoUsersAdded" | translate }}</ng-template>
@@ -31,32 +31,53 @@
3131

3232
<!-- Key Column -->
3333
<ng-container matColumnDef="key">
34-
<th mat-header-cell *matHeaderCellDef>
34+
<th *matHeaderCellDef mat-header-cell>
3535
{{ "API-KEY.KEY" | translate }}
3636
</th>
37-
<td mat-cell *matCellDef="let element">
37+
<td *matCellDef="let element" mat-cell>
3838
{{ element.key }}
3939
</td>
4040
</ng-container>
4141

42+
<!-- Expiration Column -->
43+
<ng-container matColumnDef="expiresOn">
44+
<th *matHeaderCellDef mat-header-cell mat-sort-header>
45+
{{ "API-KEY.EXPIRES-ON" | translate }}
46+
</th>
47+
<td *matCellDef="let element" mat-cell>
48+
{{ (element.expiresOn | dateOnly) ?? '-' }}
49+
</td>
50+
</ng-container>
51+
52+
<!-- Status Column -->
53+
<ng-container matColumnDef="status">
54+
<th *matHeaderCellDef mat-header-cell>
55+
{{ "API-KEY.STATUS" | translate }}
56+
</th>
57+
<td *matCellDef="let element" mat-cell>
58+
<p [ngClass]="!isKeyExpired(element) | activeDeactive">{{ !isKeyExpired(element) | activeDeactive }}</p>
59+
</td>
60+
</ng-container>
61+
62+
4263
<!-- Menu Column -->
4364
<ng-container matColumnDef="menu">
44-
<th mat-header-cell *matHeaderCellDef></th>
45-
<td mat-cell *matCellDef="let element">
65+
<th *matHeaderCellDef mat-header-cell></th>
66+
<td *matCellDef="let element" mat-cell>
4667
<div *ngIf="canAccess(element)" class="dropdown">
4768
<a
48-
href="#"
49-
role="button"
50-
id="tableRowDropdown-{{ element.id }}"
69+
[attr.aria-label]="'APPLICATION-TABLE-ROW.SHOW-OPTIONS' | translate"
70+
aria-expanded="false"
5171
class="applicationRow__edit dropdown-toggle"
5272
data-toggle="dropdown"
53-
aria-expanded="false"
54-
[attr.aria-label]="'APPLICATION-TABLE-ROW.SHOW-OPTIONS' | translate"
73+
href="#"
74+
id="tableRowDropdown-{{ element.id }}"
75+
role="button"
5576
></a>
56-
<ul class="dropdown-menu dropdown-menu--table" attr.aria-labelledby="tableRowDropdown-{{ element.id }}">
77+
<ul attr.aria-labelledby="tableRowDropdown-{{ element.id }}" class="dropdown-menu dropdown-menu--table">
5778
<li class="dropdown-item">
5879
<a [routerLink]="[element.id, 'edit-api-key']" routerLinkActive="active"
59-
>{{ "ORGANISATION-TABLE-ROW.EDIT" | translate }}
80+
>{{ "ORGANISATION-TABLE-ROW.EDIT" | translate }}
6081
</a>
6182
</li>
6283
<li class="dropdown-item">
@@ -67,13 +88,13 @@
6788
</td>
6889
</ng-container>
6990

70-
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
71-
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
91+
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
92+
<tr *matRowDef="let row; columns: displayedColumns" mat-row></tr>
7293
</table>
7394
<mat-paginator
95+
[length]="resultsLength"
7496
[pageSizeOptions]="pageSizeOptions"
7597
[pageSize]="pageSize"
76-
[length]="resultsLength"
7798
showFirstLastButtons
7899
>
79100
</mat-paginator>

src/app/admin/api-key/api-key-list/api-key-table/api-key-table.component.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ import { DefaultPageSizeOptions } from "@shared/constants/page.constants";
1919
})
2020
export class ApiKeyTableComponent implements AfterViewInit {
2121
@Input() organisationId: number;
22-
displayedColumns: string[] = ["name", "permissions", "key", "menu"];
22+
displayedColumns: string[] = ["name", "permissions", "key", "expiresOn", "status", "menu"];
2323
data: ApiKeyResponse[] = [];
2424
isLoadingResults = true;
2525
@ViewChild(MatPaginator) paginator: MatPaginator;
2626
@ViewChild(MatSort) sort: MatSort;
2727
resultsLength = 0;
2828
public pageSize = environment.tablePageSize;
2929
pageSizeOptions = DefaultPageSizeOptions;
30+
now = new Date();
3031

3132
constructor(
3233
private meService: MeService,
@@ -95,6 +96,10 @@ export class ApiKeyTableComponent implements AfterViewInit {
9596
});
9697
}
9798

99+
isKeyExpired(element: ApiKeyResponse) {
100+
return element.expiresOn != null && new Date(element.expiresOn) < new Date();
101+
}
102+
98103
private refresh() {
99104
const pageEvent = new PageEvent();
100105
pageEvent.pageIndex = this.paginator.pageIndex;

src/app/admin/api-key/api-key.model.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export class ApiKeyRequest {
44
id: number;
55
name: string;
66
permissionIds?: number[];
7+
expiresOn?: Date;
78
}
89

910
export interface ApiKeyResponse {
@@ -15,6 +16,7 @@ export interface ApiKeyResponse {
1516
updatedBy: number;
1617
createdByName: string;
1718
updatedByName: string;
19+
expiresOn?: Date;
1820
}
1921

2022
export interface ApiKeyGetManyResponse {

src/app/admin/users/user-detail/user-detail.component.html

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<div *ngIf="user">
22
<app-top-bar
3-
[data]="user"
4-
[backButton]="backButton"
5-
[subPage]="true"
63
[addDetailDowndown]="true"
7-
[dropDownButton]="dropdownButton"
4+
[backButton]="backButton"
85
[canEdit]="canEdit"
6+
[data]="user"
7+
[dropDownButton]="dropdownButton"
8+
[subPage]="true"
99
></app-top-bar>
1010
<div class="container-fluid">
1111
<div class="row">
@@ -21,6 +21,10 @@ <h3>{{ "USERS.DETAIL.HEADLINE" | translate }}</h3>
2121
<strong>{{ "USERS.DETAIL.STATUS" | translate }}</strong
2222
>{{ user.active | activeDeactive }}
2323
</p>
24+
<p *ngIf="user.expiresOn">
25+
<strong>{{ "API-KEY.EXPIRES-ON" | translate }}</strong>
26+
{{ (user.expiresOn) | dateOnly }}
27+
</p>
2428
<P *ngIf="user.lastLogin; else noLogin">
2529
<strong>{{ "USERS.DETAIL.LAST-LOGIN" | translate }}</strong
2630
>{{ user?.lastLogin | dkTime }}</P
@@ -46,7 +50,7 @@ <h3>{{ "USERS.DETAIL.HEADLINE" | translate }}</h3>
4650
<h3 class="">
4751
{{ "USERS.DETAIL.PERMISSIONS" | translate }}
4852
</h3>
49-
<app-permission-tabel [userId]="user?.id"> </app-permission-tabel>
53+
<app-permission-tabel [userId]="user?.id"></app-permission-tabel>
5054
</div>
5155
</div>
5256
</div>

0 commit comments

Comments
 (0)