mirror of https://github.com/Squidex/squidex.git
Browse Source
* Make everything async ready. * Testing the extension interface and extracting predefined rules. * Resolve reference. * Do not check for data. * Timestamp transform.pull/531/head
committed by
GitHub
25 changed files with 798 additions and 437 deletions
@ -0,0 +1,25 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading.Tasks; |
|||
using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; |
|||
|
|||
namespace Squidex.Domain.Apps.Core.HandleRules |
|||
{ |
|||
public interface IRuleEventFormatter |
|||
{ |
|||
(bool Match, string?, int ReplacedLength) Format(EnrichedEvent @event, string text) |
|||
{ |
|||
return default; |
|||
} |
|||
|
|||
(bool Match, ValueTask<string?>) Format(EnrichedEvent @event, object value, string[] path) |
|||
{ |
|||
return default; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,197 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Globalization; |
|||
using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Shared.Users; |
|||
|
|||
namespace Squidex.Domain.Apps.Core.HandleRules |
|||
{ |
|||
public sealed class PredefinedPatternsFormatter : IRuleEventFormatter |
|||
{ |
|||
private readonly List<(string Pattern, Func<EnrichedEvent, string?> Replacer)> patterns = new List<(string Pattern, Func<EnrichedEvent, string?> Replacer)>(); |
|||
private readonly IUrlGenerator urlGenerator; |
|||
|
|||
public PredefinedPatternsFormatter(IUrlGenerator urlGenerator) |
|||
{ |
|||
Guard.NotNull(urlGenerator, nameof(urlGenerator)); |
|||
|
|||
this.urlGenerator = urlGenerator; |
|||
|
|||
AddPattern("APP_ID", AppId); |
|||
AddPattern("APP_NAME", AppName); |
|||
AddPattern("ASSET_CONTENT_URL", AssetContentUrl); |
|||
AddPattern("CONTENT_ACTION", ContentAction); |
|||
AddPattern("CONTENT_URL", ContentUrl); |
|||
AddPattern("MENTIONED_ID", MentionedId); |
|||
AddPattern("MENTIONED_NAME", MentionedName); |
|||
AddPattern("MENTIONED_EMAIL", MentionedEmail); |
|||
AddPattern("SCHEMA_ID", SchemaId); |
|||
AddPattern("SCHEMA_NAME", SchemaName); |
|||
AddPattern("TIMESTAMP_DATETIME", TimestampTime); |
|||
AddPattern("TIMESTAMP_DATE", TimestampDate); |
|||
AddPattern("USER_ID", UserId); |
|||
AddPattern("USER_NAME", UserName); |
|||
AddPattern("USER_EMAIL", UserEmail); |
|||
} |
|||
|
|||
private void AddPattern(string placeholder, Func<EnrichedEvent, string?> generator) |
|||
{ |
|||
patterns.Add((placeholder, generator)); |
|||
} |
|||
|
|||
public (bool Match, string?, int ReplacedLength) Format(EnrichedEvent @event, string text) |
|||
{ |
|||
for (var j = 0; j < patterns.Count; j++) |
|||
{ |
|||
var (pattern, replacer) = patterns[j]; |
|||
|
|||
if (text.StartsWith(pattern, StringComparison.OrdinalIgnoreCase)) |
|||
{ |
|||
var result = replacer(@event); |
|||
|
|||
return (true, result, pattern.Length); |
|||
} |
|||
} |
|||
|
|||
return default; |
|||
} |
|||
|
|||
private static string TimestampDate(EnrichedEvent @event) |
|||
{ |
|||
return @event.Timestamp.ToDateTimeUtc().ToString("yyy-MM-dd", CultureInfo.InvariantCulture); |
|||
} |
|||
|
|||
private static string TimestampTime(EnrichedEvent @event) |
|||
{ |
|||
return @event.Timestamp.ToDateTimeUtc().ToString("yyy-MM-dd-hh-mm-ss", CultureInfo.InvariantCulture); |
|||
} |
|||
|
|||
private static string AppId(EnrichedEvent @event) |
|||
{ |
|||
return @event.AppId.Id.ToString(); |
|||
} |
|||
|
|||
private static string AppName(EnrichedEvent @event) |
|||
{ |
|||
return @event.AppId.Name; |
|||
} |
|||
|
|||
private static string? SchemaId(EnrichedEvent @event) |
|||
{ |
|||
if (@event is EnrichedSchemaEventBase schemaEvent) |
|||
{ |
|||
return schemaEvent.SchemaId.Id.ToString(); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
private static string? SchemaName(EnrichedEvent @event) |
|||
{ |
|||
if (@event is EnrichedSchemaEventBase schemaEvent) |
|||
{ |
|||
return schemaEvent.SchemaId.Name; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
private static string? ContentAction(EnrichedEvent @event) |
|||
{ |
|||
if (@event is EnrichedContentEvent contentEvent) |
|||
{ |
|||
return contentEvent.Type.ToString(); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
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 null; |
|||
} |
|||
|
|||
private static string? UserName(EnrichedEvent @event) |
|||
{ |
|||
if (@event is EnrichedUserEventBase userEvent) |
|||
{ |
|||
return userEvent.User?.DisplayName(); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
private static string? UserId(EnrichedEvent @event) |
|||
{ |
|||
if (@event is EnrichedUserEventBase userEvent) |
|||
{ |
|||
return userEvent.User?.Id; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
private static string? UserEmail(EnrichedEvent @event) |
|||
{ |
|||
if (@event is EnrichedUserEventBase userEvent) |
|||
{ |
|||
return userEvent.User?.Email; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
private static string? MentionedName(EnrichedEvent @event) |
|||
{ |
|||
if (@event is EnrichedCommentEvent commentEvent) |
|||
{ |
|||
return commentEvent.MentionedUser.DisplayName(); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
private static string? MentionedId(EnrichedEvent @event) |
|||
{ |
|||
if (@event is EnrichedCommentEvent commentEvent) |
|||
{ |
|||
return commentEvent.MentionedUser.Id; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
private static string? MentionedEmail(EnrichedEvent @event) |
|||
{ |
|||
if (@event is EnrichedCommentEvent commentEvent) |
|||
{ |
|||
return commentEvent.MentionedUser.Email; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,101 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using Squidex.Domain.Apps.Core.Contents; |
|||
using Squidex.Infrastructure.Json.Objects; |
|||
using Squidex.Shared.Identity; |
|||
using Squidex.Shared.Users; |
|||
|
|||
namespace Squidex.Domain.Apps.Core.HandleRules |
|||
{ |
|||
public static class RuleVariable |
|||
{ |
|||
public static (object? Result, string[] Remaining) GetValue(object @event, string[] path) |
|||
{ |
|||
object? current = @event; |
|||
|
|||
var i = 0; |
|||
|
|||
for (; i < path.Length; i++) |
|||
{ |
|||
var segment = path[i]; |
|||
|
|||
if (current is NamedContentData data) |
|||
{ |
|||
if (!data.TryGetValue(segment, out var temp) || temp == null) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
current = temp; |
|||
} |
|||
else if (current is ContentFieldData field) |
|||
{ |
|||
if (!field.TryGetValue(segment, out var temp) || temp == null) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
current = temp; |
|||
} |
|||
else if (current is IJsonValue json) |
|||
{ |
|||
if (!json.TryGet(segment, out var temp) || temp == null || temp.Type == JsonValueType.Null) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
current = temp; |
|||
} |
|||
else if (current != null) |
|||
{ |
|||
if (current is IUser user) |
|||
{ |
|||
var type = segment; |
|||
|
|||
if (string.Equals(type, "Name", StringComparison.OrdinalIgnoreCase)) |
|||
{ |
|||
type = SquidexClaimTypes.DisplayName; |
|||
} |
|||
|
|||
var claim = user.Claims.FirstOrDefault(x => string.Equals(x.Type, type, StringComparison.OrdinalIgnoreCase)); |
|||
|
|||
if (claim != null) |
|||
{ |
|||
current = claim.Value; |
|||
continue; |
|||
} |
|||
} |
|||
|
|||
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) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
current = property.GetValue(current); |
|||
} |
|||
else |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return (current, path.Skip(i).ToArray()); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue