Skip to content

Commit

Permalink
AdminUI: Display of the Identity deletion audit log for deleted ident…
Browse files Browse the repository at this point in the history
…ities (#684)

* feat: add components template

* feat: add template for endpoint

* feat: add query to retrieve audit logs of identity

* test: add unit tests for new audti log query

* feat: add endpoint for identity deletion process audit logs

* test: update sdk and integration tests

* test: refactor and add test for multiple deletion processes

* feat: add deletion process audit logs for an identity page

* chore: run prettier

* fix: change the type

* chore: make the table present correct data

* fix: audit logs of deleted identities should be returned

* fix: should not check for identity existence since behavior should work for deleted identities

* refactor: remove unnecessary produces error attribute

* chore: add deletion process cancellation to admin api sdk

* refactor: hash identity outside repository

* test: create test data generator method to create cancelled deletion process

* test: add deletion processes in different statuses to test

* refactor: order audit log entries by created at

* fix: the header title and remove expansion panel

* fix: formatting

* fix: minimize the top margin

* fix: remove uneccasary sorting

* test: refactor unit tests to use fake dbcontext

* test: simplify Handler tests

* refactor: change order of CreateDbContexts return values

* refactor: extract common code into private method

* refactor: add IEventBus parameter to DevicesDbContext

---------

Co-authored-by: Daniel Almeida <[email protected]>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: Timo Notheisen <[email protected]>
  • Loading branch information
4 people authored Jun 7, 2024
1 parent 4bf6548 commit 28a36ac
Show file tree
Hide file tree
Showing 36 changed files with 857 additions and 31 deletions.
10 changes: 10 additions & 0 deletions AdminApi.Sdk/Endpoints/Identities/IdentitiesEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ public async Task<ApiResponse<ListIdentitiesResponse>> ListIdentities()
.ExecuteOData();
}

public async Task<ApiResponse<ListIdentityDeletionProcessAuditLogsResponse>?> ListIdentityDeletionProcessAuditLogs(string address)
{
return await _client.Get<ListIdentityDeletionProcessAuditLogsResponse>($"api/{API_VERSION}/Identities/{address}/DeletionProcesses/AuditLogs");
}

public async Task<ApiResponse<GetIdentityResponse>> GetIdentity(string address)
{
return await _client.Get<GetIdentityResponse>($"api/{API_VERSION}/Identities/{address}");
Expand All @@ -44,4 +49,9 @@ public async Task<ApiResponse<StartDeletionProcessAsSupportResponse>> StartDelet
{
return await _client.Post<StartDeletionProcessAsSupportResponse>($"api/{API_VERSION}/Identities/{address}/DeletionProcesses");
}

public async Task<ApiResponse<CancelDeletionAsSupportResponse>> CancelDeletionProcess(string address, string deletionProcessId)
{
return await _client.Put<CancelDeletionAsSupportResponse>($"api/{API_VERSION}/Identities/{address}/DeletionProcesses/{deletionProcessId}/Cancel");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Backbone.AdminApi.Sdk.Endpoints.Identities.Types;

public class IdentityDeletionProcessAuditLogEntryDTO
{
public required string Id { get; set; }
public required DateTime CreatedAt { get; set; }
public required string MessageKey { get; set; }
public required string? OldStatus { get; set; }
public required string NewStatus { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Backbone.AdminApi.Sdk.Endpoints.Identities.Types.Responses;

public class CancelDeletionAsSupportResponse
{
public required string Id { get; set; }
public required string Status { get; set; }
public required DateTime CancelledAt { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using Backbone.BuildingBlocks.SDK.Endpoints.Common.Types;

namespace Backbone.AdminApi.Sdk.Endpoints.Identities.Types.Responses;

public class ListIdentityDeletionProcessAuditLogsResponse : EnumerableResponseBase<IdentityDeletionProcessAuditLogEntryDTO>;
2 changes: 2 additions & 0 deletions AdminApi/src/AdminApi/ClientApp/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ import { TierListComponent } from "./components/quotas/tier/tier-list/tier-list.
import { LoginComponent } from "./components/shared/login/login.component";
import { AuthGuard } from "./shared/auth-guard/auth-guard.guard";
import { CustomRouteReuseStrategy } from "./utils/custom-route-reuse-strategy";
import { DeletionProcessAuditLogsDetailsComponent } from "./components/identity/identity-details/deletion-processes/dp-audit-logs/dp-audit-logs-details/dp-audit-logs-details/dp-audit-logs-details.component";

const routes: Routes = [
{ path: "", redirectTo: "/dashboard", pathMatch: "full" },
{ path: "login", component: LoginComponent },
{ path: "dashboard", component: DashboardComponent, data: { breadcrumb: "Dashboard" }, canActivate: [AuthGuard] },
{ path: "identities", component: IdentityListComponent, data: { breadcrumb: "Identities" }, canActivate: [AuthGuard] },
{ path: "identities/:address", component: IdentityDetailsComponent, canActivate: [AuthGuard] },
{ path: "identities/:address/deletion-processes/audit-logs", component: DeletionProcessAuditLogsDetailsComponent, canActivate: [AuthGuard] },
{ path: "tiers", component: TierListComponent, data: { breadcrumb: "Tiers" }, canActivate: [AuthGuard] },
{ path: "tiers/create", component: TierEditComponent, data: { breadcrumb: "Create Tier" }, canActivate: [AuthGuard] },
{ path: "tiers/:id", component: TierEditComponent, canActivate: [AuthGuard] },
Expand Down
6 changes: 5 additions & 1 deletion AdminApi/src/AdminApi/ClientApp/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import { CreateClientDialogComponent } from "./components/client/create-client-d
import { DashboardComponent } from "./components/dashboard/dashboard.component";
import { PageNotFoundComponent } from "./components/error/page-not-found/page-not-found.component";
import { DeletionProcessesComponent } from "./components/identity/identity-details/deletion-processes/deletion-processes.component";
import { DeletionProcessAuditLogsDetailsComponent } from "./components/identity/identity-details/deletion-processes/dp-audit-logs/dp-audit-logs-details/dp-audit-logs-details/dp-audit-logs-details.component";
import { DeletionProcessAuditLogsComponent } from "./components/identity/identity-details/deletion-processes/dp-audit-logs/dp-audit-logs.component";
import { CancelDeletionProcessDialogComponent } from "./components/identity/identity-details/deletion-processes/dp-details/cancel-dp-dialog/cancel-dp-dialog.component";
import { DeletionProcessDetailsComponent } from "./components/identity/identity-details/deletion-processes/dp-details/dp-details.component";
import { StartDeletionProcessDialogComponent } from "./components/identity/identity-details/deletion-processes/start-deletion-process-dialog/start-deletion-process-dialog.component";
Expand Down Expand Up @@ -99,7 +101,9 @@ import { XSRFInterceptor } from "./shared/interceptors/xsrf.interceptor";
DeletionProcessesComponent,
DeletionProcessDetailsComponent,
CancelDeletionProcessDialogComponent,
StartDeletionProcessDialogComponent
StartDeletionProcessDialogComponent,
DeletionProcessAuditLogsComponent,
DeletionProcessAuditLogsDetailsComponent
],
imports: [
FormsModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
.container {
display: flex;
justify-content: space-between;
}

.column {
flex: 1;
}

.action-buttons {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}

.header-description {
color: #fff;
}

.action-buttons button {
margin: 10px;
}

.form-card {
margin-bottom: 20px;
}

.loading {
text-align: center;
}

.form-details {
padding: 20px;
}

.mat-list-item {
display: flex;
justify-content: space-between;
}

.form-card {
margin-top: 30px;
min-height: 150px;
}

.loading {
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
position: absolute;
margin-top: -60px;
width: 100%;
height: 100%;
}

.card-header {
border-radius: 3px;
padding: 15px;
background-color: #17428d;
position: relative;
z-index: 1;
margin: 15px 15px -50px 15px;
}

.header-title {
color: #fff;
}

.identity-accordion {
margin: 0px 0px 0px 5px !important;
}

.details-expansion-panel-header {
background: #17428d !important;
}

.details-expansion-panel-header:hover {
background: #11337a !important;
}

.details-expansion-panel-header.mat-expansion-panel-header.mat-expanded {
border-radius: 4px 4px 0px 0px;
}

.details-panel-header-title {
color: white !important;
}

.details-panel-header-desc {
color: rgba(255, 255, 255, 0.54) !important;
}

:host ::ng-deep .details-expansion-panel-header > .mat-expansion-indicator::after {
color: white !important;
}

@media screen and (max-width: 960px) {
.mat-mdc-table .mat-mdc-header-row {
display: none;
}

.mat-mdc-table .mat-mdc-row {
display: flex;
flex-wrap: wrap;
height: auto;
border-bottom: 1px solid #ddd;
}

.mat-mdc-table .mat-mdc-cell {
width: 100%;
border-bottom: 0px solid #ddd;
font-size: 1em;
min-height: 30px;
margin-bottom: 4%;
word-break: break-all;
white-space: pre-wrap;
}

.mat-mdc-table .mat-mdc-cell:before {
content: attr(data-label);
float: left;
font-weight: 500;
}

.mat-mdc-table .mat-mdc-cell:first-child {
margin-top: 25px;
}

.mat-mdc-table .mat-mdc-row:last-child {
border-bottom: 0px;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<div class="card-header">
<h2 class="header-title">{{ headerDeletionProcessAuditLog }}</h2>
<p class="header-description">{{ headerDeletionProcessAuditLogDescription }}</p>
</div>
<div [ngClass]="{ 'disabled-container': loading }" *ngIf="identityDeletionProcessAuditLogs.length">
<mat-card>
<mat-card-content class="form-card">
<div *ngIf="loading" class="loading">
<mat-progress-spinner color="primary" mode="indeterminate"> </mat-progress-spinner>
</div>
<div class="form-details" *ngIf="!loading">
<mat-list>
<div class="container">
<div class="column">
<mat-list-item>
<span matListItemTitle>Identity Address</span>
<span matListItemLine>{{ identityAddress }}</span>
</mat-list-item>
</div>
</div>
</mat-list>
<table mat-table class="responsive" [dataSource]="identityDeletionProcessAuditLogs">
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef>ID</th>
<td mat-cell *matCellDef="let AuditLog" data-label="ID:">
{{ AuditLog.id }}
</td>
</ng-container>
<ng-container matColumnDef="createdAt">
<th mat-header-cell *matHeaderCellDef>Created At</th>
<td mat-cell *matCellDef="let AuditLog" data-label="Created At:">
{{ AuditLog.createdAt | date }}
</td>
</ng-container>
<ng-container matColumnDef="message">
<th mat-header-cell *matHeaderCellDef>Message</th>
<td mat-cell *matCellDef="let AuditLog" data-label="Message:">
{{ replaceMessageKeyWithCorrespondingText(AuditLog.messageKey) }}
</td>
</ng-container>
<ng-container matColumnDef="oldStatus">
<th mat-header-cell *matHeaderCellDef>Old Status</th>
<td mat-cell *matCellDef="let AuditLog" data-label="Old Status:">
{{ styleStatus(AuditLog.oldStatus) }}
</td>
</ng-container>
<ng-container matColumnDef="newStatus">
<th mat-header-cell *matHeaderCellDef>New Status</th>
<td mat-cell *matCellDef="let AuditLog" data-label="New Status:">
{{ styleStatus(AuditLog.newStatus) }}
</td>
</ng-container>
<ng-container matColumnDef="identityDeletionProcessId">
<th mat-header-cell *matHeaderCellDef>Identity Deletion Process Id</th>
<td mat-cell *matCellDef="let AuditLog" data-label="Identity Deletion Process Id:">
{{ AuditLog.identityDeletionProcessId }}
</td>
</ng-container>

<tr mat-header-row *matHeaderRowDef="deletionProcessesAuditLogTableDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: deletionProcessesAuditLogTableDisplayedColumns"></tr>

<tr class="mat-row" *matNoDataRow>
<td class="mat-cell no-data" [attr.colspan]="deletionProcessesAuditLogTableDisplayedColumns.length">No deletion process audit logs found.</td>
</tr>
</table>
</div>
</mat-card-content>
</mat-card>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";

import { DeletionProcessAuditLogsDetailsComponent } from "./dp-audit-logs-details.component";

describe("DeletionProcessAuditLogsDetailsComponent", () => {
let component: DeletionProcessAuditLogsDetailsComponent;
let fixture: ComponentFixture<DeletionProcessAuditLogsDetailsComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [DeletionProcessAuditLogsDetailsComponent]
}).compileComponents();

fixture = TestBed.createComponent(DeletionProcessAuditLogsDetailsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it("should create", async () => {
await expect(component).toBeTruthy();
});
});
Loading

0 comments on commit 28a36ac

Please sign in to comment.