Browse Source

A lot of stuff

pull/311/head
Sebastian 8 years ago
parent
commit
5b8fd0ce24
  1. 40
      src/Squidex.Domain.Apps.Entities/Assets/BackupAssets.cs
  2. 5
      src/Squidex.Domain.Apps.Entities/Backup/IBackupGrain.cs
  3. 5
      src/Squidex.Domain.Apps.Entities/Rules/Indexes/IRulesByAppIndex.cs
  4. 5
      src/Squidex.Domain.Apps.Entities/Schemas/Indexes/ISchemasByAppIndex.cs
  5. 9
      src/Squidex.Domain.Apps.Entities/Tags/GrainTagService.cs
  6. 5
      src/Squidex.Domain.Apps.Entities/Tags/ITagGrain.cs
  7. 4
      src/Squidex.Domain.Apps.Entities/Tags/ITagService.cs
  8. 16
      src/Squidex.Domain.Apps.Entities/Tags/Tag.cs
  9. 22
      src/Squidex.Domain.Apps.Entities/Tags/TagGrain.cs
  10. 15
      src/Squidex.Domain.Apps.Entities/Tags/TagSet.cs
  11. 21
      src/Squidex/Config/Domain/EntitiesServices.cs
  12. 58
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/Indexes/AppsByNameIndexGrainTests.cs
  13. 20
      tests/Squidex.Domain.Apps.Entities.Tests/Tags/GrainTagServiceTests.cs
  14. 24
      tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagGrainTests.cs
  15. 1
      tools/Migrate_01/Migrations/AddPatterns.cs
  16. 3
      tools/Migrate_01/Migrations/PopulateGrainIndexes.cs

40
src/Squidex.Domain.Apps.Entities/Assets/BackupAssets.cs

@ -7,7 +7,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Squidex.Domain.Apps.Entities.Assets.Repositories;
using Squidex.Domain.Apps.Entities.Assets.State;
using Squidex.Domain.Apps.Entities.Backup;
@ -23,6 +25,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
{
public sealed class BackupAssets : BackupHandlerWithStore
{
private static readonly JsonSerializer Serializer = JsonSerializer.Create();
private readonly HashSet<Guid> assetIds = new HashSet<Guid>();
private readonly IAssetStore assetStore;
private readonly IAssetRepository assetRepository;
@ -73,6 +76,11 @@ namespace Squidex.Domain.Apps.Entities.Assets
return TaskHelper.Done;
}
public override Task BackupAsync(Guid appId, BackupWriter writer)
{
return BackupTagsAsync(appId, writer);
}
public override Task RestoreEventAsync(Envelope<IEvent> @event, Guid appId, BackupReader reader)
{
switch (@event.Payload)
@ -88,9 +96,37 @@ namespace Squidex.Domain.Apps.Entities.Assets
return TaskHelper.Done;
}
public override Task RestoreAsync(Guid appId, BackupReader reader)
public override async Task RestoreAsync(Guid appId, BackupReader reader)
{
await RestoreTagsAsync(appId, reader);
await RebuildManyAsync(assetIds, id => RebuildAsync<AssetState, AssetGrain>(id, (e, s) => s.Apply(e)));
}
private Task RestoreTagsAsync(Guid appId, BackupReader reader)
{
return reader.ReadAttachmentAsync("AssetTags.json", async stream =>
{
using (var textReader = new StreamReader(stream))
{
var tags = (TagSet)Serializer.Deserialize(textReader, typeof(TagSet));
await tagService.RebuildTagsAsync(appId, TagGroups.Assets, tags);
}
});
}
private Task BackupTagsAsync(Guid appId, BackupWriter writer)
{
return RebuildManyAsync(assetIds, id => RebuildAsync<AssetState, AssetGrain>(id, (e, s) => s.Apply(e)));
return writer.WriteAttachmentAsync("AssetTags.json", async stream =>
{
var tags = await tagService.GetExportableTagsAsync(appId, TagGroups.Assets);
using (var textWriter = new StreamWriter(stream))
{
Serializer.Serialize(textWriter, tags);
}
});
}
private Task WriteAssetAsync(Guid assetId, long fileVersion, BackupWriter writer)

5
src/Squidex.Domain.Apps.Entities/Backup/IBackupGrain.cs

@ -8,16 +8,19 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Orleans;
using Squidex.Infrastructure.Orleans;
namespace Squidex.Domain.Apps.Entities.Backup
{
public interface IBackupGrain : ICleanableAppGrain
public interface IBackupGrain : IGrainWithGuidKey
{
Task RunAsync();
Task DeleteAsync(Guid id);
Task ClearAsync();
Task<J<List<IBackupJob>>> GetStateAsync();
}
}

5
src/Squidex.Domain.Apps.Entities/Rules/Indexes/IRulesByAppIndex.cs

@ -8,10 +8,11 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Orleans;
namespace Squidex.Domain.Apps.Entities.Rules.Indexes
{
public interface IRulesByAppIndex : ICleanableAppGrain
public interface IRulesByAppIndex : IGrainWithGuidKey
{
Task AddRuleAsync(Guid ruleId);
@ -19,6 +20,8 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes
Task RebuildAsync(HashSet<Guid> rules);
Task ClearAsync();
Task<List<Guid>> GetRuleIdsAsync();
}
}

5
src/Squidex.Domain.Apps.Entities/Schemas/Indexes/ISchemasByAppIndex.cs

@ -8,10 +8,11 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Orleans;
namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
{
public interface ISchemasByAppIndex : ICleanableAppGrain
public interface ISchemasByAppIndex : IGrainWithGuidKey
{
Task AddSchemaAsync(Guid schemaId, string name);
@ -19,6 +20,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
Task RebuildAsync(Dictionary<string, Guid> schemas);
Task ClearAsync();
Task<Guid> GetSchemaIdAsync(string name);
Task<List<Guid>> GetSchemaIdsAsync();

9
src/Squidex.Domain.Apps.Entities/Tags/GrainTagService.cs

@ -49,9 +49,14 @@ namespace Squidex.Domain.Apps.Entities.Tags
return GetGrain(appId, group).GetTagsAsync();
}
public Task RebuildTagsAsync(Guid appId, string group, Dictionary<string, string> allTags)
public Task<TagSet> GetExportableTagsAsync(Guid appId, string group)
{
return GetGrain(appId, group).RebuildTagsAsync(allTags);
return GetGrain(appId, group).GetExportableTagsAsync();
}
public Task RebuildTagsAsync(Guid appId, string group, TagSet tags)
{
return GetGrain(appId, group).RebuildAsync(tags);
}
public Task ClearAsync(Guid appId, string group)

5
src/Squidex.Domain.Apps.Entities/Tags/ITagGrain.cs

@ -21,7 +21,10 @@ namespace Squidex.Domain.Apps.Entities.Tags
Task<Dictionary<string, int>> GetTagsAsync();
Task<TagSet> GetExportableTagsAsync();
Task ClearAsync();
Task RebuildTagsAsync(Dictionary<string, string> allTags);
Task RebuildAsync(TagSet tags);
}
}

4
src/Squidex.Domain.Apps.Entities/Tags/ITagService.cs

@ -21,7 +21,9 @@ namespace Squidex.Domain.Apps.Entities.Tags
Task<Dictionary<string, int>> GetTagsAsync(Guid appId, string group);
Task RebuildTagsAsync(Guid appId, string group, Dictionary<string, string> allTags);
Task<TagSet> GetExportableTagsAsync(Guid appId, string group);
Task RebuildTagsAsync(Guid appId, string group, TagSet tags);
Task ClearAsync(Guid appId, string group);
}

16
src/Squidex.Domain.Apps.Entities/Tags/Tag.cs

@ -0,0 +1,16 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Domain.Apps.Entities.Tags
{
public sealed class Tag
{
public string Name { get; set; }
public int Count { get; set; } = 1;
}
}

22
src/Squidex.Domain.Apps.Entities/Tags/TagGrain.cs

@ -24,14 +24,7 @@ namespace Squidex.Domain.Apps.Entities.Tags
[CollectionName("Index_Tags")]
public sealed class State
{
public Dictionary<string, TagInfo> Tags { get; set; } = new Dictionary<string, TagInfo>();
}
public sealed class TagInfo
{
public string Name { get; set; }
public int Count { get; set; } = 1;
public TagSet Tags { get; set; } = new TagSet();
}
public TagGrain(IStore<string> store)
@ -58,9 +51,11 @@ namespace Squidex.Domain.Apps.Entities.Tags
return persistence.DeleteAsync();
}
public Task RebuildTagsAsync(Dictionary<string, string> allTags)
public Task RebuildAsync(TagSet tags)
{
throw new NotImplementedException();
state.Tags = tags;
return persistence.DeleteAsync();
}
public async Task<HashSet<string>> NormalizeTagsAsync(HashSet<string> names, HashSet<string> ids)
@ -91,7 +86,7 @@ namespace Squidex.Domain.Apps.Entities.Tags
{
tagId = Guid.NewGuid().ToString();
state.Tags.Add(tagId, new TagInfo { Name = tagName });
state.Tags.Add(tagId, new Tag { Name = tagName });
}
result.Add(tagId);
@ -159,5 +154,10 @@ namespace Squidex.Domain.Apps.Entities.Tags
{
return Task.FromResult(state.Tags.Values.ToDictionary(x => x.Name, x => x.Count));
}
public Task<TagSet> GetExportableTagsAsync()
{
return Task.FromResult(state.Tags);
}
}
}

15
src/Squidex.Domain.Apps.Entities/Tags/TagSet.cs

@ -0,0 +1,15 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
namespace Squidex.Domain.Apps.Entities.Tags
{
public sealed class TagSet : Dictionary<string, Tag>
{
}
}

21
src/Squidex/Config/Domain/EntitiesServices.cs

@ -96,7 +96,8 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<JintScriptEngine>()
.As<IScriptEngine>();
AddCommandPipeline(services);
services.AddCommandPipeline();
services.AddBackupHandlers();
services.AddSingleton<Func<IGrainCallContext, string>>(DomainObjectGrainFormatter.Format);
@ -119,7 +120,7 @@ namespace Squidex.Config.Domain
});
}
private static void AddCommandPipeline(IServiceCollection services)
private static void AddCommandPipeline(this IServiceCollection services)
{
services.AddSingletonAs<InMemoryCommandBus>()
.As<ICommandBus>();
@ -145,6 +146,9 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<AssetCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingletonAs<AppsByNameIndexCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingletonAs<GrainCommandMiddleware<AppCommand, IAppGrain>>()
.As<ICommandMiddleware>();
@ -157,9 +161,6 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<GrainCommandMiddleware<RuleCommand, IRuleGrain>>()
.As<ICommandMiddleware>();
services.AddSingletonAs<AppsByNameIndexCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingletonAs<AppsByUserIndexCommandMiddleware>()
.As<ICommandMiddleware>();
@ -182,6 +183,16 @@ namespace Squidex.Config.Domain
.As<ICommandMiddleware>();
}
private static void AddBackupHandlers(this IServiceCollection services)
{
services.AddTransient<BackupApps>();
services.AddTransient<BackupAssets>();
services.AddTransient<BackupContents>();
services.AddTransient<BackupHistory>();
services.AddTransient<BackupRules>();
services.AddTransient<BackupSchemas>();
}
public static void AddMyMigrationServices(this IServiceCollection services)
{
services.AddSingletonAs<Migrator>()

58
tests/Squidex.Domain.Apps.Entities.Tests/Apps/Indexes/AppsByNameIndexGrainTests.cs

@ -47,6 +47,64 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
.MustHaveHappened();
}
[Fact]
public async Task Should_not_be_able_to_reserve_index_if_name_taken()
{
await sut.AddAppAsync(appId2, appName1);
Assert.False(await sut.ReserveAppAsync(appId1, appName1));
}
[Fact]
public async Task Should_not_be_able_to_reserve_if_name_reserved()
{
await sut.ReserveAppAsync(appId2, appName1);
Assert.False(await sut.ReserveAppAsync(appId1, appName1));
}
[Fact]
public async Task Should_not_be_able_to_reserve_if_id_taken()
{
await sut.AddAppAsync(appId1, appName1);
Assert.False(await sut.ReserveAppAsync(appId1, appName2));
}
[Fact]
public async Task Should_not_be_able_to_reserve_if_id_reserved()
{
await sut.ReserveAppAsync(appId1, appName1);
Assert.False(await sut.ReserveAppAsync(appId1, appName2));
}
[Fact]
public async Task Should_be_able_to_reserve_if_id_and_name_not_reserved()
{
await sut.ReserveAppAsync(appId1, appName1);
Assert.True(await sut.ReserveAppAsync(appId2, appName2));
}
[Fact]
public async Task Should_be_able_to_reserve_after_app_removed()
{
await sut.AddAppAsync(appId1, appName1);
await sut.RemoveAppAsync(appId1);
Assert.True(await sut.ReserveAppAsync(appId1, appName1));
}
[Fact]
public async Task Should_be_able_to_reserve_after_reservation_removed()
{
await sut.ReserveAppAsync(appId1, appName1);
await sut.RemoveReservationAsync(appId1, appName1);
Assert.True(await sut.ReserveAppAsync(appId1, appName1));
}
[Fact]
public async Task Should_remove_app_id_from_index()
{

20
tests/Squidex.Domain.Apps.Entities.Tests/Tags/GrainTagServiceTests.cs

@ -44,6 +44,26 @@ namespace Squidex.Domain.Apps.Entities.Tags
.MustHaveHappened();
}
[Fact]
public async Task Should_call_grain_when_rebuilding()
{
var tags = new TagSet();
await sut.RebuildTagsAsync(appId, TagGroups.Assets, tags);
A.CallTo(() => grain.RebuildAsync(tags))
.MustHaveHappened();
}
[Fact]
public async Task Should_call_grain_when_retrieving_raw_tags()
{
await sut.GetExportableTagsAsync(appId, TagGroups.Assets);
A.CallTo(() => grain.GetTagsAsync())
.MustHaveHappened();
}
[Fact]
public async Task Should_call_grain_when_retrieving_tags()
{

24
tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagGrainTests.cs

@ -45,6 +45,30 @@ namespace Squidex.Domain.Apps.Entities.Tags
.MustHaveHappened();
}
[Fact]
public async Task Should_rebuild_tags()
{
var tags = new TagSet
{
["1"] = new Tag { Name = "tag1", Count = 1 },
["2"] = new Tag { Name = "tag2", Count = 2 },
["3"] = new Tag { Name = "tag3", Count = 6 }
};
await sut.RebuildAsync(tags);
var allTags = await sut.GetTagsAsync();
Assert.Equal(new Dictionary<string, int>
{
["tag1"] = 1,
["tag2"] = 2,
["tag3"] = 6
}, allTags);
Assert.Same(tags, await sut.GetExportableTagsAsync());
}
[Fact]
public async Task Should_add_tags_to_grain()
{

1
tools/Migrate_01/Migrations/AddPatterns.cs

@ -10,6 +10,7 @@ using System.Threading.Tasks;
using Orleans;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.Apps.Indexes;
using Squidex.Infrastructure.Migrations;
using Squidex.Infrastructure.Orleans;

3
tools/Migrate_01/Migrations/PopulateGrainIndexes.cs

@ -9,8 +9,11 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Orleans;
using Squidex.Domain.Apps.Entities.Apps.Indexes;
using Squidex.Domain.Apps.Entities.Apps.State;
using Squidex.Domain.Apps.Entities.Rules.Indexes;
using Squidex.Domain.Apps.Entities.Rules.State;
using Squidex.Domain.Apps.Entities.Schemas.Indexes;
using Squidex.Domain.Apps.Entities.Schemas.State;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Migrations;

Loading…
Cancel
Save