Skip to content

Commit

Permalink
Fixed GuestInvitation to validate the token
Browse files Browse the repository at this point in the history
  • Loading branch information
jezzsantos committed Oct 25, 2024
1 parent 84f41be commit 063f3bd
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 32 deletions.
8 changes: 5 additions & 3 deletions src/EndUsersApplication.UnitTests/EndUsersApplicationSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ public async Task WhenRegisterPersonAsyncAndWasInvitedAsGuest_ThenCompletesRegis
It.IsAny<CancellationToken>()), Times.Never);
}

private const string TestingToken = "Ll4qhv77XhiXSqsTUc6icu56ZLrqu5p1gH9kT5IlHio";

[Fact]
public async Task WhenRegisterPersonAsyncAndAcceptingGuestInvitation_ThenCompletesRegistration()
{
Expand All @@ -164,7 +166,7 @@ public async Task WhenRegisterPersonAsyncAndAcceptingGuestInvitation_ThenComplet
.Returns("acallid");
var tokensService = new Mock<ITokensService>();
tokensService.Setup(ts => ts.CreateGuestInvitationToken())
.Returns("aninvitationtoken");
.Returns(TestingToken);
var invitee = EndUserRoot.Create(_recorder.Object, _idFactory.Object, UserClassification.Person).Value;
await invitee.InviteGuestAsync(tokensService.Object, "aninviterid".ToId(),
EmailAddress.Create("[email protected]").Value, (_, _) => Task.FromResult(Result.Ok));
Expand Down Expand Up @@ -204,7 +206,7 @@ await invitee.InviteGuestAsync(tokensService.Object, "aninviterid".ToId(),
}
});

var result = await _application.RegisterPersonAsync(_caller.Object, "aninvitationtoken", "[email protected]",
var result = await _application.RegisterPersonAsync(_caller.Object, TestingToken, "[email protected]",
"afirstname", "alastname", null, null, true, CancellationToken.None);

result.Should().BeSuccess();
Expand All @@ -215,7 +217,7 @@ await invitee.InviteGuestAsync(tokensService.Object, "aninviterid".ToId(),
result.Value.Roles.Should().OnlyContain(role => role == PlatformRoles.Standard.Name);
result.Value.Features.Should().ContainInOrder(PlatformFeatures.PaidTrial.Name, PlatformFeatures.Basic.Name);
_invitationRepository.Verify(rep =>
rep.FindInvitedGuestByTokenAsync("aninvitationtoken", It.IsAny<CancellationToken>()));
rep.FindInvitedGuestByTokenAsync(TestingToken, It.IsAny<CancellationToken>()));
_notificationsService.Verify(ns => ns.NotifyPasswordRegistrationRepeatCourtesyAsync(It.IsAny<ICallerContext>(),
It.IsAny<string>(),
It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,14 @@ public InvitationsApplicationDomainEventHandlersSpec()
_notificationsService = new Mock<IUserNotificationsService>();
_tokensService = new Mock<ITokensService>();
_tokensService.Setup(ts => ts.CreateGuestInvitationToken())
.Returns("aninvitationtoken");
.Returns(TestingToken);

_application =
new InvitationsApplication(_recorder.Object, idFactory.Object, _tokensService.Object,
_notificationsService.Object, _userProfilesService.Object, _repository.Object);
}

private const string TestingToken = "Ll4qhv77XhiXSqsTUc6icu56ZLrqu5p1gH9kT5IlHio";
[Fact]
public async Task WhenHandleOrganizationMemberInvitedAsyncAndNoUserIdNorEmailAddress_ThenReturnsError()
{
Expand Down Expand Up @@ -179,7 +180,7 @@ await _application.HandleOrganizationMemberInvitedAsync(_caller.Object, domainEv
_userProfilesService.Verify(ups =>
ups.FindPersonByEmailAddressPrivateAsync(_caller.Object, "[email protected]",
It.IsAny<CancellationToken>()));
_notificationsService.Verify(ns => ns.NotifyGuestInvitationToPlatformAsync(_caller.Object, "aninvitationtoken",
_notificationsService.Verify(ns => ns.NotifyGuestInvitationToPlatformAsync(_caller.Object, TestingToken,
"[email protected]", "Aninvitee", "aninviterdisplayname", It.IsAny<CancellationToken>()));
_repository.Verify(rep => rep.LoadAsync("anid".ToId(), It.IsAny<CancellationToken>()), Times.Never);
_repository.Verify(rep => rep.LoadAsync("aninviterid".ToId(), It.IsAny<CancellationToken>()));
Expand Down Expand Up @@ -229,7 +230,7 @@ await _application.HandleOrganizationMemberInvitedAsync(_caller.Object, domainEv
&& eu.GuestInvitation.IsInvited
&& eu.GuestInvitation.InvitedById! == "aninviterid".ToId()
), It.IsAny<CancellationToken>()));
_notificationsService.Verify(ns => ns.NotifyGuestInvitationToPlatformAsync(_caller.Object, "aninvitationtoken",
_notificationsService.Verify(ns => ns.NotifyGuestInvitationToPlatformAsync(_caller.Object, TestingToken,
"[email protected]", "Aninvitee", "aninviterdisplayname", It.IsAny<CancellationToken>()));
_userProfilesService.Verify(ups =>
ups.GetProfilePrivateAsync(_caller.Object, "aninviterid", It.IsAny<CancellationToken>()));
Expand Down
17 changes: 9 additions & 8 deletions src/EndUsersApplication.UnitTests/InvitationsApplicationSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace EndUsersApplication.UnitTests;
[Trait("Category", "Unit")]
public class InvitationsApplicationSpec
{
private const string TestingToken = "Ll4qhv77XhiXSqsTUc6icu56ZLrqu5p1gH9kT5IlHio";
private readonly InvitationsApplication _application;
private readonly Mock<ICallerContext> _caller;
private readonly Mock<IUserNotificationsService> _notificationsService;
Expand All @@ -48,7 +49,7 @@ public InvitationsApplicationSpec()
_notificationsService = new Mock<IUserNotificationsService>();
_tokensService = new Mock<ITokensService>();
_tokensService.Setup(ts => ts.CreateGuestInvitationToken())
.Returns("aninvitationtoken");
.Returns(TestingToken);

_application =
new InvitationsApplication(_recorder.Object, idFactory.Object, _tokensService.Object,
Expand Down Expand Up @@ -192,7 +193,7 @@ await invitee.InviteGuestAsync(_tokensService.Object, "aninviterid".ToId(),
result.Value.EmailAddress.Should().Be("[email protected]");
result.Value.FirstName.Should().Be("Aninvitee");
result.Value.LastName.Should().BeNull();
_notificationsService.Verify(ns => ns.NotifyGuestInvitationToPlatformAsync(_caller.Object, "aninvitationtoken",
_notificationsService.Verify(ns => ns.NotifyGuestInvitationToPlatformAsync(_caller.Object, TestingToken,
"[email protected]", "Aninvitee", "aninviterdisplayname", It.IsAny<CancellationToken>()));
}

Expand Down Expand Up @@ -240,7 +241,7 @@ public async Task WhenInviteGuestAsync_ThenInvitesGuest()
_userProfilesService.Verify(ups =>
ups.FindPersonByEmailAddressPrivateAsync(_caller.Object, "[email protected]",
It.IsAny<CancellationToken>()));
_notificationsService.Verify(ns => ns.NotifyGuestInvitationToPlatformAsync(_caller.Object, "aninvitationtoken",
_notificationsService.Verify(ns => ns.NotifyGuestInvitationToPlatformAsync(_caller.Object, TestingToken,
"[email protected]", "Aninvitee", "aninviterdisplayname", It.IsAny<CancellationToken>()));
_repository.Verify(rep => rep.LoadAsync("anid".ToId(), It.IsAny<CancellationToken>()), Times.Never);
_repository.Verify(rep => rep.LoadAsync("aninviterid".ToId(), It.IsAny<CancellationToken>()));
Expand All @@ -260,7 +261,7 @@ public async Task WhenResendGuestInvitationAsyncAndInvitationNotExists_ThenRetur
.ReturnsAsync(Optional<EndUserRoot>.None);

var result =
await _application.ResendGuestInvitationAsync(_caller.Object, "aninvitationtoken", CancellationToken.None);
await _application.ResendGuestInvitationAsync(_caller.Object, TestingToken, CancellationToken.None);

result.Should().BeError(ErrorCode.EntityNotFound);
}
Expand Down Expand Up @@ -295,10 +296,10 @@ await invitee.InviteGuestAsync(_tokensService.Object, "aninviterid".ToId(),
});

var result =
await _application.ResendGuestInvitationAsync(_caller.Object, "aninvitationtoken", CancellationToken.None);
await _application.ResendGuestInvitationAsync(_caller.Object, TestingToken, CancellationToken.None);

result.Should().BeSuccess();
_notificationsService.Verify(ns => ns.NotifyGuestInvitationToPlatformAsync(_caller.Object, "aninvitationtoken",
_notificationsService.Verify(ns => ns.NotifyGuestInvitationToPlatformAsync(_caller.Object, TestingToken,
"[email protected]", "Aninvitee", "aninviterdisplayname", It.IsAny<CancellationToken>()));
_repository.Verify(rep => rep.LoadAsync("anid".ToId(), It.IsAny<CancellationToken>()), Times.Never);
_repository.Verify(rep => rep.LoadAsync("aninviterid".ToId(), It.IsAny<CancellationToken>()));
Expand All @@ -318,7 +319,7 @@ public async Task WhenVerifyGuestInvitationAsyncAndInvitationNotExists_ThenRetur
.ReturnsAsync(Optional<EndUserRoot>.None);

var result =
await _application.VerifyGuestInvitationAsync(_caller.Object, "aninvitationtoken", CancellationToken.None);
await _application.VerifyGuestInvitationAsync(_caller.Object, TestingToken, CancellationToken.None);

result.Should().BeError(ErrorCode.EntityNotFound);
}
Expand All @@ -341,7 +342,7 @@ await invitee.InviteGuestAsync(_tokensService.Object, "aninviterid".ToId(),
.ReturnsAsync(invitee.ToOptional());

var result =
await _application.VerifyGuestInvitationAsync(_caller.Object, "aninvitationtoken", CancellationToken.None);
await _application.VerifyGuestInvitationAsync(_caller.Object, TestingToken, CancellationToken.None);

result.Should().BeSuccess();
result.Value.EmailAddress.Should().Be("[email protected]");
Expand Down
3 changes: 2 additions & 1 deletion src/EndUsersDomain.UnitTests/EndUserRootSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace EndUsersDomain.UnitTests;
[UsedImplicitly]
public class EndUserRootSpec
{
private const string TestingToken = "Ll4qhv77XhiXSqsTUc6icu56ZLrqu5p1gH9kT5IlHio";
private static EndUserRoot CreateOrgOwner(Mock<IRecorder> recorder, string organizationId,
UserClassification classification = UserClassification.Person)
{
Expand Down Expand Up @@ -86,7 +87,7 @@ public GivenAPerson()
});
_tokensService = new Mock<ITokensService>();
_tokensService.Setup(ts => ts.CreateGuestInvitationToken())
.Returns("aninvitationtoken");
.Returns(TestingToken);

_user = EndUserRoot.Create(_recorder.Object, _identifierFactory.Object, UserClassification.Person).Value;
}
Expand Down
53 changes: 37 additions & 16 deletions src/EndUsersDomain.UnitTests/GuestInvitationSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ namespace EndUsersDomain.UnitTests;
public class GuestInvitationSpec
{
private readonly EmailAddress _inviteeEmailAddress;

private const string TestingToken = "Ll4qhv77XhiXSqsTUc6icu56ZLrqu5p1gH9kT5IlHio";

public GuestInvitationSpec()
{
_inviteeEmailAddress = EmailAddress.Create("[email protected]").Value;
Expand All @@ -35,14 +36,24 @@ public void WhenCreateEmpty_ThenAssigned()
invitation.AcceptedAtUtc.Should().BeNull();
}

[Fact]
public void WhenInviteAndInvalidToken_ThenReturnsError()
{
var invitation = GuestInvitation.Empty;

var result = invitation.Invite("aninvalidtoken", _inviteeEmailAddress, "aninviterid".ToId());

result.Should().BeError(ErrorCode.Validation, Resources.GuestInvitation_InvalidToken);
}

[Fact]
public void WhenInviteAndAlreadyInvited_ThenReturnsError()
{
var invitation = GuestInvitation.Empty;
invitation = invitation.Invite("atoken", _inviteeEmailAddress,
invitation = invitation.Invite(TestingToken, _inviteeEmailAddress,
"aninviterid".ToId()).Value;

var result = invitation.Invite("atoken", _inviteeEmailAddress, "aninviterid".ToId());
var result = invitation.Invite(TestingToken, _inviteeEmailAddress, "aninviterid".ToId());

result.Should().BeError(ErrorCode.RuleViolation, Resources.GuestInvitation_AlreadyInvited);
}
Expand All @@ -51,11 +62,11 @@ public void WhenInviteAndAlreadyInvited_ThenReturnsError()
public void WhenInviteAndAlreadyAccepted_ThenReturnsError()
{
var invitation = GuestInvitation.Empty;
invitation = invitation.Invite("atoken", _inviteeEmailAddress,
invitation = invitation.Invite(TestingToken, _inviteeEmailAddress,
"aninviterid".ToId()).Value;
invitation = invitation.Accept(_inviteeEmailAddress).Value;

var result = invitation.Invite("atoken", _inviteeEmailAddress, "aninviterid".ToId());
var result = invitation.Invite(TestingToken, _inviteeEmailAddress, "aninviterid".ToId());

result.Should().BeError(ErrorCode.RuleViolation, Resources.GuestInvitation_AlreadyInvited);
}
Expand All @@ -65,13 +76,13 @@ public void WhenInvite_ThenIsInvited()
{
var invitation = GuestInvitation.Empty;

invitation = invitation.Invite("atoken", _inviteeEmailAddress,
invitation = invitation.Invite(TestingToken, _inviteeEmailAddress,
"aninviterid".ToId()).Value;

invitation.IsInvited.Should().BeTrue();
invitation.IsStillOpen.Should().BeTrue();
invitation.IsAccepted.Should().BeFalse();
invitation.Token.Should().Be("atoken");
invitation.Token.Should().Be(TestingToken);
invitation.ExpiresOnUtc.Should().BeNear(DateTime.UtcNow.Add(GuestInvitation.DefaultTokenExpiry));
invitation.InvitedById.Should().Be("aninviterid".ToId());
invitation.InviteeEmailAddress!.Address.Should().Be("[email protected]");
Expand All @@ -80,12 +91,22 @@ public void WhenInvite_ThenIsInvited()
invitation.AcceptedAtUtc.Should().BeNull();
}

[Fact]
public void WhenRenewAndInvalidToken_ThenReturnsError()
{
var invitation = GuestInvitation.Empty;

var result = invitation.Renew("aninvalidtoken", _inviteeEmailAddress);

result.Should().BeError(ErrorCode.Validation, Resources.GuestInvitation_InvalidToken);
}

[Fact]
public void WhenRenewAndNotInvited_ThenReturnsError()
{
var invitation = GuestInvitation.Empty;

var result = invitation.Renew("atoken", _inviteeEmailAddress);
var result = invitation.Renew(TestingToken, _inviteeEmailAddress);

result.Should().BeError(ErrorCode.RuleViolation, Resources.GuestInvitation_NotInvited);
}
Expand All @@ -94,11 +115,11 @@ public void WhenRenewAndNotInvited_ThenReturnsError()
public void WhenRenewAndAlreadyAccepted_ThenReturnsError()
{
var invitation = GuestInvitation.Empty;
invitation = invitation.Invite("atoken", _inviteeEmailAddress,
invitation = invitation.Invite(TestingToken, _inviteeEmailAddress,
"aninviterid".ToId()).Value;
invitation = invitation.Accept(_inviteeEmailAddress).Value;

var result = invitation.Renew("atoken", _inviteeEmailAddress);
var result = invitation.Renew(TestingToken, _inviteeEmailAddress);

result.Should().BeError(ErrorCode.RuleViolation, Resources.GuestInvitation_AlreadyAccepted);
}
Expand All @@ -107,15 +128,15 @@ public void WhenRenewAndAlreadyAccepted_ThenReturnsError()
public void WhenRenewAndInvited_ThenIsRenewed()
{
var invitation = GuestInvitation.Empty;
invitation = invitation.Invite("atoken", _inviteeEmailAddress,
invitation = invitation.Invite(TestingToken, _inviteeEmailAddress,
"aninviterid".ToId()).Value;

invitation = invitation.Renew("atoken", _inviteeEmailAddress).Value;
invitation = invitation.Renew(TestingToken, _inviteeEmailAddress).Value;

invitation.IsInvited.Should().BeTrue();
invitation.IsStillOpen.Should().BeTrue();
invitation.IsAccepted.Should().BeFalse();
invitation.Token.Should().Be("atoken");
invitation.Token.Should().Be(TestingToken);
invitation.ExpiresOnUtc.Should().BeNear(DateTime.UtcNow.Add(GuestInvitation.DefaultTokenExpiry));
invitation.InvitedById.Should().Be("aninviterid".ToId());
invitation.InviteeEmailAddress!.Address.Should().Be("[email protected]");
Expand All @@ -138,7 +159,7 @@ public void WhenAcceptAndNotInvited_ThenReturnsError()
public void WhenAcceptAndAlreadyAccepted_ThenReturnsError()
{
var invitation = GuestInvitation.Empty;
invitation = invitation.Invite("atoken", _inviteeEmailAddress,
invitation = invitation.Invite(TestingToken, _inviteeEmailAddress,
"aninviterid".ToId()).Value;
invitation = invitation.Accept(_inviteeEmailAddress).Value;

Expand All @@ -152,15 +173,15 @@ public void WhenAcceptAndInvited_ThenIsAccepted()
{
var invitation = GuestInvitation.Empty;

invitation = invitation.Invite("atoken", _inviteeEmailAddress,
invitation = invitation.Invite(TestingToken, _inviteeEmailAddress,
"aninviterid".ToId()).Value;

invitation = invitation.Accept(_inviteeEmailAddress).Value;

invitation.IsInvited.Should().BeTrue();
invitation.IsStillOpen.Should().BeFalse();
invitation.IsAccepted.Should().BeTrue();
invitation.Token.Should().Be("atoken");
invitation.Token.Should().Be(TestingToken);
invitation.ExpiresOnUtc.Should().BeNull();
invitation.InvitedById.Should().Be("aninviterid".ToId());
invitation.InviteeEmailAddress!.Address.Should().Be("[email protected]");
Expand Down
6 changes: 5 additions & 1 deletion src/EndUsersDomain/EndUserRoot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ namespace EndUsersDomain;

public sealed partial class EndUserRoot : AggregateRootBase
{
#if TESTINGONLY
private const string TestingToken = "Ll4qhv77XhiXSqsTUc6icu56ZLrqu5p1gH9kT5IlHio";
#endif

public static Result<EndUserRoot, Error> Create(IRecorder recorder, IIdentifierFactory idFactory,
UserClassification classification)
{
Expand Down Expand Up @@ -613,7 +617,7 @@ public void TestingOnly_ExpireGuestInvitation()
#if TESTINGONLY
public void TestingOnly_InviteGuest(EmailAddress emailAddress)
{
GuestInvitation = GuestInvitation.Invite("atoken", emailAddress, "aninviter".ToId()).Value;
GuestInvitation = GuestInvitation.Invite(TestingToken, emailAddress, "aninviter".ToId()).Value;
}
#endif

Expand Down
13 changes: 13 additions & 0 deletions src/EndUsersDomain/GuestInvitation.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Common;
using Common.Extensions;
using Domain.Common.Extensions;
using Domain.Common.ValueObjects;
using Domain.Interfaces;
using Domain.Shared;
Expand Down Expand Up @@ -102,6 +103,12 @@ public Result<GuestInvitation, Error> Accept(EmailAddress acceptedWithEmail)

public Result<GuestInvitation, Error> Invite(string token, EmailAddress inviteeEmailAddress, Identifier invitedById)
{
if (token.IsInvalidParameter(Validations.Invitation.Token, nameof(token),
Resources.GuestInvitation_InvalidToken, out var error))
{
return error;
}

if (IsInvited)
{
return Error.RuleViolation(Resources.GuestInvitation_AlreadyInvited);
Expand All @@ -118,6 +125,12 @@ public Result<GuestInvitation, Error> Invite(string token, EmailAddress inviteeE

public Result<GuestInvitation, Error> Renew(string token, EmailAddress inviteeEmailAddress)
{
if (token.IsInvalidParameter(Validations.Invitation.Token, nameof(token),
Resources.GuestInvitation_InvalidToken, out var error))
{
return error;
}

if (!IsInvited)
{
return Error.RuleViolation(Resources.GuestInvitation_NotInvited);
Expand Down
9 changes: 9 additions & 0 deletions src/EndUsersDomain/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/EndUsersDomain/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@
<data name="GuestInvitation_AlreadyAccepted" xml:space="preserve">
<value>This invitation has already been accepted</value>
</data>
<data name="GuestInvitation_InvalidToken" xml:space="preserve">
<value>The Token for this invitation is invalid</value>
</data>
<data name="EndUserRoot_GuestInvitationNeverSent" xml:space="preserve">
<value>A guest invitation has not been sent yet</value>
</data>
Expand Down

0 comments on commit 063f3bd

Please sign in to comment.