From 28fe82b480aa29beb9eba722a481405e11ef881c Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Wed, 11 Mar 2020 15:29:12 +0100 Subject: [PATCH] Rule formatter improvements and url generator alignment. (#498) --- .../EnrichedEvents/EnrichedAssetEvent.cs | 10 +- .../ConvertContent/FieldConverters.cs | 4 +- .../ConvertContent/IAssetUrlGenerator.cs | 14 -- .../HandleRules/RuleEventFormatter.cs | 198 ++++++++++-------- .../Scripting/EventScriptExtension.cs | 10 + .../IUrlGenerator.cs | 11 + .../Assets/AssetChangedTriggerHandler.cs | 2 + .../Contents/GraphQL/CachingGraphQLService.cs | 3 +- .../GraphQL/GraphQLExecutionContext.cs | 5 +- .../Contents/GraphQL/GraphQLModel.cs | 10 +- .../Contents/GraphQL/IGraphQLUrlGenerator.cs | 26 --- .../Contents/Queries/Steps/ConvertData.cs | 11 +- .../Contents/Queries/Steps/ResolveAssets.cs | 12 +- .../IEmailUrlGenerator.cs | 14 -- .../Notifications/NotificationEmailSender.cs | 11 +- .../src/Squidex.Web/Services/UrlGenerator.cs | 45 ++-- .../Squidex/Config/Domain/QueryServices.cs | 4 +- .../ConvertContent/FieldConvertersTests.cs | 45 ++-- .../HandleRules/RuleEventFormatterTests.cs | 87 +++++++- .../Contents/GraphQL/GraphQLTestBase.cs | 2 +- .../Contents/Queries/ConvertDataTests.cs | 5 +- .../Contents/Queries/ResolveAssetsTests.cs | 9 +- .../Contents/TestData/FakeUrlGenerator.cs | 121 +++++++++-- .../NotificationEmailSenderTests.cs | 7 +- 24 files changed, 406 insertions(+), 260 deletions(-) delete mode 100644 backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/IAssetUrlGenerator.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphQLUrlGenerator.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/IEmailUrlGenerator.cs diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedAssetEvent.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedAssetEvent.cs index aacddc7fb..6eed9b782 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedAssetEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedAssetEvent.cs @@ -7,6 +7,7 @@ using System; using NodaTime; +using Squidex.Domain.Apps.Core.Assets; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Rules.EnrichedEvents @@ -33,12 +34,17 @@ namespace Squidex.Domain.Apps.Core.Rules.EnrichedEvents public long FileSize { get; set; } - public bool IsImage { get; set; } - public int? PixelWidth { get; set; } public int? PixelHeight { get; set; } + public AssetType AssetType { get; set; } + + public bool IsImage + { + get { return AssetType == AssetType.Image; } + } + public override long Partition { get { return Id.GetHashCode(); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs index 60c027ece..9fe0a8061 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs @@ -85,7 +85,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent }; } - public static FieldConverter ResolveAssetUrls(IReadOnlyCollection? fields, IAssetUrlGenerator urlGenerator) + public static FieldConverter ResolveAssetUrls(IReadOnlyCollection? fields, IUrlGenerator urlGenerator) { if (fields?.Any() != true) { @@ -122,7 +122,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent { var id = array[i].ToString(); - array[i] = JsonValue.Create(urlGenerator.GenerateUrl(id)); + array[i] = JsonValue.Create(urlGenerator.AssetContent(Guid.Parse(id))); } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/IAssetUrlGenerator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/IAssetUrlGenerator.cs deleted file mode 100644 index 1a681e9c9..000000000 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/IAssetUrlGenerator.cs +++ /dev/null @@ -1,14 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -namespace Squidex.Domain.Apps.Core.ConvertContent -{ - public interface IAssetUrlGenerator - { - string GenerateUrl(string assetId); - } -} diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs index 3d4817e39..ff5ea5c60 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Reflection; using System.Text; using System.Text.RegularExpressions; using Squidex.Domain.Apps.Core.Contents; @@ -26,11 +27,9 @@ namespace Squidex.Domain.Apps.Core.HandleRules private const string Fallback = "null"; private const string ScriptSuffix = ")"; private const string ScriptPrefix = "Script("; - private static readonly char[] ContentPlaceholderStartOld = "CONTENT_DATA".ToCharArray(); - private static readonly char[] ContentPlaceholderStartNew = "{CONTENT_DATA".ToCharArray(); - private static readonly Regex ContentDataPlaceholderOld = new Regex(@"^CONTENT_DATA(\.([0-9A-Za-z\-_]*)){2,}", RegexOptions.Compiled); - private static readonly Regex ContentDataPlaceholderNew = new Regex(@"^\{CONTENT_DATA(\.([0-9A-Za-z\-_]*)){2,}\}", RegexOptions.Compiled); - private readonly List<(char[] Pattern, Func Replacer)> patterns = new List<(char[] Pattern, Func Replacer)>(); + private static readonly Regex RegexPatternOld = new Regex(@"^(?[^_]*)_(?.*)", RegexOptions.Compiled); + private static readonly Regex RegexPatternNew = new Regex(@"^\{(?[^_]*)_(?.*)\}", RegexOptions.Compiled); + private readonly List<(char[] Pattern, Func Replacer)> patterns = new List<(char[] Pattern, Func Replacer)>(); private readonly IJsonSerializer jsonSerializer; private readonly IUrlGenerator urlGenerator; private readonly IScriptEngine scriptEngine; @@ -47,8 +46,8 @@ namespace Squidex.Domain.Apps.Core.HandleRules AddPattern("APP_ID", AppId); AddPattern("APP_NAME", AppName); + AddPattern("ASSET_CONTENT_URL", AssetContentUrl); AddPattern("CONTENT_ACTION", ContentAction); - AddPattern("CONTENT_STATUS", ContentStatus); AddPattern("CONTENT_URL", ContentUrl); AddPattern("MENTIONED_ID", MentionedId); AddPattern("MENTIONED_NAME", MentionedName); @@ -62,7 +61,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules AddPattern("USER_EMAIL", UserEmail); } - private void AddPattern(string placeholder, Func generator) + private void AddPattern(string placeholder, Func generator) { patterns.Add((placeholder.ToCharArray(), generator)); } @@ -102,9 +101,6 @@ namespace Squidex.Domain.Apps.Core.HandleRules var sb = new StringBuilder(); - var cp2 = new ReadOnlySpan(ContentPlaceholderStartNew); - var cp1 = new ReadOnlySpan(ContentPlaceholderStartOld); - for (var i = 0; i < current.Length; i++) { var c = current[i]; @@ -115,50 +111,14 @@ namespace Squidex.Domain.Apps.Core.HandleRules current = current.Slice(i); - var test = current.Slice(1); - var tested = false; + var (replacement, length) = GetReplacement(current.Slice(1), @event); - for (var j = 0; j < patterns.Count; j++) + if (length > 0) { - var (pattern, replacer) = patterns[j]; - - if (test.StartsWith(pattern, StringComparison.OrdinalIgnoreCase)) - { - sb.Append(replacer(@event)); - - current = current.Slice(pattern.Length + 1); - i = 0; - - tested = true; - break; - } - } + sb.Append(replacement); - if (!tested && (test.StartsWith(cp1, StringComparison.OrdinalIgnoreCase) || test.StartsWith(cp2, StringComparison.OrdinalIgnoreCase))) - { - var currentString = test.ToString(); - - var match = ContentDataPlaceholderOld.Match(currentString); - - if (!match.Success) - { - match = ContentDataPlaceholderNew.Match(currentString); - } - - if (match.Success) - { - if (@event is EnrichedContentEvent contentEvent) - { - sb.Append(CalculateData(contentEvent.Data, match)); - } - else - { - sb.Append(Fallback); - } - - current = current.Slice(match.Length + 1); - i = 0; - } + current = current.Slice(length + 1); + i = 0; } } } @@ -168,6 +128,37 @@ namespace Squidex.Domain.Apps.Core.HandleRules return sb.ToString(); } + private (string Result, int Length) GetReplacement(ReadOnlySpan test, EnrichedEvent @event) + { + for (var j = 0; j < patterns.Count; j++) + { + var (pattern, replacer) = patterns[j]; + + if (test.StartsWith(pattern, StringComparison.OrdinalIgnoreCase)) + { + return (replacer(@event) ?? Fallback, pattern.Length); + } + } + + var currentString = test.ToString(); + + var match = RegexPatternNew.Match(currentString); + + if (!match.Success) + { + match = RegexPatternOld.Match(currentString); + } + + if (match.Success) + { + var path = match.Groups["Path"].Value.Split('.', StringSplitOptions.RemoveEmptyEntries); + + return (CalculateData(@event, path) ?? Fallback, match.Length); + } + + return (Fallback, 0); + } + private static string TimestampDate(EnrichedEvent @event) { return @event.Timestamp.ToDateTimeUtc().ToString("yyy-MM-dd", CultureInfo.InvariantCulture); @@ -188,74 +179,84 @@ namespace Squidex.Domain.Apps.Core.HandleRules return @event.AppId.Name; } - private static string SchemaId(EnrichedEvent @event) + private static string? SchemaId(EnrichedEvent @event) { if (@event is EnrichedSchemaEventBase schemaEvent) { return schemaEvent.SchemaId.Id.ToString(); } - return Fallback; + return null; } - private static string SchemaName(EnrichedEvent @event) + private static string? SchemaName(EnrichedEvent @event) { if (@event is EnrichedSchemaEventBase schemaEvent) { return schemaEvent.SchemaId.Name; } - return Fallback; + return null; } - private static string ContentAction(EnrichedEvent @event) + private static string? ContentAction(EnrichedEvent @event) { if (@event is EnrichedContentEvent contentEvent) { return contentEvent.Type.ToString(); } - return Fallback; + return null; } - private static string ContentStatus(EnrichedEvent @event) + private static string? ContentStatus(EnrichedEvent @event) { if (@event is EnrichedContentEvent contentEvent) { return contentEvent.Status.ToString(); } - return Fallback; + return null; } - private string ContentUrl(EnrichedEvent @event) + private string? AssetContentUrl(EnrichedEvent @event) + { + if (@event is EnrichedAssetEvent assetEvent) + { + return urlGenerator.AssetContent(assetEvent.Id); + } + + return null; + } + + private string? ContentUrl(EnrichedEvent @event) { if (@event is EnrichedContentEvent contentEvent) { return urlGenerator.ContentUI(contentEvent.AppId, contentEvent.SchemaId, contentEvent.Id); } - return Fallback; + return null; } - private static string UserName(EnrichedEvent @event) + private static string? UserName(EnrichedEvent @event) { if (@event is EnrichedUserEventBase userEvent) { return userEvent.User?.DisplayName() ?? Fallback; } - return Fallback; + return null; } - private static string UserId(EnrichedEvent @event) + private static string? UserId(EnrichedEvent @event) { if (@event is EnrichedUserEventBase userEvent) { return userEvent.User?.Id ?? Fallback; } - return Fallback; + return null; } private static string UserEmail(EnrichedEvent @event) @@ -298,36 +299,63 @@ namespace Squidex.Domain.Apps.Core.HandleRules return Fallback; } - private static string CalculateData(NamedContentData data, Match match) + private static string? CalculateData(object @event, string[] path) { - var captures = match.Groups[2].Captures; - - var path = new string[captures.Count]; + object? current = @event; - for (var i = 0; i < path.Length; i++) + foreach (var segment in path) { - path[i] = captures[i].Value; - } + if (current is NamedContentData data) + { + if (!data.TryGetValue(segment, out var temp) || temp == null) + { + return null; + } - if (!data.TryGetValue(path[0], out var field) || field == null) - { - return Fallback; - } + current = temp; + } + else if (current is ContentFieldData field) + { + if (!field.TryGetValue(segment, out var temp) || temp == null) + { + return null; + } - if (!field.TryGetValue(path[1], out var value)) - { - return Fallback; - } + current = temp; + } + else if (current is IJsonValue json) + { + if (!json.TryGet(segment, out var temp) || temp == null || temp.Type == JsonValueType.Null) + { + return null; + } - if (path.Skip(2).Any()) - { - if (!value.TryGetByPath(path.Skip(2), out value) || value == null || value.Type == JsonValueType.Null) + current = temp; + } + else if (current != null) + { + const BindingFlags bindingFlags = + BindingFlags.FlattenHierarchy | + BindingFlags.Public | + BindingFlags.Instance; + + var properties = current.GetType().GetProperties(bindingFlags); + var property = properties.FirstOrDefault(x => x.CanRead && string.Equals(x.Name, segment, StringComparison.OrdinalIgnoreCase)); + + if (property == null) + { + return null; + } + + current = property.GetValue(current); + } + else { - return Fallback; + return null; } } - return value.ToString() ?? Fallback; + return current?.ToString(); } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Scripting/EventScriptExtension.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Scripting/EventScriptExtension.cs index 09679802a..1a5324deb 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Scripting/EventScriptExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Scripting/EventScriptExtension.cs @@ -45,6 +45,16 @@ namespace Squidex.Domain.Apps.Core.HandleRules.Scripting return JsValue.Null; })); + + context.Engine.SetValue("assetContentUrl", new EventDelegate(() => + { + if (context.TryGetValue("event", out var temp) && temp is EnrichedAssetEvent assetEvent) + { + return urlGenerator.AssetContent(assetEvent.Id); + } + + return JsValue.Null; + })); } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/IUrlGenerator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/IUrlGenerator.cs index 20e046fa5..1e987251d 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/IUrlGenerator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/IUrlGenerator.cs @@ -6,18 +6,27 @@ // ========================================================================== using System; +using Squidex.Domain.Apps.Core.Assets; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core { public interface IUrlGenerator { + bool CanGenerateAssetSourceUrl { get; } + + string? AssetSource(Guid assetId, long fileVersion); + + string? AssetThumbnail(Guid assetId, AssetType assetType); + string AppSettingsUI(NamedId appId); string AssetsUI(NamedId appId); string AssetsUI(NamedId appId, string? query = null); + string AssetContent(Guid assetId); + string BackupsUI(NamedId appId); string ClientsUI(NamedId appId); @@ -47,5 +56,7 @@ namespace Squidex.Domain.Apps.Core string SchemaUI(NamedId appId, NamedId schemaId); string WorkflowsUI(NamedId appId); + + string UI(); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetChangedTriggerHandler.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetChangedTriggerHandler.cs index 78598674a..ac966bb16 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetChangedTriggerHandler.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetChangedTriggerHandler.cs @@ -45,6 +45,8 @@ namespace Squidex.Domain.Apps.Entities.Assets SimpleMapper.Map(asset, result); + result.AssetType = asset.Type; + switch (@event.Payload) { case AssetCreated _: diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs index a58359245..6b1b7ca89 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using GraphQL; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; +using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Infrastructure; @@ -92,7 +93,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL allSchemas, GetPageSizeForContents(), GetPageSizeForAssets(), - resolver.Resolve()); + resolver.Resolve()); }); } 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 2b4ae34bf..b6311e0ce 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Threading.Tasks; using GraphQL; using GraphQL.DataLoader; +using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types; using Squidex.Domain.Apps.Entities.Contents.Queries; @@ -26,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL private readonly IDataLoaderContextAccessor dataLoaderContextAccessor; private readonly IDependencyResolver resolver; - public IGraphQLUrlGenerator UrlGenerator { get; } + public IUrlGenerator UrlGenerator { get; } public ISemanticLog Log { get; } @@ -37,7 +38,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL resolver.Resolve(), resolver.Resolve()) { - UrlGenerator = resolver.Resolve(); + UrlGenerator = resolver.Resolve(); dataLoaderContextAccessor = resolver.Resolve(); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs index 51ecdf4f4..64cb1d7bc 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs @@ -41,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL IEnumerable schemas, int pageSizeContents, int pageSizeAssets, - IGraphQLUrlGenerator urlGenerator) + IUrlGenerator urlGenerator) { this.app = app; @@ -99,7 +99,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { var context = (GraphQLExecutionContext)c.UserContext; - return context.UrlGenerator.GenerateAssetUrl(app, c.Source); + return context.UrlGenerator.AssetContent(c.Source.Id); }); return resolver; @@ -111,7 +111,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { var context = (GraphQLExecutionContext)c.UserContext; - return context.UrlGenerator.GenerateAssetSourceUrl(c.Source); + return context.UrlGenerator.AssetSource(c.Source.Id, c.Source.FileVersion); }); return resolver; @@ -123,7 +123,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { var context = (GraphQLExecutionContext)c.UserContext; - return context.UrlGenerator.GenerateAssetThumbnailUrl(app, c.Source); + return context.UrlGenerator.AssetThumbnail(c.Source.Id, c.Source.Type); }); return resolver; @@ -135,7 +135,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { var context = (GraphQLExecutionContext)c.UserContext; - return context.UrlGenerator.GenerateContentUrl(app, schema, c.Source); + return context.UrlGenerator.ContentUI(app.NamedId(), schema.NamedId(), c.Source.Id); }); return resolver; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphQLUrlGenerator.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphQLUrlGenerator.cs deleted file mode 100644 index 6a1bb87b7..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphQLUrlGenerator.cs +++ /dev/null @@ -1,26 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Domain.Apps.Entities.Assets; -using Squidex.Domain.Apps.Entities.Schemas; - -namespace Squidex.Domain.Apps.Entities.Contents.GraphQL -{ - public interface IGraphQLUrlGenerator - { - bool CanGenerateAssetSourceUrl { get; } - - string? GenerateAssetThumbnailUrl(IAppEntity app, IAssetEntity asset); - - string? GenerateAssetSourceUrl(IAssetEntity asset); - - string GenerateAssetUrl(IAppEntity app, IAssetEntity asset); - - string GenerateContentUrl(IAppEntity app, ISchemaEntity schema, IContentEntity content); - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs index 5a4984dd6..9abdd5fcc 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.ConvertContent; using Squidex.Domain.Apps.Core.ExtractReferenceIds; using Squidex.Domain.Apps.Entities.Assets.Repositories; @@ -19,17 +20,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { public sealed class ConvertData : IContentEnricherStep { - private readonly IAssetUrlGenerator assetUrlGenerator; + private readonly IUrlGenerator urlGenerator; private readonly IAssetRepository assetRepository; private readonly IContentRepository contentRepository; - public ConvertData(IAssetUrlGenerator assetUrlGenerator, IAssetRepository assetRepository, IContentRepository contentRepository) + public ConvertData(IUrlGenerator urlGenerator, IAssetRepository assetRepository, IContentRepository contentRepository) { - Guard.NotNull(assetUrlGenerator); + Guard.NotNull(urlGenerator); Guard.NotNull(assetRepository); Guard.NotNull(contentRepository); - this.assetUrlGenerator = assetUrlGenerator; + this.urlGenerator = urlGenerator; this.assetRepository = assetRepository; this.contentRepository = contentRepository; } @@ -137,7 +138,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps if (assetUrls.Any()) { - yield return FieldConverters.ResolveAssetUrls(assetUrls.ToList(), assetUrlGenerator); + yield return FieldConverters.ResolveAssetUrls(assetUrls.ToList(), urlGenerator); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs index fdf53b40b..69ade2a20 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs @@ -9,9 +9,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Core.Contents; -using Squidex.Domain.Apps.Core.ConvertContent; using Squidex.Domain.Apps.Core.ExtractReferenceIds; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Assets; @@ -26,17 +26,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { private static readonly ILookup EmptyAssets = Enumerable.Empty().ToLookup(x => x.Id); - private readonly IAssetUrlGenerator assetUrlGenerator; + private readonly IUrlGenerator urlGenerator; private readonly IAssetQueryService assetQuery; private readonly IRequestCache requestCache; - public ResolveAssets(IAssetUrlGenerator assetUrlGenerator, IAssetQueryService assetQuery, IRequestCache requestCache) + public ResolveAssets(IUrlGenerator urlGenerator, IAssetQueryService assetQuery, IRequestCache requestCache) { - Guard.NotNull(assetUrlGenerator); + Guard.NotNull(urlGenerator); Guard.NotNull(assetQuery); Guard.NotNull(requestCache); - this.assetUrlGenerator = assetUrlGenerator; + this.urlGenerator = urlGenerator; this.assetQuery = assetQuery; this.requestCache = requestCache; } @@ -90,7 +90,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps if (referencedImage != null) { - var url = assetUrlGenerator.GenerateUrl(referencedImage.Id.ToString()); + var url = urlGenerator.AssetContent(Guid.Parse(referencedImage.Id.ToString())); requestCache.AddDependency(referencedImage.Id, referencedImage.Version); diff --git a/backend/src/Squidex.Domain.Apps.Entities/IEmailUrlGenerator.cs b/backend/src/Squidex.Domain.Apps.Entities/IEmailUrlGenerator.cs deleted file mode 100644 index 98ee82477..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/IEmailUrlGenerator.cs +++ /dev/null @@ -1,14 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -namespace Squidex.Domain.Apps.Entities -{ - public interface IEmailUrlGenerator - { - string GenerateUIUrl(); - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Notifications/NotificationEmailSender.cs b/backend/src/Squidex.Domain.Apps.Entities/Notifications/NotificationEmailSender.cs index 73f7518ab..402b73f05 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Notifications/NotificationEmailSender.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Notifications/NotificationEmailSender.cs @@ -8,6 +8,7 @@ using System; using System.Threading.Tasks; using Microsoft.Extensions.Options; +using Squidex.Domain.Apps.Core; using Squidex.Infrastructure; using Squidex.Infrastructure.Email; using Squidex.Infrastructure.Log; @@ -18,7 +19,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Notifications public sealed class NotificationEmailSender : INotificationSender { private readonly IEmailSender emailSender; - private readonly IEmailUrlGenerator emailUrlGenerator; + private readonly IUrlGenerator urlGenerator; private readonly ISemanticLog log; private readonly NotificationEmailTextOptions texts; @@ -45,17 +46,17 @@ namespace Squidex.Domain.Apps.Entities.Apps.Notifications public NotificationEmailSender( IOptions texts, IEmailSender emailSender, - IEmailUrlGenerator emailUrlGenerator, + IUrlGenerator urlGenerator, ISemanticLog log) { Guard.NotNull(texts); Guard.NotNull(emailSender); - Guard.NotNull(emailUrlGenerator); + Guard.NotNull(urlGenerator); Guard.NotNull(log); this.texts = texts.Value; this.emailSender = emailSender; - this.emailUrlGenerator = emailUrlGenerator; + this.urlGenerator = urlGenerator; this.log = log; } @@ -115,7 +116,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Notifications return; } - vars.URL = emailUrlGenerator.GenerateUIUrl(); + vars.URL = urlGenerator.UI(); vars.User = user; diff --git a/backend/src/Squidex.Web/Services/UrlGenerator.cs b/backend/src/Squidex.Web/Services/UrlGenerator.cs index 7b2686253..d0f85428c 100644 --- a/backend/src/Squidex.Web/Services/UrlGenerator.cs +++ b/backend/src/Squidex.Web/Services/UrlGenerator.cs @@ -9,18 +9,12 @@ using System; using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Assets; -using Squidex.Domain.Apps.Core.ConvertContent; -using Squidex.Domain.Apps.Entities; -using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Assets; -using Squidex.Domain.Apps.Entities.Contents; -using Squidex.Domain.Apps.Entities.Contents.GraphQL; -using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure; namespace Squidex.Web.Services { - public sealed class UrlGenerator : IGraphQLUrlGenerator, IUrlGenerator, IAssetUrlGenerator, IEmailUrlGenerator + public sealed class UrlGenerator : IUrlGenerator { private readonly IAssetFileStore assetFileStore; private readonly UrlsOptions urlsOptions; @@ -39,44 +33,29 @@ namespace Squidex.Web.Services CanGenerateAssetSourceUrl = allowAssetSourceUrl; } - public string? GenerateAssetThumbnailUrl(IAppEntity app, IAssetEntity asset) + public string? AssetThumbnail(Guid assetId, AssetType assetType) { - if (asset.Type != AssetType.Image) + if (assetType != AssetType.Image) { return null; } - return urlsOptions.BuildUrl($"api/assets/{asset.Id}?version={asset.FileVersion}&width=100&mode=Max"); + return urlsOptions.BuildUrl($"api/assets/{assetId}?width=100&mode=Max"); } - public string GenerateUrl(string assetId) - { - return urlsOptions.BuildUrl($"api/assets/{assetId}"); - } - - public string GenerateAssetUrl(IAppEntity app, IAssetEntity asset) - { - return urlsOptions.BuildUrl($"api/assets/{asset.Id}?version={asset.FileVersion}"); - } - - public string GenerateContentUrl(IAppEntity app, ISchemaEntity schema, IContentEntity content) - { - return urlsOptions.BuildUrl($"api/content/{app.Name}/{schema.SchemaDef.Name}/{content.Id}"); - } - - public string GenerateContentUIUrl(NamedId appId, NamedId schemaId, Guid contentId) + public string AppSettingsUI(NamedId appId) { - return urlsOptions.BuildUrl($"app/{appId.Name}/content/{schemaId.Name}/{contentId}/history"); + return urlsOptions.BuildUrl($"app/{appId.Name}/settings", false); } - public string GenerateUIUrl() + public string AssetContent(Guid assetId) { - return urlsOptions.BuildUrl("app", false); + return urlsOptions.BuildUrl($"api/assets/{assetId}"); } - public string AppSettingsUI(NamedId appId) + public string? AssetSource(Guid assetId, long fileVersion) { - return urlsOptions.BuildUrl($"app/{appId.Name}/settings", false); + return assetFileStore.GeneratePublicUrl(assetId, fileVersion); } public string AssetsUI(NamedId appId) @@ -164,9 +143,9 @@ namespace Squidex.Web.Services return urlsOptions.BuildUrl($"app/{appId.Name}/settings/workflows", false); } - public string? GenerateAssetSourceUrl(IAssetEntity asset) + public string UI() { - return assetFileStore.GeneratePublicUrl(asset.Id, asset.FileVersion); + return urlsOptions.BuildUrl("app", false); } } } diff --git a/backend/src/Squidex/Config/Domain/QueryServices.cs b/backend/src/Squidex/Config/Domain/QueryServices.cs index fe59c3ba8..278fd7b4a 100644 --- a/backend/src/Squidex/Config/Domain/QueryServices.cs +++ b/backend/src/Squidex/Config/Domain/QueryServices.cs @@ -11,8 +11,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Core; -using Squidex.Domain.Apps.Core.ConvertContent; -using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Contents.GraphQL; using Squidex.Web; @@ -30,7 +28,7 @@ namespace Squidex.Config.Domain c.GetRequiredService>(), c.GetRequiredService(), exposeSourceUrl)) - .As().As().As().As(); + .As(); services.AddSingletonAs(x => new FuncDependencyResolver(x.GetRequiredService)) .As(); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs index 14d15e217..ed3a9603d 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System; using System.Collections.Generic; using System.Linq; using FakeItEasy; @@ -20,13 +21,15 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent { public class FieldConvertersTests { - private readonly IAssetUrlGenerator assetUrlGenerator = A.Fake(); + private readonly IUrlGenerator urlGenerato = A.Fake(); + private readonly Guid id1 = Guid.NewGuid(); + private readonly Guid id2 = Guid.NewGuid(); private readonly LanguagesConfig languagesConfig = LanguagesConfig.English.Set(Language.DE); public FieldConvertersTests() { - A.CallTo(() => assetUrlGenerator.GenerateUrl(A._)) - .ReturnsLazily(ctx => $"url/to/{ctx.GetArgument(0)}"); + A.CallTo(() => urlGenerato.AssetContent(A._)) + .ReturnsLazily(ctx => $"url/to/{ctx.GetArgument(0)}"); } [Fact] @@ -479,13 +482,13 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent var source = new ContentFieldData() - .AddJsonValue(JsonValue.Array("1", "2")); + .AddJsonValue(JsonValue.Array(id1, id2)); var expected = new ContentFieldData() - .AddJsonValue(JsonValue.Array("url/to/1", "url/to/2")); + .AddJsonValue(JsonValue.Array($"url/to/{id1}", $"url/to/{id2}")); - var result = FieldConverters.ResolveAssetUrls(new HashSet(new[] { "assets" }), assetUrlGenerator)(source, field); + var result = FieldConverters.ResolveAssetUrls(new HashSet(new[] { "assets" }), urlGenerato)(source, field); Assert.Equal(expected, result); } @@ -501,15 +504,15 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent new ContentFieldData() .AddJsonValue(JsonValue.Array( JsonValue.Object() - .Add("assets", JsonValue.Array("1", "2")))); + .Add("assets", JsonValue.Array(id1, id2)))); var expected = new ContentFieldData() .AddJsonValue(JsonValue.Array( JsonValue.Object() - .Add("assets", JsonValue.Array("url/to/1", "url/to/2")))); + .Add("assets", JsonValue.Array($"url/to/{id1}", $"url/to/{id2}")))); - var result = FieldConverters.ResolveAssetUrls(new HashSet(new[] { "array.assets" }), assetUrlGenerator)(source, field); + var result = FieldConverters.ResolveAssetUrls(new HashSet(new[] { "array.assets" }), urlGenerato)(source, field); Assert.Equal(expected, result); } @@ -521,13 +524,13 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent var source = new ContentFieldData() - .AddJsonValue(JsonValue.Array("1", "2")); + .AddJsonValue(JsonValue.Array(id1, id2)); var expected = new ContentFieldData() - .AddJsonValue(JsonValue.Array("url/to/1", "url/to/2")); + .AddJsonValue(JsonValue.Array($"url/to/{id1}", $"url/to/{id2}")); - var result = FieldConverters.ResolveAssetUrls(new HashSet(new[] { "*" }), assetUrlGenerator)(source, field); + var result = FieldConverters.ResolveAssetUrls(new HashSet(new[] { "*" }), urlGenerato)(source, field); Assert.Equal(expected, result); } @@ -543,15 +546,15 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent new ContentFieldData() .AddJsonValue(JsonValue.Array( JsonValue.Object() - .Add("assets", JsonValue.Array("1", "2")))); + .Add("assets", JsonValue.Array(id1, id2)))); var expected = new ContentFieldData() .AddJsonValue(JsonValue.Array( JsonValue.Object() - .Add("assets", JsonValue.Array("url/to/1", "url/to/2")))); + .Add("assets", JsonValue.Array($"url/to/{id1}", $"url/to/{id2}")))); - var result = FieldConverters.ResolveAssetUrls(new HashSet(new[] { "*" }), assetUrlGenerator)(source, field); + var result = FieldConverters.ResolveAssetUrls(new HashSet(new[] { "*" }), urlGenerato)(source, field); Assert.Equal(expected, result); } @@ -563,13 +566,13 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent var source = new ContentFieldData() - .AddJsonValue(JsonValue.Array("1", "2")); + .AddJsonValue(JsonValue.Array(id1, id2)); var expected = new ContentFieldData() - .AddJsonValue(JsonValue.Array("1", "2")); + .AddJsonValue(JsonValue.Array(id1, id2)); - var result = FieldConverters.ResolveAssetUrls(new HashSet(new[] { "other" }), assetUrlGenerator)(source, field); + var result = FieldConverters.ResolveAssetUrls(new HashSet(new[] { "other" }), urlGenerato)(source, field); Assert.Equal(expected, result); } @@ -581,13 +584,13 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent var source = new ContentFieldData() - .AddJsonValue(JsonValue.Array("1", "2")); + .AddJsonValue(JsonValue.Array(id1, id2)); var expected = new ContentFieldData() - .AddJsonValue(JsonValue.Array("1", "2")); + .AddJsonValue(JsonValue.Array(id1, id2)); - var result = FieldConverters.ResolveAssetUrls(null, assetUrlGenerator)(source, field); + var result = FieldConverters.ResolveAssetUrls(null, urlGenerato)(source, field); Assert.Equal(expected, result); } 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 1eb040d97..620dc4572 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 @@ -12,6 +12,7 @@ using FakeItEasy; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using NodaTime; +using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Core.HandleRules.Scripting; @@ -34,12 +35,19 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); private readonly Instant now = SystemClock.Instance.GetCurrentInstant(); private readonly Guid contentId = Guid.NewGuid(); + private readonly Guid assetId = Guid.NewGuid(); private readonly RuleEventFormatter sut; public RuleEventFormatterTests() { + A.CallTo(() => urlGenerator.ContentUI(appId, schemaId, contentId)) + .Returns("content-url"); + + A.CallTo(() => urlGenerator.AssetContent(assetId)) + .Returns("asset-content-url"); + A.CallTo(() => user.Id) - .Returns("123"); + .Returns("user123"); A.CallTo(() => user.Email) .Returns("me@email.com"); @@ -47,9 +55,6 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules A.CallTo(() => user.Claims) .Returns(new List { new Claim(SquidexClaimTypes.DisplayName, "me") }); - A.CallTo(() => urlGenerator.ContentUI(appId, schemaId, contentId)) - .Returns("content-url"); - var extensions = new IScriptExtension[] { new DateTimeScriptExtension(), @@ -93,7 +98,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules [Theory] [InlineData("Name $APP_NAME has id $APP_ID")] [InlineData("Script(`Name ${event.appId.name} has id ${event.appId.id}`)")] - public void Should_replace_app_information_from_event(string script) + public void Should_format_app_information_from_event(string script) { var @event = new EnrichedContentEvent { AppId = appId }; @@ -105,7 +110,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules [Theory] [InlineData("Name $SCHEMA_NAME has id $SCHEMA_ID")] [InlineData("Script(`Name ${event.schemaId.name} has id ${event.schemaId.id}`)")] - public void Should_replace_schema_information_from_event(string script) + public void Should_format_schema_information_from_event(string script) { var @event = new EnrichedContentEvent { SchemaId = schemaId }; @@ -117,7 +122,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules [Theory] [InlineData("Date: $TIMESTAMP_DATE, Full: $TIMESTAMP_DATETIME")] [InlineData("Script(`Date: ${formatDate(event.timestamp, 'yyyy-MM-dd')}, Full: ${formatDate(event.timestamp, 'yyyy-MM-dd-hh-mm-ss')}`)")] - public void Should_replace_timestamp_information_from_event(string script) + public void Should_format_timestamp_information_from_event(string script) { var @event = new EnrichedContentEvent { Timestamp = now }; @@ -135,7 +140,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules var result = sut.Format(script, @event); - Assert.Equal("From me (me@email.com, 123)", result); + Assert.Equal("From me (me@email.com, user123)", result); } [Theory] @@ -147,7 +152,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules var result = sut.Format(script, @event); - Assert.Equal("From me (me@email.com, 123)", result); + Assert.Equal("From me (me@email.com, user123)", result); } [Theory] @@ -174,10 +179,70 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules Assert.Equal("From client:android (client:android, android)", result); } + [Theory] + [InlineData("Version: $ASSET_VERSION")] + [InlineData("Script(`Version: ${event.version}`)")] + public void Should_format_base_property(string script) + { + var @event = new EnrichedAssetEvent { Version = 13 }; + + var result = sut.Format(script, @event); + + Assert.Equal("Version: 13", result); + } + + [Theory] + [InlineData("File: $ASSET_FILENAME")] + [InlineData("Script(`File: ${event.fileName}`)")] + public void Should_format_asset_file_name_from_event(string script) + { + var @event = new EnrichedAssetEvent { FileName = "my-file.png" }; + + var result = sut.Format(script, @event); + + Assert.Equal("File: my-file.png", result); + } + + [Theory] + [InlineData("Type: $ASSET_ASSETTYPE")] + [InlineData("Script(`Type: ${event.assetType}`)")] + public void Should_format_asset_asset_type_from_event(string script) + { + var @event = new EnrichedAssetEvent { AssetType = AssetType.Audio }; + + var result = sut.Format(script, @event); + + Assert.Equal("Type: Audio", result); + } + + [Theory] + [InlineData("Download at $ASSET_CONTENT_URL")] + [InlineData("Script(`Download at ${assetContentUrl()}`)")] + public void Should_format_asset_content_url_from_event(string script) + { + var @event = new EnrichedAssetEvent { Id = assetId }; + + var result = sut.Format(script, @event); + + Assert.Equal("Download at asset-content-url", result); + } + + [Theory] + [InlineData("Download at $ASSET_CONTENT_URL")] + [InlineData("Script(`Download at ${assetContentUrl()}`)")] + public void Should_return_null_when_asset_content_url_not_found(string script) + { + var @event = new EnrichedContentEvent(); + + var result = sut.Format(script, @event); + + Assert.Equal("Download at null", result); + } + [Theory] [InlineData("Go to $CONTENT_URL")] [InlineData("Script(`Go to ${contentUrl()}`)")] - public void Should_replace_content_url_from_event(string script) + public void Should_format_content_url_from_event(string script) { var @event = new EnrichedContentEvent { AppId = appId, Id = contentId, SchemaId = schemaId }; @@ -189,7 +254,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules [Theory] [InlineData("Go to $CONTENT_URL")] [InlineData("Script(`Go to ${contentUrl()}`)")] - public void Should_format_content_url_when_not_found(string script) + public void Should_return_null_when_content_url_when_not_found(string script) { var @event = new EnrichedAssetEvent(); 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 8db85cd44..d7d2f0816 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 @@ -272,10 +272,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL [typeof(IAssetQueryService)] = assetQuery, [typeof(IContentQueryService)] = contentQuery, [typeof(IDataLoaderContextAccessor)] = dataLoaderContext, - [typeof(IGraphQLUrlGenerator)] = new FakeUrlGenerator(), [typeof(IOptions)] = Options.Create(new AssetOptions()), [typeof(IOptions)] = Options.Create(new ContentOptions()), [typeof(ISemanticLog)] = A.Fake(), + [typeof(IUrlGenerator)] = new FakeUrlGenerator(), [typeof(DataLoaderDocumentListener)] = new DataLoaderDocumentListener(dataLoaderContext) }; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs index 84cc5b177..69a02827c 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs @@ -12,7 +12,6 @@ using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Contents; -using Squidex.Domain.Apps.Core.ConvertContent; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Contents.Queries.Steps; @@ -28,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries public class ConvertDataTests { private readonly ISchemaEntity schema; - private readonly IAssetUrlGenerator assetUrlGenerator = A.Fake(); + private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly IAssetRepository assetRepository = A.Fake(); private readonly IContentRepository contentRepository = A.Fake(); private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); @@ -48,7 +47,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries schema = Mocks.Schema(appId, schemaId, schemaDef); schemaProvider = x => Task.FromResult(schema); - sut = new ConvertData(assetUrlGenerator, assetRepository, contentRepository); + sut = new ConvertData(urlGenerator, assetRepository, contentRepository); } [Fact] diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs index bd81fb8eb..92f423cde 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs @@ -12,7 +12,6 @@ using FakeItEasy; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Core.Contents; -using Squidex.Domain.Apps.Core.ConvertContent; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Contents.Queries.Steps; @@ -28,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries public class ResolveAssetsTests { private readonly IAssetQueryService assetQuery = A.Fake(); - private readonly IAssetUrlGenerator assetUrlGenerator = A.Fake(); + private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly IRequestCache requestCache = A.Fake(); private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); @@ -56,8 +55,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries }) .SetFieldsInLists("asset1", "asset2"); - A.CallTo(() => assetUrlGenerator.GenerateUrl(A._)) - .ReturnsLazily(new Func(id => $"url/to/{id}")); + A.CallTo(() => urlGenerator.AssetContent(A._)) + .ReturnsLazily(ctx => $"url/to/{ctx.GetArgument(0)}"); schemaProvider = x => { @@ -71,7 +70,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries } }; - sut = new ResolveAssets(assetUrlGenerator, assetQuery, requestCache); + sut = new ResolveAssets(urlGenerator, assetQuery, requestCache); } [Fact] diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/TestData/FakeUrlGenerator.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/TestData/FakeUrlGenerator.cs index e8319d568..923cf53be 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/TestData/FakeUrlGenerator.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/TestData/FakeUrlGenerator.cs @@ -5,35 +5,130 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Domain.Apps.Entities.Assets; -using Squidex.Domain.Apps.Entities.Contents.GraphQL; -using Squidex.Domain.Apps.Entities.Schemas; +using System; +using Squidex.Domain.Apps.Core; +using Squidex.Domain.Apps.Core.Assets; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.TestData { - public sealed class FakeUrlGenerator : IGraphQLUrlGenerator + public sealed class FakeUrlGenerator : IUrlGenerator { public bool CanGenerateAssetSourceUrl { get; } = true; - public string GenerateAssetUrl(IAppEntity app, IAssetEntity asset) + public string? AssetThumbnail(Guid assetId, AssetType assetType) { - return $"assets/{asset.Id}"; + return $"assets/{assetId}?width=100"; } - public string GenerateAssetThumbnailUrl(IAppEntity app, IAssetEntity asset) + public string? AssetSource(Guid assetId, long fileVersion) { - return $"assets/{asset.Id}?width=100"; + return $"assets/source/{assetId}"; } - public string GenerateAssetSourceUrl(IAssetEntity asset) + public string AssetContent(Guid assetId) { - return $"assets/source/{asset.Id}"; + return $"assets/{assetId}"; } - public string GenerateContentUrl(IAppEntity app, ISchemaEntity schema, IContentEntity content) + public string ContentUI(NamedId appId, NamedId schemaId, Guid contentId) { - return $"contents/{schema.SchemaDef.Name}/{content.Id}"; + return $"contents/{schemaId.Name}/{contentId}"; + } + + public string AppSettingsUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string AssetsUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string AssetsUI(NamedId appId, string? query = null) + { + throw new NotSupportedException(); + } + + public string AssetSource(Guid assetId) + { + throw new NotSupportedException(); + } + + public string BackupsUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string ClientsUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string ContentsUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string ContentsUI(NamedId appId, NamedId schemaId) + { + throw new NotSupportedException(); + } + + public string ContributorsUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string DashboardUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string LanguagesUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string PatternsUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string PlansUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string RolesUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string RulesUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string SchemasUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string SchemaUI(NamedId appId, NamedId schemaId) + { + throw new NotSupportedException(); + } + + public string WorkflowsUI(NamedId appId) + { + throw new NotSupportedException(); + } + + public string UI() + { + throw new NotSupportedException(); } } } 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 c453ae839..7b321c3e8 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Notifications/NotificationEmailSenderTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Notifications/NotificationEmailSenderTests.cs @@ -11,6 +11,7 @@ using System.Security.Claims; using System.Threading.Tasks; using FakeItEasy; using Microsoft.Extensions.Options; +using Squidex.Domain.Apps.Core; using Squidex.Infrastructure.Email; using Squidex.Infrastructure.Log; using Squidex.Shared.Identity; @@ -22,7 +23,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Notifications public class NotificationEmailSenderTests { private readonly IEmailSender emailSender = A.Fake(); - private readonly IEmailUrlGenerator emailUrlGenerator = A.Fake(); + private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly IUser assigner = A.Fake(); private readonly IUser user = A.Fake(); private readonly ISemanticLog log = A.Fake(); @@ -45,10 +46,10 @@ namespace Squidex.Domain.Apps.Entities.Apps.Notifications A.CallTo(() => user.Claims) .Returns(assigneeClaims); - A.CallTo(() => emailUrlGenerator.GenerateUIUrl()) + A.CallTo(() => urlGenerator.UI()) .Returns(uiUrl); - sut = new NotificationEmailSender(Options.Create(texts), emailSender, emailUrlGenerator, log); + sut = new NotificationEmailSender(Options.Create(texts), emailSender, urlGenerator, log); } [Fact]