mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
5.8 KiB
162 lines
5.8 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// =========================================-=================================
|
|
|
|
using System.Globalization;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using Squidex.Domain.Apps.Core.Contents;
|
|
using Squidex.Domain.Apps.Events;
|
|
using Squidex.Domain.Apps.Events.Contents;
|
|
using Squidex.Infrastructure;
|
|
using Squidex.Infrastructure.EventSourcing;
|
|
|
|
namespace Squidex.Domain.Apps.Core.HandleRules
|
|
{
|
|
public class RuleEventFormatter
|
|
{
|
|
private const string Undefined = "UNDEFINED";
|
|
private const string AppIdPlaceholder = "$APP_ID";
|
|
private const string AppNamePlaceholder = "$APP_NAME";
|
|
private const string SchemaIdPlaceholder = "$SCHEMA_ID";
|
|
private const string SchemaNamePlaceholder = "$SCHEMA_NAME";
|
|
private const string TimestampDatePlaceholder = "$TIMESTAMP_DATE";
|
|
private const string TimestampDateTimePlaceholder = "$TIMESTAMP_DATETIME";
|
|
private const string ContentActionPlaceholder = "$CONTENT_ACTION";
|
|
private static readonly Regex ContentDataPlaceholder = new Regex(@"\$CONTENT_DATA(\.([0-9A-Za-z\-_]*)){2,}", RegexOptions.Compiled);
|
|
private readonly JsonSerializer serializer;
|
|
|
|
public RuleEventFormatter(JsonSerializer serializer)
|
|
{
|
|
Guard.NotNull(serializer, nameof(serializer));
|
|
|
|
this.serializer = serializer;
|
|
}
|
|
|
|
public virtual JToken ToRouteData(object value)
|
|
{
|
|
return JToken.FromObject(value, serializer);
|
|
}
|
|
|
|
public virtual string FormatString(string text, Envelope<AppEvent> @event)
|
|
{
|
|
var sb = new StringBuilder(text);
|
|
|
|
if (@event.Headers.Contains(CommonHeaders.Timestamp))
|
|
{
|
|
var timestamp = @event.Headers.Timestamp().ToDateTimeUtc();
|
|
|
|
sb.Replace(TimestampDateTimePlaceholder, timestamp.ToString("yyy-MM-dd-hh-mm-ss", CultureInfo.InvariantCulture));
|
|
sb.Replace(TimestampDatePlaceholder, timestamp.ToString("yyy-MM-dd", CultureInfo.InvariantCulture));
|
|
}
|
|
|
|
if (@event.Payload.AppId != null)
|
|
{
|
|
sb.Replace(AppIdPlaceholder, @event.Payload.AppId.Id.ToString());
|
|
sb.Replace(AppNamePlaceholder, @event.Payload.AppId.Name);
|
|
}
|
|
|
|
if (@event.Payload is SchemaEvent schemaEvent && schemaEvent.SchemaId != null)
|
|
{
|
|
sb.Replace(SchemaIdPlaceholder, schemaEvent.SchemaId.Id.ToString());
|
|
sb.Replace(SchemaNamePlaceholder, schemaEvent.SchemaId.Name);
|
|
}
|
|
|
|
FormatContentAction(@event, sb);
|
|
|
|
var result = sb.ToString();
|
|
|
|
if (@event.Payload is ContentCreated contentCreated && contentCreated.Data != null)
|
|
{
|
|
result = ReplaceData(contentCreated.Data, result);
|
|
}
|
|
|
|
if (@event.Payload is ContentUpdated contentUpdated && contentUpdated.Data != null)
|
|
{
|
|
result = ReplaceData(contentUpdated.Data, result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private static void FormatContentAction(Envelope<AppEvent> @event, StringBuilder sb)
|
|
{
|
|
switch (@event.Payload)
|
|
{
|
|
case ContentCreated contentCreated:
|
|
sb.Replace(ContentActionPlaceholder, "created");
|
|
break;
|
|
|
|
case ContentUpdated contentUpdated:
|
|
sb.Replace(ContentActionPlaceholder, "updated");
|
|
break;
|
|
|
|
case ContentStatusChanged contentStatusChanged:
|
|
sb.Replace(ContentActionPlaceholder, $"set to {contentStatusChanged.Status.ToString().ToLowerInvariant()}");
|
|
break;
|
|
|
|
case ContentDeleted contentDeleted:
|
|
sb.Replace(ContentActionPlaceholder, "deleted");
|
|
break;
|
|
}
|
|
}
|
|
|
|
private static string ReplaceData(NamedContentData data, string text)
|
|
{
|
|
return ContentDataPlaceholder.Replace(text, match =>
|
|
{
|
|
var captures = match.Groups[2].Captures;
|
|
|
|
var path = new string[captures.Count];
|
|
|
|
for (var i = 0; i < path.Length; i++)
|
|
{
|
|
path[i] = captures[i].Value;
|
|
}
|
|
|
|
if (!data.TryGetValue(path[0], out var field))
|
|
{
|
|
return Undefined;
|
|
}
|
|
|
|
if (!field.TryGetValue(path[1], out var value))
|
|
{
|
|
return Undefined;
|
|
}
|
|
|
|
for (var j = 2; j < path.Length; j++)
|
|
{
|
|
if (value is JObject obj && obj.TryGetValue(path[j], out value))
|
|
{
|
|
continue;
|
|
}
|
|
if (value is JArray arr && int.TryParse(path[j], out var idx) && idx >= 0 && idx < arr.Count)
|
|
{
|
|
value = arr[idx];
|
|
}
|
|
else
|
|
{
|
|
return Undefined;
|
|
}
|
|
}
|
|
|
|
if (value == null || value.Type == JTokenType.Null || value.Type == JTokenType.Undefined)
|
|
{
|
|
return Undefined;
|
|
}
|
|
|
|
if (value is JValue jValue && jValue != null)
|
|
{
|
|
return jValue.Value.ToString();
|
|
}
|
|
|
|
return value?.ToString(Formatting.Indented) ?? Undefined;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|