mirror of https://github.com/Squidex/squidex.git
committed by
GitHub
43 changed files with 873 additions and 98 deletions
@ -0,0 +1,106 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Text.RegularExpressions; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.ExtractReferenceIds |
||||
|
{ |
||||
|
public sealed class StringReferenceExtractor |
||||
|
{ |
||||
|
private readonly List<Regex> contentsPatterns = new List<Regex>(); |
||||
|
private readonly List<Regex> assetsPatterns = new List<Regex>(); |
||||
|
|
||||
|
public StringReferenceExtractor(IUrlGenerator urlGenerator) |
||||
|
{ |
||||
|
AddAssetPattern(@"assets?:(?<Id>[a-z0-9\-_9]+)"); |
||||
|
AddAssetUrlPatterns(urlGenerator.AssetContentBase()); |
||||
|
AddAssetUrlPatterns(urlGenerator.AssetContentCDNBase()); |
||||
|
|
||||
|
AddContentPattern(@"contents?:(?<Id>[a-z0-9\-_9]+)"); |
||||
|
AddContentUrlPatterns(urlGenerator.ContentBase()); |
||||
|
AddContentUrlPatterns(urlGenerator.ContentCDNBase()); |
||||
|
} |
||||
|
|
||||
|
private void AddContentUrlPatterns(string baseUrl) |
||||
|
{ |
||||
|
if (string.IsNullOrWhiteSpace(baseUrl)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!baseUrl.EndsWith('/')) |
||||
|
{ |
||||
|
baseUrl += "/"; |
||||
|
} |
||||
|
|
||||
|
baseUrl = Regex.Escape(baseUrl); |
||||
|
|
||||
|
AddContentPattern(baseUrl + @"(.+)\/(.+)\/(?<Id>[a-z0-9\-_9]+)"); |
||||
|
} |
||||
|
|
||||
|
private void AddAssetUrlPatterns(string baseUrl) |
||||
|
{ |
||||
|
if (string.IsNullOrWhiteSpace(baseUrl)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!baseUrl.EndsWith('/')) |
||||
|
{ |
||||
|
baseUrl += "/"; |
||||
|
} |
||||
|
|
||||
|
baseUrl = Regex.Escape(baseUrl); |
||||
|
|
||||
|
AddAssetPattern(baseUrl + @"(?<Id>[a-z0-9\-_9]+)"); |
||||
|
AddAssetPattern(baseUrl + @"(.+)\/(?<Id>[a-z0-9\-_9]+)"); |
||||
|
} |
||||
|
|
||||
|
private void AddAssetPattern(string pattern) |
||||
|
{ |
||||
|
assetsPatterns.Add(new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture)); |
||||
|
} |
||||
|
|
||||
|
private void AddContentPattern(string pattern) |
||||
|
{ |
||||
|
contentsPatterns.Add(new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture)); |
||||
|
} |
||||
|
|
||||
|
public IEnumerable<DomainId> GetEmbeddedContentIds(string text) |
||||
|
{ |
||||
|
if (string.IsNullOrWhiteSpace(text)) |
||||
|
{ |
||||
|
yield break; |
||||
|
} |
||||
|
|
||||
|
foreach (var pattern in contentsPatterns) |
||||
|
{ |
||||
|
foreach (Match match in pattern.Matches(text)) |
||||
|
{ |
||||
|
yield return DomainId.Create(match.Groups["Id"].Value); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public IEnumerable<DomainId> GetEmbeddedAssetIds(string text) |
||||
|
{ |
||||
|
if (string.IsNullOrWhiteSpace(text)) |
||||
|
{ |
||||
|
yield break; |
||||
|
} |
||||
|
|
||||
|
foreach (var pattern in assetsPatterns) |
||||
|
{ |
||||
|
foreach (Match match in pattern.Matches(text)) |
||||
|
{ |
||||
|
yield return DomainId.Create(match.Groups["Id"].Value); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,64 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using GraphQL.Types; |
||||
|
using Squidex.Domain.Apps.Core; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Collections; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents |
||||
|
{ |
||||
|
internal sealed class EmbeddableStringGraphType : ObjectGraphType<string> |
||||
|
{ |
||||
|
public EmbeddableStringGraphType(Builder builder, FieldInfo fieldInfo, StringFieldProperties properties) |
||||
|
{ |
||||
|
// The name is used for equal comparison. Therefore it is important to treat it as readonly.
|
||||
|
Name = fieldInfo.EmbeddableStringType; |
||||
|
|
||||
|
AddField(ContentFields.StringFieldText); |
||||
|
AddField(ContentFields.StringFieldAssets); |
||||
|
|
||||
|
var referenceType = ResolveReferences(builder, fieldInfo, properties.SchemaIds); |
||||
|
|
||||
|
if (referenceType != null) |
||||
|
{ |
||||
|
AddField(new FieldType |
||||
|
{ |
||||
|
Name = "contents", |
||||
|
ResolvedType = new NonNullGraphType(new ListGraphType(new NonNullGraphType(referenceType))), |
||||
|
Resolver = ContentFields.ResolveStringFieldContents, |
||||
|
Description = FieldDescriptions.StringFieldReferences |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static IGraphType? ResolveReferences(Builder builder, FieldInfo fieldInfo, ReadonlyList<DomainId>? schemaIds) |
||||
|
{ |
||||
|
IGraphType? contentType = null; |
||||
|
|
||||
|
if (schemaIds?.Count == 1) |
||||
|
{ |
||||
|
contentType = builder.GetContentType(schemaIds[0]); |
||||
|
} |
||||
|
|
||||
|
if (contentType == null) |
||||
|
{ |
||||
|
var union = new ReferenceUnionGraphType(builder, fieldInfo, schemaIds); |
||||
|
|
||||
|
if (!union.HasType) |
||||
|
{ |
||||
|
return default; |
||||
|
} |
||||
|
|
||||
|
contentType = union; |
||||
|
} |
||||
|
|
||||
|
return contentType; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using GraphQL.Resolvers; |
||||
|
using GraphQL.Types; |
||||
|
|
||||
|
#pragma warning disable SA1313 // Parameter names should begin with lower-case letter
|
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents |
||||
|
{ |
||||
|
public record struct FieldGraphSchema(IGraphType? Type, IFieldResolver? Resolver, QueryArguments? Arguments); |
||||
|
} |
||||
@ -0,0 +1,64 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using FakeItEasy; |
||||
|
using Squidex.Domain.Apps.Core.ExtractReferenceIds; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds |
||||
|
{ |
||||
|
public class StringReferenceExtractorTests |
||||
|
{ |
||||
|
private readonly StringReferenceExtractor sut; |
||||
|
|
||||
|
public StringReferenceExtractorTests() |
||||
|
{ |
||||
|
var urlGenerator = A.Fake<IUrlGenerator>(); |
||||
|
|
||||
|
A.CallTo(() => urlGenerator.ContentBase()) |
||||
|
.Returns("https://cloud.squidex.io/api/content/"); |
||||
|
|
||||
|
A.CallTo(() => urlGenerator.ContentCDNBase()) |
||||
|
.Returns("https://contents.squidex.io/"); |
||||
|
|
||||
|
A.CallTo(() => urlGenerator.AssetContentBase()) |
||||
|
.Returns("https://cloud.squidex.io/api/assets/"); |
||||
|
|
||||
|
A.CallTo(() => urlGenerator.AssetContentCDNBase()) |
||||
|
.Returns("https://assets.squidex.io/"); |
||||
|
|
||||
|
sut = new StringReferenceExtractor(urlGenerator); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData("before content:a_b-123|after")] |
||||
|
[InlineData("before contents:a_b-123|after")] |
||||
|
[InlineData("before https://cloud.squidex.io/api/content/my-app/my-schema/a_b-123|after")] |
||||
|
[InlineData("before https://contents.squidex.io/my-app/my-schema/a_b-123|after")] |
||||
|
public void Should_extract_content_id(string input) |
||||
|
{ |
||||
|
var ids = sut.GetEmbeddedContentIds(input); |
||||
|
|
||||
|
Assert.Contains(DomainId.Create("a_b-123"), ids.ToList()); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData("before asset:a_b-123|after")] |
||||
|
[InlineData("before assets:a_b-123|after")] |
||||
|
[InlineData("before https://cloud.squidex.io/api/assets/a_b-123|after")] |
||||
|
[InlineData("before https://cloud.squidex.io/api/assets/my-app/a_b-123|after")] |
||||
|
[InlineData("before https://assets.squidex.io/a_b-123|after")] |
||||
|
[InlineData("before https://assets.squidex.io/my-app/a_b-123|after")] |
||||
|
public void Should_extract_asset_id(string input) |
||||
|
{ |
||||
|
var ids = sut.GetEmbeddedAssetIds(input); |
||||
|
|
||||
|
Assert.Contains(DomainId.Create("a_b-123"), ids.ToList()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue