Skip to content
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

Consumer API: Create identity deletion process as owner; create identity deletion process as support; deletion process approval #523

Merged
merged 103 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
c8f49b2
wip
tnotheis Oct 23, 2023
f7eec90
wip
NikolaVetnic Oct 24, 2023
f413525
chore: imports fixed
NikolaVetnic Oct 24, 2023
6ca6628
fix: some ref error with FakeItEasy
NikolaVetnic Oct 24, 2023
5673bea
chore: extracted IdentDeletionProcessId from the Identity class
NikolaVetnic Oct 25, 2023
5f92a18
feat: start deletion process as support
stamenione Oct 25, 2023
267fbbc
Merge branch 'main' into trigger-identity-deletion-process
tnotheis Oct 26, 2023
7c6f8d2
refactor: introduce public Hasher
tnotheis Oct 26, 2023
8814e5c
feat: StartDeletionProcess handler happy path
tnotheis Oct 26, 2023
21874de
feat: publish integration event and throw NotFoundException
NikolaDmitrasinovic Oct 26, 2023
59e5ec6
feat: canOnlyStartDeletionProcessForOwnIdentity
HunorTotBagi Oct 27, 2023
f2522a9
chore: cleanup
NikolaVetnic Oct 27, 2023
7a9110d
refactoring: method extracted
NikolaVetnic Oct 27, 2023
070fc74
refactoring: extract handler creation to static methods
NikolaVetnic Oct 27, 2023
a42a8cc
feat: start deletion process as support
NikolaVetnic Oct 27, 2023
5628008
test: add Consumer API integration test
tnotheis Oct 27, 2023
b2e8b31
Merge branch 'trigger-identity-deletion-process' of github.com:nmshd/…
NikolaVetnic Oct 30, 2023
4d8ffbd
refactor: use constructor instead of factory method for IdentityDelet…
tnotheis Oct 30, 2023
e8ae923
chore: fix typos and unnecessary whitespaces
NikolaVetnic Oct 31, 2023
2164b12
Merge branch 'trigger-identity-deletion-process' of github.com:nmshd/…
NikolaVetnic Oct 31, 2023
b64f184
feat: add migration
tnotheis Oct 31, 2023
f1c66c6
feat: add consumer api route for starting a deletion process
tnotheis Oct 31, 2023
3f9addc
Merge branch 'trigger-identity-deletion-process' of github.com:nmshd/…
tnotheis Oct 31, 2023
0fb16f3
test: add deletion process to identity that already has active deleti…
NikolaVetnic Oct 31, 2023
5b0966c
chore: fix formatting
tnotheis Nov 2, 2023
3552538
fix: test not marked as Integration
Dannyps Nov 3, 2023
b5f54aa
Merge branch 'main' into identity-deletion
daniel-almeida-konkconsulting Nov 9, 2023
5782e02
Merge branch 'trigger-identity-deletion-process' into identity-deletion
daniel-almeida-konkconsulting Nov 9, 2023
13e5fa3
test: refactor to directly assert varying outcomes
tnotheis Nov 14, 2023
e771880
feat: automatically approve deletion process if started by owner
tnotheis Nov 14, 2023
4a4a6b4
chore: combine all hashing relevant things in one file
tnotheis Nov 14, 2023
d55d09d
test: small refactoring
tnotheis Nov 17, 2023
f4f880a
feat: remove possibility to start the process as support
tnotheis Nov 17, 2023
9ee5016
feat: change url to /DeletionProcesses
tnotheis Nov 17, 2023
6e31b24
Merge branch 'main' into trigger-identity-deletion-process
tnotheis Nov 17, 2023
2dd8555
feat: introduce GracePeriodEndsAt property
tnotheis Nov 17, 2023
d36805f
feat: return deletion process in http response
tnotheis Nov 17, 2023
23f355f
test: assert that audit log is filled in repository method
tnotheis Nov 17, 2023
a4606f6
Merge branch 'identity-deletion' of github.com:nmshd/backbone into id…
tnotheis Nov 17, 2023
02955d6
chore: formatting
tnotheis Nov 17, 2023
b3ff1b7
chore: formatting/refactoring
tnotheis Nov 17, 2023
113b870
feat: implement real hashing
tnotheis Nov 17, 2023
b02698f
chore: formatting
tnotheis Nov 17, 2023
566fc43
refactor: extract method
tnotheis Nov 17, 2023
a4db0f3
fix: regenerate migrations to contain the latest columns
tnotheis Nov 17, 2023
073231b
chore: formatting/cleanup
tnotheis Nov 17, 2023
64729be
chore: formatting
tnotheis Nov 17, 2023
eae7325
Queued for Deletion Tier (#373)
daniel-almeida-konkconsulting Nov 20, 2023
be54876
Merge branch 'main' into identity-deletion
daniel-almeida-konkconsulting Nov 28, 2023
4321a2f
fix: remove using after merge
daniel-almeida-konkconsulting Nov 28, 2023
7d8a8b1
fix: remove duplicate step definitions
daniel-almeida-konkconsulting Nov 28, 2023
e2aab1f
refactor: remove whitespace
daniel-almeida-konkconsulting Nov 28, 2023
cf80086
Start process as support (#417)
daniel-almeida-konkconsulting Dec 5, 2023
9b22d48
Identity deletion process started event fails (#429)
daniel-almeida-konkconsulting Dec 7, 2023
0a931ab
feat: use Pbkdf2 instead of SHA for hashing
tnotheis Dec 8, 2023
8d36ba1
Merge branch 'identity-deletion' of github.com:nmshd/backbone into id…
tnotheis Dec 8, 2023
d62c8a2
Merge branch 'main' into identity-deletion
JLSRKonk Dec 13, 2023
beae3cf
fix: merge broke Postgres migrations
JLSRKonk Dec 13, 2023
3facbb5
fix: merge broken SqlServer migrations
JLSRKonk Dec 13, 2023
4e4ae55
refactor: remove unused Postgres compiled models
JLSRKonk Dec 13, 2023
40b8424
Merge branch 'main' into identity-deletion
JLSRKonk Dec 15, 2023
cf60a81
fix: merge fix
JLSRKonk Dec 15, 2023
6c63b76
test: fix consumerApi IdentitiesApiStepDefinitions after merge
JLSRKonk Dec 15, 2023
4226a62
fix: remake devices postgres migrations
JLSRKonk Dec 15, 2023
852bb73
fix: remake devices sqlserver migrations
JLSRKonk Dec 15, 2023
63b4980
Identity Deletion Grace Period (#443)
JLSRKonk Dec 20, 2023
8a2e835
Merge branch 'main' into identity-deletion
daniel-almeida-konkconsulting Jan 11, 2024
0212603
Waiting for approval (#449)
daniel-almeida-konkconsulting Jan 12, 2024
f9b1057
Merge remote-tracking branch 'origin/main' into identity-deletion
NikolaVetnic Jan 31, 2024
222828c
Merge commit 'b4ee4a65f74db5d2fbc35ba2f7836a572f507489' into identity…
tnotheis Feb 13, 2024
622910c
Merge commit 'e9602b3f3838b32973d8b922c8e58bfaf05db657' into identity…
tnotheis Feb 13, 2024
184deea
Merge commit '93f7076b8b9cb0f297ffeaa3728760cc10dad520' into identity…
tnotheis Feb 13, 2024
4f62c25
Merge commit '7cc013d232c606d0b982be5daae884d7f6e66e6b' into identity…
tnotheis Feb 13, 2024
742d6af
Merge commit 'a81f286c9caf5c83893a1572f0494a9e0bc8c7fe' into identity…
tnotheis Feb 13, 2024
db29a32
Merge commit '2baebb659b64981d66dce78adb37579a9130479c' into identity…
tnotheis Feb 13, 2024
19aae8c
Merge commit 'e7e611cd9e21698a1cd70770366144e381ff0cd4' into identity…
tnotheis Feb 13, 2024
7ebb49b
Merge commit 'c401c632404245df059e57a4dffee73163441f2f' into identity…
tnotheis Feb 13, 2024
a35cb3e
Merge commit 'ac07debf880745a4ef8d66b65e8addff6a09e194' into identity…
tnotheis Feb 13, 2024
71b82d1
Merge commit 'ed2c3863dd550560f1956d62c8ea38822d0073ba' into identity…
tnotheis Feb 13, 2024
5a12a6c
Merge commit '2b52cd4e2b36d500a02df28782f07fa967c54d91' into identity…
tnotheis Feb 13, 2024
4899bf6
Merge commit '4dd4377b1a8eff8ba6c69793538a76260d7b13d8' into identity…
tnotheis Feb 13, 2024
0fb2daf
chore: fix security issue
tnotheis Feb 13, 2024
467920a
fix: check for null in SeedQueuedForDeletionTierCommand Handler
tnotheis Feb 13, 2024
f20d293
Merge branch 'main' into identity-deletion
mergify[bot] Feb 13, 2024
ef79051
chore: formatting
tnotheis Feb 13, 2024
2bf631e
Merge branch 'identity-deletion' of github.com:nmshd/backbone into id…
tnotheis Feb 13, 2024
ae3fe3a
Merge branch 'main' of github.com:nmshd/backbone
tnotheis Feb 13, 2024
540f565
Merge branch 'main' into identity-deletion
tnotheis Feb 13, 2024
d73e7da
Deletion process approval (#462)
daniel-almeida-konkconsulting Feb 13, 2024
48be11f
Merge branch 'main' into identity-deletion
mergify[bot] Feb 13, 2024
ae83b9e
chore: remove migrations to be merged
NikolaVetnic Feb 13, 2024
e2e4a6f
chore: merge migrations related to identity deletion
NikolaVetnic Feb 13, 2024
3846ba8
chore: update model snapshots
NikolaVetnic Feb 13, 2024
7a5c081
chore: fix formatting
NikolaVetnic Feb 13, 2024
76b683e
Merge branch 'main' into identity-deletion
mergify[bot] Feb 14, 2024
c92e103
Merge branch 'main' into identity-deletion
mergify[bot] Feb 14, 2024
761af2d
chore: improve http error when quota is exhausted
tnotheis Feb 16, 2024
dfe7a16
refactor: rename test
tnotheis Feb 16, 2024
d51de61
fix: avoid deferred execution when adding tier quota definitions
tnotheis Feb 16, 2024
22bf879
fix: read identity as tracking
tnotheis Feb 16, 2024
9e44bc1
Merge branch 'main' into identity-deletion
tnotheis Feb 16, 2024
bc2afb0
test: comment out test for creating a deletion process to avoid error…
tnotheis Feb 16, 2024
0d1157c
test: set deletion time correctly
tnotheis Feb 16, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ export class CreateTierDialogComponent {
name: "",
quotas: [],
isDeletable: false,
numberOfIdentities: 0
numberOfIdentities: 0,
isReadOnly: false
} as Tier;
}

Expand Down Expand Up @@ -58,7 +59,8 @@ export class CreateTierDialogComponent {
name: data.result.name,
quotas: [],
numberOfIdentities: data.result.numberOfIdentities,
isDeletable: data.result.isDeletable
isDeletable: data.result.isDeletable,
isReadOnly: false
} as Tier;

this.snackBar.open("Successfully added tier.", "Dismiss", {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ <h2 class="header-title">{{ headerEdit }}</h2>
</mat-form-field>
<mat-form-field class="full-width">
<mat-label>Name</mat-label>
<input matInput required [(ngModel)]="tier.name" [disabled]="disabled || editMode" />
<input matInput required [(ngModel)]="tier.name" [disabled]="isNameInputDisabled()" />
<mat-error>You must enter a value</mat-error>
</mat-form-field>
</div>
Expand All @@ -34,10 +34,10 @@ <h2 class="header-title">{{ headerEdit }}</h2>
</mat-panel-description>
</mat-expansion-panel-header>
<div class="action-buttons">
<button mat-mini-fab color="warn" (click)="openConfirmationDialogQuotaDeletion()" [disabled]="selectionQuotas.selected.length === 0">
<button mat-mini-fab color="warn" (click)="openConfirmationDialogQuotaDeletion()" [disabled]="isQuotaDeletionDisabled()">
<mat-icon>delete</mat-icon>
</button>
<button mat-mini-fab color="primary" (click)="openAssignQuotaDialog()" [disabled]="!tier.id">
<button mat-mini-fab color="primary" (click)="openAssignQuotaDialog()" [disabled]="isQuotaAssignmentDisabled()">
<mat-icon>add</mat-icon>
</button>
</div>
Expand All @@ -47,6 +47,7 @@ <h2 class="header-title">{{ headerEdit }}</h2>
<mat-checkbox
(change)="$event ? toggleAllRowsQuotas() : null"
[checked]="selectionQuotas.hasValue() && isAllSelected()"
[disabled]="tier.isReadOnly"
color="primary"
[indeterminate]="selectionQuotas.hasValue() && !isAllSelected()"
[aria-label]="checkboxLabelQuotas()">
Expand All @@ -56,6 +57,7 @@ <h2 class="header-title">{{ headerEdit }}</h2>
<mat-checkbox
(click)="$event.stopPropagation()"
(change)="$event ? selectionQuotas.toggle(row) : null"
[disabled]="tier.isReadOnly"
[checked]="selectionQuotas.isSelected(row)"
color="primary"
[aria-label]="checkboxLabelQuotas(i, row)">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { SelectionModel } from "@angular/cdk/collections";
import { Component } from "@angular/core";
import { MatDialog, MatDialogRef } from "@angular/material/dialog";
import { MatSnackBar } from "@angular/material/snack-bar";
import { ActivatedRoute, Router } from "@angular/router";
import { Observable, forkJoin } from "rxjs";
import { ConfirmationDialogComponent } from "src/app/components/shared/confirmation-dialog/confirmation-dialog.component";
import { QuotasService, TierQuota } from "src/app/services/quotas-service/quotas.service";
import { Tier, TierService } from "src/app/services/tier-service/tier.service";
import { HttpErrorResponseWrapper } from "src/app/utils/http-error-response-wrapper";
import { HttpResponseEnvelope } from "src/app/utils/http-response-envelope";
import { AssignQuotaData, AssignQuotasDialogComponent } from "../../assign-quotas-dialog/assign-quotas-dialog.component";
import { SelectionModel } from "@angular/cdk/collections";
import { ConfirmationDialogComponent } from "src/app/components/shared/confirmation-dialog/confirmation-dialog.component";
import { Observable, forkJoin } from "rxjs";
import { HttpErrorResponseWrapper } from "src/app/utils/http-error-response-wrapper";

@Component({
selector: "app-tier-edit",
Expand All @@ -24,7 +24,6 @@ export class TierEditComponent {
public selectionQuotas: SelectionModel<TierQuota>;
public quotasTableDisplayedColumns: string[];
public tierId?: string;
public disabled: boolean;
public editMode: boolean;
public tier: Tier;
public loading: boolean;
Expand All @@ -47,12 +46,12 @@ export class TierEditComponent {
this.quotasTableDisplayedColumns = ["select", "metricName", "max", "period"];
this.editMode = false;
this.loading = true;
this.disabled = false;
this.tier = {
id: "",
name: "",
quotas: [],
isDeletable: false,
isReadOnly: false,
numberOfIdentities: 0
} as Tier;
}
Expand All @@ -76,7 +75,6 @@ export class TierEditComponent {
this.tierService.getTierById(this.tierId!).subscribe({
next: (data: HttpResponseEnvelope<Tier>) => {
this.tier = data.result;
this.tier.isDeletable = this.tier.name !== "Basic";
},
complete: () => (this.loading = false),
error: (err: any) => {
Expand Down Expand Up @@ -246,4 +244,16 @@ export class TierEditComponent {
}
return `${this.selectionQuotas.isSelected(row) ? "deselect" : "select"} row ${index + 1}`;
}

public isNameInputDisabled(): boolean {
return this.editMode || this.tier.isReadOnly;
}

public isQuotaDeletionDisabled(): boolean {
return this.selectionQuotas.selected.length === 0 || this.tier.isReadOnly;
}

public isQuotaAssignmentDisabled(): boolean {
return this.tier.id === "" || this.tier.isReadOnly;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
import { Observable, map } from "rxjs";
import { HttpResponseEnvelope } from "src/app/utils/http-response-envelope";
import { PagedHttpResponseEnvelope } from "src/app/utils/paged-http-response-envelope";
import { environment } from "src/environments/environment";
Expand All @@ -11,6 +11,9 @@ import { TierQuota } from "../quotas-service/quotas.service";
})
export class TierService {
private readonly apiUrl: string;
private static readonly QUEUED_FOR_DELETION_TIER_ID = "TIR00000000000000001";
private static readonly BASIC_TIER_NAME = "Basic";

public constructor(private readonly http: HttpClient) {
this.apiUrl = `${environment.apiUrl}/Tiers`;
}
Expand All @@ -20,7 +23,13 @@ export class TierService {
}

public getTierById(id: string): Observable<HttpResponseEnvelope<Tier>> {
return this.http.get<HttpResponseEnvelope<Tier>>(`${this.apiUrl}/${id}`);
return this.http.get<HttpResponseEnvelope<Tier>>(`${this.apiUrl}/${id}`).pipe(
map((responseEnvelope: HttpResponseEnvelope<Tier>) => {
responseEnvelope.result.isDeletable = responseEnvelope.result.name !== TierService.BASIC_TIER_NAME && responseEnvelope.result.id !== TierService.QUEUED_FOR_DELETION_TIER_ID;
responseEnvelope.result.isReadOnly = responseEnvelope.result.id === TierService.QUEUED_FOR_DELETION_TIER_ID;
return responseEnvelope;
})
);
}

public createTier(tier: Tier): Observable<HttpResponseEnvelope<Tier>> {
Expand All @@ -41,6 +50,7 @@ export interface Tier {
name: string;
quotas: TierQuota[];
isDeletable: boolean;
isReadOnly: boolean;
numberOfIdentities: number;
}

Expand Down
71 changes: 55 additions & 16 deletions AdminUi/src/AdminUi/Controllers/IdentitiesController.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using Backbone.AdminUi.Infrastructure.Persistence.Database;
using Backbone.BuildingBlocks.API;
using Backbone.BuildingBlocks.API.Mvc;
using Backbone.BuildingBlocks.API.Mvc.ControllerAttributes;
using Backbone.Modules.Devices.Application;
using Backbone.Modules.Devices.Application.Devices.DTOs;
using Backbone.Modules.Devices.Application.Identities.Commands.CreateIdentity;
using Backbone.Modules.Devices.Application.Identities.Commands.StartDeletionProcessAsSupport;
using Backbone.Modules.Devices.Application.Identities.Commands.UpdateIdentity;
using Backbone.Modules.Quotas.Application.DTOs;
using Backbone.Modules.Quotas.Application.Identities.Commands.CreateQuotaForIdentity;
Expand All @@ -11,7 +12,6 @@
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using GetIdentityQueryDevices = Backbone.Modules.Devices.Application.Identities.Queries.GetIdentity.GetIdentityQuery;
using GetIdentityQueryQuotas = Backbone.Modules.Quotas.Application.Identities.Queries.GetIdentity.GetIdentityQuery;
using GetIdentityResponseDevices = Backbone.Modules.Devices.Application.Identities.Queries.GetIdentity.GetIdentityResponse;
Expand All @@ -23,14 +23,8 @@ namespace Backbone.AdminUi.Controllers;
[Authorize("ApiKey")]
public class IdentitiesController : ApiControllerBase
{
private readonly AdminUiDbContext _adminUiDbContext;
private readonly ApplicationOptions _options;

public IdentitiesController(
IMediator mediator, IOptions<ApplicationOptions> options, AdminUiDbContext adminUiDbContext) : base(mediator)
public IdentitiesController(IMediator mediator) : base(mediator)
{
_adminUiDbContext = adminUiDbContext;
_options = options.Value;
}

[HttpPost("{identityAddress}/Quotas")]
Expand Down Expand Up @@ -86,6 +80,40 @@ public async Task<IActionResult> UpdateIdentity([FromRoute] string identityAddre
await _mediator.Send(command, cancellationToken);
return NoContent();
}

[HttpPost]
[ProducesResponseType(typeof(HttpResponseEnvelopeResult<CreateIdentityResponse>), StatusCodes.Status201Created)]
[ProducesError(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> CreateIdentity(CreateIdentityRequest request, CancellationToken cancellationToken)
{
var command = new CreateIdentityCommand
{
ClientId = request.ClientId,
DevicePassword = request.DevicePassword,
IdentityPublicKey = request.IdentityPublicKey,
IdentityVersion = request.IdentityVersion,
SignedChallenge = new SignedChallengeDTO
{
Challenge = request.SignedChallenge.Challenge,
Signature = request.SignedChallenge.Signature
},
ShouldValidateChallenge = false
};

var response = await _mediator.Send(command, cancellationToken);

return Created(response);
}

[HttpPost("{address}/DeletionProcesses")]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesError(StatusCodes.Status400BadRequest)]
[ProducesError(StatusCodes.Status404NotFound)]
public async Task<IActionResult> StartDeletionProcessAsSupport([FromRoute] string address, CancellationToken cancellationToken)
{
var response = await _mediator.Send(new StartDeletionProcessAsSupportCommand(address), cancellationToken);
return Created("", response);
}
}

public class CreateQuotaForIdentityRequest
Expand All @@ -94,6 +122,7 @@ public class CreateQuotaForIdentityRequest
public int Max { get; set; }
public QuotaPeriod Period { get; set; }
}

public class UpdateIdentityTierRequest
{
public string TierId { get; set; }
Expand All @@ -104,16 +133,26 @@ public class GetIdentityResponse
public string Address { get; set; }
public string ClientId { get; set; }
public byte[] PublicKey { get; set; }

public string TierId { get; set; }

public DateTime CreatedAt { get; set; }

public byte IdentityVersion { get; set; }

public int NumberOfDevices { get; set; }

public IEnumerable<DeviceDTO> Devices { get; set; }

public IEnumerable<QuotaDTO> Quotas { get; set; }
}

public class CreateIdentityRequest
{
public required string ClientId { get; set; }
public required string ClientSecret { get; set; }
public required byte[] IdentityPublicKey { get; set; }
public required string DevicePassword { get; set; }
public required byte IdentityVersion { get; set; }
public required CreateIdentityRequestSignedChallenge SignedChallenge { get; set; }
}

public class CreateIdentityRequestSignedChallenge
{
public required string Challenge { get; set; }
public required byte[] Signature { get; set; }
}
10 changes: 10 additions & 0 deletions AdminUi/test/AdminUi.Tests.Integration/API/IdentitiesApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,14 @@ internal async Task<HttpResponse> DeleteIndividualQuota(string identityAddress,
{
return await GetOData<List<IdentityOverviewDTO>>("/Identities?$expand=Tier", requestConfiguration);
}

internal async Task<HttpResponse<StartDeletionProcessAsSupportResponse>> StartDeletionProcess(string identityAddress, RequestConfiguration requestConfiguration)
{
return await Post<StartDeletionProcessAsSupportResponse>($"/Identities/{identityAddress}/DeletionProcesses", requestConfiguration);
}

internal async Task<HttpResponse<CreateIdentityResponse>> CreateIdentity(RequestConfiguration requestConfiguration)
{
return await Post<CreateIdentityResponse>("/Identities", requestConfiguration);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@Integration
Feature: POST Identities/{id}/DeletionProcess

Support starts a deletion process

Scenario: Starting a deletion process as support
Given an Identity i
When a POST request is sent to the /Identities/{i.id}/DeletionProcesses endpoint
Then the response status code is 201 (Created)
And the response contains a Deletion Process

Scenario: There can only be one active deletion process
Given an Identity i
And an active deletion process for Identity i exists
When a POST request is sent to the /Identities/{i.id}/DeletionProcesses endpoint
Then the response status code is 400 (Bad Request)
And the response content includes an error with the error code "error.platform.validation.device.onlyOneActiveDeletionProcessAllowed"
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Backbone.AdminUi.Tests.Integration.Models;

public class CreateIdentityRequest
{
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public string IdentityPublicKey { get; set; }
public string DevicePassword { get; set; }
public byte IdentityVersion { get; set; }
public CreateIdentityRequestSignedChallenge SignedChallenge { get; set; }
}

public class CreateIdentityRequestSignedChallenge
{
public string Challenge { get; set; }
public string Signature { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Backbone.AdminUi.Tests.Integration.Models;

public class CreateIdentityResponse
{
public string Address { get; set; }
public DateTime CreatedAt { get; set; }

public CreateIdentityResponseDevice Device { get; set; }
}

public class CreateIdentityResponseDevice
{
public string Id { get; set; }
public string Username { get; set; }
public DateTime CreatedAt { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Backbone.AdminUi.Tests.Integration.Models;

public class StartDeletionProcessAsSupportResponse
{
public string Id { get; set; }
public string Status { get; set; }
public DateTime CreatedAt { get; set; }
}
Loading