From 3c732f8d9b0ee65eed9f2d2338e36c490f455485 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 16 Sep 2020 17:12:37 +0200 Subject: [PATCH] Algolia fixes. --- .../Actions/Algolia/AlgoliaAction.cs | 4 ++ .../Actions/Algolia/AlgoliaActionHandler.cs | 17 ++++--- .../ElasticSearch/ElasticSearchAction.cs | 9 ++++ .../ElasticSearchActionHandler.cs | 45 +++++++++++++++---- .../Actions/{HttpHelper.cs => RuleHelper.cs} | 32 ++++++++++++- 5 files changed, 91 insertions(+), 16 deletions(-) rename backend/extensions/Squidex.Extensions/Actions/{HttpHelper.cs => RuleHelper.cs} (60%) diff --git a/backend/extensions/Squidex.Extensions/Actions/Algolia/AlgoliaAction.cs b/backend/extensions/Squidex.Extensions/Actions/Algolia/AlgoliaAction.cs index bcd2efd83..261470ee6 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Algolia/AlgoliaAction.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Algolia/AlgoliaAction.cs @@ -43,5 +43,9 @@ namespace Squidex.Extensions.Actions.Algolia [DataType(DataType.MultilineText)] [Formattable] public string Document { get; set; } + + [Display(Name = "Deletion", Description = "The condition when to delete the entry.")] + [DataType(DataType.Text)] + public string Delete { get; set; } } } diff --git a/backend/extensions/Squidex.Extensions/Actions/Algolia/AlgoliaActionHandler.cs b/backend/extensions/Squidex.Extensions/Actions/Algolia/AlgoliaActionHandler.cs index 442738af0..0eb38e08e 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Algolia/AlgoliaActionHandler.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Algolia/AlgoliaActionHandler.cs @@ -13,6 +13,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; +using Squidex.Domain.Apps.Core.Scripting; #pragma warning disable IDE0059 // Value assigned to symbol is never used @@ -21,8 +22,9 @@ namespace Squidex.Extensions.Actions.Algolia public sealed class AlgoliaActionHandler : RuleActionHandler { private readonly ClientPool<(string AppId, string ApiKey, string IndexName), ISearchIndex> clients; + private readonly IScriptEngine scriptEngine; - public AlgoliaActionHandler(RuleEventFormatter formatter) + public AlgoliaActionHandler(RuleEventFormatter formatter, IScriptEngine scriptEngine) : base(formatter) { clients = new ClientPool<(string AppId, string ApiKey, string IndexName), ISearchIndex>(key => @@ -31,13 +33,17 @@ namespace Squidex.Extensions.Actions.Algolia return client.InitIndex(key.IndexName); }); + + this.scriptEngine = scriptEngine; } protected override async Task<(string Description, AlgoliaJob Data)> CreateJobAsync(EnrichedEvent @event, AlgoliaAction action) { - if (@event is EnrichedContentEvent contentEvent) + if (@event is IEnrichedEntityEvent entityEvent) { - var contentId = contentEvent.Id.ToString(); + var delete = @event.ShouldDelete(scriptEngine, action.Delete); + + var contentId = entityEvent.Id.ToString(); var ruleDescription = string.Empty; var ruleJob = new AlgoliaJob @@ -48,8 +54,7 @@ namespace Squidex.Extensions.Actions.Algolia IndexName = await FormatAsync(action.IndexName, @event) }; - if (contentEvent.Type == EnrichedContentEventType.Deleted || - contentEvent.Type == EnrichedContentEventType.Unpublished) + if (delete) { ruleDescription = $"Delete entry from Algolia index: {action.IndexName}"; } @@ -69,7 +74,7 @@ namespace Squidex.Extensions.Actions.Algolia } else { - jsonString = ToJson(contentEvent); + jsonString = ToJson(@event); } json = JObject.Parse(jsonString); diff --git a/backend/extensions/Squidex.Extensions/Actions/ElasticSearch/ElasticSearchAction.cs b/backend/extensions/Squidex.Extensions/Actions/ElasticSearch/ElasticSearchAction.cs index 115f6ea77..c0fc24bd0 100644 --- a/backend/extensions/Squidex.Extensions/Actions/ElasticSearch/ElasticSearchAction.cs +++ b/backend/extensions/Squidex.Extensions/Actions/ElasticSearch/ElasticSearchAction.cs @@ -41,5 +41,14 @@ namespace Squidex.Extensions.Actions.ElasticSearch [Display(Name = "Password", Description = "The optional password.")] [DataType(DataType.Text)] public string Password { get; set; } + + [Display(Name = "Document", Description = "The optional custom document.")] + [DataType(DataType.MultilineText)] + [Formattable] + public string Document { get; set; } + + [Display(Name = "Deletion", Description = "The condition when to delete the document.")] + [DataType(DataType.Text)] + public string Delete { get; set; } } } diff --git a/backend/extensions/Squidex.Extensions/Actions/ElasticSearch/ElasticSearchActionHandler.cs b/backend/extensions/Squidex.Extensions/Actions/ElasticSearch/ElasticSearchActionHandler.cs index a1c0e6363..9b7f167fa 100644 --- a/backend/extensions/Squidex.Extensions/Actions/ElasticSearch/ElasticSearchActionHandler.cs +++ b/backend/extensions/Squidex.Extensions/Actions/ElasticSearch/ElasticSearchActionHandler.cs @@ -9,8 +9,10 @@ using System; using System.Threading; using System.Threading.Tasks; using Elasticsearch.Net; +using Newtonsoft.Json.Linq; using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; +using Squidex.Domain.Apps.Core.Scripting; #pragma warning disable IDE0059 // Value assigned to symbol is never used @@ -19,8 +21,9 @@ namespace Squidex.Extensions.Actions.ElasticSearch public sealed class ElasticSearchActionHandler : RuleActionHandler { private readonly ClientPool<(Uri Host, string Username, string Password), ElasticLowLevelClient> clients; + private readonly IScriptEngine scriptEngine; - public ElasticSearchActionHandler(RuleEventFormatter formatter) + public ElasticSearchActionHandler(RuleEventFormatter formatter, IScriptEngine scriptEngine) : base(formatter) { clients = new ClientPool<(Uri Host, string Username, string Password), ElasticLowLevelClient>(key => @@ -34,16 +37,19 @@ namespace Squidex.Extensions.Actions.ElasticSearch return new ElasticLowLevelClient(config); }); + + this.scriptEngine = scriptEngine; } protected override async Task<(string Description, ElasticSearchJob Data)> CreateJobAsync(EnrichedEvent @event, ElasticSearchAction action) { - if (@event is EnrichedContentEvent contentEvent) + if (@event is IEnrichedEntityEvent entityEvent) { - var contentId = contentEvent.Id.ToString(); + var delete = @event.ShouldDelete(scriptEngine, action.Delete); - var ruleDescription = string.Empty; + var contentId = entityEvent.Id.ToString(); + var ruleDescription = string.Empty; var ruleJob = new ElasticSearchJob { IndexName = await FormatAsync(action.IndexName, @event), @@ -53,8 +59,7 @@ namespace Squidex.Extensions.Actions.ElasticSearch ContentId = contentId }; - if (contentEvent.Type == EnrichedContentEventType.Deleted || - contentEvent.Type == EnrichedContentEventType.Unpublished) + if (delete) { ruleDescription = $"Delete entry index: {action.IndexName}"; } @@ -62,9 +67,31 @@ namespace Squidex.Extensions.Actions.ElasticSearch { ruleDescription = $"Upsert to index: {action.IndexName}"; - var json = ToJson(contentEvent); - - ruleJob.Content = $"{{ \"objectId\": \"{contentId}\", {json.Substring(1)}"; + JObject json; + try + { + string jsonString; + + if (!string.IsNullOrEmpty(action.Document)) + { + jsonString = await FormatAsync(action.Document, @event); + jsonString = jsonString?.Trim(); + } + else + { + jsonString = ToJson(@event); + } + + json = JObject.Parse(jsonString); + } + catch (Exception ex) + { + json = new JObject(new JProperty("error", $"Invalid JSON: {ex.Message}")); + } + + json.AddFirst(new JProperty("contentId", contentId)); + + ruleJob.Content = json.ToString(); } return (ruleDescription, ruleJob); diff --git a/backend/extensions/Squidex.Extensions/Actions/HttpHelper.cs b/backend/extensions/Squidex.Extensions/Actions/RuleHelper.cs similarity index 60% rename from backend/extensions/Squidex.Extensions/Actions/HttpHelper.cs rename to backend/extensions/Squidex.Extensions/Actions/RuleHelper.cs index cc1bdfe69..1869638ea 100644 --- a/backend/extensions/Squidex.Extensions/Actions/HttpHelper.cs +++ b/backend/extensions/Squidex.Extensions/Actions/RuleHelper.cs @@ -10,12 +10,42 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.HandleRules; +using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; +using Squidex.Domain.Apps.Core.Scripting; using Squidex.Infrastructure.Http; namespace Squidex.Extensions.Actions { - public static class HttpHelper + public static class RuleHelper { + public static bool ShouldDelete(this EnrichedEvent @event, IScriptEngine scriptEngine, string? expression) + { + if (!string.IsNullOrWhiteSpace(expression)) + { + var vars = new ScriptVars + { + ["event"] = @event + }; + + return scriptEngine.Evaluate(vars, expression); + } + + return IsContentDeletion(@event) || IsAssetDeletion(@event); + } + + public static bool IsContentDeletion(this EnrichedEvent @event) + { + return @event is EnrichedContentEvent contentEvent && + (contentEvent.Type == EnrichedContentEventType.Deleted || + contentEvent.Type == EnrichedContentEventType.Unpublished); + } + + public static bool IsAssetDeletion(this EnrichedEvent @event) + { + return @event is EnrichedAssetEvent assetEvent && + (assetEvent.Type == EnrichedAssetEventType.Deleted); + } + public static async Task OneWayRequestAsync(this HttpClient client, HttpRequestMessage request, string requestBody = null, CancellationToken ct = default) { HttpResponseMessage response = null;