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

Check whether a relationship can be established with a given identity #808

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4154488
feat: Add /Relationships/CanCreate endpoint, query, response and handler
MH321Productions Aug 20, 2024
f400ed7
test: Add handler tests
MH321Productions Aug 20, 2024
fee03b5
chore: Add bruno file for /Relationships/CanCreate endpoint
MH321Productions Aug 20, 2024
6eb8eaa
chore: Add validator for CanEstablishRelationshipQuery and use string…
MH321Productions Aug 21, 2024
444aace
chore: Remove unnecessary code
MH321Productions Aug 21, 2024
83f7825
Merge branch 'main' into NMSHDB-190-identity-checking-whether-a-relat…
mergify[bot] Aug 22, 2024
48db8bb
chore: Add CanCreate endpoint to ConsumerApi SDK
MH321Productions Aug 22, 2024
596a139
chore: Remove unnecessary handler tests
MH321Productions Aug 22, 2024
c73d3d5
chore: Add integration tests
MH321Productions Aug 22, 2024
34c1e37
chore: Use helper method and modify Relationship.CountsAsActive method
MH321Productions Aug 22, 2024
c3207d4
chore: Add validator for the identity address format
MH321Productions Aug 22, 2024
e8fb717
Merge branch 'main' into NMSHDB-190-identity-checking-whether-a-relat…
mergify[bot] Aug 23, 2024
10c4cc3
Merge branch 'main' into NMSHDB-190-identity-checking-whether-a-relat…
mergify[bot] Aug 24, 2024
eaa2202
Merge branch 'main' into NMSHDB-190-identity-checking-whether-a-relat…
mergify[bot] Aug 26, 2024
b1e2601
Merge branch 'main' into NMSHDB-190-identity-checking-whether-a-relat…
mergify[bot] Aug 26, 2024
d98bb21
Merge branch 'main' into NMSHDB-190-identity-checking-whether-a-relat…
mergify[bot] Aug 26, 2024
acdfc7a
chore: Remove unnecessary validator check
MH321Productions Aug 26, 2024
a5a0361
chore: Remove now obsolete static responses
MH321Productions Aug 26, 2024
0b4c4c4
chore: Use helper methods
MH321Productions Aug 26, 2024
6b63bc1
chore: Create new helper method for rejected relationships
MH321Productions Aug 26, 2024
f384662
chore: Move and rename feature file
MH321Productions Aug 26, 2024
efbd10c
chore: Extract common helper method code into own method
MH321Productions Aug 26, 2024
e4f4bc2
chore: Don't use the null fallback
MH321Productions Aug 26, 2024
417d2d2
chore: Remove unused method
MH321Productions Aug 26, 2024
4cf2fb7
chore: Extract THEN method cluster into two methods
MH321Productions Aug 26, 2024
4e9171a
chore: cleanup
tnotheis Aug 26, 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
@@ -0,0 +1,19 @@
meta {
name: /Relationships/CanCreate
type: http
seq: 4
}

get {
url: {{baseUrl}}/Relationships/CanCreate?peer={{PeerId}}
body: none
auth: inherit
}

params:query {
peer: {{PeerId}}
}

vars:pre-request {
PeerId: did:e:localhost:dids:8234cca0160ff05c785636
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@Integration
Feature: GET Relationships/CanCreate

Scenario: Two identities without a relationship can create one
Given Identities i1 and i2
When a GET request is sent to the /Relationships/CanCreate?peer={i.id} endpoint by i1 for i2
Then the response status code is 200 (OK)
And a relationship can be established

Scenario: Two identities with an active relationship can't create another one
Given Identities i1 and i2
And an active Relationship between i1 and i2 created by i1
When a GET request is sent to the /Relationships/CanCreate?peer={i.id} endpoint by i1 for i2
Then the response status code is 200 (OK)
And a relationship can not be established

Scenario: Two identities with a rejected relationship can create one
Given Identities i1 and i2
And a rejected Relationship between i1 and i2 created by i1
When a GET request is sent to the /Relationships/CanCreate?peer={i.id} endpoint by i1 for i2
Then the response status code is 200 (OK)
And a relationship can be established

Scenario: Two identities with a rejected and an active relationship can't create one
Given Identities i1 and i2
And a rejected Relationship between i1 and i2 created by i1
And an active Relationship between i1 and i2 created by i1
When a GET request is sent to the /Relationships/CanCreate?peer={i.id} endpoint by i1 for i2
Then the response status code is 200 (OK)
And a relationship can not be established

Scenario: Two identities with two rejected relationships can create one
Given Identities i1 and i2
And a rejected Relationship between i1 and i2 created by i1
And a rejected Relationship between i1 and i2 created by i1
When a GET request is sent to the /Relationships/CanCreate?peer={i.id} endpoint by i1 for i2
Then the response status code is 200 (OK)
And a relationship can be established
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Backbone.ConsumerApi.Tests.Integration.Helpers;

public static class Utils
{
public static async Task<Relationship> EstablishRelationshipBetween(Client client1, Client client2)
public static async Task<RelationshipMetadata> CreatePendingRelationshipBetween(Client client1, Client client2)
{
var createRelationshipTemplateRequest = new CreateRelationshipTemplateRequest
{
Expand All @@ -31,15 +31,40 @@ public static async Task<Relationship> EstablishRelationshipBetween(Client clien
var createRelationshipResponse = await client2.Relationships.CreateRelationship(createRelationshipRequest);
createRelationshipResponse.Should().BeASuccess();

return createRelationshipResponse.Result!;
}

public static async Task<Relationship> EstablishRelationshipBetween(Client client1, Client client2)
{
var relationshipMetadata = await CreatePendingRelationshipBetween(client1, client2);

var acceptRelationshipRequest = new AcceptRelationshipRequest
{
CreationResponseContent = "AAA".GetBytes()
};

var acceptRelationshipResponse = await client1.Relationships.AcceptRelationship(createRelationshipResponse.Result!.Id, acceptRelationshipRequest);
var acceptRelationshipResponse = await client1.Relationships.AcceptRelationship(relationshipMetadata.Id, acceptRelationshipRequest);
acceptRelationshipResponse.Should().BeASuccess();

var getRelationshipResponse = await client1.Relationships.GetRelationship(createRelationshipResponse.Result.Id);
var getRelationshipResponse = await client1.Relationships.GetRelationship(relationshipMetadata.Id);
getRelationshipResponse.Should().BeASuccess();

return getRelationshipResponse.Result!;
}

public static async Task<Relationship> CreateRejectedRelationshipBetween(Client client1, Client client2)
tnotheis marked this conversation as resolved.
Show resolved Hide resolved
{
var relationshipMetadata = await CreatePendingRelationshipBetween(client1, client2);

var rejectRelationshipRequest = new RejectRelationshipRequest
{
CreationResponseContent = "AAA".GetBytes()
};

var rejectRelationshipResponse = await client1.Relationships.RejectRelationship(relationshipMetadata.Id, rejectRelationshipRequest);
rejectRelationshipResponse.Should().BeASuccess();

var getRelationshipResponse = await client1.Relationships.GetRelationship(relationshipMetadata.Id);
getRelationshipResponse.Should().BeASuccess();

return getRelationshipResponse.Result!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
using Backbone.ConsumerApi.Sdk.Authentication;
using Backbone.ConsumerApi.Sdk.Endpoints.Relationships.Types;
using Backbone.ConsumerApi.Sdk.Endpoints.Relationships.Types.Requests;
using Backbone.ConsumerApi.Sdk.Endpoints.Relationships.Types.Responses;
using Backbone.ConsumerApi.Sdk.Endpoints.RelationshipTemplates.Types.Requests;
using Backbone.ConsumerApi.Sdk.Endpoints.RelationshipTemplates.Types.Responses;
using Backbone.ConsumerApi.Tests.Integration.Configuration;
using Backbone.ConsumerApi.Tests.Integration.Extensions;
using Backbone.ConsumerApi.Tests.Integration.Helpers;
using Backbone.ConsumerApi.Tests.Integration.Support;
using Backbone.Tooling.Extensions;
using Microsoft.Extensions.Options;
Expand All @@ -15,6 +17,7 @@ namespace Backbone.ConsumerApi.Tests.Integration.StepDefinitions;

[Binding]
[Scope(Feature = "POST Relationship")]
[Scope(Feature = "GET Relationships/CanCreate")]
internal class RelationshipsStepDefinitions
{
private Client _client1 = null!;
Expand All @@ -26,6 +29,7 @@ internal class RelationshipsStepDefinitions
private ApiResponse<RelationshipMetadata>? _acceptRelationshipResponse;
private ApiResponse<RelationshipMetadata>? _rejectRelationshipResponse;
private ApiResponse<RelationshipMetadata>? _revokeRelationshipResponse;
private ApiResponse<CanEstablishRelationshipResponse>? _canEstablishResponse;
private string _relationshipId = string.Empty;

public RelationshipsStepDefinitions(HttpClientFactory factory, IOptions<HttpConfiguration> httpConfiguration)
Expand All @@ -34,6 +38,8 @@ public RelationshipsStepDefinitions(HttpClientFactory factory, IOptions<HttpConf
_clientCredentials = new ClientCredentials(httpConfiguration.Value.ClientCredentials.ClientId, httpConfiguration.Value.ClientCredentials.ClientSecret);
}

#region Given

[Given("Identities i1 and i2")]
public async Task GivenIdentitiesI1AndI2()
{
Expand Down Expand Up @@ -65,6 +71,18 @@ public async Task GivenAPendingRelationshipBetweenI1AndI2CreatedByI1()
_relationshipId = createRelationshipResponse.Result!.Id;
}

[Given("an active Relationship between i1 and i2 created by i1")]
public async Task GivenAnActiveRelationshipBetweenI1AndI2()
{
_relationshipId = (await Utils.EstablishRelationshipBetween(_client1, _client2)).Id;
}

[Given("a rejected Relationship between i1 and i2 created by i1")]
public async Task GivenARejectedRelationshipBetweenI1AndI2()
{
_relationshipId = (await Utils.CreateRejectedRelationshipBetween(_client1, _client2)).Id;
}

[Given("i2 is in status \"ToBeDeleted\"")]
public async Task GivenIdentityI2IsToBeDeleted()
{
Expand All @@ -79,6 +97,10 @@ public async Task GivenIdentityI1IsToBeDeleted()
startDeletionProcessResponse.Should().BeASuccess();
}

#endregion

#region When

[When("a POST request is sent to the /Relationships endpoint by i1 with rt.id")]
public async Task WhenAPostRequestIsSentToTheRelationshipsEndpointByI1With()
{
Expand Down Expand Up @@ -115,6 +137,16 @@ public async Task WhenAPostRequestIsSentToTheRevokeRelationshipEndpointByI2()
_revokeRelationshipResponse = await _client1.Relationships.RevokeRelationship(_relationshipId, revokeRelationshipRequest);
}

[When("a GET request is sent to the /Relationships/CanCreate\\?peer={i.id} endpoint by i1 for i2")]
public async Task WhenAGetRequestIsSentToTheCanCreateEndpointByI1()
{
_canEstablishResponse = await _client1.Relationships.CanCreateRelationship(_client2.IdentityData!.Address);
}

#endregion

#region Then

[Then(@"the response status code is (\d\d\d) \(.+\)")]
public void ThenTheResponseStatusCodeIs(int expectedStatusCode)
{
Expand Down Expand Up @@ -187,6 +219,22 @@ public async Task ThenTheResponseContainsARelationship()
}
}

[Then("a relationship can be established")]
public void ThenARelationshipCanBeEstablished()
{
if (_canEstablishResponse != null)
_canEstablishResponse.Result!.CanCreate.Should().BeTrue();
}

[Then("a relationship can not be established")]
public void ThenARelationshipCanNotBeEstablished()
{
if (_canEstablishResponse != null)
_canEstablishResponse.Result!.CanCreate.Should().BeFalse();
}

#endregion

private async Task<ApiResponse<CreateRelationshipTemplateResponse>> CreateRelationshipTemplate(Client client)
{
var createRelationshipTemplateRequest = new CreateRelationshipTemplateRequest
Expand Down
4 changes: 0 additions & 4 deletions Backbone.sln
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerformanceSnapshotCreator"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tokens.Domain.Tests", "Modules\Tokens\test\Tokens.Domain.Tests\Tokens.Domain.Tests.csproj", "{EDCB84BE-54C3-4CAD-977E-45EEBEFA1402}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{AAE548AB-4843-476A-BF61-002CF6FEE713}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{824495A9-A255-487D-AF26-6F6CA92BC715}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Challenges.Application.Tests", "Modules\Challenges\test\Challenges.Application.Tests\Challenges.Application.Tests.csproj", "{EAA10D43-BD28-40D8-BE07-B8F6DE47C156}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Others", "Others", "{8B8EE965-0373-46D6-BB30-7C131EE524E4}"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Backbone.DevelopmentKit.Identity.ValueObjects;
using MediatR;

namespace Backbone.Modules.Relationships.Application.Relationships.Queries.CanEstablishRelationship;

public class CanEstablishRelationshipQuery : IRequest<CanEstablishRelationshipResponse>
{
public required string PeerAddress { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Backbone.BuildingBlocks.Application.FluentValidation;
using Backbone.DevelopmentKit.Identity.ValueObjects;
using FluentValidation;

namespace Backbone.Modules.Relationships.Application.Relationships.Queries.CanEstablishRelationship;

// ReSharper disable once UnusedType.Global
public class CanEstablishRelationshipQueryValidator : AbstractValidator<CanEstablishRelationshipQuery>
{
public CanEstablishRelationshipQueryValidator()
{
RuleFor(q => q.PeerAddress).Must(IdentityAddress.IsValid);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Backbone.Modules.Relationships.Application.Relationships.Queries.CanEstablishRelationship;

public class CanEstablishRelationshipResponse
{
public required bool CanCreate { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext;
using Backbone.DevelopmentKit.Identity.ValueObjects;
using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository;
using MediatR;

namespace Backbone.Modules.Relationships.Application.Relationships.Queries.CanEstablishRelationship;

public class Handler : IRequestHandler<CanEstablishRelationshipQuery, CanEstablishRelationshipResponse>
{
private readonly IRelationshipsRepository _relationshipsRepository;
private readonly IUserContext _userContext;

public Handler(IUserContext userContext, IRelationshipsRepository relationshipsRepository)
{
_relationshipsRepository = relationshipsRepository;
_userContext = userContext;
}

public async Task<CanEstablishRelationshipResponse> Handle(CanEstablishRelationshipQuery request, CancellationToken cancellationToken)
{
var hasActiveRelationship = await _relationshipsRepository.RelationshipBetweenTwoIdentitiesExists(_userContext.GetAddress(), IdentityAddress.Parse(request.PeerAddress), cancellationToken);

return new CanEstablishRelationshipResponse { CanCreate = !hasActiveRelationship };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Backbone.BuildingBlocks.API.Mvc.ControllerAttributes;
using Backbone.BuildingBlocks.Application.Abstractions.Exceptions;
using Backbone.BuildingBlocks.Application.Pagination;
using Backbone.DevelopmentKit.Identity.ValueObjects;
using Backbone.Modules.Devices.Application.Identities.Queries.GetIdentity;
using Backbone.Modules.Devices.Domain.Entities.Identities;
using Backbone.Modules.Relationships.Application;
Expand All @@ -17,6 +18,7 @@
using Backbone.Modules.Relationships.Application.Relationships.Commands.RevokeRelationshipReactivation;
using Backbone.Modules.Relationships.Application.Relationships.Commands.TerminateRelationship;
using Backbone.Modules.Relationships.Application.Relationships.DTOs;
using Backbone.Modules.Relationships.Application.Relationships.Queries.CanEstablishRelationship;
using Backbone.Modules.Relationships.Application.Relationships.Queries.GetPeerOfActiveIdentityInRelationship;
using Backbone.Modules.Relationships.Application.Relationships.Queries.GetRelationship;
using Backbone.Modules.Relationships.Application.Relationships.Queries.ListRelationships;
Expand Down Expand Up @@ -195,6 +197,15 @@ public async Task<IActionResult> DecomposeRelationship([FromRoute] string id, Ca
return Ok(response);
}

[HttpGet("CanCreate")]
[ProducesResponseType(typeof(HttpResponseEnvelopeResult<CanEstablishRelationshipResponse>), StatusCodes.Status200OK)]
[ProducesError(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> CanEstablishRelationship([FromQuery] string peer, CancellationToken cancellationToken)
{
var response = await _mediator.Send(new CanEstablishRelationshipQuery { PeerAddress = peer }, cancellationToken);
return Ok(response);
}

private async Task EnsurePeerIsNotToBeDeleted(string peerIdentityAddress, CancellationToken cancellationToken)
{
var peerIdentity = await _mediator.Send(new GetIdentityQuery(peerIdentityAddress), cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,8 @@ public static Expression<Func<Relationship, bool>> HasParticipant(string identit
public static Expression<Func<Relationship, bool>> CountsAsActive()
{
return r => r.Status != RelationshipStatus.Rejected &&
r.Status != RelationshipStatus.Revoked;
r.Status != RelationshipStatus.Revoked &&
r.Status != RelationshipStatus.ReadyForDeletion;
}

#endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,13 @@ public async Task<ApiResponse<RelationshipMetadata>> DecomposeRelationship(strin
{
return await _client.Put<RelationshipMetadata>($"api/{API_VERSION}/Relationships/{relationshipId}/Decompose");
}

public async Task<ApiResponse<CanEstablishRelationshipResponse>> CanCreateRelationship(string peerIdentityAddress)
{
return await _client
.Request<CanEstablishRelationshipResponse>(HttpMethod.Get, $"api/{API_VERSION}/Relationships/CanCreate")
.Authenticate()
.AddQueryParameter("peer", peerIdentityAddress)
.Execute();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Backbone.ConsumerApi.Sdk.Endpoints.Relationships.Types.Responses;

public class CanEstablishRelationshipResponse
{
public required bool CanCreate { get; set; }
}