Browse Source

Tests and fixes for invitation system.

pull/354/head
Sebastian Stehle 7 years ago
parent
commit
ff3ee5e3ab
  1. 11
      src/Squidex.Domain.Apps.Entities/Apps/Invitation/InvitationEmailEventConsumer.cs
  2. 10
      src/Squidex.Domain.Apps.Entities/Apps/Invitation/InvitationEmailSender.cs
  3. 4
      src/Squidex/appsettings.json
  4. 137
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEmailEventConsumerTests.cs
  5. 140
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEmailSenderTests.cs
  6. 2
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs

11
src/Squidex.Domain.Apps.Entities/Apps/Invitation/InvitationEmailEventConsumer.cs

@ -55,13 +55,16 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
public async Task On(Envelope<IEvent> @event)
{
if (@event.Payload is AppContributorAssigned appContributorAssigned && appContributorAssigned.Actor.IsClient)
if (@event.Payload is AppContributorAssigned appContributorAssigned && appContributorAssigned.Actor.IsSubject)
{
var assigner = await userResolver.FindByIdOrEmailAsync(appContributorAssigned.Actor.Identifier);
var assignerId = appContributorAssigned.Actor.Identifier;
var assigneeId = appContributorAssigned.ContributorId;
var assigner = await userResolver.FindByIdOrEmailAsync(assignerId);
if (assigner == null)
{
LogWarning($"Assigner {appContributorAssigned.Actor.Identifier} not found");
LogWarning($"Assigner {assignerId} not found");
return;
}
@ -69,7 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
if (assignee == null)
{
LogWarning($"Assignee {appContributorAssigned.ContributorId} not found");
LogWarning($"Assignee {assigneeId} not found");
return;
}

10
src/Squidex.Domain.Apps.Entities/Apps/Invitation/InvitationEmailSender.cs

@ -40,23 +40,23 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
public Task SendExistingUserEmailAsync(IUser assigner, IUser assignee, string appName)
{
return SendEmailAsync(texts.NewUserSubject, texts.NewUserBody, assigner, assignee, appName);
return SendEmailAsync(texts.ExistingUserSubject, texts.ExistingUserBody, assigner, assignee, appName);
}
public Task SendNewUserEmailAsync(IUser assigner, IUser assignee, string appName)
{
return SendEmailAsync(texts.ExistingUserBody, texts.ExistingUserSubject, assigner, assignee, appName);
return SendEmailAsync(texts.NewUserBody, texts.NewUserSubject, assigner, assignee, appName);
}
private async Task SendEmailAsync(string emailBody, string emailSubj, IUser assigner, IUser assignee, string appName)
private async Task SendEmailAsync(string emailSubj, string emailBody, IUser assigner, IUser assignee, string appName)
{
if (string.IsNullOrWhiteSpace(texts.NewUserSubject))
if (string.IsNullOrWhiteSpace(emailBody))
{
LogWarning("No email subject configured for new users");
return;
}
if (string.IsNullOrWhiteSpace(texts.NewUserBody))
if (string.IsNullOrWhiteSpace(emailSubj))
{
LogWarning("No email body configured for new users");
return;

4
src/Squidex/appsettings.json

@ -103,7 +103,7 @@
/*
* The email body when a new user is added as contributor.
*/
"newUserBody": "Welcome\n\nYou have been invited to Squidex CMS by $ASSIGNER_NAME ($ASSIGNER_EMAIL) and to app $",
"newUserBody": "You have been invited to join an app at Squidex CMS\n\nWelcome to Squidex\n$ASSIGNER_NAME ($ASSIGNER_EMAIL) has invited you to join app $APP_NAME at Squidex headless CMS.\nLogin with your Github, Google or Microsoft account to create a new user account and start editing content now.\n\nThank you very much,\nThe Squidex Team\n<<Start now!>> [$UI_URL]",
/*
* The email subject when an existing user is added as contributor.
*/
@ -111,7 +111,7 @@
/*
* The email body when an existing user is added as contributor.
*/
"existingUserBody": ""
"existingUserBody": "You have been invited to join an app at Squidex CMS\n\nWelcome to Squidex\n$ASSIGNER_NAME ($ASSIGNER_EMAIL) has invited you to join app $APP_NAME at Squidex headless CMS.\nLogin or reload the Management UI to see the app.\n\nThank you very much,\nThe Squidex Team\n<<Start now!>> [$UI_URL]"
}
},

137
tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEmailEventConsumerTests.cs

@ -0,0 +1,137 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using FakeItEasy;
using Squidex.Domain.Apps.Events.Apps;
using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Log;
using Squidex.Shared.Users;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Apps.Invitation
{
public class InvitationEmailEventConsumerTests
{
private readonly IInvitationEmailSender emailSender = A.Fake<IInvitationEmailSender>();
private readonly IUserResolver userResolver = A.Fake<IUserResolver>();
private readonly IUser assigner = A.Fake<IUser>();
private readonly IUser assignee = A.Fake<IUser>();
private readonly ISemanticLog log = A.Fake<ISemanticLog>();
private readonly string assignerId = Guid.NewGuid().ToString();
private readonly string assigneeId = Guid.NewGuid().ToString();
private readonly string appName = "my-app";
private readonly InvitationEmailEventConsumer sut;
public InvitationEmailEventConsumerTests()
{
sut = new InvitationEmailEventConsumer(emailSender, userResolver, log);
}
[Fact]
public async Task Should_ignore_contributors_assigned_by_clients()
{
var @event = Envelope.Create(CreateEvent(RefTokenType.Client, true));
await sut.On(@event);
A.CallTo(() => userResolver.FindByIdOrEmailAsync(A<string>.Ignored))
.MustNotHaveHappened();
A.CallTo(() => emailSender.SendNewUserEmailAsync(A<IUser>.Ignored, A<IUser>.Ignored, appName))
.MustNotHaveHappened();
}
[Fact]
public async Task Should_not_send_email_if_assigner_not_found()
{
var @event = Envelope.Create(CreateEvent(RefTokenType.Subject, true));
A.CallTo(() => userResolver.FindByIdOrEmailAsync(assignerId))
.Returns(Task.FromResult<IUser>(null));
await sut.On(@event);
A.CallTo(() => emailSender.SendNewUserEmailAsync(A<IUser>.Ignored, A<IUser>.Ignored, appName))
.MustNotHaveHappened();
MustLogWarning();
}
[Fact]
public async Task Should_not_send_email_if_assignee_not_found()
{
var @event = Envelope.Create(CreateEvent(RefTokenType.Subject, true));
A.CallTo(() => userResolver.FindByIdOrEmailAsync(assignerId))
.Returns(assigner);
A.CallTo(() => userResolver.FindByIdOrEmailAsync(assigneeId))
.Returns(Task.FromResult<IUser>(null));
await sut.On(@event);
A.CallTo(() => emailSender.SendNewUserEmailAsync(A<IUser>.Ignored, A<IUser>.Ignored, appName))
.MustNotHaveHappened();
MustLogWarning();
}
[Fact]
public async Task Should_send_email_for_new_user()
{
var @event = Envelope.Create(CreateEvent(RefTokenType.Subject, false));
A.CallTo(() => userResolver.FindByIdOrEmailAsync(assignerId))
.Returns(assigner);
A.CallTo(() => userResolver.FindByIdOrEmailAsync(assigneeId))
.Returns(assignee);
await sut.On(@event);
A.CallTo(() => emailSender.SendNewUserEmailAsync(assigner, assignee, appName))
.MustNotHaveHappened();
}
[Fact]
public async Task Should_send_email_for_existing_user()
{
var @event = Envelope.Create(CreateEvent(RefTokenType.Subject, true));
A.CallTo(() => userResolver.FindByIdOrEmailAsync(assignerId))
.Returns(assigner);
A.CallTo(() => userResolver.FindByIdOrEmailAsync(assigneeId))
.Returns(assignee);
await sut.On(@event);
A.CallTo(() => emailSender.SendExistingUserEmailAsync(assigner, assignee, appName))
.MustNotHaveHappened();
}
private void MustLogWarning()
{
A.CallTo(() => log.Log(SemanticLogLevel.Warning, A<None>.Ignored, A<Action<None, IObjectWriter>>.Ignored))
.MustHaveHappened();
}
private IEvent CreateEvent(string assignerType, bool isNew)
{
return new AppContributorAssigned
{
Actor = new RefToken(assignerType, assignerId),
AppId = new NamedId<Guid>(Guid.NewGuid(), appName),
ContributorId = assigneeId,
IsCreated = isNew
};
}
}
}

140
tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEmailSenderTests.cs

@ -0,0 +1,140 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using FakeItEasy;
using Microsoft.Extensions.Options;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Email;
using Squidex.Infrastructure.Log;
using Squidex.Shared.Identity;
using Squidex.Shared.Users;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Apps.Invitation
{
public class InvitationEmailSenderTests
{
private readonly IEmailSender emailSender = A.Fake<IEmailSender>();
private readonly IEmailUrlGenerator emailUrlGenerator = A.Fake<IEmailUrlGenerator>();
private readonly IUser assigner = A.Fake<IUser>();
private readonly IUser assignee = A.Fake<IUser>();
private readonly ISemanticLog log = A.Fake<ISemanticLog>();
private readonly string appName = "my-app";
private readonly string uiUrl = "my-ui";
private readonly InvitationEmailTextOptions texts = new InvitationEmailTextOptions();
private readonly InvitationEmailSender sut;
public InvitationEmailSenderTests()
{
A.CallTo(() => assigner.Email)
.Returns("sebastian@squidex.io");
A.CallTo(() => assigner.Claims)
.Returns(new List<Claim> { new Claim(SquidexClaimTypes.DisplayName, "Sebastian Stehle") });
A.CallTo(() => assignee.Email)
.Returns("qaisar@squidex.io");
A.CallTo(() => assignee.Claims)
.Returns(new List<Claim> { new Claim(SquidexClaimTypes.DisplayName, "Qaisar Ahmad") });
A.CallTo(() => emailUrlGenerator.GenerateUIUrl())
.Returns(uiUrl);
sut = new InvitationEmailSender(Options.Create(texts), emailSender, emailUrlGenerator, log);
}
[Fact]
public async Task Should_format_assigner_email_and_send_email()
{
await TestFormattingAsync("Email: $ASSIGNER_EMAIL", "Email: sebastian@squidex.io");
}
[Fact]
public async Task Should_format_assignee_email_and_send_email()
{
await TestFormattingAsync("Email: $ASSIGNEE_EMAIL", "Email: qaisar@squidex.io");
}
[Fact]
public async Task Should_format_assigner_name_and_send_email()
{
await TestFormattingAsync("Name: $ASSIGNER_NAME", "Name: Sebastian Stehle");
}
[Fact]
public async Task Should_format_assignee_name_and_send_email()
{
await TestFormattingAsync("Name: $ASSIGNEE_NAME", "Name: Qaisar Ahmad");
}
[Fact]
public async Task Should_format_app_name_and_send_email()
{
await TestFormattingAsync("App: $APP_NAME", "App: my-app");
}
[Fact]
public async Task Should_format_ui_url_and_send_email()
{
await TestFormattingAsync("UI: $UI_URL", "UI: my-ui");
}
[Fact]
public async Task Should_not_send_email_if_texts_for_new_user_are_empty()
{
await sut.SendNewUserEmailAsync(assigner, assignee, appName);
A.CallTo(() => emailSender.SendAsync(assignee.Email, A<string>.Ignored, A<string>.Ignored))
.MustNotHaveHappened();
MustLogWarning();
}
[Fact]
public async Task Should_not_send_email_if_texts_for_existing_user_are_empty()
{
await sut.SendExistingUserEmailAsync(assigner, assignee, appName);
A.CallTo(() => emailSender.SendAsync(assignee.Email, A<string>.Ignored, A<string>.Ignored))
.MustNotHaveHappened();
MustLogWarning();
}
[Fact]
public async Task Should_send_email_for_existing_user()
{
texts.ExistingUserSubject = "email-subject";
texts.ExistingUserBody = "email-body";
await sut.SendExistingUserEmailAsync(assigner, assignee, appName);
A.CallTo(() => emailSender.SendAsync(assignee.Email, "email-subject", "email-body"))
.MustHaveHappened();
}
private async Task TestFormattingAsync(string pattern, string result)
{
texts.NewUserSubject = pattern;
texts.NewUserBody = pattern;
await sut.SendNewUserEmailAsync(assigner, assignee, appName);
A.CallTo(() => emailSender.SendAsync(assignee.Email, result, result))
.MustHaveHappened();
}
private void MustLogWarning()
{
A.CallTo(() => log.Log(SemanticLogLevel.Warning, A<None>.Ignored, A<Action<None, IObjectWriter>>.Ignored))
.MustHaveHappened();
}
}
}

2
tests/Squidex.Domain.Apps.Entities.Tests/Apps/InviteUserCommandMiddlewareTests.cs → tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs

@ -12,7 +12,7 @@ using Squidex.Infrastructure.Commands;
using Squidex.Shared.Users;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Apps
namespace Squidex.Domain.Apps.Entities.Apps.Invitation
{
public class InviteUserCommandMiddlewareTests
{
Loading…
Cancel
Save