Browse Source

Rule formatter improvements and url generator alignment. (#498)

pull/499/head
Sebastian Stehle 6 years ago
committed by GitHub
parent
commit
28fe82b480
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedAssetEvent.cs
  2. 4
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs
  3. 14
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/IAssetUrlGenerator.cs
  4. 198
      backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs
  5. 10
      backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Scripting/EventScriptExtension.cs
  6. 11
      backend/src/Squidex.Domain.Apps.Core.Operations/IUrlGenerator.cs
  7. 2
      backend/src/Squidex.Domain.Apps.Entities/Assets/AssetChangedTriggerHandler.cs
  8. 3
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs
  9. 5
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs
  10. 10
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs
  11. 26
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphQLUrlGenerator.cs
  12. 11
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs
  13. 12
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs
  14. 14
      backend/src/Squidex.Domain.Apps.Entities/IEmailUrlGenerator.cs
  15. 11
      backend/src/Squidex.Domain.Apps.Entities/Notifications/NotificationEmailSender.cs
  16. 45
      backend/src/Squidex.Web/Services/UrlGenerator.cs
  17. 4
      backend/src/Squidex/Config/Domain/QueryServices.cs
  18. 45
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs
  19. 87
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs
  20. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs
  21. 5
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs
  22. 9
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs
  23. 121
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/TestData/FakeUrlGenerator.cs
  24. 7
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Notifications/NotificationEmailSenderTests.cs

10
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(); }

4
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<string>? fields, IAssetUrlGenerator urlGenerator)
public static FieldConverter ResolveAssetUrls(IReadOnlyCollection<string>? 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)));
}
}
}

14
backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/IAssetUrlGenerator.cs

@ -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);
}
}

198
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<EnrichedEvent, string> Replacer)> patterns = new List<(char[] Pattern, Func<EnrichedEvent, string> Replacer)>();
private static readonly Regex RegexPatternOld = new Regex(@"^(?<Type>[^_]*)_(?<Path>.*)", RegexOptions.Compiled);
private static readonly Regex RegexPatternNew = new Regex(@"^\{(?<Type>[^_]*)_(?<Path>.*)\}", RegexOptions.Compiled);
private readonly List<(char[] Pattern, Func<EnrichedEvent, string?> Replacer)> patterns = new List<(char[] Pattern, Func<EnrichedEvent, string?> 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<EnrichedEvent, string> generator)
private void AddPattern(string placeholder, Func<EnrichedEvent, string?> generator)
{
patterns.Add((placeholder.ToCharArray(), generator));
}
@ -102,9 +101,6 @@ namespace Squidex.Domain.Apps.Core.HandleRules
var sb = new StringBuilder();
var cp2 = new ReadOnlySpan<char>(ContentPlaceholderStartNew);
var cp1 = new ReadOnlySpan<char>(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<char> 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();
}
}
}

10
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;
}));
}
}
}

11
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<Guid> appId);
string AssetsUI(NamedId<Guid> appId);
string AssetsUI(NamedId<Guid> appId, string? query = null);
string AssetContent(Guid assetId);
string BackupsUI(NamedId<Guid> appId);
string ClientsUI(NamedId<Guid> appId);
@ -47,5 +56,7 @@ namespace Squidex.Domain.Apps.Core
string SchemaUI(NamedId<Guid> appId, NamedId<Guid> schemaId);
string WorkflowsUI(NamedId<Guid> appId);
string UI();
}
}

2
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 _:

3
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<IGraphQLUrlGenerator>());
resolver.Resolve<IUrlGenerator>());
});
}

5
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<IAssetQueryService>(),
resolver.Resolve<IContentQueryService>())
{
UrlGenerator = resolver.Resolve<IGraphQLUrlGenerator>();
UrlGenerator = resolver.Resolve<IUrlGenerator>();
dataLoaderContextAccessor = resolver.Resolve<IDataLoaderContextAccessor>();

10
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs

@ -41,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
IEnumerable<ISchemaEntity> 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;

26
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphQLUrlGenerator.cs

@ -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);
}
}

11
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);
}
}
}

12
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<Guid, IEnrichedAssetEntity> EmptyAssets = Enumerable.Empty<IEnrichedAssetEntity>().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);

14
backend/src/Squidex.Domain.Apps.Entities/IEmailUrlGenerator.cs

@ -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();
}
}

11
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<NotificationEmailTextOptions> 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;

45
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<Guid> appId, NamedId<Guid> schemaId, Guid contentId)
public string AppSettingsUI(NamedId<Guid> 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<Guid> 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<Guid> 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);
}
}
}

4
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<IOptions<UrlsOptions>>(),
c.GetRequiredService<IAssetFileStore>(),
exposeSourceUrl))
.As<IGraphQLUrlGenerator>().As<IUrlGenerator>().As<IAssetUrlGenerator>().As<IEmailUrlGenerator>();
.As<IUrlGenerator>();
services.AddSingletonAs(x => new FuncDependencyResolver(x.GetRequiredService))
.As<IDependencyResolver>();

45
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<IAssetUrlGenerator>();
private readonly IUrlGenerator urlGenerato = A.Fake<IUrlGenerator>();
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<string>._))
.ReturnsLazily(ctx => $"url/to/{ctx.GetArgument<string>(0)}");
A.CallTo(() => urlGenerato.AssetContent(A<Guid>._))
.ReturnsLazily(ctx => $"url/to/{ctx.GetArgument<Guid>(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<string>(new[] { "assets" }), assetUrlGenerator)(source, field);
var result = FieldConverters.ResolveAssetUrls(new HashSet<string>(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<string>(new[] { "array.assets" }), assetUrlGenerator)(source, field);
var result = FieldConverters.ResolveAssetUrls(new HashSet<string>(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<string>(new[] { "*" }), assetUrlGenerator)(source, field);
var result = FieldConverters.ResolveAssetUrls(new HashSet<string>(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<string>(new[] { "*" }), assetUrlGenerator)(source, field);
var result = FieldConverters.ResolveAssetUrls(new HashSet<string>(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<string>(new[] { "other" }), assetUrlGenerator)(source, field);
var result = FieldConverters.ResolveAssetUrls(new HashSet<string>(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);
}

87
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<Guid> 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<Claim> { 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();

2
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<AssetOptions>)] = Options.Create(new AssetOptions()),
[typeof(IOptions<ContentOptions>)] = Options.Create(new ContentOptions()),
[typeof(ISemanticLog)] = A.Fake<ISemanticLog>(),
[typeof(IUrlGenerator)] = new FakeUrlGenerator(),
[typeof(DataLoaderDocumentListener)] = new DataLoaderDocumentListener(dataLoaderContext)
};

5
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<IAssetUrlGenerator>();
private readonly IUrlGenerator urlGenerator = A.Fake<IUrlGenerator>();
private readonly IAssetRepository assetRepository = A.Fake<IAssetRepository>();
private readonly IContentRepository contentRepository = A.Fake<IContentRepository>();
private readonly NamedId<Guid> 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]

9
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<IAssetQueryService>();
private readonly IAssetUrlGenerator assetUrlGenerator = A.Fake<IAssetUrlGenerator>();
private readonly IUrlGenerator urlGenerator = A.Fake<IUrlGenerator>();
private readonly IRequestCache requestCache = A.Fake<IRequestCache>();
private readonly NamedId<Guid> appId = NamedId.Of(Guid.NewGuid(), "my-app");
private readonly NamedId<Guid> 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<string>._))
.ReturnsLazily(new Func<string, string>(id => $"url/to/{id}"));
A.CallTo(() => urlGenerator.AssetContent(A<Guid>._))
.ReturnsLazily(ctx => $"url/to/{ctx.GetArgument<Guid>(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]

121
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<Guid> appId, NamedId<Guid> schemaId, Guid contentId)
{
return $"contents/{schema.SchemaDef.Name}/{content.Id}";
return $"contents/{schemaId.Name}/{contentId}";
}
public string AppSettingsUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string AssetsUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string AssetsUI(NamedId<Guid> appId, string? query = null)
{
throw new NotSupportedException();
}
public string AssetSource(Guid assetId)
{
throw new NotSupportedException();
}
public string BackupsUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string ClientsUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string ContentsUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string ContentsUI(NamedId<Guid> appId, NamedId<Guid> schemaId)
{
throw new NotSupportedException();
}
public string ContributorsUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string DashboardUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string LanguagesUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string PatternsUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string PlansUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string RolesUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string RulesUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string SchemasUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string SchemaUI(NamedId<Guid> appId, NamedId<Guid> schemaId)
{
throw new NotSupportedException();
}
public string WorkflowsUI(NamedId<Guid> appId)
{
throw new NotSupportedException();
}
public string UI()
{
throw new NotSupportedException();
}
}
}

7
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<IEmailSender>();
private readonly IEmailUrlGenerator emailUrlGenerator = A.Fake<IEmailUrlGenerator>();
private readonly IUrlGenerator urlGenerator = A.Fake<IUrlGenerator>();
private readonly IUser assigner = A.Fake<IUser>();
private readonly IUser user = A.Fake<IUser>();
private readonly ISemanticLog log = A.Fake<ISemanticLog>();
@ -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]

Loading…
Cancel
Save