Skip to content

IOT-46: Time limited access #202

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: stage
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions src/app/admin/api-key/api-key-edit/api-key-edit.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@
<label class="form-label" for="name">{{ "API-KEY.EDIT.NAME" | translate }}</label
>*
<input
type="text"
class="form-control"
id="name"
name="name"
[placeholder]="'API-KEY.EDIT.NAME-PLACEHOLDER' | translate"
maxlength="50"
required
[(ngModel)]="apiKeyRequest.name"
[ngClass]="{
'is-invalid': formFailedSubmit && errorFields.includes('name'),
'is-valid': formFailedSubmit && !errorFields.includes('name')
}"
[placeholder]="'API-KEY.EDIT.NAME-PLACEHOLDER' | translate"
class="form-control"
id="name"
maxlength="50"
name="name"
required
type="text"
/>
</div>
</div>
Expand All @@ -35,11 +35,11 @@
<label class="form-label" for="permissions">{{ "QUESTION.PERMISSION.SELECT-PERMISSION" | translate }}</label
>*
<mat-select
class="form-control"
name="permissions"
[compareWith]="compare"
[(ngModel)]="apiKeyRequest.permissionIds"
[compareWith]="compare"
[multiple]="true"
class="form-control"
name="permissions"
>
<mat-option *ngFor="let permission of permissions" [value]="permission.id">
{{ permission.name }}
Expand All @@ -48,6 +48,21 @@
</div>
</div>

<div class="row form-group mt-3">
<label class="form-label">{{ "API-KEY.EDIT.EXPIRATION-DATE" | translate }}</label>
<mat-form-field appearance="outline">
<mat-label>{{ "API-KEY.EDIT.EXPIRATION-DATE-PLACEHOLDER" | translate }}</mat-label>
<input
[formControl]="serializedExpirationDate"
[matDatepicker]="expirationDatePicker"
matInput
/>
<mat-datepicker-toggle [for]="expirationDatePicker" matSuffix></mat-datepicker-toggle>
<mat-datepicker #expirationDatePicker panelClass="datepicker-table-fix"></mat-datepicker>
<mat-hint>{{ "API-KEY.EDIT.EXPIRATION-DATE-DESCRIPTION" | translate }}</mat-hint>
</mat-form-field>
</div>

<div class="form-group mt-5">
<button (click)="routeBack()" class="btn btn-secondary" type="button">
{{ "GEN.CANCEL" | translate }}
Expand Down
44 changes: 26 additions & 18 deletions src/app/admin/api-key/api-key-edit/api-key-edit.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { BackButton } from "@shared/models/back-button.model";
import { SharedVariableService } from "@shared/shared-variable/shared-variable.service";
import { ApiKeyRequest } from "../api-key.model";
import { ApiKeyService } from "../api-key.service";
import { FormControl } from "@angular/forms";

@Component({
selector: "app-api-key-edit",
Expand All @@ -29,6 +30,8 @@ export class ApiKeyEditComponent implements OnInit {
public errorFields: string[];
public formFailedSubmit = false;
public permissions: PermissionResponse[] = [];

serializedExpirationDate = new FormControl<Date | undefined>(undefined);
private organizationId: number;
private id: number;

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

onSubmit(): void {
this.id ? this.update() : this.create();
}

public compare(matOptionValue: number, ngModelObject: number): boolean {
return matOptionValue === ngModelObject;
}

showError(err: HttpErrorResponse) {
const result = this.errorMessageService.handleErrorMessageWithFields(err);
this.errorFields = result.errorFields;
this.errorMessages = result.errorMessages;
}

routeBack(): void {
this.location.back();
}

private getPermissions() {
this.permissionService
.getPermissions(undefined, undefined, undefined, undefined, undefined, this.organizationId)
Expand All @@ -77,38 +98,25 @@ export class ApiKeyEditComponent implements OnInit {
this.apiKeyRequest.id = key.id;
this.apiKeyRequest.name = key.name;
this.apiKeyRequest.permissionIds = key.permissions.map(pm => pm.id);
if (key.expiresOn) {
this.serializedExpirationDate.setValue(key.expiresOn);
}
});
}

onSubmit(): void {
this.id ? this.update() : this.create();
}

private create(): void {
this.apiKeyRequest.expiresOn = this.serializedExpirationDate.value;
this.apiKeyService.create(this.apiKeyRequest).subscribe(
() => this.routeBack(),
err => this.showError(err)
);
}

private update(): void {
this.apiKeyRequest.expiresOn = this.serializedExpirationDate.value;
this.apiKeyService.update(this.apiKeyRequest, this.id).subscribe(
() => this.routeBack(),
err => this.showError(err)
);
}

public compare(matOptionValue: number, ngModelObject: number): boolean {
return matOptionValue === ngModelObject;
}

showError(err: HttpErrorResponse) {
const result = this.errorMessageService.handleErrorMessageWithFields(err);
this.errorFields = result.errorFields;
this.errorMessages = result.errorMessages;
}

routeBack(): void {
this.location.back();
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
<div class="mat-elevation-z8">
<div class="loading-shade" *ngIf="isLoadingResults">
<div *ngIf="isLoadingResults" class="loading-shade">
<mat-spinner *ngIf="isLoadingResults"></mat-spinner>
</div>
<table mat-table [dataSource]="data" matSort matSortActive="name" matSortDirection="asc" matSortDisableClear>
<table [dataSource]="data" mat-table matSort matSortActive="name" matSortDirection="asc" matSortDisableClear>
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header>
<th *matHeaderCellDef mat-header-cell mat-sort-header>
{{ "API-KEY.NAME" | translate }}
</th>
<td mat-cell *matCellDef="let element">
<td *matCellDef="let element" mat-cell>
{{ element.name }}
</td>
</ng-container>

<!-- User Groups Column -->
<ng-container matColumnDef="permissions">
<th mat-header-cell *matHeaderCellDef>
<th *matHeaderCellDef mat-header-cell>
{{ "API-KEY.PERMISSIONS" | translate }}
</th>
<td mat-cell *matCellDef="let element">
<td *matCellDef="let element" mat-cell>
<ng-container *ngIf="element.permissions; else noUsers">
<ng-container *ngFor="let pm of element.permissions">
<span>{{ pm.name }}</span>
<br />
<br/>
</ng-container>
</ng-container>
<ng-template #noUsers>{{ "NoUsersAdded" | translate }}</ng-template>
Expand All @@ -31,32 +31,53 @@

<!-- Key Column -->
<ng-container matColumnDef="key">
<th mat-header-cell *matHeaderCellDef>
<th *matHeaderCellDef mat-header-cell>
{{ "API-KEY.KEY" | translate }}
</th>
<td mat-cell *matCellDef="let element">
<td *matCellDef="let element" mat-cell>
{{ element.key }}
</td>
</ng-container>

<!-- Expiration Column -->
<ng-container matColumnDef="expiresOn">
<th *matHeaderCellDef mat-header-cell mat-sort-header>
{{ "API-KEY.EXPIRES-ON" | translate }}
</th>
<td *matCellDef="let element" mat-cell>
{{ (element.expiresOn | dateOnly) ?? '-' }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it be done so it doesnt always translate to english? If it's not easy then it might not matter

</td>
</ng-container>

<!-- Status Column -->
<ng-container matColumnDef="status">
<th *matHeaderCellDef mat-header-cell>
{{ "API-KEY.STATUS" | translate }}
</th>
<td *matCellDef="let element" mat-cell>
<p [ngClass]="!isKeyExpired(element) | activeDeactive">{{ !isKeyExpired(element) | activeDeactive }}</p>
</td>
</ng-container>


<!-- Menu Column -->
<ng-container matColumnDef="menu">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let element">
<th *matHeaderCellDef mat-header-cell></th>
<td *matCellDef="let element" mat-cell>
<div *ngIf="canAccess(element)" class="dropdown">
<a
href="#"
role="button"
id="tableRowDropdown-{{ element.id }}"
[attr.aria-label]="'APPLICATION-TABLE-ROW.SHOW-OPTIONS' | translate"
aria-expanded="false"
class="applicationRow__edit dropdown-toggle"
data-toggle="dropdown"
aria-expanded="false"
[attr.aria-label]="'APPLICATION-TABLE-ROW.SHOW-OPTIONS' | translate"
href="#"
id="tableRowDropdown-{{ element.id }}"
role="button"
></a>
<ul class="dropdown-menu dropdown-menu--table" attr.aria-labelledby="tableRowDropdown-{{ element.id }}">
<ul attr.aria-labelledby="tableRowDropdown-{{ element.id }}" class="dropdown-menu dropdown-menu--table">
<li class="dropdown-item">
<a [routerLink]="[element.id, 'edit-api-key']" routerLinkActive="active"
>{{ "ORGANISATION-TABLE-ROW.EDIT" | translate }}
>{{ "ORGANISATION-TABLE-ROW.EDIT" | translate }}
</a>
</li>
<li class="dropdown-item">
Expand All @@ -67,13 +88,13 @@
</td>
</ng-container>

<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
<tr *matRowDef="let row; columns: displayedColumns" mat-row></tr>
</table>
<mat-paginator
[length]="resultsLength"
[pageSizeOptions]="pageSizeOptions"
[pageSize]="pageSize"
[length]="resultsLength"
showFirstLastButtons
>
</mat-paginator>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ import { DefaultPageSizeOptions } from "@shared/constants/page.constants";
})
export class ApiKeyTableComponent implements AfterViewInit {
@Input() organisationId: number;
displayedColumns: string[] = ["name", "permissions", "key", "menu"];
displayedColumns: string[] = ["name", "permissions", "key", "expiresOn", "status", "menu"];
data: ApiKeyResponse[] = [];
isLoadingResults = true;
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
resultsLength = 0;
public pageSize = environment.tablePageSize;
pageSizeOptions = DefaultPageSizeOptions;
now = new Date();

constructor(
private meService: MeService,
Expand Down Expand Up @@ -95,6 +96,10 @@ export class ApiKeyTableComponent implements AfterViewInit {
});
}

isKeyExpired(element: ApiKeyResponse) {
return element.expiresOn != null && new Date(element.expiresOn) < new Date();
}

private refresh() {
const pageEvent = new PageEvent();
pageEvent.pageIndex = this.paginator.pageIndex;
Expand Down
2 changes: 2 additions & 0 deletions src/app/admin/api-key/api-key.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export class ApiKeyRequest {
id: number;
name: string;
permissionIds?: number[];
expiresOn?: Date;
}

export interface ApiKeyResponse {
Expand All @@ -15,6 +16,7 @@ export interface ApiKeyResponse {
updatedBy: number;
createdByName: string;
updatedByName: string;
expiresOn?: Date;
}

export interface ApiKeyGetManyResponse {
Expand Down
14 changes: 9 additions & 5 deletions src/app/admin/users/user-detail/user-detail.component.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<div *ngIf="user">
<app-top-bar
[data]="user"
[backButton]="backButton"
[subPage]="true"
[addDetailDowndown]="true"
[dropDownButton]="dropdownButton"
[backButton]="backButton"
[canEdit]="canEdit"
[data]="user"
[dropDownButton]="dropdownButton"
[subPage]="true"
></app-top-bar>
<div class="container-fluid">
<div class="row">
Expand All @@ -21,6 +21,10 @@ <h3>{{ "USERS.DETAIL.HEADLINE" | translate }}</h3>
<strong>{{ "USERS.DETAIL.STATUS" | translate }}</strong
>{{ user.active | activeDeactive }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we miss a check here? If the user is expired this should show deactivate, shouldn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Users are disabled by a service in the backend. So their expiration date is not validated expicitly in the frontend

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense :)

</p>
<p *ngIf="user.expiresOn">
<strong>{{ "API-KEY.EXPIRES-ON" | translate }}</strong>
{{ (user.expiresOn) | dateOnly }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it be done so it doesnt always translate to english? If it's not easy then it might not matter

</p>
<P *ngIf="user.lastLogin; else noLogin">
<strong>{{ "USERS.DETAIL.LAST-LOGIN" | translate }}</strong
>{{ user?.lastLogin | dkTime }}</P
Expand All @@ -46,7 +50,7 @@ <h3>{{ "USERS.DETAIL.HEADLINE" | translate }}</h3>
<h3 class="">
{{ "USERS.DETAIL.PERMISSIONS" | translate }}
</h3>
<app-permission-tabel [userId]="user?.id"> </app-permission-tabel>
<app-permission-tabel [userId]="user?.id"></app-permission-tabel>
</div>
</div>
</div>
Expand Down
Loading