From b3e136943c38f9e512aa75f8f46d7a35a00ccbd4 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 13 Apr 2021 18:26:42 +0200 Subject: [PATCH] User in graphql. (#682) * User in graphql. * Formatting. --- .../GraphQL/GraphQLExecutionContext.cs | 32 ++++++++- .../GraphQL/Types/Assets/AssetGraphType.cs | 16 +++++ .../GraphQL/Types/Contents/ContentFields.cs | 16 +++++ .../Types/Contents/ContentGraphType.cs | 2 + .../Types/Primitives/EntityResolvers.cs | 9 +++ .../Contents/GraphQL/Types/UserGraphType.cs | 58 ++++++++++++++++ .../src/Squidex.Shared/Users/ClientUser.cs | 2 +- .../Controllers/Schemas/Models/SchemaDto.cs | 5 +- .../RuleEventFormatterCompareTests.cs | 13 +--- .../HandleRules/RuleEventFormatterTests.cs | 11 +-- .../TestHelpers/UserMocks.cs | 46 +++++++++++++ .../Apps/DomainObject/AppDomainObjectTests.cs | 6 +- .../Guards/GuardAppContributorsTests.cs | 6 +- .../InvitationEventConsumerTests.cs | 5 +- .../InviteUserCommandMiddlewareTests.cs | 22 ++---- .../Apps/Plans/UsageNotifierGrainTests.cs | 6 +- .../Backup/UserMappingTests.cs | 30 +++----- .../Comments/CommentTriggerHandlerTests.cs | 25 +++---- .../CommentsCommandMiddlewareTests.cs | 6 +- .../Contents/GraphQL/GraphQLQueriesTests.cs | 2 +- .../Contents/GraphQL/GraphQLTestBase.cs | 14 ++++ .../Contents/GraphQL/TestAsset.cs | 24 ++++++- .../Contents/GraphQL/TestContent.cs | 28 +++++++- .../NotificationEmailSenderTests.cs | 68 +++++++++---------- .../TestHelpers/Mocks.cs | 30 +++++--- 25 files changed, 341 insertions(+), 141 deletions(-) create mode 100644 backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/UserGraphType.cs create mode 100644 backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/UserMocks.cs diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs index 5dfc57be5..5510b4e8f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs @@ -16,6 +16,7 @@ using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Json.Objects; using Squidex.Log; +using Squidex.Shared.Users; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { @@ -24,6 +25,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL private static readonly List EmptyAssets = new List(); private static readonly List EmptyContents = new List(); private readonly IDataLoaderContextAccessor dataLoaders; + private readonly IUserResolver userResolver; public IUrlGenerator UrlGenerator { get; } @@ -35,10 +37,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL public GraphQLExecutionContext(IAssetQueryService assetQuery, IContentQueryService contentQuery, Context context, - IDataLoaderContextAccessor dataLoaders, ICommandBus commandBus, IUrlGenerator urlGenerator, ISemanticLog log) + IDataLoaderContextAccessor dataLoaders, + ICommandBus commandBus, IUrlGenerator urlGenerator, IUserResolver userResolver, + ISemanticLog log) : base(assetQuery, contentQuery) { this.dataLoaders = dataLoaders; + this.userResolver = userResolver; CommandBus = commandBus; @@ -51,6 +56,20 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL Log = log; } + public async Task FindUserAsync(RefToken refToken) + { + if (refToken.IsClient) + { + return new ClientUser(refToken); + } + else + { + var dataLoader = GetUserLoader(); + + return await dataLoader.LoadAsync(refToken.Identifier).GetResultAsync(); + } + } + public async Task FindAssetAsync(DomainId id) { var dataLoader = GetAssetsLoader(); @@ -115,6 +134,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL }); } + private IDataLoader GetUserLoader() + { + return dataLoaders.Context.GetOrAddBatchLoader(nameof(GetUserLoader), + async batch => + { + var result = await userResolver.QueryManyAsync(batch.ToArray()); + + return result; + }); + } + private static async Task> LoadManyAsync(IDataLoader dataLoader, ICollection keys) where T : class { var contents = await Task.WhenAll(keys.Select(x => dataLoader.LoadAsync(x).GetResultAsync())); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Assets/AssetGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Assets/AssetGraphType.cs index a324ba1bf..6836294d3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Assets/AssetGraphType.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Assets/AssetGraphType.cs @@ -54,6 +54,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets Description = "The user that has created the asset." }); + AddField(new FieldType + { + Name = "createdByUser", + ResolvedType = UserGraphType.NonNull, + Resolver = EntityResolvers.CreatedByUser, + Description = "The full info of the user that has created the asset." + }); + AddField(new FieldType { Name = "lastModified", @@ -70,6 +78,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets Description = "The user that has updated the asset last." }); + AddField(new FieldType + { + Name = "lastModifiedByUser", + ResolvedType = UserGraphType.NonNull, + Resolver = EntityResolvers.LastModifiedByUser, + Description = "The full info of the user that has created the asset." + }); + AddField(new FieldType { Name = "mimeType", diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentFields.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentFields.cs index 2af627aef..e12e697f9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentFields.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentFields.cs @@ -46,6 +46,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents Description = "The user that has created the content." }; + public static readonly FieldType CreatedByUser = new FieldType + { + Name = "createdByUser", + ResolvedType = UserGraphType.NonNull, + Resolver = EntityResolvers.CreatedByUser, + Description = "The full info of the user that has created the content." + }; + public static readonly FieldType LastModified = new FieldType { Name = "lastModified", @@ -62,6 +70,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents Description = "The user that has updated the content last." }; + public static readonly FieldType LastModifiedByUser = new FieldType + { + Name = "lastModifiedByUser", + ResolvedType = UserGraphType.NonNull, + Resolver = EntityResolvers.LastModifiedByUser, + Description = "The full info of the user that has updated the content last." + }; + public static readonly FieldType Status = new FieldType { Name = "status", diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentGraphType.cs index d52935541..2a5eecc29 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentGraphType.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentGraphType.cs @@ -27,8 +27,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents AddField(ContentFields.Version); AddField(ContentFields.Created); AddField(ContentFields.CreatedBy); + AddField(ContentFields.CreatedByUser); AddField(ContentFields.LastModified); AddField(ContentFields.LastModifiedBy); + AddField(ContentFields.LastModifiedByUser); AddField(ContentFields.Status); AddField(ContentFields.StatusColor); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/EntityResolvers.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/EntityResolvers.cs index c93998acb..ae2aecf95 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/EntityResolvers.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/EntityResolvers.cs @@ -7,6 +7,8 @@ using System; using GraphQL.Resolvers; +using Squidex.Infrastructure; +using Squidex.Shared.Users; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives { @@ -15,13 +17,20 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives public static readonly IFieldResolver Id = Resolve(x => x.Id.ToString()); public static readonly IFieldResolver Created = Resolve(x => x.Created.ToDateTimeUtc()); public static readonly IFieldResolver CreatedBy = Resolve(x => x.CreatedBy.ToString()); + public static readonly IFieldResolver CreatedByUser = ResolveUser(x => x.CreatedBy); public static readonly IFieldResolver LastModified = Resolve(x => x.LastModified.ToDateTimeUtc()); public static readonly IFieldResolver LastModifiedBy = Resolve(x => x.LastModifiedBy.ToString()); + public static readonly IFieldResolver LastModifiedByUser = ResolveUser(x => x.LastModifiedBy); public static readonly IFieldResolver Version = Resolve(x => x.Version); private static IFieldResolver Resolve(Func resolver) { return Resolvers.Sync(resolver); } + + private static IFieldResolver ResolveUser(Func resolver) + { + return Resolvers.Async((source, _, context) => context.FindUserAsync(resolver(source))); + } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/UserGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/UserGraphType.cs new file mode 100644 index 000000000..484feae8e --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/UserGraphType.cs @@ -0,0 +1,58 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using GraphQL.Resolvers; +using GraphQL.Types; +using Squidex.Shared.Identity; +using Squidex.Shared.Users; + +namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types +{ + internal sealed class UserGraphType : ObjectGraphType + { + public static readonly IGraphType Nullable = new UserGraphType(); + + public static readonly IGraphType NonNull = new NonNullGraphType(Nullable); + + public UserGraphType() + { + Name = "User"; + + AddField(new FieldType + { + Name = "id", + Resolver = Resolve(x => x.Id), + ResolvedType = AllTypes.NonNullString, + Description = "The id of the user." + }); + + AddField(new FieldType + { + Name = "displayName", + Resolver = Resolve(x => x.Claims.DisplayName()), + ResolvedType = AllTypes.String, + Description = "The display name of the user." + }); + + AddField(new FieldType + { + Name = "email", + Resolver = Resolve(x => x.Email), + ResolvedType = AllTypes.String, + Description = "The email of the user." + }); + + Description = "A user that created or modified a content or asset."; + } + + private static IFieldResolver Resolve(Func resolver) + { + return Resolvers.Sync(resolver); + } + } +} diff --git a/backend/src/Squidex.Shared/Users/ClientUser.cs b/backend/src/Squidex.Shared/Users/ClientUser.cs index d2ab35cce..7bae92707 100644 --- a/backend/src/Squidex.Shared/Users/ClientUser.cs +++ b/backend/src/Squidex.Shared/Users/ClientUser.cs @@ -49,7 +49,7 @@ namespace Squidex.Shared.Users claims = new List { new Claim(OpenIdClaims.ClientId, token.Identifier), - new Claim(SquidexClaimTypes.DisplayName, token.ToString()) + new Claim(SquidexClaimTypes.DisplayName, token.Identifier) }; } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs index e53f9d30c..161687673 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs @@ -106,7 +106,6 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models if (resources.CanCreateContent(Name)) { AddPostLink("contents/create", resources.Url(x => nameof(x.PostContent), values)); - AddPostLink("contents/create/publish", resources.Url(x => nameof(x.PostContent), values) + "?publish=true"); } @@ -130,10 +129,10 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models AddPutLink("fields/order", resources.Url(x => nameof(x.PutSchemaFieldOrdering), values)); AddPutLink("update", resources.Url(x => nameof(x.PutSchema), values)); + AddPutLink("update/category", resources.Url(x => nameof(x.PutCategory), values)); + AddPutLink("update/rules", resources.Url(x => nameof(x.PutRules), values)); AddPutLink("update/sync", resources.Url(x => nameof(x.PutSchemaSync), values)); AddPutLink("update/urls", resources.Url(x => nameof(x.PutPreviewUrls), values)); - AddPutLink("update/rules", resources.Url(x => nameof(x.PutRules), values)); - AddPutLink("update/category", resources.Url(x => nameof(x.PutCategory), values)); } if (resources.CanUpdateSchemaScripts(Name)) diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterCompareTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterCompareTests.cs index 9877ef6ef..62df9157c 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterCompareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterCompareTests.cs @@ -34,7 +34,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules { public class RuleEventFormatterCompareTests { - private readonly IUser user = A.Fake(); + private readonly IUser user = UserMocks.User("user123", "me@email.com", "me"); private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); @@ -74,15 +74,6 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules A.CallTo(() => urlGenerator.AssetContent(appId, "file-name")) .Returns("asset-content-slug-url"); - A.CallTo(() => user.Id) - .Returns("user123"); - - A.CallTo(() => user.Email) - .Returns("me@email.com"); - - A.CallTo(() => user.Claims) - .Returns(new List { new Claim(SquidexClaimTypes.DisplayName, "me") }); - var formatters = new IRuleEventFormatter[] { new PredefinedPatternsFormatter(urlGenerator), @@ -247,7 +238,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules var result = await sut.FormatAsync(script, @event); - Assert.Equal("From client:android (client:android, android)", result); + Assert.Equal("From android (client:android, android)", result); } [Theory] diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs index 5c9ccfd14..24e2ff73a 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs @@ -32,7 +32,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules { public class RuleEventFormatterTests { - private readonly IUser user = A.Fake(); + private readonly IUser user = UserMocks.User("user123", "me@email.com", "me"); private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); @@ -68,15 +68,6 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules A.CallTo(() => urlGenerator.AssetContent(appId, assetId.ToString())) .Returns("asset-content-url"); - A.CallTo(() => user.Id) - .Returns("user123"); - - A.CallTo(() => user.Email) - .Returns("me@email.com"); - - A.CallTo(() => user.Claims) - .Returns(new List { new Claim(SquidexClaimTypes.DisplayName, "me") }); - var formatters = new IRuleEventFormatter[] { new PredefinedPatternsFormatter(urlGenerator), diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/UserMocks.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/UserMocks.cs new file mode 100644 index 000000000..f2855a95d --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/UserMocks.cs @@ -0,0 +1,46 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; +using System.Security.Claims; +using FakeItEasy; +using Squidex.Shared.Identity; +using Squidex.Shared.Users; + +namespace Squidex.Domain.Apps.Core.TestHelpers +{ + public static class UserMocks + { + public static IUser User(string id, string? email = null, string? name = null, bool consent = false) + { + var claims = new List(); + + if (!string.IsNullOrWhiteSpace(name)) + { + claims.Add(new Claim(SquidexClaimTypes.DisplayName, name)); + } + + if (consent) + { + claims.Add(new Claim(SquidexClaimTypes.Consent, "True")); + } + + var user = A.Fake(); + + A.CallTo(() => user.Id) + .Returns(id); + + A.CallTo(() => user.Email) + .Returns(email ?? id); + + A.CallTo(() => user.Claims) + .Returns(claims); + + return user; + } + } +} diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs index dd4d67c5d..5746b0d38 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Plans; using Squidex.Domain.Apps.Entities.TestHelpers; @@ -26,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject { private readonly IAppPlansProvider appPlansProvider = A.Fake(); private readonly IAppPlanBillingManager appPlansBillingManager = A.Fake(); - private readonly IUser user = A.Fake(); + private readonly IUser user; private readonly IUserResolver userResolver = A.Fake(); private readonly string contributorId = DomainId.NewGuid().ToString(); private readonly string clientId = "client"; @@ -48,8 +49,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject public AppDomainObjectTests() { - A.CallTo(() => user.Id) - .Returns(contributorId); + user = UserMocks.User(contributorId); A.CallTo(() => userResolver.FindByIdOrEmailAsync(contributorId)) .Returns(user); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppContributorsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppContributorsTests.cs index 5bb52c4dd..b864b763a 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppContributorsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppContributorsTests.cs @@ -23,9 +23,9 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject.Guards { public class GuardAppContributorsTests : IClassFixture { - private readonly IUser user1 = A.Fake(); - private readonly IUser user2 = A.Fake(); - private readonly IUser user3 = A.Fake(); + private readonly IUser user1 = UserMocks.User("1"); + private readonly IUser user2 = UserMocks.User("2"); + private readonly IUser user3 = UserMocks.User("3"); private readonly IUserResolver users = A.Fake(); private readonly IAppLimitsPlan appPlan = A.Fake(); private readonly AppContributors contributors_0 = AppContributors.Empty; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEventConsumerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEventConsumerTests.cs index b95dd8002..d800811eb 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEventConsumerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEventConsumerTests.cs @@ -9,6 +9,7 @@ using System; using System.Threading.Tasks; using FakeItEasy; using NodaTime; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Notifications; using Squidex.Domain.Apps.Events.Apps; using Squidex.Infrastructure; @@ -23,8 +24,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation { private readonly INotificationSender notificatíonSender = A.Fake(); private readonly IUserResolver userResolver = A.Fake(); - private readonly IUser assigner = A.Fake(); - private readonly IUser assignee = A.Fake(); + private readonly IUser assigner = UserMocks.User("1"); + private readonly IUser assignee = UserMocks.User("2"); private readonly ISemanticLog log = A.Fake(); private readonly string assignerId = DomainId.NewGuid().ToString(); private readonly string assigneeId = DomainId.NewGuid().ToString(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs index afdf08572..8d3614266 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using FakeItEasy; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; @@ -37,9 +38,9 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation new CommandContext(command, commandBus) .Complete(app); - var user = CreateUser("123"); + var user = UserMocks.User("123", command.ContributorId); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync("me@email.com", true)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true)) .Returns((user, true)); await sut.HandleAsync(context); @@ -47,7 +48,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation Assert.Same(context.Result().App, app); Assert.Equal(user.Id, command.ContributorId); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync("me@email.com", true)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true)) .MustHaveHappened(); } @@ -60,9 +61,9 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation new CommandContext(command, commandBus) .Complete(app); - var user = CreateUser("123"); + var user = UserMocks.User("123", command.ContributorId); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync("me@email.com", true)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true)) .Returns((user, false)); await sut.HandleAsync(context); @@ -70,7 +71,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation Assert.Same(context.Result(), app); Assert.Equal(user.Id, command.ContributorId); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync("me@email.com", true)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true)) .MustHaveHappened(); } @@ -103,14 +104,5 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(A._, A._)) .MustNotHaveHappened(); } - - private static IUser CreateUser(string id) - { - var user = A.Fake(); - - A.CallTo(() => user.Id).Returns(id); - - return user; - } } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/UsageNotifierGrainTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/UsageNotifierGrainTests.cs index 77231aecf..7036283a6 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/UsageNotifierGrainTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/UsageNotifierGrainTests.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using FakeItEasy; using NodaTime; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Notifications; using Squidex.Infrastructure.Orleans; using Squidex.Shared.Users; @@ -157,10 +158,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans { if (email != null) { - var user = A.Fake(); - - A.CallTo(() => user.Email) - .Returns(email); + var user = UserMocks.User(id, email); A.CallTo(() => userResolver.FindByIdOrEmailAsync(id)) .Returns(user); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/UserMappingTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/UserMappingTests.cs index 940144f5d..8c6f057f5 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/UserMappingTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/UserMappingTests.cs @@ -29,13 +29,13 @@ namespace Squidex.Domain.Apps.Entities.Backup [Fact] public async Task Should_backup_users_but_no_clients() { - sut.Backup("user1"); - sut.Backup(Subject("user2")); + sut.Backup("1"); + sut.Backup(Subject("2")); sut.Backup(Client("client")); - var user1 = CreateUser("user1", "mail1@squidex.io"); - var user2 = CreateUser("user2", "mail2@squidex.io"); + var user1 = UserMocks.User("1", "1@email.com"); + var user2 = UserMocks.User("2", "1@email.com"); var users = new Dictionary { @@ -67,8 +67,8 @@ namespace Squidex.Domain.Apps.Entities.Backup [Fact] public async Task Should_restore_users() { - var user1 = CreateUser("user1", "mail1@squidex.io"); - var user2 = CreateUser("user2", "mail2@squidex.io"); + var user1 = UserMocks.User("1", "1@email.com"); + var user2 = UserMocks.User("2", "2@email.com"); var reader = SetupReader(user1, user2); @@ -82,11 +82,11 @@ namespace Squidex.Domain.Apps.Entities.Backup await sut.RestoreAsync(reader, userResolver); - Assert.True(sut.TryMap("user1_old", out var mapped1)); - Assert.True(sut.TryMap(Subject("user2_old"), out var mapped2)); + Assert.True(sut.TryMap("1_old", out var mapped1)); + Assert.True(sut.TryMap(Subject("2_old"), out var mapped2)); - Assert.Equal(Subject("user1"), mapped1); - Assert.Equal(Subject("user2"), mapped2); + Assert.Equal(Subject("1"), mapped1); + Assert.Equal(Subject("2"), mapped2); } [Fact] @@ -107,16 +107,6 @@ namespace Squidex.Domain.Apps.Entities.Backup Assert.Same(client, mapped); } - private static IUser CreateUser(string id, string email) - { - var user = A.Fake(); - - A.CallTo(() => user.Id).Returns(id); - A.CallTo(() => user.Email).Returns(email); - - return user; - } - private static IBackupReader SetupReader(params IUser[] users) { var storedUsers = users.ToDictionary(x => $"{x.Id}_old", x => x.Email); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentTriggerHandlerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentTriggerHandlerTests.cs index 1b3a6cdef..4971467da 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentTriggerHandlerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentTriggerHandlerTests.cs @@ -16,6 +16,7 @@ using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; using Squidex.Domain.Apps.Core.Rules.Triggers; using Squidex.Domain.Apps.Core.Scripting; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events.Comments; using Squidex.Domain.Apps.Events.Contents; @@ -52,8 +53,8 @@ namespace Squidex.Domain.Apps.Entities.Comments [Fact] public async Task Should_create_enriched_events() { - var user1 = CreateUser("1"); - var user2 = CreateUser("2"); + var user1 = UserMocks.User("1"); + var user2 = UserMocks.User("2"); var users = new List { user1, user2 }; var userIds = users.Select(x => x.Id).ToArray(); @@ -79,8 +80,8 @@ namespace Squidex.Domain.Apps.Entities.Comments [Fact] public async Task Should_not_create_enriched_events_when_users_cannot_be_resolved() { - var user1 = CreateUser("1"); - var user2 = CreateUser("2"); + var user1 = UserMocks.User("1"); + var user2 = UserMocks.User("2"); var users = new List { user1, user2 }; var userIds = users.Select(x => x.Id).ToArray(); @@ -213,9 +214,9 @@ namespace Squidex.Domain.Apps.Entities.Comments [Fact] public void Should_trigger_check_when_email_is_correct() { - TestForRealCondition("event.mentionedUser.email == 'sebastian@squidex.io'", (handler, trigger) => + TestForRealCondition("event.mentionedUser.email == '1@email.com'", (handler, trigger) => { - var user = CreateUser("1"); + var user = UserMocks.User("1", "1@email.com"); var result = handler.Trigger(new EnrichedCommentEvent { MentionedUser = user }, trigger); @@ -228,7 +229,7 @@ namespace Squidex.Domain.Apps.Entities.Comments { TestForRealCondition("event.mentionedUser.email == 'other@squidex.io'", (handler, trigger) => { - var user = CreateUser("1"); + var user = UserMocks.User("1"); var result = handler.Trigger(new EnrichedCommentEvent { MentionedUser = user }, trigger); @@ -262,16 +263,6 @@ namespace Squidex.Domain.Apps.Entities.Comments }); } - private static IUser CreateUser(string id, string email = "sebastian@squidex.io") - { - var user = A.Fake(); - - A.CallTo(() => user.Id).Returns(id); - A.CallTo(() => user.Email).Returns(email); - - return user; - } - private void TestForRealCondition(string condition, Action action) { var trigger = new CommentTrigger diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/DomainObject/CommentsCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/DomainObject/CommentsCommandMiddlewareTests.cs index 29cf5fe4f..f4e81bc49 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/DomainObject/CommentsCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/DomainObject/CommentsCommandMiddlewareTests.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using FakeItEasy; using Orleans; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Comments.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -138,10 +139,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.DomainObject private void SetupUser(string id, string email) { - var user = A.Fake(); - - A.CallTo(() => user.Id).Returns(id); - A.CallTo(() => user.Email).Returns(email); + var user = UserMocks.User(id, email); A.CallTo(() => userResolver.FindByIdOrEmailAsync(email)) .Returns(user); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs index 4ad01c394..0796f17f0 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs @@ -229,7 +229,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL created = content.Created, createdBy = "subject:user1", lastModified = content.LastModified, - lastModifiedBy = "subject:user2", + lastModifiedBy = "client:client1", status = "DRAFT", statusColor = "red", url = $"contents/my-schema/{content.Id}", diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs index 3ae16e79f..99b434ee4 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs @@ -6,6 +6,7 @@ // ========================================================================== using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using FakeItEasy; using GraphQL; @@ -32,6 +33,7 @@ using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Json; using Squidex.Log; using Squidex.Shared; +using Squidex.Shared.Users; using Xunit; #pragma warning disable SA1401 // Fields must be private @@ -46,6 +48,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL protected readonly IAssetQueryService assetQuery = A.Fake(); protected readonly ICommandBus commandBus = A.Fake(); protected readonly IContentQueryService contentQuery = A.Fake(); + protected readonly IUserResolver userResolver = A.Fake(); protected readonly ISchemaEntity schema; protected readonly ISchemaEntity schemaRef1; protected readonly ISchemaEntity schemaRef2; @@ -63,6 +66,16 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { app = Mocks.App(appId, Language.DE, Language.GermanGermany); + A.CallTo(() => userResolver.QueryManyAsync(A._)) + .ReturnsLazily(x => + { + var ids = x.GetArgument(0)!; + + var users = ids.Select(id => UserMocks.User(id, $"{id}@email.com", $"name_{id}")); + + return Task.FromResult(users.ToDictionary(x => x.Id)); + }); + var schemaDef = new Schema(schemaId.Name) .Publish() @@ -201,6 +214,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL .AddSingleton(contentQuery) .AddSingleton(dataLoaderContext) .AddSingleton(dataLoaderListener) + .AddSingleton(userResolver) .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestAsset.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestAsset.cs index 57a8a2d0e..d478dce41 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestAsset.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestAsset.cs @@ -20,8 +20,18 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL version created createdBy + createdByUser { + id, + email, + displayName + } lastModified lastModifiedBy + lastModifiedByUser { + id, + email, + displayName + } url thumbnailUrl sourceUrl @@ -54,7 +64,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL Created = now, CreatedBy = RefToken.User("user1"), LastModified = now, - LastModifiedBy = RefToken.User("user2"), + LastModifiedBy = RefToken.Client("client1"), FileName = "MyFile.png", Slug = "myfile.png", FileSize = 1024, @@ -85,8 +95,20 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL version = asset.Version, created = asset.Created, createdBy = asset.CreatedBy.ToString(), + createdByUser = new + { + id = asset.CreatedBy.Identifier, + email = $"{asset.CreatedBy.Identifier}@email.com", + displayName = $"name_{asset.CreatedBy.Identifier}" + }, lastModified = asset.LastModified, lastModifiedBy = asset.LastModifiedBy.ToString(), + lastModifiedByUser = new + { + id = asset.LastModifiedBy.Identifier, + email = $"{asset.LastModifiedBy}", + displayName = asset.LastModifiedBy.Identifier + }, url = $"assets/{asset.AppId.Name}/{asset.Id}", thumbnailUrl = $"assets/{asset.AppId.Name}/{asset.Id}?width=100", sourceUrl = $"assets/source/{asset.Id}", diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs index d672a39cf..9098be300 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs @@ -20,8 +20,18 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL version created createdBy + createdByUser { + id, + email, + displayName + } lastModified lastModifiedBy + lastModifiedByUser { + id, + email, + displayName + } status statusColor url @@ -148,7 +158,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL Created = now, CreatedBy = RefToken.User("user1"), LastModified = now, - LastModifiedBy = RefToken.User("user2"), + LastModifiedBy = RefToken.Client("client1"), Data = data, SchemaId = schemaId, Status = Status.Draft, @@ -192,9 +202,21 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL id = content.Id, version = 1, created = content.Created, - createdBy = "subject:user1", + createdBy = content.CreatedBy.ToString(), + createdByUser = new + { + id = content.CreatedBy.Identifier, + email = $"{content.CreatedBy.Identifier}@email.com", + displayName = $"name_{content.CreatedBy.Identifier}" + }, lastModified = content.LastModified, - lastModifiedBy = "subject:user2", + lastModifiedBy = content.LastModifiedBy.ToString(), + lastModifiedByUser = new + { + id = content.LastModifiedBy.Identifier, + email = $"{content.LastModifiedBy}", + displayName = content.LastModifiedBy.Identifier + }, status = "DRAFT", statusColor = "red", url = $"contents/my-schema/{content.Id}", diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Notifications/NotificationEmailSenderTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Notifications/NotificationEmailSenderTests.cs index 2f9db703a..feb57f2b6 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Notifications/NotificationEmailSenderTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Notifications/NotificationEmailSenderTests.cs @@ -6,16 +6,14 @@ // ========================================================================== using System; -using System.Collections.Generic; -using System.Security.Claims; using System.Threading; using System.Threading.Tasks; using FakeItEasy; using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Core; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Infrastructure.Email; using Squidex.Log; -using Squidex.Shared.Identity; using Squidex.Shared.Users; using Xunit; @@ -25,11 +23,9 @@ namespace Squidex.Domain.Apps.Entities.Notifications { private readonly IEmailSender emailSender = A.Fake(); private readonly IUrlGenerator urlGenerator = A.Fake(); - private readonly IUser assigner = A.Fake(); - private readonly IUser user = A.Fake(); + private readonly IUser assigner = UserMocks.User("1", "1@email.com", "user1"); + private readonly IUser assigned = UserMocks.User("2", "2@email.com", "user2"); private readonly ISemanticLog log = A.Fake(); - private readonly List assignerClaims = new List { new Claim(SquidexClaimTypes.DisplayName, "Sebastian Stehle") }; - private readonly List assigneeClaims = new List { new Claim(SquidexClaimTypes.DisplayName, "Qaisar Ahmad") }; private readonly string appName = "my-app"; private readonly string uiUrl = "my-ui"; private readonly NotificationEmailTextOptions texts = new NotificationEmailTextOptions(); @@ -37,16 +33,6 @@ namespace Squidex.Domain.Apps.Entities.Notifications public NotificationEmailSenderTests() { - A.CallTo(() => assigner.Email) - .Returns("sebastian@squidex.io"); - A.CallTo(() => assigner.Claims) - .Returns(assignerClaims); - - A.CallTo(() => user.Email) - .Returns("qaisar@squidex.io"); - A.CallTo(() => user.Claims) - .Returns(assigneeClaims); - A.CallTo(() => urlGenerator.UI()) .Returns(uiUrl); @@ -56,25 +42,25 @@ namespace Squidex.Domain.Apps.Entities.Notifications [Fact] public async Task Should_format_assigner_email_and_send_email() { - await TestInvitationFormattingAsync("Email: $ASSIGNER_EMAIL", "Email: sebastian@squidex.io"); + await TestInvitationFormattingAsync("Email: $ASSIGNER_EMAIL", "Email: 1@email.com"); } [Fact] public async Task Should_format_assigner_name_and_send_email() { - await TestInvitationFormattingAsync("Name: $ASSIGNER_NAME", "Name: Sebastian Stehle"); + await TestInvitationFormattingAsync("Name: $ASSIGNER_NAME", "Name: user1"); } [Fact] public async Task Should_format_user_email_and_send_email() { - await TestInvitationFormattingAsync("Email: $USER_EMAIL", "Email: qaisar@squidex.io"); + await TestInvitationFormattingAsync("Email: $USER_EMAIL", "Email: 2@email.com"); } [Fact] public async Task Should_format_user_name_and_send_email() { - await TestInvitationFormattingAsync("Name: $USER_NAME", "Name: Qaisar Ahmad"); + await TestInvitationFormattingAsync("Name: $USER_NAME", "Name: user2"); } [Fact] @@ -104,9 +90,9 @@ namespace Squidex.Domain.Apps.Entities.Notifications [Fact] public async Task Should_not_send_invitation_email_if_texts_for_new_user_are_empty() { - await sut.SendInviteAsync(assigner, user, appName); + await sut.SendInviteAsync(assigner, assigned, appName); - A.CallTo(() => emailSender.SendAsync(user.Email, A._, A._, A._)) + A.CallTo(() => emailSender.SendAsync(assigned.Email, A._, A._, A._)) .MustNotHaveHappened(); MustLogWarning(); @@ -115,9 +101,9 @@ namespace Squidex.Domain.Apps.Entities.Notifications [Fact] public async Task Should_not_send_invitation_email_if_texts_for_existing_user_are_empty() { - await sut.SendInviteAsync(assigner, user, appName); + await sut.SendInviteAsync(assigner, assigned, appName); - A.CallTo(() => emailSender.SendAsync(user.Email, A._, A._, A._)) + A.CallTo(() => emailSender.SendAsync(assigned.Email, A._, A._, A._)) .MustNotHaveHappened(); MustLogWarning(); @@ -126,25 +112,39 @@ namespace Squidex.Domain.Apps.Entities.Notifications [Fact] public async Task Should_not_send_usage_email_if_texts_empty() { - await sut.SendUsageAsync(user, appName, 100, 120); + await sut.SendUsageAsync(assigned, appName, 100, 120); - A.CallTo(() => emailSender.SendAsync(user.Email, A._, A._, A._)) + A.CallTo(() => emailSender.SendAsync(assigned.Email, A._, A._, A._)) .MustNotHaveHappened(); MustLogWarning(); } + [Fact] + public async Task Should_not_send_invitation_email_when_no_consent_given() + { + var withoutConsent = UserMocks.User("2", "2@email.com", "user", false); + + texts.ExistingUserSubject = "email-subject"; + texts.ExistingUserBody = "email-body"; + + await sut.SendInviteAsync(assigner, withoutConsent, appName); + + A.CallTo(() => emailSender.SendAsync(withoutConsent.Email, "email-subject", "email-body", A._)) + .MustNotHaveHappened(); + } + [Fact] public async Task Should_send_invitation_email_when_consent_given() { - assigneeClaims.Add(new Claim(SquidexClaimTypes.Consent, "True")); + var withConsent = UserMocks.User("2", "2@email.com", "user", true); texts.ExistingUserSubject = "email-subject"; texts.ExistingUserBody = "email-body"; - await sut.SendInviteAsync(assigner, user, appName); + await sut.SendInviteAsync(assigner, withConsent, appName); - A.CallTo(() => emailSender.SendAsync(user.Email, "email-subject", "email-body", A._)) + A.CallTo(() => emailSender.SendAsync(withConsent.Email, "email-subject", "email-body", A._)) .MustHaveHappened(); } @@ -153,9 +153,9 @@ namespace Squidex.Domain.Apps.Entities.Notifications texts.UsageSubject = pattern; texts.UsageBody = pattern; - await sut.SendUsageAsync(user, appName, 100, 120); + await sut.SendUsageAsync(assigned, appName, 100, 120); - A.CallTo(() => emailSender.SendAsync(user.Email, result, result, A._)) + A.CallTo(() => emailSender.SendAsync(assigned.Email, result, result, A._)) .MustHaveHappened(); } @@ -164,9 +164,9 @@ namespace Squidex.Domain.Apps.Entities.Notifications texts.NewUserSubject = pattern; texts.NewUserBody = pattern; - await sut.SendInviteAsync(assigner, user, appName); + await sut.SendInviteAsync(assigner, assigned, appName); - A.CallTo(() => emailSender.SendAsync(user.Email, result, result, A._)) + A.CallTo(() => emailSender.SendAsync(assigned.Email, result, result, A._)) .MustHaveHappened(); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs index f077854b4..9380ef888 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs @@ -31,10 +31,17 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers var app = A.Fake(); - A.CallTo(() => app.Id).Returns(appId.Id); - A.CallTo(() => app.Name).Returns(appId.Name); - A.CallTo(() => app.Languages).Returns(config); - A.CallTo(() => app.UniqueId).Returns(appId.Id); + A.CallTo(() => app.Id) + .Returns(appId.Id); + + A.CallTo(() => app.Name) + .Returns(appId.Name); + + A.CallTo(() => app.Languages) + .Returns(config); + + A.CallTo(() => app.UniqueId) + .Returns(appId.Id); return app; } @@ -43,10 +50,17 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers { var schema = A.Fake(); - A.CallTo(() => schema.Id).Returns(schemaId.Id); - A.CallTo(() => schema.AppId).Returns(appId); - A.CallTo(() => schema.SchemaDef).Returns(schemaDef ?? new Schema(schemaId.Name)); - A.CallTo(() => schema.UniqueId).Returns(DomainId.Combine(appId, schemaId.Id)); + A.CallTo(() => schema.Id) + .Returns(schemaId.Id); + + A.CallTo(() => schema.AppId) + .Returns(appId); + + A.CallTo(() => schema.SchemaDef) + .Returns(schemaDef ?? new Schema(schemaId.Name)); + + A.CallTo(() => schema.UniqueId) + .Returns(DomainId.Combine(appId, schemaId.Id)); return schema; }