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.
232 lines
8.0 KiB
232 lines
8.0 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// ==========================================================================
|
|
|
|
using System;
|
|
using System.Threading.Tasks;
|
|
using Squidex.Domain.Apps.Core.Contents;
|
|
using Squidex.Domain.Apps.Core.Scripting;
|
|
using Squidex.Domain.Apps.Entities.Assets.Repositories;
|
|
using Squidex.Domain.Apps.Entities.Contents.Commands;
|
|
using Squidex.Domain.Apps.Entities.Contents.Guards;
|
|
using Squidex.Domain.Apps.Entities.Contents.Repositories;
|
|
using Squidex.Domain.Apps.Entities.Contents.State;
|
|
using Squidex.Domain.Apps.Events;
|
|
using Squidex.Domain.Apps.Events.Contents;
|
|
using Squidex.Infrastructure;
|
|
using Squidex.Infrastructure.Commands;
|
|
using Squidex.Infrastructure.EventSourcing;
|
|
using Squidex.Infrastructure.Reflection;
|
|
using Squidex.Infrastructure.States;
|
|
|
|
namespace Squidex.Domain.Apps.Entities.Contents
|
|
{
|
|
public class ContentGrain : DomainObjectGrain<ContentState>, IContentGrain
|
|
{
|
|
private readonly IAppProvider appProvider;
|
|
private readonly IAssetRepository assetRepository;
|
|
private readonly IContentRepository contentRepository;
|
|
private readonly IScriptEngine scriptEngine;
|
|
|
|
public ContentGrain(
|
|
IStore<Guid> store,
|
|
IAppProvider appProvider,
|
|
IAssetRepository assetRepository,
|
|
IScriptEngine scriptEngine,
|
|
IContentRepository contentRepository)
|
|
: base(store)
|
|
{
|
|
Guard.NotNull(appProvider, nameof(appProvider));
|
|
Guard.NotNull(scriptEngine, nameof(scriptEngine));
|
|
Guard.NotNull(assetRepository, nameof(assetRepository));
|
|
Guard.NotNull(contentRepository, nameof(contentRepository));
|
|
|
|
this.appProvider = appProvider;
|
|
this.scriptEngine = scriptEngine;
|
|
this.assetRepository = assetRepository;
|
|
this.contentRepository = contentRepository;
|
|
}
|
|
|
|
protected override Task<object> ExecuteAsync(IAggregateCommand command)
|
|
{
|
|
VerifyNotDeleted();
|
|
|
|
switch (command)
|
|
{
|
|
case CreateContent createContent:
|
|
return CreateReturnAsync(createContent, async c =>
|
|
{
|
|
GuardContent.CanCreate(c);
|
|
|
|
var operationContext = await CreateContext(c, () => "Failed to create content.");
|
|
|
|
if (c.Publish)
|
|
{
|
|
await operationContext.ExecuteScriptAsync(x => x.ScriptChange, "Published");
|
|
}
|
|
|
|
await operationContext.ExecuteScriptAndTransformAsync(x => x.ScriptCreate, "Create");
|
|
await operationContext.EnrichAsync();
|
|
await operationContext.ValidateAsync();
|
|
|
|
Create(c);
|
|
|
|
return EntityCreatedResult.Create(c.Data, NewVersion);
|
|
});
|
|
|
|
case UpdateContent updateContent:
|
|
return UpdateReturnAsync(updateContent, async c =>
|
|
{
|
|
GuardContent.CanUpdate(c);
|
|
|
|
var operationContext = await CreateContext(c, () => "Failed to update content.");
|
|
|
|
await operationContext.ValidateAsync();
|
|
await operationContext.ExecuteScriptAndTransformAsync(x => x.ScriptUpdate, "Update");
|
|
|
|
Update(c);
|
|
|
|
return new ContentDataChangedResult(Snapshot.Data, NewVersion);
|
|
});
|
|
|
|
case PatchContent patchContent:
|
|
return UpdateReturnAsync(patchContent, async c =>
|
|
{
|
|
GuardContent.CanPatch(c);
|
|
|
|
var operationContext = await CreateContext(c, () => "Failed to patch content.");
|
|
|
|
await operationContext.ValidatePartialAsync();
|
|
await operationContext.ExecuteScriptAndTransformAsync(x => x.ScriptUpdate, "Patch");
|
|
|
|
Patch(c);
|
|
|
|
return new ContentDataChangedResult(Snapshot.Data, NewVersion);
|
|
});
|
|
|
|
case ChangeContentStatus patchContent:
|
|
return UpdateAsync(patchContent, async c =>
|
|
{
|
|
GuardContent.CanChangeContentStatus(Snapshot.Status, c);
|
|
|
|
if (!c.DueTime.HasValue)
|
|
{
|
|
var operationContext = await CreateContext(c, () => "Failed to patch content.");
|
|
|
|
await operationContext.ExecuteScriptAsync(x => x.ScriptChange, c.Status);
|
|
}
|
|
|
|
ChangeStatus(c);
|
|
});
|
|
|
|
case DeleteContent deleteContent:
|
|
return UpdateAsync(deleteContent, async c =>
|
|
{
|
|
GuardContent.CanDelete(c);
|
|
|
|
var operationContext = await CreateContext(c, () => "Failed to delete content.");
|
|
|
|
await operationContext.ExecuteScriptAsync(x => x.ScriptDelete, "Delete");
|
|
|
|
Delete(c);
|
|
});
|
|
|
|
default:
|
|
throw new NotSupportedException();
|
|
}
|
|
}
|
|
|
|
public void Create(CreateContent command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new ContentCreated()));
|
|
|
|
if (command.Publish)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new ContentStatusChanged { Status = Status.Published }));
|
|
}
|
|
}
|
|
|
|
public void Update(UpdateContent command)
|
|
{
|
|
if (!command.Data.Equals(Snapshot.Data))
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new ContentUpdated()));
|
|
}
|
|
}
|
|
|
|
public void ChangeStatus(ChangeContentStatus command)
|
|
{
|
|
if (command.DueTime.HasValue)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new ContentStatusScheduled { DueTime = command.DueTime.Value }));
|
|
}
|
|
else
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new ContentStatusChanged()));
|
|
}
|
|
}
|
|
|
|
public void Patch(PatchContent command)
|
|
{
|
|
var newData = command.Data.MergeInto(Snapshot.Data);
|
|
|
|
if (!newData.Equals(Snapshot.Data))
|
|
{
|
|
var @event = SimpleMapper.Map(command, new ContentUpdated());
|
|
|
|
@event.Data = newData;
|
|
|
|
RaiseEvent(@event);
|
|
}
|
|
}
|
|
|
|
public void Delete(DeleteContent command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new ContentDeleted()));
|
|
}
|
|
|
|
private void RaiseEvent(SchemaEvent @event)
|
|
{
|
|
if (@event.AppId == null)
|
|
{
|
|
@event.AppId = Snapshot.AppId;
|
|
}
|
|
|
|
if (@event.SchemaId == null)
|
|
{
|
|
@event.SchemaId = Snapshot.SchemaId;
|
|
}
|
|
|
|
RaiseEvent(Envelope.Create(@event));
|
|
}
|
|
|
|
private void VerifyNotDeleted()
|
|
{
|
|
if (Snapshot.IsDeleted)
|
|
{
|
|
throw new DomainException("Content has already been deleted.");
|
|
}
|
|
}
|
|
|
|
public override void ApplyEvent(Envelope<IEvent> @event)
|
|
{
|
|
ApplySnapshot(Snapshot.Apply(@event));
|
|
}
|
|
|
|
private async Task<ContentOperationContext> CreateContext(ContentCommand command, Func<string> message)
|
|
{
|
|
var operationContext =
|
|
await ContentOperationContext.CreateAsync(command, Snapshot,
|
|
contentRepository,
|
|
appProvider,
|
|
assetRepository,
|
|
scriptEngine,
|
|
message);
|
|
|
|
return operationContext;
|
|
}
|
|
}
|
|
}
|
|
|