mirror of https://github.com/Squidex/squidex.git
26 changed files with 759 additions and 47 deletions
@ -0,0 +1,55 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.Commands; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
using Squidex.Infrastructure.States; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup.Handlers |
|||
{ |
|||
public abstract class HandlerBase |
|||
{ |
|||
private readonly IStore<Guid> store; |
|||
|
|||
protected HandlerBase(IStore<Guid> store) |
|||
{ |
|||
Guard.NotNull(store, nameof(store)); |
|||
|
|||
this.store = store; |
|||
} |
|||
|
|||
protected async Task RebuildManyAsync(IEnumerable<Guid> ids, Func<Guid, Task> action) |
|||
{ |
|||
foreach (var id in ids) |
|||
{ |
|||
await action(id); |
|||
} |
|||
} |
|||
|
|||
protected async Task RebuildAsync<TState, TGrain>(Guid key, Func<Envelope<IEvent>, TState, TState> func) where TState : IDomainState, new() |
|||
{ |
|||
var state = new TState |
|||
{ |
|||
Version = EtagVersion.Empty |
|||
}; |
|||
|
|||
var persistence = store.WithSnapshotsAndEventSourcing<TState, Guid>(typeof(TGrain), key, s => state = s, e => |
|||
{ |
|||
state = func(e, state); |
|||
|
|||
state.Version++; |
|||
}); |
|||
|
|||
await persistence.ReadAsync(); |
|||
await persistence.WriteSnapshotAsync(state); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Domain.Apps.Events.Apps; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
using Squidex.Infrastructure.States; |
|||
using Squidex.Infrastructure.Tasks; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup.Handlers |
|||
{ |
|||
public sealed class RestoreApp : HandlerBase, IRestoreHandler |
|||
{ |
|||
private NamedId<Guid> appId; |
|||
|
|||
public string Name { get; } = "App"; |
|||
|
|||
public RestoreApp(IStore<Guid> store) |
|||
: base(store) |
|||
{ |
|||
} |
|||
|
|||
public Task HandleAsync(Envelope<IEvent> @event, Stream attachment) |
|||
{ |
|||
if (@event.Payload is AppCreated appCreated) |
|||
{ |
|||
appId = appCreated.AppId; |
|||
} |
|||
|
|||
return TaskHelper.Done; |
|||
} |
|||
|
|||
public Task ProcessAsync() |
|||
{ |
|||
return TaskHelper.Done; |
|||
} |
|||
|
|||
public Task CompleteAsync() |
|||
{ |
|||
return TaskHelper.Done; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,72 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Domain.Apps.Entities.Assets; |
|||
using Squidex.Domain.Apps.Entities.Assets.State; |
|||
using Squidex.Domain.Apps.Events.Assets; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.Assets; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
using Squidex.Infrastructure.States; |
|||
using Squidex.Infrastructure.Tasks; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup.Handlers |
|||
{ |
|||
public sealed class RestoreAssets : HandlerBase, IRestoreHandler |
|||
{ |
|||
private readonly HashSet<Guid> assetIds = new HashSet<Guid>(); |
|||
private readonly IAssetStore assetStore; |
|||
|
|||
public string Name { get; } = "Assets"; |
|||
|
|||
public RestoreAssets(IStore<Guid> store, IAssetStore assetStore) |
|||
: base(store) |
|||
{ |
|||
Guard.NotNull(assetStore, nameof(assetStore)); |
|||
|
|||
this.assetStore = assetStore; |
|||
} |
|||
|
|||
public async Task HandleAsync(Envelope<IEvent> @event, Stream attachment) |
|||
{ |
|||
var assetVersion = 0L; |
|||
var assetId = Guid.Empty; |
|||
|
|||
switch (@event.Payload) |
|||
{ |
|||
case AssetCreated assetCreated: |
|||
assetId = assetCreated.AssetId; |
|||
assetVersion = assetCreated.FileVersion; |
|||
assetIds.Add(assetCreated.AssetId); |
|||
break; |
|||
case AssetUpdated asetUpdated: |
|||
assetId = asetUpdated.AssetId; |
|||
assetVersion = asetUpdated.FileVersion; |
|||
break; |
|||
} |
|||
|
|||
if (attachment != null) |
|||
{ |
|||
await assetStore.UploadAsync(assetId.ToString(), assetVersion, null, attachment); |
|||
} |
|||
} |
|||
|
|||
public Task ProcessAsync() |
|||
{ |
|||
return RebuildManyAsync(assetIds, id => RebuildAsync<AssetState, AssetGrain>(id, (e, s) => s.Apply(e))); |
|||
} |
|||
|
|||
public Task CompleteAsync() |
|||
{ |
|||
return TaskHelper.Done; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Domain.Apps.Entities.Contents; |
|||
using Squidex.Domain.Apps.Entities.Contents.State; |
|||
using Squidex.Domain.Apps.Events.Contents; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
using Squidex.Infrastructure.States; |
|||
using Squidex.Infrastructure.Tasks; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup.Handlers |
|||
{ |
|||
public sealed class RestoreContents : HandlerBase, IRestoreHandler |
|||
{ |
|||
private readonly HashSet<Guid> contentIds = new HashSet<Guid>(); |
|||
|
|||
public string Name { get; } = "Contents"; |
|||
|
|||
public RestoreContents(IStore<Guid> store) |
|||
: base(store) |
|||
{ |
|||
} |
|||
|
|||
public Task HandleAsync(Envelope<IEvent> @event, Stream attachment) |
|||
{ |
|||
switch (@event.Payload) |
|||
{ |
|||
case ContentCreated contentCreated: |
|||
contentIds.Add(contentCreated.ContentId); |
|||
break; |
|||
} |
|||
|
|||
return TaskHelper.Done; |
|||
} |
|||
|
|||
public Task ProcessAsync() |
|||
{ |
|||
return RebuildManyAsync(contentIds, id => RebuildAsync<ContentState, ContentGrain>(id, (e, s) => s.Apply(e))); |
|||
} |
|||
|
|||
public Task CompleteAsync() |
|||
{ |
|||
return TaskHelper.Done; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Orleans; |
|||
using Squidex.Domain.Apps.Entities.Rules; |
|||
using Squidex.Domain.Apps.Entities.Rules.State; |
|||
using Squidex.Domain.Apps.Events.Apps; |
|||
using Squidex.Domain.Apps.Events.Rules; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
using Squidex.Infrastructure.States; |
|||
using Squidex.Infrastructure.Tasks; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup.Handlers |
|||
{ |
|||
public sealed class RestoreRules : HandlerBase, IRestoreHandler |
|||
{ |
|||
private readonly HashSet<Guid> ruleIds = new HashSet<Guid>(); |
|||
private readonly IGrainFactory grainFactory; |
|||
private Guid appId; |
|||
|
|||
public string Name { get; } = "Rules"; |
|||
|
|||
public RestoreRules(IStore<Guid> store, IGrainFactory grainFactory) |
|||
: base(store) |
|||
{ |
|||
Guard.NotNull(grainFactory, nameof(grainFactory)); |
|||
|
|||
this.grainFactory = grainFactory; |
|||
} |
|||
|
|||
public Task HandleAsync(Envelope<IEvent> @event, Stream attachment) |
|||
{ |
|||
switch (@event.Payload) |
|||
{ |
|||
case AppCreated appCreated: |
|||
appId = appCreated.AppId.Id; |
|||
break; |
|||
case RuleCreated ruleCreated: |
|||
ruleIds.Add(ruleCreated.RuleId); |
|||
break; |
|||
case RuleDeleted ruleDeleted: |
|||
ruleIds.Remove(ruleDeleted.RuleId); |
|||
break; |
|||
} |
|||
|
|||
return TaskHelper.Done; |
|||
} |
|||
|
|||
public async Task ProcessAsync() |
|||
{ |
|||
await RebuildManyAsync(ruleIds, id => RebuildAsync<RuleState, RuleGrain>(id, (e, s) => s.Apply(e))); |
|||
|
|||
await grainFactory.GetGrain<IRulesByAppIndex>(appId).RebuildAsync(ruleIds); |
|||
} |
|||
|
|||
public Task CompleteAsync() |
|||
{ |
|||
return TaskHelper.Done; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Orleans; |
|||
using Squidex.Domain.Apps.Core.Schemas; |
|||
using Squidex.Domain.Apps.Entities.Schemas; |
|||
using Squidex.Domain.Apps.Entities.Schemas.State; |
|||
using Squidex.Domain.Apps.Events.Apps; |
|||
using Squidex.Domain.Apps.Events.Schemas; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
using Squidex.Infrastructure.States; |
|||
using Squidex.Infrastructure.Tasks; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup.Handlers |
|||
{ |
|||
public sealed class RestoreSchemas : HandlerBase, IRestoreHandler |
|||
{ |
|||
private readonly HashSet<NamedId<Guid>> schemaIds = new HashSet<NamedId<Guid>>(); |
|||
private readonly Dictionary<string, Guid> schemasByName = new Dictionary<string, Guid>(); |
|||
private readonly FieldRegistry fieldRegistry; |
|||
private readonly IGrainFactory grainFactory; |
|||
private Guid appId; |
|||
|
|||
public string Name { get; } = "Schemas"; |
|||
|
|||
public RestoreSchemas(IStore<Guid> store, FieldRegistry fieldRegistry, IGrainFactory grainFactory) |
|||
: base(store) |
|||
{ |
|||
Guard.NotNull(fieldRegistry, nameof(fieldRegistry)); |
|||
Guard.NotNull(grainFactory, nameof(grainFactory)); |
|||
|
|||
this.fieldRegistry = fieldRegistry; |
|||
|
|||
this.grainFactory = grainFactory; |
|||
} |
|||
|
|||
public Task HandleAsync(Envelope<IEvent> @event, Stream attachment) |
|||
{ |
|||
switch (@event.Payload) |
|||
{ |
|||
case AppCreated appCreated: |
|||
appId = appCreated.AppId.Id; |
|||
break; |
|||
case SchemaCreated schemaCreated: |
|||
schemaIds.Add(schemaCreated.SchemaId); |
|||
schemasByName[schemaCreated.SchemaId.Name] = schemaCreated.SchemaId.Id; |
|||
break; |
|||
} |
|||
|
|||
return TaskHelper.Done; |
|||
} |
|||
|
|||
public async Task ProcessAsync() |
|||
{ |
|||
await RebuildManyAsync(schemaIds.Select(x => x.Id), id => RebuildAsync<SchemaState, SchemaGrain>(id, (e, s) => s.Apply(e, fieldRegistry))); |
|||
|
|||
await grainFactory.GetGrain<ISchemasByAppIndex>(appId).RebuildAsync(schemasByName); |
|||
} |
|||
|
|||
public Task CompleteAsync() |
|||
{ |
|||
return TaskHelper.Done; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.Orleans; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup |
|||
{ |
|||
public interface IRestoreGrain |
|||
{ |
|||
Task RestoreAsync(Uri url, RefToken user); |
|||
|
|||
Task<J<IRestoreJob>> GetStateAsync(); |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup |
|||
{ |
|||
public interface IRestoreHandler |
|||
{ |
|||
string Name { get; } |
|||
|
|||
Task HandleAsync(Envelope<IEvent> @event, Stream attachment); |
|||
|
|||
Task ProcessAsync(); |
|||
|
|||
Task CompleteAsync(); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using NodaTime; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup |
|||
{ |
|||
public interface IRestoreJob |
|||
{ |
|||
Uri Uri { get; } |
|||
|
|||
Instant Started { get; } |
|||
|
|||
bool IsFailed { get; } |
|||
|
|||
string Status { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Newtonsoft.Json; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup.State |
|||
{ |
|||
public class RestoreState |
|||
{ |
|||
[JsonProperty] |
|||
public RestoreStateJob Job { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using Newtonsoft.Json; |
|||
using NodaTime; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup.State |
|||
{ |
|||
public sealed class RestoreStateJob : IRestoreJob |
|||
{ |
|||
[JsonProperty] |
|||
public Guid Id { get; set; } = Guid.NewGuid(); |
|||
|
|||
[JsonProperty] |
|||
public Guid AppId { get; set; } |
|||
|
|||
[JsonProperty] |
|||
public RefToken User { get; set; } |
|||
|
|||
[JsonProperty] |
|||
public Uri Uri { get; set; } |
|||
|
|||
[JsonProperty] |
|||
public Instant Started { get; set; } |
|||
|
|||
[JsonProperty] |
|||
public string Status { get; set; } |
|||
|
|||
[JsonProperty] |
|||
public bool IsFailed { get; set; } |
|||
} |
|||
} |
|||
Loading…
Reference in new issue