mirror of https://github.com/Squidex/squidex.git
50 changed files with 958 additions and 612 deletions
@ -1,44 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using MongoDB.Bson; |
|
||||
using MongoDB.Bson.Serialization.Attributes; |
|
||||
using Squidex.Domain.Apps.Entities.Apps.State; |
|
||||
using Squidex.Infrastructure.MongoDb; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Apps |
|
||||
{ |
|
||||
public sealed class MongoAppEntity : IVersionedEntity<Guid> |
|
||||
{ |
|
||||
[BsonId] |
|
||||
[BsonElement] |
|
||||
[BsonRepresentation(BsonType.String)] |
|
||||
public Guid Id { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonRequired] |
|
||||
[BsonJson] |
|
||||
public AppState State { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonRequired] |
|
||||
public long Version { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonRequired] |
|
||||
public string Name { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonRequired] |
|
||||
public string[] UserIds { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonIgnoreIfDefault] |
|
||||
public bool IsArchived { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,64 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Threading.Tasks; |
|
||||
using MongoDB.Bson; |
|
||||
using MongoDB.Driver; |
|
||||
using Squidex.Domain.Apps.Entities.Apps.Repositories; |
|
||||
using Squidex.Infrastructure.MongoDb; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Apps |
|
||||
{ |
|
||||
public sealed partial class MongoAppRepository : MongoRepositoryBase<MongoAppEntity>, IAppRepository |
|
||||
{ |
|
||||
public MongoAppRepository(IMongoDatabase database) |
|
||||
: base(database) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
protected override string CollectionName() |
|
||||
{ |
|
||||
return "States_Apps"; |
|
||||
} |
|
||||
|
|
||||
protected override async Task SetupCollectionAsync(IMongoCollection<MongoAppEntity> collection) |
|
||||
{ |
|
||||
await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.UserIds)); |
|
||||
await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.Name)); |
|
||||
} |
|
||||
|
|
||||
public async Task<IReadOnlyList<Guid>> QueryAppIdsAsync() |
|
||||
{ |
|
||||
var appEntities = |
|
||||
await Collection.Find(new BsonDocument()).Only(x => x.Id) |
|
||||
.ToListAsync(); |
|
||||
|
|
||||
return appEntities.Select(x => Guid.Parse(x["_id"].AsString)).ToList(); |
|
||||
} |
|
||||
|
|
||||
public async Task<IReadOnlyList<Guid>> QueryUserAppIdsAsync(string userId) |
|
||||
{ |
|
||||
var appEntities = |
|
||||
await Collection.Find(x => x.UserIds.Contains(userId) && x.IsArchived != true).Only(x => x.Id) |
|
||||
.ToListAsync(); |
|
||||
|
|
||||
return appEntities.Select(x => Guid.Parse(x["_id"].AsString)).ToList(); |
|
||||
} |
|
||||
|
|
||||
public async Task<Guid> FindAppIdByNameAsync(string name) |
|
||||
{ |
|
||||
var appEntity = |
|
||||
await Collection.Find(x => x.Name == name && x.IsArchived != true).Only(x => x.Id) |
|
||||
.FirstOrDefaultAsync(); |
|
||||
|
|
||||
return appEntity != null ? Guid.Parse(appEntity["_id"].AsString) : Guid.Empty; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,44 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Linq; |
|
||||
using System.Threading.Tasks; |
|
||||
using MongoDB.Driver; |
|
||||
using Squidex.Domain.Apps.Entities.Apps.State; |
|
||||
using Squidex.Infrastructure; |
|
||||
using Squidex.Infrastructure.MongoDb; |
|
||||
using Squidex.Infrastructure.States; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Apps |
|
||||
{ |
|
||||
public sealed partial class MongoAppRepository : ISnapshotStore<AppState, Guid> |
|
||||
{ |
|
||||
public async Task<(AppState Value, long Version)> ReadAsync(Guid key) |
|
||||
{ |
|
||||
var existing = |
|
||||
await Collection.Find(x => x.Id == key) |
|
||||
.FirstOrDefaultAsync(); |
|
||||
|
|
||||
if (existing != null) |
|
||||
{ |
|
||||
return (existing.State, existing.Version); |
|
||||
} |
|
||||
|
|
||||
return (null, EtagVersion.NotFound); |
|
||||
} |
|
||||
|
|
||||
public Task WriteAsync(Guid key, AppState value, long oldVersion, long newVersion) |
|
||||
{ |
|
||||
return Collection.UpsertVersionedAsync(key, oldVersion, newVersion, u => u |
|
||||
.Set(x => x.Name, value.Name) |
|
||||
.Set(x => x.State, value) |
|
||||
.Set(x => x.UserIds, value.Contributors.Keys.ToArray()) |
|
||||
.Set(x => x.IsArchived, value.IsArchived)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,41 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using MongoDB.Bson; |
|
||||
using MongoDB.Bson.Serialization.Attributes; |
|
||||
using Squidex.Domain.Apps.Entities.Rules.State; |
|
||||
using Squidex.Infrastructure.MongoDb; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Rules |
|
||||
{ |
|
||||
public sealed class MongoRuleEntity : IVersionedEntity<Guid> |
|
||||
{ |
|
||||
[BsonId] |
|
||||
[BsonElement] |
|
||||
[BsonRepresentation(BsonType.String)] |
|
||||
public Guid Id { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonRequired] |
|
||||
[BsonRepresentation(BsonType.String)] |
|
||||
public Guid AppId { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonRequired] |
|
||||
[BsonJson] |
|
||||
public RuleState State { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonRequired] |
|
||||
public long Version { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonRequired] |
|
||||
public bool IsDeleted { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,45 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Threading.Tasks; |
|
||||
using MongoDB.Driver; |
|
||||
using Squidex.Domain.Apps.Entities.Rules.Repositories; |
|
||||
using Squidex.Infrastructure.MongoDb; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Rules |
|
||||
{ |
|
||||
public sealed partial class MongoRuleRepository : MongoRepositoryBase<MongoRuleEntity>, IRuleRepository |
|
||||
{ |
|
||||
public MongoRuleRepository(IMongoDatabase database) |
|
||||
: base(database) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
protected override string CollectionName() |
|
||||
{ |
|
||||
return "States_Rules"; |
|
||||
} |
|
||||
|
|
||||
protected override async Task SetupCollectionAsync(IMongoCollection<MongoRuleEntity> collection) |
|
||||
{ |
|
||||
await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.AppId)); |
|
||||
await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.IsDeleted)); |
|
||||
} |
|
||||
|
|
||||
public async Task<IReadOnlyList<Guid>> QueryRuleIdsAsync(Guid appId) |
|
||||
{ |
|
||||
var ruleEntities = |
|
||||
await Collection.Find(x => x.AppId == appId && !x.IsDeleted).Only(x => x.Id) |
|
||||
.ToListAsync(); |
|
||||
|
|
||||
return ruleEntities.Select(x => Guid.Parse(x["_id"].AsString)).ToList(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,42 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
using MongoDB.Driver; |
|
||||
using Squidex.Domain.Apps.Entities.Rules.State; |
|
||||
using Squidex.Infrastructure; |
|
||||
using Squidex.Infrastructure.MongoDb; |
|
||||
using Squidex.Infrastructure.States; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Rules |
|
||||
{ |
|
||||
public sealed partial class MongoRuleRepository : ISnapshotStore<RuleState, Guid> |
|
||||
{ |
|
||||
public async Task<(RuleState Value, long Version)> ReadAsync(Guid key) |
|
||||
{ |
|
||||
var existing = |
|
||||
await Collection.Find(x => x.Id == key) |
|
||||
.FirstOrDefaultAsync(); |
|
||||
|
|
||||
if (existing != null) |
|
||||
{ |
|
||||
return (existing.State, existing.Version); |
|
||||
} |
|
||||
|
|
||||
return (null, EtagVersion.NotFound); |
|
||||
} |
|
||||
|
|
||||
public Task WriteAsync(Guid key, RuleState value, long oldVersion, long newVersion) |
|
||||
{ |
|
||||
return Collection.UpsertVersionedAsync(key, oldVersion, newVersion, u => u |
|
||||
.Set(x => x.State, value) |
|
||||
.Set(x => x.AppId, value.AppId.Id) |
|
||||
.Set(x => x.IsDeleted, value.IsDeleted)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,45 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using MongoDB.Bson; |
|
||||
using MongoDB.Bson.Serialization.Attributes; |
|
||||
using Squidex.Domain.Apps.Entities.Schemas.State; |
|
||||
using Squidex.Infrastructure.MongoDb; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas |
|
||||
{ |
|
||||
public sealed class MongoSchemaEntity : IVersionedEntity<Guid> |
|
||||
{ |
|
||||
[BsonId] |
|
||||
[BsonElement] |
|
||||
[BsonRepresentation(BsonType.String)] |
|
||||
public Guid Id { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonRequired] |
|
||||
[BsonRepresentation(BsonType.String)] |
|
||||
public Guid AppId { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonRequired] |
|
||||
[BsonJson] |
|
||||
public SchemaState State { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonRequired] |
|
||||
public string Name { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonRequired] |
|
||||
public long Version { get; set; } |
|
||||
|
|
||||
[BsonElement] |
|
||||
[BsonRequired] |
|
||||
public bool IsDeleted { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,54 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Threading.Tasks; |
|
||||
using MongoDB.Driver; |
|
||||
using Squidex.Domain.Apps.Entities.Schemas.Repositories; |
|
||||
using Squidex.Infrastructure.MongoDb; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas |
|
||||
{ |
|
||||
public sealed partial class MongoSchemaRepository : MongoRepositoryBase<MongoSchemaEntity>, ISchemaRepository |
|
||||
{ |
|
||||
public MongoSchemaRepository(IMongoDatabase database) |
|
||||
: base(database) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
protected override string CollectionName() |
|
||||
{ |
|
||||
return "States_Schemas"; |
|
||||
} |
|
||||
|
|
||||
protected override async Task SetupCollectionAsync(IMongoCollection<MongoSchemaEntity> collection) |
|
||||
{ |
|
||||
await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.AppId).Ascending(x => x.IsDeleted)); |
|
||||
await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.AppId).Ascending(x => x.Name).Ascending(x => x.IsDeleted)); |
|
||||
} |
|
||||
|
|
||||
public async Task<Guid> FindSchemaIdAsync(Guid appId, string name) |
|
||||
{ |
|
||||
var schemaEntity = |
|
||||
await Collection.Find(x => x.AppId == appId && x.Name == name && !x.IsDeleted).Only(x => x.Id).SortByDescending(x => x.Version) |
|
||||
.FirstOrDefaultAsync(); |
|
||||
|
|
||||
return schemaEntity != null ? Guid.Parse(schemaEntity["_id"].AsString) : Guid.Empty; |
|
||||
} |
|
||||
|
|
||||
public async Task<IReadOnlyList<Guid>> QuerySchemaIdsAsync(Guid appId) |
|
||||
{ |
|
||||
var schemaEntities = |
|
||||
await Collection.Find(x => x.AppId == appId && !x.IsDeleted).Only(x => x.Id) |
|
||||
.ToListAsync(); |
|
||||
|
|
||||
return schemaEntities.Select(x => Guid.Parse(x["_id"].AsString)).ToList(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,43 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
using MongoDB.Driver; |
|
||||
using Squidex.Domain.Apps.Entities.Schemas.State; |
|
||||
using Squidex.Infrastructure; |
|
||||
using Squidex.Infrastructure.MongoDb; |
|
||||
using Squidex.Infrastructure.States; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas |
|
||||
{ |
|
||||
public sealed partial class MongoSchemaRepository : ISnapshotStore<SchemaState, Guid> |
|
||||
{ |
|
||||
public async Task<(SchemaState Value, long Version)> ReadAsync(Guid key) |
|
||||
{ |
|
||||
var existing = |
|
||||
await Collection.Find(x => x.Id == key) |
|
||||
.FirstOrDefaultAsync(); |
|
||||
|
|
||||
if (existing != null) |
|
||||
{ |
|
||||
return (existing.State, existing.Version); |
|
||||
} |
|
||||
|
|
||||
return (null, EtagVersion.NotFound); |
|
||||
} |
|
||||
|
|
||||
public Task WriteAsync(Guid key, SchemaState value, long oldVersion, long newVersion) |
|
||||
{ |
|
||||
return Collection.UpsertVersionedAsync(key, oldVersion, newVersion, u => u |
|
||||
.Set(x => x.State, value) |
|
||||
.Set(x => x.AppId, value.AppId.Id) |
|
||||
.Set(x => x.Name, value.Name) |
|
||||
.Set(x => x.IsDeleted, value.IsDeleted)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,47 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Orleans; |
||||
|
using Squidex.Domain.Apps.Entities.Apps.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Commands; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
||||
|
{ |
||||
|
public sealed class AppsByNameIndexCommandMiddleware : ICommandMiddleware |
||||
|
{ |
||||
|
private readonly IAppsByNameIndex index; |
||||
|
|
||||
|
public AppsByNameIndexCommandMiddleware(IGrainFactory grainFactory) |
||||
|
{ |
||||
|
Guard.NotNull(grainFactory, nameof(grainFactory)); |
||||
|
|
||||
|
index = grainFactory.GetGrain<IAppsByNameIndex>(SingleGrain.Id); |
||||
|
} |
||||
|
|
||||
|
public async Task HandleAsync(CommandContext context, Func<Task> next) |
||||
|
{ |
||||
|
if (context.IsCompleted) |
||||
|
{ |
||||
|
switch (context.Command) |
||||
|
{ |
||||
|
case CreateApp createApp: |
||||
|
await index.AddAppAsync(createApp.AppId, createApp.Name); |
||||
|
break; |
||||
|
case ArchiveApp archiveApp: |
||||
|
await index.RemoveAppAsync(archiveApp.AppId); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
await next(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,80 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
using Squidex.Infrastructure.States; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
||||
|
{ |
||||
|
public sealed class AppsByNameIndexGrain : GrainOfString, IAppsByNameIndex |
||||
|
{ |
||||
|
private readonly IStore<string> store; |
||||
|
private IPersistence<State> persistence; |
||||
|
private State state = new State(); |
||||
|
|
||||
|
[CollectionName("Index_AppsByName")] |
||||
|
private sealed class State |
||||
|
{ |
||||
|
public Dictionary<string, Guid> Apps { get; set; } = new Dictionary<string, Guid>(); |
||||
|
} |
||||
|
|
||||
|
public AppsByNameIndexGrain(IStore<string> store) |
||||
|
{ |
||||
|
Guard.NotNull(store, nameof(store)); |
||||
|
|
||||
|
this.store = store; |
||||
|
} |
||||
|
|
||||
|
public override Task OnActivateAsync(string key) |
||||
|
{ |
||||
|
persistence = store.WithSnapshots<AppsByNameIndexGrain, State, string>(key, s => |
||||
|
{ |
||||
|
state = s; |
||||
|
}); |
||||
|
|
||||
|
return persistence.ReadAsync(); |
||||
|
} |
||||
|
|
||||
|
public Task RebuildAsync(Dictionary<string, Guid> apps) |
||||
|
{ |
||||
|
state = new State { Apps = apps }; |
||||
|
|
||||
|
return persistence.WriteSnapshotAsync(state); |
||||
|
} |
||||
|
|
||||
|
public Task AddAppAsync(Guid appId, string name) |
||||
|
{ |
||||
|
state.Apps[name] = appId; |
||||
|
|
||||
|
return persistence.WriteSnapshotAsync(state); |
||||
|
} |
||||
|
|
||||
|
public Task RemoveAppAsync(Guid appId) |
||||
|
{ |
||||
|
state.Apps.Remove(state.Apps.FirstOrDefault(x => x.Value == appId).Key ?? string.Empty); |
||||
|
|
||||
|
return persistence.WriteSnapshotAsync(state); |
||||
|
} |
||||
|
|
||||
|
public Task<Guid> GetAppIdAsync(string appName) |
||||
|
{ |
||||
|
state.Apps.TryGetValue(appName, out var appId); |
||||
|
|
||||
|
return Task.FromResult(appId); |
||||
|
} |
||||
|
|
||||
|
public Task<List<Guid>> GetAppIdAsync() |
||||
|
{ |
||||
|
return Task.FromResult(state.Apps.Values.ToList()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,80 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Orleans; |
||||
|
using Squidex.Domain.Apps.Entities.Apps.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Commands; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
||||
|
{ |
||||
|
public sealed class AppsByUserIndexCommandMiddleware : ICommandMiddleware |
||||
|
{ |
||||
|
private readonly IGrainFactory grainFactory; |
||||
|
|
||||
|
public AppsByUserIndexCommandMiddleware(IGrainFactory grainFactory) |
||||
|
{ |
||||
|
Guard.NotNull(grainFactory, nameof(grainFactory)); |
||||
|
|
||||
|
this.grainFactory = grainFactory; |
||||
|
} |
||||
|
|
||||
|
public async Task HandleAsync(CommandContext context, Func<Task> next) |
||||
|
{ |
||||
|
if (context.IsCompleted) |
||||
|
{ |
||||
|
switch (context.Command) |
||||
|
{ |
||||
|
case CreateApp createApp: |
||||
|
await Index(GetUserId(createApp)).AddAppAsync(createApp.AppId); |
||||
|
break; |
||||
|
case AssignContributor assignContributor: |
||||
|
await Index(GetUserId(context)).AddAppAsync(assignContributor.AppId); |
||||
|
break; |
||||
|
case RemoveContributor removeContributor: |
||||
|
await Index(GetUserId(removeContributor)).RemoveAppAsync(removeContributor.AppId); |
||||
|
break; |
||||
|
case ArchiveApp archiveApp: |
||||
|
{ |
||||
|
var appState = await grainFactory.GetGrain<IAppGrain>(archiveApp.AppId).GetStateAsync(); |
||||
|
|
||||
|
foreach (var contributorId in appState.Value.Contributors.Keys) |
||||
|
{ |
||||
|
await Index(contributorId).RemoveAppAsync(archiveApp.AppId); |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
await next(); |
||||
|
} |
||||
|
|
||||
|
private static string GetUserId(RemoveContributor removeContributor) |
||||
|
{ |
||||
|
return removeContributor.ContributorId; |
||||
|
} |
||||
|
|
||||
|
private static string GetUserId(CreateApp createApp) |
||||
|
{ |
||||
|
return createApp.Actor.Identifier; |
||||
|
} |
||||
|
|
||||
|
private static string GetUserId(CommandContext context) |
||||
|
{ |
||||
|
return context.Result<EntityCreatedResult<string>>().IdOrValue; |
||||
|
} |
||||
|
|
||||
|
private IAppsByUserIndex Index(string id) |
||||
|
{ |
||||
|
return grainFactory.GetGrain<IAppsByUserIndex>(id); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,73 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
using Squidex.Infrastructure.States; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
||||
|
{ |
||||
|
public sealed class AppsByUserIndexGrain : GrainOfString, IAppsByUserIndex |
||||
|
{ |
||||
|
private readonly IStore<string> store; |
||||
|
private IPersistence<State> persistence; |
||||
|
private State state = new State(); |
||||
|
|
||||
|
[CollectionName("Index_AppsByUser")] |
||||
|
private sealed class State |
||||
|
{ |
||||
|
public HashSet<Guid> Apps { get; set; } = new HashSet<Guid>(); |
||||
|
} |
||||
|
|
||||
|
public AppsByUserIndexGrain(IStore<string> store) |
||||
|
{ |
||||
|
Guard.NotNull(store, nameof(store)); |
||||
|
|
||||
|
this.store = store; |
||||
|
} |
||||
|
|
||||
|
public override Task OnActivateAsync(string key) |
||||
|
{ |
||||
|
persistence = store.WithSnapshots<AppsByUserIndexGrain, State, string>(key, s => |
||||
|
{ |
||||
|
state = s; |
||||
|
}); |
||||
|
|
||||
|
return persistence.ReadAsync(); |
||||
|
} |
||||
|
|
||||
|
public Task RebuildAsync(HashSet<Guid> apps) |
||||
|
{ |
||||
|
state = new State { Apps = apps }; |
||||
|
|
||||
|
return persistence.WriteSnapshotAsync(state); |
||||
|
} |
||||
|
|
||||
|
public Task AddAppAsync(Guid appId) |
||||
|
{ |
||||
|
state.Apps.Add(appId); |
||||
|
|
||||
|
return persistence.WriteSnapshotAsync(state); |
||||
|
} |
||||
|
|
||||
|
public Task RemoveAppAsync(Guid appId) |
||||
|
{ |
||||
|
state.Apps.Remove(appId); |
||||
|
|
||||
|
return persistence.WriteSnapshotAsync(state); |
||||
|
} |
||||
|
|
||||
|
public Task<List<Guid>> GetAppIdsAsync() |
||||
|
{ |
||||
|
return Task.FromResult(state.Apps.ToList()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
// ==========================================================================
|
||||
|
// 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 Orleans; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Apps |
||||
|
{ |
||||
|
public interface IAppsByNameIndex : IGrainWithStringKey |
||||
|
{ |
||||
|
Task AddAppAsync(Guid appId, string name); |
||||
|
|
||||
|
Task RemoveAppAsync(Guid appId); |
||||
|
|
||||
|
Task RebuildAsync(Dictionary<string, Guid> apps); |
||||
|
|
||||
|
Task<Guid> GetAppIdAsync(string name); |
||||
|
|
||||
|
Task<List<Guid>> GetAppIdAsync(); |
||||
|
} |
||||
|
} |
||||
@ -1,22 +1,25 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Squidex Headless CMS
|
// Squidex Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
// All rights reserved. Licensed under the MIT license.
|
// All rights reserved. Licensed under the MIT license.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
using System; |
using System; |
||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using Orleans; |
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.Apps.Repositories |
namespace Squidex.Domain.Apps.Entities.Apps |
||||
{ |
{ |
||||
public interface IAppRepository |
public interface IAppsByUserIndex : IGrainWithStringKey |
||||
{ |
{ |
||||
Task<Guid> FindAppIdByNameAsync(string name); |
Task AddAppAsync(Guid appId); |
||||
|
|
||||
Task<IReadOnlyList<Guid>> QueryAppIdsAsync(); |
Task RemoveAppAsync(Guid appId); |
||||
|
|
||||
Task<IReadOnlyList<Guid>> QueryUserAppIdsAsync(string userId); |
Task RebuildAsync(HashSet<Guid> apps); |
||||
|
|
||||
|
Task<List<Guid>> GetAppIdsAsync(); |
||||
} |
} |
||||
} |
} |
||||
@ -1,26 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Newtonsoft.Json; |
|
||||
using NodaTime; |
|
||||
using Squidex.Domain.Apps.Core.Contents; |
|
||||
using Squidex.Infrastructure; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.Contents.State |
|
||||
{ |
|
||||
public sealed class ContentStateScheduleItem : IContentScheduleItem |
|
||||
{ |
|
||||
[JsonProperty] |
|
||||
public Instant ScheduledAt { get; set; } |
|
||||
|
|
||||
[JsonProperty] |
|
||||
public RefToken ScheduledBy { get; set; } |
|
||||
|
|
||||
[JsonProperty] |
|
||||
public Status ScheduledTo { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,20 +1,25 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Squidex Headless CMS
|
// Squidex Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
// All rights reserved. Licensed under the MIT license.
|
// All rights reserved. Licensed under the MIT license.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
using System; |
using System; |
||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using Orleans; |
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.Schemas.Repositories |
namespace Squidex.Domain.Apps.Entities.Rules |
||||
{ |
{ |
||||
public interface ISchemaRepository |
public interface IRulesByAppIndex : IGrainWithGuidKey |
||||
{ |
{ |
||||
Task<Guid> FindSchemaIdAsync(Guid appId, string name); |
Task AddRuleAsync(Guid ruleId); |
||||
|
|
||||
Task<IReadOnlyList<Guid>> QuerySchemaIdsAsync(Guid appId); |
Task RemoveRuleAsync(Guid ruleId); |
||||
|
|
||||
|
Task RebuildAsync(HashSet<Guid> rules); |
||||
|
|
||||
|
Task<List<Guid>> GetRuleIdsAsync(); |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Orleans; |
||||
|
using Squidex.Domain.Apps.Entities.Rules.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Commands; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Rules.Indexes |
||||
|
{ |
||||
|
public sealed class RulesByAppIndexCommandMiddleware : ICommandMiddleware |
||||
|
{ |
||||
|
private readonly IGrainFactory grainFactory; |
||||
|
|
||||
|
public RulesByAppIndexCommandMiddleware(IGrainFactory grainFactory) |
||||
|
{ |
||||
|
Guard.NotNull(grainFactory, nameof(grainFactory)); |
||||
|
|
||||
|
this.grainFactory = grainFactory; |
||||
|
} |
||||
|
|
||||
|
public async Task HandleAsync(CommandContext context, Func<Task> next) |
||||
|
{ |
||||
|
if (context.IsCompleted) |
||||
|
{ |
||||
|
switch (context.Command) |
||||
|
{ |
||||
|
case CreateRule createRule: |
||||
|
await Index(createRule.AppId.Id).AddRuleAsync(createRule.RuleId); |
||||
|
break; |
||||
|
case DeleteRule deleteRule: |
||||
|
{ |
||||
|
var schema = await grainFactory.GetGrain<IRuleGrain>(deleteRule.RuleId).GetStateAsync(); |
||||
|
|
||||
|
await Index(schema.Value.AppId.Id).RemoveRuleAsync(deleteRule.RuleId); |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
await next(); |
||||
|
} |
||||
|
|
||||
|
private IRulesByAppIndex Index(Guid appId) |
||||
|
{ |
||||
|
return grainFactory.GetGrain<IRulesByAppIndex>(appId); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,73 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
using Squidex.Infrastructure.States; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Rules.Indexes |
||||
|
{ |
||||
|
public sealed class RulesByAppIndexGrain : GrainOfGuid, IRulesByAppIndex |
||||
|
{ |
||||
|
private readonly IStore<Guid> store; |
||||
|
private IPersistence<State> persistence; |
||||
|
private State state = new State(); |
||||
|
|
||||
|
[CollectionName("Index_RulesByApp")] |
||||
|
private sealed class State |
||||
|
{ |
||||
|
public HashSet<Guid> Rules { get; set; } = new HashSet<Guid>(); |
||||
|
} |
||||
|
|
||||
|
public RulesByAppIndexGrain(IStore<Guid> store) |
||||
|
{ |
||||
|
Guard.NotNull(store, nameof(store)); |
||||
|
|
||||
|
this.store = store; |
||||
|
} |
||||
|
|
||||
|
public override Task OnActivateAsync(Guid key) |
||||
|
{ |
||||
|
persistence = store.WithSnapshots<RulesByAppIndexGrain, State, Guid>(key, s => |
||||
|
{ |
||||
|
state = s; |
||||
|
}); |
||||
|
|
||||
|
return persistence.ReadAsync(); |
||||
|
} |
||||
|
|
||||
|
public Task RebuildAsync(HashSet<Guid> rules) |
||||
|
{ |
||||
|
state = new State { Rules = rules }; |
||||
|
|
||||
|
return persistence.WriteSnapshotAsync(state); |
||||
|
} |
||||
|
|
||||
|
public Task AddRuleAsync(Guid ruleId) |
||||
|
{ |
||||
|
state.Rules.Add(ruleId); |
||||
|
|
||||
|
return persistence.WriteSnapshotAsync(state); |
||||
|
} |
||||
|
|
||||
|
public Task RemoveRuleAsync(Guid ruleId) |
||||
|
{ |
||||
|
state.Rules.Remove(ruleId); |
||||
|
|
||||
|
return persistence.WriteSnapshotAsync(state); |
||||
|
} |
||||
|
|
||||
|
public Task<List<Guid>> GetRuleIdsAsync() |
||||
|
{ |
||||
|
return Task.FromResult(state.Rules.ToList()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
// ==========================================================================
|
||||
|
// 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 Orleans; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Schemas |
||||
|
{ |
||||
|
public interface ISchemasByAppIndex : IGrainWithGuidKey |
||||
|
{ |
||||
|
Task AddSchemaAsync(Guid schemaId, string name); |
||||
|
|
||||
|
Task RemoveSchemaAsync(Guid schemaId); |
||||
|
|
||||
|
Task RebuildAsync(Dictionary<string, Guid> schemas); |
||||
|
|
||||
|
Task<Guid> GetSchemaIdAsync(string name); |
||||
|
|
||||
|
Task<List<Guid>> GetSchemaIdsAsync(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Orleans; |
||||
|
using Squidex.Domain.Apps.Entities.Schemas.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Commands; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Schemas.Indexes |
||||
|
{ |
||||
|
public sealed class SchemasByAppIndexCommandMiddleware : ICommandMiddleware |
||||
|
{ |
||||
|
private readonly IGrainFactory grainFactory; |
||||
|
|
||||
|
public SchemasByAppIndexCommandMiddleware(IGrainFactory grainFactory) |
||||
|
{ |
||||
|
Guard.NotNull(grainFactory, nameof(grainFactory)); |
||||
|
|
||||
|
this.grainFactory = grainFactory; |
||||
|
} |
||||
|
|
||||
|
public async Task HandleAsync(CommandContext context, Func<Task> next) |
||||
|
{ |
||||
|
if (context.IsCompleted) |
||||
|
{ |
||||
|
switch (context.Command) |
||||
|
{ |
||||
|
case CreateSchema createSchema: |
||||
|
await Index(createSchema.AppId.Id).AddSchemaAsync(createSchema.SchemaId, createSchema.Name); |
||||
|
break; |
||||
|
case DeleteSchema deleteSchema: |
||||
|
{ |
||||
|
var schema = await grainFactory.GetGrain<ISchemaGrain>(deleteSchema.SchemaId).GetStateAsync(); |
||||
|
|
||||
|
await Index(schema.Value.AppId.Id).RemoveSchemaAsync(deleteSchema.SchemaId); |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
await next(); |
||||
|
} |
||||
|
|
||||
|
private ISchemasByAppIndex Index(Guid appId) |
||||
|
{ |
||||
|
return grainFactory.GetGrain<ISchemasByAppIndex>(appId); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,80 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
using Squidex.Infrastructure.States; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Schemas.Indexes |
||||
|
{ |
||||
|
public sealed class SchemasByAppIndexGrain : GrainOfGuid, ISchemasByAppIndex |
||||
|
{ |
||||
|
private readonly IStore<Guid> store; |
||||
|
private IPersistence<State> persistence; |
||||
|
private State state = new State(); |
||||
|
|
||||
|
[CollectionName("Index_SchemasByApp")] |
||||
|
private sealed class State |
||||
|
{ |
||||
|
public Dictionary<string, Guid> Schemas { get; set; } = new Dictionary<string, Guid>(); |
||||
|
} |
||||
|
|
||||
|
public SchemasByAppIndexGrain(IStore<Guid> store) |
||||
|
{ |
||||
|
Guard.NotNull(store, nameof(store)); |
||||
|
|
||||
|
this.store = store; |
||||
|
} |
||||
|
|
||||
|
public override Task OnActivateAsync(Guid key) |
||||
|
{ |
||||
|
persistence = store.WithSnapshots<SchemasByAppIndexGrain, State, Guid>(key, s => |
||||
|
{ |
||||
|
state = s; |
||||
|
}); |
||||
|
|
||||
|
return persistence.ReadAsync(); |
||||
|
} |
||||
|
|
||||
|
public Task RebuildAsync(Dictionary<string, Guid> schemas) |
||||
|
{ |
||||
|
state = new State { Schemas = schemas }; |
||||
|
|
||||
|
return persistence.WriteSnapshotAsync(state); |
||||
|
} |
||||
|
|
||||
|
public Task AddSchemaAsync(Guid schemaId, string name) |
||||
|
{ |
||||
|
state.Schemas[name] = schemaId; |
||||
|
|
||||
|
return persistence.WriteSnapshotAsync(state); |
||||
|
} |
||||
|
|
||||
|
public Task RemoveSchemaAsync(Guid schemaId) |
||||
|
{ |
||||
|
state.Schemas.Remove(state.Schemas.FirstOrDefault(x => x.Value == schemaId).Key ?? string.Empty); |
||||
|
|
||||
|
return persistence.WriteSnapshotAsync(state); |
||||
|
} |
||||
|
|
||||
|
public Task<Guid> GetSchemaIdAsync(string name) |
||||
|
{ |
||||
|
state.Schemas.TryGetValue(name, out var schemaId); |
||||
|
|
||||
|
return Task.FromResult(schemaId); |
||||
|
} |
||||
|
|
||||
|
public Task<List<Guid>> GetSchemaIdsAsync() |
||||
|
{ |
||||
|
return Task.FromResult(state.Schemas.Values.ToList()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,18 +1,14 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Squidex Headless CMS
|
// Squidex Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
// All rights reserved. Licensed under the MIT license.
|
// All rights reserved. Licensed under the MIT license.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
using System; |
namespace Squidex.Infrastructure.Orleans |
||||
using System.Collections.Generic; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.Rules.Repositories |
|
||||
{ |
{ |
||||
public interface IRuleRepository |
public static class SingleGrain |
||||
{ |
{ |
||||
Task<IReadOnlyList<Guid>> QueryRuleIdsAsync(Guid appId); |
public const string Id = "Default"; |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using MongoDB.Bson; |
||||
|
using MongoDB.Driver; |
||||
|
using Squidex.Infrastructure.Migrations; |
||||
|
|
||||
|
namespace Migrate_01.Migrations |
||||
|
{ |
||||
|
public sealed class ConvertOldSnapshotStores : IMigration |
||||
|
{ |
||||
|
private readonly IMongoDatabase database; |
||||
|
|
||||
|
public ConvertOldSnapshotStores(IMongoDatabase database) |
||||
|
{ |
||||
|
this.database = database; |
||||
|
} |
||||
|
|
||||
|
public Task UpdateAsync() |
||||
|
{ |
||||
|
var collections = new[] |
||||
|
{ |
||||
|
"States_Apps", |
||||
|
"States_Rules", |
||||
|
"States_Schemas" |
||||
|
}; |
||||
|
|
||||
|
var update = Builders<BsonDocument>.Update.Rename("State", "Doc"); |
||||
|
|
||||
|
var filter = new BsonDocument(); |
||||
|
|
||||
|
return Task.WhenAll( |
||||
|
collections |
||||
|
.Select(x => database.GetCollection<BsonDocument>(x)) |
||||
|
.Select(x => x.UpdateManyAsync(filter, update))); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,127 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Orleans; |
||||
|
using Squidex.Domain.Apps.Entities.Apps; |
||||
|
using Squidex.Domain.Apps.Entities.Apps.State; |
||||
|
using Squidex.Domain.Apps.Entities.Rules; |
||||
|
using Squidex.Domain.Apps.Entities.Rules.State; |
||||
|
using Squidex.Domain.Apps.Entities.Schemas; |
||||
|
using Squidex.Domain.Apps.Entities.Schemas.State; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Migrations; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
using Squidex.Infrastructure.States; |
||||
|
using Squidex.Infrastructure.Tasks; |
||||
|
|
||||
|
namespace Migrate_01.Migrations |
||||
|
{ |
||||
|
public class PopulateGrainIndexes : IMigration |
||||
|
{ |
||||
|
private readonly IGrainFactory grainFactory; |
||||
|
private readonly ISnapshotStore<AppState, Guid> statesForApps; |
||||
|
private readonly ISnapshotStore<RuleState, Guid> statesForRules; |
||||
|
private readonly ISnapshotStore<SchemaState, Guid> statesForSchemas; |
||||
|
|
||||
|
public PopulateGrainIndexes( |
||||
|
IGrainFactory grainFactory, |
||||
|
ISnapshotStore<AppState, Guid> statesForApps, |
||||
|
ISnapshotStore<RuleState, Guid> statesForRules, |
||||
|
ISnapshotStore<SchemaState, Guid> statesForSchemas) |
||||
|
{ |
||||
|
this.grainFactory = grainFactory; |
||||
|
this.statesForApps = statesForApps; |
||||
|
this.statesForRules = statesForRules; |
||||
|
this.statesForSchemas = statesForSchemas; |
||||
|
} |
||||
|
|
||||
|
public Task UpdateAsync() |
||||
|
{ |
||||
|
return Task.WhenAll( |
||||
|
RebuildAppIndexes(), |
||||
|
RebuildRuleIndexes(), |
||||
|
RebuildSchemaIndexes()); |
||||
|
} |
||||
|
|
||||
|
private async Task RebuildAppIndexes() |
||||
|
{ |
||||
|
var appsByName = new Dictionary<string, Guid>(); |
||||
|
var appsByUser = new Dictionary<string, HashSet<Guid>>(); |
||||
|
|
||||
|
await statesForApps.ReadAllAsync((app, version) => |
||||
|
{ |
||||
|
if (!app.IsArchived) |
||||
|
{ |
||||
|
appsByName[app.Name] = app.Id; |
||||
|
|
||||
|
foreach (var contributor in app.Contributors.Keys) |
||||
|
{ |
||||
|
appsByUser.GetOrAddNew(contributor).Add(app.Id); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return TaskHelper.Done; |
||||
|
}); |
||||
|
|
||||
|
var tasks = |
||||
|
appsByUser.Select(x => |
||||
|
grainFactory.GetGrain<IAppsByUserIndex>(x.Key).RebuildAsync(x.Value)) |
||||
|
.Union(new[] |
||||
|
{ |
||||
|
grainFactory.GetGrain<IAppsByNameIndex>(SingleGrain.Id).RebuildAsync(appsByName) |
||||
|
}); |
||||
|
|
||||
|
await Task.WhenAll(tasks); |
||||
|
} |
||||
|
|
||||
|
private async Task RebuildRuleIndexes() |
||||
|
{ |
||||
|
var schemasByApp = new Dictionary<Guid, HashSet<Guid>>(); |
||||
|
|
||||
|
await statesForRules.ReadAllAsync((schema, version) => |
||||
|
{ |
||||
|
if (!schema.IsDeleted) |
||||
|
{ |
||||
|
schemasByApp.GetOrAddNew(schema.AppId.Id).Add(schema.Id); |
||||
|
} |
||||
|
|
||||
|
return TaskHelper.Done; |
||||
|
}); |
||||
|
|
||||
|
var tasks = |
||||
|
schemasByApp.Select(x => |
||||
|
grainFactory.GetGrain<IRulesByAppIndex>(x.Key).RebuildAsync(x.Value)); |
||||
|
|
||||
|
await Task.WhenAll(tasks); |
||||
|
} |
||||
|
|
||||
|
private async Task RebuildSchemaIndexes() |
||||
|
{ |
||||
|
var schemasByApp = new Dictionary<Guid, Dictionary<string, Guid>>(); |
||||
|
|
||||
|
await statesForSchemas.ReadAllAsync((schema, version) => |
||||
|
{ |
||||
|
if (!schema.IsDeleted) |
||||
|
{ |
||||
|
schemasByApp.GetOrAddNew(schema.AppId.Id).Add(schema.Name, schema.Id); |
||||
|
} |
||||
|
|
||||
|
return TaskHelper.Done; |
||||
|
}); |
||||
|
|
||||
|
var tasks = |
||||
|
schemasByApp.Select(x => |
||||
|
grainFactory.GetGrain<ISchemasByAppIndex>(x.Key).RebuildAsync(x.Value)); |
||||
|
|
||||
|
await Task.WhenAll(tasks); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue