diff --git a/src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTriggerSchema.cs b/src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTriggerSchema.cs index 33d073f5a..aca1f16e5 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTriggerSchema.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTriggerSchema.cs @@ -20,5 +20,7 @@ namespace Squidex.Domain.Apps.Core.Rules.Triggers public bool SendDelete { get; set; } public bool SendPublish { get; set; } + + public bool SendUnpublish { get; set; } } } diff --git a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/AlgoliaActionHandler.cs b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/AlgoliaActionHandler.cs index 83678590c..3d7171141 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/AlgoliaActionHandler.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/AlgoliaActionHandler.cs @@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules.Actions }; if (contentEvent.Action == EnrichedContentEventAction.Deleted || - contentEvent.Action == EnrichedContentEventAction.Archived) + contentEvent.Action == EnrichedContentEventAction.Unpublished) { ruleDescription = $"Delete entry from Algolia index: {action.IndexName}"; } diff --git a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/ElasticSearchActionHandler.cs b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/ElasticSearchActionHandler.cs index 7eb7fe61d..624795c6b 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/ElasticSearchActionHandler.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/ElasticSearchActionHandler.cs @@ -78,13 +78,13 @@ namespace Squidex.Domain.Apps.Core.HandleRules.Actions }; if (contentEvent.Action == EnrichedContentEventAction.Deleted || - contentEvent.Action == EnrichedContentEventAction.Archived) + contentEvent.Action == EnrichedContentEventAction.Unpublished) { - ruleDescription = $"Delete entry from Algolia index: {action.IndexName}"; + ruleDescription = $"Delete entry index: {action.IndexName}"; } else { - ruleDescription = $"Upsert to ES index: {action.IndexName}"; + ruleDescription = $"Upsert to index: {action.IndexName}"; ruleJob.Content = formatter.ToPayload(contentEvent); ruleJob.Content["objectID"] = contentId; diff --git a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/EnrichedEvents/EnrichedContentEventAction.cs b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/EnrichedEvents/EnrichedContentEventAction.cs index 57d107e82..6c02c8f48 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/EnrichedEvents/EnrichedContentEventAction.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/EnrichedEvents/EnrichedContentEventAction.cs @@ -9,11 +9,10 @@ namespace Squidex.Domain.Apps.Core.HandleRules.EnrichedEvents { public enum EnrichedContentEventAction { - Archived, Created, Deleted, Published, - Restored, + Unpublished, Updated } } diff --git a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Triggers/ContentChangedTriggerHandler.cs b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Triggers/ContentChangedTriggerHandler.cs index 6914f3d44..c0505f309 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Triggers/ContentChangedTriggerHandler.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Triggers/ContentChangedTriggerHandler.cs @@ -44,10 +44,36 @@ namespace Squidex.Domain.Apps.Core.HandleRules.Triggers private static bool MatchsType(ContentChangedTriggerSchema schema, SchemaEvent @event) { return - (schema.SendCreate && @event is ContentCreated) || - (schema.SendUpdate && @event is ContentUpdated) || - (schema.SendDelete && @event is ContentDeleted) || - (schema.SendPublish && @event is ContentStatusChanged statusChanged && statusChanged.Status == Status.Published); + IsCreate(schema, @event) || + IsUpdate(schema, @event) || + IsDelete(schema, @event) || + IsPublished(schema, @event) || + IsUnpublished(schema, @event); + } + + private static bool IsPublished(ContentChangedTriggerSchema schema, SchemaEvent @event) + { + return schema.SendPublish && @event is ContentStatusChanged statusChanged && statusChanged.Status == Status.Published; + } + + private static bool IsUnpublished(ContentChangedTriggerSchema schema, SchemaEvent @event) + { + return schema.SendUnpublish && @event is ContentStatusChanged statusChanged && statusChanged.Status != Status.Published; + } + + private static bool IsCreate(ContentChangedTriggerSchema schema, SchemaEvent @event) + { + return schema.SendCreate && @event is ContentCreated; + } + + private static bool IsUpdate(ContentChangedTriggerSchema schema, SchemaEvent @event) + { + return schema.SendUpdate && @event is ContentUpdated || schema.SendUpdate && @event is ContentChangesPublished; + } + + private static bool IsDelete(ContentChangedTriggerSchema schema, SchemaEvent @event) + { + return (schema.SendDelete && @event is ContentDeleted); } } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentVersionLoader.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentVersionLoader.cs index dca35ba34..7016766ef 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentVersionLoader.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentVersionLoader.cs @@ -7,52 +7,37 @@ using System; using System.Threading.Tasks; -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Contents.State; +using Orleans; using Squidex.Infrastructure; using Squidex.Infrastructure.Log; -using Squidex.Infrastructure.States; namespace Squidex.Domain.Apps.Entities.Contents { public sealed class ContentVersionLoader : IContentVersionLoader { - private readonly IStore store; - private readonly FieldRegistry registry; + private readonly IGrainFactory grainFactory; - public ContentVersionLoader(IStore store, FieldRegistry registry) + public ContentVersionLoader(IGrainFactory grainFactory) { - Guard.NotNull(store, nameof(store)); - Guard.NotNull(registry, nameof(registry)); + Guard.NotNull(grainFactory, nameof(grainFactory)); - this.store = store; - - this.registry = registry; + this.grainFactory = grainFactory; } public async Task LoadAsync(Guid id, long version) { using (Profiler.TraceMethod()) { - var content = new ContentState(); - - var persistence = store.WithEventSourcing(id, e => - { - if (content.Version < version) - { - content = content.Apply(e); - content.Version++; - } - }); + var grain = grainFactory.GetGrain(id); - await persistence.ReadAsync(); + var content = await grain.GetStateAsync(version); - if (content.Version != version) + if (content.Value == null || content.Value.Version != version) { throw new DomainObjectNotFoundException(id.ToString(), typeof(IContentEntity)); } - return content; + return content.Value; } } } diff --git a/src/Squidex.Domain.Apps.Entities/Rules/EventEnricher.cs b/src/Squidex.Domain.Apps.Entities/Rules/EventEnricher.cs new file mode 100644 index 000000000..7c51d63cf --- /dev/null +++ b/src/Squidex.Domain.Apps.Entities/Rules/EventEnricher.cs @@ -0,0 +1,123 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Threading.Tasks; +using NodaTime; +using Orleans; +using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Core.HandleRules; +using Squidex.Domain.Apps.Core.HandleRules.EnrichedEvents; +using Squidex.Domain.Apps.Entities.Contents; +using Squidex.Domain.Apps.Events; +using Squidex.Domain.Apps.Events.Assets; +using Squidex.Domain.Apps.Events.Contents; +using Squidex.Infrastructure; +using Squidex.Infrastructure.EventSourcing; +using Squidex.Infrastructure.Reflection; + +namespace Squidex.Domain.Apps.Entities.Rules +{ + public sealed class EventEnricher : IEventEnricher + { + private readonly IGrainFactory grainFactory; + private readonly IClock clock; + + public EventEnricher(IGrainFactory grainFactory, IClock clock) + { + Guard.NotNull(grainFactory, nameof(grainFactory)); + Guard.NotNull(clock, nameof(clock)); + + this.grainFactory = grainFactory; + + this.clock = clock; + } + + public Task EnrichAsync(Envelope @event) + { + Guard.NotNull(@event, nameof(@event)); + + if (@event.Payload is ContentEvent contentEvent) + { + return CreateContentEventAsync(contentEvent, @event); + } + + if (@event.Payload is AssetEvent assetEvent) + { + } + + return Task.FromResult(null); + } + + private async Task CreateContentEventAsync(ContentEvent contentEvent, Envelope @event) + { + var result = new EnrichedContentEvent(); + + var content = + (await grainFactory + .GetGrain(contentEvent.ContentId) + .GetStateAsync(@event.Headers.EventStreamNumber())).Value; + + SimpleMapper.Map(content, result); + + result.Data = content.Data ?? content.DataDraft; + + switch (contentEvent) + { + case ContentCreated e: + result.Action = EnrichedContentEventAction.Created; + break; + case ContentDeleted e: + result.Action = EnrichedContentEventAction.Deleted; + break; + case ContentUpdated e: + result.Action = EnrichedContentEventAction.Updated; + break; + case ContentStatusChanged e: + if (e.Status == Status.Published) + { + result.Action = EnrichedContentEventAction.Published; + } + else + { + result.Action = EnrichedContentEventAction.Unpublished; + } + + break; + } + + result.Name = $"{content.SchemaId.Name.ToPascalCase()}{result.Action}"; + + SetDefault(result, @event); + + return result; + } + + private void SetDefault(EnrichedEvent result, Envelope @event) + { + result.Timestamp = + @event.Headers.Contains(CommonHeaders.Timestamp) ? + @event.Headers.Timestamp() : + clock.GetCurrentInstant(); + + result.AggregateId = + @event.Headers.Contains(CommonHeaders.AggregateId) ? + @event.Headers.AggregateId() : + Guid.NewGuid(); + + if (@event.Payload is SquidexEvent squidexEvent) + { + result.Actor = squidexEvent.Actor; + } + + if (@event.Payload is AppEvent appEvent) + { + result.AppId = appEvent.AppId; + } + } + } +} diff --git a/src/Squidex/Areas/Api/Controllers/Rules/Models/Triggers/ContentChangedTriggerSchemaDto.cs b/src/Squidex/Areas/Api/Controllers/Rules/Models/Triggers/ContentChangedTriggerSchemaDto.cs index dacd359b3..14e17c511 100644 --- a/src/Squidex/Areas/Api/Controllers/Rules/Models/Triggers/ContentChangedTriggerSchemaDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Rules/Models/Triggers/ContentChangedTriggerSchemaDto.cs @@ -35,5 +35,10 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models.Triggers /// Determines whether to handle the event when a content is published. /// public bool SendPublish { get; set; } + + /// + /// Determines whether to handle the event when a content is unpublished. + /// + public bool SendUnpublish { get; set; } } }