diff --git a/backend/extensions/Squidex.Extensions/Actions/Comment/CommentActionHandler.cs b/backend/extensions/Squidex.Extensions/Actions/Comment/CommentActionHandler.cs index c2b89fb54..e3a794033 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Comment/CommentActionHandler.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Comment/CommentActionHandler.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.HandleRules; @@ -74,7 +73,7 @@ namespace Squidex.Extensions.Actions.Comment public sealed class CommentJob { - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } public RefToken Actor { get; set; } diff --git a/backend/extensions/Squidex.Extensions/Actions/Email/EmailActionHandler.cs b/backend/extensions/Squidex.Extensions/Actions/Email/EmailActionHandler.cs index 499f2f75d..f10d48796 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Email/EmailActionHandler.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Email/EmailActionHandler.cs @@ -69,13 +69,13 @@ namespace Squidex.Extensions.Actions.Email return Result.Complete(); } - private async Task CheckConnectionAsync(EmailJob job, CancellationToken ct) + private static async Task CheckConnectionAsync(EmailJob job, CancellationToken ct) { using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { var tcs = new TaskCompletionSource(); - var state = socket.BeginConnect(job.ServerHost, job.ServerPort, tcs.SetResult, null); + socket.BeginConnect(job.ServerHost, job.ServerPort, tcs.SetResult, null); using (ct.Register(() => { diff --git a/backend/extensions/Squidex.Extensions/Actions/Kafka/KafkaProducer.cs b/backend/extensions/Squidex.Extensions/Actions/Kafka/KafkaProducer.cs index b347cbf09..9d13d054e 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Kafka/KafkaProducer.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Kafka/KafkaProducer.cs @@ -131,7 +131,7 @@ namespace Squidex.Extensions.Actions.Kafka } } - private async Task ProduceAsync(IProducer producer, Message message, KafkaJob job, CancellationToken ct) + private static async Task ProduceAsync(IProducer producer, Message message, KafkaJob job, CancellationToken ct) { message.Key = job.MessageKey; @@ -181,7 +181,7 @@ namespace Squidex.Extensions.Actions.Kafka avroProducer?.Dispose(); } - private object GetValue(IJsonValue value, Schema schema) + private static object GetValue(IJsonValue value, Schema schema) { switch (value) { diff --git a/backend/extensions/Squidex.Extensions/Actions/Notification/NotificationActionHandler.cs b/backend/extensions/Squidex.Extensions/Actions/Notification/NotificationActionHandler.cs index 0093b2335..ee569ccc8 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Notification/NotificationActionHandler.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Notification/NotificationActionHandler.cs @@ -21,7 +21,7 @@ namespace Squidex.Extensions.Actions.Notification public sealed class NotificationActionHandler : RuleActionHandler { private const string Description = "Send a Notification"; - private static readonly NamedId NoApp = NamedId.Of(Guid.Empty, "none"); + private static readonly NamedId NoApp = NamedId.Of(DomainId.Empty, "none"); private readonly ICommandBus commandBus; private readonly IUserResolver userResolver; diff --git a/backend/extensions/Squidex.Extensions/Validation/CompositeUniqueValidator.cs b/backend/extensions/Squidex.Extensions/Validation/CompositeUniqueValidator.cs index 47f2f0812..b1eb3c71a 100644 --- a/backend/extensions/Squidex.Extensions/Validation/CompositeUniqueValidator.cs +++ b/backend/extensions/Squidex.Extensions/Validation/CompositeUniqueValidator.cs @@ -78,15 +78,15 @@ namespace Squidex.Extensions.Validation { case BooleanFieldProperties _ when value is JsonBoolean boolean: return boolean.Value; - case BooleanFieldProperties _ when value is JsonNull _: + case BooleanFieldProperties _ when value is JsonNull: return ClrValue.Null; case NumberFieldProperties _ when value is JsonNumber number: return number.Value; - case NumberFieldProperties _ when value is JsonNull _: + case NumberFieldProperties _ when value is JsonNull: return ClrValue.Null; case StringFieldProperties _ when value is JsonString @string: return @string.Value; - case StringFieldProperties _ when value is JsonNull _: + case StringFieldProperties _ when value is JsonNull: return ClrValue.Null; case ReferencesFieldProperties _ when value is JsonArray array && array.FirstOrDefault() is JsonString @string: return @string.Value; diff --git a/backend/src/Migrations/MigrationPath.cs b/backend/src/Migrations/MigrationPath.cs index 03950a6d2..f24eb8bae 100644 --- a/backend/src/Migrations/MigrationPath.cs +++ b/backend/src/Migrations/MigrationPath.cs @@ -18,7 +18,7 @@ namespace Migrations { public sealed class MigrationPath : IMigrationPath { - private const int CurrentVersion = 21; + private const int CurrentVersion = 22; private readonly IServiceProvider serviceProvider; public MigrationPath(IServiceProvider serviceProvider) @@ -48,6 +48,12 @@ namespace Migrations yield return serviceProvider.GetRequiredService(); } + // Version 22: Also add app id to aggregate id. + if (version < 22) + { + yield return serviceProvider.GetRequiredService(); + } + // Version 07: Introduces AppId for backups. else if (version < 7) { @@ -74,14 +80,18 @@ namespace Migrations } // Version 14: Schema refactoring - if (version < 14) + // Version 22: Also add app id to aggregate id. + if (version < 22) { yield return serviceProvider.GetRequiredService(); + yield return serviceProvider.GetRequiredService(); } // Version 18: Rebuild assets. - if (version < 18) + // Version 22: Introduce domain id. + if (version < 22) { + yield return serviceProvider.GetService(); yield return serviceProvider.GetService(); } else @@ -100,18 +110,13 @@ namespace Migrations } // Version 21: Introduce content drafts V2. - if (version < 21) + // Version 22: Introduce domain id. + if (version < 22) { yield return serviceProvider.GetRequiredService(); } } - // Version 01: Introduce app patterns. - if (version < 1) - { - yield return serviceProvider.GetRequiredService(); - } - // Version 13: Json refactoring if (version < 13) { diff --git a/backend/src/Migrations/Migrations/AddPatterns.cs b/backend/src/Migrations/Migrations/AddPatterns.cs deleted file mode 100644 index df55f092e..000000000 --- a/backend/src/Migrations/Migrations/AddPatterns.cs +++ /dev/null @@ -1,60 +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 Squidex.Domain.Apps.Entities.Apps; -using Squidex.Domain.Apps.Entities.Apps.Commands; -using Squidex.Domain.Apps.Entities.Apps.Indexes; -using Squidex.Infrastructure.Commands; -using Squidex.Infrastructure.Migrations; - -namespace Migrations.Migrations -{ - public sealed class AddPatterns : IMigration - { - private readonly InitialPatterns initialPatterns; - private readonly ICommandBus commandBus; - private readonly IAppsIndex indexForApps; - - public AddPatterns(InitialPatterns initialPatterns, ICommandBus commandBus, IAppsIndex indexForApps) - { - this.indexForApps = indexForApps; - this.initialPatterns = initialPatterns; - this.commandBus = commandBus; - } - - public async Task UpdateAsync() - { - var ids = await indexForApps.GetIdsAsync(); - - foreach (var id in ids) - { - var app = await indexForApps.GetAppAsync(id); - - if (app != null && app.Patterns.Count == 0) - { - foreach (var pattern in initialPatterns.Values) - { - var command = - new AddPattern - { - Actor = app.CreatedBy, - AppId = id, - Name = pattern.Name, - PatternId = Guid.NewGuid(), - Pattern = pattern.Pattern, - Message = pattern.Message - }; - - await commandBus.PublishAsync(command); - } - } - } - } - } -} \ No newline at end of file diff --git a/backend/src/Migrations/Migrations/ClearRules.cs b/backend/src/Migrations/Migrations/ClearRules.cs new file mode 100644 index 000000000..97b3976b1 --- /dev/null +++ b/backend/src/Migrations/Migrations/ClearRules.cs @@ -0,0 +1,30 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Threading.Tasks; +using Squidex.Domain.Apps.Entities.Rules.State; +using Squidex.Infrastructure.Migrations; +using Squidex.Infrastructure.States; + +namespace Migrations.Migrations +{ + public sealed class ClearRules : IMigration + { + private readonly IStore store; + + public ClearRules(IStore store) + { + this.store = store; + } + + public Task UpdateAsync() + { + return store.ClearSnapshotsAsync(); + } + } +} diff --git a/backend/src/Migrations/Migrations/ConvertEventStoreAppId.cs b/backend/src/Migrations/Migrations/ConvertEventStoreAppId.cs index ed0f465f4..709363a5c 100644 --- a/backend/src/Migrations/Migrations/ConvertEventStoreAppId.cs +++ b/backend/src/Migrations/Migrations/ConvertEventStoreAppId.cs @@ -11,7 +11,6 @@ using System.Threading.Tasks; using MongoDB.Bson; using MongoDB.Driver; using Newtonsoft.Json.Linq; -using Squidex.Domain.Apps.Events; using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.Migrations; @@ -67,7 +66,7 @@ namespace Migrations.Migrations { var appId = NamedId.Parse(appIdValue.ToString(), Guid.TryParse).Id.ToString(); - var eventUpdate = updater.Set($"Events.{index}.Metadata.{SquidexHeaders.AppId}", appId); + var eventUpdate = updater.Set($"Events.{index}.Metadata.AppId", appId); if (update != null) { diff --git a/backend/src/Migrations/Migrations/CreateAssetSlugs.cs b/backend/src/Migrations/Migrations/CreateAssetSlugs.cs index 419f5bb12..dc3bef24c 100644 --- a/backend/src/Migrations/Migrations/CreateAssetSlugs.cs +++ b/backend/src/Migrations/Migrations/CreateAssetSlugs.cs @@ -5,10 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Assets.State; +using Squidex.Infrastructure; using Squidex.Infrastructure.Migrations; using Squidex.Infrastructure.States; @@ -16,9 +16,9 @@ namespace Migrations.Migrations { public sealed class CreateAssetSlugs : IMigration { - private readonly ISnapshotStore stateForAssets; + private readonly ISnapshotStore stateForAssets; - public CreateAssetSlugs(ISnapshotStore stateForAssets) + public CreateAssetSlugs(ISnapshotStore stateForAssets) { this.stateForAssets = stateForAssets; } @@ -29,7 +29,9 @@ namespace Migrations.Migrations { state.Slug = state.FileName.ToAssetSlug(); - await stateForAssets.WriteAsync(state.Id, state, version, version); + var key = DomainId.Combine(state.AppId.Id, state.Id).ToString(); + + await stateForAssets.WriteAsync(key, state, version, version); }); } } diff --git a/backend/src/Migrations/Migrations/MongoDb/AddAppIdToEventStream.cs b/backend/src/Migrations/Migrations/MongoDb/AddAppIdToEventStream.cs new file mode 100644 index 000000000..9e1e89278 --- /dev/null +++ b/backend/src/Migrations/Migrations/MongoDb/AddAppIdToEventStream.cs @@ -0,0 +1,118 @@ +// ========================================================================== +// 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 System.Threading.Tasks.Dataflow; +using MongoDB.Bson; +using MongoDB.Driver; +using Squidex.Infrastructure.Migrations; + +namespace Migrations.Migrations.MongoDb +{ + public sealed class AddAppIdToEventStream : IMigration + { + private readonly IMongoDatabase database; + + public AddAppIdToEventStream(IMongoDatabase database) + { + this.database = database; + } + + public async Task UpdateAsync() + { + var collection = database.GetCollection("Events"); + + const int SizeOfBatch = 200; + const int SizeOfQueue = 20; + + var batchBlock = new BatchBlock(SizeOfBatch, new GroupingDataflowBlockOptions + { + BoundedCapacity = SizeOfQueue * SizeOfBatch + }); + + var actionBlock = new ActionBlock(async batch => + { + var updates = new List>(); + + foreach (var commit in batch) + { + var eventStream = commit["EventStream"].AsString; + + string? appId = null; + + foreach (var @event in commit["Events"].AsBsonArray) + { + var metadata = @event["Metadata"].AsBsonDocument; + + if (metadata.TryGetValue("AppId", out var value)) + { + appId = value.AsString; + } + } + + if (appId != null) + { + var parts = eventStream.Split("-"); + + var domainType = parts[0]; + var domainId = string.Join("-", parts.Skip(1)); + + var newStreamName = $"{domainType}-{appId}--{domainId}"; + + var update = Builders.Update.Set("EventStream", newStreamName); + + var i = 0; + + foreach (var @event in commit["Events"].AsBsonArray) + { + update = update.Set($"Events.{i}.Metadata.AggregateId", $"{appId}--{domainId}"); + update = update.Unset($"Events.{i}.Metadata.AppId"); + + i++; + } + + var filter = Builders.Filter.Eq("_id", commit["_id"].AsString); + + updates.Add(new UpdateOneModel(filter, update)); + } + } + + if (updates.Count > 0) + { + await collection.BulkWriteAsync(updates); + } + }, new ExecutionDataflowBlockOptions + { + MaxDegreeOfParallelism = 4, + MaxMessagesPerTask = 1, + BoundedCapacity = SizeOfQueue + }); + + batchBlock.LinkTo(actionBlock, new DataflowLinkOptions + { + PropagateCompletion = true + }); + + await collection.Find(new BsonDocument()).ForEachAsync(async commit => + { + var eventStream = commit["EventStream"].AsString; + + if (!eventStream.Contains("--") && !eventStream.StartsWith("app-", StringComparison.OrdinalIgnoreCase)) + { + await batchBlock.SendAsync(commit); + } + }); + + batchBlock.Complete(); + + await actionBlock.Completion; + } + } +} diff --git a/backend/src/Migrations/Migrations/PopulateGrainIndexes.cs b/backend/src/Migrations/Migrations/PopulateGrainIndexes.cs index ef64223cc..eeb535789 100644 --- a/backend/src/Migrations/Migrations/PopulateGrainIndexes.cs +++ b/backend/src/Migrations/Migrations/PopulateGrainIndexes.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Apps.Indexes; @@ -50,20 +49,20 @@ namespace Migrations.Migrations private async Task RebuildAppIndexes() { - var appsByName = new Dictionary(); - var appsByUser = new Dictionary>(); + var appsByName = new Dictionary(); + var appsByUser = new Dictionary>(); - bool HasApp(NamedId appId, bool consistent, out Guid id) + bool HasApp(NamedId appId, bool consistent, out DomainId id) { return appsByName!.TryGetValue(appId.Name, out id) && (!consistent || id == appId.Id); } - HashSet Index(string contributorId) + HashSet Index(string contributorId) { return appsByUser!.GetOrAddNew(contributorId); } - void RemoveApp(NamedId appId, bool consistent) + void RemoveApp(NamedId appId, bool consistent) { if (HasApp(appId, consistent, out var id)) { @@ -121,9 +120,9 @@ namespace Migrations.Migrations private async Task RebuildRuleIndexes() { - var rulesByApp = new Dictionary>(); + var rulesByApp = new Dictionary>(); - HashSet Index(RuleEvent @event) + HashSet Index(RuleEvent @event) { return rulesByApp!.GetOrAddNew(@event.AppId.Id); } @@ -153,9 +152,9 @@ namespace Migrations.Migrations private async Task RebuildSchemaIndexes() { - var schemasByApp = new Dictionary>(); + var schemasByApp = new Dictionary>(); - Dictionary Index(SchemaEvent @event) + Dictionary Index(SchemaEvent @event) { return schemasByApp!.GetOrAddNew(@event.AppId.Id); } diff --git a/backend/src/Migrations/Migrations/RebuildAssetFolders.cs b/backend/src/Migrations/Migrations/RebuildAssetFolders.cs new file mode 100644 index 000000000..0168c910d --- /dev/null +++ b/backend/src/Migrations/Migrations/RebuildAssetFolders.cs @@ -0,0 +1,28 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Threading.Tasks; +using Squidex.Infrastructure.Commands; +using Squidex.Infrastructure.Migrations; + +namespace Migrations.Migrations +{ + public sealed class RebuildAssetFolders : IMigration + { + private readonly Rebuilder rebuilder; + + public RebuildAssetFolders(Rebuilder rebuilder) + { + this.rebuilder = rebuilder; + } + + public Task UpdateAsync() + { + return rebuilder.RebuildAssetFoldersAsync(); + } + } +} diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Apps/AppPatterns.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Apps/AppPatterns.cs index 294d1ccc0..b9729b400 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Apps/AppPatterns.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Apps/AppPatterns.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using Squidex.Infrastructure; @@ -13,7 +12,7 @@ using Squidex.Infrastructure.Collections; namespace Squidex.Domain.Apps.Core.Apps { - public sealed class AppPatterns : ImmutableDictionary + public sealed class AppPatterns : ImmutableDictionary { public static readonly AppPatterns Empty = new AppPatterns(); @@ -21,19 +20,19 @@ namespace Squidex.Domain.Apps.Core.Apps { } - public AppPatterns(Dictionary inner) + public AppPatterns(Dictionary inner) : base(inner) { } [Pure] - public AppPatterns Remove(Guid id) + public AppPatterns Remove(DomainId id) { return Without(id); } [Pure] - public AppPatterns Add(Guid id, string name, string pattern, string? message = null) + public AppPatterns Add(DomainId id, string name, string pattern, string? message = null) { var newPattern = new AppPattern(name, pattern, message); @@ -41,7 +40,7 @@ namespace Squidex.Domain.Apps.Core.Apps } [Pure] - public AppPatterns Update(Guid id, string name, string pattern, string? message = null) + public AppPatterns Update(DomainId id, string name, string pattern, string? message = null) { Guard.NotNullOrEmpty(name, nameof(name)); Guard.NotNullOrEmpty(pattern, nameof(pattern)); diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Json/AppPatternsConverter.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Json/AppPatternsConverter.cs index adcafa6f4..7c6e647c8 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Json/AppPatternsConverter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Json/AppPatternsConverter.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; +using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Newtonsoft; namespace Squidex.Domain.Apps.Core.Apps.Json @@ -17,7 +18,7 @@ namespace Squidex.Domain.Apps.Core.Apps.Json { protected override void WriteValue(JsonWriter writer, AppPatterns value, JsonSerializer serializer) { - var json = new Dictionary(value.Count); + var json = new Dictionary(value.Count); foreach (var (key, appPattern) in value) { @@ -29,7 +30,7 @@ namespace Squidex.Domain.Apps.Core.Apps.Json protected override AppPatterns ReadValue(JsonReader reader, Type objectType, JsonSerializer serializer) { - var json = serializer.Deserialize>(reader)!; + var json = serializer.Deserialize>(reader)!; return new AppPatterns(json.ToDictionary(x => x.Key, x => x.Value.ToPattern())); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Comments/Comment.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Comments/Comment.cs index 238ab6f4d..abcb8074f 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Comments/Comment.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Comments/Comment.cs @@ -13,7 +13,7 @@ namespace Squidex.Domain.Apps.Core.Comments { public sealed class Comment { - public Guid Id { get; } + public DomainId Id { get; } public Instant Time { get; } @@ -23,7 +23,7 @@ namespace Squidex.Domain.Apps.Core.Comments public Uri? Url { get; } - public Comment(Guid id, Instant time, RefToken user, string text, Uri? url = null) + public Comment(DomainId id, Instant time, RefToken user, string text, Uri? url = null) { Guard.NotEmpty(id, nameof(id)); Guard.NotNull(user, nameof(user)); diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Json/WorkflowConverter.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Json/WorkflowConverter.cs index a5c8d14b4..2a57b3d05 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Json/WorkflowConverter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Json/WorkflowConverter.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using Newtonsoft.Json; +using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Newtonsoft; namespace Squidex.Domain.Apps.Core.Contents.Json @@ -16,7 +17,7 @@ namespace Squidex.Domain.Apps.Core.Contents.Json { protected override void WriteValue(JsonWriter writer, Workflows value, JsonSerializer serializer) { - var json = new Dictionary(value.Count); + var json = new Dictionary(value.Count); foreach (var (key, workflow) in value) { @@ -28,7 +29,7 @@ namespace Squidex.Domain.Apps.Core.Contents.Json protected override Workflows ReadValue(JsonReader reader, Type objectType, JsonSerializer serializer) { - var json = serializer.Deserialize>(reader); + var json = serializer.Deserialize>(reader); return new Workflows(json!); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Status.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Status.cs index a275cf051..41117764f 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Status.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Status.cs @@ -11,8 +11,8 @@ using System.Diagnostics.CodeAnalysis; namespace Squidex.Domain.Apps.Core.Contents { - [TypeConverter(typeof(StatusConverter))] - public struct Status : IEquatable, IComparable + [TypeConverter(typeof(StatusTypeConverter))] + public readonly struct Status : IEquatable, IComparable { public static readonly Status Archived = new Status("Archived"); public static readonly Status Draft = new Status("Draft"); @@ -37,12 +37,12 @@ namespace Squidex.Domain.Apps.Core.Contents public bool Equals(Status other) { - return string.Equals(name, other.name); + return string.Equals(Name, other.Name); } public override int GetHashCode() { - return name?.GetHashCode() ?? 0; + return Name.GetHashCode(); } public override string ToString() diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/StatusConverter.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/StatusTypeConverter.cs similarity index 85% rename from backend/src/Squidex.Domain.Apps.Core.Model/Contents/StatusConverter.cs rename to backend/src/Squidex.Domain.Apps.Core.Model/Contents/StatusTypeConverter.cs index f580cfc27..4f54ad259 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/StatusConverter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/StatusTypeConverter.cs @@ -11,7 +11,7 @@ using System.Globalization; namespace Squidex.Domain.Apps.Core.Contents { - public sealed class StatusConverter : TypeConverter + public sealed class StatusTypeConverter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { @@ -25,7 +25,12 @@ namespace Squidex.Domain.Apps.Core.Contents public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - return new Status(value?.ToString()); + if (value is string s) + { + return new Status(s); + } + + return default(Status); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Workflow.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Workflow.cs index 311467aad..6b455a43d 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Workflow.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Workflow.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Squidex.Infrastructure; @@ -20,21 +19,21 @@ namespace Squidex.Domain.Apps.Core.Contents private const string DefaultName = "Unnamed"; public static readonly IReadOnlyDictionary EmptySteps = new Dictionary(); - public static readonly IReadOnlyList EmptySchemaIds = new List(); + public static readonly IReadOnlyList EmptySchemaIds = new List(); public static readonly Workflow Default = CreateDefault(); public static readonly Workflow Empty = new Workflow(default, EmptySteps); [IgnoreDuringEquals] public IReadOnlyDictionary Steps { get; } = EmptySteps; - public IReadOnlyList SchemaIds { get; } = EmptySchemaIds; + public IReadOnlyList SchemaIds { get; } = EmptySchemaIds; public Status Initial { get; } public Workflow( Status initial, IReadOnlyDictionary? steps, - IReadOnlyList? schemaIds = null, + IReadOnlyList? schemaIds = null, string? name = null) : base(name ?? DefaultName) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Workflows.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Workflows.cs index cadf85d76..f586b76d3 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Workflows.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Workflows.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; @@ -14,7 +13,7 @@ using Squidex.Infrastructure.Collections; namespace Squidex.Domain.Apps.Core.Contents { - public sealed class Workflows : ImmutableDictionary + public sealed class Workflows : ImmutableDictionary { public static readonly Workflows Empty = new Workflows(); @@ -22,19 +21,19 @@ namespace Squidex.Domain.Apps.Core.Contents { } - public Workflows(Dictionary inner) + public Workflows(Dictionary inner) : base(inner) { } [Pure] - public Workflows Remove(Guid id) + public Workflows Remove(DomainId id) { return Without(id); } [Pure] - public Workflows Add(Guid workflowId, string name) + public Workflows Add(DomainId workflowId, string name) { Guard.NotNullOrEmpty(name, nameof(name)); @@ -46,11 +45,11 @@ namespace Squidex.Domain.Apps.Core.Contents { Guard.NotNull(workflow, nameof(workflow)); - return With(Guid.Empty, workflow); + return With(default, workflow); } [Pure] - public Workflows Set(Guid id, Workflow workflow) + public Workflows Set(DomainId id, Workflow workflow) { Guard.NotNull(workflow, nameof(workflow)); @@ -58,11 +57,11 @@ namespace Squidex.Domain.Apps.Core.Contents } [Pure] - public Workflows Update(Guid id, Workflow workflow) + public Workflows Update(DomainId id, Workflow workflow) { Guard.NotNull(workflow, nameof(workflow)); - if (id == Guid.Empty) + if (id == DomainId.Empty) { return Set(workflow); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedAssetEvent.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedAssetEvent.cs index 6eed9b782..85b4761e9 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedAssetEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedAssetEvent.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; using Squidex.Domain.Apps.Core.Assets; using Squidex.Infrastructure; @@ -16,7 +15,7 @@ namespace Squidex.Domain.Apps.Core.Rules.EnrichedEvents { public EnrichedAssetEventType Type { get; set; } - public Guid Id { get; set; } + public DomainId Id { get; set; } public Instant Created { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedContentEvent.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedContentEvent.cs index 9ca850775..3a8cb228a 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedContentEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedContentEvent.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; using Squidex.Domain.Apps.Core.Contents; using Squidex.Infrastructure; @@ -16,7 +15,7 @@ namespace Squidex.Domain.Apps.Core.Rules.EnrichedEvents { public EnrichedContentEventType Type { get; set; } - public Guid Id { get; set; } + public DomainId Id { get; set; } public Instant Created { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedEvent.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedEvent.cs index d1fab9186..2a8376c2e 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedEvent.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; using Squidex.Infrastructure; @@ -13,7 +12,7 @@ namespace Squidex.Domain.Apps.Core.Rules.EnrichedEvents { public abstract class EnrichedEvent { - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } public Instant Timestamp { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedSchemaEvent.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedSchemaEvent.cs index 5362705c6..d0c57b2ca 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedSchemaEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedSchemaEvent.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Rules.EnrichedEvents { @@ -13,7 +13,7 @@ namespace Squidex.Domain.Apps.Core.Rules.EnrichedEvents { public EnrichedSchemaEventType Type { get; set; } - public Guid Id + public DomainId Id { get { return SchemaId.Id; } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedSchemaEventBase.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedSchemaEventBase.cs index 1092eca84..484c15edf 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedSchemaEventBase.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/EnrichedSchemaEventBase.cs @@ -5,13 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Rules.EnrichedEvents { public abstract class EnrichedSchemaEventBase : EnrichedUserEventBase { - public NamedId SchemaId { get; set; } + public NamedId SchemaId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/IEnrichedEntityEvent.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/IEnrichedEntityEvent.cs index 98f9cfff1..d3b08b379 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/IEnrichedEntityEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/EnrichedEvents/IEnrichedEntityEvent.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Rules.EnrichedEvents { public interface IEnrichedEntityEvent { - Guid Id { get; } + DomainId Id { get; } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/RuleJob.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/RuleJob.cs index 106358450..d713cfb41 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/RuleJob.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/RuleJob.cs @@ -5,18 +5,18 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Rules { public sealed class RuleJob { - public Guid Id { get; set; } + public DomainId Id { get; set; } - public Guid AppId { get; set; } + public DomainId AppId { get; set; } - public Guid RuleId { get; set; } + public DomainId RuleId { get; set; } public string EventName { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTriggerSchemaV2.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTriggerSchemaV2.cs index 0d797b6f4..13eb43b17 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTriggerSchemaV2.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTriggerSchemaV2.cs @@ -5,13 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Rules.Triggers { public sealed class ContentChangedTriggerSchemaV2 : Freezable { - public Guid SchemaId { get; set; } + public DomainId SchemaId { get; set; } public string? Condition { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField{T}.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField{T}.cs index c0c9b1be5..d338789d6 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField{T}.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField{T}.cs @@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Core.Schemas properties.Freeze(); } - private T ValidateProperties(FieldProperties newProperties) + private static T ValidateProperties(FieldProperties newProperties) { Guard.NotNull(newProperties, nameof(newProperties)); diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/ReferencesFieldProperties.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/ReferencesFieldProperties.cs index ce06e0135..af1585cc7 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/ReferencesFieldProperties.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/ReferencesFieldProperties.cs @@ -5,10 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Schemas { @@ -25,17 +25,17 @@ namespace Squidex.Domain.Apps.Core.Schemas public ReferencesFieldEditor Editor { get; set; } - public Guid SchemaId + public DomainId SchemaId { get { - return SchemaIds?.FirstOrDefault() ?? Guid.Empty; + return SchemaIds?.FirstOrDefault() ?? default; } set { if (value != default) { - SchemaIds = new ReadOnlyCollection(new List { value }); + SchemaIds = new ReadOnlyCollection(new List { value }); } else { @@ -44,7 +44,7 @@ namespace Squidex.Domain.Apps.Core.Schemas } } - public ReadOnlyCollection? SchemaIds { get; set; } + public ReadOnlyCollection? SchemaIds { get; set; } public override T Accept(IFieldPropertiesVisitor visitor) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/RootField{T}.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/RootField{T}.cs index 460540181..1365bfaf9 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/RootField{T}.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/RootField{T}.cs @@ -53,7 +53,7 @@ namespace Squidex.Domain.Apps.Core.Schemas properties.Freeze(); } - private T ValidateProperties(FieldProperties newProperties) + private static T ValidateProperties(FieldProperties newProperties) { Guard.NotNull(newProperties, nameof(newProperties)); diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaExtensions.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaExtensions.cs index 5df556719..7dce0d8ff 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaExtensions.cs @@ -59,9 +59,9 @@ namespace Squidex.Domain.Apps.Core.Schemas return schema.Properties.Label.WithFallback(schema.Name); } - public static Guid SingleId(this ReferencesFieldProperties properties) + public static DomainId SingleId(this ReferencesFieldProperties properties) { - return properties.SchemaIds?.Count == 1 ? properties.SchemaIds[0] : Guid.Empty; + return properties.SchemaIds?.Count == 1 ? properties.SchemaIds[0] : default; } public static IEnumerable ReferenceFields(this Schema schema) diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs index ae9cc05cf..d8b6ce562 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs @@ -131,7 +131,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent { if (field is IArrayField arrayField) { - foreach (var (key, value) in data) + foreach (var (_, value) in data) { if (value is JsonArray array) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ValueConverters.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ValueConverters.cs index ab9affe46..fe4dc2c45 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ValueConverters.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ValueConverters.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Text; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.ValidateContent; +using Squidex.Infrastructure; using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json.Objects; @@ -81,7 +82,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent }; } - public static ValueConverter ResolveAssetUrls(IReadOnlyCollection? fields, IUrlGenerator urlGenerator) + public static ValueConverter ResolveAssetUrls(NamedId appId, IReadOnlyCollection? fields, IUrlGenerator urlGenerator) { if (fields?.Any() != true) { @@ -132,10 +133,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent { var id = array[i].ToString(); - if (Guid.TryParse(id, out var assetId)) - { - array[i] = JsonValue.Create(urlGenerator.AssetContent(assetId)); - } + array[i] = JsonValue.Create(urlGenerator.AssetContent(appId, id)); } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs index 602fba9a8..1b78ebf91 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Text; using Squidex.Domain.Apps.Core.Contents; @@ -17,18 +16,18 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { public static class ContentReferencesExtensions { - public static HashSet GetReferencedIds(this NamedContentData source, Schema schema, int referencesPerField = int.MaxValue) + public static HashSet GetReferencedIds(this NamedContentData source, Schema schema, int referencesPerField = int.MaxValue) { Guard.NotNull(schema, nameof(schema)); - var extractor = new ReferencesExtractor(new HashSet(), referencesPerField); + var extractor = new ReferencesExtractor(new HashSet(), referencesPerField); AddReferencedIds(source, schema.Fields, extractor); return extractor.Result; } - public static void AddReferencedIds(this NamedContentData source, Schema schema, HashSet result, int referencesPerField = int.MaxValue) + public static void AddReferencedIds(this NamedContentData source, Schema schema, HashSet result, int referencesPerField = int.MaxValue) { Guard.NotNull(schema, nameof(schema)); @@ -37,7 +36,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds AddReferencedIds(source, schema.Fields, extractor); } - public static void AddReferencedIds(this NamedContentData source, IEnumerable fields, HashSet result, int referencesPerField = int.MaxValue) + public static void AddReferencedIds(this NamedContentData source, IEnumerable fields, HashSet result, int referencesPerField = int.MaxValue) { Guard.NotNull(fields, nameof(fields)); @@ -46,7 +45,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds AddReferencedIds(source, fields, extractor); } - public static void AddReferencedIds(this NamedContentData source, IField field, HashSet result, int referencesPerField = int.MaxValue) + public static void AddReferencedIds(this NamedContentData source, IField field, HashSet result, int referencesPerField = int.MaxValue) { Guard.NotNull(field, nameof(field)); @@ -76,9 +75,9 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds } } - public static HashSet GetReferencedIds(this IField field, IJsonValue? value, int referencesPerField = int.MaxValue) + public static HashSet GetReferencedIds(this IField field, IJsonValue? value, int referencesPerField = int.MaxValue) { - var result = new HashSet(); + var result = new HashSet(); if (value != null) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs index 3b5fabcd6..c68f71244 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; @@ -15,10 +14,10 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { public sealed class ReferencesCleaner : IFieldVisitor { - private readonly HashSet validIds; + private readonly HashSet validIds; private IJsonValue value; - public ReferencesCleaner(HashSet validIds) + public ReferencesCleaner(HashSet validIds) { Guard.NotNull(validIds, nameof(validIds)); @@ -113,7 +112,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds private bool IsValidReference(IJsonValue item) { - return item is JsonString s && Guid.TryParse(s.Value, out var guid) && validIds.Contains(guid); + return item is JsonString s && validIds.Contains(s.Value); } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtensions.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtensions.cs index ced99e669..4981ef012 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtensions.cs @@ -5,15 +5,15 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; +using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { public static class ReferencesExtensions { - public static void AddIds(this IJsonValue? value, HashSet result, int take) + public static void AddIds(this IJsonValue? value, HashSet result, int take) { var added = 0; @@ -21,9 +21,9 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { foreach (var id in array) { - if (id.Type == JsonValueType.String && Guid.TryParse(id.ToString(), out var guid)) + if (id is JsonString s) { - result.Add(guid); + result.Add(s.Value); added++; diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtractor.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtractor.cs index 6c6450055..a5beee7b8 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtractor.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtractor.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using Squidex.Domain.Apps.Core.Schemas; @@ -16,16 +15,16 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { internal sealed class ReferencesExtractor : IFieldVisitor { - private readonly HashSet result; + private readonly HashSet result; private readonly int take; private IJsonValue? value; - public HashSet Result + public HashSet Result { get { return result; } } - public ReferencesExtractor(HashSet result, int take) + public ReferencesExtractor(HashSet result, int take) { Guard.NotNull(result, nameof(result)); diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ValueReferencesConverter.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ValueReferencesConverter.cs index b0dec3778..2ca7ad847 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ValueReferencesConverter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ValueReferencesConverter.cs @@ -5,16 +5,16 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Squidex.Domain.Apps.Core.ConvertContent; +using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { public static class ValueReferencesConverter { - public static ValueConverter CleanReferences(HashSet? validIds = null) + public static ValueConverter CleanReferences(HashSet? validIds = null) { if (validIds == null) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/ContentSchemaBuilder.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/ContentSchemaBuilder.cs index 0328df650..55b81420b 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/ContentSchemaBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/ContentSchemaBuilder.cs @@ -24,7 +24,7 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema { Properties = { - ["id"] = SchemaBuilder.GuidProperty($"The id of the {schemaName} content.", true), + ["id"] = SchemaBuilder.StringProperty($"The id of the {schemaName} content.", true), ["data"] = SchemaBuilder.ObjectProperty(dataSchema, $"The data of the {schemaName}.", true), ["dataDraft"] = SchemaBuilder.ObjectProperty(dataSchema, $"The draft data of the {schemaName}."), ["version"] = SchemaBuilder.NumberProperty($"The version of the {schemaName}.", true), diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs index f680d1cea..733e7a04a 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs @@ -47,7 +47,7 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema public JsonSchemaProperty? Visit(IField field) { - var itemSchema = schemaResolver("AssetItem", SchemaBuilder.Guid()); + var itemSchema = schemaResolver("AssetItem", SchemaBuilder.String()); return SchemaBuilder.ArrayProperty(itemSchema); } @@ -113,7 +113,7 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema public JsonSchemaProperty? Visit(IField field) { - var itemSchema = schemaResolver("ReferenceItem", SchemaBuilder.Guid()); + var itemSchema = schemaResolver("ReferenceItem", SchemaBuilder.String()); return SchemaBuilder.ArrayProperty(itemSchema); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/SchemaBuilder.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/SchemaBuilder.cs index b84cafd7d..f7cfcf035 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/SchemaBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/SchemaBuilder.cs @@ -16,11 +16,6 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema return new JsonSchema { Type = JsonObjectType.Object }; } - public static JsonSchema Guid() - { - return new JsonSchema { Type = JsonObjectType.String, Format = JsonFormatStrings.Guid }; - } - public static JsonSchema String() { return new JsonSchema { Type = JsonObjectType.String }; @@ -41,11 +36,6 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema return Enrich(new JsonSchemaProperty { Type = JsonObjectType.String, Format = JsonFormatStrings.DateTime }, description, isRequired); } - public static JsonSchemaProperty GuidProperty(string? description = null, bool isRequired = false) - { - return Enrich(new JsonSchemaProperty { Type = JsonObjectType.String, Format = JsonFormatStrings.Guid }, description, isRequired); - } - public static JsonSchemaProperty NumberProperty(string? description = null, bool isRequired = false) { return Enrich(new JsonSchemaProperty { Type = JsonObjectType.Number }, description, isRequired); diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Extensions/EventFluidExtensions.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Extensions/EventFluidExtensions.cs index 099b67053..723dbac9f 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Extensions/EventFluidExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Extensions/EventFluidExtensions.cs @@ -37,9 +37,9 @@ namespace Squidex.Domain.Apps.Core.HandleRules.Extensions { if (context.GetValue("event")?.ToObjectValue() is EnrichedContentEvent contentEvent) { - if (objectValue.ToObjectValue() is Guid guid && guid != Guid.Empty) + if (objectValue.ToObjectValue() is DomainId id && id != DomainId.Empty) { - var result = urlGenerator.ContentUI(contentEvent.AppId, contentEvent.SchemaId, guid); + var result = urlGenerator.ContentUI(contentEvent.AppId, contentEvent.SchemaId, id); return new StringValue(result); } @@ -53,11 +53,14 @@ namespace Squidex.Domain.Apps.Core.HandleRules.Extensions { if (input is ObjectValue objectValue) { - if (objectValue.ToObjectValue() is Guid guid && guid != Guid.Empty) + if (context.GetValue("event")?.ToObjectValue() is EnrichedEvent @event) { - var result = urlGenerator.AssetContent(guid); + if (objectValue.ToObjectValue() is DomainId id && id != DomainId.Empty) + { + var result = urlGenerator.AssetContent(@event.AppId, id); - return new StringValue(result); + return new StringValue(result); + } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Extensions/EventJintExtension.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Extensions/EventJintExtension.cs index 14d91d048..6620fcb4f 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Extensions/EventJintExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Extensions/EventJintExtension.cs @@ -50,7 +50,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules.Extensions { if (context.TryGetValue("event", out var temp) && temp is EnrichedAssetEvent assetEvent) { - return urlGenerator.AssetContent(assetEvent.Id); + return urlGenerator.AssetContent(assetEvent.AppId, assetEvent.Id); } return JsValue.Null; diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/IRuleTriggerHandler.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/IRuleTriggerHandler.cs index 49fd6be5b..81a51e6ed 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/IRuleTriggerHandler.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/IRuleTriggerHandler.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; using Squidex.Domain.Apps.Events; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Core.HandleRules @@ -23,6 +24,6 @@ namespace Squidex.Domain.Apps.Core.HandleRules bool Trigger(EnrichedEvent @event, RuleTrigger trigger); - bool Trigger(AppEvent @event, RuleTrigger trigger, Guid ruleId); + bool Trigger(AppEvent @event, RuleTrigger trigger, DomainId ruleId); } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/PredefinedPatternsFormatter.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/PredefinedPatternsFormatter.cs index f2877da5f..5f2878a21 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/PredefinedPatternsFormatter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/PredefinedPatternsFormatter.cs @@ -118,7 +118,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules { if (@event is EnrichedAssetEvent assetEvent) { - return urlGenerator.AssetContent(assetEvent.Id); + return urlGenerator.AssetContent(assetEvent.AppId, assetEvent.Id); } return null; diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs index f283ff06a..f984db6b1 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs @@ -136,7 +136,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules return CombineParts(text, parts); } - private string CombineParts(string text, List parts) + private static string CombineParts(string text, List parts) { var span = text.AsSpan(); @@ -224,7 +224,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules return default; } - private (bool IsNew, Match) Match(string test) + private static (bool IsNew, Match) Match(string test) { var match = RegexPatternNew.Match(test); diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs index f35b4feb9..3675e71cf 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs @@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules this.log = log; } - public virtual async Task CreateJobsAsync(Rule rule, Guid ruleId, Envelope @event, bool ignoreStale = true) + public virtual async Task CreateJobsAsync(Rule rule, DomainId ruleId, Envelope @event, bool ignoreStale = true) { Guard.NotNull(rule, nameof(rule)); Guard.NotNull(@event, nameof(@event)); @@ -139,7 +139,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules var job = new RuleJob { - Id = Guid.NewGuid(), + Id = DomainId.NewGuid(), ActionData = string.Empty, ActionName = actionName, AppId = enrichedEvent.AppId.Id, diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleTriggerHandler.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleTriggerHandler.cs index e9cb5f03f..30c499b83 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleTriggerHandler.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleTriggerHandler.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; using Squidex.Domain.Apps.Events; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; #pragma warning disable IDE0019 // Use pattern matching @@ -56,7 +57,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules return false; } - bool IRuleTriggerHandler.Trigger(AppEvent @event, RuleTrigger trigger, Guid ruleId) + bool IRuleTriggerHandler.Trigger(AppEvent @event, RuleTrigger trigger, DomainId ruleId) { if (@event is TEvent typed) { @@ -73,7 +74,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules protected abstract bool Trigger(TEnrichedEvent @event, TTrigger trigger); - protected virtual bool Trigger(TEvent @event, TTrigger trigger, Guid ruleId) + protected virtual bool Trigger(TEvent @event, TTrigger trigger, DomainId ruleId) { return true; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/IUrlGenerator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/IUrlGenerator.cs index 1e987251d..49751932a 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/IUrlGenerator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/IUrlGenerator.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Assets; using Squidex.Infrastructure; @@ -15,47 +14,47 @@ namespace Squidex.Domain.Apps.Core { bool CanGenerateAssetSourceUrl { get; } - string? AssetSource(Guid assetId, long fileVersion); + string? AssetSource(NamedId appId, DomainId assetId, long fileVersion); - string? AssetThumbnail(Guid assetId, AssetType assetType); + string? AssetThumbnail(NamedId appId, DomainId assetId, AssetType assetType); - string AppSettingsUI(NamedId appId); + string AppSettingsUI(NamedId appId); - string AssetsUI(NamedId appId); + string AssetsUI(NamedId appId); - string AssetsUI(NamedId appId, string? query = null); + string AssetsUI(NamedId appId, string? query = null); - string AssetContent(Guid assetId); + string AssetContent(NamedId appId, DomainId assetId); - string BackupsUI(NamedId appId); + string BackupsUI(NamedId appId); - string ClientsUI(NamedId appId); + string ClientsUI(NamedId appId); - string ContentsUI(NamedId appId); + string ContentsUI(NamedId appId); - string ContentsUI(NamedId appId, NamedId schemaId); + string ContentsUI(NamedId appId, NamedId schemaId); - string ContentUI(NamedId appId, NamedId schemaId, Guid contentId); + string ContentUI(NamedId appId, NamedId schemaId, DomainId contentId); - string ContributorsUI(NamedId appId); + string ContributorsUI(NamedId appId); - string DashboardUI(NamedId appId); + string DashboardUI(NamedId appId); - string LanguagesUI(NamedId appId); + string LanguagesUI(NamedId appId); - string PatternsUI(NamedId appId); + string PatternsUI(NamedId appId); - string PlansUI(NamedId appId); + string PlansUI(NamedId appId); - string RolesUI(NamedId appId); + string RolesUI(NamedId appId); - string RulesUI(NamedId appId); + string RulesUI(NamedId appId); - string SchemasUI(NamedId appId); + string SchemasUI(NamedId appId); - string SchemaUI(NamedId appId, NamedId schemaId); + string SchemaUI(NamedId appId, NamedId schemaId); - string WorkflowsUI(NamedId appId); + string WorkflowsUI(NamedId appId); string UI(); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/ContentFieldObject.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/ContentFieldObject.cs index 9f86e3b02..48c736ec7 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/ContentFieldObject.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/ContentFieldObject.cs @@ -82,12 +82,9 @@ namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper public override void RemoveOwnProperty(string propertyName) { - if (valuesToDelete == null) - { - valuesToDelete = new HashSet(); - } - + valuesToDelete ??= new HashSet(); valuesToDelete.Add(propertyName); + valueProperties?.Remove(propertyName); MarkChanged(); diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs index ca9f9d16b..3670c2682 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs @@ -96,7 +96,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions return request; } - private async Task ParseResponse(ExecutionContext context, HttpResponseMessage response) + private static async Task ParseResponse(ExecutionContext context, HttpResponseMessage response) { var responseString = await response.Content.ReadAsStringAsync(); diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOperations.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOperations.cs index de3d6643b..458145670 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOperations.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOperations.cs @@ -15,19 +15,19 @@ namespace Squidex.Domain.Apps.Core.Scripting { private delegate void MessageDelegate(string? message); - private static readonly MessageDelegate Disallow = new MessageDelegate(message => + private static readonly MessageDelegate Disallow = message => { message = !string.IsNullOrWhiteSpace(message) ? message : "Not allowed"; throw new DomainForbiddenException(message); - }); + }; - private static readonly MessageDelegate Reject = new MessageDelegate(message => + private static readonly MessageDelegate Reject = message => { var errors = !string.IsNullOrWhiteSpace(message) ? new[] { new ValidationError(message) } : null; throw new ValidationException("Script rejected the operation.", errors); - }); + }; public static Engine AddDisallow(this Engine engine) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs index 190bd1a31..6692ebdc7 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Security.Claims; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Scripting { @@ -26,15 +27,15 @@ namespace Squidex.Domain.Apps.Core.Scripting set => SetValue(value); } - public Guid AppId + public DomainId AppId { - get => GetValue(); + get => GetValue(); set => SetValue(value); } - public Guid ContentId + public DomainId ContentId { - get => GetValue(); + get => GetValue(); set => SetValue(value); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/ITagService.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/ITagService.cs index 281893a1e..baa9483b1 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/ITagService.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/ITagService.cs @@ -5,26 +5,26 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Tags { public interface ITagService { - Task> GetTagIdsAsync(Guid appId, string group, HashSet names); + Task> GetTagIdsAsync(DomainId appId, string group, HashSet names); - Task> NormalizeTagsAsync(Guid appId, string group, HashSet? names, HashSet? ids); + Task> NormalizeTagsAsync(DomainId appId, string group, HashSet? names, HashSet? ids); - Task> DenormalizeTagsAsync(Guid appId, string group, HashSet ids); + Task> DenormalizeTagsAsync(DomainId appId, string group, HashSet ids); - Task GetTagsAsync(Guid appId, string group); + Task GetTagsAsync(DomainId appId, string group); - Task GetExportableTagsAsync(Guid appId, string group); + Task GetExportableTagsAsync(DomainId appId, string group); - Task RebuildTagsAsync(Guid appId, string group, TagsExport tags); + Task RebuildTagsAsync(DomainId appId, string group, TagsExport tags); - Task ClearAsync(Guid appId, string group); + Task ClearAsync(DomainId appId, string group); } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/TagGroups.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/TagGroups.cs index fd69b313b..6a62b0a07 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/TagGroups.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/TagGroups.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Tags { @@ -13,7 +13,7 @@ namespace Squidex.Domain.Apps.Core.Tags { public const string Assets = "Assets"; - public static string Schemas(Guid schemaId) + public static string Schemas(DomainId schemaId) { return $"Schemas_{schemaId}"; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/TagNormalizer.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/TagNormalizer.cs index da4ebd983..c3cd66078 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/TagNormalizer.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/TagNormalizer.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Contents; @@ -17,7 +16,7 @@ namespace Squidex.Domain.Apps.Core.Tags { public static class TagNormalizer { - public static async Task NormalizeAsync(this ITagService tagService, Guid appId, Guid schemaId, Schema schema, NamedContentData newData, NamedContentData? oldData) + public static async Task NormalizeAsync(this ITagService tagService, DomainId appId, DomainId schemaId, Schema schema, NamedContentData newData, NamedContentData? oldData) { Guard.NotNull(tagService, nameof(tagService)); Guard.NotNull(schema, nameof(schema)); @@ -53,7 +52,7 @@ namespace Squidex.Domain.Apps.Core.Tags } } - public static async Task DenormalizeAsync(this ITagService tagService, Guid appId, Guid schemaId, Schema schema, params NamedContentData[] datas) + public static async Task DenormalizeAsync(this ITagService tagService, DomainId appId, DomainId schemaId, Schema schema, params NamedContentData[] datas) { Guard.NotNull(tagService, nameof(tagService)); Guard.NotNull(schema, nameof(schema)); diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/FluidTemplateEngine.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/FluidTemplateEngine.cs index ededdd5da..55f72761f 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/FluidTemplateEngine.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/FluidTemplateEngine.cs @@ -45,6 +45,7 @@ namespace Squidex.Domain.Apps.Core.Templates FluidValue.SetTypeMapping(type, x => new StringValue(x.ToString())); } + globalTypes.Register>(); globalTypes.Register>(); globalTypes.Register>(); globalTypes.Register>(); diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs index 38306da6f..b83262e77 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using NodaTime; using Squidex.Domain.Apps.Core.Schemas; @@ -59,7 +58,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent if (!field.Properties.AllowDuplicates) { - yield return new UniqueValuesValidator(); + yield return new UniqueValuesValidator(); } } @@ -127,7 +126,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent if (!field.Properties.AllowDuplicates) { - yield return new UniqueValuesValidator(); + yield return new UniqueValuesValidator(); } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/IAssetInfo.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/IAssetInfo.cs index a91663107..8f1f63055 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/IAssetInfo.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/IAssetInfo.cs @@ -5,14 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Assets; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.ValidateContent { public interface IAssetInfo { - Guid AssetId { get; } + DomainId AssetId { get; } long FileSize { get; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs index ee50150f4..9cf521e8c 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs @@ -35,12 +35,12 @@ namespace Squidex.Domain.Apps.Core.ValidateContent public (object? Result, JsonError? Error) Visit(IField field) { - return ConvertToGuidList(); + return ConvertToStringList(); } public (object? Result, JsonError? Error) Visit(IField field) { - return ConvertToGuidList(); + return ConvertToStringList(); } public (object? Result, JsonError? Error) Visit(IField field) @@ -152,30 +152,6 @@ namespace Squidex.Domain.Apps.Core.ValidateContent return (value, null); } - private (object? Result, JsonError? Error) ConvertToGuidList() - { - if (value is JsonArray array) - { - var result = new List(array.Count); - - foreach (var item in array) - { - if (item is JsonString s && Guid.TryParse(s.Value, out var guid)) - { - result.Add(guid); - } - else - { - return (null, new JsonError("Invalid json type, expected array of guid strings.")); - } - } - - return (result, null); - } - - return (null, new JsonError("Invalid json type, expected array of guid strings.")); - } - private (object? Result, JsonError? Error) ConvertToStringList() { if (value is JsonArray array) diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs index 1a8c660e7..ca842cfb5 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Immutable; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; @@ -16,33 +15,33 @@ namespace Squidex.Domain.Apps.Core.ValidateContent { public ImmutableQueue Path { get; } - public NamedId AppId { get; } + public NamedId AppId { get; } - public NamedId SchemaId { get; } + public NamedId SchemaId { get; } public Schema Schema { get; } - public Guid ContentId { get; } + public DomainId ContentId { get; } public bool IsOptional { get; } public ValidationMode Mode { get; } public ValidationContext( - NamedId appId, - NamedId schemaId, + NamedId appId, + NamedId schemaId, Schema schema, - Guid contentId, + DomainId contentId, ValidationMode mode = ValidationMode.Default) : this(appId, schemaId, schema, contentId, ImmutableQueue.Empty, false, mode) { } private ValidationContext( - NamedId appId, - NamedId schemaId, + NamedId appId, + NamedId schemaId, Schema schema, - Guid contentId, + DomainId contentId, ImmutableQueue path, bool isOptional, ValidationMode mode = ValidationMode.Default) diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AssetsValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AssetsValidator.cs index e3fd8e414..735039bcc 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AssetsValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AssetsValidator.cs @@ -15,7 +15,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.ValidateContent.Validators { - public delegate Task> CheckAssets(IEnumerable ids); + public delegate Task> CheckAssets(IEnumerable ids); public sealed class AssetsValidator : IValidator { @@ -39,7 +39,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators return; } - if (value is ICollection assetIds && assetIds.Count > 0) + if (value is ICollection assetIds && assetIds.Count > 0) { var assets = await checkAssets(assetIds); var index = 0; diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/ReferencesValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/ReferencesValidator.cs index 8551d0f56..f1cf45838 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/ReferencesValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/ReferencesValidator.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -13,14 +12,14 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.ValidateContent.Validators { - public delegate Task> CheckContentsByIds(HashSet ids); + public delegate Task> CheckContentsByIds(HashSet ids); public sealed class ReferencesValidator : IValidator { - private readonly IEnumerable? schemaIds; + private readonly IEnumerable? schemaIds; private readonly CheckContentsByIds checkReferences; - public ReferencesValidator(IEnumerable? schemaIds, CheckContentsByIds checkReferences) + public ReferencesValidator(IEnumerable? schemaIds, CheckContentsByIds checkReferences) { Guard.NotNull(checkReferences, nameof(checkReferences)); @@ -36,7 +35,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators return; } - if (value is ICollection contentIds) + if (value is ICollection contentIds) { var foundIds = await checkReferences(contentIds.ToHashSet()); @@ -44,7 +43,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators { var (schemaId, _) = foundIds.FirstOrDefault(x => x.Id == id); - if (schemaId == Guid.Empty) + if (schemaId == DomainId.Empty) { addError(context.Path, $"Contains invalid reference '{id}'."); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueValidator.cs index e16194f6e..955b51e76 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueValidator.cs @@ -5,15 +5,15 @@ // 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.Queries; namespace Squidex.Domain.Apps.Core.ValidateContent.Validators { - public delegate Task> CheckUniqueness(FilterNode filter); + public delegate Task> CheckUniqueness(FilterNode filter); public sealed class UniqueValidator : IValidator { diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetEntity.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetEntity.cs index 8301989ec..4410d7c70 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetEntity.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetEntity.cs @@ -5,9 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; -using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using NodaTime; using Squidex.Domain.Apps.Core.Assets; @@ -17,21 +15,27 @@ using Squidex.Infrastructure.MongoDb; namespace Squidex.Domain.Apps.Entities.MongoDb.Assets { - public sealed class MongoAssetEntity : IAssetEntity, IVersionedEntity + public sealed class MongoAssetEntity : IAssetEntity, IVersionedEntity { [BsonId] [BsonElement("_id")] - [BsonRepresentation(BsonType.String)] - public Guid Id { get; set; } + public DomainId DocumentId { get; set; } [BsonRequired] [BsonElement("_ai")] - [BsonRepresentation(BsonType.String)] - public Guid IndexedAppId { get; set; } + public DomainId IndexedAppId { get; set; } + + [BsonIgnoreIfDefault] + [BsonElement("id")] + public DomainId Id { get; set; } [BsonIgnoreIfDefault] [BsonElement("pi")] - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } + + [BsonRequired] + [BsonElement("ai")] + public NamedId AppId { get; set; } [BsonRequired] [BsonElement("ct")] @@ -41,10 +45,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets [BsonElement("mt")] public Instant LastModified { get; set; } - [BsonRequired] - [BsonElement("ai")] - public NamedId AppId { get; set; } - [BsonRequired] [BsonElement("mm")] public string MimeType { get; set; } @@ -102,9 +102,14 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets [BsonElement("md")] public AssetMetadata Metadata { get; set; } - public Guid AssetId + public DomainId AssetId { get { return Id; } } + + public DomainId UniqueId + { + get { return DocumentId; } + } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderEntity.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderEntity.cs index 74d5d8ed3..8642ebdba 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderEntity.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderEntity.cs @@ -5,30 +5,35 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; -using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using NodaTime; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Infrastructure; +using Squidex.Infrastructure.MongoDb; namespace Squidex.Domain.Apps.Entities.MongoDb.Assets { - public sealed class MongoAssetFolderEntity : IAssetFolderEntity + public sealed class MongoAssetFolderEntity : IAssetFolderEntity, IVersionedEntity { [BsonId] [BsonElement("_id")] - [BsonRepresentation(BsonType.String)] - public Guid Id { get; set; } + public DomainId DocumentId { get; set; } [BsonRequired] [BsonElement("_ai")] - [BsonRepresentation(BsonType.String)] - public Guid IndexedAppId { get; set; } + public DomainId IndexedAppId { get; set; } + + [BsonRequired] + [BsonElement("id")] + public DomainId Id { get; set; } [BsonRequired] [BsonElement("pi")] - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } + + [BsonRequired] + [BsonElement("ai")] + public NamedId AppId { get; set; } [BsonRequired] [BsonElement("ct")] @@ -38,10 +43,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets [BsonElement("mt")] public Instant LastModified { get; set; } - [BsonRequired] - [BsonElement("ai")] - public NamedId AppId { get; set; } - [BsonRequired] [BsonElement("fn")] public string FolderName { get; set; } @@ -61,5 +62,10 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets [BsonRequired] [BsonElement("dl")] public bool IsDeleted { get; set; } + + public DomainId UniqueId + { + get { return DocumentId; } + } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository.cs index ecad09811..e53092444 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository.cs @@ -46,7 +46,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets }, ct); } - public async Task> QueryAsync(Guid appId, Guid parentId) + public async Task> QueryAsync(DomainId appId, DomainId parentId) { using (Profiler.TraceMethod("QueryAsyncByQuery")) { @@ -59,7 +59,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets } } - public async Task> QueryChildIdsAsync(Guid appId, Guid parentId) + public async Task> QueryChildIdsAsync(DomainId appId, DomainId parentId) { using (Profiler.TraceMethod()) { @@ -67,23 +67,20 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.ParentId == parentId).Only(x => x.Id) .ToListAsync(); - return assetFolderEntities.Select(x => Guid.Parse(x[IdField.Value].AsString)).ToList(); + return assetFolderEntities.Select(x => DomainId.Create(x[IdField.Value].AsString)).ToList(); } } - public async Task FindAssetFolderAsync(Guid id) + public async Task FindAssetFolderAsync(DomainId appId, DomainId id) { using (Profiler.TraceMethod()) { + var documentId = DomainId.Combine(appId, id).ToString(); + var assetFolderEntity = - await Collection.Find(x => x.Id == id) + await Collection.Find(x => x.DocumentId == documentId && !x.IsDeleted) .FirstOrDefaultAsync(); - if (assetFolderEntity?.IsDeleted == true) - { - return null; - } - return assetFolderEntity; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository_SnapshotStore.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository_SnapshotStore.cs index b4c671464..4409c1608 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository_SnapshotStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository_SnapshotStore.cs @@ -19,14 +19,14 @@ using Squidex.Infrastructure.States; namespace Squidex.Domain.Apps.Entities.MongoDb.Assets { - public sealed partial class MongoAssetFolderRepository : ISnapshotStore + public sealed partial class MongoAssetFolderRepository : ISnapshotStore { - async Task<(AssetFolderState Value, long Version)> ISnapshotStore.ReadAsync(Guid key) + async Task<(AssetFolderState Value, long Version)> ISnapshotStore.ReadAsync(DomainId key) { using (Profiler.TraceMethod()) { var existing = - await Collection.Find(x => x.Id == key) + await Collection.Find(x => x.DocumentId == key) .FirstOrDefaultAsync(); if (existing != null) @@ -38,20 +38,19 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets } } - async Task ISnapshotStore.WriteAsync(Guid key, AssetFolderState value, long oldVersion, long newVersion) + async Task ISnapshotStore.WriteAsync(DomainId key, AssetFolderState value, long oldVersion, long newVersion) { using (Profiler.TraceMethod()) { var entity = SimpleMapper.Map(value, new MongoAssetFolderEntity()); - entity.Version = newVersion; entity.IndexedAppId = value.AppId.Id; - await Collection.ReplaceOneAsync(x => x.Id == key && x.Version == oldVersion, entity, UpsertReplace); + await Collection.UpsertVersionedAsync(key, oldVersion, newVersion, entity); } } - async Task ISnapshotStore.ReadAllAsync(Func callback, CancellationToken ct) + async Task ISnapshotStore.ReadAllAsync(Func callback, CancellationToken ct) { using (Profiler.TraceMethod()) { @@ -59,11 +58,11 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets } } - async Task ISnapshotStore.RemoveAsync(Guid key) + async Task ISnapshotStore.RemoveAsync(DomainId key) { using (Profiler.TraceMethod()) { - await Collection.DeleteOneAsync(x => x.Id == key); + await Collection.DeleteOneAsync(x => x.DocumentId == key); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs index 5833e3337..2b46b4ef4 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs @@ -67,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets }, ct); } - public async Task> QueryAsync(Guid appId, Guid? parentId, ClrQuery query) + public async Task> QueryAsync(DomainId appId, DomainId? parentId, ClrQuery query) { using (Profiler.TraceMethod("QueryAsyncByQuery")) { @@ -96,31 +96,31 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets } } - public async Task> QueryIdsAsync(Guid appId, HashSet ids) + public async Task> QueryIdsAsync(DomainId appId, HashSet ids) { using (Profiler.TraceMethod("QueryAsyncByIds")) { var assetEntities = - await Collection.Find(BuildFilter(appId, ids)).Only(x => x.Id) + await Collection.Find(BuildFilter(appId, ids)).Only(x => x.DocumentId) .ToListAsync(); - return assetEntities.Select(x => Guid.Parse(x[IdField.Value].AsString)).ToList(); + return assetEntities.Select(x => DomainId.Create(x[IdField.Value].AsString)).ToList(); } } - public async Task> QueryChildIdsAsync(Guid appId, Guid parentId) + public async Task> QueryChildIdsAsync(DomainId appId, DomainId parentId) { using (Profiler.TraceMethod()) { var assetEntities = - await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.ParentId == parentId).Only(x => x.Id) + await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.ParentId == parentId).Only(x => x.DocumentId) .ToListAsync(); - return assetEntities.Select(x => Guid.Parse(x[IdField.Value].AsString)).ToList(); + return assetEntities.Select(x => DomainId.Create(x[IdField.Value].AsString)).ToList(); } } - public async Task> QueryAsync(Guid appId, HashSet ids) + public async Task> QueryAsync(DomainId appId, HashSet ids) { using (Profiler.TraceMethod("QueryAsyncByIds")) { @@ -132,7 +132,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets } } - public async Task FindAssetBySlugAsync(Guid appId, string slug) + public async Task FindAssetBySlugAsync(DomainId appId, string slug) { using (Profiler.TraceMethod()) { @@ -144,7 +144,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets } } - public async Task> QueryByHashAsync(Guid appId, string hash) + public async Task> QueryByHashAsync(DomainId appId, string hash) { using (Profiler.TraceMethod()) { @@ -156,7 +156,21 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets } } - public async Task FindAssetAsync(Guid id) + public async Task FindAssetAsync(DomainId appId, DomainId id) + { + using (Profiler.TraceMethod()) + { + var documentId = DomainId.Combine(appId, id).ToString(); + + var assetEntity = + await Collection.Find(x => x.DocumentId == documentId && !x.IsDeleted) + .FirstOrDefaultAsync(); + + return assetEntity; + } + } + + public async Task FindAssetAsync(DomainId id) { using (Profiler.TraceMethod()) { @@ -168,11 +182,12 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets } } - private static FilterDefinition BuildFilter(Guid appId, HashSet ids) + private static FilterDefinition BuildFilter(DomainId appId, HashSet ids) { + var documentIds = ids.Select(x => DomainId.Combine(appId, x)); + return Filter.And( - Filter.Eq(x => x.IndexedAppId, appId), - Filter.In(x => x.Id, ids), + Filter.In(x => x.Id, documentIds), Filter.Ne(x => x.IsDeleted, true)); } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs index ea27c74ab..076780322 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs @@ -19,14 +19,14 @@ using Squidex.Infrastructure.States; namespace Squidex.Domain.Apps.Entities.MongoDb.Assets { - public sealed partial class MongoAssetRepository : ISnapshotStore + public sealed partial class MongoAssetRepository : ISnapshotStore { - async Task<(AssetState Value, long Version)> ISnapshotStore.ReadAsync(Guid key) + async Task<(AssetState Value, long Version)> ISnapshotStore.ReadAsync(DomainId key) { using (Profiler.TraceMethod()) { var existing = - await Collection.Find(x => x.Id == key) + await Collection.Find(x => x.DocumentId == key) .FirstOrDefaultAsync(); if (existing != null) @@ -38,20 +38,19 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets } } - async Task ISnapshotStore.WriteAsync(Guid key, AssetState value, long oldVersion, long newVersion) + async Task ISnapshotStore.WriteAsync(DomainId key, AssetState value, long oldVersion, long newVersion) { using (Profiler.TraceMethod()) { var entity = SimpleMapper.Map(value, new MongoAssetEntity()); - entity.Version = newVersion; entity.IndexedAppId = value.AppId.Id; - await Collection.UpsertVersionedAsync(key, oldVersion, entity); + await Collection.UpsertVersionedAsync(key, oldVersion, newVersion, entity); } } - async Task ISnapshotStore.ReadAllAsync(Func callback, CancellationToken ct) + async Task ISnapshotStore.ReadAllAsync(Func callback, CancellationToken ct) { using (Profiler.TraceMethod()) { @@ -59,11 +58,11 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets } } - async Task ISnapshotStore.RemoveAsync(Guid key) + async Task ISnapshotStore.RemoveAsync(DomainId key) { using (Profiler.TraceMethod()) { - await Collection.DeleteOneAsync(x => x.Id == key); + await Collection.DeleteOneAsync(x => x.DocumentId == key); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/Visitors/FindExtensions.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/Visitors/FindExtensions.cs index 703cae70f..5c9a83ae9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/Visitors/FindExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/Visitors/FindExtensions.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using MongoDB.Bson; using MongoDB.Driver; +using Squidex.Infrastructure; using Squidex.Infrastructure.MongoDb.Queries; using Squidex.Infrastructure.Queries; @@ -36,7 +36,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors return query; } - public static FilterDefinition BuildFilter(this ClrQuery query, Guid appId, Guid? parentId) + public static FilterDefinition BuildFilter(this ClrQuery query, DomainId appId, DomainId? parentId) { var filters = new List> { @@ -46,12 +46,12 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors if (parentId.HasValue) { - if (parentId == Guid.Empty) + if (parentId == DomainId.Empty) { filters.Add( Filter.Or( Filter.Exists(x => x.ParentId, false), - Filter.Eq(x => x.ParentId, Guid.Empty))); + Filter.Eq(x => x.ParentId, DomainId.Empty))); } else { diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollectionAll.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollectionAll.cs index 9d92b587b..53b19feda 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollectionAll.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollectionAll.cs @@ -69,7 +69,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public async Task> QueryAsync(IAppEntity app, ISchemaEntity schema, HashSet ids) + public async Task> QueryAsync(IAppEntity app, ISchemaEntity schema, HashSet ids) { Guard.NotNull(app, nameof(app)); @@ -81,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public async Task> QueryAsync(IAppEntity app, HashSet ids) + public async Task> QueryAsync(IAppEntity app, HashSet ids) { Guard.NotNull(app, nameof(app)); @@ -93,7 +93,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public async Task FindContentAsync(ISchemaEntity schema, Guid id) + public async Task FindContentAsync(ISchemaEntity schema, DomainId id) { using (Profiler.TraceMethod()) { @@ -109,7 +109,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public async Task> QueryIdsAsync(Guid appId, HashSet ids) + public async Task> QueryIdsAsync(DomainId appId, HashSet ids) { using (Profiler.TraceMethod()) { @@ -117,7 +117,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public async Task> QueryIdsAsync(Guid appId, Guid schemaId, FilterNode filterNode) + public async Task> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode filterNode) { using (Profiler.TraceMethod()) { @@ -125,19 +125,19 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public Task FindAsync(Guid id) + public Task FindAsync(DomainId documentId) { - return Collection.Find(x => x.Id == id).FirstOrDefaultAsync(); + return Collection.Find(x => x.DocumentId == documentId).FirstOrDefaultAsync(); } - public Task UpsertVersionedAsync(Guid id, long oldVersion, MongoContentEntity entity) + public Task UpsertVersionedAsync(DomainId documentId, long oldVersion, MongoContentEntity entity) { - return Collection.UpsertVersionedAsync(id, oldVersion, entity); + return Collection.UpsertVersionedAsync(documentId, oldVersion, entity.Version, entity); } - public Task RemoveAsync(Guid id) + public Task RemoveAsync(DomainId documentId) { - return Collection.DeleteOneAsync(x => x.Id == id); + return Collection.DeleteOneAsync(x => x.DocumentId == documentId); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollectionPublished.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollectionPublished.cs index 80a1b4574..27240d141 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollectionPublished.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollectionPublished.cs @@ -73,7 +73,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public async Task> QueryAsync(IAppEntity app, ISchemaEntity schema, HashSet ids) + public async Task> QueryAsync(IAppEntity app, ISchemaEntity schema, HashSet ids) { Guard.NotNull(app, nameof(app)); @@ -85,7 +85,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public async Task> QueryAsync(IAppEntity app, HashSet ids) + public async Task> QueryAsync(IAppEntity app, HashSet ids) { Guard.NotNull(app, nameof(app)); @@ -97,7 +97,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public async Task FindContentAsync(ISchemaEntity schema, Guid id) + public async Task FindContentAsync(ISchemaEntity schema, DomainId id) { using (Profiler.TraceMethod()) { @@ -105,7 +105,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public async Task> QueryIdsAsync(Guid appId, HashSet ids) + public async Task> QueryIdsAsync(DomainId appId, HashSet ids) { using (Profiler.TraceMethod()) { @@ -113,14 +113,14 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public Task UpsertVersionedAsync(Guid id, long oldVersion, MongoContentEntity entity) + public Task UpsertVersionedAsync(DomainId documentId, long oldVersion, MongoContentEntity entity) { - return Collection.UpsertVersionedAsync(id, oldVersion, entity); + return Collection.UpsertVersionedAsync(documentId, oldVersion, entity.Version, entity); } - public Task RemoveAsync(Guid id) + public Task RemoveAsync(DomainId documentId) { - return Collection.DeleteOneAsync(x => x.Id == id); + return Collection.DeleteOneAsync(x => x.DocumentId == documentId); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentEntity.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentEntity.cs index 2252827e0..354784803 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentEntity.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentEntity.cs @@ -5,9 +5,8 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; -using MongoDB.Bson; +using System.Linq; using MongoDB.Bson.Serialization.Attributes; using NodaTime; using Squidex.Domain.Apps.Core.Contents; @@ -21,29 +20,37 @@ using Squidex.Infrastructure.MongoDb; namespace Squidex.Domain.Apps.Entities.MongoDb.Contents { [BsonIgnoreExtraElements] - public sealed class MongoContentEntity : IContentEntity, IVersionedEntity + public sealed class MongoContentEntity : IContentEntity, IVersionedEntity { private NamedContentData data; [BsonId] [BsonElement("_id")] - [BsonRepresentation(BsonType.String)] - public Guid Id { get; set; } + public DomainId DocumentId { get; set; } [BsonRequired] [BsonElement("_ai")] - [BsonRepresentation(BsonType.String)] - public Guid IndexedAppId { get; set; } + public DomainId IndexedAppId { get; set; } [BsonRequired] [BsonElement("_si")] - [BsonRepresentation(BsonType.String)] - public Guid IndexedSchemaId { get; set; } + public DomainId IndexedSchemaId { get; set; } + + [BsonRequired] + [BsonElement("ai")] + public NamedId AppId { get; set; } + + [BsonRequired] + [BsonElement("si")] + public NamedId SchemaId { get; set; } [BsonRequired] [BsonElement("rf")] - [BsonRepresentation(BsonType.String)] - public HashSet? ReferencedIds { get; set; } + public HashSet? ReferencedIds { get; set; } + + [BsonRequired] + [BsonElement("id")] + public DomainId Id { get; set; } [BsonRequired] [BsonElement("ss")] @@ -58,14 +65,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents [BsonJson] public IdContentData DataByIds { get; set; } - [BsonRequired] - [BsonElement("ai")] - public NamedId AppId { get; set; } - - [BsonRequired] - [BsonElement("si")] - public NamedId SchemaId { get; set; } - [BsonIgnoreIfNull] [BsonElement("sa")] public Instant? ScheduledAt { get; set; } @@ -104,9 +103,14 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents get { return data; } } + public DomainId UniqueId + { + get { return DocumentId; } + } + public void LoadData(NamedContentData data, Schema schema, DataConverter converter) { - ReferencedIds = data.GetReferencedIds(schema); + ReferencedIds = data.GetReferencedIds(schema).Select(x => DomainId.Combine(AppId, x)).ToHashSet(); DataByIds = converter.ToMongoModel(data, schema); } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs index b84d8406a..384856753 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs @@ -66,7 +66,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public Task> QueryAsync(IAppEntity app, ISchemaEntity schema, HashSet ids, SearchScope scope) + public Task> QueryAsync(IAppEntity app, ISchemaEntity schema, HashSet ids, SearchScope scope) { if (scope == SearchScope.All) { @@ -78,7 +78,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public Task> QueryAsync(IAppEntity app, HashSet ids, SearchScope scope) + public Task> QueryAsync(IAppEntity app, HashSet ids, SearchScope scope) { if (scope == SearchScope.All) { @@ -90,7 +90,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public Task FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id, SearchScope scope) + public Task FindContentAsync(IAppEntity app, ISchemaEntity schema, DomainId id, SearchScope scope) { if (scope == SearchScope.All) { @@ -102,7 +102,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - public Task> QueryIdsAsync(Guid appId, HashSet ids, SearchScope scope) + public Task> QueryIdsAsync(DomainId appId, HashSet ids, SearchScope scope) { if (scope == SearchScope.All) { @@ -119,7 +119,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents return collectionAll.QueryScheduledWithoutDataAsync(now, callback); } - public Task> QueryIdsAsync(Guid appId, Guid schemaId, FilterNode filterNode) + public Task> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode filterNode) { return collectionAll.QueryIdsAsync(appId, schemaId, filterNode); } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs index 1f730705d..7cd875916 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs @@ -18,14 +18,14 @@ using Squidex.Infrastructure.States; namespace Squidex.Domain.Apps.Entities.MongoDb.Contents { - public partial class MongoContentRepository : ISnapshotStore + public partial class MongoContentRepository : ISnapshotStore { - Task ISnapshotStore.ReadAllAsync(Func callback, CancellationToken ct) + Task ISnapshotStore.ReadAllAsync(Func callback, CancellationToken ct) { throw new NotSupportedException(); } - async Task ISnapshotStore.ClearAsync() + async Task ISnapshotStore.ClearAsync() { using (Profiler.TraceMethod()) { @@ -34,7 +34,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - async Task ISnapshotStore.RemoveAsync(Guid key) + async Task ISnapshotStore.RemoveAsync(DomainId key) { using (Profiler.TraceMethod()) { @@ -43,7 +43,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - async Task<(ContentState Value, long Version)> ISnapshotStore.ReadAsync(Guid key) + async Task<(ContentState Value, long Version)> ISnapshotStore.ReadAsync(DomainId key) { using (Profiler.TraceMethod()) { @@ -62,11 +62,11 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } - async Task ISnapshotStore.WriteAsync(Guid key, ContentState value, long oldVersion, long newVersion) + async Task ISnapshotStore.WriteAsync(DomainId key, ContentState value, long oldVersion, long newVersion) { using (Profiler.TraceMethod()) { - if (value.SchemaId.Id == Guid.Empty) + if (value.SchemaId.Id == DomainId.Empty) { return; } @@ -87,13 +87,15 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } else { - await DeletePublishedContentAsync(value.Id); + await DeletePublishedContentAsync(value.AppId.Id, value.Id); } } - private Task DeletePublishedContentAsync(Guid key) + private Task DeletePublishedContentAsync(DomainId appId, DomainId id) { - return collectionPublished.RemoveAsync(key); + var documentId = DomainId.Combine(appId, id).ToString(); + + return collectionPublished.RemoveAsync(documentId); } private async Task UpsertDraftContentAsync(ContentState value, long oldVersion, long newVersion, ISchemaEntity schema) @@ -105,34 +107,37 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents Version = newVersion }); + content.DocumentId = value.UniqueId; content.ScheduledAt = value.ScheduleJob?.DueTime; content.ScheduleJob = value.ScheduleJob; content.NewStatus = value.NewStatus; content.LoadData(value.Data, schema.SchemaDef, converter); - await collectionAll.UpsertVersionedAsync(content.Id, oldVersion, content); + await collectionAll.UpsertVersionedAsync(content.DocumentId, oldVersion, content); } private async Task UpsertPublishedContentAsync(ContentState value, long oldVersion, long newVersion, ISchemaEntity schema) { var content = SimpleMapper.Map(value, new MongoContentEntity { + Id = value.Id, IndexedAppId = value.AppId.Id, IndexedSchemaId = value.SchemaId.Id, Version = newVersion }); + content.DocumentId = value.UniqueId; content.ScheduledAt = null; content.ScheduleJob = null; content.NewStatus = null; content.LoadData(value.CurrentVersion.Data, schema.SchemaDef, converter); - await collectionPublished.UpsertVersionedAsync(content.Id, oldVersion, content); + await collectionPublished.UpsertVersionedAsync(content.DocumentId, oldVersion, content); } - private async Task GetSchemaAsync(Guid appId, Guid schemaId) + private async Task GetSchemaAsync(DomainId appId, DomainId schemaId) { var schema = await appProvider.GetSchemaAsync(appId, schemaId, true); diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryContent.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryContent.cs index 3ecee088c..62f17f4aa 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryContent.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryContent.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using MongoDB.Driver; using Squidex.Domain.Apps.Entities.Contents; @@ -23,11 +22,13 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations this.converter = converter; } - public async Task DoAsync(ISchemaEntity schema, Guid id) + public async Task DoAsync(ISchemaEntity schema, DomainId id) { Guard.NotNull(schema, nameof(schema)); - var find = Collection.Find(x => x.Id == id); + var documentId = DomainId.Combine(schema.AppId, id).ToString(); + + var find = Collection.Find(x => x.DocumentId == documentId); var contentEntity = await find.FirstOrDefaultAsync(); diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryContentsByIds.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryContentsByIds.cs index afa377614..a805ac94e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryContentsByIds.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryContentsByIds.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -28,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations this.appProvider = appProvider; } - public async Task> DoAsync(Guid appId, ISchemaEntity? schema, HashSet ids) + public async Task> DoAsync(DomainId appId, ISchemaEntity? schema, HashSet ids) { Guard.NotNull(ids, nameof(ids)); @@ -52,9 +51,9 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations return result; } - private async Task> GetSchemasAsync(Guid appId, ISchemaEntity? schema, List contentItems) + private async Task> GetSchemasAsync(DomainId appId, ISchemaEntity? schema, List contentItems) { - var schemas = new Dictionary(); + var schemas = new Dictionary(); if (schema != null) { @@ -79,29 +78,30 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations return schemas; } - private static FilterDefinition CreateFilter(Guid appId, ICollection ids) + private static FilterDefinition CreateFilter(DomainId appId, ICollection ids) { var filters = new List> { - Filter.Eq(x => x.IndexedAppId, appId), Filter.Ne(x => x.IsDeleted, true) }; if (ids != null && ids.Count > 0) { + var documentIds = ids.Select(x => DomainId.Combine(appId, x)).ToList(); + if (ids.Count > 1) { filters.Add( Filter.Or( - Filter.In(x => x.Id, ids))); + Filter.In(x => x.DocumentId, documentIds))); } else { - var first = ids.First(); + var first = documentIds.First(); filters.Add( Filter.Or( - Filter.Eq(x => x.Id, first))); + Filter.Eq(x => x.DocumentId, first))); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryContentsByQuery.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryContentsByQuery.cs index c44e26ee5..e64967101 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryContentsByQuery.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryContentsByQuery.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -34,8 +33,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations { [BsonId] [BsonElement("_id")] - [BsonRepresentation(BsonType.String)] - public Guid Id { get; set; } + public DomainId Id { get; set; } public MongoContentEntity[] Joined { get; set; } } @@ -51,6 +49,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations { var index = new CreateIndexModel(Index + .Ascending(x => x.IndexedAppId) .Ascending(x => x.IndexedSchemaId) .Ascending(x => x.IsDeleted) .Ascending(x => x.ReferencedIds) @@ -69,7 +68,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations { query = query.AdjustToModel(schema.SchemaDef); - List? fullTextIds = null; + List? fullTextIds = null; if (!string.IsNullOrWhiteSpace(query.FullText)) { @@ -83,7 +82,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations } } - var filter = CreateFilter(schema.Id, fullTextIds, query); + var filter = CreateFilter(schema.AppId.Id, schema.Id, fullTextIds, query); var contentCount = Collection.Find(filter).CountDocumentsAsync(); var contentItems = FindContentsAsync(query, filter); @@ -125,7 +124,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations .QuerySort(query) .QuerySkip(query) .QueryLimit(query) - .Lookup(Collection, x => x.Id, x => x.Id, x => x.Joined) + .Lookup(Collection, x => x.Id, x => x.DocumentId, x => x.Joined) .ToListAsync(); return joined.Select(x => x.Joined[0]).ToList(); @@ -146,20 +145,23 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations return query.Sort?.All(x => x.Path.ToString() == "mt" && x.Order == SortOrder.Descending) == true; } - private static FilterDefinition CreateFilter(Guid schemaId, ICollection? ids, ClrQuery? query) + private static FilterDefinition CreateFilter(DomainId appId, DomainId schemaId, ICollection? ids, ClrQuery? query) { var filters = new List> { + Filter.Eq(x => x.IndexedAppId, appId), Filter.Eq(x => x.IndexedSchemaId, schemaId), Filter.Ne(x => x.IsDeleted, true) }; if (ids != null && ids.Count > 0) { + var documentIds = ids.Select(x => DomainId.Combine(appId, x)).ToList(); + filters.Add( Filter.Or( - Filter.AnyIn(x => x.ReferencedIds, ids), - Filter.In(x => x.Id, ids))); + Filter.AnyIn(x => x.ReferencedIds, documentIds), + Filter.In(x => x.DocumentId, documentIds))); } if (query?.Filter != null) diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryIdsAsync.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryIdsAsync.cs index 6a9f1d467..683a95529 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryIdsAsync.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryIdsAsync.cs @@ -12,6 +12,7 @@ using System.Threading; using System.Threading.Tasks; using MongoDB.Bson.Serialization; using MongoDB.Driver; +using Squidex.Infrastructure; using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.MongoDb.Queries; using Squidex.Infrastructure.Queries; @@ -20,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations { internal sealed class QueryIdsAsync : OperationBase { - private static readonly List<(Guid SchemaId, Guid Id)> EmptyIds = new List<(Guid SchemaId, Guid Id)>(); + private static readonly IReadOnlyList<(DomainId SchemaId, DomainId Id)> EmptyIds = new List<(DomainId SchemaId, DomainId Id)>(); private static readonly Lazy IdField = new Lazy(GetIdField); private static readonly Lazy SchemaIdField = new Lazy(GetSchemaIdField); private readonly IAppProvider appProvider; @@ -34,28 +35,30 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations { var index = new CreateIndexModel(Index + .Ascending(x => x.IndexedAppId) .Ascending(x => x.IndexedSchemaId) .Ascending(x => x.IsDeleted)); return Collection.Indexes.CreateOneAsync(index, cancellationToken: ct); } - public async Task> DoAsync(Guid appId, HashSet ids) + public async Task> DoAsync(DomainId appId, HashSet ids) { + var documentIds = ids.Select(x => DomainId.Combine(appId, x)); + var filter = Filter.And( - Filter.Eq(x => x.IndexedAppId, appId), - Filter.In(x => x.Id, ids), + Filter.In(x => x.DocumentId, documentIds), Filter.Ne(x => x.IsDeleted, true)); var contentEntities = await Collection.Find(filter).Only(x => x.Id, x => x.IndexedSchemaId) .ToListAsync(); - return contentEntities.Select(x => (Guid.Parse(x[SchemaIdField.Value].AsString), Guid.Parse(x[IdField.Value].AsString))).ToList(); + return contentEntities.Select(x => (DomainId.Create(x[SchemaIdField.Value].AsString), DomainId.Create(x[IdField.Value].AsString))).ToList(); } - public async Task> DoAsync(Guid appId, Guid schemaId, FilterNode filterNode) + public async Task> DoAsync(DomainId appId, DomainId schemaId, FilterNode filterNode) { var schema = await appProvider.GetSchemaAsync(appId, schemaId); @@ -64,19 +67,20 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations return EmptyIds; } - var filter = BuildFilter(filterNode.AdjustToModel(schema.SchemaDef), schemaId); + var filter = BuildFilter(filterNode.AdjustToModel(schema.SchemaDef), appId, schemaId); var contentEntities = - await Collection.Find(filter).Only(x => x.Id, x => x.IndexedSchemaId) + await Collection.Find(filter).Only(x => x.DocumentId, x => x.IndexedSchemaId) .ToListAsync(); - return contentEntities.Select(x => (Guid.Parse(x[SchemaIdField.Value].AsString), Guid.Parse(x[IdField.Value].AsString))).ToList(); + return contentEntities.Select(x => (DomainId.Create(x[SchemaIdField.Value].AsString), DomainId.Create(x[IdField.Value].AsString))).ToList(); } - public static FilterDefinition BuildFilter(FilterNode? filterNode, Guid schemaId) + public static FilterDefinition BuildFilter(FilterNode? filterNode, DomainId appId, DomainId schemaId) { var filters = new List> { + Filter.Eq(x => x.IndexedAppId, appId), Filter.Eq(x => x.IndexedSchemaId, schemaId), Filter.Ne(x => x.IsDeleted, true) }; diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/StatusSerializer.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/StatusSerializer.cs index 5d59c836a..933084a96 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/StatusSerializer.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/StatusSerializer.cs @@ -6,6 +6,7 @@ // ========================================================================== using System.Threading; +using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using Squidex.Domain.Apps.Core.Contents; @@ -14,13 +15,20 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents { public sealed class StatusSerializer : SerializerBase { - private static volatile int isRegistered; + private static int isRegistered; public static void Register() { if (Interlocked.Increment(ref isRegistered) == 1) { - BsonSerializer.RegisterSerializer(new StatusSerializer()); + try + { + BsonSerializer.RegisterSerializer(new StatusSerializer()); + } + catch (BsonSerializationException) + { + return; + } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoIndexStorage.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoIndexStorage.cs index fca521983..153965a7c 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoIndexStorage.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoIndexStorage.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.IO; using System.IO.Compression; using System.Threading.Tasks; @@ -29,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.FullText this.bucket = bucket; } - public async Task CreateDirectoryAsync(Guid ownerId) + public async Task CreateDirectoryAsync(DomainId ownerId) { var fileId = $"index_{ownerId}"; diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoTextIndexState.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoTextIndexState.cs new file mode 100644 index 000000000..bf1e78a06 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoTextIndexState.cs @@ -0,0 +1,61 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using MongoDB.Bson.Serialization.Attributes; +using Squidex.Domain.Apps.Entities.Contents.Text.State; +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Entities.MongoDb.FullText +{ + public sealed class MongoTextIndexState + { + [BsonId] + [BsonElement] + public DomainId DocumentId { get; set; } + + [BsonRequired] + [BsonElement] + public DomainId ContentId { get; set; } + + [BsonRequired] + [BsonElement("c")] + public string DocIdCurrent { get; set; } + + [BsonRequired] + [BsonElement("n")] + public string? DocIdNew { get; set; } + + [BsonRequired] + [BsonElement("p")] + public string? DocIdForPublished { get; set; } + + public MongoTextIndexState() + { + } + + public MongoTextIndexState(DomainId documentId, TextContentState state) + { + DocumentId = documentId; + + ContentId = state.ContentId; + DocIdNew = state.DocIdNew; + DocIdCurrent = state.DocIdCurrent; + DocIdForPublished = state.DocIdForPublished; + } + + public TextContentState ToState() + { + return new TextContentState + { + ContentId = ContentId, + DocIdNew = DocIdNew, + DocIdCurrent = DocIdCurrent, + DocIdForPublished = DocIdForPublished + }; + } + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoTextIndexerState.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoTextIndexerState.cs index 95dede9c9..854a50c80 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoTextIndexerState.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoTextIndexerState.cs @@ -5,34 +5,16 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; -using MongoDB.Bson.Serialization; using MongoDB.Driver; using Squidex.Domain.Apps.Entities.Contents.Text.State; +using Squidex.Infrastructure; using Squidex.Infrastructure.MongoDb; namespace Squidex.Domain.Apps.Entities.MongoDb.FullText { - public sealed class MongoTextIndexerState : MongoRepositoryBase, ITextIndexerState + public sealed class MongoTextIndexerState : MongoRepositoryBase, ITextIndexerState { - static MongoTextIndexerState() - { - BsonClassMap.RegisterClassMap(cm => - { - cm.MapIdField(x => x.ContentId); - - cm.MapProperty(x => x.DocIdCurrent) - .SetElementName("c"); - - cm.MapProperty(x => x.DocIdNew) - .SetElementName("n").SetIgnoreIfNull(true); - - cm.MapProperty(x => x.DocIdForPublished) - .SetElementName("p").SetIgnoreIfNull(true); - }); - } - public MongoTextIndexerState(IMongoDatabase database, bool setup = false) : base(database, setup) { @@ -43,19 +25,28 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.FullText return "TextIndexerState"; } - public Task GetAsync(Guid contentId) + public async Task GetAsync(DomainId appId, DomainId contentId) { - return Collection.Find(x => x.ContentId == contentId).FirstOrDefaultAsync()!; + var documentId = DomainId.Combine(appId, contentId).ToString(); + + var result = await Collection.Find(x => x.DocumentId == documentId).FirstOrDefaultAsync()!; + + return result?.ToState(); } - public Task RemoveAsync(Guid contentId) + public Task RemoveAsync(DomainId appId, DomainId contentId) { - return Collection.DeleteOneAsync(x => x.ContentId == contentId); + var documentId = DomainId.Combine(appId, contentId).ToString(); + + return Collection.DeleteOneAsync(x => x.DocumentId == documentId); } - public Task SetAsync(TextContentState state) + public Task SetAsync(DomainId appId, TextContentState state) { - return Collection.ReplaceOneAsync(x => x.ContentId == state.ContentId, state, UpsertReplace); + var documentId = DomainId.Combine(appId, state.ContentId).ToString(); + var document = new MongoTextIndexState(documentId, state); + + return Collection.ReplaceOneAsync(x => x.DocumentId == documentId, document, UpsertReplace); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/History/MongoHistoryEventRepository.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/History/MongoHistoryEventRepository.cs index a1109021c..5cf5c10f7 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/History/MongoHistoryEventRepository.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/History/MongoHistoryEventRepository.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -13,6 +12,7 @@ using MongoDB.Bson.Serialization; using MongoDB.Driver; using Squidex.Domain.Apps.Entities.History; using Squidex.Domain.Apps.Entities.History.Repositories; +using Squidex.Infrastructure; using Squidex.Infrastructure.MongoDb; namespace Squidex.Domain.Apps.Entities.MongoDb.History @@ -52,7 +52,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.History cancellationToken: ct); } - public async Task> QueryByChannelAsync(Guid appId, string channelPrefix, int count) + public async Task> QueryByChannelAsync(DomainId appId, string channelPrefix, int count) { if (!string.IsNullOrWhiteSpace(channelPrefix)) { @@ -69,7 +69,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.History return Collection.ReplaceOneAsync(x => x.Id == item.Id, item, UpsertReplace); } - public Task RemoveAsync(Guid appId) + public Task RemoveAsync(DomainId appId) { return Collection.DeleteManyAsync(x => x.AppId == appId); } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventEntity.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventEntity.cs index c5a417aef..54c4537ae 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventEntity.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventEntity.cs @@ -5,13 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using NodaTime; using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Entities.Rules; +using Squidex.Infrastructure; using Squidex.Infrastructure.MongoDb; namespace Squidex.Domain.Apps.Entities.MongoDb.Rules @@ -20,13 +20,11 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules { [BsonRequired] [BsonElement] - [BsonRepresentation(BsonType.String)] - public Guid AppId { get; set; } + public DomainId AppId { get; set; } [BsonIgnoreIfDefault] [BsonElement] - [BsonRepresentation(BsonType.String)] - public Guid RuleId { get; set; } + public DomainId RuleId { get; set; } [BsonRequired] [BsonElement] @@ -58,5 +56,15 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules [BsonRequired] [BsonElement] public Instant? NextAttempt { get; set; } + + DomainId IEntity.Id + { + get { return DocumentId; } + } + + DomainId IEntity.UniqueId + { + get { return DocumentId; } + } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs index 4f5fb1bde..ee27d862c 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs @@ -43,8 +43,12 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules await collection.Indexes.CreateManyAsync(new[] { - new CreateIndexModel(Index.Ascending(x => x.NextAttempt)), - new CreateIndexModel(Index.Ascending(x => x.AppId).Descending(x => x.Created)), + new CreateIndexModel( + Index.Ascending(x => x.NextAttempt)), + + new CreateIndexModel( + Index.Ascending(x => x.AppId).Descending(x => x.Created)), + new CreateIndexModel( Index .Ascending(x => x.Expires), @@ -60,13 +64,13 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules return Collection.Find(x => x.NextAttempt < now).ForEachAsync(callback, ct); } - public async Task> QueryByAppAsync(Guid appId, Guid? ruleId = null, int skip = 0, int take = 20) + public async Task> QueryByAppAsync(DomainId appId, DomainId? ruleId = null, int skip = 0, int take = 20) { var filter = Filter.Eq(x => x.AppId, appId); - if (ruleId.HasValue) + if (ruleId.HasValue && ruleId.Value != DomainId.Empty) { - filter = Filter.And(filter, Filter.Eq(x => x.RuleId, ruleId)); + filter = Filter.And(filter, Filter.Eq(x => x.RuleId, ruleId.Value)); } var taskForItems = Collection.Find(filter).Skip(skip).Limit(take).SortByDescending(x => x.Created).ToListAsync(); @@ -77,18 +81,18 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules return ResultList.Create(total, items); } - public async Task FindAsync(Guid id) + public async Task FindAsync(DomainId id) { var ruleEvent = - await Collection.Find(x => x.Id == id) + await Collection.Find(x => x.DocumentId == id) .FirstOrDefaultAsync(); return ruleEvent; } - public Task EnqueueAsync(Guid id, Instant nextAttempt) + public Task EnqueueAsync(DomainId id, Instant nextAttempt) { - return Collection.UpdateOneAsync(x => x.Id == id, Update.Set(x => x.NextAttempt, nextAttempt)); + return Collection.UpdateOneAsync(x => x.DocumentId == id, Update.Set(x => x.NextAttempt, nextAttempt)); } public async Task EnqueueAsync(RuleJob job, Instant? nextAttempt, CancellationToken ct = default) @@ -98,9 +102,9 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules await Collection.InsertOneIfNotExistsAsync(entity, ct); } - public Task CancelAsync(Guid id) + public Task CancelAsync(DomainId id) { - return Collection.UpdateOneAsync(x => x.Id == id, + return Collection.UpdateOneAsync(x => x.DocumentId == id, Update .Set(x => x.NextAttempt, null) .Set(x => x.JobResult, RuleJobResult.Cancelled)); @@ -120,7 +124,9 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules await statisticsCollection.IncrementFailed(job.AppId, job.RuleId, update.Finished); } - await Collection.UpdateOneAsync(x => x.Id == job.Id, + var documentId = job.Id.ToString(); + + await Collection.UpdateOneAsync(x => x.DocumentId == documentId, Update .Set(x => x.Result, update.ExecutionResult) .Set(x => x.LastDump, update.ExecutionDump) @@ -129,7 +135,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules .Inc(x => x.NumCalls, 1)); } - public Task> QueryStatisticsByAppAsync(Guid appId) + public Task> QueryStatisticsByAppAsync(DomainId appId) { return statisticsCollection.QueryByAppAsync(appId); } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleStatisticsCollection.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleStatisticsCollection.cs index e4beb3036..091d6c18a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleStatisticsCollection.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleStatisticsCollection.cs @@ -5,16 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using MongoDB.Bson; using MongoDB.Bson.Serialization; -using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver; using NodaTime; using Squidex.Domain.Apps.Entities.Rules.Repositories; +using Squidex.Infrastructure; using Squidex.Infrastructure.MongoDb; namespace Squidex.Domain.Apps.Entities.MongoDb.Rules @@ -23,15 +21,10 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules { static MongoRuleStatisticsCollection() { - var guidSerializer = new GuidSerializer().WithRepresentation(BsonType.String); - BsonClassMap.RegisterClassMap(cm => { cm.AutoMap(); - cm.MapProperty(x => x.AppId).SetSerializer(guidSerializer); - cm.MapProperty(x => x.RuleId).SetSerializer(guidSerializer); - cm.SetIgnoreExtraElements(true); }); } @@ -56,14 +49,14 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules cancellationToken: ct); } - public async Task> QueryByAppAsync(Guid appId) + public async Task> QueryByAppAsync(DomainId appId) { var statistics = await Collection.Find(x => x.AppId == appId).ToListAsync(); return statistics; } - public Task IncrementSuccess(Guid appId, Guid ruleId, Instant now) + public Task IncrementSuccess(DomainId appId, DomainId ruleId, Instant now) { return Collection.UpdateOneAsync( x => x.AppId == appId && x.RuleId == ruleId, @@ -75,7 +68,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules Upsert); } - public Task IncrementFailed(Guid appId, Guid ruleId, Instant now) + public Task IncrementFailed(DomainId appId, DomainId ruleId, Instant now) { return Collection.UpdateOneAsync( x => x.AppId == appId && x.RuleId == ruleId, diff --git a/backend/src/Squidex.Domain.Apps.Entities/AppProvider.cs b/backend/src/Squidex.Domain.Apps.Entities/AppProvider.cs index e28a49e90..462d210ee 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/AppProvider.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/AppProvider.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Apps; @@ -40,7 +39,7 @@ namespace Squidex.Domain.Apps.Entities this.indexSchemas = indexSchemas; } - public Task<(IAppEntity?, ISchemaEntity?)> GetAppWithSchemaAsync(Guid appId, Guid id) + public Task<(IAppEntity?, ISchemaEntity?)> GetAppWithSchemaAsync(DomainId appId, DomainId id) { return localCache.GetOrCreateAsync($"GetAppWithSchemaAsync({appId}, {id})", async () => { @@ -48,7 +47,7 @@ namespace Squidex.Domain.Apps.Entities }); } - private async Task<(IAppEntity?, ISchemaEntity?)> GetAppWithSchemaUncachedAsync(Guid appId, Guid id) + private async Task<(IAppEntity?, ISchemaEntity?)> GetAppWithSchemaUncachedAsync(DomainId appId, DomainId id) { var app = await GetAppAsync(appId); @@ -67,7 +66,7 @@ namespace Squidex.Domain.Apps.Entities return (app, schema); } - public Task GetAppAsync(Guid appId) + public Task GetAppAsync(DomainId appId) { return localCache.GetOrCreateAsync($"GetAppAsync({appId})", async () => { @@ -91,7 +90,7 @@ namespace Squidex.Domain.Apps.Entities }); } - public Task GetSchemaAsync(Guid appId, string name) + public Task GetSchemaAsync(DomainId appId, string name) { return localCache.GetOrCreateAsync($"GetSchemaAsync({appId}, {name})", async () => { @@ -99,7 +98,7 @@ namespace Squidex.Domain.Apps.Entities }); } - public Task GetSchemaAsync(Guid appId, Guid id, bool allowDeleted = false) + public Task GetSchemaAsync(DomainId appId, DomainId id, bool allowDeleted = false) { return localCache.GetOrCreateAsync($"GetSchemaAsync({appId}, {id}, {allowDeleted})", async () => { @@ -107,7 +106,7 @@ namespace Squidex.Domain.Apps.Entities }); } - public Task> GetSchemasAsync(Guid appId) + public Task> GetSchemasAsync(DomainId appId) { return localCache.GetOrCreateAsync($"GetSchemasAsync({appId})", async () => { @@ -115,7 +114,7 @@ namespace Squidex.Domain.Apps.Entities }); } - public Task> GetRulesAsync(Guid appId) + public Task> GetRulesAsync(DomainId appId) { return localCache.GetOrCreateAsync($"GetRulesAsync({appId})", async () => { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppCommandMiddleware.cs index 1a0f8c866..0fc8948b2 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppCommandMiddleware.cs @@ -70,7 +70,7 @@ namespace Squidex.Domain.Apps.Entities.Apps using (var uploadStream = file.OpenRead()) { - await appImageStore.UploadAsync(uploadImage.AppId, uploadStream); + await appImageStore.UploadAsync(uploadImage.AppId.Id, uploadStream); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppDomainObject.cs index 0da6580e0..0ac932f09 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppDomainObject.cs @@ -34,7 +34,7 @@ namespace Squidex.Domain.Apps.Entities.Apps public AppDomainObject( InitialPatterns initialPatterns, - IStore store, + IStore store, ISemanticLog log, IAppPlansProvider appPlansProvider, IAppPlanBillingManager appPlansBillingManager, @@ -52,10 +52,24 @@ namespace Squidex.Domain.Apps.Entities.Apps this.initialPatterns = initialPatterns; } - public override Task ExecuteAsync(IAggregateCommand command) + protected override bool IsDeleted() { - VerifyNotArchived(); + return Snapshot.IsArchived; + } + + protected override bool CanAcceptCreation(ICommand command) + { + return command is CreateApp; + } + protected override bool CanAccept(ICommand command) + { + return command is AppUpdateCommand update && + Equals(update?.AppId?.Id, Snapshot.Id); + } + + public override Task ExecuteAsync(IAggregateCommand command) + { switch (command) { case CreateApp createApp: @@ -466,20 +480,9 @@ namespace Squidex.Domain.Apps.Entities.Apps RaiseEvent(SimpleMapper.Map(command, new AppArchived())); } - private void VerifyNotArchived() - { - if (Snapshot.IsArchived) - { - throw new DomainException("App has already been archived."); - } - } - private void RaiseEvent(AppEvent @event) { - if (@event.AppId == null) - { - @event.AppId = NamedId.Of(Snapshot.Id, Snapshot.Name); - } + @event.AppId ??= Snapshot.NamedId(); RaiseEvent(Envelope.Create(@event)); } @@ -489,7 +492,7 @@ namespace Squidex.Domain.Apps.Entities.Apps return new AppCreated { Name = name }; } - private static AppPatternAdded CreateInitialPattern(Guid id, AppPattern pattern) + private static AppPatternAdded CreateInitialPattern(DomainId id, AppPattern pattern) { return new AppPatternAdded { PatternId = id, Name = pattern.Name, Pattern = pattern.Pattern, Message = pattern.Message }; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppExtensions.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppExtensions.cs index 8f94a80cf..3793f186b 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppExtensions.cs @@ -5,16 +5,15 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps { public static class AppExtensions { - public static NamedId NamedId(this IAppEntity app) + public static NamedId NamedId(this IAppEntity app) { - return new NamedId(app.Id, app.Name); + return new NamedId(app.Id, app.Name); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs index ed1487a9b..9b56e49ef 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.History; using Squidex.Domain.Apps.Events.Apps; @@ -133,7 +132,7 @@ namespace Squidex.Domain.Apps.Entities.Apps return ForEvent(e, "settings.roles").Param("Name", name); } - private HistoryEvent CreatePatternsEvent(IEvent e, Guid id, string? name = null) + private HistoryEvent CreatePatternsEvent(IEvent e, DomainId id, string? name = null) { return ForEvent(e, "settings.patterns").Param("PatternId", id).Param("Name", name); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppSettingsSearchSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppSettingsSearchSource.cs index 46a66ccd3..6631974ff 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppSettingsSearchSource.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppSettingsSearchSource.cs @@ -32,7 +32,7 @@ namespace Squidex.Domain.Apps.Entities.Apps var appId = context.App.NamedId(); - void Search(string term, string permissionId, Func, string> generate, SearchResultType type) + void Search(string term, string permissionId, Func, string> generate, SearchResultType type) { if (result.Count < MaxItems && term.Contains(query, StringComparison.OrdinalIgnoreCase)) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettings.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettings.cs index 55eaea02a..4fbfbbcc7 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettings.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettings.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Orleans; using Squidex.Infrastructure; @@ -25,34 +24,34 @@ namespace Squidex.Domain.Apps.Entities.Apps this.grainFactory = grainFactory; } - public async Task GetAsync(Guid appId, string? userId) + public async Task GetAsync(DomainId appId, string? userId) { var result = await GetGrain(appId, userId).GetAsync(); return result.Value; } - public Task RemoveAsync(Guid appId, string? userId, string path) + public Task RemoveAsync(DomainId appId, string? userId, string path) { return GetGrain(appId, userId).RemoveAsync(path); } - public Task SetAsync(Guid appId, string? userId, string path, IJsonValue value) + public Task SetAsync(DomainId appId, string? userId, string path, IJsonValue value) { return GetGrain(appId, userId).SetAsync(path, value.AsJ()); } - public Task SetAsync(Guid appId, string? userId, JsonObject settings) + public Task SetAsync(DomainId appId, string? userId, JsonObject settings) { return GetGrain(appId, userId).SetAsync(settings.AsJ()); } - private IAppUISettingsGrain GetGrain(Guid appId, string? userId) + private IAppUISettingsGrain GetGrain(DomainId appId, string? userId) { return grainFactory.GetGrain(GetKey(appId, userId)); } - private static string GetKey(Guid appId, string? userId) + private static string GetKey(DomainId appId, string? userId) { if (!string.IsNullOrWhiteSpace(userId)) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/BackupApps.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/BackupApps.cs index 42d0ef196..a3a97b5eb 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/BackupApps.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/BackupApps.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; @@ -115,7 +114,7 @@ namespace Squidex.Domain.Apps.Entities.Apps await appUISettings.SetAsync(context.AppId, null, json); } - private async Task ReserveAppAsync(Guid appId, string appName) + private async Task ReserveAppAsync(DomainId appId, string appName) { appReservation = await appsIndex.ReserveAsync(appId, appName); @@ -125,7 +124,7 @@ namespace Squidex.Domain.Apps.Entities.Apps } } - public async Task CleanupRestoreErrorAsync(Guid appId) + public async Task CleanupRestoreErrorAsync(DomainId appId) { if (appReservation != null) { @@ -140,7 +139,7 @@ namespace Squidex.Domain.Apps.Entities.Apps await appsIndex.RebuildByContributorsAsync(context.AppId, contributors); } - private Task WriteAssetAsync(Guid appId, IBackupWriter writer) + private Task WriteAssetAsync(DomainId appId, IBackupWriter writer) { return writer.WriteBlobAsync(AvatarFile, async stream => { @@ -154,7 +153,7 @@ namespace Squidex.Domain.Apps.Entities.Apps }); } - private async Task ReadAssetAsync(Guid appId, IBackupReader reader) + private async Task ReadAssetAsync(DomainId appId, IBackupReader reader) { try { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddLanguage.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddLanguage.cs index 3cfec0965..ee4225797 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddLanguage.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddLanguage.cs @@ -9,7 +9,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class AddLanguage : AppCommand + public sealed class AddLanguage : AppUpdateCommand { public Language Language { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddPattern.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddPattern.cs index 9f74f6291..18ac2d6f9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddPattern.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddPattern.cs @@ -5,13 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class AddPattern : AppCommand + public sealed class AddPattern : AppUpdateCommand { - public Guid PatternId { get; set; } + public DomainId PatternId { get; set; } public string Name { get; set; } @@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Commands public AddPattern() { - PatternId = Guid.NewGuid(); + PatternId = DomainId.NewGuid(); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddRole.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddRole.cs index c1623759f..a536c7067 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddRole.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddRole.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class AddRole : AppCommand + public sealed class AddRole : AppUpdateCommand { public string Name { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddWorkflow.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddWorkflow.cs index 54ca7b4bb..a96c76829 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddWorkflow.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AddWorkflow.cs @@ -5,19 +5,19 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class AddWorkflow : AppCommand + public sealed class AddWorkflow : AppUpdateCommand { - public Guid WorkflowId { get; set; } + public DomainId WorkflowId { get; set; } public string Name { get; set; } public AddWorkflow() { - WorkflowId = Guid.NewGuid(); + WorkflowId = DomainId.NewGuid(); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AppCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AppCommand.cs index a391da077..09d401854 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AppCommand.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AppCommand.cs @@ -1,22 +1,17 @@ // ========================================================================== // Squidex Headless CMS // ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) +// Copyright (c) Squidex UG (haftungsbeschraenkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; namespace Squidex.Domain.Apps.Entities.Apps.Commands { public abstract class AppCommand : SquidexCommand, IAggregateCommand { - public Guid AppId { get; set; } - - Guid IAggregateCommand.AggregateId - { - get { return AppId; } - } + public abstract DomainId AggregateId { get; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AppUpdateCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AppUpdateCommand.cs new file mode 100644 index 000000000..24b0a6b32 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AppUpdateCommand.cs @@ -0,0 +1,21 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Entities.Apps.Commands +{ + public abstract class AppUpdateCommand : AppCommand, IAppCommand + { + public NamedId AppId { get; set; } + + public override DomainId AggregateId + { + get { return AppId.Id; } + } + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/ArchiveApp.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/ArchiveApp.cs index aeb898751..c4999db95 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/ArchiveApp.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/ArchiveApp.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class ArchiveApp : AppCommand + public sealed class ArchiveApp : AppUpdateCommand { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AssignContributor.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AssignContributor.cs index 6e1276744..a5e018901 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AssignContributor.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AssignContributor.cs @@ -9,7 +9,7 @@ using Roles = Squidex.Domain.Apps.Core.Apps.Role; namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class AssignContributor : AppCommand + public sealed class AssignContributor : AppUpdateCommand { public string ContributorId { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AttachClient.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AttachClient.cs index 0fd8c6c4d..eca13317a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AttachClient.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/AttachClient.cs @@ -9,7 +9,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class AttachClient : AppCommand + public sealed class AttachClient : AppUpdateCommand { public string Id { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/ChangePlan.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/ChangePlan.cs index a323b8b10..380d1c406 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/ChangePlan.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/ChangePlan.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class ChangePlan : AppCommand + public sealed class ChangePlan : AppUpdateCommand { public bool FromCallback { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/CreateApp.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/CreateApp.cs index 89a491519..0e6a404ad 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/CreateApp.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/CreateApp.cs @@ -5,19 +5,27 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; +using Squidex.Infrastructure.Commands; namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class CreateApp : AppCommand + public sealed class CreateApp : AppCommand, IAggregateCommand { + public DomainId AppId { get; set; } + public string Name { get; set; } public string? Template { get; set; } + public override DomainId AggregateId + { + get { return AppId; } + } + public CreateApp() { - AppId = Guid.NewGuid(); + AppId = DomainId.NewGuid(); } } } \ No newline at end of file diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/DeletePattern.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/DeletePattern.cs index 199bff83c..bd778377c 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/DeletePattern.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/DeletePattern.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class DeletePattern : AppCommand + public sealed class DeletePattern : AppUpdateCommand { - public Guid PatternId { get; set; } + public DomainId PatternId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/DeleteRole.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/DeleteRole.cs index d18e03892..0ae4cf648 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/DeleteRole.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/DeleteRole.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class DeleteRole : AppCommand + public sealed class DeleteRole : AppUpdateCommand { public string Name { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/DeleteWorkflow.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/DeleteWorkflow.cs index c21492e79..33a29e8c3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/DeleteWorkflow.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/DeleteWorkflow.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class DeleteWorkflow : AppCommand + public sealed class DeleteWorkflow : AppUpdateCommand { - public Guid WorkflowId { get; set; } + public DomainId WorkflowId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RemoveAppImage.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RemoveAppImage.cs index c88fa5c56..be603b50f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RemoveAppImage.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RemoveAppImage.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class RemoveAppImage : AppCommand + public sealed class RemoveAppImage : AppUpdateCommand { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RemoveContributor.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RemoveContributor.cs index a4e27d426..7e2d8323e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RemoveContributor.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RemoveContributor.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class RemoveContributor : AppCommand + public sealed class RemoveContributor : AppUpdateCommand { public string ContributorId { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RemoveLanguage.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RemoveLanguage.cs index 602c35756..919a31e67 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RemoveLanguage.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RemoveLanguage.cs @@ -9,7 +9,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class RemoveLanguage : AppCommand + public sealed class RemoveLanguage : AppUpdateCommand { public Language Language { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RevokeClient.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RevokeClient.cs index 9361891ba..f563075ab 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RevokeClient.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/RevokeClient.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class RevokeClient : AppCommand + public sealed class RevokeClient : AppUpdateCommand { public string Id { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateApp.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateApp.cs index f47952812..605decdd5 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateApp.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateApp.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class UpdateApp : AppCommand + public sealed class UpdateApp : AppUpdateCommand { public string? Label { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateClient.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateClient.cs index 854242be3..de2317a39 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateClient.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateClient.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class UpdateClient : AppCommand + public sealed class UpdateClient : AppUpdateCommand { public string Id { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateLanguage.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateLanguage.cs index 07ee21cde..5fcbe66cd 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateLanguage.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateLanguage.cs @@ -10,7 +10,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class UpdateLanguage : AppCommand + public sealed class UpdateLanguage : AppUpdateCommand { public Language Language { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdatePattern.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdatePattern.cs index 0f28418f9..2be0fbc2d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdatePattern.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdatePattern.cs @@ -5,13 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class UpdatePattern : AppCommand + public sealed class UpdatePattern : AppUpdateCommand { - public Guid PatternId { get; set; } + public DomainId PatternId { get; set; } public string Name { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateRole.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateRole.cs index 3d7c648f7..cdf054568 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateRole.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateRole.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class UpdateRole : AppCommand + public sealed class UpdateRole : AppUpdateCommand { public string Name { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateWorkflow.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateWorkflow.cs index 635936040..16755127d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateWorkflow.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateWorkflow.cs @@ -5,14 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class UpdateWorkflow : AppCommand + public sealed class UpdateWorkflow : AppUpdateCommand { - public Guid WorkflowId { get; set; } + public DomainId WorkflowId { get; set; } public Workflow Workflow { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UploadAppImage.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UploadAppImage.cs index 375cad39f..f45af9142 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UploadAppImage.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UploadAppImage.cs @@ -9,7 +9,7 @@ using Squidex.Infrastructure.Assets; namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public sealed class UploadAppImage : AppCommand + public sealed class UploadAppImage : AppUpdateCommand { public AssetFile File { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppImageStore.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppImageStore.cs index 55b09e076..af89efc16 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppImageStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppImageStore.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -25,23 +24,23 @@ namespace Squidex.Domain.Apps.Entities.Apps this.assetStore = assetStore; } - public Task DownloadAsync(Guid backupId, Stream stream, CancellationToken ct = default) + public Task DownloadAsync(DomainId appId, Stream stream, CancellationToken ct = default) { - var fileName = GetFileName(backupId); + var fileName = GetFileName(appId); return assetStore.DownloadAsync(fileName, stream, default, ct); } - public Task UploadAsync(Guid backupId, Stream stream, CancellationToken ct = default) + public Task UploadAsync(DomainId appId, Stream stream, CancellationToken ct = default) { - var fileName = GetFileName(backupId); + var fileName = GetFileName(appId); return assetStore.UploadAsync(fileName, stream, true, ct); } - private static string GetFileName(Guid backupId) + private static string GetFileName(DomainId appId) { - return backupId.ToString(); + return appId.ToString(); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppLogStore.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppLogStore.cs index c70a3d40b..a66534b9a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppLogStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppLogStore.cs @@ -39,7 +39,7 @@ namespace Squidex.Domain.Apps.Entities.Apps this.requestLogStore = requestLogStore; } - public Task LogAsync(Guid appId, Instant timestamp, string? requestMethod, string? requestPath, string? userId, string? clientId, long elapsedMs, double costs) + public Task LogAsync(DomainId appId, Instant timestamp, string? requestMethod, string? requestPath, string? userId, string? clientId, long elapsedMs, double costs) { var request = new Request { @@ -61,7 +61,7 @@ namespace Squidex.Domain.Apps.Entities.Apps return requestLogStore.LogAsync(request); } - public async Task ReadLogAsync(Guid appId, DateTime fromDate, DateTime toDate, Stream stream, CancellationToken ct = default) + public async Task ReadLogAsync(DomainId appId, DateTime fromDate, DateTime toDate, Stream stream, CancellationToken ct = default) { Guard.NotNull(appId, nameof(appId)); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppContributors.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppContributors.cs index f6cb10e23..9d35bbc21 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppContributors.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppContributors.cs @@ -50,7 +50,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards throw new DomainForbiddenException("You cannot change your own role."); } - if (!contributors.TryGetValue(command.ContributorId, out var role)) + if (!contributors.TryGetValue(command.ContributorId, out _)) { if (plan != null && plan.MaxContributors > 0 && contributors.Count >= plan.MaxContributors) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppPatterns.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppPatterns.cs index d5c0437d9..fbdf2755b 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppPatterns.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppPatterns.cs @@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards Validate.It(() => "Cannot add pattern.", e => { - if (command.PatternId == Guid.Empty) + if (command.PatternId == DomainId.Empty) { e(Not.Defined("Id"), nameof(command.PatternId)); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppWorkflows.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppWorkflows.cs index bbff8ca5d..143994338 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppWorkflows.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppWorkflows.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Infrastructure; @@ -97,7 +96,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards CheckWorkflowExists(workflows, command.WorkflowId); } - private static void CheckWorkflowExists(Workflows workflows, Guid id) + private static void CheckWorkflowExists(Workflows workflows, DomainId id) { if (!workflows.ContainsKey(id)) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppImageStore.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppImageStore.cs index e1d0e31d7..689d8c963 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppImageStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppImageStore.cs @@ -5,17 +5,17 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.IO; using System.Threading; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps { public interface IAppImageStore { - Task UploadAsync(Guid appId, Stream stream, CancellationToken ct = default); + Task UploadAsync(DomainId appId, Stream stream, CancellationToken ct = default); - Task DownloadAsync(Guid appId, Stream stream, CancellationToken ct = default); + Task DownloadAsync(DomainId appId, Stream stream, CancellationToken ct = default); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppLogStore.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppLogStore.cs index 1088ff0de..7e56e128b 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppLogStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppLogStore.cs @@ -10,13 +10,14 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using NodaTime; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps { public interface IAppLogStore { - Task LogAsync(Guid appId, Instant timestamp, string? requestMethod, string? requestPath, string? userId, string? clientId, long elapsedMs, double costs); + Task LogAsync(DomainId appId, Instant timestamp, string? requestMethod, string? requestPath, string? userId, string? clientId, long elapsedMs, double costs); - Task ReadLogAsync(Guid appId, DateTime fromDate, DateTime toDate, Stream stream, CancellationToken ct = default); + Task ReadLogAsync(DomainId appId, DateTime fromDate, DateTime toDate, Stream stream, CancellationToken ct = default); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettings.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettings.cs index b6a46d78f..4172a1403 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettings.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettings.cs @@ -5,20 +5,20 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; +using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Entities.Apps { public interface IAppUISettings { - Task GetAsync(Guid appId, string? userId); + Task GetAsync(DomainId appId, string? userId); - Task SetAsync(Guid appId, string? userId, string path, IJsonValue value); + Task SetAsync(DomainId appId, string? userId, string path, IJsonValue value); - Task SetAsync(Guid appId, string? userId, JsonObject settings); + Task SetAsync(DomainId appId, string? userId, JsonObject settings); - Task RemoveAsync(Guid appId, string? userId, string path); + Task RemoveAsync(DomainId appId, string? userId, string path); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByNameIndexGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByNameIndexGrain.cs index 0a0d78e82..11200a848 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByNameIndexGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByNameIndexGrain.cs @@ -5,14 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Orleans.Indexes; using Squidex.Infrastructure.States; namespace Squidex.Domain.Apps.Entities.Apps.Indexes { - public sealed class AppsByNameIndexGrain : UniqueNameIndexGrain, IAppsByNameIndexGrain + public sealed class AppsByNameIndexGrain : UniqueNameIndexGrain, IAppsByNameIndexGrain { public AppsByNameIndexGrain(IGrainState state) : base(state) @@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes } [CollectionName("Index_AppsByName")] - public sealed class AppsByNameIndexState : UniqueNameIndexState + public sealed class AppsByNameIndexState : UniqueNameIndexState { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByUserIndexGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByUserIndexGrain.cs index acd31e195..4214a73f9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByUserIndexGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByUserIndexGrain.cs @@ -5,14 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Orleans.Indexes; using Squidex.Infrastructure.States; namespace Squidex.Domain.Apps.Entities.Apps.Indexes { - public sealed class AppsByUserIndexGrain : IdsIndexGrain, IAppsByUserIndexGrain + public sealed class AppsByUserIndexGrain : IdsIndexGrain, IAppsByUserIndexGrain { public AppsByUserIndexGrain(IGrainState state) : base(state) @@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes } [CollectionName("Index_AppsByUser")] - public sealed class AppsByUserIndex : IdsIndexState + public sealed class AppsByUserIndex : IdsIndexState { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsIndex.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsIndex.cs index abfac7046..cd6b04992 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsIndex.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsIndex.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -32,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes this.grainFactory = grainFactory; } - public async Task RebuildByContributorsAsync(Guid appId, HashSet contributors) + public async Task RebuildByContributorsAsync(DomainId appId, HashSet contributors) { foreach (var contributorId in contributors) { @@ -40,12 +39,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes } } - public Task RebuildByContributorsAsync(string contributorId, HashSet apps) + public Task RebuildByContributorsAsync(string contributorId, HashSet apps) { return Index(contributorId).RebuildAsync(apps); } - public Task RebuildAsync(Dictionary appsByName) + public Task RebuildAsync(Dictionary appsByName) { return Index().RebuildAsync(appsByName); } @@ -55,7 +54,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes return Index().RemoveReservationAsync(token); } - public Task> GetIdsAsync() + public Task> GetIdsAsync() { return Index().GetIdsAsync(); } @@ -65,7 +64,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes return Index().AddAsync(token); } - public Task ReserveAsync(Guid id, string name) + public Task ReserveAsync(DomainId id, string name) { return Index().ReserveAsync(id, name); } @@ -108,7 +107,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes { var appId = await GetAppIdAsync(name); - if (appId == default) + if (appId == DomainId.Empty) { return null; } @@ -117,11 +116,11 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes } } - public async Task GetAppAsync(Guid appId) + public async Task GetAppAsync(DomainId appId) { using (Profiler.TraceMethod()) { - var app = await grainFactory.GetGrain(appId).GetStateAsync(); + var app = await grainFactory.GetGrain(appId.ToString()).GetStateAsync(); if (IsFound(app.Value, false)) { @@ -132,7 +131,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes } } - private async Task> GetAppIdsByUserAsync(string userId) + private async Task> GetAppIdsByUserAsync(string userId) { using (Profiler.TraceMethod()) { @@ -140,7 +139,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes } } - private async Task> GetAppIdsAsync() + private async Task> GetAppIdsAsync() { using (Profiler.TraceMethod()) { @@ -148,7 +147,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes } } - private async Task> GetAppIdsAsync(string[] names) + private async Task> GetAppIdsAsync(string[] names) { using (Profiler.TraceMethod()) { @@ -156,7 +155,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes } } - private async Task GetAppIdAsync(string name) + private async Task GetAppIdAsync(string name) { using (Profiler.TraceMethod()) { @@ -184,7 +183,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes { await index.AddAsync(token); - await Index(createApp.Actor.Identifier).AddAsync(createApp.AppId); + await Index(createApp.Actor.Identifier).AddAsync(createApp.AppId.ToString()); } else { @@ -223,7 +222,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes if (name.IsSlug()) { - var token = await index.ReserveAsync(command.AppId, name); + var token = await index.ReserveAsync(command.AppId.ToString(), name); if (token == null) { @@ -240,28 +239,28 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes private Task AssignContributorAsync(AssignContributor command) { - return Index(command.ContributorId).AddAsync(command.AppId); + return Index(command.ContributorId).AddAsync(command.AppId.Id); } private Task RemoveContributorAsync(RemoveContributor command) { - return Index(command.ContributorId).RemoveAsync(command.AppId); + return Index(command.ContributorId).RemoveAsync(command.AppId.Id); } private async Task ArchiveAppAsync(ArchiveApp command) { var appId = command.AppId; - var app = await grainFactory.GetGrain(appId).GetStateAsync(); + var app = await grainFactory.GetGrain(appId.Id.ToString()).GetStateAsync(); if (IsFound(app.Value, true)) { - await Index().RemoveAsync(appId); + await Index().RemoveAsync(appId.Id); } foreach (var contributorId in app.Value.Contributors.Keys) { - await Index(contributorId).RemoveAsync(appId); + await Index(contributorId).RemoveAsync(appId.Id); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/IAppsByNameIndexGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/IAppsByNameIndexGrain.cs index 13566260a..09154d325 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/IAppsByNameIndexGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/IAppsByNameIndexGrain.cs @@ -5,13 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Orleans; +using Squidex.Infrastructure; using Squidex.Infrastructure.Orleans.Indexes; namespace Squidex.Domain.Apps.Entities.Apps.Indexes { - public interface IAppsByNameIndexGrain : IUniqueNameIndexGrain, IGrainWithStringKey + public interface IAppsByNameIndexGrain : IUniqueNameIndexGrain, IGrainWithStringKey { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/IAppsByUserIndexGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/IAppsByUserIndexGrain.cs index 6a19ccd43..077679645 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/IAppsByUserIndexGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/IAppsByUserIndexGrain.cs @@ -5,13 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Orleans; +using Squidex.Infrastructure; using Squidex.Infrastructure.Orleans.Indexes; namespace Squidex.Domain.Apps.Entities.Apps.Indexes { - public interface IAppsByUserIndexGrain : IIdsIndexGrain, IGrainWithStringKey + public interface IAppsByUserIndexGrain : IIdsIndexGrain, IGrainWithStringKey { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/IAppsIndex.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/IAppsIndex.cs index 383c349d3..a881f0eff 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/IAppsIndex.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/IAppsIndex.cs @@ -5,16 +5,16 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; +using Squidex.Infrastructure; using Squidex.Infrastructure.Security; namespace Squidex.Domain.Apps.Entities.Apps.Indexes { public interface IAppsIndex { - Task> GetIdsAsync(); + Task> GetIdsAsync(); Task> GetAppsAsync(); @@ -22,18 +22,18 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes Task GetAppByNameAsync(string name); - Task GetAppAsync(Guid appId); + Task GetAppAsync(DomainId appId); - Task ReserveAsync(Guid id, string name); + Task ReserveAsync(DomainId id, string name); Task AddAsync(string? token); Task RemoveReservationAsync(string? token); - Task RebuildByContributorsAsync(string contributorId, HashSet apps); + Task RebuildByContributorsAsync(string contributorId, HashSet apps); - Task RebuildAsync(Dictionary apps); + Task RebuildAsync(Dictionary apps); - Task RebuildByContributorsAsync(Guid appId, HashSet contributors); + Task RebuildByContributorsAsync(DomainId appId, HashSet contributors); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/InitialPatterns.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/InitialPatterns.cs index d8da459ed..f839c26ea 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/InitialPatterns.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/InitialPatterns.cs @@ -5,19 +5,19 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Squidex.Domain.Apps.Core.Apps; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps { - public sealed class InitialPatterns : Dictionary + public sealed class InitialPatterns : Dictionary { public InitialPatterns() { } - public InitialPatterns(Dictionary patterns) + public InitialPatterns(Dictionary patterns) : base(patterns) { } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/IAppPlanBillingManager.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/IAppPlanBillingManager.cs index e2ceb6832..672e2d621 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/IAppPlanBillingManager.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/IAppPlanBillingManager.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Squidex.Infrastructure; @@ -15,7 +14,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans { bool HasPortal { get; } - Task ChangePlanAsync(string userId, NamedId appId, string? planId); + Task ChangePlanAsync(string userId, NamedId appId, string? planId); Task GetPortalLinkAsync(string userId); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/NoopAppPlanBillingManager.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/NoopAppPlanBillingManager.cs index 64697e998..d43aa71a2 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/NoopAppPlanBillingManager.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/NoopAppPlanBillingManager.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Squidex.Infrastructure; @@ -18,7 +17,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans get { return false; } } - public Task ChangePlanAsync(string userId, NamedId appId, string? planId) + public Task ChangePlanAsync(string userId, NamedId appId, string? planId) { return Task.FromResult(new PlanChangedResult()); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/UsageGate.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/UsageGate.cs index 3418bf0f6..0fe56b3fe 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/UsageGate.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/UsageGate.cs @@ -76,17 +76,17 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans return isLocked; } - private bool HasNotifiedBefore(Guid appId) + private bool HasNotifiedBefore(DomainId appId) { return memoryCache.Get(appId); } - private bool TrackNotified(Guid appId) + private bool TrackNotified(DomainId appId) { return memoryCache.Set(appId, true, TimeSpan.FromHours(1)); } - private bool IsAboutToBeLocked(DateTime today, long limit, long usage) + private static bool IsAboutToBeLocked(DateTime today, long limit, long usage) { var daysInMonth = DateTime.DaysInMonth(today.Year, today.Month); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/UsageNotification.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/UsageNotification.cs index 5aff26d9f..ad0c27fac 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/UsageNotification.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/UsageNotification.cs @@ -5,13 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps.Plans { public sealed class UsageNotification { - public Guid AppId { get; set; } + public DomainId AppId { get; set; } public string AppName { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/UsageNotifierGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/UsageNotifierGrain.cs index 5204512d6..45c455d11 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/UsageNotifierGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/UsageNotifierGrain.cs @@ -27,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans [CollectionName("UsageNotifications")] public sealed class State { - public Dictionary NotificationsSent { get; } = new Dictionary(); + public Dictionary NotificationsSent { get; } = new Dictionary(); } public UsageNotifierGrain(IGrainState state, INotificationSender notificationSender, IUserResolver userResolver) @@ -67,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans } } - private bool HasBeenSentBefore(Guid appId, DateTime now) + private bool HasBeenSentBefore(DomainId appId, DateTime now) { if (state.Value.NotificationsSent.TryGetValue(appId, out var lastSent)) { @@ -79,7 +79,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans return false; } - private Task TrackNotifiedAsync(Guid appId, DateTime now) + private Task TrackNotifiedAsync(DomainId appId, DateTime now) { state.Value.NotificationsSent[appId] = now; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs index 742608a9b..1fef2e09c 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs @@ -9,6 +9,7 @@ using System; using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Events.Apps; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.Reflection; @@ -45,12 +46,19 @@ namespace Squidex.Domain.Apps.Entities.Apps.State public bool IsArchived { get; set; } + public DomainId UniqueId + { + get { return Id; } + } + public override bool ApplyEvent(IEvent @event) { switch (@event) { case AppCreated e: { + Id = e.AppId.Id; + SimpleMapper.Map(e, this); return true; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/AlwaysCreateClientCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/AlwaysCreateClientCommandMiddleware.cs index de9fad661..3da911147 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/AlwaysCreateClientCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/AlwaysCreateClientCommandMiddleware.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Apps.Commands; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Tasks; @@ -18,7 +19,9 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates { if (context.IsCompleted && context.Command is CreateApp createApp) { - var command = new AttachClient { Id = "default", AppId = createApp.AppId }; + var appId = NamedId.Of(createApp.AppId, createApp.Name); + + var command = new AttachClient { Id = "default", AppId = appId }; context.CommandBus.PublishAsync(command).Forget(); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/AssetFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/AssetFieldBuilder.cs index 1e0b1f582..2bc0b441f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/AssetFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/AssetFieldBuilder.cs @@ -12,7 +12,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { public class AssetFieldBuilder : FieldBuilder { - public AssetFieldBuilder(UpsertSchemaField field, UpsertCommand schema) + public AssetFieldBuilder(UpsertSchemaField field, CreateSchema schema) : base(field, schema) { } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/BooleanFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/BooleanFieldBuilder.cs index a6ee63839..86ca35c61 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/BooleanFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/BooleanFieldBuilder.cs @@ -12,7 +12,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { public class BooleanFieldBuilder : FieldBuilder { - public BooleanFieldBuilder(UpsertSchemaField field, UpsertCommand schema) + public BooleanFieldBuilder(UpsertSchemaField field, CreateSchema schema) : base(field, schema) { } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/DateTimeFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/DateTimeFieldBuilder.cs index de18458f2..ad2dbaf4c 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/DateTimeFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/DateTimeFieldBuilder.cs @@ -12,7 +12,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { public class DateTimeFieldBuilder : FieldBuilder { - public DateTimeFieldBuilder(UpsertSchemaField field, UpsertCommand schema) + public DateTimeFieldBuilder(UpsertSchemaField field, CreateSchema schema) : base(field, schema) { } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/FieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/FieldBuilder.cs index 8521e6ce1..209f3b5cc 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/FieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/FieldBuilder.cs @@ -14,14 +14,14 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders public abstract class FieldBuilder { private readonly UpsertSchemaField field; - private readonly UpsertCommand schema; + private readonly CreateSchema schema; protected T Properties() where T : FieldProperties { return (T)field.Properties; } - protected FieldBuilder(UpsertSchemaField field, UpsertCommand schema) + protected FieldBuilder(UpsertSchemaField field, CreateSchema schema) { this.field = field; this.schema = schema; @@ -64,11 +64,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders public FieldBuilder ShowInList() { - if (schema.FieldsInReferences == null) - { - schema.FieldsInReferences = new FieldNames(); - } - + schema.FieldsInReferences ??= new FieldNames(); schema.FieldsInReferences.Add(field.Name); return this; @@ -76,11 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders public FieldBuilder ShowInReferences() { - if (schema.FieldsInLists == null) - { - schema.FieldsInLists = new FieldNames(); - } - + schema.FieldsInLists ??= new FieldNames(); schema.FieldsInLists.Add(field.Name); return this; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/JsonFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/JsonFieldBuilder.cs index 7a488d0a9..6c2ac8b88 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/JsonFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/JsonFieldBuilder.cs @@ -11,7 +11,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { public class JsonFieldBuilder : FieldBuilder { - public JsonFieldBuilder(UpsertSchemaField field, UpsertCommand schema) + public JsonFieldBuilder(UpsertSchemaField field, CreateSchema schema) : base(field, schema) { } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/NumberFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/NumberFieldBuilder.cs index 211a1807f..c09a5fa68 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/NumberFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/NumberFieldBuilder.cs @@ -11,7 +11,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { public class NumberFieldBuilder : FieldBuilder { - public NumberFieldBuilder(UpsertSchemaField field, UpsertCommand schema) + public NumberFieldBuilder(UpsertSchemaField field, CreateSchema schema) : base(field, schema) { } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/StringFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/StringFieldBuilder.cs index 703d96f46..4b8de8d1e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/StringFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/StringFieldBuilder.cs @@ -13,7 +13,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { public class StringFieldBuilder : FieldBuilder { - public StringFieldBuilder(UpsertSchemaField field, UpsertCommand schema) + public StringFieldBuilder(UpsertSchemaField field, CreateSchema schema) : base(field, schema) { } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/TagsFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/TagsFieldBuilder.cs index 67a34d62c..b9fa4a2d9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/TagsFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/TagsFieldBuilder.cs @@ -11,7 +11,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { public class TagsFieldBuilder : FieldBuilder { - public TagsFieldBuilder(UpsertSchemaField field, UpsertCommand schema) + public TagsFieldBuilder(UpsertSchemaField field, CreateSchema schema) : base(field, schema) { } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlogCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlogCommandMiddleware.cs index 94967d103..4ca53a7b6 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlogCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlogCommandMiddleware.cs @@ -87,7 +87,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates }); } - private static async Task> CreatePostsSchemaAsync(Func publish) + private static async Task> CreatePostsSchemaAsync(Func publish) { var schema = SchemaBuilder.Create("Posts") @@ -113,7 +113,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates return NamedId.Of(schema.SchemaId, schema.Name); } - private static async Task> CreatePagesSchemaAsync(Func publish) + private static async Task> CreatePagesSchemaAsync(Func publish) { var schema = SchemaBuilder.Create("Pages") diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateIdentityCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateIdentityCommandMiddleware.cs index 6bcbe0628..97d30a927 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateIdentityCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateIdentityCommandMiddleware.cs @@ -51,7 +51,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates return string.Equals(createApp.Template, TemplateName, StringComparison.OrdinalIgnoreCase); } - private static async Task> CreateAuthenticationSchemeSchemaAsync(Func publish) + private static async Task> CreateAuthenticationSchemeSchemaAsync(Func publish) { var schema = SchemaBuilder.Create("Authentication Schemes") diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfileCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfileCommandMiddleware.cs index aab99d41c..ea435007f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfileCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfileCommandMiddleware.cs @@ -70,11 +70,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates .AddValue("Doe")) .AddField("profession", new ContentFieldData() - .AddValue("Software Developer")) + .AddValue("Software Developer")), + SchemaId = postsId }); } - private static async Task> CreateBasicsSchemaAsync(Func publish) + private static async Task> CreateBasicsSchemaAsync(Func publish) { var command = SchemaBuilder.Create("Basics") @@ -117,7 +118,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates return NamedId.Of(command.SchemaId, command.Name); } - private static async Task> CreateProjectsSchemaAsync(Func publish) + private static async Task> CreateProjectsSchemaAsync(Func publish) { var schema = SchemaBuilder.Create("Projects") @@ -147,7 +148,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates return NamedId.Of(schema.SchemaId, schema.Name); } - private static async Task> CreateExperienceSchemaAsync(Func publish) + private static async Task> CreateExperienceSchemaAsync(Func publish) { var schema = SchemaBuilder.Create("Experience") @@ -174,7 +175,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates return NamedId.Of(schema.SchemaId, schema.Name); } - private static async Task> CreateEducationSchemaAsync(Func publish) + private static async Task> CreateEducationSchemaAsync(Func publish) { var schema = SchemaBuilder.Create("Education") @@ -201,7 +202,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates return NamedId.Of(schema.SchemaId, schema.Name); } - private static async Task> CreatePublicationsSchemaAsync(Func publish) + private static async Task> CreatePublicationsSchemaAsync(Func publish) { var command = SchemaBuilder.Create("Publications") @@ -223,7 +224,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates return NamedId.Of(command.SchemaId, command.Name); } - private static async Task> CreateSkillsSchemaAsync(Func publish) + private static async Task> CreateSkillsSchemaAsync(Func publish) { var command = SchemaBuilder.Create("Skills") diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetChangedTriggerHandler.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetChangedTriggerHandler.cs index 47efad3fc..9efdbbd8f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetChangedTriggerHandler.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetChangedTriggerHandler.cs @@ -41,7 +41,10 @@ namespace Squidex.Domain.Apps.Entities.Assets var result = new EnrichedAssetEvent(); - var asset = await assetLoader.GetAsync(@event.Payload.AssetId, @event.Headers.EventStreamNumber()); + var asset = await assetLoader.GetAsync( + @event.Payload.AppId.Id, + @event.Payload.AssetId, + @event.Headers.EventStreamNumber()); SimpleMapper.Map(asset, result); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs index 33bac4b6d..c790d2e16 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs @@ -115,7 +115,7 @@ namespace Squidex.Domain.Apps.Entities.Assets if (asset != null) { - await assetFileStore.CopyAsync(tempFile, command.AssetId, asset.FileVersion); + await assetFileStore.CopyAsync(tempFile, command.AppId.Id, command.AssetId, asset.FileVersion); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetDomainObject.cs index 146c59a7e..efb778565 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetDomainObject.cs @@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Assets private readonly ITagService tagService; private readonly IAssetQueryService assetQuery; - public AssetDomainObject(IStore store, ITagService tagService, IAssetQueryService assetQuery, ISemanticLog log) + public AssetDomainObject(IStore store, ITagService tagService, IAssetQueryService assetQuery, ISemanticLog log) : base(store, log) { Guard.NotNull(tagService, nameof(tagService)); @@ -39,10 +39,25 @@ namespace Squidex.Domain.Apps.Entities.Assets this.assetQuery = assetQuery; } - public override Task ExecuteAsync(IAggregateCommand command) + protected override bool IsDeleted() { - VerifyNotDeleted(); + return Snapshot.IsDeleted; + } + + protected override bool CanAcceptCreation(ICommand command) + { + return command is AssetCommand; + } + protected override bool CanAccept(ICommand command) + { + return command is AssetCommand assetCommand && + Equals(assetCommand.AppId, Snapshot.AppId) && + Equals(assetCommand.AssetId, Snapshot.Id); + } + + public override Task ExecuteAsync(IAggregateCommand command) + { switch (command) { case CreateAsset createAsset: @@ -99,7 +114,7 @@ namespace Squidex.Domain.Apps.Entities.Assets } } - private async Task?> NormalizeTagsAsync(Guid appId, HashSet tags) + private async Task?> NormalizeTagsAsync(DomainId appId, HashSet tags) { if (tags == null) { @@ -160,20 +175,9 @@ namespace Squidex.Domain.Apps.Entities.Assets private void RaiseEvent(AppEvent @event) { - if (@event.AppId == null) - { - @event.AppId = Snapshot.AppId; - } + @event.AppId ??= Snapshot.AppId; RaiseEvent(Envelope.Create(@event)); } - - private void VerifyNotDeleted() - { - if (Snapshot.IsDeleted) - { - throw new DomainException("Asset has already been deleted"); - } - } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetDomainObjectGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetDomainObjectGrain.cs index d23103330..bdbc4ab77 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetDomainObjectGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetDomainObjectGrain.cs @@ -24,7 +24,7 @@ namespace Squidex.Domain.Apps.Entities.Assets limit?.SetLimit(5000, Lifetime); } - protected override Task OnActivateAsync(Guid key) + protected override Task OnActivateAsync(string key) { TryDelayDeactivation(Lifetime); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetEntity.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetEntity.cs index fe2fe26c2..ae0061f15 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetEntity.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetEntity.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using NodaTime; using Squidex.Domain.Apps.Core.Assets; @@ -15,11 +14,11 @@ namespace Squidex.Domain.Apps.Entities.Assets { public sealed class AssetEntity : IEnrichedAssetEntity { - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } - public Guid Id { get; set; } + public DomainId Id { get; set; } - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } public Instant Created { get; set; } @@ -57,9 +56,14 @@ namespace Squidex.Domain.Apps.Entities.Assets public AssetType Type { get; set; } - public Guid AssetId + public DomainId AssetId { get { return Id; } } + + public DomainId UniqueId + { + get { return DomainId.Combine(AppId, Id); } + } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetFolderDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetFolderDomainObject.cs index 30ca258ed..abe1fbaa7 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetFolderDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetFolderDomainObject.cs @@ -25,7 +25,7 @@ namespace Squidex.Domain.Apps.Entities.Assets { private readonly IAssetQueryService assetQuery; - public AssetFolderDomainObject(IStore store, IAssetQueryService assetQuery, ISemanticLog log) + public AssetFolderDomainObject(IStore store, IAssetQueryService assetQuery, ISemanticLog log) : base(store, log) { Guard.NotNull(assetQuery, nameof(assetQuery)); @@ -33,9 +33,27 @@ namespace Squidex.Domain.Apps.Entities.Assets this.assetQuery = assetQuery; } + protected override bool IsDeleted() + { + return Snapshot.IsDeleted; + } + + protected override bool CanAcceptCreation(ICommand command) + { + return command is AssetFolderCommand; + } + + protected override bool CanAccept(ICommand command) + { + return command is AssetFolderCommand assetFolderCommand && + Equals(assetFolderCommand.AppId, Snapshot.AppId) && + Equals(assetFolderCommand.AssetFolderId, Snapshot.Id); + } + public override Task ExecuteAsync(IAggregateCommand command) { VerifyNotDeleted(); + VerifyCommand(command); switch (command) { @@ -78,6 +96,24 @@ namespace Squidex.Domain.Apps.Entities.Assets } } + private void VerifyCommand(IAggregateCommand command) + { + switch (command) + { + case AssetFolderCommand assetFolderCommand: + if (Version >= 0 && ( + !assetFolderCommand.AssetFolderId.Equals(Snapshot.Id) || + !assetFolderCommand.AppId.Equals(Snapshot.AppId))) + { + throw new InvalidOperationException(); + } + + break; + default: + throw new NotSupportedException(); + } + } + public void Create(CreateAssetFolder command) { RaiseEvent(SimpleMapper.Map(command, new AssetFolderCreated())); @@ -100,10 +136,7 @@ namespace Squidex.Domain.Apps.Entities.Assets private void RaiseEvent(AppEvent @event) { - if (@event.AppId == null) - { - @event.AppId = Snapshot.AppId; - } + @event.AppId ??= Snapshot.AppId; RaiseEvent(Envelope.Create(@event)); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetFolderDomainObjectGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetFolderDomainObjectGrain.cs index 5c045ed5b..2381a40a3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetFolderDomainObjectGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetFolderDomainObjectGrain.cs @@ -23,7 +23,7 @@ namespace Squidex.Domain.Apps.Entities.Assets limit?.SetLimit(5000, Lifetime); } - protected override Task OnActivateAsync(Guid key) + protected override Task OnActivateAsync(string key) { TryDelayDeactivation(Lifetime); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetHistoryEventsCreator.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetHistoryEventsCreator.cs index 7fb827a3d..99ab91c08 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetHistoryEventsCreator.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetHistoryEventsCreator.cs @@ -30,11 +30,16 @@ namespace Squidex.Domain.Apps.Entities.Assets protected override Task CreateEventCoreAsync(Envelope @event) { - var channel = $"assets.{@event.Headers.AggregateId()}"; + HistoryEvent? result = null; - var result = ForEvent(@event.Payload, channel); + if (@event.Payload is AssetEvent assetEvent) + { + var channel = $"assets.{assetEvent.AssetId}"; - return Task.FromResult(result); + result = ForEvent(@event.Payload, channel); + } + + return Task.FromResult(result); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetUsageTracker.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetUsageTracker.cs index 6a3a7680b..e3f68cfb4 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetUsageTracker.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetUsageTracker.cs @@ -30,7 +30,7 @@ namespace Squidex.Domain.Apps.Entities.Assets this.usageTracker = usageTracker; } - public async Task GetTotalSizeAsync(Guid appId) + public async Task GetTotalSizeAsync(DomainId appId) { var key = GetKey(appId); @@ -39,7 +39,7 @@ namespace Squidex.Domain.Apps.Entities.Assets return counters.GetInt64(CounterTotalSize); } - public async Task> QueryAsync(Guid appId, DateTime fromDate, DateTime toDate) + public async Task> QueryAsync(DomainId appId, DateTime fromDate, DateTime toDate) { var enriched = new List(); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetUsageTracker_EventHandling.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetUsageTracker_EventHandling.cs index a00abd5f6..1e43087fb 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetUsageTracker_EventHandling.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetUsageTracker_EventHandling.cs @@ -8,6 +8,7 @@ using System; using System.Threading.Tasks; using Squidex.Domain.Apps.Events.Assets; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.UsageTracking; @@ -57,7 +58,7 @@ namespace Squidex.Domain.Apps.Entities.Assets return @event.Headers.Timestamp().ToDateTimeUtc().Date; } - private Task UpdateSizeAsync(Guid appId, DateTime date, long size, long count) + private Task UpdateSizeAsync(DomainId appId, DateTime date, long size, long count) { var counters = new Counters { @@ -72,7 +73,7 @@ namespace Squidex.Domain.Apps.Entities.Assets usageTracker.TrackAsync(SummaryDate, appKey, null, counters)); } - private static string GetKey(Guid appId) + private static string GetKey(DomainId appId) { return $"{appId}_Assets"; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/BackupAssets.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/BackupAssets.cs index e9c25af37..a6616e85f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/BackupAssets.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/BackupAssets.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Tags; @@ -21,8 +20,8 @@ namespace Squidex.Domain.Apps.Entities.Assets public sealed class BackupAssets : IBackupHandler { private const string TagsFile = "AssetTags.json"; - private readonly HashSet assetIds = new HashSet(); - private readonly HashSet assetFolderIds = new HashSet(); + private readonly HashSet assetIds = new HashSet(); + private readonly HashSet assetFolderIds = new HashSet(); private readonly Rebuilder rebuilder; private readonly IAssetFileStore assetFileStore; private readonly ITagService tagService; @@ -50,9 +49,17 @@ namespace Squidex.Domain.Apps.Entities.Assets switch (@event.Payload) { case AssetCreated assetCreated: - return WriteAssetAsync(assetCreated.AssetId, assetCreated.FileVersion, context.Writer); + return WriteAssetAsync( + assetCreated.AppId.Id, + assetCreated.AssetId, + assetCreated.FileVersion, + context.Writer); case AssetUpdated assetUpdated: - return WriteAssetAsync(assetUpdated.AssetId, assetUpdated.FileVersion, context.Writer); + return WriteAssetAsync( + assetUpdated.AppId.Id, + assetUpdated.AssetId, + assetUpdated.FileVersion, + context.Writer); } return Task.CompletedTask; @@ -62,14 +69,24 @@ namespace Squidex.Domain.Apps.Entities.Assets { switch (@event.Payload) { - case AssetFolderCreated assetFolderCreated: - assetFolderIds.Add(assetFolderCreated.AssetFolderId); + case AssetFolderCreated _: + assetFolderIds.Add(@event.Headers.AggregateId()); break; case AssetCreated assetCreated: - await ReadAssetAsync(assetCreated.AssetId, assetCreated.FileVersion, context.Reader); + assetIds.Add(@event.Headers.AggregateId()); + + await ReadAssetAsync( + assetCreated.AppId.Id, + assetCreated.AssetId, + assetCreated.FileVersion, + context.Reader); break; case AssetUpdated assetUpdated: - await ReadAssetAsync(assetUpdated.AssetId, assetUpdated.FileVersion, context.Reader); + await ReadAssetAsync( + assetUpdated.AppId.Id, + assetUpdated.AssetId, + assetUpdated.FileVersion, + context.Reader); break; } @@ -82,24 +99,12 @@ namespace Squidex.Domain.Apps.Entities.Assets if (assetIds.Count > 0) { - await rebuilder.InsertManyAsync(async target => - { - foreach (var id in assetIds) - { - await target(id); - } - }); + await rebuilder.InsertManyAsync(assetIds); } if (assetFolderIds.Count > 0) { - await rebuilder.InsertManyAsync(async target => - { - foreach (var id in assetFolderIds) - { - await target(id); - } - }); + await rebuilder.InsertManyAsync(assetFolderIds); } } @@ -117,25 +122,23 @@ namespace Squidex.Domain.Apps.Entities.Assets await context.Writer.WriteJsonAsync(TagsFile, tags); } - private Task WriteAssetAsync(Guid assetId, long fileVersion, IBackupWriter writer) + private Task WriteAssetAsync(DomainId appId, DomainId assetId, long fileVersion, IBackupWriter writer) { return writer.WriteBlobAsync(GetName(assetId, fileVersion), stream => { - return assetFileStore.DownloadAsync(assetId, fileVersion, stream); + return assetFileStore.DownloadAsync(appId, assetId, fileVersion, stream); }); } - private Task ReadAssetAsync(Guid assetId, long fileVersion, IBackupReader reader) + private Task ReadAssetAsync(DomainId appId, DomainId assetId, long fileVersion, IBackupReader reader) { - assetIds.Add(assetId); - - return reader.ReadBlobAsync(GetName(reader.OldGuid(assetId), fileVersion), stream => + return reader.ReadBlobAsync(GetName(assetId, fileVersion), stream => { - return assetFileStore.UploadAsync(assetId, fileVersion, stream); + return assetFileStore.UploadAsync(appId, assetId, fileVersion, stream); }); } - private static string GetName(Guid assetId, long fileVersion) + private static string GetName(DomainId assetId, long fileVersion) { return $"{assetId}_{fileVersion}.asset"; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/AssetCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/AssetCommand.cs index 4898243dd..6fd0ff579 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/AssetCommand.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/AssetCommand.cs @@ -5,18 +5,20 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; namespace Squidex.Domain.Apps.Entities.Assets.Commands { - public abstract class AssetCommand : SquidexCommand, IAggregateCommand + public abstract class AssetCommand : SquidexCommand, IAppCommand, IAggregateCommand { - public Guid AssetId { get; set; } + public NamedId AppId { get; set; } - Guid IAggregateCommand.AggregateId + public DomainId AssetId { get; set; } + + DomainId IAggregateCommand.AggregateId { - get { return AssetId; } + get { return DomainId.Combine(AppId, AssetId); } } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/AssetFolderCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/AssetFolderCommand.cs index 8d3999c25..f93ec017f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/AssetFolderCommand.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/AssetFolderCommand.cs @@ -5,18 +5,20 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; namespace Squidex.Domain.Apps.Entities.Assets.Commands { - public abstract class AssetFolderCommand : SquidexCommand, IAggregateCommand + public abstract class AssetFolderCommand : SquidexCommand, IAppCommand, IAggregateCommand { - public Guid AssetFolderId { get; set; } + public NamedId AppId { get; set; } - Guid IAggregateCommand.AggregateId + public DomainId AssetFolderId { get; set; } + + DomainId IAggregateCommand.AggregateId { - get { return AssetFolderId; } + get { return DomainId.Combine(AppId, AssetFolderId); } } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAsset.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAsset.cs index 5257a8e7a..5d4731817 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAsset.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAsset.cs @@ -5,23 +5,20 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Assets.Commands { - public sealed class CreateAsset : UploadAssetCommand, IAppCommand + public sealed class CreateAsset : UploadAssetCommand { - public NamedId AppId { get; set; } - - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } public HashSet Tags { get; } = new HashSet(); public CreateAsset() { - AssetId = Guid.NewGuid(); + AssetId = DomainId.NewGuid(); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAssetFolder.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAssetFolder.cs index 8ca8d412c..0b2a5adde 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAssetFolder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAssetFolder.cs @@ -5,22 +5,19 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Assets.Commands { - public sealed class CreateAssetFolder : AssetFolderCommand, IAppCommand + public sealed class CreateAssetFolder : AssetFolderCommand { - public NamedId AppId { get; set; } - public string FolderName { get; set; } - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } public CreateAssetFolder() { - AssetFolderId = Guid.NewGuid(); + AssetFolderId = DomainId.NewGuid(); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/MoveAsset.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/MoveAsset.cs index 05a16b5fb..809b2b422 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/MoveAsset.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/MoveAsset.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Assets.Commands { public sealed class MoveAsset : AssetCommand { - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/MoveAssetFolder.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/MoveAssetFolder.cs index 45d16672d..1e24c6ac1 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/MoveAssetFolder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Commands/MoveAssetFolder.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Assets.Commands { public sealed class MoveAssetFolder : AssetFolderCommand { - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/DefaultAssetFileStore.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/DefaultAssetFileStore.cs index f62251e16..c24f40552 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/DefaultAssetFileStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/DefaultAssetFileStore.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -23,23 +22,48 @@ namespace Squidex.Domain.Apps.Entities.Assets this.assetStore = assetStore; } - public string? GeneratePublicUrl(Guid id, long fileVersion) + public string? GeneratePublicUrl(DomainId appId, DomainId id, long fileVersion) { - var fileName = GetFileName(id, fileVersion); + var fileName = GetFileName(appId, id, fileVersion); return assetStore.GeneratePublicUrl(fileName); } - public Task GetFileSizeAsync(Guid id, long fileVersion, CancellationToken ct = default) + public async Task GetFileSizeAsync(DomainId appId, DomainId id, long fileVersion, CancellationToken ct = default) { - var fileName = GetFileName(id, fileVersion); + try + { + var fileNameNew = GetFileName(appId, id, fileVersion); + + return await assetStore.GetSizeAsync(fileNameNew, ct); + } + catch (AssetNotFoundException) + { + var fileNameOld = GetFileName(id, fileVersion); + + return await assetStore.GetSizeAsync(fileNameOld, ct); + } + } - return assetStore.GetSizeAsync(fileName, ct); + public async Task DownloadAsync(DomainId appId, DomainId id, long fileVersion, Stream stream, BytesRange range = default, CancellationToken ct = default) + { + try + { + var fileNameNew = GetFileName(appId, id, fileVersion); + + await assetStore.DownloadAsync(fileNameNew, stream, range, ct); + } + catch (AssetNotFoundException) + { + var fileNameOld = GetFileName(id, fileVersion); + + await assetStore.DownloadAsync(fileNameOld, stream, range, ct); + } } - public Task UploadAsync(Guid id, long fileVersion, Stream stream, CancellationToken ct = default) + public Task UploadAsync(DomainId appId, DomainId id, long fileVersion, Stream stream, CancellationToken ct = default) { - var fileName = GetFileName(id, fileVersion); + var fileName = GetFileName(appId, id, fileVersion); return assetStore.UploadAsync(fileName, stream, true, ct); } @@ -49,25 +73,21 @@ namespace Squidex.Domain.Apps.Entities.Assets return assetStore.UploadAsync(tempFile, stream, false, ct); } - public Task CopyAsync(string tempFile, Guid id, long fileVersion, CancellationToken ct = default) + public Task CopyAsync(string tempFile, DomainId appId, DomainId id, long fileVersion, CancellationToken ct = default) { - var fileName = GetFileName(id, fileVersion); + var fileName = GetFileName(appId, id, fileVersion); return assetStore.CopyAsync(tempFile, fileName, ct); } - public Task DownloadAsync(Guid id, long fileVersion, Stream stream, BytesRange range = default, CancellationToken ct = default) + public async Task DeleteAsync(DomainId appId, DomainId id, long fileVersion) { - var fileName = GetFileName(id, fileVersion); + var fileNameOld = GetFileName(id, fileVersion); + var fileNameNew = GetFileName(appId, id, fileVersion); - return assetStore.DownloadAsync(fileName, stream, range, ct); - } - - public Task DeleteAsync(Guid id, long fileVersion) - { - var fileName = GetFileName(id, fileVersion); - - return assetStore.DeleteAsync(fileName); + await Task.WhenAll( + assetStore.DeleteAsync(fileNameOld), + assetStore.DeleteAsync(fileNameNew)); } public Task DeleteAsync(string tempFile) @@ -75,9 +95,14 @@ namespace Squidex.Domain.Apps.Entities.Assets return assetStore.DeleteAsync(tempFile); } - private static string GetFileName(Guid id, long fileVersion) + private static string GetFileName(DomainId id, long fileVersion) { return $"{id}_{fileVersion}"; } + + private static string GetFileName(DomainId appId, DomainId id, long fileVersion) + { + return $"{appId}_{id}_{fileVersion}"; + } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/FileTagAssetMetadataSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/FileTagAssetMetadataSource.cs index ee54868d1..054c887f5 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/FileTagAssetMetadataSource.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/FileTagAssetMetadataSource.cs @@ -59,7 +59,7 @@ namespace Squidex.Domain.Apps.Entities.Assets return Task.CompletedTask; } - private void Enhance(UploadAssetCommand command) + private static void Enhance(UploadAssetCommand command) { try { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Guards/GuardAsset.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Guards/GuardAsset.cs index ad157b704..86511c56b 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Guards/GuardAsset.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Guards/GuardAsset.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Infrastructure; @@ -43,11 +42,11 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards return Validate.It(() => "Cannot upload asset.", async e => { - await CheckPathAsync(command.ParentId, assetQuery, e); + await CheckPathAsync(command.AppId.Id, command.ParentId, assetQuery, e); }); } - public static Task CanMove(MoveAsset command, IAssetQueryService assetQuery, Guid oldParentId) + public static Task CanMove(MoveAsset command, IAssetQueryService assetQuery, DomainId oldParentId) { Guard.NotNull(command, nameof(command)); @@ -55,7 +54,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards { if (command.ParentId != oldParentId) { - await CheckPathAsync(command.ParentId, assetQuery, e); + await CheckPathAsync(command.AppId.Id, command.ParentId, assetQuery, e); } }); } @@ -70,11 +69,11 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards Guard.NotNull(command, nameof(command)); } - private static async Task CheckPathAsync(Guid parentId, IAssetQueryService assetQuery, AddValidation e) + private static async Task CheckPathAsync(DomainId appId, DomainId parentId, IAssetQueryService assetQuery, AddValidation e) { - if (parentId != default) + if (parentId != DomainId.Empty) { - var path = await assetQuery.FindAssetFolderAsync(parentId); + var path = await assetQuery.FindAssetFolderAsync(appId, parentId); if (path.Count == 0) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Guards/GuardAssetFolder.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Guards/GuardAssetFolder.cs index b615d065b..27f0942a3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Guards/GuardAssetFolder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Guards/GuardAssetFolder.cs @@ -26,7 +26,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards e(Not.Defined("Folder name"), nameof(command.FolderName)); } - await CheckPathAsync(command.ParentId, assetQuery, Guid.Empty, e); + await CheckPathAsync(command.AppId.Id, command.ParentId, assetQuery, DomainId.Empty, e); }); } @@ -43,7 +43,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards }); } - public static Task CanMove(MoveAssetFolder command, IAssetQueryService assetQuery, Guid id, Guid oldParentId) + public static Task CanMove(MoveAssetFolder command, IAssetQueryService assetQuery, DomainId id, DomainId oldParentId) { Guard.NotNull(command, nameof(command)); @@ -51,7 +51,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards { if (command.ParentId != oldParentId) { - await CheckPathAsync(command.ParentId, assetQuery, id, e); + await CheckPathAsync(command.AppId.Id, command.ParentId, assetQuery, id, e); } }); } @@ -61,22 +61,22 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards Guard.NotNull(command, nameof(command)); } - private static async Task CheckPathAsync(Guid parentId, IAssetQueryService assetQuery, Guid id, AddValidation e) + private static async Task CheckPathAsync(DomainId appId, DomainId parentId, IAssetQueryService assetQuery, DomainId id, AddValidation e) { - if (parentId != default) + if (parentId != DomainId.Empty) { - var path = await assetQuery.FindAssetFolderAsync(parentId); + var path = await assetQuery.FindAssetFolderAsync(appId, parentId); if (path.Count == 0) { e("Asset folder does not exist.", nameof(MoveAssetFolder.ParentId)); } - else if (id != default) + else if (id != DomainId.Empty) { - var indexOfThis = path.IndexOf(x => x.Id == id); + var indexOfSelf = path.IndexOf(x => x.Id == id); var indexOfParent = path.IndexOf(x => x.Id == parentId); - if (indexOfThis >= 0 && indexOfParent > indexOfThis) + if (indexOfSelf >= 0 && indexOfParent > indexOfSelf) { e("Cannot add folder to its own child.", nameof(MoveAssetFolder.ParentId)); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetEntity.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetEntity.cs index 8804009a2..cff4ee4b5 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetEntity.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetEntity.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.ValidateContent; using Squidex.Infrastructure; @@ -19,9 +18,9 @@ namespace Squidex.Domain.Apps.Entities.Assets IEntityWithTags, IAssetInfo { - NamedId AppId { get; } + NamedId AppId { get; } - Guid ParentId { get; } + DomainId ParentId { get; } string MimeType { get; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetFileStore.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetFileStore.cs index 0e0d31e62..8d74ec2c9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetFileStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetFileStore.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -15,20 +14,20 @@ namespace Squidex.Domain.Apps.Entities.Assets { public interface IAssetFileStore { - string? GeneratePublicUrl(Guid id, long fileVersion); + string? GeneratePublicUrl(DomainId appId, DomainId id, long fileVersion); - Task GetFileSizeAsync(Guid id, long fileVersion, CancellationToken ct = default); + Task GetFileSizeAsync(DomainId appId, DomainId id, long fileVersion, CancellationToken ct = default); - Task CopyAsync(string tempFile, Guid id, long fileVersion, CancellationToken ct = default); + Task CopyAsync(string tempFile, DomainId appId, DomainId id, long fileVersion, CancellationToken ct = default); Task UploadAsync(string tempFile, Stream stream, CancellationToken ct = default); - Task UploadAsync(Guid id, long fileVersion, Stream stream, CancellationToken ct = default); + Task UploadAsync(DomainId appId, DomainId id, long fileVersion, Stream stream, CancellationToken ct = default); - Task DownloadAsync(Guid id, long fileVersion, Stream stream, BytesRange range = default, CancellationToken ct = default); + Task DownloadAsync(DomainId appId, DomainId id, long fileVersion, Stream stream, BytesRange range = default, CancellationToken ct = default); Task DeleteAsync(string tempFile); - Task DeleteAsync(Guid id, long fileVersion); + Task DeleteAsync(DomainId appId, DomainId id, long fileVersion); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetFolderEntity.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetFolderEntity.cs index 83f9cf768..2bd9573b7 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetFolderEntity.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetFolderEntity.cs @@ -5,17 +5,16 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Assets { public interface IAssetFolderEntity : IEntity, IEntityWithVersion { - NamedId AppId { get; set; } + NamedId AppId { get; set; } string FolderName { get; set; } - Guid ParentId { get; set; } + DomainId ParentId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetLoader.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetLoader.cs index 21bcca35f..8e859e6a8 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetLoader.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetLoader.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Squidex.Infrastructure; @@ -13,6 +12,6 @@ namespace Squidex.Domain.Apps.Entities.Assets { public interface IAssetLoader { - Task GetAsync(Guid id, long version = EtagVersion.Any); + Task GetAsync(DomainId appId, DomainId id, long version = EtagVersion.Any); } } \ No newline at end of file diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs index 6db84de4d..659a3ca19 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Infrastructure; @@ -14,14 +13,14 @@ namespace Squidex.Domain.Apps.Entities.Assets { public interface IAssetQueryService { - Task> QueryByHashAsync(Context context, Guid appId, string hash); + Task> QueryByHashAsync(Context context, DomainId appId, string hash); - Task> QueryAsync(Context context, Guid? parentId, Q query); + Task> QueryAsync(Context context, DomainId? parentId, Q query); - Task> QueryAssetFoldersAsync(Context context, Guid parentId); + Task> QueryAssetFoldersAsync(Context context, DomainId parentId); - Task> FindAssetFolderAsync(Guid id); + Task> FindAssetFolderAsync(DomainId appId, DomainId id); - Task FindAssetAsync(Context context, Guid id); + Task FindAssetAsync(Context context, DomainId id); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetUsageTracker.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetUsageTracker.cs index 3699a5489..28fc122f9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetUsageTracker.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetUsageTracker.cs @@ -8,13 +8,14 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Assets { public interface IAssetUsageTracker { - Task> QueryAsync(Guid appId, DateTime fromDate, DateTime toDate); + Task> QueryAsync(DomainId appId, DateTime fromDate, DateTime toDate); - Task GetTotalSizeAsync(Guid appId); + Task GetTotalSizeAsync(DomainId appId); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetEnricher.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetEnricher.cs index 903554259..79d9b1063 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetEnricher.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetEnricher.cs @@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries foreach (var asset in results) { - requestCache.AddDependency(asset.Id, asset.Version); + requestCache.AddDependency(asset.UniqueId, asset.Version); } if (ShouldEnrich(context)) @@ -128,7 +128,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries } } - private async Task> CalculateTags(IGrouping group) + private async Task> CalculateTags(IGrouping group) { var uniqueIds = group.Where(x => x.Tags != null).SelectMany(x => x.Tags).ToHashSet(); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetLoader.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetLoader.cs index cfdaf9cec..c92be7fda 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetLoader.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetLoader.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Orleans; using Squidex.Infrastructure; @@ -24,11 +23,13 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries this.grainFactory = grainFactory; } - public async Task GetAsync(Guid id, long version) + public async Task GetAsync(DomainId appId, DomainId id, long version) { using (Profiler.TraceMethod()) { - var assetGrain = grainFactory.GetGrain(id); + var key = DomainId.Combine(appId, id); + + var assetGrain = grainFactory.GetGrain(key.ToString()); var assetState = await assetGrain.GetStateAsync(version); var asset = assetState.Value; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryParser.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryParser.cs index a7aa7658d..539dc5751 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryParser.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryParser.cs @@ -125,7 +125,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries schema.Properties[name.ToCamelCase()] = property; } - AddProperty(nameof(IAssetEntity.Id), JsonObjectType.String, JsonFormatStrings.Guid); + AddProperty(nameof(IAssetEntity.Id), JsonObjectType.String); AddProperty(nameof(IAssetEntity.Created), JsonObjectType.String, JsonFormatStrings.DateTime); AddProperty(nameof(IAssetEntity.CreatedBy), JsonObjectType.String); AddProperty(nameof(IAssetEntity.FileHash), JsonObjectType.String); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs index 916c5775a..43ef713c5 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -38,9 +37,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries this.queryParser = queryParser; } - public async Task FindAssetAsync(Context context, Guid id) + public async Task FindAssetAsync(Context context, DomainId id) { - var asset = await assetRepository.FindAssetAsync(id); + var asset = await assetRepository.FindAssetAsync(context.App.Id, id); if (asset != null) { @@ -50,13 +49,13 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries return null; } - public async Task> FindAssetFolderAsync(Guid id) + public async Task> FindAssetFolderAsync(DomainId appId, DomainId id) { var result = new List(); - while (id != default) + while (id != DomainId.Empty) { - var folder = await assetFolderRepository.FindAssetFolderAsync(id); + var folder = await assetFolderRepository.FindAssetFolderAsync(appId, id); if (folder == null || result.Any(x => x.Id == folder.Id)) { @@ -72,14 +71,14 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries return result; } - public async Task> QueryAssetFoldersAsync(Context context, Guid parentId) + public async Task> QueryAssetFoldersAsync(Context context, DomainId parentId) { var assetFolders = await assetFolderRepository.QueryAsync(context.App.Id, parentId); return assetFolders; } - public async Task> QueryByHashAsync(Context context, Guid appId, string hash) + public async Task> QueryByHashAsync(Context context, DomainId appId, string hash) { Guard.NotNull(hash, nameof(hash)); @@ -88,7 +87,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries return await assetEnricher.EnrichAsync(assets, context); } - public async Task> QueryAsync(Context context, Guid? parentId, Q query) + public async Task> QueryAsync(Context context, DomainId? parentId, Q query) { Guard.NotNull(context, nameof(context)); Guard.NotNull(query, nameof(query)); @@ -109,7 +108,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries return ResultList.Create(assets.Total, enriched); } - private async Task> QueryByQueryAsync(Context context, Guid? parentId, Q query) + private async Task> QueryByQueryAsync(Context context, DomainId? parentId, Q query) { var parsedQuery = await queryParser.ParseQueryAsync(context, query); @@ -118,12 +117,12 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries private async Task> QueryByIdsAsync(Context context, Q query) { - var assets = await assetRepository.QueryAsync(context.App.Id, new HashSet(query.Ids)); + var assets = await assetRepository.QueryAsync(context.App.Id, new HashSet(query.Ids)); return Sort(assets, query.Ids); } - private static IResultList Sort(IResultList assets, IReadOnlyList ids) + private static IResultList Sort(IResultList assets, IReadOnlyList ids) { return assets.SortSet(x => x.Id, ids); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/FilterTagTransformer.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/FilterTagTransformer.cs index eb5eb25d1..1eac8482f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/FilterTagTransformer.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/FilterTagTransformer.cs @@ -16,16 +16,16 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries public sealed class FilterTagTransformer : AsyncTransformVisitor { private readonly ITagService tagService; - private readonly Guid appId; + private readonly DomainId appId; - private FilterTagTransformer(Guid appId, ITagService tagService) + private FilterTagTransformer(DomainId appId, ITagService tagService) { this.appId = appId; this.tagService = tagService; } - public static ValueTask?> TransformAsync(FilterNode nodeIn, Guid appId, ITagService tagService) + public static ValueTask?> TransformAsync(FilterNode nodeIn, DomainId appId, ITagService tagService) { Guard.NotNull(nodeIn, nameof(nodeIn)); Guard.NotNull(tagService, nameof(tagService)); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetFolderRepository.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetFolderRepository.cs index 614619828..2058dab6a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetFolderRepository.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetFolderRepository.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Infrastructure; @@ -14,10 +13,10 @@ namespace Squidex.Domain.Apps.Entities.Assets.Repositories { public interface IAssetFolderRepository { - Task> QueryAsync(Guid appId, Guid parentId); + Task> QueryAsync(DomainId appId, DomainId parentId); - Task> QueryChildIdsAsync(Guid appId, Guid parentId); + Task> QueryChildIdsAsync(DomainId appId, DomainId parentId); - Task FindAssetFolderAsync(Guid id); + Task FindAssetFolderAsync(DomainId appId, DomainId id); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetRepository.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetRepository.cs index 42ee6aea1..42b2f1778 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetRepository.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetRepository.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Infrastructure; @@ -15,18 +14,20 @@ namespace Squidex.Domain.Apps.Entities.Assets.Repositories { public interface IAssetRepository { - Task> QueryByHashAsync(Guid appId, string hash); + Task> QueryByHashAsync(DomainId appId, string hash); - Task> QueryAsync(Guid appId, Guid? parentId, ClrQuery query); + Task> QueryAsync(DomainId appId, DomainId? parentId, ClrQuery query); - Task> QueryAsync(Guid appId, HashSet ids); + Task> QueryAsync(DomainId appId, HashSet ids); - Task> QueryIdsAsync(Guid appId, HashSet ids); + Task> QueryIdsAsync(DomainId appId, HashSet ids); - Task> QueryChildIdsAsync(Guid appId, Guid parentId); + Task> QueryChildIdsAsync(DomainId appId, DomainId parentId); - Task FindAssetAsync(Guid id); + Task FindAssetAsync(DomainId appId); - Task FindAssetBySlugAsync(Guid appId, string slug); + Task FindAssetAsync(DomainId appId, DomainId id); + + Task FindAssetBySlugAsync(DomainId appId, string slug); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/State/AssetFolderState.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/State/AssetFolderState.cs index fc2123dce..b3eb77306 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/State/AssetFolderState.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/State/AssetFolderState.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Events.Assets; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -18,11 +17,16 @@ namespace Squidex.Domain.Apps.Entities.Assets.State { public sealed class AssetFolderState : DomainObjectState, IAssetFolderEntity { - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } public string FolderName { get; set; } - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } + + public DomainId UniqueId + { + get { return DomainId.Combine(AppId, Id); } + } public override bool ApplyEvent(IEvent @event) { @@ -30,6 +34,8 @@ namespace Squidex.Domain.Apps.Entities.Assets.State { case AssetFolderCreated e: { + Id = e.AssetFolderId; + SimpleMapper.Map(e, this); return true; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/State/AssetState.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/State/AssetState.cs index e128803fa..5fff9a467 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/State/AssetState.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/State/AssetState.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Events.Assets; @@ -20,9 +19,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.State { public class AssetState : DomainObjectState, IAssetEntity { - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } public string FileName { get; set; } @@ -46,17 +45,24 @@ namespace Squidex.Domain.Apps.Entities.Assets.State public AssetType Type { get; set; } - public Guid AssetId + public DomainId AssetId { get { return Id; } } + public DomainId UniqueId + { + get { return DomainId.Combine(AppId, Id); } + } + public override bool ApplyEvent(IEvent @event) { switch (@event) { case AssetCreated e: { + Id = e.AssetId; + SimpleMapper.Map(e, this); FileName = e.FileName; @@ -136,6 +142,8 @@ namespace Squidex.Domain.Apps.Entities.Assets.State { ParentId = e.ParentId; + EnsureProperties(); + return true; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupContext.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupContext.cs index 764892de7..417cad7c4 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupContext.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupContext.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Backup @@ -14,7 +13,7 @@ namespace Squidex.Domain.Apps.Entities.Backup { public IBackupWriter Writer { get; } - public BackupContext(Guid appId, IUserMapping userMapping, IBackupWriter writer) + public BackupContext(DomainId appId, IUserMapping userMapping, IBackupWriter writer) : base(appId, userMapping) { Guard.NotNull(writer, nameof(writer)); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupContextBase.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupContextBase.cs index 67dee0ea5..5f919450d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupContextBase.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupContextBase.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Backup @@ -14,14 +13,14 @@ namespace Squidex.Domain.Apps.Entities.Backup { public IUserMapping UserMapping { get; } - public Guid AppId { get; set; } + public DomainId AppId { get; set; } public RefToken Initiator { get { return UserMapping.Initiator; } } - protected BackupContextBase(Guid appId, IUserMapping userMapping) + protected BackupContextBase(DomainId appId, IUserMapping userMapping) { Guard.NotNull(userMapping, nameof(userMapping)); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupGrain.cs index 60434cddf..f8d0e7f22 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupGrain.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; @@ -25,7 +26,7 @@ using Squidex.Shared.Users; namespace Squidex.Domain.Apps.Entities.Backup { [Reentrant] - public sealed class BackupGrain : GrainOfGuid, IBackupGrain + public sealed class BackupGrain : GrainOfString, IBackupGrain { private const int MaxBackups = 10; private static readonly Duration UpdateDuration = Duration.FromSeconds(1); @@ -74,7 +75,7 @@ namespace Squidex.Domain.Apps.Entities.Backup this.log = log; } - protected override Task OnActivateAsync(Guid key) + protected override Task OnActivateAsync(string key) { RecoverAfterRestartAsync().Forget(); @@ -102,7 +103,7 @@ namespace Squidex.Domain.Apps.Entities.Backup var job = new BackupJob { - Id = Guid.NewGuid(), + Id = DomainId.NewGuid(), Started = clock.GetCurrentInstant(), Status = JobStatus.Started }; @@ -138,6 +139,8 @@ namespace Squidex.Domain.Apps.Entities.Backup var context = new BackupContext(Key, userMapping, writer); + var filter = $"^[^\\-]*-{Regex.Escape(Key)}"; + await eventStore.QueryAsync(async storedEvent => { var @event = eventDataFormatter.Parse(storedEvent.Data); @@ -158,7 +161,7 @@ namespace Squidex.Domain.Apps.Entities.Backup job.HandledAssets = writer.WrittenAttachments; lastTimestamp = await WritePeriodically(lastTimestamp); - }, SquidexHeaders.AppId, Key.ToString(), null, ct); + }, filter, null, ct); foreach (var handler in handlers) { @@ -225,7 +228,7 @@ namespace Squidex.Domain.Apps.Entities.Backup return lastTimestamp; } - public async Task DeleteAsync(Guid id) + public async Task DeleteAsync(DomainId id) { var job = state.Value.Jobs.FirstOrDefault(x => x.Id == id); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupReader.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupReader.cs index 56460d1e6..40ecc9e00 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupReader.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupReader.cs @@ -8,14 +8,12 @@ using System; using System.IO; using System.IO.Compression; -using System.Linq; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Backup.Helpers; using Squidex.Domain.Apps.Entities.Backup.Model; using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.Json; -using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.States; #pragma warning disable SA1401 // Fields must be private @@ -24,7 +22,6 @@ namespace Squidex.Domain.Apps.Entities.Backup { public class BackupReader : DisposableObjectBase, IBackupReader { - private readonly GuidMapper guidMapper = new GuidMapper(); private readonly ZipArchive archive; private readonly IJsonSerializer serializer; private int readEvents; @@ -57,11 +54,6 @@ namespace Squidex.Domain.Apps.Entities.Backup } } - public Guid OldGuid(Guid newId) - { - return guidMapper.OldGuid(newId); - } - public Task ReadJsonAttachmentAsync(string name) { Guard.NotNullOrEmpty(name, nameof(name)); @@ -77,7 +69,7 @@ namespace Squidex.Domain.Apps.Entities.Backup using (var stream = attachmentEntry.Open()) { - result = serializer.Deserialize(stream, null, guidMapper.NewGuidOrValue); + result = serializer.Deserialize(stream, null); } readAttachments++; @@ -124,10 +116,8 @@ namespace Squidex.Domain.Apps.Entities.Backup { var (streamName, data) = serializer.Deserialize(stream).ToEvent(); - MapHeaders(data); - - var eventStream = streamNameResolver.WithNewId(streamName, guidMapper.NewGuidOrNull); - var eventEnvelope = formatter.Parse(data, guidMapper.NewGuidOrValue); + var eventStream = streamName; + var eventEnvelope = formatter.Parse(data); await handler((eventStream, eventEnvelope)); } @@ -135,21 +125,5 @@ namespace Squidex.Domain.Apps.Entities.Backup readEvents++; } } - - private void MapHeaders(EventData data) - { - foreach (var (key, value) in data.Headers.ToList()) - { - if (value.Type == JsonValueType.String) - { - var newGuid = guidMapper.NewGuidOrNull(value.ToString()); - - if (newGuid != null) - { - data.Headers.Add(key, newGuid); - } - } - } - } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupService.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupService.cs index 42a80bdc9..446df5487 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupService.cs @@ -25,9 +25,9 @@ namespace Squidex.Domain.Apps.Entities.Backup this.grainFactory = grainFactory; } - public Task StartBackupAsync(Guid appId, RefToken actor) + public Task StartBackupAsync(DomainId appId, RefToken actor) { - var grain = grainFactory.GetGrain(appId); + var grain = grainFactory.GetGrain(appId.ToString()); return grain.BackupAsync(actor); } @@ -48,27 +48,27 @@ namespace Squidex.Domain.Apps.Entities.Backup return state.Value; } - public async Task> GetBackupsAsync(Guid appId) + public async Task> GetBackupsAsync(DomainId appId) { - var grain = grainFactory.GetGrain(appId); + var grain = grainFactory.GetGrain(appId.ToString()); var state = await grain.GetStateAsync(); return state.Value; } - public async Task GetBackupAsync(Guid appId, Guid backupId) + public async Task GetBackupAsync(DomainId appId, DomainId backupId) { - var grain = grainFactory.GetGrain(appId); + var grain = grainFactory.GetGrain(appId.ToString()); var state = await grain.GetStateAsync(); return state.Value.Find(x => x.Id == backupId); } - public Task DeleteBackupAsync(Guid appId, Guid backupId) + public Task DeleteBackupAsync(DomainId appId, DomainId backupId) { - var grain = grainFactory.GetGrain(appId); + var grain = grainFactory.GetGrain(appId.ToString()); return grain.DeleteAsync(backupId); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/DefaultBackupArchiveStore.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/DefaultBackupArchiveStore.cs index 9a03e48a7..84f21e9a9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/DefaultBackupArchiveStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/DefaultBackupArchiveStore.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -25,28 +24,28 @@ namespace Squidex.Domain.Apps.Entities.Backup this.assetStore = assetStore; } - public Task DownloadAsync(Guid backupId, Stream stream, CancellationToken ct = default) + public Task DownloadAsync(DomainId backupId, Stream stream, CancellationToken ct = default) { var fileName = GetFileName(backupId); return assetStore.DownloadAsync(fileName, stream, default, ct); } - public Task UploadAsync(Guid backupId, Stream stream, CancellationToken ct = default) + public Task UploadAsync(DomainId backupId, Stream stream, CancellationToken ct = default) { var fileName = GetFileName(backupId); return assetStore.UploadAsync(fileName, stream, true, ct); } - public Task DeleteAsync(Guid backupId) + public Task DeleteAsync(DomainId backupId) { var fileName = GetFileName(backupId); return assetStore.DeleteAsync(fileName); } - private static string GetFileName(Guid backupId) + private static string GetFileName(DomainId backupId) { return $"{backupId}_0"; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/GuidMapper.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/GuidMapper.cs deleted file mode 100644 index a99236ee3..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/GuidMapper.cs +++ /dev/null @@ -1,114 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using Squidex.Infrastructure; - -namespace Squidex.Domain.Apps.Entities.Backup -{ - internal sealed class GuidMapper - { - private static readonly int GuidLength = Guid.Empty.ToString().Length; - private readonly Dictionary oldToNewGuid = new Dictionary(); - private readonly Dictionary newToOldGuid = new Dictionary(); - private readonly Dictionary strings = new Dictionary(); - - public Guid OldGuid(Guid newGuid) - { - return newToOldGuid.GetOrCreate(newGuid, x => x); - } - - public string? NewGuidOrNull(string value) - { - if (TryGenerateNewGuidString(value, out var result) || TryGenerateNewNamedId(value, out result)) - { - return result; - } - - return null; - } - - public string NewGuidOrValue(string value) - { - if (TryGenerateNewGuidString(value, out var result) || TryGenerateNewNamedId(value, out result)) - { - return result; - } - - return value; - } - - private bool TryGenerateNewGuidString(string value, [MaybeNullWhen(false)] out string result) - { - if (value.Length == GuidLength) - { - if (strings.TryGetValue(value, out result!)) - { - return true; - } - - if (Guid.TryParse(value, out var guid)) - { - var newGuid = GenerateNewGuid(guid); - - strings[value] = result = newGuid.ToString(); - - return true; - } - } - - result = null!; - - return false; - } - - private bool TryGenerateNewNamedId(string value, [MaybeNullWhen(false)] out string result) - { - if (value.Length > GuidLength) - { - if (strings.TryGetValue(value, out result!)) - { - return true; - } - - if (NamedId.TryParse(value, Guid.TryParse, out var namedId)) - { - var newGuid = GenerateNewGuid(namedId.Id); - - strings[value] = result = NamedId.Of(newGuid, namedId.Name).ToString(); - - return true; - } - } - - result = null!; - - return false; - } - - private Guid GenerateNewGuid(Guid oldGuid) - { - if (oldGuid == Guid.Empty) - { - return Guid.Empty; - } - - return oldToNewGuid.GetOrAdd(oldGuid, GuidGenerator); - } - - private Guid GuidGenerator(Guid oldGuid) - { - var newGuid = Guid.NewGuid(); - - newToOldGuid[newGuid] = oldGuid; - - return newGuid; - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupArchiveLocation.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupArchiveLocation.cs index c2e59ee9c..4a81cd6a8 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupArchiveLocation.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupArchiveLocation.cs @@ -8,15 +8,16 @@ using System; using System.IO; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Backup { public interface IBackupArchiveLocation { - Stream OpenStream(Guid backupId); + Stream OpenStream(DomainId backupId); Task OpenWriterAsync(Stream stream); - Task OpenReaderAsync(Uri url, Guid id); + Task OpenReaderAsync(Uri url, DomainId id); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupArchiveStore.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupArchiveStore.cs index 4ff57a28f..bbe812178 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupArchiveStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupArchiveStore.cs @@ -5,19 +5,19 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.IO; using System.Threading; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Backup { public interface IBackupArchiveStore { - Task UploadAsync(Guid backupId, Stream stream, CancellationToken ct = default); + Task UploadAsync(DomainId backupId, Stream stream, CancellationToken ct = default); - Task DownloadAsync(Guid backupId, Stream stream, CancellationToken ct = default); + Task DownloadAsync(DomainId backupId, Stream stream, CancellationToken ct = default); - Task DeleteAsync(Guid backupId); + Task DeleteAsync(DomainId backupId); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupGrain.cs index 9d82ae0d1..803a7898d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupGrain.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Orleans; @@ -14,11 +13,11 @@ using Squidex.Infrastructure.Orleans; namespace Squidex.Domain.Apps.Entities.Backup { - public interface IBackupGrain : IGrainWithGuidKey + public interface IBackupGrain : IGrainWithStringKey { Task BackupAsync(RefToken actor); - Task DeleteAsync(Guid id); + Task DeleteAsync(DomainId id); Task>> GetStateAsync(); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupHandler.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupHandler.cs index 89729e121..8c5d60ab0 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupHandler.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupHandler.cs @@ -5,8 +5,8 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Backup @@ -35,7 +35,7 @@ namespace Squidex.Domain.Apps.Entities.Backup return Task.CompletedTask; } - public Task CleanupRestoreErrorAsync(Guid appId) + public Task CleanupRestoreErrorAsync(DomainId appId) { return Task.CompletedTask; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupJob.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupJob.cs index 56fe0a19e..3dbccbabe 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupJob.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupJob.cs @@ -5,14 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Backup { public interface IBackupJob { - Guid Id { get; } + DomainId Id { get; } Instant Started { get; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupReader.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupReader.cs index 0e6e4a80e..f584e162e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupReader.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupReader.cs @@ -19,8 +19,6 @@ namespace Squidex.Domain.Apps.Entities.Backup int ReadEvents { get; } - Guid OldGuid(Guid newId); - Task ReadBlobAsync(string name, Func handler); Task ReadEventsAsync(IStreamNameResolver streamNameResolver, IEventDataFormatter formatter, Func<(string Stream, Envelope Event), Task> handler); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupService.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupService.cs index 7541e5b26..afb2f3db5 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/IBackupService.cs @@ -14,16 +14,16 @@ namespace Squidex.Domain.Apps.Entities.Backup { public interface IBackupService { - Task StartBackupAsync(Guid appId, RefToken actor); + Task StartBackupAsync(DomainId appId, RefToken actor); Task StartRestoreAsync(RefToken actor, Uri url, string? newAppName); Task GetRestoreAsync(); - Task> GetBackupsAsync(Guid appId); + Task> GetBackupsAsync(DomainId appId); - Task GetBackupAsync(Guid appId, Guid backupId); + Task GetBackupAsync(DomainId appId, DomainId backupId); - Task DeleteBackupAsync(Guid appId, Guid backupId); + Task DeleteBackupAsync(DomainId appId, DomainId backupId); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/RestoreContext.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/RestoreContext.cs index e122069b5..b0746c6de 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/RestoreContext.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/RestoreContext.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Backup @@ -14,12 +13,16 @@ namespace Squidex.Domain.Apps.Entities.Backup { public IBackupReader Reader { get; } - public RestoreContext(Guid appId, IUserMapping userMapping, IBackupReader reader) + public DomainId PreviousAppId { get; set; } + + public RestoreContext(DomainId appId, IUserMapping userMapping, IBackupReader reader, DomainId previousAppId) : base(appId, userMapping) { Guard.NotNull(reader, nameof(reader)); Reader = reader; + + PreviousAppId = previousAppId; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/RestoreGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/RestoreGrain.cs index 297e051e1..e70f88d34 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/RestoreGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/RestoreGrain.cs @@ -19,6 +19,7 @@ using Squidex.Domain.Apps.Events.Apps; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.EventSourcing; +using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Log; using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.States; @@ -117,7 +118,7 @@ namespace Squidex.Domain.Apps.Entities.Backup state.Value.Job = new RestoreJob { - Id = Guid.NewGuid(), + Id = DomainId.NewGuid(), NewAppName = newAppName, Actor = actor, Started = clock.GetCurrentInstant(), @@ -250,7 +251,7 @@ namespace Squidex.Domain.Apps.Entities.Backup await commandBus.PublishAsync(new AssignContributor { Actor = actor, - AppId = CurrentJob.AppId.Id, + AppId = CurrentJob.AppId, ContributorId = actor.Identifier, Restoring = true, Role = Role.Owner @@ -320,20 +321,26 @@ namespace Squidex.Domain.Apps.Entities.Backup { if (@event.Payload is AppCreated appCreated) { + var previousAppId = appCreated.AppId.Id.ToString(); + if (!string.IsNullOrWhiteSpace(CurrentJob.NewAppName)) { appCreated.Name = CurrentJob.NewAppName; - CurrentJob.AppId = NamedId.Of(appCreated.AppId.Id, CurrentJob.NewAppName); + CurrentJob.AppId = NamedId.Of(DomainId.NewGuid(), CurrentJob.NewAppName); } else { - CurrentJob.AppId = appCreated.AppId; + CurrentJob.AppId = NamedId.Of(DomainId.NewGuid(), appCreated.Name); } - await CreateContextAsync(reader); + await CreateContextAsync(reader, previousAppId); } + stream = stream.Replace( + restoreContext.PreviousAppId.ToString(), + restoreContext.AppId.ToString()); + if (@event.Payload is SquidexEvent squidexEvent && squidexEvent.Actor != null) { if (restoreContext.UserMapping.TryMap(squidexEvent.Actor, out var newUser)) @@ -347,6 +354,15 @@ namespace Squidex.Domain.Apps.Entities.Backup appEvent.AppId = CurrentJob.AppId; } + if (@event.Headers.TryGet(CommonHeaders.AggregateId, out var aggregateId) && aggregateId is JsonString s) + { + var id = s.Value.Replace( + restoreContext.PreviousAppId.ToString(), + restoreContext.AppId.ToString()); + + @event.SetAggregateId(id); + } + foreach (var handler in handlers) { if (!await handler.RestoreEventAsync(@event, restoreContext)) @@ -356,14 +372,18 @@ namespace Squidex.Domain.Apps.Entities.Backup } var eventData = eventDataFormatter.ToEventData(@event, @event.Headers.CommitId()); - var eventCommit = new List { eventData }; + + var eventCommit = new List + { + eventData + }; await eventStore.AppendAsync(Guid.NewGuid(), stream, eventCommit); Log($"Read {reader.ReadEvents} events and {reader.ReadAttachments} attachments.", true); } - private async Task CreateContextAsync(IBackupReader reader) + private async Task CreateContextAsync(IBackupReader reader, DomainId previousAppId) { var userMapping = new UserMapping(CurrentJob.Actor); @@ -376,7 +396,7 @@ namespace Squidex.Domain.Apps.Entities.Backup Log("Created Users"); } - restoreContext = new RestoreContext(CurrentJob.AppId.Id, userMapping, reader); + restoreContext = new RestoreContext(CurrentJob.AppId.Id, userMapping, reader, previousAppId); } private void Log(string message, bool replace = false) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/State/BackupJob.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/State/BackupJob.cs index e4bae619e..c58c9f665 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/State/BackupJob.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/State/BackupJob.cs @@ -5,14 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Backup.State { public sealed class BackupJob : IBackupJob { - public Guid Id { get; set; } + public DomainId Id { get; set; } public Instant Started { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/State/RestoreJob.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/State/RestoreJob.cs index 511b3484f..c11d979dd 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/State/RestoreJob.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/State/RestoreJob.cs @@ -16,9 +16,9 @@ namespace Squidex.Domain.Apps.Entities.Backup.State { public string AppName { get; set; } - public Guid Id { get; set; } + public DomainId Id { get; set; } - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } public RefToken Actor { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/TempFolderBackupArchiveLocation.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/TempFolderBackupArchiveLocation.cs index 0dab4fcdf..c833dade5 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/TempFolderBackupArchiveLocation.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/TempFolderBackupArchiveLocation.cs @@ -27,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.Backup this.jsonSerializer = jsonSerializer; } - public async Task OpenReaderAsync(Uri url, Guid id) + public async Task OpenReaderAsync(Uri url, DomainId id) { var stream = OpenStream(id); @@ -75,19 +75,19 @@ namespace Squidex.Domain.Apps.Entities.Backup } catch (IOException) { - stream.Dispose(); + await stream.DisposeAsync(); throw new BackupRestoreException("The backup archive is corrupt and cannot be opened."); } catch (Exception) { - stream.Dispose(); + await stream.DisposeAsync(); throw; } } - public Stream OpenStream(Guid backupId) + public Stream OpenStream(DomainId backupId) { var tempFile = Path.Combine(Path.GetTempPath(), backupId + ".zip"); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Comments/Commands/CommentsCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/Comments/Commands/CommentsCommand.cs index a9fcdcc13..067dfeb2e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Comments/Commands/CommentsCommand.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Comments/Commands/CommentsCommand.cs @@ -5,17 +5,16 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Comments.Commands { public abstract class CommentsCommand : SquidexCommand, IAppCommand { - public string CommentsId { get; set; } + public NamedId AppId { get; set; } - public Guid CommentId { get; set; } + public DomainId CommentsId { get; set; } - public NamedId AppId { get; set; } + public DomainId CommentId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Comments/Commands/CreateComment.cs b/backend/src/Squidex.Domain.Apps.Entities/Comments/Commands/CreateComment.cs index f0016afdd..56ebd3722 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Comments/Commands/CreateComment.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Comments/Commands/CreateComment.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Comments.Commands { @@ -17,7 +18,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Commands public CreateComment() { - CommentId = Guid.NewGuid(); + CommentId = DomainId.NewGuid(); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Comments/CommentsCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Comments/CommentsCommandMiddleware.cs index 860159c27..de1d96a39 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Comments/CommentsCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Comments/CommentsCommandMiddleware.cs @@ -52,7 +52,7 @@ namespace Squidex.Domain.Apps.Entities.Comments private async Task ExecuteCommandAsync(CommandContext context, CommentsCommand commentsCommand) { - var grain = grainFactory.GetGrain(commentsCommand.CommentsId); + var grain = grainFactory.GetGrain(commentsCommand.CommentsId.ToString()); var result = await grain.ExecuteAsync(commentsCommand.AsJ()); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Comments/CommentsResult.cs b/backend/src/Squidex.Domain.Apps.Entities/Comments/CommentsResult.cs index b442789c8..e54465459 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Comments/CommentsResult.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Comments/CommentsResult.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using Squidex.Domain.Apps.Core.Comments; using Squidex.Domain.Apps.Events.Comments; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Comments @@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.Comments public List UpdatedComments { get; set; } = new List(); - public List DeletedComments { get; set; } = new List(); + public List DeletedComments { get; set; } = new List(); public long Version { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Comments/Guards/GuardComments.cs b/backend/src/Squidex.Domain.Apps.Entities/Comments/Guards/GuardComments.cs index ddde50c91..fa54a5dfd 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Comments/Guards/GuardComments.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Comments/Guards/GuardComments.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Squidex.Domain.Apps.Entities.Comments.Commands; using Squidex.Domain.Apps.Events.Comments; @@ -62,7 +61,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Guards } } - private static Envelope FindComment(List> events, Guid commentId) + private static Envelope FindComment(List> events, DomainId commentId) { Envelope? result = null; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/BackupContents.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/BackupContents.cs index 6542477ea..feb37c5d6 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/BackupContents.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/BackupContents.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -21,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { public sealed class BackupContents : IBackupHandler { - private readonly Dictionary> contentIdsBySchemaId = new Dictionary>(); + private readonly Dictionary> contentIdsBySchemaId = new Dictionary>(); private readonly Rebuilder rebuilder; public string Name { get; } = "Contents"; @@ -38,7 +37,7 @@ namespace Squidex.Domain.Apps.Entities.Contents switch (@event.Payload) { case ContentCreated contentCreated: - contentIdsBySchemaId.GetOrAddNew(contentCreated.SchemaId.Id).Add(contentCreated.ContentId); + contentIdsBySchemaId.GetOrAddNew(contentCreated.SchemaId.Id).Add(@event.Headers.AggregateId()); break; case SchemaDeleted schemaDeleted: contentIdsBySchemaId.Remove(schemaDeleted.SchemaId.Id); @@ -50,15 +49,11 @@ namespace Squidex.Domain.Apps.Entities.Contents public async Task RestoreAsync(RestoreContext context) { - if (contentIdsBySchemaId.Count > 0) + var ids = contentIdsBySchemaId.Values.SelectMany(x => x); + + if (ids.Any()) { - await rebuilder.InsertManyAsync(async target => - { - foreach (var contentId in contentIdsBySchemaId.Values.SelectMany(x => x)) - { - await target(contentId); - } - }); + await rebuilder.InsertManyAsync(ids); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/BulkUpdateCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/BulkUpdateCommandMiddleware.cs index 11d5b0a3c..b0f27a4f9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/BulkUpdateCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/BulkUpdateCommandMiddleware.cs @@ -87,7 +87,7 @@ namespace Squidex.Domain.Apps.Entities.Contents case BulkUpdateType.ChangeStatus: { - if (id == null || id == default) + if (id == null || id == DomainId.Empty) { throw new DomainObjectNotFoundException("NOT DEFINED", typeof(IContentEntity)); } @@ -105,7 +105,7 @@ namespace Squidex.Domain.Apps.Entities.Contents case BulkUpdateType.Delete: { - if (id == null || id == default) + if (id == null || id == DomainId.Empty) { throw new DomainObjectNotFoundException("NOT DEFINED", typeof(IContentEntity)); } @@ -150,7 +150,7 @@ namespace Squidex.Domain.Apps.Entities.Contents } } - private async Task FindIdAsync(Context context, string schema, BulkUpdateJob job) + private async Task FindIdAsync(Context context, string schema, BulkUpdateJob job) { var id = job.Id; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/BulkUpdateResultItem.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/BulkUpdateResultItem.cs index b93e58f33..d78e239f4 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/BulkUpdateResultItem.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/BulkUpdateResultItem.cs @@ -6,12 +6,13 @@ // ========================================================================== using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents { public sealed class BulkUpdateResultItem { - public Guid? ContentId { get; set; } + public DomainId? ContentId { get; set; } public Exception? Exception { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateContents.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateContents.cs index 6ebcfecdd..baa646a52 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateContents.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateContents.cs @@ -5,17 +5,16 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Commands { - public sealed class BulkUpdateContents : SquidexCommand, ISchemaCommand, IAppCommand + public sealed class BulkUpdateContents : SquidexCommand, IAppCommand, ISchemaCommand { - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } - public NamedId SchemaId { get; set; } + public NamedId SchemaId { get; set; } public bool Publish { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateJob.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateJob.cs index 80c751e02..e28824871 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateJob.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateJob.cs @@ -5,8 +5,8 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Queries; @@ -16,7 +16,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Commands { public Query? Query { get; set; } - public Guid? Id { get; set; } + public DomainId? Id { get; set; } public NamedContentData Data { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/ChangeContentStatus.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/ChangeContentStatus.cs index d388b70e7..6fe371623 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/ChangeContentStatus.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/ChangeContentStatus.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================= -using System; using NodaTime; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Commands { @@ -17,6 +17,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.Commands public Instant? DueTime { get; set; } - public Guid? JobId { get; set; } + public DomainId? JobId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/ContentCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/ContentCommand.cs index fdf122c55..68317c2dd 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/ContentCommand.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/ContentCommand.cs @@ -5,20 +5,24 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; namespace Squidex.Domain.Apps.Entities.Contents.Commands { - public abstract class ContentCommand : SquidexCommand, IAggregateCommand + public abstract class ContentCommand : SquidexCommand, IAppCommand, ISchemaCommand, IAggregateCommand { - public Guid ContentId { get; set; } + public NamedId AppId { get; set; } + + public NamedId SchemaId { get; set; } + + public DomainId ContentId { get; set; } public bool DoNotScript { get; set; } - Guid IAggregateCommand.AggregateId + DomainId IAggregateCommand.AggregateId { - get { return ContentId; } + get { return DomainId.Combine(AppId, ContentId); } } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/CreateContent.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/CreateContent.cs index 2eec65f73..2fed70e94 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/CreateContent.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/CreateContent.cs @@ -5,22 +5,17 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Commands { - public sealed class CreateContent : ContentDataCommand, ISchemaCommand, IAppCommand + public sealed class CreateContent : ContentDataCommand, ISchemaCommand { - public NamedId AppId { get; set; } - - public NamedId SchemaId { get; set; } - public bool Publish { get; set; } public CreateContent() { - ContentId = Guid.NewGuid(); + ContentId = DomainId.NewGuid(); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentChangedTriggerHandler.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentChangedTriggerHandler.cs index e63133729..487f53c44 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentChangedTriggerHandler.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentChangedTriggerHandler.cs @@ -5,7 +5,6 @@ // 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.HandleRules; @@ -39,7 +38,8 @@ namespace Squidex.Domain.Apps.Entities.Contents var content = await contentLoader.GetAsync( - @event.Headers.AggregateId(), + @event.Payload.AppId.Id, + @event.Payload.ContentId, @event.Headers.EventStreamNumber()); SimpleMapper.Map(content, result); @@ -77,6 +77,7 @@ namespace Squidex.Domain.Apps.Entities.Contents var previousContent = await contentLoader.GetAsync( + content.AppId.Id, content.Id, content.Version - 1); @@ -90,7 +91,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return result; } - protected override bool Trigger(ContentEvent @event, ContentChangedTriggerV2 trigger, Guid ruleId) + protected override bool Trigger(ContentEvent @event, ContentChangedTriggerV2 trigger, DomainId ruleId) { if (trigger.HandleAll) { @@ -132,7 +133,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return false; } - private static bool MatchsSchema(ContentChangedTriggerSchemaV2 schema, NamedId eventId) + private static bool MatchsSchema(ContentChangedTriggerSchemaV2 schema, NamedId eventId) { return eventId.Id == schema.SchemaId; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentDomainObject.cs index 27683b69f..d590f280a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentDomainObject.cs @@ -29,7 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Contents private readonly IContentWorkflow contentWorkflow; private readonly ContentOperationContext context; - public ContentDomainObject(IStore store, IContentWorkflow contentWorkflow, ContentOperationContext context, ISemanticLog log) + public ContentDomainObject(IStore store, IContentWorkflow contentWorkflow, ContentOperationContext context, ISemanticLog log) : base(store, log) { Guard.NotNull(context, nameof(context)); @@ -39,6 +39,24 @@ namespace Squidex.Domain.Apps.Entities.Contents this.context = context; } + protected override bool IsDeleted() + { + return Snapshot.IsDeleted; + } + + protected override bool CanAcceptCreation(ICommand command) + { + return command is ContentCommand; + } + + protected override bool CanAccept(ICommand command) + { + return command is ContentCommand contentCommand && + Equals(contentCommand.AppId, Snapshot.AppId) && + Equals(contentCommand.SchemaId, Snapshot.SchemaId) && + Equals(contentCommand.ContentId, Snapshot.Id); + } + public override Task ExecuteAsync(IAggregateCommand command) { VerifyNotDeleted(); @@ -304,15 +322,8 @@ namespace Squidex.Domain.Apps.Entities.Contents private void RaiseEvent(SchemaEvent @event) { - if (@event.AppId == null) - { - @event.AppId = Snapshot.AppId; - } - - if (@event.SchemaId == null) - { - @event.SchemaId = Snapshot.SchemaId; - } + @event.AppId ??= Snapshot.AppId; + @event.SchemaId ??= Snapshot.SchemaId; RaiseEvent(Envelope.Create(@event)); } @@ -341,7 +352,7 @@ namespace Squidex.Domain.Apps.Entities.Contents } } - private Task LoadContext(NamedId appId, NamedId schemaId, ContentCommand command, Func message, bool optimized = false) + private Task LoadContext(NamedId appId, NamedId schemaId, ContentCommand command, Func message, bool optimized = false) { return context.LoadAsync(appId, schemaId, command, message, optimized); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentEntity.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentEntity.cs index 18faf3b73..0c2b6ea25 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentEntity.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentEntity.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; @@ -13,13 +12,13 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents { - public sealed class ContentEntity : IEnrichedContentEntity, IContentEntity + public sealed class ContentEntity : IEnrichedContentEntity { - public Guid Id { get; set; } + public DomainId Id { get; set; } - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } - public NamedId SchemaId { get; set; } + public NamedId SchemaId { get; set; } public long Version { get; set; } @@ -58,5 +57,10 @@ namespace Squidex.Domain.Apps.Entities.Contents public string? ScheduledStatusColor { get; set; } public RootField[]? ReferenceFields { get; set; } + + public DomainId UniqueId + { + get { return DomainId.Combine(AppId, Id); } + } } } \ No newline at end of file diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentHistoryEventsCreator.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentHistoryEventsCreator.cs index 4dc41f3a5..eb6724b07 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentHistoryEventsCreator.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentHistoryEventsCreator.cs @@ -46,36 +46,41 @@ namespace Squidex.Domain.Apps.Entities.Contents protected override Task CreateEventCoreAsync(Envelope @event) { - var channel = $"contents.{@event.Headers.AggregateId()}"; + HistoryEvent? result = null; - if (@event.Payload is SchemaEvent schemaEvent) + if (@event.Payload is ContentEvent contentEvent) { - if (schemaEvent.SchemaId == null) + var channel = $"contents.{contentEvent.ContentId}"; + + if (@event.Payload is SchemaEvent schemaEvent) { - return Task.FromResult(null); - } + if (schemaEvent.SchemaId == null) + { + return Task.FromResult(null); + } - channel = $"schemas.{schemaEvent.SchemaId.Id}.{channel}"; - } + channel = $"schemas.{schemaEvent.SchemaId.Id}.{channel}"; + } - var result = ForEvent(@event.Payload, channel); + result = ForEvent(@event.Payload, channel); - if (@event.Payload is SchemaEvent schemaEvent2) - { - result = result.Param("Schema", schemaEvent2.SchemaId.Name); - } + if (@event.Payload is SchemaEvent schemaEvent2) + { + result = result.Param("Schema", schemaEvent2.SchemaId.Name); + } - if (@event.Payload is ContentStatusChanged contentStatusChanged) - { - result = result.Param("Status", contentStatusChanged.Status); - } + if (@event.Payload is ContentStatusChanged contentStatusChanged) + { + result = result.Param("Status", contentStatusChanged.Status); + } - if (@event.Payload is ContentStatusScheduled contentStatusScheduled) - { - result = result.Param("Status", contentStatusScheduled.Status); + if (@event.Payload is ContentStatusScheduled contentStatusScheduled) + { + result = result.Param("Status", contentStatusScheduled.Status); + } } - return Task.FromResult(result); + return Task.FromResult(result); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs index c2a07ae70..331069c4a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs @@ -54,7 +54,7 @@ namespace Squidex.Domain.Apps.Entities.Contents get { return schema; } } - public async Task LoadAsync(NamedId appId, NamedId schemaId, ContentCommand command, Func message, bool optimized) + public async Task LoadAsync(NamedId appId, NamedId schemaId, ContentCommand command, Func message, bool optimized) { var (app, schema) = await appProvider.GetAppWithSchemaAsync(appId.Id, schemaId.Id); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs index 77f5a415b..295034130 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; @@ -82,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Contents private async Task CreateSearchFilterAsync(Context context) { - var allowedSchemas = new List(); + var allowedSchemas = new List(); var schemas = await appProvider.GetSchemasAsync(context.App.Id); @@ -109,7 +108,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return context.Permissions.Allows(permission); } - private string FormatName(IEnrichedContentEntity content, string masterLanguage) + private static string FormatName(IEnrichedContentEntity content, string masterLanguage) { var sb = new StringBuilder(); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/CounterGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/CounterGrain.cs index 4eea97aba..a410848b6 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/CounterGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/CounterGrain.cs @@ -13,7 +13,7 @@ using Squidex.Infrastructure.States; namespace Squidex.Domain.Apps.Entities.Contents.Counter { - public sealed class CounterGrain : GrainOfGuid, ICounterGrain + public sealed class CounterGrain : GrainOfString, ICounterGrain { private readonly IGrainState state; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/CounterJintExtension.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/CounterJintExtension.cs index a4d2c91c0..e3d81eabc 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/CounterJintExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/CounterJintExtension.cs @@ -26,7 +26,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Counter public void Extend(ExecutionContext context, bool async) { - if (context.TryGetValue("appId", out var temp) && temp is Guid appId) + if (context.TryGetValue("appId", out var temp) && temp is DomainId appId) { var engine = context.Engine; @@ -42,16 +42,16 @@ namespace Squidex.Domain.Apps.Entities.Contents.Counter } } - private long Increment(Guid appId, string name) + private long Increment(DomainId appId, string name) { - var grain = grainFactory.GetGrain(appId); + var grain = grainFactory.GetGrain(appId.ToString()); return AsyncHelper.Sync(() => grain.IncrementAsync(name)); } - private long Reset(Guid appId, string name, long value) + private long Reset(DomainId appId, string name, long value) { - var grain = grainFactory.GetGrain(appId); + var grain = grainFactory.GetGrain(appId.ToString()); return AsyncHelper.Sync(() => grain.ResetAsync(name, value)); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/ICounterGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/ICounterGrain.cs index a2d302495..39551a7bc 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/ICounterGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/ICounterGrain.cs @@ -10,7 +10,7 @@ using Orleans; namespace Squidex.Domain.Apps.Entities.Contents.Counter { - public interface ICounterGrain : IGrainWithGuidKey + public interface ICounterGrain : IGrainWithStringKey { Task IncrementAsync(string name); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DefaultWorkflowsValidator.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DefaultWorkflowsValidator.cs index 75ddd704b..fec9cfc3d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DefaultWorkflowsValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DefaultWorkflowsValidator.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -25,7 +24,7 @@ namespace Squidex.Domain.Apps.Entities.Contents this.appProvider = appProvider; } - public async Task> ValidateAsync(Guid appId, Workflows workflows) + public async Task> ValidateAsync(DomainId appId, Workflows workflows) { Guard.NotNull(workflows, nameof(workflows)); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DynamicContentWorkflow.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DynamicContentWorkflow.cs index 5c8c0f109..8b13dfe96 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DynamicContentWorkflow.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DynamicContentWorkflow.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; @@ -126,7 +125,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return true; } - private async Task GetWorkflowAsync(Guid appId, Guid schemaId) + private async Task GetWorkflowAsync(DomainId appId, DomainId schemaId) { Workflow? result = null; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs index 6437d3fb5..673fa478b 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs @@ -107,7 +107,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return resolver.Resolve>().Value.DefaultPageSizeGraphQl; } - private static object CreateCacheKey(Guid appId, string etag) + private static object CreateCacheKey(DomainId appId, string etag) { return $"GraphQLModel_{appId}_{etag}"; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs index b6311e0ce..c29683b73 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -15,6 +14,7 @@ using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types; using Squidex.Domain.Apps.Entities.Contents.Queries; +using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Log; @@ -22,8 +22,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { public sealed class GraphQLExecutionContext : QueryExecutionContext { - private static readonly List EmptyAssets = new List(); - private static readonly List EmptyContents = new List(); + private static readonly IReadOnlyList EmptyAssets = new List(); + private static readonly IReadOnlyList EmptyContents = new List(); private readonly IDataLoaderContextAccessor dataLoaderContextAccessor; private readonly IDependencyResolver resolver; @@ -56,14 +56,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL execution.UserContext = this; } - public override async Task FindAssetAsync(Guid id) + public override async Task FindAssetAsync(DomainId id) { var dataLoader = GetAssetsLoader(); return await dataLoader.LoadAsync(id); } - public async Task FindContentAsync(Guid id) + public async Task FindContentAsync(DomainId id) { var dataLoader = GetContentsLoader(); @@ -98,39 +98,39 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return await dataLoader.LoadManyAsync(ids); } - private IDataLoader GetAssetsLoader() + private IDataLoader GetAssetsLoader() { - return dataLoaderContextAccessor.Context.GetOrAddBatchLoader("Assets", + return dataLoaderContextAccessor.Context.GetOrAddBatchLoader("Assets", async batch => { - var result = await GetReferencedAssetsAsync(new List(batch)); + var result = await GetReferencedAssetsAsync(new List(batch)); return result.ToDictionary(x => x.Id); }); } - private IDataLoader GetContentsLoader() + private IDataLoader GetContentsLoader() { - return dataLoaderContextAccessor.Context.GetOrAddBatchLoader("References", + return dataLoaderContextAccessor.Context.GetOrAddBatchLoader("References", async batch => { - var result = await GetReferencedContentsAsync(new List(batch)); + var result = await GetReferencedContentsAsync(new List(batch)); return result.ToDictionary(x => x.Id); }); } - private static ICollection? ParseIds(IJsonValue value) + private static ICollection? ParseIds(IJsonValue value) { try { - var result = new List(); + var result = new List(); if (value is JsonArray array) { foreach (var id in array) { - result.Add(Guid.Parse(id.ToString())); + result.Add(id.ToString()); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs index 8bdfc9219..500f41e80 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -28,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { public sealed class GraphQLModel : IGraphModel { - private readonly Dictionary contentTypes = new Dictionary(); + private readonly Dictionary contentTypes = new Dictionary(); private readonly PartitionResolver partitionResolver; private readonly IAppEntity app; private readonly IObjectGraphType assetType; @@ -99,7 +98,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { var context = (GraphQLExecutionContext)c.UserContext; - return context.UrlGenerator.AssetContent(c.Source.Id); + return context.UrlGenerator.AssetContent(c.Source.AppId, c.Source.Id); }); return resolver; @@ -111,7 +110,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { var context = (GraphQLExecutionContext)c.UserContext; - return context.UrlGenerator.AssetSource(c.Source.Id, c.Source.FileVersion); + return context.UrlGenerator.AssetSource(c.Source.AppId, c.Source.Id, c.Source.FileVersion); }); return resolver; @@ -123,7 +122,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { var context = (GraphQLExecutionContext)c.UserContext; - return context.UrlGenerator.AssetThumbnail(c.Source.Id, c.Source.Type); + return context.UrlGenerator.AssetThumbnail(c.Source.AppId, c.Source.Id, c.Source.Type); }); return resolver; @@ -156,7 +155,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return assetType as IObjectGraphType; } - public IObjectGraphType GetContentType(Guid schemaId) + public IObjectGraphType GetContentType(DomainId schemaId) { return contentTypes.GetOrDefault(schemaId); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs index 01e8ee4fc..e6b79c0d9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs @@ -5,13 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using GraphQL.Resolvers; using GraphQL.Types; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types; using Squidex.Domain.Apps.Entities.Schemas; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { @@ -31,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL IObjectGraphType GetAssetType(); - IObjectGraphType GetContentType(Guid schemaId); + IObjectGraphType GetContentType(DomainId schemaId); (IGraphType?, ValueResolver?, QueryArguments?) GetGraphType(ISchemaEntity schema, IField field, string fieldName); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AllTypes.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AllTypes.cs index 57ac5c124..1e6ed30e3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AllTypes.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AllTypes.cs @@ -22,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types public static readonly IGraphType Int = new IntGraphType(); - public static readonly IGraphType Guid = new GuidGraphType2(); + public static readonly IGraphType DomainId = new StringGraphType(); public static readonly IGraphType Date = new InstantGraphType(); @@ -38,7 +38,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types public static readonly IGraphType NonNullInt = new NonNullGraphType(Int); - public static readonly IGraphType NonNullGuid = new NonNullGraphType(Guid); + public static readonly IGraphType NonNullDomainId = new NonNullGraphType(DomainId); public static readonly IGraphType NonNullDate = new NonNullGraphType(Date); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppQueriesGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppQueriesGraphType.cs index b079e203e..217873bc3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppQueriesGraphType.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppQueriesGraphType.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using GraphQL.Resolvers; using GraphQL.Types; using Squidex.Domain.Apps.Entities.Schemas; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types { @@ -48,7 +49,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types ResolvedType = assetType, Resolver = ResolveAsync((c, e) => { - var assetId = c.GetArgument("id"); + var assetId = c.GetArgument("id"); return e.FindAssetAsync(assetId); }), @@ -65,7 +66,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types ResolvedType = contentType, Resolver = ResolveAsync((c, e) => { - var contentId = c.GetArgument("id"); + var contentId = c.GetArgument("id"); return e.FindContentAsync(contentId); }), @@ -104,7 +105,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types }); } - private void AddContentQueries(Guid schemaId, string schemaType, string schemaName, IGraphType contentType, int pageSize) + private void AddContentQueries(DomainId schemaId, string schemaType, string schemaName, IGraphType contentType, int pageSize) { AddField(new FieldType { @@ -142,9 +143,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types new QueryArgument(AllTypes.None) { Name = "id", - Description = "The id of the asset (GUID).", + Description = "The id of the asset (DomainId).", DefaultValue = string.Empty, - ResolvedType = AllTypes.NonNullGuid + ResolvedType = AllTypes.NonNullDomainId } }; } @@ -156,9 +157,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types new QueryArgument(AllTypes.None) { Name = "id", - Description = $"The id of the {schemaName} content (GUID)", + Description = $"The id of the {schemaName} content (DomainId)", DefaultValue = string.Empty, - ResolvedType = AllTypes.NonNullGuid + ResolvedType = AllTypes.NonNullDomainId } }; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AssetGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AssetGraphType.cs index 66b3d5728..a30181cc3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AssetGraphType.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AssetGraphType.cs @@ -23,7 +23,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types AddField(new FieldType { Name = "id", - ResolvedType = AllTypes.NonNullGuid, + ResolvedType = AllTypes.NonNullDomainId, Resolver = Resolve(x => x.Id.ToString()), Description = "The id of the asset." }); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentGraphType.cs index 4305893e2..3f7c269fe 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentGraphType.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentGraphType.cs @@ -33,7 +33,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types AddField(new FieldType { Name = "id", - ResolvedType = AllTypes.NonNullGuid, + ResolvedType = AllTypes.NonNullDomainId, Resolver = Resolve(x => x.Id), Description = $"The id of the {schemaName} content." }); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentInterfaceGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentInterfaceGraphType.cs index 32e0657b5..7b188603a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentInterfaceGraphType.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentInterfaceGraphType.cs @@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types AddField(new FieldType { Name = "id", - ResolvedType = AllTypes.NonNullGuid, + ResolvedType = AllTypes.NonNullDomainId, Resolver = Resolve(x => x.Id), Description = "The id of the content." }); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentUnionGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentUnionGraphType.cs index fdd52734d..f5e682425 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentUnionGraphType.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentUnionGraphType.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using GraphQL.Types; @@ -15,9 +14,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types { public sealed class ContentUnionGraphType : UnionGraphType { - private readonly Dictionary types = new Dictionary(); + private readonly Dictionary types = new Dictionary(); - public ContentUnionGraphType(string fieldName, Dictionary schemaTypes, IEnumerable? schemaIds) + public ContentUnionGraphType(string fieldName, Dictionary schemaTypes, IEnumerable? schemaIds) { Name = $"{fieldName}ReferenceUnionDto"; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs index 3efa4bdaa..80b6abe21 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using GraphQL.Types; @@ -21,14 +20,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types public sealed class QueryGraphTypeVisitor : IFieldVisitor<(IGraphType?, ValueResolver?, QueryArguments?)> { private static readonly ValueResolver NoopResolver = (value, c) => value; - private readonly Dictionary schemaTypes; + private readonly Dictionary schemaTypes; private readonly ISchemaEntity schema; private readonly IGraphModel model; private readonly IGraphType assetListType; private readonly string fieldName; public QueryGraphTypeVisitor(ISchemaEntity schema, - Dictionary schemaTypes, + Dictionary schemaTypes, IGraphModel model, IGraphType assetListType, string fieldName) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Utils/GuidGraphType2.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Utils/GuidGraphType2.cs deleted file mode 100644 index a19703dbd..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Utils/GuidGraphType2.cs +++ /dev/null @@ -1,55 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using GraphQL.Language.AST; -using GraphQL.Types; - -namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Utils -{ - public sealed class GuidGraphType2 : ScalarGraphType - { - public GuidGraphType2() - { - Name = "Guid"; - - Description = "The `Guid` scalar type global unique identifier"; - } - - public override object? Serialize(object value) - { - return ParseValue(value)?.ToString(); - } - - public override object? ParseValue(object value) - { - if (value is Guid guid) - { - return guid; - } - - var inputValue = value?.ToString()?.Trim('"'); - - if (Guid.TryParse(inputValue, out guid)) - { - return guid; - } - - return null; - } - - public override object? ParseLiteral(IValue value) - { - if (value is StringValue stringValue) - { - return ParseValue(stringValue.Value); - } - - return null; - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentEntity.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentEntity.cs index 95f72e6c3..b2271c7ae 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentEntity.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentEntity.cs @@ -6,7 +6,6 @@ // ========================================================================== // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Contents; using Squidex.Infrastructure; @@ -18,9 +17,9 @@ namespace Squidex.Domain.Apps.Entities.Contents IEntityWithLastModifiedBy, IEntityWithVersion { - NamedId AppId { get; } + NamedId AppId { get; } - NamedId SchemaId { get; } + NamedId SchemaId { get; } Status? NewStatus { get; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentLoader.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentLoader.cs index 664fdde45..ddb4d22bb 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentLoader.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentLoader.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Squidex.Infrastructure; @@ -13,6 +12,6 @@ namespace Squidex.Domain.Apps.Entities.Contents { public interface IContentLoader { - Task GetAsync(Guid id, long version = EtagVersion.Any); + Task GetAsync(DomainId appId, DomainId id, long version = EtagVersion.Any); } } \ No newline at end of file diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs index 62607cd06..0e1777fb9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Schemas; @@ -15,11 +14,11 @@ namespace Squidex.Domain.Apps.Entities.Contents { public interface IContentQueryService { - Task> QueryAsync(Context context, IReadOnlyList ids); + Task> QueryAsync(Context context, IReadOnlyList ids); Task> QueryAsync(Context context, string schemaIdOrName, Q query); - Task FindContentAsync(Context context, string schemaIdOrName, Guid id, long version = EtagVersion.Any); + Task FindContentAsync(Context context, string schemaIdOrName, DomainId id, long version = EtagVersion.Any); Task GetSchemaOrThrowAsync(Context context, string schemaIdOrName); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/IWorkflowsValidator.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/IWorkflowsValidator.cs index 01c8574b4..589000e35 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/IWorkflowsValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/IWorkflowsValidator.cs @@ -5,15 +5,15 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents { public interface IWorkflowsValidator { - Task> ValidateAsync(Guid appId, Workflows workflows); + Task> ValidateAsync(DomainId appId, Workflows workflows); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs index 925cdc1b2..d844c2c5d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs @@ -78,9 +78,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries results.Add(result); } - var schemaCache = new Dictionary>(); + var schemaCache = new Dictionary>(); - Task GetSchema(Guid id) + Task GetSchema(DomainId id) { return schemaCache.GetOrAdd(id, x => ContentQuery.GetSchemaOrThrowAsync(context, x.ToString())); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentLoader.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentLoader.cs index c29116b5d..98abc2384 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentLoader.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentLoader.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Orleans; using Squidex.Infrastructure; @@ -24,11 +23,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries this.grainFactory = grainFactory; } - public async Task GetAsync(Guid id, long version) + public async Task GetAsync(DomainId appId, DomainId id, long version) { using (Profiler.TraceMethod()) { - var contentGrain = grainFactory.GetGrain(id); + var key = DomainId.Combine(appId, id).ToString(); + + var contentGrain = grainFactory.GetGrain(key); var contentState = await contentGrain.GetStateAsync(version); var content = contentState.Value; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs index 039456f88..b264c8bff 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs @@ -50,7 +50,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries this.queryParser = queryParser; } - public async Task FindContentAsync(Context context, string schemaIdOrName, Guid id, long version = -1) + public async Task FindContentAsync(Context context, string schemaIdOrName, DomainId id, long version = -1) { Guard.NotNull(context, nameof(context)); @@ -64,7 +64,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries if (version > EtagVersion.Empty) { - content = await FindByVersionAsync(id, version); + content = await FindByVersionAsync(context, id, version); } else { @@ -105,7 +105,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries } } - public async Task> QueryAsync(Context context, IReadOnlyList ids) + public async Task> QueryAsync(Context context, IReadOnlyList ids) { Guard.NotNull(context, nameof(context)); @@ -156,9 +156,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { ISchemaEntity? schema = null; - if (Guid.TryParse(schemaIdOrName, out var id)) + if (Guid.TryParse(schemaIdOrName, out var guid)) { - schema = await appProvider.GetSchemaAsync(context.App.Id, id); + schema = await appProvider.GetSchemaAsync(context.App.Id, guid); } if (schema == null) @@ -185,7 +185,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries } } - private static IEnumerable FilterContents(IGrouping group, Context context) + private static IEnumerable FilterContents(IGrouping group, Context context) { var schema = group.First().Schema; @@ -220,9 +220,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries return contents.SortSet(x => x.Id, query.Ids); } - private Task> QueryCoreAsync(Context context, IReadOnlyList ids) + private Task> QueryCoreAsync(Context context, IReadOnlyList ids) { - return contentRepository.QueryAsync(context.App, new HashSet(ids), context.Scope()); + return contentRepository.QueryAsync(context.App, new HashSet(ids), context.Scope()); } private Task> QueryCoreAsync(Context context, ISchemaEntity schema, ClrQuery query) @@ -230,19 +230,19 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries return contentRepository.QueryAsync(context.App, schema, query, context.Scope()); } - private Task> QueryCoreAsync(Context context, ISchemaEntity schema, HashSet ids) + private Task> QueryCoreAsync(Context context, ISchemaEntity schema, HashSet ids) { return contentRepository.QueryAsync(context.App, schema, ids, context.Scope()); } - private Task FindCoreAsync(Context context, Guid id, ISchemaEntity schema) + private Task FindCoreAsync(Context context, DomainId id, ISchemaEntity schema) { return contentRepository.FindContentAsync(context.App, schema, id, context.Scope()); } - private Task FindByVersionAsync(Guid id, long version) + private Task FindByVersionAsync(Context context, DomainId id, long version) { - return contentVersionLoader.GetAsync(id, version); + return contentVersionLoader.GetAsync(context.App.Id, id, version); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/FilterTagTransformer.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/FilterTagTransformer.cs index bc79d824e..954844bc5 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/FilterTagTransformer.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/FilterTagTransformer.cs @@ -20,16 +20,16 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { private readonly ITagService tagService; private readonly ISchemaEntity schema; - private readonly Guid appId; + private readonly DomainId appId; - private FilterTagTransformer(Guid appId, ISchemaEntity schema, ITagService tagService) + private FilterTagTransformer(DomainId appId, ISchemaEntity schema, ITagService tagService) { this.appId = appId; this.schema = schema; this.tagService = tagService; } - public static ValueTask?> TransformAsync(FilterNode nodeIn, Guid appId, ISchemaEntity schema, ITagService tagService) + public static ValueTask?> TransformAsync(FilterNode nodeIn, DomainId appId, ISchemaEntity schema, ITagService tagService) { Guard.NotNull(nodeIn, nameof(nodeIn)); Guard.NotNull(tagService, nameof(tagService)); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/IContentEnricherStep.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/IContentEnricherStep.cs index c750f3902..82ab79b5a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/IContentEnricherStep.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/IContentEnricherStep.cs @@ -5,14 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Schemas; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Queries { - public delegate Task ProvideSchema(Guid id); + public delegate Task ProvideSchema(DomainId id); public interface IContentEnricherStep { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/QueryExecutionContext.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/QueryExecutionContext.cs index 5e00eaf6a..f3ae8cfa7 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/QueryExecutionContext.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/QueryExecutionContext.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -17,8 +16,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { public class QueryExecutionContext { - private readonly ConcurrentDictionary cachedContents = new ConcurrentDictionary(); - private readonly ConcurrentDictionary cachedAssets = new ConcurrentDictionary(); + private readonly ConcurrentDictionary cachedContents = new ConcurrentDictionary(); + private readonly ConcurrentDictionary cachedAssets = new ConcurrentDictionary(); private readonly IContentQueryService contentQuery; private readonly IAssetQueryService assetQuery; private readonly Context context; @@ -39,7 +38,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries this.context = context; } - public virtual async Task FindAssetAsync(Guid id) + public virtual async Task FindAssetAsync(DomainId id) { var asset = cachedAssets.GetOrDefault(id); @@ -56,7 +55,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries return asset; } - public virtual async Task FindContentAsync(Guid schemaId, Guid id) + public virtual async Task FindContentAsync(DomainId schemaId, DomainId id) { var content = cachedContents.GetOrDefault(id); @@ -97,11 +96,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries return result; } - public virtual async Task> GetReferencedAssetsAsync(ICollection ids) + public virtual async Task> GetReferencedAssetsAsync(ICollection ids) { Guard.NotNull(ids, nameof(ids)); - var notLoadedAssets = new HashSet(ids.Where(id => !cachedAssets.ContainsKey(id))); + var notLoadedAssets = new HashSet(ids.Where(id => !cachedAssets.ContainsKey(id))); if (notLoadedAssets.Count > 0) { @@ -116,7 +115,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries return ids.Select(cachedAssets.GetOrDefault).NotNull().ToList(); } - public virtual async Task> GetReferencedContentsAsync(ICollection ids) + public virtual async Task> GetReferencedContentsAsync(ICollection ids) { Guard.NotNull(ids, nameof(ids)); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs index 698adb036..de4b59a89 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs @@ -5,13 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.ConvertContent; using Squidex.Domain.Apps.Core.ExtractReferenceIds; +using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Infrastructure; @@ -38,8 +38,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps public async Task EnrichAsync(Context context, IEnumerable contents, ProvideSchema schemas) { - var resolveDataDraft = context.ShouldProvideUnpublished() || context.IsFrontendClient; - var referenceCleaner = await CleanReferencesAsync(context, contents, schemas); var converters = GenerateConverters(context, referenceCleaner).ToArray(); @@ -59,7 +57,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { if (context.ShouldCleanup()) { - var ids = new HashSet(); + var ids = new HashSet(); foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) { @@ -77,7 +75,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps QueryAssetIdsAsync(context, ids), QueryContentIdsAsync(context, ids)); - var foundIds = new HashSet(assets.Union(refContents)); + var foundIds = assets.Union(refContents).ToHashSet(); return ValueReferencesConverter.CleanReferences(foundIds); } @@ -86,14 +84,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps return null; } - private async Task> QueryContentIdsAsync(Context context, HashSet ids) + private async Task> QueryContentIdsAsync(Context context, HashSet ids) { var result = await contentRepository.QueryIdsAsync(context.App.Id, ids, context.Scope()); return result.Select(x => x.Id); } - private async Task> QueryAssetIdsAsync(Context context, HashSet ids) + private async Task> QueryAssetIdsAsync(Context context, HashSet ids) { var result = await assetRepository.QueryIdsAsync(context.App.Id, ids); @@ -138,7 +136,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps if (assetUrls.Count > 0) { - var resolveAssetUrls = ValueConverters.ResolveAssetUrls(assetUrls, urlGenerator); + var appId = context.App.NamedId(); + + var resolveAssetUrls = ValueConverters.ResolveAssetUrls(appId, assetUrls, urlGenerator); yield return FieldConverters.ForValues(resolveAssetUrls); yield return FieldConverters.ForValues(ValueConverters.ForNested(resolveAssetUrls)); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichForCaching.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichForCaching.cs index b5dc3d10e..f91c3e858 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichForCaching.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichForCaching.cs @@ -41,9 +41,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps foreach (var content in group) { - requestCache.AddDependency(content.Id, content.Version); - requestCache.AddDependency(app.Id, app.Version); - requestCache.AddDependency(schema.Id, schema.Version); + requestCache.AddDependency(content.UniqueId, content.Version); + requestCache.AddDependency(schema.UniqueId, schema.Version); + requestCache.AddDependency(app.UniqueId, app.Version); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichWithWorkflows.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichWithWorkflows.cs index 8deaff880..2fcb1b9e8 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichWithWorkflows.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichWithWorkflows.cs @@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps public async Task EnrichAsync(Context context, IEnumerable contents, ProvideSchema schemas) { - var cache = new Dictionary<(Guid, Status), StatusInfo>(); + var cache = new Dictionary<(DomainId, Status), StatusInfo>(); foreach (var content in contents) { @@ -73,7 +73,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps content.CanUpdate = await contentWorkflow.CanUpdateAsync(content, editingStatus, context.User); } - private async Task EnrichColorAsync(ContentEntity content, ContentEntity result, Dictionary<(Guid, Status), StatusInfo> cache) + private async Task EnrichColorAsync(ContentEntity content, ContentEntity result, Dictionary<(DomainId, Status), StatusInfo> cache) { result.StatusColor = await GetColorAsync(content, content.Status, cache); @@ -88,7 +88,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps } } - private async Task GetColorAsync(IContentEntity content, Status status, Dictionary<(Guid, Status), StatusInfo> cache) + private async Task GetColorAsync(IContentEntity content, Status status, Dictionary<(DomainId, Status), StatusInfo> cache) { if (!cache.TryGetValue((content.SchemaId.Id, status), out var info)) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs index e41056e11..370b63ed3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -24,7 +23,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { public sealed class ResolveAssets : IContentEnricherStep { - private static readonly ILookup EmptyAssets = Enumerable.Empty().ToLookup(x => x.Id); + private static readonly ILookup EmptyAssets = Enumerable.Empty().ToLookup(x => x.Id); private readonly IUrlGenerator urlGenerator; private readonly IAssetQueryService assetQuery; @@ -45,7 +44,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { if (ShouldEnrich(context)) { - var ids = new HashSet(); + var ids = new HashSet(); foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) { @@ -65,16 +64,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps } } - private void ResolveAssetsUrls(ISchemaEntity schema, IGrouping contents, ILookup assets) + private void ResolveAssetsUrls(ISchemaEntity schema, IGrouping contents, ILookup assets) { foreach (var field in schema.SchemaDef.ResolvingAssets()) { foreach (var content in contents) { - if (content.ReferenceData == null) - { - content.ReferenceData = new NamedContentData(); - } + content.ReferenceData ??= new NamedContentData(); var fieldReference = content.ReferenceData.GetOrAdd(field.Name, _ => new ContentFieldData())!; @@ -94,7 +90,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps if (referencedAsset.Type == AssetType.Image) { - var url = urlGenerator.AssetContent(Guid.Parse(referencedAsset.Id.ToString())); + var url = urlGenerator.AssetContent( + referencedAsset.AppId, + referencedAsset.Id); array = JsonValue.Array(url, referencedAsset.FileName); } @@ -103,7 +101,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps array = JsonValue.Array(referencedAsset.FileName); } - requestCache.AddDependency(referencedAsset.Id, referencedAsset.Version); + requestCache.AddDependency(referencedAsset.UniqueId, referencedAsset.Version); fieldReference.AddJsonValue(partitionKey, array); } @@ -113,7 +111,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps } } - private async Task> GetAssetsAsync(Context context, HashSet ids) + private async Task> GetAssetsAsync(Context context, HashSet ids) { if (ids.Count == 0) { @@ -125,7 +123,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps return assets.ToLookup(x => x.Id); } - private void AddAssetIds(HashSet ids, ISchemaEntity schema, IEnumerable contents) + private static void AddAssetIds(HashSet ids, ISchemaEntity schema, IEnumerable contents) { foreach (var content in contents) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveReferences.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveReferences.cs index d81b3cca7..23098cd26 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveReferences.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveReferences.cs @@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { public sealed class ResolveReferences : IContentEnricherStep { - private static readonly ILookup EmptyContents = Enumerable.Empty().ToLookup(x => x.Id); + private static readonly ILookup EmptyContents = Enumerable.Empty().ToLookup(x => x.Id); private readonly Lazy contentQuery; private readonly IRequestCache requestCache; @@ -44,7 +44,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { if (ShouldEnrich(context)) { - var ids = new HashSet(); + var ids = new HashSet(); foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) { @@ -64,7 +64,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps } } - private async Task ResolveReferencesAsync(Context context, ISchemaEntity schema, IEnumerable contents, ILookup references, ProvideSchema schemas) + private async Task ResolveReferencesAsync(Context context, ISchemaEntity schema, IEnumerable contents, ILookup references, ProvideSchema schemas) { var formatted = new Dictionary(); @@ -72,10 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { foreach (var content in contents) { - if (content.ReferenceData == null) - { - content.ReferenceData = new NamedContentData(); - } + content.ReferenceData ??= new NamedContentData(); var fieldReference = content.ReferenceData.GetOrAdd(field.Name, _ => new ContentFieldData())!; @@ -97,8 +94,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps var referencedSchema = await schemas(reference.SchemaId.Id); - requestCache.AddDependency(referencedSchema.Id, referencedSchema.Version); - requestCache.AddDependency(reference.Id, reference.Version); + requestCache.AddDependency(referencedSchema.UniqueId, referencedSchema.Version); + requestCache.AddDependency(reference.UniqueId, reference.Version); var value = formatted.GetOrAdd(reference, x => Format(x, context, referencedSchema)); @@ -140,7 +137,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps return value; } - private void AddReferenceIds(HashSet ids, ISchemaEntity schema, IEnumerable contents) + private static void AddReferenceIds(HashSet ids, ISchemaEntity schema, IEnumerable contents) { foreach (var content in contents) { @@ -148,7 +145,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps } } - private async Task> GetReferencesAsync(Context context, HashSet ids) + private async Task> GetReferencesAsync(Context context, HashSet ids) { if (ids.Count == 0) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs index 2baecf6a9..c67fb4691 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs @@ -36,8 +36,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps if (!string.IsNullOrWhiteSpace(script)) { - var results = new List(); - await Task.WhenAll(group.Select(x => TransformAsync(context, script, x))); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ReferencesFluidExtension.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ReferencesFluidExtension.cs index 9e4bf8511..99431f618 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ReferencesFluidExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ReferencesFluidExtension.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -58,17 +57,14 @@ namespace Squidex.Domain.Apps.Entities.Contents var id = (await arguments[1].Expression.EvaluateAsync(context)).ToStringValue(); - if (Guid.TryParse(id, out var guid)) - { - var references = await contentQueryService.QueryAsync(appContext, new List { guid }); - var reference = references.FirstOrDefault(); + var references = await contentQueryService.QueryAsync(appContext, new List { id }); + var reference = references.FirstOrDefault(); - if (reference != null) - { - var name = (await arguments[0].Expression.EvaluateAsync(context)).ToStringValue(); + if (reference != null) + { + var name = (await arguments[0].Expression.EvaluateAsync(context)).ToStringValue(); - context.SetValue(name, reference); - } + context.SetValue(name, reference); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs index 820d509eb..1561e46e3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs @@ -18,17 +18,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.Repositories { public interface IContentRepository { - Task> QueryAsync(IAppEntity app, HashSet ids, SearchScope scope); + Task> QueryAsync(IAppEntity app, HashSet ids, SearchScope scope); - Task> QueryAsync(IAppEntity app, ISchemaEntity schema, HashSet ids, SearchScope scope); + Task> QueryAsync(IAppEntity app, ISchemaEntity schema, HashSet ids, SearchScope scope); Task> QueryAsync(IAppEntity app, ISchemaEntity schema, ClrQuery query, SearchScope scope); - Task> QueryIdsAsync(Guid appId, Guid schemaId, FilterNode filterNode); + Task> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode filterNode); - Task> QueryIdsAsync(Guid appId, HashSet ids, SearchScope scope); + Task> QueryIdsAsync(DomainId appId, HashSet ids, SearchScope scope); - Task FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id, SearchScope scope); + Task FindContentAsync(IAppEntity app, ISchemaEntity schema, DomainId id, SearchScope scope); Task QueryScheduledWithoutDataAsync(Instant now, Func callback); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs index 6d0c7799c..64c33593d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; using Squidex.Domain.Apps.Core.Contents; using Squidex.Infrastructure; @@ -14,7 +13,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { public sealed class ScheduleJob { - public Guid Id { get; } + public DomainId Id { get; } public Instant DueTime { get; } @@ -22,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Contents public RefToken ScheduledBy { get; } - public ScheduleJob(Guid id, Status status, RefToken scheduledBy, Instant dueTime) + public ScheduleJob(DomainId id, Status status, RefToken scheduledBy, Instant dueTime) { Id = id; ScheduledBy = scheduledBy; @@ -32,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Contents public static ScheduleJob Build(Status status, RefToken scheduledBy, Instant dueTime) { - return new ScheduleJob(Guid.NewGuid(), status, scheduledBy, dueTime); + return new ScheduleJob(DomainId.NewGuid(), status, scheduledBy, dueTime); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs index ca2c8dc7c..09049adfd 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Events.Contents; using Squidex.Infrastructure; @@ -18,9 +17,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.State { public sealed class ContentState : DomainObjectState, IContentEntity { - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } - public NamedId SchemaId { get; set; } + public NamedId SchemaId { get; set; } public ContentVersion? NewVersion { get; set; } @@ -28,6 +27,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.State public ScheduleJob? ScheduleJob { get; set; } + public DomainId UniqueId + { + get { return DomainId.Combine(AppId, Id); } + } + public NamedContentData Data { get { return NewVersion?.Data ?? CurrentVersion.Data; } @@ -54,6 +58,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.State { case ContentCreated e: { + Id = e.ContentId; + SimpleMapper.Map(e, this); CurrentVersion = new ContentVersion(e.Status, e.Data); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Elastic/ElasticSearchTextIndex.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Elastic/ElasticSearchTextIndex.cs index 5d916a770..f2dfa4a8b 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Elastic/ElasticSearchTextIndex.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Elastic/ElasticSearchTextIndex.cs @@ -33,7 +33,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Elastic return Task.CompletedTask; } - public async Task ExecuteAsync(NamedId appId, NamedId schemaId, params IndexCommand[] commands) + public async Task ExecuteAsync(NamedId appId, NamedId schemaId, params IndexCommand[] commands) { foreach (var command in commands) { @@ -52,7 +52,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Elastic } } - private async Task UpsertAsync(NamedId appId, NamedId schemaId, UpsertIndexEntry upsert) + private async Task UpsertAsync(NamedId appId, NamedId schemaId, UpsertIndexEntry upsert) { var data = new { @@ -63,7 +63,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Elastic schemaName = schemaId.Name, serveAll = upsert.ServeAll, servePublished = upsert.ServePublished, - texts = upsert.Texts, + texts = upsert.Texts }; var result = await client.IndexAsync(IndexName, upsert.DocId, CreatePost(data)); @@ -103,7 +103,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Elastic return new SerializableData(data); } - public async Task?> SearchAsync(string? queryText, IAppEntity app, SearchFilter? filter, SearchScope scope) + public async Task?> SearchAsync(string? queryText, IAppEntity app, SearchFilter? filter, SearchScope scope) { var serveField = GetServeField(scope); @@ -178,13 +178,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Elastic throw result.OriginalException; } - var ids = new List(); + var ids = new List(); foreach (var item in result.Body.hits.hits) { if (item != null) { - ids.Add(Guid.Parse(item["_source"]["contentId"])); + ids.Add(item["_source"]["contentId"]); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/ITextIndex.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/ITextIndex.cs index fd4d8c7e9..43922fc27 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/ITextIndex.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/ITextIndex.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Apps; @@ -15,10 +14,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text { public interface ITextIndex { - Task?> SearchAsync(string? queryText, IAppEntity app, SearchFilter? filter, SearchScope scope); + Task?> SearchAsync(string? queryText, IAppEntity app, SearchFilter? filter, SearchScope scope); Task ClearAsync(); - Task ExecuteAsync(NamedId appId, NamedId schemaId, params IndexCommand[] commands); + Task ExecuteAsync(NamedId appId, NamedId schemaId, params IndexCommand[] commands); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/ILuceneTextIndexGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/ILuceneTextIndexGrain.cs index 964a8fa37..fd137d631 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/ILuceneTextIndexGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/ILuceneTextIndexGrain.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Orleans; @@ -14,10 +13,10 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene { - public interface ILuceneTextIndexGrain : IGrainWithGuidKey + public interface ILuceneTextIndexGrain : IGrainWithStringKey { - Task IndexAsync(NamedId schemaId, Immutable updates); + Task IndexAsync(NamedId schemaId, Immutable updates); - Task> SearchAsync(string queryText, SearchFilter? filter, SearchContext context); + Task> SearchAsync(string queryText, SearchFilter? filter, SearchContext context); } } \ No newline at end of file diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/IndexManager.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/IndexManager.cs index 2408b3b7f..b5c86253b 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/IndexManager.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/IndexManager.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -17,7 +16,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene { public sealed partial class IndexManager : DisposableObjectBase { - private readonly Dictionary indices = new Dictionary(); + private readonly Dictionary indices = new Dictionary(); private readonly SemaphoreSlim lockObject = new SemaphoreSlim(1); private readonly IIndexStorage indexStorage; private readonly ISemanticLog log; @@ -45,7 +44,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene return indexStorage.ClearAsync(); } - public async Task AcquireAsync(Guid ownerId) + public async Task AcquireAsync(DomainId ownerId) { IndexHolder? indexHolder; @@ -83,7 +82,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene try { - lockObject.Wait(); + await lockObject.WaitAsync(); indexHolder.Dispose(); indices.Remove(indexHolder.Id); @@ -126,7 +125,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene try { - lockObject.Wait(); + await lockObject.WaitAsync(); indices.Clear(); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/IndexManager_Impl.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/IndexManager_Impl.cs index edb5f0732..8f1b3b9a5 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/IndexManager_Impl.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/IndexManager_Impl.cs @@ -11,6 +11,7 @@ using Lucene.Net.Index; using Lucene.Net.Search; using Lucene.Net.Store; using Lucene.Net.Util; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene { @@ -78,9 +79,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene } } - public Guid Id { get; } + public DomainId Id { get; } - public IndexHolder(Guid id, Directory directory) + public IndexHolder(DomainId id, Directory directory) { Id = id; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/LuceneTextIndex.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/LuceneTextIndex.cs index 623beebbf..486f7214e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/LuceneTextIndex.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/LuceneTextIndex.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Orleans; @@ -36,14 +35,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene return indexManager.ClearAsync(); } - public async Task?> SearchAsync(string? queryText, IAppEntity app, SearchFilter? filter, SearchScope scope) + public async Task?> SearchAsync(string? queryText, IAppEntity app, SearchFilter? filter, SearchScope scope) { if (string.IsNullOrWhiteSpace(queryText)) { return null; } - var index = grainFactory.GetGrain(app.Id); + var index = grainFactory.GetGrain(app.Id.ToString()); using (Profiler.TraceMethod()) { @@ -60,9 +59,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene return new SearchContext { Languages = languages, Scope = scope }; } - public Task ExecuteAsync(NamedId appId, NamedId schemaId, params IndexCommand[] commands) + public Task ExecuteAsync(NamedId appId, NamedId schemaId, params IndexCommand[] commands) { - var index = grainFactory.GetGrain(appId.Id); + var index = grainFactory.GetGrain(appId.Id.ToString()); return index.IndexAsync(schemaId, commands.AsImmutable()); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/LuceneTextIndexGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/LuceneTextIndexGrain.cs index 57cbd81fd..40bf7a916 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/LuceneTextIndexGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/LuceneTextIndexGrain.cs @@ -22,7 +22,7 @@ using Squidex.Infrastructure.Validation; namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene { - public sealed class LuceneTextIndexGrain : GrainOfGuid, ILuceneTextIndexGrain + public sealed class LuceneTextIndexGrain : GrainOfString, ILuceneTextIndexGrain { private const LuceneVersion Version = LuceneVersion.LUCENE_48; private const int MaxResults = 2000; @@ -58,14 +58,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene } } - protected override async Task OnActivateAsync(Guid key) + protected override async Task OnActivateAsync(string key) { index = await indexManager.AcquireAsync(key); } - public Task> SearchAsync(string queryText, SearchFilter? filter, SearchContext context) + public Task> SearchAsync(string queryText, SearchFilter? filter, SearchContext context) { - var result = new List(); + var result = new List(); if (!string.IsNullOrWhiteSpace(queryText)) { @@ -81,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene { var buffer = new BytesRef(2); - var found = new HashSet(); + var found = new HashSet(); foreach (var hit in hits) { @@ -99,16 +99,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene var document = index.Searcher.Doc(hit.Doc); - if (document != null) - { - var idString = document.Get(MetaContentId); + var idString = document?.Get(MetaContentId); - if (Guid.TryParse(idString, out var id)) + if (idString != null) + { + if (found.Add(idString)) { - if (found.Add(id)) - { - result.Add(id); - } + result.Add(idString); } } } @@ -204,7 +201,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene } } - public Task IndexAsync(NamedId schemaId, Immutable updates) + public Task IndexAsync(NamedId schemaId, Immutable updates) { foreach (var command in updates.Value) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/Storage/AssetIndexStorage.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/Storage/AssetIndexStorage.cs index 24703e09f..cce669a76 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/Storage/AssetIndexStorage.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/Storage/AssetIndexStorage.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.IO; using System.IO.Compression; using System.Threading.Tasks; @@ -29,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene.Storage this.assetStore = assetStore; } - public async Task CreateDirectoryAsync(Guid schemaId) + public async Task CreateDirectoryAsync(DomainId schemaId) { var directoryInfo = new DirectoryInfo(Path.Combine(Path.GetTempPath(), "LocalIndices", schemaId.ToString())); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/Storage/FileIndexStorage.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/Storage/FileIndexStorage.cs index b90926c32..5561c9e73 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/Storage/FileIndexStorage.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/Storage/FileIndexStorage.cs @@ -5,18 +5,18 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.IO; using System.Threading.Tasks; using Lucene.Net.Index; using Lucene.Net.Store; +using Squidex.Infrastructure; using LuceneDirectory = Lucene.Net.Store.Directory; namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene.Storage { public sealed class FileIndexStorage : IIndexStorage { - public Task CreateDirectoryAsync(Guid ownerId) + public Task CreateDirectoryAsync(DomainId ownerId) { var folderName = $"Indexes/{ownerId}"; var folderPath = Path.Combine(Path.GetTempPath(), folderName); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/Storage/IIndexStorage.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/Storage/IIndexStorage.cs index 37036c469..097d43502 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/Storage/IIndexStorage.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Lucene/Storage/IIndexStorage.cs @@ -5,16 +5,16 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Lucene.Net.Index; using Lucene.Net.Store; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text.Lucene { public interface IIndexStorage { - Task CreateDirectoryAsync(Guid ownerId); + Task CreateDirectoryAsync(DomainId ownerId); Task WriteAsync(Directory directory, SnapshotDeletionPolicy snapshotter); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/SearchFilter.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/SearchFilter.cs index d34cfff41..a434c69bd 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/SearchFilter.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/SearchFilter.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using Squidex.Infrastructure; @@ -15,11 +14,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text [Equals(DoNotAddEqualityOperators = true)] public sealed class SearchFilter { - public IReadOnlyList SchemaIds { get; } + public IReadOnlyList SchemaIds { get; } public bool Must { get; } - public SearchFilter(IReadOnlyList schemaIds, bool must) + public SearchFilter(IReadOnlyList schemaIds, bool must) { Guard.NotNull(schemaIds, nameof(schemaIds)); @@ -28,17 +27,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text Must = must; } - public static SearchFilter MustHaveSchemas(List schemaIds) + public static SearchFilter MustHaveSchemas(List schemaIds) { return new SearchFilter(schemaIds, true); } - public static SearchFilter MustHaveSchemas(params Guid[] schemaIds) + public static SearchFilter MustHaveSchemas(params DomainId[] schemaIds) { return new SearchFilter(schemaIds?.ToList()!, true); } - public static SearchFilter ShouldHaveSchemas(params Guid[] schemaIds) + public static SearchFilter ShouldHaveSchemas(params DomainId[] schemaIds) { return new SearchFilter(schemaIds?.ToList()!, false); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/CachingTextIndexerState.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/CachingTextIndexerState.cs index 7d057b006..e3cc4883f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/CachingTextIndexerState.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/CachingTextIndexerState.cs @@ -15,7 +15,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.State public sealed class CachingTextIndexerState : ITextIndexerState { private readonly ITextIndexerState inner; - private LRUCache> cache = new LRUCache>(1000); + private LRUCache<(DomainId, DomainId), Tuple> cache = new LRUCache<(DomainId, DomainId), Tuple>(1000); public CachingTextIndexerState(ITextIndexerState inner) { @@ -28,37 +28,37 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.State { await inner.ClearAsync(); - cache = new LRUCache>(1000); + cache = new LRUCache<(DomainId, DomainId), Tuple>(1000); } - public async Task GetAsync(Guid contentId) + public async Task GetAsync(DomainId appId, DomainId contentId) { - if (cache.TryGetValue(contentId, out var value)) + if (cache.TryGetValue((appId, contentId), out var value)) { return value.Item1; } - var result = await inner.GetAsync(contentId); + var result = await inner.GetAsync(appId, contentId); - cache.Set(contentId, Tuple.Create(result)); + cache.Set((appId, contentId), Tuple.Create(result)); return result; } - public Task SetAsync(TextContentState state) + public Task SetAsync(DomainId appId, TextContentState state) { Guard.NotNull(state, nameof(state)); - cache.Set(state.ContentId, Tuple.Create(state)); + cache.Set((appId, state.ContentId), Tuple.Create(state)); - return inner.SetAsync(state); + return inner.SetAsync(appId, state); } - public Task RemoveAsync(Guid contentId) + public Task RemoveAsync(DomainId appId, DomainId contentId) { - cache.Set(contentId, Tuple.Create(null)); + cache.Set((appId, contentId), Tuple.Create(null)); - return inner.RemoveAsync(contentId); + return inner.RemoveAsync(appId, contentId); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/ITextIndexerState.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/ITextIndexerState.cs index b1693a10b..ab46f8fe2 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/ITextIndexerState.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/ITextIndexerState.cs @@ -5,18 +5,18 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text.State { public interface ITextIndexerState { - Task GetAsync(Guid contentId); + Task GetAsync(DomainId appId, DomainId contentId); - Task SetAsync(TextContentState state); + Task SetAsync(DomainId appId, TextContentState state); - Task RemoveAsync(Guid contentId); + Task RemoveAsync(DomainId appId, DomainId contentId); Task ClearAsync(); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/InMemoryTextIndexerState.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/InMemoryTextIndexerState.cs index 017102b36..d7e29576e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/InMemoryTextIndexerState.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/InMemoryTextIndexerState.cs @@ -5,15 +5,15 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text.State { public sealed class InMemoryTextIndexerState : ITextIndexerState { - private readonly Dictionary states = new Dictionary(); + private readonly Dictionary<(DomainId, DomainId), TextContentState> states = new Dictionary<(DomainId, DomainId), TextContentState>(); public Task ClearAsync() { @@ -22,9 +22,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.State return Task.CompletedTask; } - public Task GetAsync(Guid contentId) + public Task GetAsync(DomainId appId, DomainId contentId) { - if (states.TryGetValue(contentId, out var result)) + if (states.TryGetValue((appId, contentId), out var result)) { return Task.FromResult(result); } @@ -32,16 +32,16 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.State return Task.FromResult(null); } - public Task RemoveAsync(Guid contentId) + public Task SetAsync(DomainId appId, TextContentState state) { - states.Remove(contentId); + states[(appId, state.ContentId)] = state; return Task.CompletedTask; } - public Task SetAsync(TextContentState state) + public Task RemoveAsync(DomainId appId, DomainId contentId) { - states[state.ContentId] = state; + states.Remove((appId, contentId)); return Task.CompletedTask; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/TextContentState.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/TextContentState.cs index 3f2bbe07e..a9f371402 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/TextContentState.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/State/TextContentState.cs @@ -5,13 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text.State { public sealed class TextContentState { - public Guid ContentId { get; set; } + public DomainId ContentId { get; set; } public string DocIdCurrent { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexingProcess.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexingProcess.cs index ca4c64fc4..328372e2f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexingProcess.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexingProcess.cs @@ -93,6 +93,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text private async Task CreateAsync(ContentEvent @event, NamedContentData data) { + var appId = @event.AppId.Id; + var state = new TextContentState { ContentId = @event.ContentId @@ -110,24 +112,28 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text Texts = data.ToTexts() }); - await textIndexerState.SetAsync(state); + await textIndexerState.SetAsync(appId, state); } private async Task CreateDraftAsync(ContentEvent @event) { - var state = await textIndexerState.GetAsync(@event.ContentId); + var appId = @event.AppId.Id; + + var state = await textIndexerState.GetAsync(appId, @event.ContentId); if (state != null) { state.GenerateDocIdNew(); - await textIndexerState.SetAsync(state); + await textIndexerState.SetAsync(appId, state); } } private async Task UpdateAsync(ContentEvent @event, NamedContentData data) { - var state = await textIndexerState.GetAsync(@event.ContentId); + var appId = @event.AppId.Id; + + var state = await textIndexerState.GetAsync(appId, @event.ContentId); if (state != null) { @@ -164,15 +170,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text }); } - await textIndexerState.SetAsync(state); + await textIndexerState.SetAsync(appId, state); } } private async Task UnpublishAsync(ContentEvent @event) { - var state = await textIndexerState.GetAsync(@event.ContentId); + var appId = @event.AppId.Id; + + var state = await textIndexerState.GetAsync(appId, @event.ContentId); - if (state != null && state.DocIdForPublished != null) + if (state?.DocIdForPublished != null) { await IndexAsync(@event, new UpdateIndexEntry @@ -184,13 +192,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text state.DocIdForPublished = null; - await textIndexerState.SetAsync(state); + await textIndexerState.SetAsync(appId, state); } } private async Task PublishAsync(ContentEvent @event) { - var state = await textIndexerState.GetAsync(@event.ContentId); + var appId = @event.AppId.Id; + + var state = await textIndexerState.GetAsync(appId, @event.ContentId); if (state != null) { @@ -226,15 +236,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text state.DocIdNew = null; - await textIndexerState.SetAsync(state); + await textIndexerState.SetAsync(appId, state); } } private async Task DeleteDraftAsync(ContentEvent @event) { - var state = await textIndexerState.GetAsync(@event.ContentId); + var appId = @event.AppId.Id; + + var state = await textIndexerState.GetAsync(appId, @event.ContentId); - if (state != null && state.DocIdNew != null) + if (state?.DocIdNew != null) { await IndexAsync(@event, new UpdateIndexEntry @@ -250,13 +262,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text state.DocIdNew = null; - await textIndexerState.SetAsync(state); + await textIndexerState.SetAsync(appId, state); } } private async Task DeleteAsync(ContentEvent @event) { - var state = await textIndexerState.GetAsync(@event.ContentId); + var appId = @event.AppId.Id; + + var state = await textIndexerState.GetAsync(appId, @event.ContentId); if (state != null) { @@ -270,7 +284,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text DocId = state.DocIdNew ?? NotFound }); - await textIndexerState.RemoveAsync(state.ContentId); + await textIndexerState.RemoveAsync(appId, state.ContentId); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/UpsertIndexEntry.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/UpsertIndexEntry.cs index dcff59286..5e2dc914f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/UpsertIndexEntry.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/UpsertIndexEntry.cs @@ -5,8 +5,8 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text { @@ -18,6 +18,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text public bool ServePublished { get; set; } - public Guid ContentId { get; set; } + public DomainId ContentId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Validation/DependencyValidatorsFactory.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Validation/DependencyValidatorsFactory.cs index 324cdc391..adadffb66 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Validation/DependencyValidatorsFactory.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Validation/DependencyValidatorsFactory.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.ValidateContent; @@ -36,7 +35,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Validation { var checkAssets = new CheckAssets(async ids => { - return await assetRepository.QueryAsync(context.AppId.Id, new HashSet(ids)); + return await assetRepository.QueryAsync(context.AppId.Id, new HashSet(ids)); }); yield return new AssetsValidator(assetsField.Properties, checkAssets); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Context.cs b/backend/src/Squidex.Domain.Apps.Entities/Context.cs index d4482fc6b..335250bff 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Context.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Context.cs @@ -26,9 +26,9 @@ namespace Squidex.Domain.Apps.Entities public ClaimsPrincipal User { get; } - public ClaimsPermissions Permissions { get; } = ClaimsPermissions.Empty; + public ClaimsPermissions Permissions { get; } - public bool IsFrontendClient { get; private set; } + public bool IsFrontendClient { get; } public Context(ClaimsPrincipal user) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/DomainObjectState.cs b/backend/src/Squidex.Domain.Apps.Entities/DomainObjectState.cs index 83c55edbf..b0560434a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/DomainObjectState.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/DomainObjectState.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; using Squidex.Domain.Apps.Events; using Squidex.Infrastructure; @@ -14,15 +13,9 @@ using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities { - public abstract class DomainObjectState : - IDomainState, - IEntity, - IEntityWithCreatedBy, - IEntityWithLastModifiedBy, - IEntityWithVersion - where T : class + public abstract class DomainObjectState : IDomainState where T : class { - public Guid Id { get; set; } + public DomainId Id { get; set; } public RefToken CreatedBy { get; set; } @@ -64,7 +57,7 @@ namespace Squidex.Domain.Apps.Entities var headers = @event.Headers; - if (clone.Id == default) + if (clone.Id == DomainId.Empty) { clone.Id = headers.AggregateId(); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/EventStoreInitializer.cs b/backend/src/Squidex.Domain.Apps.Entities/EventStoreInitializer.cs deleted file mode 100644 index abcd8f12a..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/EventStoreInitializer.cs +++ /dev/null @@ -1,34 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System.Threading; -using System.Threading.Tasks; -using Squidex.Domain.Apps.Events; -using Squidex.Infrastructure; -using Squidex.Infrastructure.EventSourcing; - -namespace Squidex.Domain.Apps.Entities -{ - public sealed class EventStoreInitializer : IInitializable - { - private readonly IEventStore eventStore; - - public int Order => 1000; - - public EventStoreInitializer(IEventStore eventStore) - { - Guard.NotNull(eventStore, nameof(eventStore)); - - this.eventStore = eventStore; - } - - public Task InitializeAsync(CancellationToken ct = default) - { - return eventStore.CreateIndexAsync(SquidexHeaders.AppId); - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/History/HistoryEvent.cs b/backend/src/Squidex.Domain.Apps.Entities/History/HistoryEvent.cs index e3a20e89c..524467096 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/History/HistoryEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/History/HistoryEvent.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using NodaTime; using Squidex.Infrastructure; @@ -14,9 +13,9 @@ namespace Squidex.Domain.Apps.Entities.History { public sealed class HistoryEvent { - public Guid Id { get; set; } = Guid.NewGuid(); + public DomainId Id { get; set; } = DomainId.NewGuid(); - public Guid AppId { get; set; } + public DomainId AppId { get; set; } public Instant Created { get; set; } @@ -46,14 +45,11 @@ namespace Squidex.Domain.Apps.Entities.History public HistoryEvent Param(string key, object? value) { - if (value != null) - { - var formatted = value.ToString(); + var formatted = value?.ToString(); - if (formatted != null) - { - Parameters[key] = formatted; - } + if (formatted != null) + { + Parameters[key] = formatted; } return this; diff --git a/backend/src/Squidex.Domain.Apps.Entities/History/HistoryService.cs b/backend/src/Squidex.Domain.Apps.Entities/History/HistoryService.cs index 81048ab6d..af33b79fe 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/History/HistoryService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/History/HistoryService.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -88,7 +87,7 @@ namespace Squidex.Domain.Apps.Entities.History } } - public async Task> QueryByChannelAsync(Guid appId, string channelPrefix, int count) + public async Task> QueryByChannelAsync(DomainId appId, string channelPrefix, int count) { var items = await repository.QueryByChannelAsync(appId, channelPrefix, count); diff --git a/backend/src/Squidex.Domain.Apps.Entities/History/IHistoryService.cs b/backend/src/Squidex.Domain.Apps.Entities/History/IHistoryService.cs index 71a307a37..a5a2d7e4e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/History/IHistoryService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/History/IHistoryService.cs @@ -5,14 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.History { public interface IHistoryService { - Task> QueryByChannelAsync(Guid appId, string channelPrefix, int count); + Task> QueryByChannelAsync(DomainId appId, string channelPrefix, int count); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/History/ParsedHistoryEvent.cs b/backend/src/Squidex.Domain.Apps.Entities/History/ParsedHistoryEvent.cs index 047c72796..4ed7c1eaa 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/History/ParsedHistoryEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/History/ParsedHistoryEvent.cs @@ -17,7 +17,7 @@ namespace Squidex.Domain.Apps.Entities.History private readonly HistoryEvent item; private readonly Lazy message; - public Guid Id + public DomainId Id { get { return item.Id; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/History/Repositories/IHistoryEventRepository.cs b/backend/src/Squidex.Domain.Apps.Entities/History/Repositories/IHistoryEventRepository.cs index d9fb04e2b..6401a2d1d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/History/Repositories/IHistoryEventRepository.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/History/Repositories/IHistoryEventRepository.cs @@ -5,15 +5,15 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.History.Repositories { public interface IHistoryEventRepository { - Task> QueryByChannelAsync(Guid appId, string channelPrefix, int count); + Task> QueryByChannelAsync(DomainId appId, string channelPrefix, int count); Task InsertAsync(HistoryEvent item); diff --git a/backend/src/Squidex.Domain.Apps.Entities/IAppCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/IAppCommand.cs index 6a7bcf31b..fdb2e1459 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/IAppCommand.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/IAppCommand.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -13,6 +12,6 @@ namespace Squidex.Domain.Apps.Entities { public interface IAppCommand : ICommand { - NamedId AppId { get; set; } + NamedId AppId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/IAppProvider.cs b/backend/src/Squidex.Domain.Apps.Entities/IAppProvider.cs index bc4dd03ff..5c6d41c14 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/IAppProvider.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/IAppProvider.cs @@ -5,32 +5,32 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Rules; using Squidex.Domain.Apps.Entities.Schemas; +using Squidex.Infrastructure; using Squidex.Infrastructure.Security; namespace Squidex.Domain.Apps.Entities { public interface IAppProvider { - Task<(IAppEntity?, ISchemaEntity?)> GetAppWithSchemaAsync(Guid appId, Guid id); + Task<(IAppEntity?, ISchemaEntity?)> GetAppWithSchemaAsync(DomainId appId, DomainId id); - Task GetAppAsync(Guid appId); + Task GetAppAsync(DomainId appId); Task GetAppAsync(string appName); Task> GetUserAppsAsync(string userId, PermissionSet permissions); - Task GetSchemaAsync(Guid appId, Guid id, bool allowDeleted = false); + Task GetSchemaAsync(DomainId appId, DomainId id, bool allowDeleted = false); - Task GetSchemaAsync(Guid appId, string name); + Task GetSchemaAsync(DomainId appId, string name); - Task> GetSchemasAsync(Guid appId); + Task> GetSchemasAsync(DomainId appId); - Task> GetRulesAsync(Guid appId); + Task> GetRulesAsync(DomainId appId); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/IEntity.cs b/backend/src/Squidex.Domain.Apps.Entities/IEntity.cs index f58de4d60..2e05b3bfa 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/IEntity.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/IEntity.cs @@ -5,17 +5,19 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities { public interface IEntity { - Guid Id { get; } + DomainId Id { get; } Instant Created { get; } Instant LastModified { get; } + + DomainId UniqueId { get; } } } \ No newline at end of file diff --git a/backend/src/Squidex.Domain.Apps.Entities/ISchemaCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/ISchemaCommand.cs index bd75842d8..41ddd2610 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/ISchemaCommand.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/ISchemaCommand.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -13,6 +12,6 @@ namespace Squidex.Domain.Apps.Entities { public interface ISchemaCommand : ICommand { - NamedId SchemaId { get; set; } + NamedId SchemaId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Q.cs b/backend/src/Squidex.Domain.Apps.Entities/Q.cs index 6737a3c84..e62feeea3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Q.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Q.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using Squidex.Infrastructure; @@ -18,7 +17,7 @@ namespace Squidex.Domain.Apps.Entities { public static readonly Q Empty = new Q(); - public IReadOnlyList Ids { get; private set; } + public IReadOnlyList Ids { get; private set; } public string? ODataQuery { get; private set; } @@ -48,12 +47,12 @@ namespace Squidex.Domain.Apps.Entities return Clone(c => c.ParsedJsonQuery = jsonQuery); } - public Q WithIds(params Guid[] ids) + public Q WithIds(params DomainId[] ids) { return Clone(c => c.Ids = ids.ToList()); } - public Q WithIds(IEnumerable ids) + public Q WithIds(IEnumerable ids) { return Clone(c => c.Ids = ids.ToList()); } @@ -64,14 +63,11 @@ namespace Squidex.Domain.Apps.Entities { return Clone(c => { - var idsList = new List(); + var idsList = new List(); foreach (var id in ids.Split(',')) { - if (Guid.TryParse(id, out var guid)) - { - idsList.Add(guid); - } + idsList.Add(id); } c.Ids = idsList; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/BackupRules.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/BackupRules.cs index c8425f9cc..bff44e872 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/BackupRules.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/BackupRules.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Backup; @@ -18,7 +17,7 @@ namespace Squidex.Domain.Apps.Entities.Rules { public sealed class BackupRules : IBackupHandler { - private readonly HashSet ruleIds = new HashSet(); + private readonly HashSet ruleIds = new HashSet(); private readonly IRulesIndex indexForRules; public string Name { get; } = "Rules"; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Commands/CreateRule.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Commands/CreateRule.cs index 07b49c12b..4c76776c4 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Commands/CreateRule.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Commands/CreateRule.cs @@ -5,18 +5,15 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Rules.Commands { - public sealed class CreateRule : RuleEditCommand, IAppCommand + public sealed class CreateRule : RuleEditCommand { - public NamedId AppId { get; set; } - public CreateRule() { - RuleId = Guid.NewGuid(); + RuleId = DomainId.NewGuid(); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Commands/RuleCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Commands/RuleCommand.cs index 7d8690c46..28499b531 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Commands/RuleCommand.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Commands/RuleCommand.cs @@ -5,18 +5,20 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; namespace Squidex.Domain.Apps.Entities.Rules.Commands { - public abstract class RuleCommand : SquidexCommand, IAggregateCommand + public abstract class RuleCommand : SquidexCommand, IAppCommand, IAggregateCommand { - public Guid RuleId { get; set; } + public NamedId AppId { get; set; } - Guid IAggregateCommand.AggregateId + public DomainId RuleId { get; set; } + + DomainId IAggregateCommand.AggregateId { - get { return RuleId; } + get { return DomainId.Combine(AppId, RuleId); } } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Guards/GuardRule.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Guards/GuardRule.cs index 66a7ae204..aa0034182 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Guards/GuardRule.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Guards/GuardRule.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Rules.Commands; using Squidex.Infrastructure; @@ -45,7 +44,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Guards }); } - public static Task CanUpdate(UpdateRule command, Guid appId, IAppProvider appProvider) + public static Task CanUpdate(UpdateRule command, DomainId appId, IAppProvider appProvider) { Guard.NotNull(command, nameof(command)); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Guards/RuleTriggerValidator.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Guards/RuleTriggerValidator.cs index 3d7841798..465b530fa 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Guards/RuleTriggerValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Guards/RuleTriggerValidator.cs @@ -19,14 +19,14 @@ namespace Squidex.Domain.Apps.Entities.Rules.Guards { public sealed class RuleTriggerValidator : IRuleTriggerVisitor>> { - public Func> SchemaProvider { get; } + public Func> SchemaProvider { get; } - public RuleTriggerValidator(Func> schemaProvider) + public RuleTriggerValidator(Func> schemaProvider) { SchemaProvider = schemaProvider; } - public static Task> ValidateAsync(Guid appId, RuleTrigger action, IAppProvider appProvider) + public static Task> ValidateAsync(DomainId appId, RuleTrigger action, IAppProvider appProvider) { Guard.NotNull(action, nameof(action)); Guard.NotNull(appProvider, nameof(appProvider)); @@ -78,7 +78,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Guards foreach (var schema in trigger.Schemas) { - if (schema.SchemaId == Guid.Empty) + if (schema.SchemaId == DomainId.Empty) { errors.Add(new ValidationError(Not.Defined("Schema id"), nameof(trigger.Schemas))); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/IRuleEnqueuer.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/IRuleEnqueuer.cs index 0a06a363e..1d1ace9c9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/IRuleEnqueuer.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/IRuleEnqueuer.cs @@ -5,15 +5,15 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Rules; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Rules { public interface IRuleEnqueuer { - Task Enqueue(Rule rule, Guid ruleId, Envelope @event); + Task Enqueue(Rule rule, DomainId ruleId, Envelope @event); } } \ No newline at end of file diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/IRuleEntity.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/IRuleEntity.cs index 829f5fb95..ffa3af76b 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/IRuleEntity.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/IRuleEntity.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Rules; using Squidex.Infrastructure; @@ -17,7 +16,7 @@ namespace Squidex.Domain.Apps.Entities.Rules IEntityWithLastModifiedBy, IEntityWithVersion { - NamedId AppId { get; set; } + NamedId AppId { get; set; } Rule RuleDef { get; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/IRulesByAppIndexGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/IRulesByAppIndexGrain.cs index d7eb0223a..0d3825cbf 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/IRulesByAppIndexGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/IRulesByAppIndexGrain.cs @@ -5,13 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Orleans; +using Squidex.Infrastructure; using Squidex.Infrastructure.Orleans.Indexes; namespace Squidex.Domain.Apps.Entities.Rules.Indexes { - public interface IRulesByAppIndexGrain : IIdsIndexGrain, IGrainWithGuidKey + public interface IRulesByAppIndexGrain : IIdsIndexGrain, IGrainWithStringKey { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/IRulesIndex.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/IRulesIndex.cs index 607b56129..8a1995a3c 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/IRulesIndex.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/IRulesIndex.cs @@ -5,16 +5,16 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Rules.Indexes { public interface IRulesIndex { - Task> GetRulesAsync(Guid appId); + Task> GetRulesAsync(DomainId appId); - Task RebuildAsync(Guid appId, HashSet rules); + Task RebuildAsync(DomainId appId, HashSet rules); } } \ No newline at end of file diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesByAppIndexGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesByAppIndexGrain.cs index aa5ad8935..04633ae69 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesByAppIndexGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesByAppIndexGrain.cs @@ -5,14 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Orleans.Indexes; using Squidex.Infrastructure.States; namespace Squidex.Domain.Apps.Entities.Rules.Indexes { - public sealed class RulesByAppIndexGrain : IdsIndexGrain, IRulesByAppIndexGrain + public sealed class RulesByAppIndexGrain : IdsIndexGrain, IRulesByAppIndexGrain { public RulesByAppIndexGrain(IGrainState state) : base(state) @@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes } [CollectionName("Index_RulesByApp")] - public sealed class RulesByAppIndexState : IdsIndexState + public sealed class RulesByAppIndexState : IdsIndexState { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesIndex.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesIndex.cs index f26ba274e..aaa08424c 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesIndex.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesIndex.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -28,12 +27,12 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes this.grainFactory = grainFactory; } - public Task RebuildAsync(Guid appId, HashSet rues) + public Task RebuildAsync(DomainId appId, HashSet rules) { - return Index(appId).RebuildAsync(rues); + return Index(appId).RebuildAsync(rules); } - public async Task> GetRulesAsync(Guid appId) + public async Task> GetRulesAsync(DomainId appId) { using (Profiler.TraceMethod()) { @@ -41,28 +40,28 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes var rules = await Task.WhenAll( - ids.Select(GetRuleAsync)); + ids.Select(x => GetRuleAsync(appId, x))); return rules.NotNull().ToList(); } } - private async Task GetRuleAsync(Guid id) + private async Task GetRuleAsync(DomainId appId, DomainId id) { using (Profiler.TraceMethod()) { - var ruleEntity = await grainFactory.GetGrain(id).GetStateAsync(); + var rule = await GetRuleInternalAsync(appId, id); - if (IsFound(ruleEntity.Value)) + if (IsFound(rule)) { - return ruleEntity.Value; + return rule; } return null; } } - private async Task> GetRuleIdsAsync(Guid appId) + private async Task> GetRuleIdsAsync(DomainId appId) { using (Profiler.TraceMethod()) { @@ -95,19 +94,26 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes private async Task DeleteRuleAsync(DeleteRule command) { - var id = command.RuleId; + var rule = await GetRuleInternalAsync(command.AppId.Id, command.RuleId); - var rule = await grainFactory.GetGrain(id).GetStateAsync(); - - if (IsFound(rule.Value)) + if (IsFound(rule)) { - await Index(rule.Value.AppId.Id).RemoveAsync(id); + await Index(rule.AppId.Id).RemoveAsync(rule.Id); } } - private IRulesByAppIndexGrain Index(Guid appId) + private async Task GetRuleInternalAsync(DomainId appId, DomainId id) + { + var key = DomainId.Combine(appId, id).ToString(); + + var rule = await grainFactory.GetGrain(key).GetStateAsync(); + + return rule.Value; + } + + private IRulesByAppIndexGrain Index(DomainId appId) { - return grainFactory.GetGrain(appId); + return grainFactory.GetGrain(appId.ToString()); } private static bool IsFound(IRuleEntity rule) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Queries/RuleEnricher.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Queries/RuleEnricher.cs index 83b647c5c..ebea6deb9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Queries/RuleEnricher.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Queries/RuleEnricher.cs @@ -62,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Queries foreach (var rule in group) { - requestCache.AddDependency(rule.Id, rule.Version); + requestCache.AddDependency(rule.UniqueId, rule.Version); var statistic = statistics.FirstOrDefault(x => x.RuleId == rule.Id); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Repositories/IRuleEventRepository.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Repositories/IRuleEventRepository.cs index b08673f33..c31d523fa 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Repositories/IRuleEventRepository.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Repositories/IRuleEventRepository.cs @@ -21,16 +21,16 @@ namespace Squidex.Domain.Apps.Entities.Rules.Repositories Task EnqueueAsync(RuleJob job, Instant? nextAttempt, CancellationToken ct = default); - Task EnqueueAsync(Guid id, Instant nextAttempt); + Task EnqueueAsync(DomainId id, Instant nextAttempt); - Task CancelAsync(Guid id); + Task CancelAsync(DomainId id); Task QueryPendingAsync(Instant now, Func callback, CancellationToken ct = default); - Task> QueryStatisticsByAppAsync(Guid appId); + Task> QueryStatisticsByAppAsync(DomainId appId); - Task> QueryByAppAsync(Guid appId, Guid? ruleId = null, int skip = 0, int take = 20); + Task> QueryByAppAsync(DomainId appId, DomainId? ruleId = null, int skip = 0, int take = 20); - Task FindAsync(Guid id); + Task FindAsync(DomainId id); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Repositories/RuleStatistics.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Repositories/RuleStatistics.cs index b4a8f78bb..f9cf7bfb1 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Repositories/RuleStatistics.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Repositories/RuleStatistics.cs @@ -5,16 +5,16 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Rules.Repositories { - public class RuleStatistics + public sealed class RuleStatistics { - public Guid AppId { get; set; } + public DomainId AppId { get; set; } - public Guid RuleId { get; set; } + public DomainId RuleId { get; set; } public int NumSucceeded { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleDequeuerGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleDequeuerGrain.cs index dcbe3a8e1..15b67bd7d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleDequeuerGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleDequeuerGrain.cs @@ -26,7 +26,7 @@ namespace Squidex.Domain.Apps.Entities.Rules private readonly ITargetBlock requestBlock; private readonly IRuleEventRepository ruleEventRepository; private readonly RuleService ruleService; - private readonly ConcurrentDictionary executing = new ConcurrentDictionary(); + private readonly ConcurrentDictionary executing = new ConcurrentDictionary(); private readonly IClock clock; private readonly ISemanticLog log; @@ -112,7 +112,7 @@ namespace Squidex.Domain.Apps.Entities.Rules ExecutionResult = response.Status, Finished = now, JobNext = jobDelay, - JobResult = ComputeJobResult(response.Status, jobDelay) + JobResult = jobResult }; await ruleEventRepository.UpdateAsync(@event.Job, update); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleDomainObject.cs index 3f14da2dd..75e935f9f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleDomainObject.cs @@ -26,7 +26,7 @@ namespace Squidex.Domain.Apps.Entities.Rules private readonly IAppProvider appProvider; private readonly IRuleEnqueuer ruleEnqueuer; - public RuleDomainObject(IStore store, ISemanticLog log, IAppProvider appProvider, IRuleEnqueuer ruleEnqueuer) + public RuleDomainObject(IStore store, ISemanticLog log, IAppProvider appProvider, IRuleEnqueuer ruleEnqueuer) : base(store, log) { Guard.NotNull(appProvider, nameof(appProvider)); @@ -37,10 +37,25 @@ namespace Squidex.Domain.Apps.Entities.Rules this.ruleEnqueuer = ruleEnqueuer; } - public override Task ExecuteAsync(IAggregateCommand command) + protected override bool IsDeleted() { - VerifyNotDeleted(); + return Snapshot.IsDeleted; + } + + protected override bool CanAcceptCreation(ICommand command) + { + return command is RuleCommand; + } + protected override bool CanAccept(ICommand command) + { + return command is RuleCommand ruleCommand && + ruleCommand.AppId.Equals(Snapshot.AppId) && + ruleCommand.RuleId.Equals(Snapshot.Id); + } + + public override Task ExecuteAsync(IAggregateCommand command) + { switch (command) { case CreateRule createRule: @@ -131,20 +146,9 @@ namespace Squidex.Domain.Apps.Entities.Rules private void RaiseEvent(AppEvent @event) { - if (@event.AppId == null) - { - @event.AppId = Snapshot.AppId; - } + @event.AppId ??= Snapshot.AppId; RaiseEvent(Envelope.Create(@event)); } - - private void VerifyNotDeleted() - { - if (Snapshot.IsDeleted) - { - throw new DomainException("Rule has already been deleted."); - } - } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs index d55045c6b..39138fd20 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs @@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Entities.Rules return Task.CompletedTask; } - public async Task Enqueue(Rule rule, Guid ruleId, Envelope @event) + public async Task Enqueue(Rule rule, DomainId ruleId, Envelope @event) { Guard.NotNull(rule, nameof(rule)); Guard.NotNull(@event, nameof(@event)); @@ -109,7 +109,7 @@ namespace Squidex.Domain.Apps.Entities.Rules } } - private Task> GetRulesAsync(Guid appId) + private Task> GetRulesAsync(DomainId appId) { return cache.GetOrCreateAsync(appId, entry => { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleEntity.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleEntity.cs index ec28b184d..0616106fa 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleEntity.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/RuleEntity.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; using Squidex.Domain.Apps.Core.Rules; using Squidex.Infrastructure; @@ -14,11 +13,11 @@ namespace Squidex.Domain.Apps.Entities.Rules { public sealed class RuleEntity : IEnrichedRuleEntity { - public Guid Id { get; set; } + public DomainId Id { get; set; } - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } - public NamedId SchemaId { get; set; } + public NamedId SchemaId { get; set; } public long Version { get; set; } @@ -39,5 +38,10 @@ namespace Squidex.Domain.Apps.Entities.Rules public int NumFailed { get; set; } public Instant? LastExecuted { get; set; } + + public DomainId UniqueId + { + get { return DomainId.Combine(AppId, Id); } + } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/GrainRuleRunnerService.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/GrainRuleRunnerService.cs index 4262ad8cb..7b6fc5fee 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/GrainRuleRunnerService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/GrainRuleRunnerService.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Orleans; using Squidex.Infrastructure; @@ -23,23 +22,23 @@ namespace Squidex.Domain.Apps.Entities.Rules.Runner this.grainFactory = grainFactory; } - public Task CancelAsync(Guid appId) + public Task CancelAsync(DomainId appId) { - var grain = grainFactory.GetGrain(appId); + var grain = grainFactory.GetGrain(appId.ToString()); return grain.CancelAsync(); } - public Task GetRunningRuleIdAsync(Guid appId) + public Task GetRunningRuleIdAsync(DomainId appId) { - var grain = grainFactory.GetGrain(appId); + var grain = grainFactory.GetGrain(appId.ToString()); return grain.GetRunningRuleIdAsync(); } - public Task RunAsync(Guid appId, Guid ruleId) + public Task RunAsync(DomainId appId, DomainId ruleId) { - var grain = grainFactory.GetGrain(appId); + var grain = grainFactory.GetGrain(appId.ToString()); return grain.RunAsync(ruleId); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/IRuleRunnerGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/IRuleRunnerGrain.cs index 0aa9088a0..ba6dadc20 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/IRuleRunnerGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/IRuleRunnerGrain.cs @@ -5,18 +5,18 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Orleans; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Rules.Runner { - public interface IRuleRunnerGrain : IGrainWithGuidKey + public interface IRuleRunnerGrain : IGrainWithStringKey { - Task RunAsync(Guid ruleId); + Task RunAsync(DomainId ruleId); Task CancelAsync(); - Task GetRunningRuleIdAsync(); + Task GetRunningRuleIdAsync(); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/IRuleRunnerService.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/IRuleRunnerService.cs index b5021fcf1..87089a92e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/IRuleRunnerService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/IRuleRunnerService.cs @@ -5,17 +5,17 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Rules.Runner { public interface IRuleRunnerService { - Task RunAsync(Guid appId, Guid ruleId); + Task RunAsync(DomainId appId, DomainId ruleId); - Task CancelAsync(Guid appId); + Task CancelAsync(DomainId appId); - Task GetRunningRuleIdAsync(Guid appId); + Task GetRunningRuleIdAsync(DomainId appId); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/RuleRunnerGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/RuleRunnerGrain.cs index 105f02b87..e439fc8e3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/RuleRunnerGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/RuleRunnerGrain.cs @@ -12,7 +12,6 @@ using Orleans; using Orleans.Runtime; using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Entities.Rules.Repositories; -using Squidex.Domain.Apps.Events; using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.Log; @@ -23,7 +22,7 @@ using Squidex.Infrastructure.Tasks; namespace Squidex.Domain.Apps.Entities.Rules.Runner { - public sealed class RuleRunnerGrain : GrainOfGuid, IRuleRunnerGrain, IRemindable + public sealed class RuleRunnerGrain : GrainOfString, IRuleRunnerGrain, IRemindable { private readonly IGrainState state; private readonly IAppProvider appProvider; @@ -39,7 +38,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Runner [CollectionName("Rules_Runner")] public sealed class State { - public Guid? RuleId { get; set; } + public DomainId? RuleId { get; set; } public string? Position { get; set; } } @@ -70,7 +69,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Runner this.log = log; } - protected override Task OnActivateAsync(Guid key) + protected override Task OnActivateAsync(string key) { EnsureIsRunning(); @@ -100,12 +99,12 @@ namespace Squidex.Domain.Apps.Entities.Rules.Runner return Task.CompletedTask; } - public Task GetRunningRuleIdAsync() + public Task GetRunningRuleIdAsync() { return Task.FromResult(state.Value.RuleId); } - public async Task RunAsync(Guid ruleId) + public async Task RunAsync(DomainId ruleId) { if (currentJobToken != null) { @@ -177,10 +176,10 @@ namespace Squidex.Domain.Apps.Entities.Rules.Runner finally { job.Position = storedEvent.EventPosition; - - await state.WriteAsync(); } - }, SquidexHeaders.AppId, Key.ToString(), job.Position, ct); + + await state.WriteAsync(); + }, $"\\-{Key}", job.Position, ct); } catch (OperationCanceledException) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/State/RuleState.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/State/RuleState.cs index 7a872abc1..232f80c3b 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/State/RuleState.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/State/RuleState.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Events.Rules; using Squidex.Infrastructure; @@ -19,10 +18,15 @@ namespace Squidex.Domain.Apps.Entities.Rules.State [CollectionName("Rules")] public sealed class RuleState : DomainObjectState, IRuleEntity { - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } public Rule RuleDef { get; set; } + public DomainId UniqueId + { + get { return DomainId.Combine(AppId, Id); } + } + public override bool ApplyEvent(IEvent @event) { var previousRule = RuleDef; @@ -31,6 +35,8 @@ namespace Squidex.Domain.Apps.Entities.Rules.State { case RuleCreated e: { + Id = e.RuleId; + RuleDef = new Rule(e.Trigger, e.Action); RuleDef = RuleDef.Rename(e.Name); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/IUsageTrackerGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/IUsageTrackerGrain.cs index 25f42c72e..704b811d6 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/IUsageTrackerGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/IUsageTrackerGrain.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Squidex.Infrastructure; using Squidex.Infrastructure.Orleans; @@ -14,10 +13,10 @@ namespace Squidex.Domain.Apps.Entities.Rules.UsageTracking { public interface IUsageTrackerGrain : IBackgroundGrain { - Task AddTargetAsync(Guid ruleId, NamedId appId, int limits, int? numDays); + Task AddTargetAsync(DomainId ruleId, NamedId appId, int limits, int? numDays); - Task RemoveTargetAsync(Guid ruleId); + Task RemoveTargetAsync(DomainId ruleId); - Task UpdateTargetAsync(Guid ruleId, int limits, int? numDays); + Task UpdateTargetAsync(DomainId ruleId, int limits, int? numDays); } } \ No newline at end of file diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/UsageTrackerGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/UsageTrackerGrain.cs index dd63d0d45..be9da63c6 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/UsageTrackerGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/UsageTrackerGrain.cs @@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.UsageTracking public sealed class Target { - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } public int Limits { get; set; } @@ -40,7 +40,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.UsageTracking [CollectionName("UsageTracker")] public sealed class State { - public Dictionary Targets { get; set; } = new Dictionary(); + public Dictionary Targets { get; set; } = new Dictionary(); } public UsageTrackerGrain(IGrainState state, IApiUsageTracker usageTracker) @@ -119,35 +119,35 @@ namespace Squidex.Domain.Apps.Entities.Rules.UsageTracking } } - public Task AddTargetAsync(Guid ruleId, NamedId appId, int limits, int? numDays) + public Task AddTargetAsync(DomainId ruleId, NamedId appId, int limits, int? numDays) { UpdateTarget(ruleId, t => { t.Limits = limits; t.AppId = appId; t.NumDays = numDays; }); return state.WriteAsync(); } - public Task UpdateTargetAsync(Guid ruleId, int limits, int? numDays) + public Task UpdateTargetAsync(DomainId ruleId, int limits, int? numDays) { UpdateTarget(ruleId, t => { t.Limits = limits; t.NumDays = numDays; }); return state.WriteAsync(); } - public Task AddTargetAsync(Guid ruleId, int limits) + public Task AddTargetAsync(DomainId ruleId, int limits) { UpdateTarget(ruleId, t => t.Limits = limits); return state.WriteAsync(); } - public Task RemoveTargetAsync(Guid ruleId) + public Task RemoveTargetAsync(DomainId ruleId) { state.Value.Targets.Remove(ruleId); return state.WriteAsync(); } - private void UpdateTarget(Guid ruleId, Action updater) + private void UpdateTarget(DomainId ruleId, Action updater) { updater(state.Value.Targets.GetOrAddNew(ruleId)); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/BackupSchemas.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/BackupSchemas.cs index 3767680fc..572246578 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/BackupSchemas.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/BackupSchemas.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Backup; @@ -18,7 +17,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas { public sealed class BackupSchemas : IBackupHandler { - private readonly Dictionary schemasByName = new Dictionary(); + private readonly Dictionary schemasByName = new Dictionary(); private readonly ISchemasIndex indexSchemas; public string Name { get; } = "Schemas"; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ChangeCategory.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ChangeCategory.cs index c6eb7ff18..28ad2e50a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ChangeCategory.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ChangeCategory.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Commands { - public sealed class ChangeCategory : SchemaCommand + public sealed class ChangeCategory : SchemaUpdateCommand { public string Name { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigurePreviewUrls.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigurePreviewUrls.cs index 0ce6dbcf5..b83ea0f1e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigurePreviewUrls.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigurePreviewUrls.cs @@ -9,7 +9,7 @@ using System.Collections.Generic; namespace Squidex.Domain.Apps.Entities.Schemas.Commands { - public sealed class ConfigurePreviewUrls : SchemaCommand + public sealed class ConfigurePreviewUrls : SchemaUpdateCommand { public Dictionary PreviewUrls { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigureScripts.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigureScripts.cs index 5e9528a2c..649890681 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigureScripts.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigureScripts.cs @@ -9,7 +9,7 @@ using Squidex.Domain.Apps.Core.Schemas; namespace Squidex.Domain.Apps.Entities.Schemas.Commands { - public sealed class ConfigureScripts : SchemaCommand + public sealed class ConfigureScripts : SchemaUpdateCommand { public SchemaScripts Scripts { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigureUIFields.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigureUIFields.cs index 9655cdab0..5d9c33211 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigureUIFields.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigureUIFields.cs @@ -9,7 +9,7 @@ using Squidex.Domain.Apps.Core.Schemas; namespace Squidex.Domain.Apps.Entities.Schemas.Commands { - public sealed class ConfigureUIFields : SchemaCommand + public sealed class ConfigureUIFields : SchemaUpdateCommand { public FieldNames? FieldsInLists { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs index cc882abe4..d9272087b 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs @@ -5,28 +5,53 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using System.Collections.Generic; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; +using Squidex.Infrastructure.Commands; +using SchemaFields = System.Collections.Generic.List; namespace Squidex.Domain.Apps.Entities.Schemas.Commands { - public sealed class CreateSchema : UpsertCommand, IAppCommand + public sealed class CreateSchema : SchemaCommand, IUpsertCommand, IAggregateCommand { - public NamedId AppId { get; set; } + public DomainId SchemaId { get; set; } public string Name { get; set; } + public string Category { get; set; } + + public bool IsPublished { get; set; } + public bool IsSingleton { get; set; } + public SchemaFields Fields { get; set; } + + public FieldNames? FieldsInReferences { get; set; } + + public FieldNames? FieldsInLists { get; set; } + + public SchemaScripts? Scripts { get; set; } + + public SchemaProperties Properties { get; set; } + + public Dictionary? PreviewUrls { get; set; } + + public override DomainId AggregateId + { + get { return DomainId.Combine(AppId, SchemaId); } + } + public CreateSchema() { - SchemaId = Guid.NewGuid(); + SchemaId = DomainId.NewGuid(); } - public Schema ToSchema() + public Schema BuildSchema() { - return ToSchema(Name, IsSingleton); + IUpsertCommand self = this; + + return self.ToSchema(Name, IsSingleton); } } } \ No newline at end of file diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/DeleteSchema.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/DeleteSchema.cs index d3b79c454..9733d4f82 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/DeleteSchema.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/DeleteSchema.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Commands { - public sealed class DeleteSchema : SchemaCommand + public sealed class DeleteSchema : SchemaUpdateCommand { } } \ No newline at end of file diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UpsertCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/IUpsertCommand.cs similarity index 86% rename from backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UpsertCommand.cs rename to backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/IUpsertCommand.cs index 1dfcc95d2..4b2ab15bd 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UpsertCommand.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/IUpsertCommand.cs @@ -12,25 +12,25 @@ using SchemaFields = System.Collections.Generic.List? PreviewUrls { get; set; } + Dictionary? PreviewUrls { get; set; } - public Schema ToSchema(string name, bool isSingleton) + Schema ToSchema(string name, bool isSingleton) { var schema = new Schema(name, Properties, isSingleton); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ParentFieldCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ParentFieldCommand.cs index 91f067fb1..69e2425aa 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ParentFieldCommand.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ParentFieldCommand.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Commands { - public abstract class ParentFieldCommand : SchemaCommand + public abstract class ParentFieldCommand : SchemaUpdateCommand { public long? ParentFieldId { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/PublishSchema.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/PublishSchema.cs index c8d68314d..88c6340ef 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/PublishSchema.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/PublishSchema.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Commands { - public sealed class PublishSchema : SchemaCommand + public sealed class PublishSchema : SchemaUpdateCommand { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SchemaCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SchemaCommand.cs index f23581c88..2f31e7da0 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SchemaCommand.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SchemaCommand.cs @@ -1,22 +1,19 @@ // ========================================================================== // Squidex Headless CMS // ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) +// Copyright (c) Squidex UG (haftungsbeschraenkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; namespace Squidex.Domain.Apps.Entities.Schemas.Commands { - public abstract class SchemaCommand : SquidexCommand, IAggregateCommand + public abstract class SchemaCommand : SquidexCommand, IAppCommand, IAggregateCommand { - public Guid SchemaId { get; set; } + public NamedId AppId { get; set; } - Guid IAggregateCommand.AggregateId - { - get { return SchemaId; } - } + public abstract DomainId AggregateId { get; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SchemaUpdateCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SchemaUpdateCommand.cs new file mode 100644 index 000000000..cbd6a5ed6 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SchemaUpdateCommand.cs @@ -0,0 +1,21 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Entities.Schemas.Commands +{ + public abstract class SchemaUpdateCommand : SchemaCommand, ISchemaCommand + { + public NamedId SchemaId { get; set; } + + public override DomainId AggregateId + { + get { return DomainId.Combine(AppId, SchemaId.Id); } + } + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SynchronizeSchema.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SynchronizeSchema.cs index cc185e52b..47a994b76 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SynchronizeSchema.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SynchronizeSchema.cs @@ -5,12 +5,40 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System.Collections.Generic; +using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Infrastructure.Commands; +using SchemaFields = System.Collections.Generic.List; + namespace Squidex.Domain.Apps.Entities.Schemas.Commands { - public sealed class SynchronizeSchema : UpsertCommand + public sealed class SynchronizeSchema : SchemaUpdateCommand, IUpsertCommand, IAggregateCommand, ISchemaCommand { public bool NoFieldDeletion { get; set; } public bool NoFieldRecreation { get; set; } + + public bool IsPublished { get; set; } + + public string Category { get; set; } + + public SchemaFields Fields { get; set; } + + public FieldNames? FieldsInReferences { get; set; } + + public FieldNames? FieldsInLists { get; set; } + + public SchemaScripts? Scripts { get; set; } + + public SchemaProperties Properties { get; set; } + + public Dictionary? PreviewUrls { get; set; } + + public Schema BuildSchema(string name, bool isSingleton) + { + IUpsertCommand self = this; + + return self.ToSchema(name, isSingleton); + } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UnpublishSchema.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UnpublishSchema.cs index 31d5c284a..65b250e02 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UnpublishSchema.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UnpublishSchema.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Commands { - public sealed class UnpublishSchema : SchemaCommand + public sealed class UnpublishSchema : SchemaUpdateCommand { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UpdateSchema.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UpdateSchema.cs index 579f55bb7..a4f23d9f8 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UpdateSchema.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UpdateSchema.cs @@ -9,7 +9,7 @@ using Squidex.Domain.Apps.Core.Schemas; namespace Squidex.Domain.Apps.Entities.Schemas.Commands { - public sealed class UpdateSchema : SchemaCommand + public sealed class UpdateSchema : SchemaUpdateCommand { public SchemaProperties Properties { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchema.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchema.cs index 5ac8e78b5..8552a4500 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchema.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchema.cs @@ -129,7 +129,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards Guard.NotNull(command, nameof(command)); } - private static void ValidateUpsert(UpsertCommand command, AddValidation e) + private static void ValidateUpsert(IUpsertCommand command, AddValidation e) { if (command.Fields?.Count > 0) { @@ -290,7 +290,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards } } - private static void ValidateFieldNames(UpsertCommand command, FieldNames? fields, string path, AddValidation e, Func isAllowed) + private static void ValidateFieldNames(IUpsertCommand command, FieldNames? fields, string path, AddValidation e, Func isAllowed) { if (fields != null) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs index 05b20f405..b9ddbd743 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; @@ -17,7 +16,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas IEntityWithLastModifiedBy, IEntityWithVersion { - NamedId AppId { get; } + NamedId AppId { get; } bool IsDeleted { get; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/ISchemasByAppIndexGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/ISchemasByAppIndexGrain.cs index 7a73fe20d..bc4ec46c8 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/ISchemasByAppIndexGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/ISchemasByAppIndexGrain.cs @@ -5,13 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Orleans; +using Squidex.Infrastructure; using Squidex.Infrastructure.Orleans.Indexes; namespace Squidex.Domain.Apps.Entities.Schemas.Indexes { - public interface ISchemasByAppIndexGrain : IUniqueNameIndexGrain, IGrainWithGuidKey + public interface ISchemasByAppIndexGrain : IUniqueNameIndexGrain, IGrainWithStringKey { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/ISchemasIndex.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/ISchemasIndex.cs index 0031ffe31..ffdb82df8 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/ISchemasIndex.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/ISchemasIndex.cs @@ -5,20 +5,20 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Schemas.Indexes { public interface ISchemasIndex { - Task GetSchemaAsync(Guid appId, Guid id, bool allowDeleted = false); + Task GetSchemaAsync(DomainId appId, DomainId id, bool allowDeleted = false); - Task GetSchemaByNameAsync(Guid appId, string name, bool allowDeleted = false); + Task GetSchemaByNameAsync(DomainId appId, string name, bool allowDeleted = false); - Task> GetSchemasAsync(Guid appId, bool allowDeleted = false); + Task> GetSchemasAsync(DomainId appId, bool allowDeleted = false); - Task RebuildAsync(Guid appId, Dictionary schemas); + Task RebuildAsync(DomainId appId, Dictionary schemas); } } \ No newline at end of file diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasByAppIndexGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasByAppIndexGrain.cs index 81a6e8aa1..d59cb07a3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasByAppIndexGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasByAppIndexGrain.cs @@ -5,14 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Orleans.Indexes; using Squidex.Infrastructure.States; namespace Squidex.Domain.Apps.Entities.Schemas.Indexes { - public sealed class SchemasByAppIndexGrain : UniqueNameIndexGrain, ISchemasByAppIndexGrain + public sealed class SchemasByAppIndexGrain : UniqueNameIndexGrain, ISchemasByAppIndexGrain { public SchemasByAppIndexGrain(IGrainState state) : base(state) @@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes } [CollectionName("Index_SchemasByApp")] - public sealed class SchemasByAppIndexGrainState : UniqueNameIndexState + public sealed class SchemasByAppIndexGrainState : UniqueNameIndexState { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs index c0a7b3ba4..222ac9974 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -29,12 +28,12 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes this.grainFactory = grainFactory; } - public Task RebuildAsync(Guid appId, Dictionary schemas) + public Task RebuildAsync(DomainId appId, Dictionary schemas) { return Index(appId).RebuildAsync(schemas); } - public async Task> GetSchemasAsync(Guid appId, bool allowDeleted = false) + public async Task> GetSchemasAsync(DomainId appId, bool allowDeleted = false) { using (Profiler.TraceMethod()) { @@ -48,13 +47,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes } } - public async Task GetSchemaByNameAsync(Guid appId, string name, bool allowDeleted = false) + public async Task GetSchemaByNameAsync(DomainId appId, string name, bool allowDeleted = false) { using (Profiler.TraceMethod()) { var id = await GetSchemaIdAsync(appId, name); - if (id == default) + if (id == DomainId.Empty) { return null; } @@ -63,22 +62,22 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes } } - public async Task GetSchemaAsync(Guid appId, Guid id, bool allowDeleted = false) + public async Task GetSchemaAsync(DomainId appId, DomainId id, bool allowDeleted = false) { using (Profiler.TraceMethod()) { - var schema = await grainFactory.GetGrain(id).GetStateAsync(); + var schema = await GetSchemaInternalAsync(appId, id); - if (IsFound(schema.Value, allowDeleted)) + if (IsFound(schema, allowDeleted)) { - return schema.Value; + return schema; } return null; } } - private async Task GetSchemaIdAsync(Guid appId, string name) + private async Task GetSchemaIdAsync(DomainId appId, string name) { using (Profiler.TraceMethod()) { @@ -86,7 +85,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes } } - private async Task> GetSchemaIdsAsync(Guid appId) + private async Task> GetSchemaIdsAsync(DomainId appId) { using (Profiler.TraceMethod()) { @@ -158,19 +157,26 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes private async Task DeleteSchemaAsync(DeleteSchema commmand) { - var schemaId = commmand.SchemaId; + var schema = await GetSchemaInternalAsync(commmand.AppId.Id, commmand.SchemaId.Id); - var schema = await grainFactory.GetGrain(schemaId).GetStateAsync(); - - if (IsFound(schema.Value, true)) + if (IsFound(schema, true)) { - await Index(schema.Value.AppId.Id).RemoveAsync(schemaId); + await Index(schema.AppId.Id).RemoveAsync(schema.Id); } } - private ISchemasByAppIndexGrain Index(Guid appId) + private async Task GetSchemaInternalAsync(DomainId appId, DomainId id) + { + var key = DomainId.Combine(appId, id).ToString(); + + var rule = await grainFactory.GetGrain(key).GetStateAsync(); + + return rule.Value; + } + + private ISchemasByAppIndexGrain Index(DomainId appId) { - return grainFactory.GetGrain(appId); + return grainFactory.GetGrain(appId.ToString()); } private static bool IsFound(ISchemaEntity entity, bool allowDeleted) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemaDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemaDomainObject.cs index 24d9659f9..1a59f99bf 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemaDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemaDomainObject.cs @@ -26,15 +26,30 @@ namespace Squidex.Domain.Apps.Entities.Schemas { public class SchemaDomainObject : DomainObject { - public SchemaDomainObject(IStore store, ISemanticLog log) + public SchemaDomainObject(IStore store, ISemanticLog log) : base(store, log) { } - public override Task ExecuteAsync(IAggregateCommand command) + protected override bool IsDeleted() + { + return Snapshot.IsDeleted; + } + + protected override bool CanAcceptCreation(ICommand command) + { + return command is SchemaCommand; + } + + protected override bool CanAccept(ICommand command) { - VerifyNotDeleted(); + return command is SchemaUpdateCommand schemaCommand && + Equals(schemaCommand.AppId, Snapshot.AppId) && + Equals(schemaCommand.SchemaId?.Id, Snapshot.Id); + } + public override Task ExecuteAsync(IAggregateCommand command) + { switch (command) { case AddField addField: @@ -250,7 +265,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas }; var schemaSource = Snapshot.SchemaDef; - var schemaTarget = command.ToSchema(schemaSource.Name, schemaSource.IsSingleton); + var schemaTarget = command.BuildSchema(schemaSource.Name, schemaSource.IsSingleton); var events = schemaSource.Synchronize(schemaTarget, () => Snapshot.SchemaFieldsTotal + 1, options); @@ -262,7 +277,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas public void Create(CreateSchema command) { - RaiseEvent(command, new SchemaCreated { SchemaId = NamedId.Of(command.SchemaId, command.Name), Schema = command.ToSchema() }); + RaiseEvent(command, new SchemaCreated { SchemaId = NamedId.Of(command.SchemaId, command.Name), Schema = command.BuildSchema() }); } public void Add(AddField command) @@ -350,7 +365,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas RaiseEvent(command, new SchemaDeleted()); } - private void RaiseEvent(TCommand command, TEvent @event) where TCommand : SchemaCommand where TEvent : SchemaEvent + private void RaiseEvent(TCommand command, TEvent @event) where TCommand : class where TEvent : SchemaEvent { SimpleMapper.Map(command, @event); @@ -392,15 +407,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas private void RaiseEvent(SchemaEvent @event) { - if (@event.SchemaId == null) - { - @event.SchemaId = Snapshot.NamedId(); - } - - if (@event.AppId == null) - { - @event.AppId = Snapshot.AppId; - } + @event.AppId ??= Snapshot.AppId; + @event.SchemaId ??= Snapshot.NamedId(); RaiseEvent(Envelope.Create(@event)); } @@ -410,14 +418,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas return NamedId.Of(Snapshot.SchemaFieldsTotal + 1, command.Name); } - private void VerifyNotDeleted() - { - if (Snapshot.IsDeleted) - { - throw new DomainException("Schema has already been deleted."); - } - } - public Task> GetStateAsync() { return J.AsTask(Snapshot); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemaExtensions.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemaExtensions.cs index 9d9cb5e29..43000d19c 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemaExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemaExtensions.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; using StaticNamedId = Squidex.Infrastructure.NamedId; @@ -14,7 +13,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas { public static class SchemaExtensions { - public static NamedId NamedId(this ISchemaEntity schema) + public static NamedId NamedId(this ISchemaEntity schema) { return StaticNamedId.Of(schema.Id, schema.SchemaDef.Name); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemasSearchSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemasSearchSource.cs index 81eddcffc..5fb5d33a9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemasSearchSource.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemasSearchSource.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Schemas; @@ -62,14 +61,14 @@ namespace Squidex.Domain.Apps.Entities.Schemas return result; } - private void AddSchemaUrl(SearchResults result, NamedId appId, NamedId schemaId, string name) + private void AddSchemaUrl(SearchResults result, NamedId appId, NamedId schemaId, string name) { var schemaUrl = urlGenerator.SchemaUI(appId, schemaId); result.Add($"{name} Schema", SearchResultType.Schema, schemaUrl); } - private void AddContentsUrl(SearchResults result, NamedId appId, ISchemaEntity schema, NamedId schemaId, string name) + private void AddContentsUrl(SearchResults result, NamedId appId, ISchemaEntity schema, NamedId schemaId, string name) { if (schema.SchemaDef.IsSingleton) { @@ -85,7 +84,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas } } - private static bool HasPermission(Context context, NamedId schemaId) + private static bool HasPermission(Context context, NamedId schemaId) { var permission = Permissions.ForApp(Permissions.AppContentsRead, context.App.Name, schemaId.Name); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs index 06e141d75..361d90b38 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs @@ -20,12 +20,17 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State [CollectionName("Schemas")] public sealed class SchemaState : DomainObjectState, ISchemaEntity { - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } public Schema SchemaDef { get; set; } public long SchemaFieldsTotal { get; set; } + public DomainId UniqueId + { + get { return DomainId.Combine(AppId, Id); } + } + public override bool ApplyEvent(IEvent @event) { var previousSchema = SchemaDef; @@ -34,6 +39,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State { case SchemaCreated e: { + Id = e.SchemaId.Id; + SchemaDef = e.Schema; SchemaFieldsTotal = e.Schema.MaxId(); diff --git a/backend/src/Squidex.Domain.Apps.Entities/SquidexEventEnricher.cs b/backend/src/Squidex.Domain.Apps.Entities/SquidexEventEnricher.cs deleted file mode 100644 index 7e01c2359..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/SquidexEventEnricher.cs +++ /dev/null @@ -1,25 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Events; -using Squidex.Infrastructure.EventSourcing; - -namespace Squidex.Domain.Apps.Entities -{ - public sealed class SquidexEventEnricher : DefaultEventEnricher - { - public override void Enrich(Envelope @event, T id) - { - if (@event.Payload is AppEvent appEvent) - { - @event.SetAppId(appEvent.AppId.Id); - } - - base.Enrich(@event, id); - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Tags/GrainTagService.cs b/backend/src/Squidex.Domain.Apps.Entities/Tags/GrainTagService.cs index 64a1dd13e..333ee66d7 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Tags/GrainTagService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Tags/GrainTagService.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Orleans; @@ -30,42 +29,42 @@ namespace Squidex.Domain.Apps.Entities.Tags this.grainFactory = grainFactory; } - public Task> NormalizeTagsAsync(Guid appId, string group, HashSet? names, HashSet? ids) + public Task> NormalizeTagsAsync(DomainId appId, string group, HashSet? names, HashSet? ids) { return GetGrain(appId, group).NormalizeTagsAsync(names, ids); } - public Task> GetTagIdsAsync(Guid appId, string group, HashSet names) + public Task> GetTagIdsAsync(DomainId appId, string group, HashSet names) { return GetGrain(appId, group).GetTagIdsAsync(names); } - public Task> DenormalizeTagsAsync(Guid appId, string group, HashSet ids) + public Task> DenormalizeTagsAsync(DomainId appId, string group, HashSet ids) { return GetGrain(appId, group).DenormalizeTagsAsync(ids); } - public Task GetTagsAsync(Guid appId, string group) + public Task GetTagsAsync(DomainId appId, string group) { return GetGrain(appId, group).GetTagsAsync(); } - public Task GetExportableTagsAsync(Guid appId, string group) + public Task GetExportableTagsAsync(DomainId appId, string group) { return GetGrain(appId, group).GetExportableTagsAsync(); } - public Task RebuildTagsAsync(Guid appId, string group, TagsExport tags) + public Task RebuildTagsAsync(DomainId appId, string group, TagsExport tags) { return GetGrain(appId, group).RebuildAsync(tags); } - public Task ClearAsync(Guid appId, string group) + public Task ClearAsync(DomainId appId, string group) { return GetGrain(appId, group).ClearAsync(); } - private ITagGrain GetGrain(Guid appId, string group) + private ITagGrain GetGrain(DomainId appId, string group) { Guard.NotNullOrEmpty(group, nameof(group)); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Tags/TagGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Tags/TagGrain.cs index a47a852b2..f6f2d8860 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Tags/TagGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Tags/TagGrain.cs @@ -71,7 +71,7 @@ namespace Squidex.Domain.Apps.Entities.Tags } else { - tagId = Guid.NewGuid().ToString(); + tagId = DomainId.NewGuid().ToString(); state.Value.Tags.Add(tagId, new Tag { Name = tagName }); } diff --git a/backend/src/Squidex.Domain.Apps.Events/AppEvent.cs b/backend/src/Squidex.Domain.Apps.Events/AppEvent.cs index ddf334d26..a3d856c32 100644 --- a/backend/src/Squidex.Domain.Apps.Events/AppEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Events/AppEvent.cs @@ -5,13 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events { public abstract class AppEvent : SquidexEvent { - public NamedId AppId { get; set; } + public NamedId AppId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Events/AppUsageExceeded.cs b/backend/src/Squidex.Domain.Apps.Events/AppUsageExceeded.cs index c7b6c6d8d..e6415c660 100644 --- a/backend/src/Squidex.Domain.Apps.Events/AppUsageExceeded.cs +++ b/backend/src/Squidex.Domain.Apps.Events/AppUsageExceeded.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events @@ -17,6 +17,6 @@ namespace Squidex.Domain.Apps.Events public long CallsLimit { get; set; } - public Guid RuleId { get; set; } + public DomainId RuleId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Events/Apps/AppPatternAdded.cs b/backend/src/Squidex.Domain.Apps.Events/Apps/AppPatternAdded.cs index 8635344e5..7756bebd5 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Apps/AppPatternAdded.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Apps/AppPatternAdded.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Apps @@ -13,7 +13,7 @@ namespace Squidex.Domain.Apps.Events.Apps [EventType(nameof(AppPatternAdded))] public sealed class AppPatternAdded : AppEvent { - public Guid PatternId { get; set; } + public DomainId PatternId { get; set; } public string Name { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Events/Apps/AppPatternDeleted.cs b/backend/src/Squidex.Domain.Apps.Events/Apps/AppPatternDeleted.cs index 3ae54ab42..09988ba1e 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Apps/AppPatternDeleted.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Apps/AppPatternDeleted.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Apps @@ -13,6 +13,6 @@ namespace Squidex.Domain.Apps.Events.Apps [EventType(nameof(AppPatternDeleted))] public sealed class AppPatternDeleted : AppEvent { - public Guid PatternId { get; set; } + public DomainId PatternId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Events/Apps/AppPatternUpdated.cs b/backend/src/Squidex.Domain.Apps.Events/Apps/AppPatternUpdated.cs index cc898cc6c..92d5060e0 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Apps/AppPatternUpdated.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Apps/AppPatternUpdated.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Apps @@ -13,7 +13,7 @@ namespace Squidex.Domain.Apps.Events.Apps [EventType(nameof(AppPatternUpdated))] public sealed class AppPatternUpdated : AppEvent { - public Guid PatternId { get; set; } + public DomainId PatternId { get; set; } public string Name { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowAdded.cs b/backend/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowAdded.cs index 3e5627bee..03ca4f6fc 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowAdded.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowAdded.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Apps @@ -13,7 +13,7 @@ namespace Squidex.Domain.Apps.Events.Apps [EventType(nameof(AppWorkflowAdded))] public sealed class AppWorkflowAdded : AppEvent { - public Guid WorkflowId { get; set; } + public DomainId WorkflowId { get; set; } public string Name { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowDeleted.cs b/backend/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowDeleted.cs index 15d418994..c5a97051c 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowDeleted.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowDeleted.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Apps @@ -13,6 +13,6 @@ namespace Squidex.Domain.Apps.Events.Apps [EventType(nameof(AppWorkflowDeleted))] public sealed class AppWorkflowDeleted : AppEvent { - public Guid WorkflowId { get; set; } + public DomainId WorkflowId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowUpdated.cs b/backend/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowUpdated.cs index 672242ed8..72fc4296e 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowUpdated.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowUpdated.cs @@ -5,8 +5,8 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Apps @@ -14,7 +14,7 @@ namespace Squidex.Domain.Apps.Events.Apps [EventType(nameof(AppWorkflowUpdated))] public sealed class AppWorkflowUpdated : AppEvent { - public Guid WorkflowId { get; set; } + public DomainId WorkflowId { get; set; } public Workflow Workflow { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Events/Assets/AssetCreated.cs b/backend/src/Squidex.Domain.Apps.Events/Assets/AssetCreated.cs index dc646ac0d..96a5ed9bf 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Assets/AssetCreated.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Assets/AssetCreated.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Squidex.Domain.Apps.Core.Assets; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Assets @@ -15,7 +15,7 @@ namespace Squidex.Domain.Apps.Events.Assets [EventType(nameof(AssetCreated), 2)] public sealed class AssetCreated : AssetEvent { - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } public string FileName { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Events/Assets/AssetEvent.cs b/backend/src/Squidex.Domain.Apps.Events/Assets/AssetEvent.cs index 3b6ab77df..29bba3a90 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Assets/AssetEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Assets/AssetEvent.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Assets { public abstract class AssetEvent : AppEvent { - public Guid AssetId { get; set; } + public DomainId AssetId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Events/Assets/AssetFolderCreated.cs b/backend/src/Squidex.Domain.Apps.Events/Assets/AssetFolderCreated.cs index 228dc54dd..ffd53a1ab 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Assets/AssetFolderCreated.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Assets/AssetFolderCreated.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Assets @@ -13,7 +13,7 @@ namespace Squidex.Domain.Apps.Events.Assets [EventType(nameof(AssetFolderCreated))] public sealed class AssetFolderCreated : AssetFolderEvent { - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } public string FolderName { get; set; } } diff --git a/backend/src/Squidex.Domain.Apps.Events/Assets/AssetFolderEvent.cs b/backend/src/Squidex.Domain.Apps.Events/Assets/AssetFolderEvent.cs index 7fc7c5fa6..2a317cc0f 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Assets/AssetFolderEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Assets/AssetFolderEvent.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Assets { public abstract class AssetFolderEvent : AppEvent { - public Guid AssetFolderId { get; set; } + public DomainId AssetFolderId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Events/Assets/AssetFolderMoved.cs b/backend/src/Squidex.Domain.Apps.Events/Assets/AssetFolderMoved.cs index c225ba6e5..3a7711b25 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Assets/AssetFolderMoved.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Assets/AssetFolderMoved.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Assets @@ -13,6 +13,6 @@ namespace Squidex.Domain.Apps.Events.Assets [EventType(nameof(AssetFolderMoved))] public sealed class AssetFolderMoved : AssetFolderEvent { - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Events/Assets/AssetMoved.cs b/backend/src/Squidex.Domain.Apps.Events/Assets/AssetMoved.cs index 9a1ab2cc9..2ee9fba6b 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Assets/AssetMoved.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Assets/AssetMoved.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Assets @@ -13,6 +13,6 @@ namespace Squidex.Domain.Apps.Events.Assets [EventType(nameof(AssetMoved))] public sealed class AssetMoved : AssetEvent { - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Events/Comments/CommentsEvent.cs b/backend/src/Squidex.Domain.Apps.Events/Comments/CommentsEvent.cs index 74c4a68c0..cf8ef7e99 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Comments/CommentsEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Comments/CommentsEvent.cs @@ -5,14 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Comments { public abstract class CommentsEvent : AppEvent { - public string CommentsId { get; set; } + public DomainId CommentsId { get; set; } - public Guid CommentId { get; set; } + public DomainId CommentId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Events/Contents/ContentEvent.cs b/backend/src/Squidex.Domain.Apps.Events/Contents/ContentEvent.cs index 20443dbdf..5fb19ecd2 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Contents/ContentEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Contents/ContentEvent.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Contents { public abstract class ContentEvent : SchemaEvent { - public Guid ContentId { get; set; } + public DomainId ContentId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Events/Rules/RuleEvent.cs b/backend/src/Squidex.Domain.Apps.Events/Rules/RuleEvent.cs index 4e95119fb..781356282 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Rules/RuleEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Events/Rules/RuleEvent.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Rules { public abstract class RuleEvent : AppEvent { - public Guid RuleId { get; set; } + public DomainId RuleId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Events/SchemaEvent.cs b/backend/src/Squidex.Domain.Apps.Events/SchemaEvent.cs index 54b1087dd..6cfd6f67e 100644 --- a/backend/src/Squidex.Domain.Apps.Events/SchemaEvent.cs +++ b/backend/src/Squidex.Domain.Apps.Events/SchemaEvent.cs @@ -5,13 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events { public abstract class SchemaEvent : AppEvent { - public NamedId SchemaId { get; set; } + public NamedId SchemaId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Events/SquidexHeaderExtensions.cs b/backend/src/Squidex.Domain.Apps.Events/SquidexHeaderExtensions.cs deleted file mode 100644 index d4139ae71..000000000 --- a/backend/src/Squidex.Domain.Apps.Events/SquidexHeaderExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using Squidex.Infrastructure.EventSourcing; - -namespace Squidex.Domain.Apps.Events -{ - public static class SquidexHeaderExtensions - { - public static Guid AppId(this EnvelopeHeaders headers) - { - return headers.GetGuid(SquidexHeaders.AppId); - } - - public static Envelope SetAppId(this Envelope envelope, Guid value) where T : class, IEvent - { - envelope.Headers.Add(SquidexHeaders.AppId, value.ToString()); - - return envelope; - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Events/SquidexHeaders.cs b/backend/src/Squidex.Domain.Apps.Events/SquidexHeaders.cs deleted file mode 100644 index e2f610a10..000000000 --- a/backend/src/Squidex.Domain.Apps.Events/SquidexHeaders.cs +++ /dev/null @@ -1,14 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -namespace Squidex.Domain.Apps.Events -{ - public static class SquidexHeaders - { - public static readonly string AppId = "AppId"; - } -} diff --git a/backend/src/Squidex.Domain.Users.MongoDb/MongoKeyStore.cs b/backend/src/Squidex.Domain.Users.MongoDb/MongoKeyStore.cs index db6b2873d..dcc092a5f 100644 --- a/backend/src/Squidex.Domain.Users.MongoDb/MongoKeyStore.cs +++ b/backend/src/Squidex.Domain.Users.MongoDb/MongoKeyStore.cs @@ -93,7 +93,7 @@ namespace Squidex.Domain.Users.MongoDb } else { - throw ex; + throw; } } } diff --git a/backend/src/Squidex.Domain.Users/DefaultUserResolver.cs b/backend/src/Squidex.Domain.Users/DefaultUserResolver.cs index 6dcc88e57..abacbaa8e 100644 --- a/backend/src/Squidex.Domain.Users/DefaultUserResolver.cs +++ b/backend/src/Squidex.Domain.Users/DefaultUserResolver.cs @@ -94,7 +94,6 @@ namespace Squidex.Domain.Users using (var scope = serviceProvider.CreateScope()) { - var userFactory = scope.ServiceProvider.GetRequiredService(); var userManager = scope.ServiceProvider.GetRequiredService>(); return await userManager.FindByIdWithClaimsAsync(id); diff --git a/backend/src/Squidex.Infrastructure.Amazon/Assets/AmazonS3AssetStore.cs b/backend/src/Squidex.Infrastructure.Amazon/Assets/AmazonS3AssetStore.cs index 6e5462c2f..6b8e9b881 100644 --- a/backend/src/Squidex.Infrastructure.Amazon/Assets/AmazonS3AssetStore.cs +++ b/backend/src/Squidex.Infrastructure.Amazon/Assets/AmazonS3AssetStore.cs @@ -193,7 +193,7 @@ namespace Squidex.Infrastructure.Assets using (tempStream) { - await stream.CopyToAsync(tempStream); + await stream.CopyToAsync(tempStream, ct); request.InputStream = tempStream; diff --git a/backend/src/Squidex.Infrastructure.Azure/Assets/AzureBlobAssetStore.cs b/backend/src/Squidex.Infrastructure.Azure/Assets/AzureBlobAssetStore.cs index 63194eacb..780b083ef 100644 --- a/backend/src/Squidex.Infrastructure.Azure/Assets/AzureBlobAssetStore.cs +++ b/backend/src/Squidex.Infrastructure.Azure/Assets/AzureBlobAssetStore.cs @@ -38,7 +38,7 @@ namespace Squidex.Infrastructure.Assets var blobClient = storageAccount.CreateCloudBlobClient(); var blobReference = blobClient.GetContainerReference(containerName); - await blobReference.CreateIfNotExistsAsync(); + await blobReference.CreateIfNotExistsAsync(ct); blobContainer = blobReference; } @@ -70,7 +70,7 @@ namespace Squidex.Infrastructure.Assets { var blob = blobContainer.GetBlockBlobReference(fileName); - await blob.FetchAttributesAsync(); + await blob.FetchAttributesAsync(ct); return blob.Properties.Length; } diff --git a/backend/src/Squidex.Infrastructure.Azure/EventSourcing/CosmosDbEventStore_Reader.cs b/backend/src/Squidex.Infrastructure.Azure/EventSourcing/CosmosDbEventStore_Reader.cs index b5e3e3860..5d46ae803 100644 --- a/backend/src/Squidex.Infrastructure.Azure/EventSourcing/CosmosDbEventStore_Reader.cs +++ b/backend/src/Squidex.Infrastructure.Azure/EventSourcing/CosmosDbEventStore_Reader.cs @@ -10,7 +10,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.Azure.Documents; using Squidex.Infrastructure.Log; namespace Squidex.Infrastructure.EventSourcing @@ -19,7 +18,7 @@ namespace Squidex.Infrastructure.EventSourcing public partial class CosmosDbEventStore : IEventStore, IInitializable { - private static readonly List EmptyEvents = new List(); + private static readonly IReadOnlyList EmptyEvents = new List(); public IEventSubscription CreateSubscription(IEventSubscriber subscriber, string? streamFilter = null, string? position = null) { @@ -30,15 +29,6 @@ namespace Squidex.Infrastructure.EventSourcing return new CosmosDbSubscription(this, subscriber, streamFilter, position); } - public Task CreateIndexAsync(string property) - { - Guard.NotNullOrEmpty(property, nameof(property)); - - ThrowIfDisposed(); - - return Task.CompletedTask; - } - public async Task> QueryLatestAsync(string streamName, int count) { Guard.NotNullOrEmpty(streamName, nameof(streamName)); @@ -126,23 +116,7 @@ namespace Squidex.Infrastructure.EventSourcing } } - public Task QueryAsync(Func callback, string property, object value, string? position = null, CancellationToken ct = default) - { - Guard.NotNull(callback, nameof(callback)); - Guard.NotNullOrEmpty(property, nameof(property)); - Guard.NotNull(value, nameof(value)); - - ThrowIfDisposed(); - - StreamPosition lastPosition = position; - - var filterDefinition = FilterBuilder.CreateByProperty(property, value, lastPosition); - var filterExpression = FilterBuilder.CreateExpression(property, value); - - return QueryAsync(callback, lastPosition, filterDefinition, filterExpression, ct); - } - - public Task QueryAsync(Func callback, string? streamFilter = null, string? position = null, CancellationToken ct = default) + public async Task QueryAsync(Func callback, string? streamFilter = null, string? position = null, CancellationToken ct = default) { Guard.NotNull(callback, nameof(callback)); @@ -153,14 +127,9 @@ namespace Squidex.Infrastructure.EventSourcing var filterDefinition = FilterBuilder.CreateByFilter(streamFilter, lastPosition); var filterExpression = FilterBuilder.CreateExpression(null, null); - return QueryAsync(callback, lastPosition, filterDefinition, filterExpression, ct); - } - - private async Task QueryAsync(Func callback, StreamPosition lastPosition, SqlQuerySpec query, EventPredicate filterExpression, CancellationToken ct = default) - { using (Profiler.TraceMethod()) { - await documentClient.QueryAsync(collectionUri, query, async commit => + await documentClient.QueryAsync(collectionUri, filterDefinition, async commit => { var eventStreamOffset = (int)commit.EventStreamOffset; diff --git a/backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStore.cs b/backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStore.cs index 80503ad0a..2fef85258 100644 --- a/backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStore.cs +++ b/backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStore.cs @@ -21,7 +21,7 @@ namespace Squidex.Infrastructure.EventSourcing { private const int WritePageSize = 500; private const int ReadPageSize = 500; - private static readonly List EmptyEvents = new List(); + private static readonly IReadOnlyList EmptyEvents = new List(); private readonly IEventStoreConnection connection; private readonly IJsonSerializer serializer; private readonly string prefix; @@ -61,29 +61,6 @@ namespace Squidex.Infrastructure.EventSourcing return new GetEventStoreSubscription(connection, subscriber, serializer, projectionClient, position, prefix, streamFilter); } - public Task CreateIndexAsync(string property) - { - Guard.NotNullOrEmpty(property, nameof(property)); - - return projectionClient.CreateProjectionAsync(property, string.Empty); - } - - public async Task QueryAsync(Func callback, string property, object value, string? position = null, CancellationToken ct = default) - { - Guard.NotNull(callback, nameof(callback)); - Guard.NotNullOrEmpty(property, nameof(property)); - Guard.NotNull(value, nameof(value)); - - using (Profiler.TraceMethod()) - { - var streamName = await projectionClient.CreateProjectionAsync(property, value); - - var sliceStart = projectionClient.ParsePosition(position); - - await QueryAsync(callback, streamName, sliceStart, ct); - } - } - public async Task QueryAsync(Func callback, string? streamFilter = null, string? position = null, CancellationToken ct = default) { Guard.NotNull(callback, nameof(callback)); diff --git a/backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionClient.cs b/backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionClient.cs index 3136d7f0d..1911ef4b2 100644 --- a/backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionClient.cs +++ b/backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionClient.cs @@ -38,30 +38,6 @@ namespace Squidex.Infrastructure.EventSourcing return $"by-{prefix.Slugify()}-{filter.Slugify()}"; } - private string CreatePropertyProjectionName(string property) - { - return $"by-{prefix.Slugify()}-{property.Slugify()}-property"; - } - - public async Task CreateProjectionAsync(string property, object value) - { - var name = CreatePropertyProjectionName(property); - - var query = - $@"fromAll() - .when({{ - $any: function (s, e) {{ - if (e.streamId.indexOf('{prefix}') === 0 && e.metadata.{property}) {{ - linkTo('{name}-' + e.metadata.{property}, e); - }} - }} - }});"; - - await CreateProjectionAsync(name, query); - - return $"{name}-{value}"; - } - public async Task CreateProjectionAsync(string? streamFilter = null) { streamFilter ??= ".*"; diff --git a/backend/src/Squidex.Infrastructure.GoogleCloud/Assets/GoogleCloudAssetStore.cs b/backend/src/Squidex.Infrastructure.GoogleCloud/Assets/GoogleCloudAssetStore.cs index b3356a1a2..9116f1475 100644 --- a/backend/src/Squidex.Infrastructure.GoogleCloud/Assets/GoogleCloudAssetStore.cs +++ b/backend/src/Squidex.Infrastructure.GoogleCloud/Assets/GoogleCloudAssetStore.cs @@ -34,7 +34,7 @@ namespace Squidex.Infrastructure.Assets { try { - storageClient = StorageClient.Create(); + storageClient = await StorageClient.CreateAsync(); await storageClient.GetBucketAsync(bucketName, cancellationToken: ct); } diff --git a/backend/src/Squidex.Infrastructure.MongoDb/Assets/MongoGridFsAssetStore.cs b/backend/src/Squidex.Infrastructure.MongoDb/Assets/MongoGridFsAssetStore.cs index 79f45275a..ed2eef507 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/Assets/MongoGridFsAssetStore.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/Assets/MongoGridFsAssetStore.cs @@ -49,7 +49,9 @@ namespace Squidex.Infrastructure.Assets { var name = GetFileName(fileName, nameof(fileName)); - var file = await bucket.Find(Builders>.Filter.Eq(x => x.Id, name)).FirstOrDefaultAsync(); + var find = await bucket.FindAsync(Builders>.Filter.Eq(x => x.Id, name), cancellationToken: ct); + + var file = await find.FirstOrDefaultAsync(ct); if (file == null) { @@ -67,7 +69,7 @@ namespace Squidex.Infrastructure.Assets { var sourceName = GetFileName(sourceFileName, nameof(sourceFileName)); - using (var readStream = await bucket.OpenDownloadStreamAsync(sourceName, cancellationToken: ct)) + await using (var readStream = await bucket.OpenDownloadStreamAsync(sourceName, cancellationToken: ct)) { await UploadAsync(targetFileName, readStream, false, ct); } diff --git a/backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs b/backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs index 191ca742d..c1c1458e6 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs @@ -22,18 +22,7 @@ namespace Squidex.Infrastructure.EventSourcing public partial class MongoEventStore : MongoRepositoryBase, IEventStore { - private static readonly List EmptyEvents = new List(); - - public Task CreateIndexAsync(string property) - { - Guard.NotNullOrEmpty(property, nameof(property)); - - return Collection.Indexes.CreateOneAsync( - new CreateIndexModel( - Index - .Ascending(CreateIndexPath(property)) - .Ascending(TimestampField))); - } + private static readonly IReadOnlyList EmptyEvents = new List(); public IEventSubscription CreateSubscription(IEventSubscriber subscriber, string? streamFilter = null, string? position = null) { @@ -129,21 +118,7 @@ namespace Squidex.Infrastructure.EventSourcing } } - public Task QueryAsync(Func callback, string property, object value, string? position = null, CancellationToken ct = default) - { - Guard.NotNull(callback, nameof(callback)); - Guard.NotNullOrEmpty(property, nameof(property)); - Guard.NotNull(value, nameof(value)); - - StreamPosition lastPosition = position; - - var filterDefinition = CreateFilter(property, value, lastPosition); - var filterExpression = CreateFilterExpression(property, value); - - return QueryAsync(callback, lastPosition, filterDefinition, filterExpression, ct); - } - - public Task QueryAsync(Func callback, string? streamFilter = null, string? position = null, CancellationToken ct = default) + public async Task QueryAsync(Func callback, string? streamFilter = null, string? position = null, CancellationToken ct = default) { Guard.NotNull(callback, nameof(callback)); @@ -152,11 +127,6 @@ namespace Squidex.Infrastructure.EventSourcing var filterDefinition = CreateFilter(streamFilter, lastPosition); var filterExpression = CreateFilterExpression(null, null); - return QueryAsync(callback, lastPosition, filterDefinition, filterExpression, ct); - } - - private async Task QueryAsync(Func callback, StreamPosition lastPosition, EventFilter filterDefinition, EventPredicate filterExpression, CancellationToken ct = default) - { using (Profiler.TraceMethod()) { await Collection.Find(filterDefinition, options: Batching.Options).Sort(Sort.Ascending(TimestampField)).ForEachPipelineAsync(async commit => @@ -188,16 +158,6 @@ namespace Squidex.Infrastructure.EventSourcing } } - private static EventFilter CreateFilter(string property, object value, StreamPosition streamPosition) - { - var filters = new List(); - - AppendByPosition(streamPosition, filters); - AppendByProperty(property, value, filters); - - return Filter.And(filters); - } - private static EventFilter CreateFilter(string? streamFilter, StreamPosition streamPosition) { var filters = new List(); @@ -208,11 +168,6 @@ namespace Squidex.Infrastructure.EventSourcing return Filter.And(filters); } - private static void AppendByProperty(string property, object value, List filters) - { - filters.Add(Filter.Eq(CreateIndexPath(property), value)); - } - private static void AppendByStream(string? streamFilter, List filters) { if (!StreamFilter.IsAll(streamFilter)) @@ -253,10 +208,5 @@ namespace Squidex.Infrastructure.EventSourcing return x => true; } } - - private static string CreateIndexPath(string property) - { - return $"Events.Metadata.{property}"; - } } } \ No newline at end of file diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/DomainIdSerializer.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/DomainIdSerializer.cs new file mode 100644 index 000000000..b4b77117b --- /dev/null +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/DomainIdSerializer.cs @@ -0,0 +1,83 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Threading; +using MongoDB.Bson; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; + +namespace Squidex.Infrastructure.MongoDb +{ + public sealed class DomainIdSerializer : SerializerBase, IBsonPolymorphicSerializer, IRepresentationConfigurable + { + private static int isRegistered; + + public static void Register() + { + if (Interlocked.Increment(ref isRegistered) == 1) + { + try + { + BsonSerializer.RegisterSerializer(new DomainIdSerializer()); + } + catch (BsonSerializationException) + { + return; + } + } + } + + public bool IsDiscriminatorCompatibleWithObjectSerializer + { + get { return true; } + } + + public BsonType Representation { get; } = BsonType.String; + + public override DomainId Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) + { + switch (context.Reader.CurrentBsonType) + { + case BsonType.String: + return DomainId.Create(context.Reader.ReadString()); + case BsonType.Binary: + var binary = context.Reader.ReadBinaryData(); + + if (binary.SubType == BsonBinarySubType.UuidLegacy || + binary.SubType == BsonBinarySubType.UuidStandard) + { + return DomainId.Create(binary.ToGuid()); + } + + return DomainId.Create(binary.ToString()); + default: + throw new NotSupportedException(); + } + } + + public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, DomainId value) + { + context.Writer.WriteString(value.ToString()); + } + + public DomainIdSerializer WithRepresentation(BsonType representation) + { + if (representation != BsonType.String) + { + throw new NotSupportedException(); + } + + return this; + } + + IBsonSerializer IRepresentationConfigurable.WithRepresentation(BsonType representation) + { + return WithRepresentation(representation); + } + } +} diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/IVersionedEntity.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/IVersionedEntity.cs index 2cd118f2f..3b8a3bfbe 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/IVersionedEntity.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/IVersionedEntity.cs @@ -9,7 +9,7 @@ namespace Squidex.Infrastructure.MongoDb { public interface IVersionedEntity { - T Id { get; set; } + T DocumentId { get; set; } long Version { get; set; } } diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/InstantSerializer.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/InstantSerializer.cs index 6979cafe3..2e597bcbf 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/InstantSerializer.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/InstantSerializer.cs @@ -6,6 +6,7 @@ // ========================================================================== using System.Threading; +using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using NodaTime; @@ -14,13 +15,20 @@ namespace Squidex.Infrastructure.MongoDb { public sealed class InstantSerializer : SerializerBase, IBsonPolymorphicSerializer { - private static volatile int isRegistered; + private static int isRegistered; public static void Register() { if (Interlocked.Increment(ref isRegistered) == 1) { - BsonSerializer.RegisterSerializer(new InstantSerializer()); + try + { + BsonSerializer.RegisterSerializer(new InstantSerializer()); + } + catch (BsonSerializationException) + { + return; + } } } diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoEntity.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoEntity.cs index c22eecd22..db978a4e1 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoEntity.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoEntity.cs @@ -5,8 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; -using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using NodaTime; @@ -16,8 +14,7 @@ namespace Squidex.Infrastructure.MongoDb { [BsonId] [BsonElement] - [BsonRepresentation(BsonType.String)] - public Guid Id { get; set; } + public string DocumentId { get; set; } [BsonRequired] [BsonElement] diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs index f6e45c1fb..bab125c23 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs @@ -31,7 +31,9 @@ namespace Squidex.Infrastructure.MongoDb Filter = new BsonDocument("name", collectionName) }; - return (await database.ListCollectionNamesAsync(options)).Any(); + var collections = await database.ListCollectionNamesAsync(options); + + return await collections.AnyAsync(); } public static async Task InsertOneIfNotExistsAsync(this IMongoCollection collection, T document, CancellationToken ct = default) @@ -96,17 +98,17 @@ namespace Squidex.Infrastructure.MongoDb if (oldVersion > EtagVersion.Any) { - await collection.UpdateOneAsync(x => x.Id.Equals(key) && x.Version == oldVersion, update, Upsert); + await collection.UpdateOneAsync(x => x.DocumentId.Equals(key) && x.Version == oldVersion, update, Upsert); } else { - await collection.UpdateOneAsync(x => x.Id.Equals(key), update, Upsert); + await collection.UpdateOneAsync(x => x.DocumentId.Equals(key), update, Upsert); } } catch (MongoWriteException ex) when (ex.WriteError?.Category == ServerErrorCategory.DuplicateKey) { var existingVersion = - await collection.Find(x => x.Id.Equals(key)).Only(x => x.Id, x => x.Version) + await collection.Find(x => x.DocumentId.Equals(key)).Only(x => x.DocumentId, x => x.Version) .FirstOrDefaultAsync(); if (existingVersion != null) @@ -122,25 +124,28 @@ namespace Squidex.Infrastructure.MongoDb } } - public static async Task UpsertVersionedAsync(this IMongoCollection collection, TKey key, long oldVersion, TEntity doc) + public static async Task UpsertVersionedAsync(this IMongoCollection collection, TKey key, long oldVersion, long newVersion, TEntity doc) where TEntity : IVersionedEntity where TKey : notnull { try { + doc.DocumentId = key; + doc.Version = newVersion; + if (oldVersion > EtagVersion.Any) { - await collection.ReplaceOneAsync(x => x.Id.Equals(key) && x.Version == oldVersion, doc, UpsertReplace); + await collection.ReplaceOneAsync(x => x.DocumentId.Equals(key) && x.Version == oldVersion, doc, UpsertReplace); } else { - await collection.ReplaceOneAsync(x => x.Id.Equals(key), doc, UpsertReplace); + await collection.ReplaceOneAsync(x => x.DocumentId.Equals(key), doc, UpsertReplace); } } catch (MongoWriteException ex) when (ex.WriteError?.Category == ServerErrorCategory.DuplicateKey) { var existingVersion = - await collection.Find(x => x.Id.Equals(key)).Only(x => x.Id, x => x.Version) + await collection.Find(x => x.DocumentId.Equals(key)).Only(x => x.DocumentId, x => x.Version) .FirstOrDefaultAsync(); if (existingVersion != null) diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs index 8ca268545..43f462791 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs @@ -54,6 +54,8 @@ namespace Squidex.Infrastructure.MongoDb RefTokenSerializer.Register(); InstantSerializer.Register(); + + DomainIdSerializer.Register(); } protected MongoRepositoryBase(IMongoDatabase database, bool setup = false) diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/RefTokenSerializer.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/RefTokenSerializer.cs index b4c45f945..913be29be 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/RefTokenSerializer.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/RefTokenSerializer.cs @@ -6,6 +6,7 @@ // ========================================================================== using System.Threading; +using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; @@ -13,13 +14,20 @@ namespace Squidex.Infrastructure.MongoDb { public class RefTokenSerializer : ClassSerializerBase { - private static volatile int isRegistered; + private static int isRegistered; public static void Register() { if (Interlocked.Increment(ref isRegistered) == 1) { - BsonSerializer.RegisterSerializer(new RefTokenSerializer()); + try + { + BsonSerializer.RegisterSerializer(new RefTokenSerializer()); + } + catch (BsonSerializationException) + { + return; + } } } diff --git a/backend/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs b/backend/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs index d235d7d85..f34dfe6a1 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs @@ -47,7 +47,7 @@ namespace Squidex.Infrastructure.States using (Profiler.TraceMethod>()) { var existing = - await Collection.Find(x => x.Id.Equals(key)) + await Collection.Find(x => x.DocumentId.Equals(key)) .FirstOrDefaultAsync(); if (existing != null) @@ -79,7 +79,7 @@ namespace Squidex.Infrastructure.States { using (Profiler.TraceMethod>()) { - await Collection.DeleteOneAsync(x => x.Id.Equals(key)); + await Collection.DeleteOneAsync(x => x.DocumentId.Equals(key)); } } } diff --git a/backend/src/Squidex.Infrastructure.MongoDb/States/MongoState.cs b/backend/src/Squidex.Infrastructure.MongoDb/States/MongoState.cs index bbea29936..dfc1687ac 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/States/MongoState.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/States/MongoState.cs @@ -17,7 +17,7 @@ namespace Squidex.Infrastructure.States [BsonId] [BsonElement] [BsonRepresentation(BsonType.String)] - public TKey Id { get; set; } + public TKey DocumentId { get; set; } [BsonRequired] [BsonElement] diff --git a/backend/src/Squidex.Infrastructure/BytesRange.cs b/backend/src/Squidex.Infrastructure/BytesRange.cs index 48585785b..66f8d09e5 100644 --- a/backend/src/Squidex.Infrastructure/BytesRange.cs +++ b/backend/src/Squidex.Infrastructure/BytesRange.cs @@ -9,7 +9,7 @@ using System; namespace Squidex.Infrastructure { - public struct BytesRange + public readonly struct BytesRange { public readonly long? From; diff --git a/backend/src/Squidex.Infrastructure/Caching/IRequestCache.cs b/backend/src/Squidex.Infrastructure/Caching/IRequestCache.cs index d51fb3998..9f3279986 100644 --- a/backend/src/Squidex.Infrastructure/Caching/IRequestCache.cs +++ b/backend/src/Squidex.Infrastructure/Caching/IRequestCache.cs @@ -5,13 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; - namespace Squidex.Infrastructure.Caching { public interface IRequestCache { - void AddDependency(Guid key, long version); + void AddDependency(DomainId key, long version); void AddDependency(object? value); diff --git a/backend/src/Squidex.Infrastructure/Commands/CommandContext.cs b/backend/src/Squidex.Infrastructure/Commands/CommandContext.cs index d7ec30710..a1dc5f760 100644 --- a/backend/src/Squidex.Infrastructure/Commands/CommandContext.cs +++ b/backend/src/Squidex.Infrastructure/Commands/CommandContext.cs @@ -13,7 +13,7 @@ namespace Squidex.Infrastructure.Commands { private Tuple? result; - public Guid ContextId { get; } = Guid.NewGuid(); + public DomainId ContextId { get; } = DomainId.NewGuid(); public ICommand Command { get; } diff --git a/backend/src/Squidex.Infrastructure/Commands/DomainObject.cs b/backend/src/Squidex.Infrastructure/Commands/DomainObject.cs index c83bd6d5f..ce0c77a9c 100644 --- a/backend/src/Squidex.Infrastructure/Commands/DomainObject.cs +++ b/backend/src/Squidex.Infrastructure/Commands/DomainObject.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.Log; @@ -15,7 +14,7 @@ namespace Squidex.Infrastructure.Commands { public abstract class DomainObject : DomainObjectBase where T : class, IDomainState, new() { - private readonly IStore store; + private readonly IStore store; private T snapshot = new T { Version = EtagVersion.Empty }; private IPersistence? persistence; @@ -24,7 +23,7 @@ namespace Squidex.Infrastructure.Commands get { return snapshot; } } - protected DomainObject(IStore store, ISemanticLog log) + protected DomainObject(IStore store, ISemanticLog log) : base(log) { Guard.NotNull(store, nameof(store)); @@ -34,7 +33,7 @@ namespace Squidex.Infrastructure.Commands protected override void OnSetup() { - persistence = store.WithSnapshotsAndEventSourcing(GetType(), Id, new HandleSnapshot(ApplySnapshot), x => ApplyEvent(x, true)); + persistence = store.WithSnapshotsAndEventSourcing(GetType(), UniqueId.ToString(), new HandleSnapshot(ApplySnapshot), x => ApplyEvent(x, true)); } protected sealed override bool ApplyEvent(Envelope @event, bool isLoading) @@ -85,6 +84,11 @@ namespace Squidex.Infrastructure.Commands { await EnsureLoadedAsync(true); + if (Snapshot.Version <= EtagVersion.Empty) + { + throw new DomainObjectNotFoundException(UniqueId.ToString(), GetType()); + } + if (persistence != null) { await persistence.WriteSnapshotAsync(Snapshot); diff --git a/backend/src/Squidex.Infrastructure/Commands/DomainObjectBase.cs b/backend/src/Squidex.Infrastructure/Commands/DomainObjectBase.cs index 07e6670c0..9fedeaf0c 100644 --- a/backend/src/Squidex.Infrastructure/Commands/DomainObjectBase.cs +++ b/backend/src/Squidex.Infrastructure/Commands/DomainObjectBase.cs @@ -19,11 +19,11 @@ namespace Squidex.Infrastructure.Commands private readonly List> uncomittedEvents = new List>(); private readonly ISemanticLog log; private bool isLoaded; - private Guid id; + private DomainId uniqueId; - public Guid Id + public DomainId UniqueId { - get { return id; } + get { return uniqueId; } } public long Version @@ -40,9 +40,9 @@ namespace Squidex.Infrastructure.Commands this.log = log; } - public virtual void Setup(Guid id) + public virtual void Setup(DomainId uniqueId) { - this.id = id; + this.uniqueId = uniqueId; OnSetup(); } @@ -60,7 +60,7 @@ namespace Squidex.Infrastructure.Commands } else { - var logContext = (id: id.ToString(), name: GetType().Name); + var logContext = (id: uniqueId.ToString(), name: GetType().Name); using (log.MeasureInformation(logContext, (ctx, w) => w .WriteProperty("action", "ActivateDomainObject") @@ -83,7 +83,7 @@ namespace Squidex.Infrastructure.Commands { Guard.NotNull(@event, nameof(@event)); - @event.SetAggregateId(id); + @event.SetAggregateId(uniqueId); if (ApplyEvent(@event, false)) { @@ -151,14 +151,34 @@ namespace Squidex.Infrastructure.Commands await EnsureLoadedAsync(); } + if (IsDeleted()) + { + throw new DomainException("Object has already been deleted."); + } + + if (isUpdate) + { + if (!CanAccept(command)) + { + throw new NotSupportedException("Invalid command."); + } + } + else + { + if (!CanAcceptCreation(command)) + { + throw new NotSupportedException("Invalid command."); + } + } + if (command.ExpectedVersion > EtagVersion.Any && command.ExpectedVersion != Version) { - throw new DomainObjectVersionException(id.ToString(), GetType(), Version, command.ExpectedVersion); + throw new DomainObjectVersionException(uniqueId.ToString(), GetType(), Version, command.ExpectedVersion); } if (isUpdate && Version < 0) { - throw new DomainObjectNotFoundException(id.ToString(), GetType()); + throw new DomainObjectNotFoundException(uniqueId.ToString(), GetType()); } var previousSnapshot = Snapshot; @@ -179,7 +199,7 @@ namespace Squidex.Infrastructure.Commands } else { - result = EntityCreatedResult.Create(id, Version); + result = EntityCreatedResult.Create(uniqueId, Version); } } @@ -199,6 +219,21 @@ namespace Squidex.Infrastructure.Commands } } + protected virtual bool CanAcceptCreation(ICommand command) + { + return true; + } + + protected virtual bool CanAccept(ICommand command) + { + return true; + } + + protected virtual bool IsDeleted() + { + return false; + } + protected abstract void RestorePreviousSnapshot(T previousSnapshot, long previousVersion); protected abstract bool ApplyEvent(Envelope @event, bool isLoading); diff --git a/backend/src/Squidex.Infrastructure/Commands/DomainObjectGrain.cs b/backend/src/Squidex.Infrastructure/Commands/DomainObjectGrain.cs index d475d02da..efac952ec 100644 --- a/backend/src/Squidex.Infrastructure/Commands/DomainObjectGrain.cs +++ b/backend/src/Squidex.Infrastructure/Commands/DomainObjectGrain.cs @@ -12,7 +12,7 @@ using Squidex.Infrastructure.Orleans; namespace Squidex.Infrastructure.Commands { - public abstract class DomainObjectGrain : GrainOfGuid where T : DomainObjectBase where TState : class, IDomainState, new() + public abstract class DomainObjectGrain : GrainOfString where T : DomainObjectBase where TState : class, IDomainState, new() { private readonly T domainObject; @@ -33,7 +33,7 @@ namespace Squidex.Infrastructure.Commands domainObject = serviceProvider.GetRequiredService(); } - protected override Task OnActivateAsync(Guid key) + protected override Task OnActivateAsync(string key) { domainObject.Setup(key); diff --git a/backend/src/Squidex.Infrastructure/Commands/GrainCommandMiddleware.cs b/backend/src/Squidex.Infrastructure/Commands/GrainCommandMiddleware.cs index 8b49b1683..1e9220c7f 100644 --- a/backend/src/Squidex.Infrastructure/Commands/GrainCommandMiddleware.cs +++ b/backend/src/Squidex.Infrastructure/Commands/GrainCommandMiddleware.cs @@ -40,7 +40,7 @@ namespace Squidex.Infrastructure.Commands private async Task ExecuteCommandAsync(TCommand typedCommand) { - var grain = grainFactory.GetGrain(typedCommand.AggregateId); + var grain = grainFactory.GetGrain(typedCommand.AggregateId.ToString()); var result = await grain.ExecuteAsync(typedCommand); diff --git a/backend/src/Squidex.Infrastructure/Commands/IAggregateCommand.cs b/backend/src/Squidex.Infrastructure/Commands/IAggregateCommand.cs index d8b03a235..7b73a0ea6 100644 --- a/backend/src/Squidex.Infrastructure/Commands/IAggregateCommand.cs +++ b/backend/src/Squidex.Infrastructure/Commands/IAggregateCommand.cs @@ -5,12 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; - namespace Squidex.Infrastructure.Commands { public interface IAggregateCommand : ICommand { - Guid AggregateId { get; } + DomainId AggregateId { get; } } } \ No newline at end of file diff --git a/backend/src/Squidex.Infrastructure/Commands/IDomainObjectGrain.cs b/backend/src/Squidex.Infrastructure/Commands/IDomainObjectGrain.cs index ea10c037b..1e179aece 100644 --- a/backend/src/Squidex.Infrastructure/Commands/IDomainObjectGrain.cs +++ b/backend/src/Squidex.Infrastructure/Commands/IDomainObjectGrain.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure.Orleans; namespace Squidex.Infrastructure.Commands { - public interface IDomainObjectGrain : IGrainWithGuidKey + public interface IDomainObjectGrain : IGrainWithStringKey { Task> ExecuteAsync(J command); } diff --git a/backend/src/Squidex.Infrastructure/Commands/Is.cs b/backend/src/Squidex.Infrastructure/Commands/Is.cs index 4f5f33e51..0b73fe453 100644 --- a/backend/src/Squidex.Infrastructure/Commands/Is.cs +++ b/backend/src/Squidex.Infrastructure/Commands/Is.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -13,7 +12,7 @@ namespace Squidex.Infrastructure.Commands { public static class Is { - public static bool Change(Guid oldValue, Guid newValue) + public static bool Change(DomainId oldValue, DomainId newValue) { return !Equals(oldValue, newValue); } diff --git a/backend/src/Squidex.Infrastructure/Commands/LogSnapshotDomainObject.cs b/backend/src/Squidex.Infrastructure/Commands/LogSnapshotDomainObject.cs index 5809a0d30..b0db7be03 100644 --- a/backend/src/Squidex.Infrastructure/Commands/LogSnapshotDomainObject.cs +++ b/backend/src/Squidex.Infrastructure/Commands/LogSnapshotDomainObject.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -17,7 +16,7 @@ namespace Squidex.Infrastructure.Commands { public abstract class LogSnapshotDomainObject : DomainObjectBase where T : class, IDomainState, new() { - private readonly IStore store; + private readonly IStore store; private readonly List snapshots = new List { new T { Version = EtagVersion.Empty } }; private IPersistence? persistence; @@ -26,7 +25,7 @@ namespace Squidex.Infrastructure.Commands get { return snapshots.Last(); } } - protected LogSnapshotDomainObject(IStore store, ISemanticLog log) + protected LogSnapshotDomainObject(IStore store, ISemanticLog log) : base(log) { Guard.NotNull(log, nameof(log)); @@ -36,7 +35,7 @@ namespace Squidex.Infrastructure.Commands protected override void OnSetup() { - persistence = store.WithEventSourcing(GetType(), Id, x => ApplyEvent(x, true)); + persistence = store.WithEventSourcing(GetType(), UniqueId.ToString(), x => ApplyEvent(x, true)); } public T GetSnapshot(long version) @@ -83,7 +82,7 @@ namespace Squidex.Infrastructure.Commands var persistedSnapshots = store.GetSnapshotStore(); await persistence.WriteEventsAsync(newEvents); - await persistedSnapshots.WriteAsync(Id, Snapshot, previousVersion, Snapshot.Version); + await persistedSnapshots.WriteAsync(UniqueId.ToString(), Snapshot, previousVersion, Snapshot.Version); } } @@ -99,11 +98,16 @@ namespace Squidex.Infrastructure.Commands { await EnsureLoadedAsync(true); + if (Snapshot.Version <= EtagVersion.Empty) + { + throw new DomainObjectNotFoundException(UniqueId.ToString(), GetType()); + } + if (persistence != null) { var persistedSnapshots = store.GetSnapshotStore(); - await persistedSnapshots.WriteAsync(Id, Snapshot, EtagVersion.Any, Snapshot.Version); + await persistedSnapshots.WriteAsync(UniqueId.ToString(), Snapshot, EtagVersion.Any, Snapshot.Version); } } diff --git a/backend/src/Squidex.Infrastructure/Commands/Rebuilder.cs b/backend/src/Squidex.Infrastructure/Commands/Rebuilder.cs index 433afcd60..6e78448bd 100644 --- a/backend/src/Squidex.Infrastructure/Commands/Rebuilder.cs +++ b/backend/src/Squidex.Infrastructure/Commands/Rebuilder.cs @@ -16,18 +16,18 @@ using Squidex.Infrastructure.States; namespace Squidex.Infrastructure.Commands { - public delegate Task IdSource(Func add); + public delegate Task IdSource(Func add); public class Rebuilder { private readonly ILocalCache localCache; - private readonly IStore store; + private readonly IStore store; private readonly IEventStore eventStore; private readonly IServiceProvider serviceProvider; public Rebuilder( ILocalCache localCache, - IStore store, + IStore store, IEventStore eventStore, IServiceProvider serviceProvider) { @@ -41,9 +41,11 @@ namespace Squidex.Infrastructure.Commands this.store = store; } - public Task RebuildAsync(string filter, CancellationToken ct) where T : DomainObjectBase where TState : class, IDomainState, new() + public virtual async Task RebuildAsync(string filter, CancellationToken ct) where T : DomainObjectBase where TState : class, IDomainState, new() { - return RebuildAsync(async target => + await store.GetSnapshotStore().ClearAsync(); + + await InsertManyAsync(async target => { await eventStore.QueryAsync(async storedEvent => { @@ -54,20 +56,22 @@ namespace Squidex.Infrastructure.Commands }, ct); } - public virtual async Task RebuildAsync(IdSource source, CancellationToken ct = default) where T : DomainObjectBase where TState : class, IDomainState, new() + public virtual async Task InsertManyAsync(IEnumerable source, CancellationToken ct = default) where T : DomainObjectBase where TState : class, IDomainState, new() { Guard.NotNull(source, nameof(source)); - await store.GetSnapshotStore().ClearAsync(); - - await InsertManyAsync(source, ct); + await InsertManyAsync(async target => + { + foreach (var id in source) + { + await target(id); + } + }, ct); } - public virtual async Task InsertManyAsync(IdSource source, CancellationToken ct = default) where T : DomainObjectBase where TState : class, IDomainState, new() + private async Task InsertManyAsync(IdSource source, CancellationToken ct = default) where T : DomainObjectBase where TState : class, IDomainState, new() { - Guard.NotNull(source, nameof(source)); - - var worker = new ActionBlock(async id => + var worker = new ActionBlock(async id => { try { @@ -84,10 +88,10 @@ namespace Squidex.Infrastructure.Commands }, new ExecutionDataflowBlockOptions { - MaxDegreeOfParallelism = Environment.ProcessorCount * 2 + MaxDegreeOfParallelism = Environment.ProcessorCount * 4 }); - var handledIds = new HashSet(); + var handledIds = new HashSet(); using (localCache.StartContext()) { diff --git a/backend/src/Squidex.Infrastructure/DomainId.cs b/backend/src/Squidex.Infrastructure/DomainId.cs new file mode 100644 index 000000000..35ff75af4 --- /dev/null +++ b/backend/src/Squidex.Infrastructure/DomainId.cs @@ -0,0 +1,117 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; + +namespace Squidex.Infrastructure +{ + [TypeConverter(typeof(DomainIdTypeConverter))] + public readonly struct DomainId : IEquatable, IComparable + { + private static readonly string EmptyString = Guid.Empty.ToString(); + public static readonly DomainId Empty = default; + + private readonly string? id; + + private DomainId(string id) + { + this.id = id; + } + + public static DomainId? CreateNullable(string? value) + { + if (value == null) + { + return null; + } + + return new DomainId(value); + } + + public static DomainId Create(string value) + { + if (value == null || string.Equals(value, EmptyString, StringComparison.OrdinalIgnoreCase)) + { + return Empty; + } + + return new DomainId(value); + } + + public static DomainId Create(Guid value) + { + if (value == Guid.Empty) + { + return Empty; + } + + return new DomainId(value.ToString()); + } + + public override bool Equals(object? obj) + { + return obj is DomainId status && Equals(status); + } + + public bool Equals(DomainId other) + { + return string.Equals(id, other.id); + } + + public override int GetHashCode() + { + return id?.GetHashCode() ?? 0; + } + + public override string ToString() + { + return id ?? EmptyString; + } + + public int CompareTo([AllowNull] DomainId other) + { + return string.Compare(id, other.id, StringComparison.Ordinal); + } + + public static implicit operator DomainId(string value) + { + return Create(value); + } + + public static implicit operator DomainId(Guid value) + { + return Create(value); + } + + public static bool operator ==(DomainId lhs, DomainId rhs) + { + return lhs.Equals(rhs); + } + + public static bool operator !=(DomainId lhs, DomainId rhs) + { + return !lhs.Equals(rhs); + } + + public static DomainId NewGuid() + { + return new DomainId(Guid.NewGuid().ToString()); + } + + public static DomainId Combine(NamedId id1, DomainId id2) + { + return new DomainId($"{id1.Id}--{id2}"); + } + + public static DomainId Combine(DomainId id1, DomainId id2) + { + return new DomainId($"{id1}--{id2}"); + } + } +} diff --git a/backend/src/Squidex.Infrastructure/DomainIdTypeConverter.cs b/backend/src/Squidex.Infrastructure/DomainIdTypeConverter.cs new file mode 100644 index 000000000..451ff4d28 --- /dev/null +++ b/backend/src/Squidex.Infrastructure/DomainIdTypeConverter.cs @@ -0,0 +1,46 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.ComponentModel; +using System.Globalization; + +namespace Squidex.Infrastructure +{ + public sealed class DomainIdTypeConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + return sourceType == typeof(string) && sourceType == typeof(Guid); + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + return destinationType == typeof(string); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string text) + { + return DomainId.Create(text); + } + + if (value is Guid guid) + { + return DomainId.Create(guid); + } + + return DomainId.Empty; + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + return value.ToString()!; + } + } +} diff --git a/backend/src/Squidex.Infrastructure/Email/SmtpEmailSender.cs b/backend/src/Squidex.Infrastructure/Email/SmtpEmailSender.cs index 214fd37e6..4cb3b8323 100644 --- a/backend/src/Squidex.Infrastructure/Email/SmtpEmailSender.cs +++ b/backend/src/Squidex.Infrastructure/Email/SmtpEmailSender.cs @@ -88,7 +88,7 @@ namespace Squidex.Infrastructure.Email { var tcs = new TaskCompletionSource(); - var state = socket.BeginConnect(options.Server, options.Port, tcs.SetResult, null); + socket.BeginConnect(options.Server, options.Port, tcs.SetResult, null); using (ct.Register(() => { diff --git a/backend/src/Squidex.Infrastructure/EventSourcing/DefaultEventDataFormatter.cs b/backend/src/Squidex.Infrastructure/EventSourcing/DefaultEventDataFormatter.cs index 55fe5dfd1..5bc05f6f0 100644 --- a/backend/src/Squidex.Infrastructure/EventSourcing/DefaultEventDataFormatter.cs +++ b/backend/src/Squidex.Infrastructure/EventSourcing/DefaultEventDataFormatter.cs @@ -28,10 +28,10 @@ namespace Squidex.Infrastructure.EventSourcing this.serializer = serializer; } - public Envelope Parse(EventData eventData, Func? stringConverter = null) + public Envelope Parse(EventData eventData) { var payloadType = typeNameRegistry.GetType(eventData.Type); - var payloadObj = serializer.Deserialize(eventData.Payload, payloadType, stringConverter); + var payloadObj = serializer.Deserialize(eventData.Payload, payloadType); if (payloadObj is IMigrated migratedEvent) { diff --git a/backend/src/Squidex.Infrastructure/EventSourcing/DefaultEventEnricher.cs b/backend/src/Squidex.Infrastructure/EventSourcing/DefaultEventEnricher.cs index b010ab00c..98d439c91 100644 --- a/backend/src/Squidex.Infrastructure/EventSourcing/DefaultEventEnricher.cs +++ b/backend/src/Squidex.Infrastructure/EventSourcing/DefaultEventEnricher.cs @@ -5,17 +5,15 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; - namespace Squidex.Infrastructure.EventSourcing { public class DefaultEventEnricher : IEventEnricher { - public virtual void Enrich(Envelope @event, TKey id) + public virtual void Enrich(Envelope @event, TKey key) { - if (id is Guid guid) + if (key is DomainId domainId) { - @event.SetAggregateId(guid); + @event.SetAggregateId(domainId); } } } diff --git a/backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeExtensions.cs b/backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeExtensions.cs index c23398990..7954e769b 100644 --- a/backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeExtensions.cs +++ b/backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeExtensions.cs @@ -51,12 +51,12 @@ namespace Squidex.Infrastructure.EventSourcing return envelope; } - public static Guid AggregateId(this EnvelopeHeaders headers) + public static DomainId AggregateId(this EnvelopeHeaders headers) { - return headers.GetGuid(CommonHeaders.AggregateId); + return headers.GetString(CommonHeaders.AggregateId); } - public static Envelope SetAggregateId(this Envelope envelope, Guid value) where T : class, IEvent + public static Envelope SetAggregateId(this Envelope envelope, DomainId value) where T : class, IEvent { envelope.Headers.Add(CommonHeaders.AggregateId, value.ToString()); diff --git a/backend/src/Squidex.Infrastructure/EventSourcing/IEventDataFormatter.cs b/backend/src/Squidex.Infrastructure/EventSourcing/IEventDataFormatter.cs index 38332ea9a..9d13c2e68 100644 --- a/backend/src/Squidex.Infrastructure/EventSourcing/IEventDataFormatter.cs +++ b/backend/src/Squidex.Infrastructure/EventSourcing/IEventDataFormatter.cs @@ -11,7 +11,7 @@ namespace Squidex.Infrastructure.EventSourcing { public interface IEventDataFormatter { - Envelope Parse(EventData eventData, Func? stringConverter = null); + Envelope Parse(EventData eventData); EventData ToEventData(Envelope envelope, Guid commitId, bool migrate = true); } diff --git a/backend/src/Squidex.Infrastructure/EventSourcing/IEventEnricher.cs b/backend/src/Squidex.Infrastructure/EventSourcing/IEventEnricher.cs index f623c9edc..17a40b462 100644 --- a/backend/src/Squidex.Infrastructure/EventSourcing/IEventEnricher.cs +++ b/backend/src/Squidex.Infrastructure/EventSourcing/IEventEnricher.cs @@ -9,6 +9,6 @@ namespace Squidex.Infrastructure.EventSourcing { public interface IEventEnricher { - void Enrich(Envelope @event, T id); + void Enrich(Envelope @event, T key); } } diff --git a/backend/src/Squidex.Infrastructure/EventSourcing/IEventStore.cs b/backend/src/Squidex.Infrastructure/EventSourcing/IEventStore.cs index 104000c2e..4f594a291 100644 --- a/backend/src/Squidex.Infrastructure/EventSourcing/IEventStore.cs +++ b/backend/src/Squidex.Infrastructure/EventSourcing/IEventStore.cs @@ -14,16 +14,12 @@ namespace Squidex.Infrastructure.EventSourcing { public interface IEventStore { - Task CreateIndexAsync(string property); - Task> QueryLatestAsync(string streamName, int count); Task> QueryAsync(string streamName, long streamPosition = 0); Task QueryAsync(Func callback, string? streamFilter = null, string? position = null, CancellationToken ct = default); - Task QueryAsync(Func callback, string property, object value, string? position = null, CancellationToken ct = default); - Task AppendAsync(Guid commitId, string streamName, ICollection events); Task AppendAsync(Guid commitId, string streamName, long expectedVersion, ICollection events); diff --git a/backend/src/Squidex.Infrastructure/EventSourcing/RetrySubscription.cs b/backend/src/Squidex.Infrastructure/EventSourcing/RetrySubscription.cs index fbf66a199..7cc7bd767 100644 --- a/backend/src/Squidex.Infrastructure/EventSourcing/RetrySubscription.cs +++ b/backend/src/Squidex.Infrastructure/EventSourcing/RetrySubscription.cs @@ -45,10 +45,7 @@ namespace Squidex.Infrastructure.EventSourcing private void Subscribe() { - if (currentSubscription == null) - { - currentSubscription = eventStore.CreateSubscription(this, streamFilter, position); - } + currentSubscription ??= eventStore.CreateSubscription(this, streamFilter, position); } private void Unsubscribe() diff --git a/backend/src/Squidex.Infrastructure/Guard.cs b/backend/src/Squidex.Infrastructure/Guard.cs index 7ed6bdbd5..f54e2d256 100644 --- a/backend/src/Squidex.Infrastructure/Guard.cs +++ b/backend/src/Squidex.Infrastructure/Guard.cs @@ -163,6 +163,16 @@ namespace Squidex.Infrastructure } } + [DebuggerStepThrough] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void NotEmpty(DomainId target, string parameterName) + { + if (target == DomainId.Empty) + { + throw new ArgumentException("Value cannot be empty.", parameterName); + } + } + [DebuggerStepThrough] public static void NotNull(object? target, string parameterName) { diff --git a/backend/src/Squidex.Infrastructure/Json/IJsonSerializer.cs b/backend/src/Squidex.Infrastructure/Json/IJsonSerializer.cs index c544520ed..703551399 100644 --- a/backend/src/Squidex.Infrastructure/Json/IJsonSerializer.cs +++ b/backend/src/Squidex.Infrastructure/Json/IJsonSerializer.cs @@ -16,8 +16,8 @@ namespace Squidex.Infrastructure.Json void Serialize(T value, Stream stream); - T Deserialize(string value, Type? actualType = null, Func? stringConverter = null); + T Deserialize(string value, Type? actualType = null); - T Deserialize(Stream stream, Type? actualType = null, Func? stringConverter = null); + T Deserialize(Stream stream, Type? actualType = null); } } diff --git a/backend/src/Squidex.Infrastructure/Json/Newtonsoft/DomainIdConverter.cs b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/DomainIdConverter.cs new file mode 100644 index 000000000..6038a9380 --- /dev/null +++ b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/DomainIdConverter.cs @@ -0,0 +1,62 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Squidex.Infrastructure.Json.Newtonsoft +{ + public sealed class DomainIdConverter : JsonConverter + { + public IEnumerable SupportedTypes + { + get + { + yield return typeof(DomainId); + yield return typeof(DomainId?); + } + } + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + if (value != null) + { + writer.WriteValue(value.ToString()); + } + else + { + writer.WriteNull(); + } + } + + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + if (reader.Value == null) + { + return null; + } + + if (reader.TokenType == JsonToken.String) + { + return DomainId.Create(reader.Value.ToString()!); + } + + if (reader.TokenType == JsonToken.Null && objectType == typeof(DomainId?)) + { + return null; + } + + throw new JsonException($"Not a valid date time, expected String, but got {reader.TokenType}."); + } + + public override bool CanConvert(Type objectType) + { + return objectType == typeof(DomainId) || objectType == typeof(DomainId?); + } + } +} \ No newline at end of file diff --git a/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NamedDomainIdConverter.cs b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NamedDomainIdConverter.cs new file mode 100644 index 000000000..d332a128e --- /dev/null +++ b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NamedDomainIdConverter.cs @@ -0,0 +1,41 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using Newtonsoft.Json; + +namespace Squidex.Infrastructure.Json.Newtonsoft +{ + public sealed class NamedDomainIdConverter : JsonClassConverter> + { + private static readonly Parser Parser = ParseString; + + protected override void WriteValue(JsonWriter writer, NamedId value, JsonSerializer serializer) + { + writer.WriteValue(value.ToString()); + } + + protected override NamedId ReadValue(JsonReader reader, Type objectType, JsonSerializer serializer) + { + var value = serializer.Deserialize(reader)!; + + if (!NamedId.TryParse(value, Parser, out var result)) + { + throw new JsonException("Named id must have at least 2 parts divided by commata."); + } + + return result; + } + + private static bool ParseString(ReadOnlySpan value, out DomainId result) + { + result = new string(value); + + return true; + } + } +} diff --git a/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs index 9deee78c9..3e70cf92b 100644 --- a/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs +++ b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs @@ -16,32 +16,6 @@ namespace Squidex.Infrastructure.Json.Newtonsoft private readonly JsonSerializerSettings settings; private readonly JsonSerializer serializer; - private sealed class CustomReader : JsonTextReader - { - private readonly Func stringConverter; - - public override object? Value - { - get - { - var value = base.Value; - - if (value is string s) - { - return stringConverter(s); - } - - return value; - } - } - - public CustomReader(TextReader reader, Func stringConverter) - : base(reader) - { - this.stringConverter = stringConverter; - } - } - public NewtonsoftJsonSerializer(JsonSerializerSettings settings) { Guard.NotNull(settings, nameof(settings)); @@ -66,35 +40,35 @@ namespace Squidex.Infrastructure.Json.Newtonsoft } } - public T Deserialize(string value, Type? actualType = null, Func? stringConverter = null) + public T Deserialize(string value, Type? actualType = null) { using (var textReader = new StringReader(value)) { actualType ??= typeof(T); - using (var reader = GetReader(stringConverter, textReader)) + using (var reader = GetReader(textReader)) { return (T)serializer.Deserialize(reader, actualType)!; } } } - public T Deserialize(Stream stream, Type? actualType = null, Func? stringConverter = null) + public T Deserialize(Stream stream, Type? actualType = null) { using (var textReader = new StreamReader(stream)) { actualType ??= typeof(T); - using (var reader = GetReader(stringConverter, textReader)) + using (var reader = GetReader(textReader)) { return (T)serializer.Deserialize(reader, actualType)!; } } } - private static JsonTextReader GetReader(Func? stringConverter, TextReader textReader) + private static JsonTextReader GetReader(TextReader textReader) { - return stringConverter != null ? new CustomReader(textReader, stringConverter) : new JsonTextReader(textReader); + return new JsonTextReader(textReader); } } } diff --git a/backend/src/Squidex.Infrastructure/Json/Objects/JsonValue.cs b/backend/src/Squidex.Infrastructure/Json/Objects/JsonValue.cs index 46330f893..d84768b37 100644 --- a/backend/src/Squidex.Infrastructure/Json/Objects/JsonValue.cs +++ b/backend/src/Squidex.Infrastructure/Json/Objects/JsonValue.cs @@ -70,6 +70,8 @@ namespace Squidex.Infrastructure.Json.Objects return Create(l); case Guid g: return Create(g); + case DomainId i: + return Create(i); case Instant i: return Create(i); } @@ -82,6 +84,11 @@ namespace Squidex.Infrastructure.Json.Objects return Create(value.ToString()); } + public static IJsonValue Create(DomainId value) + { + return Create(value.ToString()); + } + public static IJsonValue Create(Guid? value) { if (value == null) diff --git a/backend/src/Squidex.Infrastructure/Log/Adapter/SemanticLogLogger.cs b/backend/src/Squidex.Infrastructure/Log/Adapter/SemanticLogLogger.cs index 8bf1ee07f..42c9bb87b 100644 --- a/backend/src/Squidex.Infrastructure/Log/Adapter/SemanticLogLogger.cs +++ b/backend/src/Squidex.Infrastructure/Log/Adapter/SemanticLogLogger.cs @@ -51,7 +51,7 @@ namespace Squidex.Infrastructure.Log.Adapter if (state is IReadOnlyList> parameters) { - foreach (var (key, value) in parameters) + foreach (var (_, value) in parameters) { if (value is Exception ex && exception == null) { diff --git a/backend/src/Squidex.Infrastructure/Log/ProfilerSpan.cs b/backend/src/Squidex.Infrastructure/Log/ProfilerSpan.cs index 771114415..7ea459d7c 100644 --- a/backend/src/Squidex.Infrastructure/Log/ProfilerSpan.cs +++ b/backend/src/Squidex.Infrastructure/Log/ProfilerSpan.cs @@ -36,11 +36,7 @@ namespace Squidex.Infrastructure.Log { Guard.NotNull(hook, nameof(hook)); - if (hooks == null) - { - hooks = new List(1); - } - + hooks ??= new List(1); hooks.Add(hook); } diff --git a/backend/src/Squidex.Infrastructure/Log/SemanticLog.cs b/backend/src/Squidex.Infrastructure/Log/SemanticLog.cs index 2ef09e464..5c2157b7e 100644 --- a/backend/src/Squidex.Infrastructure/Log/SemanticLog.cs +++ b/backend/src/Squidex.Infrastructure/Log/SemanticLog.cs @@ -76,11 +76,7 @@ namespace Squidex.Infrastructure.Log } catch (Exception ex) { - if (exceptions == null) - { - exceptions = new List(); - } - + exceptions ??= new List(); exceptions.Add(ex); } } diff --git a/backend/src/Squidex.Infrastructure/Orleans/GrainOfGuid.cs b/backend/src/Squidex.Infrastructure/Orleans/GrainOfGuid.cs deleted file mode 100644 index deb81959f..000000000 --- a/backend/src/Squidex.Infrastructure/Orleans/GrainOfGuid.cs +++ /dev/null @@ -1,46 +0,0 @@ -// ========================================================================== -// 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 Orleans.Core; -using Orleans.Runtime; - -namespace Squidex.Infrastructure.Orleans -{ - public abstract class GrainOfGuid : GrainBase - { - public Guid Key { get; private set; } - - protected GrainOfGuid() - { - } - - protected GrainOfGuid(IGrainIdentity identity, IGrainRuntime runtime) - : base(identity, runtime) - { - } - - public sealed override Task OnActivateAsync() - { - return ActivateAsync(this.GetPrimaryKey()); - } - - public async Task ActivateAsync(Guid key) - { - Key = key; - - await OnActivateAsync(key); - } - - protected virtual Task OnActivateAsync(Guid key) - { - return Task.CompletedTask; - } - } -} diff --git a/backend/src/Squidex.Infrastructure/Orleans/J{T}.cs b/backend/src/Squidex.Infrastructure/Orleans/J{T}.cs index 8584b59b5..af70c52e6 100644 --- a/backend/src/Squidex.Infrastructure/Orleans/J{T}.cs +++ b/backend/src/Squidex.Infrastructure/Orleans/J{T}.cs @@ -19,7 +19,7 @@ using Squidex.Infrastructure.Log; namespace Squidex.Infrastructure.Orleans { [Immutable] - public struct J + public readonly struct J { public T Value { get; } diff --git a/backend/src/Squidex.Infrastructure/Security/Permission.Part.cs b/backend/src/Squidex.Infrastructure/Security/Permission.Part.cs index eb63501b3..a0c2ee008 100644 --- a/backend/src/Squidex.Infrastructure/Security/Permission.Part.cs +++ b/backend/src/Squidex.Infrastructure/Security/Permission.Part.cs @@ -12,7 +12,7 @@ namespace Squidex.Infrastructure.Security { public sealed partial class Permission { - internal struct Part + internal readonly struct Part { private static readonly char[] AlternativeSeparators = { '|' }; private static readonly char[] MainSeparators = { '.' }; diff --git a/backend/src/Squidex.Infrastructure/States/DefaultStreamNameResolver.cs b/backend/src/Squidex.Infrastructure/States/DefaultStreamNameResolver.cs index bb671221a..329ce99f7 100644 --- a/backend/src/Squidex.Infrastructure/States/DefaultStreamNameResolver.cs +++ b/backend/src/Squidex.Infrastructure/States/DefaultStreamNameResolver.cs @@ -21,25 +21,5 @@ namespace Squidex.Infrastructure.States return $"{aggregateType.TypeName(true, Suffixes)}-{id}"; } - - public string WithNewId(string streamName, Func idGenerator) - { - Guard.NotNullOrEmpty(streamName, nameof(streamName)); - Guard.NotNull(idGenerator, nameof(idGenerator)); - - var positionOfDash = streamName.IndexOf('-'); - - if (positionOfDash >= 0) - { - var newId = idGenerator(streamName.Substring(positionOfDash + 1)); - - if (!string.IsNullOrWhiteSpace(newId)) - { - streamName = $"{streamName.Substring(0, positionOfDash)}-{newId}"; - } - } - - return streamName; - } } } diff --git a/backend/src/Squidex.Infrastructure/States/IStreamNameResolver.cs b/backend/src/Squidex.Infrastructure/States/IStreamNameResolver.cs index cd2fe904e..a8d13034c 100644 --- a/backend/src/Squidex.Infrastructure/States/IStreamNameResolver.cs +++ b/backend/src/Squidex.Infrastructure/States/IStreamNameResolver.cs @@ -12,7 +12,5 @@ namespace Squidex.Infrastructure.States public interface IStreamNameResolver { string GetStreamName(Type aggregateType, string id); - - string WithNewId(string streamName, Func idGenerator); } } diff --git a/backend/src/Squidex.Infrastructure/Validation/Validate.cs b/backend/src/Squidex.Infrastructure/Validation/Validate.cs index 95e3a8db5..98a1be84e 100644 --- a/backend/src/Squidex.Infrastructure/Validation/Validate.cs +++ b/backend/src/Squidex.Infrastructure/Validation/Validate.cs @@ -19,11 +19,7 @@ namespace Squidex.Infrastructure.Validation var addValidation = new AddValidation((m, p) => { - if (errors == null) - { - errors = new List(); - } - + errors ??= new List(); errors.Add(new ValidationError(m, p)); }); @@ -41,11 +37,7 @@ namespace Squidex.Infrastructure.Validation var addValidation = new AddValidation((m, p) => { - if (errors == null) - { - errors = new List(); - } - + errors ??= new List(); errors.Add(new ValidationError(m, p)); }); diff --git a/backend/src/Squidex.Infrastructure/ValueStopwatch.cs b/backend/src/Squidex.Infrastructure/ValueStopwatch.cs index 133cfab83..66af46944 100644 --- a/backend/src/Squidex.Infrastructure/ValueStopwatch.cs +++ b/backend/src/Squidex.Infrastructure/ValueStopwatch.cs @@ -9,7 +9,7 @@ using System.Diagnostics; namespace Squidex.Infrastructure { - public struct ValueStopwatch + public readonly struct ValueStopwatch { private const long TicksPerMillisecond = 10000; private const long TicksPerSecond = TicksPerMillisecond * 1000; diff --git a/backend/src/Squidex.Web/ApiController.cs b/backend/src/Squidex.Web/ApiController.cs index 091d2745c..dee44fbe6 100644 --- a/backend/src/Squidex.Web/ApiController.cs +++ b/backend/src/Squidex.Web/ApiController.cs @@ -50,7 +50,7 @@ namespace Squidex.Web get { return HttpContext.Context(); } } - protected Guid AppId + protected DomainId AppId { get { return App.Id; } } diff --git a/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithActorCommandMiddleware.cs b/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithActorCommandMiddleware.cs index 6d7e821fd..442eb9102 100644 --- a/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithActorCommandMiddleware.cs +++ b/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithActorCommandMiddleware.cs @@ -43,10 +43,7 @@ namespace Squidex.Web.CommandMiddlewares squidexCommand.Actor = actorToken ?? throw new DomainForbiddenException("No actor with subject or client id available."); } - if (squidexCommand.User == null) - { - squidexCommand.User = httpContextAccessor.HttpContext.User; - } + squidexCommand.User ??= httpContextAccessor.HttpContext.User; } return next(context); diff --git a/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs b/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs index 1ff8a6ac3..c17251a32 100644 --- a/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs +++ b/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs @@ -9,7 +9,6 @@ using System; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -35,17 +34,10 @@ namespace Squidex.Web.CommandMiddlewares appCommand.AppId = appId; } - if (context.Command is AppCommand appSelfCommand && appSelfCommand.AppId == Guid.Empty) - { - var appId = GetAppId(); - - appSelfCommand.AppId = appId.Id; - } - return next(context); } - private NamedId GetAppId() + private NamedId GetAppId() { var context = contextProvider.Context; diff --git a/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs b/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs index 1247447b0..e94331cbf 100644 --- a/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs +++ b/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs @@ -7,11 +7,8 @@ using System; using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Http; using Squidex.Domain.Apps.Entities; -using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Domain.Apps.Entities.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -19,88 +16,42 @@ namespace Squidex.Web.CommandMiddlewares { public sealed class EnrichWithSchemaIdCommandMiddleware : ICommandMiddleware { - private readonly IAppProvider appProvider; - private readonly IActionContextAccessor actionContextAccessor; + private readonly IHttpContextAccessor httpContextAccessor; - public EnrichWithSchemaIdCommandMiddleware(IAppProvider appProvider, IActionContextAccessor actionContextAccessor) + public EnrichWithSchemaIdCommandMiddleware(IHttpContextAccessor httpContextAccessor) { - Guard.NotNull(appProvider, nameof(appProvider)); - Guard.NotNull(actionContextAccessor, nameof(actionContextAccessor)); + Guard.NotNull(httpContextAccessor, nameof(httpContextAccessor)); - this.appProvider = appProvider; - - this.actionContextAccessor = actionContextAccessor; + this.httpContextAccessor = httpContextAccessor; } - public async Task HandleAsync(CommandContext context, NextDelegate next) + public Task HandleAsync(CommandContext context, NextDelegate next) { - if (actionContextAccessor.ActionContext == null) + if (httpContextAccessor.HttpContext == null) { - await next(context); - - return; + return next(context); } if (context.Command is ISchemaCommand schemaCommand && schemaCommand.SchemaId == null) { - var schemaId = await GetSchemaIdAsync(context); + var schemaId = GetSchemaId(); - schemaCommand.SchemaId = schemaId!; + schemaCommand.SchemaId = schemaId; } - if (context.Command is SchemaCommand schemaSelfCommand && schemaSelfCommand.SchemaId == Guid.Empty) - { - var schemaId = await GetSchemaIdAsync(context); - - schemaSelfCommand.SchemaId = schemaId?.Id ?? Guid.Empty; - } - - await next(context); + return next(context); } - private async Task?> GetSchemaIdAsync(CommandContext context) + private NamedId GetSchemaId() { - NamedId? appId = null; - - if (context.Command is IAppCommand appCommand) - { - appId = appCommand.AppId; - } + var schemaFeature = httpContextAccessor.HttpContext.Features.Get(); - if (appId == null) + if (schemaFeature == null) { - appId = actionContextAccessor.ActionContext.HttpContext.Context().App?.NamedId(); - } - - if (appId != null) - { - var routeValues = actionContextAccessor.ActionContext.RouteData.Values; - - if (routeValues.ContainsKey("name")) - { - var schemaName = routeValues["name"].ToString()!; - - ISchemaEntity? schema; - - if (Guid.TryParse(schemaName, out var id)) - { - schema = await appProvider.GetSchemaAsync(appId.Id, id); - } - else - { - schema = await appProvider.GetSchemaAsync(appId.Id, schemaName); - } - - if (schema == null) - { - throw new DomainObjectNotFoundException(schemaName, typeof(ISchemaEntity)); - } - - return schema.NamedId(); - } + throw new InvalidOperationException("Cannot resolve schema."); } - return null; + return schemaFeature.SchemaId; } } } \ No newline at end of file diff --git a/backend/src/Squidex.Web/Deferred.cs b/backend/src/Squidex.Web/Deferred.cs index 7367c639d..bda383f0e 100644 --- a/backend/src/Squidex.Web/Deferred.cs +++ b/backend/src/Squidex.Web/Deferred.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Web { - public struct Deferred + public readonly struct Deferred { private readonly Lazy> value; diff --git a/backend/src/Squidex.Web/ETagExtensions.cs b/backend/src/Squidex.Web/ETagExtensions.cs index db1903a2f..2a9f57a85 100644 --- a/backend/src/Squidex.Web/ETagExtensions.cs +++ b/backend/src/Squidex.Web/ETagExtensions.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Security.Cryptography; +using System.Text; using Squidex.Domain.Apps.Entities; using Squidex.Infrastructure; using Squidex.Infrastructure.Log; @@ -44,7 +45,7 @@ namespace Squidex.Web foreach (var item in entities) { - hasher.AppendData(item.Id.ToByteArray()); + hasher.AppendData(Encoding.Default.GetBytes(item.UniqueId.ToString())); hasher.AppendData(BitConverter.GetBytes(item.Version)); } diff --git a/backend/src/Squidex.Web/IAppFeature.cs b/backend/src/Squidex.Web/IAppFeature.cs index b350e2cfa..f565fdcf4 100644 --- a/backend/src/Squidex.Web/IAppFeature.cs +++ b/backend/src/Squidex.Web/IAppFeature.cs @@ -5,13 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Web { public interface IAppFeature { - NamedId AppId { get; } + NamedId AppId { get; } } } diff --git a/backend/src/Squidex.Web/ISchemaFeature.cs b/backend/src/Squidex.Web/ISchemaFeature.cs index afa531680..7bac96660 100644 --- a/backend/src/Squidex.Web/ISchemaFeature.cs +++ b/backend/src/Squidex.Web/ISchemaFeature.cs @@ -5,13 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Web { public interface ISchemaFeature { - NamedId SchemaId { get; } + NamedId SchemaId { get; } } } diff --git a/backend/src/Squidex.Web/Pipeline/ApiCostsFilter.cs b/backend/src/Squidex.Web/Pipeline/ApiCostsFilter.cs index 0946cd3d5..b5c34d0a3 100644 --- a/backend/src/Squidex.Web/Pipeline/ApiCostsFilter.cs +++ b/backend/src/Squidex.Web/Pipeline/ApiCostsFilter.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using System.Globalization; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; @@ -62,7 +63,7 @@ namespace Squidex.Web.Pipeline } } - context.HttpContext.Response.Headers.Add("X-Costs", FilterDefinition.Costs.ToString()); + context.HttpContext.Response.Headers.Add("X-Costs", FilterDefinition.Costs.ToString(CultureInfo.InvariantCulture)); } await next(); diff --git a/backend/src/Squidex.Web/Pipeline/AppFeature.cs b/backend/src/Squidex.Web/Pipeline/AppFeature.cs index 5d236f024..9e6b380b5 100644 --- a/backend/src/Squidex.Web/Pipeline/AppFeature.cs +++ b/backend/src/Squidex.Web/Pipeline/AppFeature.cs @@ -5,16 +5,15 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Web.Pipeline { public sealed class AppFeature : IAppFeature { - public NamedId AppId { get; } + public NamedId AppId { get; } - public AppFeature(NamedId appId) + public AppFeature(NamedId appId) { AppId = appId; } diff --git a/backend/src/Squidex.Web/Pipeline/AppResolver.cs b/backend/src/Squidex.Web/Pipeline/AppResolver.cs index 909bfd3b0..923291de3 100644 --- a/backend/src/Squidex.Web/Pipeline/AppResolver.cs +++ b/backend/src/Squidex.Web/Pipeline/AppResolver.cs @@ -90,7 +90,7 @@ namespace Squidex.Web.Pipeline await next(); } - private Context SetContext(HttpContext httpContext, IAppEntity app) + private static Context SetContext(HttpContext httpContext, IAppEntity app) { var requestContext = new Context(httpContext.User, app); diff --git a/backend/src/Squidex.Web/Pipeline/CachingManager.cs b/backend/src/Squidex.Web/Pipeline/CachingManager.cs index b4068e97a..b58aeb2b1 100644 --- a/backend/src/Squidex.Web/Pipeline/CachingManager.cs +++ b/backend/src/Squidex.Web/Pipeline/CachingManager.cs @@ -30,7 +30,7 @@ namespace Squidex.Web.Pipeline private readonly CachingOptions cachingOptions; private readonly IHttpContextAccessor httpContextAccessor; - internal sealed class CacheContext : IRequestCache, IDisposable + internal sealed class CacheContext : IDisposable { private readonly IncrementalHash hasher = IncrementalHash.CreateHash(HashAlgorithmName.SHA256); private readonly HashSet keys = new HashSet(); @@ -51,7 +51,7 @@ namespace Squidex.Web.Pipeline slimLock.Dispose(); } - public void AddDependency(Guid key, long version) + public void AddDependency(string key, long version) { if (key != default) { @@ -59,9 +59,9 @@ namespace Squidex.Web.Pipeline { slimLock.EnterWriteLock(); - keys.Add(key.ToString()); + keys.Add(key); - hasher.AppendData(key.ToByteArray()); + hasher.AppendData(Encoding.Default.GetBytes(key)); hasher.AppendData(BitConverter.GetBytes(version)); hasDependency = true; @@ -189,7 +189,7 @@ namespace Squidex.Web.Pipeline { Guard.NotNull(httpContext, nameof(httpContext)); - int maxKeysSize = GetKeysSize(httpContext); + var maxKeysSize = GetKeysSize(httpContext); httpContext.Features.Set(new CacheContext(maxKeysSize)); } @@ -198,7 +198,7 @@ namespace Squidex.Web.Pipeline { var headers = httpContext.Request.Headers; - if (!headers.TryGetValue(SurrogateKeySizeHeader, out var header) || !int.TryParse(header, out int size)) + if (!headers.TryGetValue(SurrogateKeySizeHeader, out var header) || !int.TryParse(header, out var size)) { size = cachingOptions.MaxSurrogateKeysSize; } @@ -206,43 +206,25 @@ namespace Squidex.Web.Pipeline return Math.Min(MaxAllowedKeysSize, size); } - public void AddDependency(Guid key, long version) + public void AddDependency(DomainId key, long version) { - if (httpContextAccessor.HttpContext != null) - { - var cacheContext = httpContextAccessor.HttpContext.Features.Get(); + var cacheContext = httpContextAccessor.HttpContext?.Features.Get(); - if (cacheContext != null) - { - cacheContext.AddDependency(key, version); - } - } + cacheContext?.AddDependency(key.ToString(), version); } public void AddDependency(object? value) { - if (httpContextAccessor.HttpContext != null) - { - var cacheContext = httpContextAccessor.HttpContext.Features.Get(); + var cacheContext = httpContextAccessor.HttpContext?.Features.Get(); - if (cacheContext != null) - { - cacheContext.AddDependency(value); - } - } + cacheContext?.AddDependency(value); } public void AddHeader(string header) { - if (httpContextAccessor.HttpContext != null) - { - var cacheContext = httpContextAccessor.HttpContext.Features.Get(); + var cacheContext = httpContextAccessor.HttpContext?.Features.Get(); - if (cacheContext != null) - { - cacheContext.AddHeader(header); - } - } + cacheContext?.AddHeader(header); } public void Finish(HttpContext httpContext) @@ -251,10 +233,7 @@ namespace Squidex.Web.Pipeline var cacheContext = httpContextAccessor.HttpContext.Features.Get(); - if (cacheContext != null) - { - cacheContext.Finish(httpContext.Response, stringBuilderPool); - } + cacheContext?.Finish(httpContext.Response, stringBuilderPool); } } } diff --git a/backend/src/Squidex.Web/Pipeline/SchemaFeature.cs b/backend/src/Squidex.Web/Pipeline/SchemaFeature.cs index 22a786732..116a1489a 100644 --- a/backend/src/Squidex.Web/Pipeline/SchemaFeature.cs +++ b/backend/src/Squidex.Web/Pipeline/SchemaFeature.cs @@ -5,16 +5,15 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Infrastructure; namespace Squidex.Web.Pipeline { public sealed class SchemaFeature : ISchemaFeature { - public NamedId SchemaId { get; } + public NamedId SchemaId { get; } - public SchemaFeature(NamedId schemaId) + public SchemaFeature(NamedId schemaId) { SchemaId = schemaId; } diff --git a/backend/src/Squidex.Web/Pipeline/SchemaResolver.cs b/backend/src/Squidex.Web/Pipeline/SchemaResolver.cs index fe9f90356..a02da6f97 100644 --- a/backend/src/Squidex.Web/Pipeline/SchemaResolver.cs +++ b/backend/src/Squidex.Web/Pipeline/SchemaResolver.cs @@ -51,11 +51,11 @@ namespace Squidex.Web.Pipeline await next(); } - private Task GetSchemaAsync(Guid appId, string schemaIdOrName) + private Task GetSchemaAsync(DomainId appId, string schemaIdOrName) { - if (Guid.TryParse(schemaIdOrName, out var id)) + if (Guid.TryParse(schemaIdOrName, out var guid)) { - return appProvider.GetSchemaAsync(appId, id); + return appProvider.GetSchemaAsync(appId, guid); } else { diff --git a/backend/src/Squidex.Web/Services/UrlGenerator.cs b/backend/src/Squidex.Web/Services/UrlGenerator.cs index 4ae668c10..eb021c1ba 100644 --- a/backend/src/Squidex.Web/Services/UrlGenerator.cs +++ b/backend/src/Squidex.Web/Services/UrlGenerator.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Assets; @@ -33,112 +32,112 @@ namespace Squidex.Web.Services CanGenerateAssetSourceUrl = allowAssetSourceUrl; } - public string? AssetThumbnail(Guid assetId, AssetType assetType) + public string? AssetThumbnail(NamedId appId, DomainId assetId, AssetType assetType) { if (assetType != AssetType.Image) { return null; } - return urlsOptions.BuildUrl($"api/assets/{assetId}?width=100&mode=Max"); + return urlsOptions.BuildUrl($"api/assets/{appId.Name}/{assetId}?width=100&mode=Max"); } - public string AppSettingsUI(NamedId appId) + public string AppSettingsUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}/settings", false); } - public string AssetContent(Guid assetId) + public string AssetContent(NamedId appId, DomainId assetId) { - return urlsOptions.BuildUrl($"api/assets/{assetId}"); + return urlsOptions.BuildUrl($"api/assets/{appId.Name}/{assetId}"); } - public string? AssetSource(Guid assetId, long fileVersion) + public string? AssetSource(NamedId appId, DomainId assetId, long fileVersion) { - return assetFileStore.GeneratePublicUrl(assetId, fileVersion); + return assetFileStore.GeneratePublicUrl(appId.Id, assetId, fileVersion); } - public string AssetsUI(NamedId appId) + public string AssetsUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}/assets", false); } - public string AssetsUI(NamedId appId, string? query = null) + public string AssetsUI(NamedId appId, string? query = null) { return urlsOptions.BuildUrl($"app/{appId.Name}/assets?query={query}", false); } - public string BackupsUI(NamedId appId) + public string BackupsUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}/settings/backups", false); } - public string ClientsUI(NamedId appId) + public string ClientsUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}/settings/clients", false); } - public string ContentsUI(NamedId appId) + public string ContentsUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}/content", false); } - public string ContentsUI(NamedId appId, NamedId schemaId) + public string ContentsUI(NamedId appId, NamedId schemaId) { return urlsOptions.BuildUrl($"app/{appId.Name}/content/{schemaId.Name}", false); } - public string ContentUI(NamedId appId, NamedId schemaId, Guid contentId) + public string ContentUI(NamedId appId, NamedId schemaId, DomainId contentId) { return urlsOptions.BuildUrl($"app/{appId.Name}/content/{schemaId.Name}/{contentId}/history", false); } - public string ContributorsUI(NamedId appId) + public string ContributorsUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}/settings/contributors", false); } - public string DashboardUI(NamedId appId) + public string DashboardUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}", false); } - public string LanguagesUI(NamedId appId) + public string LanguagesUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}/settings/languages", false); } - public string PatternsUI(NamedId appId) + public string PatternsUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}/settings/patterns", false); } - public string PlansUI(NamedId appId) + public string PlansUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}/settings/plans", false); } - public string RolesUI(NamedId appId) + public string RolesUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}/settings/roles", false); } - public string RulesUI(NamedId appId) + public string RulesUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}/rules", false); } - public string SchemasUI(NamedId appId) + public string SchemasUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}/schemas", false); } - public string SchemaUI(NamedId appId, NamedId schemaId) + public string SchemaUI(NamedId appId, NamedId schemaId) { return urlsOptions.BuildUrl($"app/{appId.Name}/schemas/{schemaId.Name}", false); } - public string WorkflowsUI(NamedId appId) + public string WorkflowsUI(NamedId appId) { return urlsOptions.BuildUrl($"app/{appId.Name}/settings/workflows", false); } diff --git a/backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs b/backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs index d3b31e8d0..27906aba3 100644 --- a/backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs +++ b/backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs @@ -73,6 +73,7 @@ namespace Squidex.Areas.Api.Config.OpenApi { CreateStringMap(JsonFormatStrings.DateTime), CreateStringMap(), + CreateStringMap(), CreateStringMap(), CreateStringMap(), diff --git a/backend/src/Squidex/Areas/Api/Config/OpenApi/ScopesProcessor.cs b/backend/src/Squidex/Areas/Api/Config/OpenApi/ScopesProcessor.cs index c7043f120..5b78839f6 100644 --- a/backend/src/Squidex/Areas/Api/Config/OpenApi/ScopesProcessor.cs +++ b/backend/src/Squidex/Areas/Api/Config/OpenApi/ScopesProcessor.cs @@ -20,10 +20,7 @@ namespace Squidex.Areas.Api.Config.OpenApi { public bool Process(OperationProcessorContext context) { - if (context.OperationDescription.Operation.Security == null) - { - context.OperationDescription.Operation.Security = new List(); - } + context.OperationDescription.Operation.Security ??= new List(); var permissionAttribute = context.MethodInfo.GetCustomAttribute(); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs index da84d6945..b8a9c88f7 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Net.Http.Headers; @@ -97,7 +96,7 @@ namespace Squidex.Areas.Api.Controllers.Apps [ProducesResponseType(typeof(PatternsDto), 200)] [ApiPermission(Permissions.AppPatternsUpdate)] [ApiCosts(1)] - public async Task PutPattern(string app, Guid id, [FromBody] UpdatePatternDto request) + public async Task PutPattern(string app, string id, [FromBody] UpdatePatternDto request) { var command = request.ToUpdateCommand(id); @@ -123,7 +122,7 @@ namespace Squidex.Areas.Api.Controllers.Apps [ProducesResponseType(typeof(PatternsDto), 200)] [ApiPermission(Permissions.AppPatternsDelete)] [ApiCosts(1)] - public async Task DeletePattern(string app, Guid id) + public async Task DeletePattern(string app, string id) { var command = new DeletePattern { PatternId = id }; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppWorkflowsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppWorkflowsController.cs index 5a5099d4e..5e55f3142 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppWorkflowsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppWorkflowsController.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Net.Http.Headers; @@ -98,7 +97,7 @@ namespace Squidex.Areas.Api.Controllers.Apps [ProducesResponseType(typeof(WorkflowsDto), 200)] [ApiPermission(Permissions.AppWorkflowsUpdate)] [ApiCosts(1)] - public async Task PutWorkflow(string app, Guid id, [FromBody] UpdateWorkflowDto request) + public async Task PutWorkflow(string app, string id, [FromBody] UpdateWorkflowDto request) { var command = request.ToCommand(id); @@ -121,7 +120,7 @@ namespace Squidex.Areas.Api.Controllers.Apps [ProducesResponseType(typeof(WorkflowsDto), 200)] [ApiPermission(Permissions.AppWorkflowsUpdate)] [ApiCosts(1)] - public async Task DeleteWorkflow(string app, Guid id) + public async Task DeleteWorkflow(string app, string id) { var command = new DeleteWorkflow { WorkflowId = id }; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs index 32392e1df..90d469f06 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs @@ -105,7 +105,6 @@ namespace Squidex.Areas.Api.Controllers.Apps var response = Deferred.Response(() => { var userOrClientId = HttpContext.User.UserOrClientId()!; - var userPermissions = Resources.Permissions; return AppDto.FromApp(App, userOrClientId, appPlansProvider, Resources); }); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs index 2224b2e9f..816ad2e5f 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using NodaTime; @@ -17,6 +16,7 @@ using Squidex.Areas.Api.Controllers.Rules; using Squidex.Areas.Api.Controllers.Schemas; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps.Plans; +using Squidex.Infrastructure; using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Security; using Squidex.Web; @@ -53,7 +53,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// /// The id of the app. /// - public Guid Id { get; set; } + public DomainId Id { get; set; } /// /// The timestamp when the app has been created. diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/PatternDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/PatternDto.cs index 39761d261..0867d8113 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/PatternDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/PatternDto.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.ComponentModel.DataAnnotations; using Squidex.Domain.Apps.Core.Apps; +using Squidex.Infrastructure; using Squidex.Infrastructure.Reflection; using Squidex.Web; @@ -18,7 +18,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// /// Unique id of the pattern. /// - public Guid Id { get; set; } + public DomainId Id { get; set; } /// /// The name of the suggestion. @@ -37,7 +37,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// public string? Message { get; set; } - public static PatternDto FromPattern(Guid id, AppPattern pattern, Resources resources) + public static PatternDto FromPattern(DomainId id, AppPattern pattern, Resources resources) { var result = SimpleMapper.Map(pattern, new PatternDto { Id = id }); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdatePatternDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdatePatternDto.cs index 384c1c909..909f50da6 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdatePatternDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdatePatternDto.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.ComponentModel.DataAnnotations; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Infrastructure.Reflection; @@ -36,7 +35,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models return SimpleMapper.Map(this, new AddPattern()); } - public UpdatePattern ToUpdateCommand(Guid id) + public UpdatePattern ToUpdateCommand(string id) { return SimpleMapper.Map(this, new UpdatePattern { PatternId = id }); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateWorkflowDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateWorkflowDto.cs index cac16339f..c1aa74f63 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateWorkflowDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateWorkflowDto.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Apps.Commands; +using Squidex.Infrastructure; namespace Squidex.Areas.Api.Controllers.Apps.Models { @@ -30,7 +30,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// /// The schema ids. /// - public List? SchemaIds { get; set; } + public List? SchemaIds { get; set; } /// /// The initial step. @@ -38,7 +38,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models [Required] public Status Initial { get; set; } - public UpdateWorkflow ToCommand(Guid id) + public UpdateWorkflow ToCommand(string id) { var workflow = new Workflow( Initial, diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowDto.cs index 69351c835..a8134c043 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowDto.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Infrastructure; using Squidex.Infrastructure.Reflection; using Squidex.Web; @@ -20,7 +20,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// /// The workflow id. /// - public Guid Id { get; set; } + public DomainId Id { get; set; } /// /// The name of the workflow. @@ -36,14 +36,14 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// /// The schema ids. /// - public IReadOnlyList? SchemaIds { get; set; } + public IReadOnlyList? SchemaIds { get; set; } /// /// The initial step. /// public Status Initial { get; set; } - public static WorkflowDto FromWorkflow(Guid id, Workflow workflow) + public static WorkflowDto FromWorkflow(DomainId id, Workflow workflow) { var result = SimpleMapper.Map(workflow, new WorkflowDto { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs index 12078adf9..4cae2ce24 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs @@ -77,11 +77,11 @@ namespace Squidex.Areas.Api.Controllers.Assets if (Guid.TryParse(idOrSlug, out var guid)) { - asset = await assetRepository.FindAssetAsync(guid); + asset = await assetRepository.FindAssetAsync(AppId, guid); } else { - asset = await assetRepository.FindAssetBySlugAsync(App.Id, idOrSlug); + asset = await assetRepository.FindAssetBySlugAsync(AppId, idOrSlug); } return await DeliverAssetAsync(asset, query); @@ -102,7 +102,8 @@ namespace Squidex.Areas.Api.Controllers.Assets [ApiPermission] [ApiCosts(0.5)] [AllowAnonymous] - public async Task GetAssetContent(Guid id, [FromQuery] AssetContentQueryDto query) + [Obsolete] + public async Task GetAssetContent(string id, [FromQuery] AssetContentQueryDto query) { var asset = await assetRepository.FindAssetAsync(id); @@ -125,7 +126,7 @@ namespace Squidex.Areas.Api.Controllers.Assets if (query.Version > EtagVersion.Any && asset.Version != query.Version) { - asset = await assetLoader.GetAsync(asset.Id, query.Version); + asset = await assetLoader.GetAsync(AppId, asset.Id, query.Version); } var resizeOptions = query.ToResizeOptions(asset); @@ -143,9 +144,9 @@ namespace Squidex.Areas.Api.Controllers.Assets if (asset.Type == AssetType.Image && resizeOptions.IsValid) { - callback = new FileCallback(async (bodyStream, range, ct) => + callback = async (bodyStream, range, ct) => { - var resizedAsset = $"{asset.Id}_{asset.FileVersion}_{resizeOptions}"; + var resizedAsset = $"{asset.AppId.Id}_{asset.Id}_{asset.FileVersion}_{resizeOptions}"; if (query.ForceResize) { @@ -155,23 +156,23 @@ namespace Squidex.Areas.Api.Controllers.Assets { try { - await assetStore.DownloadAsync(resizedAsset, bodyStream); + await assetStore.DownloadAsync(resizedAsset, bodyStream, ct: ct); } catch (AssetNotFoundException) { await ResizeAsync(asset, bodyStream, resizedAsset, resizeOptions, false, ct); } } - }); + }; } else { contentLength = asset.FileSize; - callback = new FileCallback(async (bodyStream, range, ct) => + callback = async (bodyStream, range, ct) => { - await assetFileStore.DownloadAsync(asset.Id, asset.FileVersion, bodyStream, range, ct); - }); + await assetFileStore.DownloadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, bodyStream, range, ct); + }; } return new FileCallbackResult(asset.MimeType, callback) @@ -195,7 +196,7 @@ namespace Squidex.Areas.Api.Controllers.Assets { using (Profiler.Trace("ResizeDownload")) { - await assetFileStore.DownloadAsync(asset.Id, asset.FileVersion, sourceStream); + await assetFileStore.DownloadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, sourceStream); sourceStream.Position = 0; } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs index ba46c2964..14468ef3e 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Net.Http.Headers; @@ -50,11 +49,11 @@ namespace Squidex.Areas.Api.Controllers.Assets [ProducesResponseType(typeof(AssetsDto), 200)] [ApiPermission(Permissions.AppAssetsRead)] [ApiCosts(1)] - public async Task GetAssetFolders(string app, [FromQuery] Guid parentId) + public async Task GetAssetFolders(string app, [FromQuery] string parentId) { var (folders, path) = await AsyncHelper.WhenAll( assetQuery.QueryAssetFoldersAsync(Context, parentId), - assetQuery.FindAssetFolderAsync(parentId)); + assetQuery.FindAssetFolderAsync(Context.App.Id, parentId)); var response = Deferred.Response(() => { @@ -85,7 +84,7 @@ namespace Squidex.Areas.Api.Controllers.Assets { var command = request.ToCommand(); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return CreatedAtAction(nameof(GetAssetFolders), new { parentId = request.ParentId, app }, response); } @@ -107,11 +106,11 @@ namespace Squidex.Areas.Api.Controllers.Assets [AssetRequestSizeLimit] [ApiPermission(Permissions.AppAssetsUpdate)] [ApiCosts(1)] - public async Task PutAssetFolder(string app, Guid id, [FromBody] RenameAssetFolderDto request) + public async Task PutAssetFolder(string app, string id, [FromBody] RenameAssetFolderDto request) { var command = request.ToCommand(id); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -132,11 +131,11 @@ namespace Squidex.Areas.Api.Controllers.Assets [AssetRequestSizeLimit] [ApiPermission(Permissions.AppAssetsUpdate)] [ApiCosts(1)] - public async Task PutAssetFolderParent(string app, Guid id, [FromBody] MoveAssetItemDto request) + public async Task PutAssetFolderParent(string app, string id, [FromBody] MoveAssetItemDto request) { var command = request.ToFolderCommand(id); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -154,14 +153,14 @@ namespace Squidex.Areas.Api.Controllers.Assets [Route("apps/{app}/assets/folders/{id}/", Order = -1)] [ApiPermission(Permissions.AppAssetsUpdate)] [ApiCosts(1)] - public async Task DeleteAssetFolder(string app, Guid id) + public async Task DeleteAssetFolder(string app, string id) { await CommandBus.PublishAsync(new DeleteAssetFolder { AssetFolderId = id }); return NoContent(); } - private async Task InvokeCommandAsync(string app, ICommand command) + private async Task InvokeCommandAsync(ICommand command) { var context = await CommandBus.PublishAsync(command); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs index a6312f470..e34144921 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -94,9 +93,9 @@ namespace Squidex.Areas.Api.Controllers.Assets [ProducesResponseType(typeof(AssetsDto), 200)] [ApiPermission(Permissions.AppAssetsRead)] [ApiCosts(1)] - public async Task GetAssets(string app, [FromQuery] Guid? parentId, [FromQuery] string? ids = null, [FromQuery] string? q = null) + public async Task GetAssets(string app, [FromQuery] string? parentId, [FromQuery] string? ids = null, [FromQuery] string? q = null) { - var assets = await assetQuery.QueryAsync(Context, parentId, CreateQuery(ids, q)); + var assets = await assetQuery.QueryAsync(Context, parentId!, CreateQuery(ids, q)); var response = Deferred.Response(() => { @@ -149,7 +148,7 @@ namespace Squidex.Areas.Api.Controllers.Assets [ProducesResponseType(typeof(AssetDto), 200)] [ApiPermission(Permissions.AppAssetsRead)] [ApiCosts(1)] - public async Task GetAsset(string app, Guid id) + public async Task GetAsset(string app, string id) { var asset = await assetQuery.FindAssetAsync(Context, id); @@ -186,13 +185,13 @@ namespace Squidex.Areas.Api.Controllers.Assets [AssetRequestSizeLimit] [ApiPermission(Permissions.AppAssetsCreate)] [ApiCosts(1)] - public async Task PostAsset(string app, [FromQuery] Guid parentId, IFormFile file) + public async Task PostAsset(string app, [FromQuery] string parentId, IFormFile file) { var assetFile = await CheckAssetFileAsync(file); var command = new CreateAsset { File = assetFile, ParentId = parentId }; - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return CreatedAtAction(nameof(GetAsset), new { app, id = response.Id }, response); } @@ -216,13 +215,13 @@ namespace Squidex.Areas.Api.Controllers.Assets [ProducesResponseType(typeof(AssetDto), 200)] [ApiPermission(Permissions.AppAssetsUpload)] [ApiCosts(1)] - public async Task PutAssetContent(string app, Guid id, IFormFile file) + public async Task PutAssetContent(string app, string id, IFormFile file) { var assetFile = await CheckAssetFileAsync(file); var command = new UpdateAsset { File = assetFile, AssetId = id }; - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -244,11 +243,11 @@ namespace Squidex.Areas.Api.Controllers.Assets [AssetRequestSizeLimit] [ApiPermission(Permissions.AppAssetsUpdate)] [ApiCosts(1)] - public async Task PutAsset(string app, Guid id, [FromBody] AnnotateAssetDto request) + public async Task PutAsset(string app, string id, [FromBody] AnnotateAssetDto request) { var command = request.ToCommand(id); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -269,11 +268,11 @@ namespace Squidex.Areas.Api.Controllers.Assets [AssetRequestSizeLimit] [ApiPermission(Permissions.AppAssetsUpdate)] [ApiCosts(1)] - public async Task PutAssetParent(string app, Guid id, [FromBody] MoveAssetItemDto request) + public async Task PutAssetParent(string app, string id, [FromBody] MoveAssetItemDto request) { var command = request.ToCommand(id); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -291,14 +290,14 @@ namespace Squidex.Areas.Api.Controllers.Assets [Route("apps/{app}/assets/{id}/")] [ApiPermission(Permissions.AppAssetsDelete)] [ApiCosts(1)] - public async Task DeleteAsset(string app, Guid id) + public async Task DeleteAsset(string app, string id) { await CommandBus.PublishAsync(new DeleteAsset { AssetId = id }); return NoContent(); } - private async Task InvokeCommandAsync(string app, ICommand command) + private async Task InvokeCommandAsync(ICommand command) { var context = await CommandBus.PublishAsync(command); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AnnotateAssetDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AnnotateAssetDto.cs index 098002cb3..cf8daadb5 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AnnotateAssetDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AnnotateAssetDto.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Entities.Assets.Commands; @@ -40,7 +39,7 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models /// public AssetMetadata? Metadata { get; set; } - public AnnotateAsset ToCommand(Guid id) + public AnnotateAsset ToCommand(string id) { return SimpleMapper.Map(this, new AnnotateAsset { AssetId = id }); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs index 826727184..3793632f9 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs @@ -23,12 +23,12 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models /// /// The id of the asset. /// - public Guid Id { get; set; } + public DomainId Id { get; set; } /// /// The id of the parent folder. Empty for files without parent. /// - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } /// /// The file name. @@ -201,8 +201,6 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models response.AddDeleteLink("delete", resources.Url(x => nameof(x.DeleteAsset), values)); } - var version = response.FileVersion; - if (!string.IsNullOrWhiteSpace(response.Slug)) { response.AddGetLink("content", resources.Url(x => nameof(x.GetAssetContentBySlug), new { app, idOrSlug = response.Id, more = response.Slug })); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFolderDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFolderDto.cs index 0fadd5d39..3f941e1c6 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFolderDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFolderDto.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.ComponentModel.DataAnnotations; using Squidex.Domain.Apps.Entities.Assets; +using Squidex.Infrastructure; using Squidex.Infrastructure.Reflection; using Squidex.Web; @@ -18,12 +18,12 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models /// /// The id of the asset. /// - public Guid Id { get; set; } + public DomainId Id { get; set; } /// /// The id of the parent folder. Empty for files without parent. /// - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } /// /// The folder name. diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFoldersDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFoldersDto.cs index 97b0bb917..35b96d798 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFoldersDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFoldersDto.cs @@ -38,7 +38,7 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models var response = new AssetFoldersDto { Total = assetFolders.Total, - Items = assetFolders.Select(x => AssetFolderDto.FromAssetFolder(x, resources)).ToArray(), + Items = assetFolders.Select(x => AssetFolderDto.FromAssetFolder(x, resources)).ToArray() }; response.Path = path.Select(x => AssetFolderDto.FromAssetFolder(x, resources)).ToArray(); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/CreateAssetFolderDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/CreateAssetFolderDto.cs index 1b2154b43..c0767f64d 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/CreateAssetFolderDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/CreateAssetFolderDto.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.ComponentModel.DataAnnotations; using Squidex.Domain.Apps.Entities.Assets.Commands; +using Squidex.Infrastructure; using Squidex.Infrastructure.Reflection; namespace Squidex.Areas.Api.Controllers.Assets.Models @@ -23,7 +23,7 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models /// /// The id of the parent folder. /// - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } public CreateAssetFolder ToCommand() { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/MoveAssetItemDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/MoveAssetItemDto.cs index 7053d9d53..337fc0fdf 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/MoveAssetItemDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/MoveAssetItemDto.cs @@ -5,8 +5,8 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Entities.Assets.Commands; +using Squidex.Infrastructure; namespace Squidex.Areas.Api.Controllers.Assets.Models { @@ -15,14 +15,14 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models /// /// The parent folder id. /// - public Guid ParentId { get; set; } + public DomainId ParentId { get; set; } - public MoveAsset ToCommand(Guid id) + public MoveAsset ToCommand(DomainId id) { return new MoveAsset { AssetId = id, ParentId = ParentId }; } - public MoveAssetFolder ToFolderCommand(Guid id) + public MoveAssetFolder ToFolderCommand(string id) { return new MoveAssetFolder { AssetFolderId = id, ParentId = ParentId }; } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/RenameAssetFolderDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/RenameAssetFolderDto.cs index c0b4568e9..c6e9cbcd2 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/RenameAssetFolderDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/RenameAssetFolderDto.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.ComponentModel.DataAnnotations; using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Infrastructure.Reflection; @@ -20,7 +19,7 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models [Required] public string FolderName { get; set; } - public RenameAssetFolder ToCommand(Guid id) + public RenameAssetFolder ToCommand(string id) { return SimpleMapper.Map(this, new RenameAssetFolder { AssetFolderId = id }); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Backups/BackupContentController.cs b/backend/src/Squidex/Areas/Api/Controllers/Backups/BackupContentController.cs index b76c72c91..7cb162c0a 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Backups/BackupContentController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Backups/BackupContentController.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -48,7 +47,7 @@ namespace Squidex.Areas.Api.Controllers.Backups [ProducesResponseType(typeof(FileResult), 200)] [ApiCosts(0)] [AllowAnonymous] - public async Task GetBackupContent(string app, Guid id) + public async Task GetBackupContent(string app, string id) { var backup = await backupservice.GetBackupAsync(AppId, id); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs index d73e03c19..97f0823c2 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; @@ -89,7 +88,7 @@ namespace Squidex.Areas.Api.Controllers.Backups [ProducesResponseType(typeof(List), 200)] [ApiPermission(Permissions.AppBackupsDelete)] [ApiCosts(0)] - public async Task DeleteBackup(string app, Guid id) + public async Task DeleteBackup(string app, string id) { await backupService.DeleteBackupAsync(AppId, id); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobDto.cs index 0f64a06df..df50f3b3b 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobDto.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; using Squidex.Domain.Apps.Entities.Backup; +using Squidex.Infrastructure; using Squidex.Infrastructure.Reflection; using Squidex.Web; @@ -18,7 +18,7 @@ namespace Squidex.Areas.Api.Controllers.Backups.Models /// /// The id of the backup job. /// - public Guid Id { get; set; } + public DomainId Id { get; set; } /// /// The time when the job has been started. diff --git a/backend/src/Squidex/Areas/Api/Controllers/Comments/CommentsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Comments/CommentsController.cs index 792f038a5..424fed72e 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Comments/CommentsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Comments/CommentsController.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Net.Http.Headers; @@ -108,7 +107,7 @@ namespace Squidex.Areas.Api.Controllers.Comments [Route("apps/{app}/comments/{commentsId}/{commentId}")] [ApiPermission(Permissions.AppCommon)] [ApiCosts(0)] - public async Task PutComment(string app, string commentsId, Guid commentId, [FromBody] UpsertCommentDto request) + public async Task PutComment(string app, string commentsId, string commentId, [FromBody] UpsertCommentDto request) { await CommandBus.PublishAsync(request.ToUpdateComment(commentsId, commentId)); @@ -129,7 +128,7 @@ namespace Squidex.Areas.Api.Controllers.Comments [Route("apps/{app}/comments/{commentsId}/{commentId}")] [ApiPermission(Permissions.AppCommon)] [ApiCosts(0)] - public async Task DeleteComment(string app, string commentsId, Guid commentId) + public async Task DeleteComment(string app, string commentsId, string commentId) { await CommandBus.PublishAsync(new DeleteComment { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentDto.cs index 25bbd699f..96b5ed41f 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentDto.cs @@ -20,7 +20,7 @@ namespace Squidex.Areas.Api.Controllers.Comments.Models /// /// The id of the comment. /// - public Guid Id { get; set; } + public DomainId Id { get; set; } /// /// The time when the comment was created or updated last. diff --git a/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentsDto.cs index 5fc302acb..d15b9d0e3 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentsDto.cs @@ -5,10 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using Squidex.Domain.Apps.Entities.Comments; +using Squidex.Infrastructure; namespace Squidex.Areas.Api.Controllers.Comments.Models { @@ -27,7 +27,7 @@ namespace Squidex.Areas.Api.Controllers.Comments.Models /// /// The deleted comments since the last version. /// - public List? DeletedComments { get; set; } + public List? DeletedComments { get; set; } /// /// The current version. diff --git a/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/UpsertCommentDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/UpsertCommentDto.cs index 0a17abffa..b61a73451 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/UpsertCommentDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/UpsertCommentDto.cs @@ -30,7 +30,7 @@ namespace Squidex.Areas.Api.Controllers.Comments.Models return SimpleMapper.Map(this, new CreateComment { CommentsId = commentsId }); } - public UpdateComment ToUpdateComment(string commentsId, Guid commentId) + public UpdateComment ToUpdateComment(string commentsId, string commentId) { return SimpleMapper.Map(this, new UpdateComment { CommentsId = commentsId, CommentId = commentId }); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Comments/Notifications/UserNotificationsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Comments/Notifications/UserNotificationsController.cs index 8b55ee330..187b1dd96 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Comments/Notifications/UserNotificationsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Comments/Notifications/UserNotificationsController.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Net.Http.Headers; @@ -25,7 +24,7 @@ namespace Squidex.Areas.Api.Controllers.Comments.Notifications [ApiExplorerSettings(GroupName = nameof(Notifications))] public sealed class UserNotificationsController : ApiController { - private static readonly NamedId NoApp = NamedId.Of(Guid.Empty, "none"); + private static readonly NamedId NoApp = NamedId.Of(DomainId.Empty, "none"); private readonly ICommentsLoader commentsLoader; public UserNotificationsController(ICommandBus commandBus, ICommentsLoader commentsLoader) @@ -77,7 +76,7 @@ namespace Squidex.Areas.Api.Controllers.Comments.Notifications [HttpDelete] [Route("users/{userId}/notifications/{commentId}")] [ApiPermission] - public async Task DeleteComment(string userId, Guid commentId) + public async Task DeleteComment(string userId, string commentId) { CheckPermissions(userId); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs index 8d222b9d6..16c5f6f44 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; @@ -242,7 +241,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ProducesResponseType(typeof(ContentsDto), 200)] [ApiPermission] [ApiCosts(1)] - public async Task GetContent(string app, string name, Guid id) + public async Task GetContent(string app, string name, string id) { var content = await contentQuery.FindContentAsync(Context, name, id); @@ -270,7 +269,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [Route("content/{app}/{name}/{id}/{version}/")] [ApiPermission(Permissions.AppContentsRead)] [ApiCosts(1)] - public async Task GetContentVersion(string app, string name, Guid id, int version) + public async Task GetContentVersion(string app, string name, string id, int version) { var content = await contentQuery.FindContentAsync(Context, name, id, version); @@ -301,7 +300,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ApiCosts(1)] public async Task PostContent(string app, string name, [FromBody] NamedContentData request, [FromQuery] bool publish = false) { - var command = new CreateContent { ContentId = Guid.NewGuid(), Data = request.ToCleaned(), Publish = publish }; + var command = new CreateContent { Data = request.ToCleaned(), Publish = publish }; var response = await InvokeCommandAsync(command); @@ -390,7 +389,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ProducesResponseType(typeof(ContentsDto), 200)] [ApiPermission(Permissions.AppContentsUpdate)] [ApiCosts(1)] - public async Task PutContent(string app, string name, Guid id, [FromBody] NamedContentData request) + public async Task PutContent(string app, string name, string id, [FromBody] NamedContentData request) { var command = new UpdateContent { ContentId = id, Data = request.ToCleaned() }; @@ -419,7 +418,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ProducesResponseType(typeof(ContentsDto), 200)] [ApiPermission(Permissions.AppContentsUpdate)] [ApiCosts(1)] - public async Task PatchContent(string app, string name, Guid id, [FromBody] NamedContentData request) + public async Task PatchContent(string app, string name, string id, [FromBody] NamedContentData request) { var command = new PatchContent { ContentId = id, Data = request.ToCleaned() }; @@ -448,7 +447,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ProducesResponseType(typeof(ContentsDto), 200)] [ApiPermission(Permissions.AppContentsUpdate)] [ApiCosts(1)] - public async Task PutContentStatus(string app, string name, Guid id, ChangeStatusDto request) + public async Task PutContentStatus(string app, string name, string id, ChangeStatusDto request) { var command = request.ToCommand(id); @@ -475,7 +474,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ProducesResponseType(typeof(ContentsDto), 200)] [ApiPermission(Permissions.AppContentsVersionCreate)] [ApiCosts(1)] - public async Task CreateDraft(string app, string name, Guid id) + public async Task CreateDraft(string app, string name, string id) { var command = new CreateContentDraft { ContentId = id }; @@ -502,7 +501,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ProducesResponseType(typeof(ContentsDto), 200)] [ApiPermission(Permissions.AppContentsDelete)] [ApiCosts(1)] - public async Task DeleteVersion(string app, string name, Guid id) + public async Task DeleteVersion(string app, string name, string id) { var command = new DeleteContentDraft { ContentId = id }; @@ -528,7 +527,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [Route("content/{app}/{name}/{id}/")] [ApiPermission(Permissions.AppContentsDelete)] [ApiCosts(1)] - public async Task DeleteContent(string app, string name, Guid id) + public async Task DeleteContent(string app, string name, string id) { var command = new DeleteContent { ContentId = id }; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemaOpenApiGenerator.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemaOpenApiGenerator.cs index 2662011e3..f5b925f82 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemaOpenApiGenerator.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemaOpenApiGenerator.cs @@ -215,7 +215,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Generator if (path.StartsWith("/{id}", StringComparison.OrdinalIgnoreCase)) { - operation.AddPathParameter("id", JsonObjectType.String, $"The id of the {schemaName} content.", JsonFormatStrings.Guid); + operation.AddPathParameter("id", JsonObjectType.String, $"The id of the {schemaName} content."); operation.AddResponse("404", $"App, schema or {schemaName} content not found."); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemasOpenApiGenerator.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemasOpenApiGenerator.cs index 3459bddcd..25b027ffa 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemasOpenApiGenerator.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemasOpenApiGenerator.cs @@ -83,13 +83,13 @@ namespace Squidex.Areas.Api.Controllers.Contents.Generator private void GenerateSchemasOperations(IEnumerable schemas, IAppEntity app) { - requestCache.AddDependency(app.Id, app.Version); + requestCache.AddDependency(app.UniqueId, app.Version); var appBasePath = $"/content/{app.Name}"; foreach (var schema in schemas.Where(x => x.SchemaDef.IsPublished)) { - requestCache.AddDependency(schema.Id, schema.Version); + requestCache.AddDependency(schema.UniqueId, schema.Version); var partition = app.PartitionResolver(); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/BulkResultDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/BulkResultDto.cs index 5790d8c81..50f957655 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/BulkResultDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/BulkResultDto.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Microsoft.AspNetCore.Http; using Squidex.Domain.Apps.Entities.Contents; +using Squidex.Infrastructure; using Squidex.Web; namespace Squidex.Areas.Api.Controllers.Contents.Models @@ -22,7 +22,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models /// /// The id of the content when the import succeeds. /// - public Guid? ContentId { get; set; } + public DomainId? ContentId { get; set; } public static BulkResultDto FromImportResult(BulkUpdateResultItem result, HttpContext httpContext) { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/BulkUpdateJobDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/BulkUpdateJobDto.cs index d8b021b55..68e2df912 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/BulkUpdateJobDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/BulkUpdateJobDto.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Contents.Commands; +using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Queries; using Squidex.Infrastructure.Reflection; @@ -24,7 +24,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models /// /// An optional id of the content to update. /// - public Guid? Id { get; set; } + public DomainId? Id { get; set; } /// /// The data of the content when type is set to 'Upsert'. diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ChangeStatusDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ChangeStatusDto.cs index 7a89789c9..91f3659ed 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ChangeStatusDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ChangeStatusDto.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.ComponentModel.DataAnnotations; using NodaTime; using Squidex.Domain.Apps.Core.Contents; @@ -26,7 +25,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models /// public Instant? DueTime { get; set; } - public ChangeContentStatus ToCommand(Guid id) + public ChangeContentStatus ToCommand(string id) { return new ChangeContentStatus { ContentId = id, Status = Status, DueTime = DueTime }; } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs index fbe8555c6..39660b5e6 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.ComponentModel.DataAnnotations; using System.Linq; using NodaTime; @@ -25,7 +24,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models /// /// The if of the content item. /// - public Guid Id { get; set; } + public DomainId Id { get; set; } /// /// The user that has created the content item. diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsIdsQueryDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsIdsQueryDto.cs index b31cd5b07..37346144d 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsIdsQueryDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsIdsQueryDto.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using Squidex.Infrastructure; namespace Squidex.Areas.Api.Controllers.Contents.Models { @@ -17,6 +17,6 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models /// The list of ids to query. /// [Required] - public List Ids { get; set; } + public List Ids { get; set; } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ScheduleJobDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ScheduleJobDto.cs index 265afeb98..0ea841dff 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ScheduleJobDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ScheduleJobDto.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.ComponentModel.DataAnnotations; using NodaTime; using Squidex.Domain.Apps.Core.Contents; @@ -18,7 +17,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models /// /// The id of the schedule job. /// - public Guid Id { get; set; } + public DomainId Id { get; set; } /// /// The new status. diff --git a/backend/src/Squidex/Areas/Api/Controllers/History/Models/HistoryEventDto.cs b/backend/src/Squidex/Areas/Api/Controllers/History/Models/HistoryEventDto.cs index 4247d1adc..2a8c2c7e4 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/History/Models/HistoryEventDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/History/Models/HistoryEventDto.cs @@ -5,10 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.ComponentModel.DataAnnotations; using NodaTime; using Squidex.Domain.Apps.Entities.History; +using Squidex.Infrastructure; using Squidex.Infrastructure.Reflection; namespace Squidex.Areas.Api.Controllers.History.Models @@ -36,7 +36,7 @@ namespace Squidex.Areas.Api.Controllers.History.Models /// /// Gets a unique id for the event. /// - public Guid EventId { get; set; } + public DomainId EventId { get; set; } /// /// The time when the event happened. diff --git a/backend/src/Squidex/Areas/Api/Controllers/QueryDto.cs b/backend/src/Squidex/Areas/Api/Controllers/QueryDto.cs index 7272eddf1..da443780e 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/QueryDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/QueryDto.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Squidex.Domain.Apps.Entities; +using Squidex.Infrastructure; namespace Squidex.Areas.Api.Controllers { @@ -18,7 +18,7 @@ namespace Squidex.Areas.Api.Controllers /// /// The optional list of ids to query. /// - public List? Ids { get; set; } + public List? Ids { get; set; } /// /// The optional odata query. @@ -34,7 +34,7 @@ namespace Squidex.Areas.Api.Controllers /// /// The parent id (for assets). /// - public Guid? ParentId { get; set; } + public DomainId? ParentId { get; set; } public Q ToQuery() { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs index a844c6f19..f7af01a30 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.ComponentModel.DataAnnotations; using Newtonsoft.Json; using NodaTime; @@ -23,7 +22,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models /// /// The id of the rule. /// - public Guid Id { get; set; } + public DomainId Id { get; set; } /// /// The user that has created the rule. @@ -90,7 +89,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models /// public Instant? LastExecuted { get; set; } - public static RuleDto FromRule(IEnrichedRuleEntity rule, Guid? runningRuleId, Resources resources) + public static RuleDto FromRule(IEnrichedRuleEntity rule, DomainId? runningRuleId, Resources resources) { var result = new RuleDto(); @@ -105,7 +104,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models return result.CreateLinks(resources, runningRuleId); } - private RuleDto CreateLinks(Resources resources, Guid? runningRuleId) + private RuleDto CreateLinks(Resources resources, DomainId? runningRuleId) { var values = new { app = resources.App, id = Id }; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs index 3866c88b7..24a49e55d 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.ComponentModel.DataAnnotations; using NodaTime; using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Entities.Rules; +using Squidex.Infrastructure; using Squidex.Infrastructure.Reflection; using Squidex.Web; @@ -20,7 +20,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models /// /// The id of the event. /// - public Guid Id { get; set; } + public DomainId Id { get; set; } /// /// The time when the event has been created. diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RulesDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RulesDto.cs index c46cf07e7..6fee093cd 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RulesDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RulesDto.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using Squidex.Domain.Apps.Entities.Rules; +using Squidex.Infrastructure; using Squidex.Web; namespace Squidex.Areas.Api.Controllers.Rules.Models @@ -25,9 +25,9 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models /// /// The id of the rule that is currently rerunning. /// - public Guid? RunningRuleId { get; set; } + public DomainId? RunningRuleId { get; set; } - public static RulesDto FromRules(IEnumerable items, Guid? runningRuleId, Resources resources) + public static RulesDto FromRules(IEnumerable items, DomainId? runningRuleId, Resources resources) { var result = new RulesDto { @@ -39,7 +39,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models return result.CreateLinks(resources, runningRuleId); } - private RulesDto CreateLinks(Resources resources, Guid? runningRuleId) + private RulesDto CreateLinks(Resources resources, DomainId? runningRuleId) { var values = new { app = resources.App }; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/Triggers/ContentChangedRuleTriggerSchemaDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/Triggers/ContentChangedRuleTriggerSchemaDto.cs index 9ce4b6915..34bc7a81c 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/Triggers/ContentChangedRuleTriggerSchemaDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/Triggers/ContentChangedRuleTriggerSchemaDto.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using Squidex.Infrastructure; namespace Squidex.Areas.Api.Controllers.Rules.Models.Triggers { @@ -14,7 +14,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models.Triggers /// /// The id of the schema. /// - public Guid SchemaId { get; set; } + public DomainId SchemaId { get; set; } /// /// Javascript condition when to trigger. diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/UpdateRuleDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/UpdateRuleDto.cs index 8474e9952..ab6d0ce19 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/UpdateRuleDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/UpdateRuleDto.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Newtonsoft.Json; using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Entities.Rules.Commands; @@ -30,7 +29,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models [JsonConverter(typeof(RuleActionConverter))] public RuleAction Action { get; set; } - public UpdateRule ToCommand(Guid id) + public UpdateRule ToCommand(string id) { var command = new UpdateRule { RuleId = id, Action = Action, Name = Name }; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs index d34c674d0..75e48cada 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -120,7 +119,7 @@ namespace Squidex.Areas.Api.Controllers.Rules { var command = request.ToCommand(); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return CreatedAtAction(nameof(GetRules), new { app }, response); } @@ -160,11 +159,11 @@ namespace Squidex.Areas.Api.Controllers.Rules [ProducesResponseType(typeof(RuleDto), 200)] [ApiPermission(Permissions.AppRulesUpdate)] [ApiCosts(1)] - public async Task PutRule(string app, Guid id, [FromBody] UpdateRuleDto request) + public async Task PutRule(string app, string id, [FromBody] UpdateRuleDto request) { var command = request.ToCommand(id); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -183,11 +182,11 @@ namespace Squidex.Areas.Api.Controllers.Rules [ProducesResponseType(typeof(RuleDto), 200)] [ApiPermission(Permissions.AppRulesDisable)] [ApiCosts(1)] - public async Task EnableRule(string app, Guid id) + public async Task EnableRule(string app, string id) { var command = new EnableRule { RuleId = id }; - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -206,11 +205,11 @@ namespace Squidex.Areas.Api.Controllers.Rules [ProducesResponseType(typeof(RuleDto), 200)] [ApiPermission(Permissions.AppRulesDisable)] [ApiCosts(1)] - public async Task DisableRule(string app, Guid id) + public async Task DisableRule(string app, string id) { var command = new DisableRule { RuleId = id }; - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -228,7 +227,7 @@ namespace Squidex.Areas.Api.Controllers.Rules [Route("apps/{app}/rules/{id}/trigger/")] [ApiPermission(Permissions.AppRulesEvents)] [ApiCosts(1)] - public async Task TriggerRule(string app, Guid id) + public async Task TriggerRule(string app, string id) { var command = new TriggerRule { RuleId = id }; @@ -250,7 +249,7 @@ namespace Squidex.Areas.Api.Controllers.Rules [ProducesResponseType(204)] [ApiPermission(Permissions.AppRulesEvents)] [ApiCosts(1)] - public async Task PutRuleRun(string app, Guid id) + public async Task PutRuleRun(string app, string id) { await ruleRunnerService.RunAsync(App.Id, id); @@ -270,7 +269,7 @@ namespace Squidex.Areas.Api.Controllers.Rules [Route("apps/{app}/rules/{id}/")] [ApiPermission(Permissions.AppRulesDelete)] [ApiCosts(1)] - public async Task DeleteRule(string app, Guid id) + public async Task DeleteRule(string app, string id) { await CommandBus.PublishAsync(new DeleteRule { RuleId = id }); @@ -293,9 +292,9 @@ namespace Squidex.Areas.Api.Controllers.Rules [ProducesResponseType(typeof(RuleEventsDto), 200)] [ApiPermission(Permissions.AppRulesRead)] [ApiCosts(0)] - public async Task GetEvents(string app, [FromQuery] Guid? ruleId = null, [FromQuery] int skip = 0, [FromQuery] int take = 20) + public async Task GetEvents(string app, [FromQuery] string? ruleId = null, [FromQuery] int skip = 0, [FromQuery] int take = 20) { - var ruleEvents = await ruleEventsRepository.QueryByAppAsync(AppId, ruleId, skip, take); + var ruleEvents = await ruleEventsRepository.QueryByAppAsync(AppId, DomainId.CreateNullable(ruleId), skip, take); var response = RuleEventsDto.FromRuleEvents(ruleEvents, Resources); @@ -315,7 +314,7 @@ namespace Squidex.Areas.Api.Controllers.Rules [Route("apps/{app}/rules/events/{id}/")] [ApiPermission(Permissions.AppRulesEvents)] [ApiCosts(0)] - public async Task PutEvent(string app, Guid id) + public async Task PutEvent(string app, string id) { var ruleEvent = await ruleEventsRepository.FindAsync(id); @@ -342,7 +341,7 @@ namespace Squidex.Areas.Api.Controllers.Rules [Route("apps/{app}/rules/events/{id}/")] [ApiPermission(Permissions.AppRulesEvents)] [ApiCosts(0)] - public async Task DeleteEvent(string app, Guid id) + public async Task DeleteEvent(string app, string id) { var ruleEvent = await ruleEventsRepository.FindAsync(id); @@ -356,7 +355,7 @@ namespace Squidex.Areas.Api.Controllers.Rules return NoContent(); } - private async Task InvokeCommandAsync(string app, ICommand command) + private async Task InvokeCommandAsync(ICommand command) { var context = await CommandBus.PublishAsync(command); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/Fields/ReferencesFieldPropertiesDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/Fields/ReferencesFieldPropertiesDto.cs index a769176ff..eb8034af9 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/Fields/ReferencesFieldPropertiesDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/Fields/ReferencesFieldPropertiesDto.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.ObjectModel; using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Infrastructure; using Squidex.Infrastructure.Reflection; namespace Squidex.Areas.Api.Controllers.Schemas.Models.Fields @@ -42,7 +42,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models.Fields /// /// The id of the referenced schemas. /// - public ReadOnlyCollection? SchemaIds { get; set; } + public ReadOnlyCollection? SchemaIds { get; set; } public override FieldProperties ToProperties() { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs index 5dd4cd33c..7e324df49 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.ComponentModel.DataAnnotations; using NodaTime; using Squidex.Areas.Api.Controllers.Contents; @@ -21,7 +20,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models /// /// The id of the schema. /// - public Guid Id { get; set; } + public DomainId Id { get; set; } /// /// The name of the schema. Unique within the app. diff --git a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/UpsertSchemaDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/UpsertSchemaDto.cs index eb6fe9400..f117e481f 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/UpsertSchemaDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/UpsertSchemaDto.cs @@ -54,7 +54,8 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models /// public bool IsPublished { get; set; } - public static TCommand ToCommand(TDto dto, TCommand command) where TCommand : UpsertCommand where TDto : UpsertSchemaDto + public static TCommand ToCommand(TDto dto, TCommand command) + where TCommand : SchemaCommand, IUpsertCommand where TDto : UpsertSchemaDto { SimpleMapper.Map(dto, command); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs b/backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs index eb49eb3f5..60a64fed7 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs @@ -78,9 +78,9 @@ namespace Squidex.Areas.Api.Controllers.Schemas { ISchemaEntity? schema; - if (Guid.TryParse(name, out var id)) + if (Guid.TryParse(name, out var guid)) { - schema = await appProvider.GetSchemaAsync(AppId, id); + schema = await appProvider.GetSchemaAsync(AppId, guid); } else { @@ -121,7 +121,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas { var command = request.ToCommand(); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return CreatedAtAction(nameof(GetSchema), new { app, name = request.Name }, response); } @@ -146,7 +146,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas { var command = request.ToCommand(); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -171,7 +171,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas { var command = request.ToCommand(); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -195,7 +195,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas { var command = request.ToCommand(); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -219,7 +219,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas { var command = request.ToCommand(); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -244,7 +244,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas { var command = request.ToCommand(); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -267,7 +267,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas { var command = new PublishSchema(); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -290,7 +290,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas { var command = new UnpublishSchema(); - var response = await InvokeCommandAsync(app, command); + var response = await InvokeCommandAsync(command); return Ok(response); } @@ -315,7 +315,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas return NoContent(); } - private async Task InvokeCommandAsync(string app, ICommand command) + private async Task InvokeCommandAsync(ICommand command) { var context = await CommandBus.PublishAsync(command); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs b/backend/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs index 8f42efb86..00da64661 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs @@ -178,7 +178,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics var callback = new FileCallback((body, range, ct) => { - return appLogStore.ReadLogAsync(Guid.Parse(appId), today.AddDays(-30), today, body, ct); + return appLogStore.ReadLogAsync(appId, today.AddDays(-30), today, body, ct); }); return new FileCallbackResult("text/csv", callback) diff --git a/backend/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs b/backend/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs index 97056f31c..e518866a2 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs @@ -176,7 +176,7 @@ namespace Squidex.Areas.Api.Controllers.Users } catch { - await body.WriteAsync(AvatarBytes); + await body.WriteAsync(AvatarBytes, ct); } }); diff --git a/backend/src/Squidex/Areas/IdentityServer/Controllers/Profile/ProfileController.cs b/backend/src/Squidex/Areas/IdentityServer/Controllers/Profile/ProfileController.cs index 5dec1f7b9..6646abdb8 100644 --- a/backend/src/Squidex/Areas/IdentityServer/Controllers/Profile/ProfileController.cs +++ b/backend/src/Squidex/Areas/IdentityServer/Controllers/Profile/ProfileController.cs @@ -258,10 +258,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Profile SimpleMapper.Map(model, result); } - if (result.Properties == null) - { - result.Properties = user.GetCustomProperties().Select(UserProperty.FromTuple).ToList(); - } + result.Properties ??= user.GetCustomProperties().Select(UserProperty.FromTuple).ToList(); return result; } diff --git a/backend/src/Squidex/Areas/IdentityServer/Views/Profile/Profile.cshtml b/backend/src/Squidex/Areas/IdentityServer/Views/Profile/Profile.cshtml index 31b33c81f..f35ff7319 100644 --- a/backend/src/Squidex/Areas/IdentityServer/Views/Profile/Profile.cshtml +++ b/backend/src/Squidex/Areas/IdentityServer/Views/Profile/Profile.cshtml @@ -10,7 +10,7 @@ @if (ViewContext.ViewData.ModelState[field]?.ValidationState == Microsoft.AspNetCore.Mvc.ModelBinding.ModelValidationState.Invalid) {
- @Html.ValidationMessage(field) + Html.ValidationMessage(field)
} } @@ -278,13 +278,13 @@ } document.addEventListener('click', - function (event) { + function(event) { if (event.target.className.indexOf('remove-item') >= 0) { event.target.parentNode.parentNode.remove(); updateNames(); } - }) + }); pictureButton.addEventListener('click', function () { diff --git a/backend/src/Squidex/Areas/IdentityServer/Views/_Layout.cshtml b/backend/src/Squidex/Areas/IdentityServer/Views/_Layout.cshtml index e00d6fcfc..c18398e08 100644 --- a/backend/src/Squidex/Areas/IdentityServer/Views/_Layout.cshtml +++ b/backend/src/Squidex/Areas/IdentityServer/Views/_Layout.cshtml @@ -14,7 +14,7 @@ @if (IsSectionDefined("header")) { - @RenderSection("header") + @await RenderSectionAsync("header") } diff --git a/backend/src/Squidex/Config/Domain/AppsServices.cs b/backend/src/Squidex/Config/Domain/AppsServices.cs index 1d9d1f3a9..0f15f2582 100644 --- a/backend/src/Squidex/Config/Domain/AppsServices.cs +++ b/backend/src/Squidex/Config/Domain/AppsServices.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Squidex.Areas.Api.Controllers.UI; @@ -14,6 +13,7 @@ using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.History; using Squidex.Domain.Apps.Entities.Search; +using Squidex.Infrastructure; namespace Squidex.Config.Domain { @@ -55,7 +55,7 @@ namespace Squidex.Config.Domain if (!string.IsNullOrWhiteSpace(key) && !string.IsNullOrWhiteSpace(value)) { - result[Guid.NewGuid()] = new AppPattern(key, value); + result[DomainId.NewGuid()] = new AppPattern(key, value); } } } diff --git a/backend/src/Squidex/Config/Domain/BackupsServices.cs b/backend/src/Squidex/Config/Domain/BackupsServices.cs index 1c8e3b32e..31b650c2c 100644 --- a/backend/src/Squidex/Config/Domain/BackupsServices.cs +++ b/backend/src/Squidex/Config/Domain/BackupsServices.cs @@ -6,7 +6,6 @@ // ========================================================================== using Microsoft.Extensions.DependencyInjection; -using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Backup; @@ -43,9 +42,6 @@ namespace Squidex.Config.Domain services.AddTransientAs() .As(); - - services.AddSingletonAs() - .AsSelf(); } } } \ No newline at end of file diff --git a/backend/src/Squidex/Config/Domain/CommandsServices.cs b/backend/src/Squidex/Config/Domain/CommandsServices.cs index 2ec0f662c..54fb16e2b 100644 --- a/backend/src/Squidex/Config/Domain/CommandsServices.cs +++ b/backend/src/Squidex/Config/Domain/CommandsServices.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps.Indexes; using Squidex.Domain.Apps.Entities.Apps.Invitation; @@ -113,7 +112,7 @@ namespace Squidex.Config.Domain services.AddSingletonAs() .As(); - services.AddSingleton(typeof(IEventEnricher<>), typeof(SquidexEventEnricher<>)); + services.AddSingleton(typeof(IEventEnricher<>), typeof(DefaultEventEnricher<>)); } } } \ No newline at end of file diff --git a/backend/src/Squidex/Config/Domain/MigrationServices.cs b/backend/src/Squidex/Config/Domain/MigrationServices.cs index 1634fde5d..ea10f6a3e 100644 --- a/backend/src/Squidex/Config/Domain/MigrationServices.cs +++ b/backend/src/Squidex/Config/Domain/MigrationServices.cs @@ -29,15 +29,15 @@ namespace Squidex.Config.Domain services.AddTransientAs() .As(); - services.AddTransientAs() - .As(); - services.AddTransientAs() .As(); services.AddTransientAs() .As(); + services.AddTransientAs() + .As(); + services.AddTransientAs() .As(); @@ -59,6 +59,9 @@ namespace Squidex.Config.Domain services.AddTransientAs() .As(); + services.AddTransientAs() + .As(); + services.AddTransientAs() .As(); diff --git a/backend/src/Squidex/Config/Domain/SerializationServices.cs b/backend/src/Squidex/Config/Domain/SerializationServices.cs index 9d74defdf..5b1e2247f 100644 --- a/backend/src/Squidex/Config/Domain/SerializationServices.cs +++ b/backend/src/Squidex/Config/Domain/SerializationServices.cs @@ -36,12 +36,14 @@ namespace Squidex.Config.Domain new AppPatternsConverter(), new ClaimsPrincipalConverter(), new ContentFieldDataConverter(), + new DomainIdConverter(), new EnvelopeHeadersConverter(), new FilterConverter(), new InstantConverter(), new JsonValueConverter(), new LanguageConverter(), new LanguagesConfigConverter(), + new NamedDomainIdConverter(), new NamedGuidIdConverter(), new NamedLongIdConverter(), new NamedStringIdConverter(), diff --git a/backend/src/Squidex/Config/Domain/StoreServices.cs b/backend/src/Squidex/Config/Domain/StoreServices.cs index 0b4e7b9dd..bff8a6a41 100644 --- a/backend/src/Squidex/Config/Domain/StoreServices.cs +++ b/backend/src/Squidex/Config/Domain/StoreServices.cs @@ -82,6 +82,9 @@ namespace Squidex.Config.Domain services.AddTransientAs() .As(); + services.AddTransientAs() + .As(); + services.AddHealthChecks() .AddCheck("MongoDB", tags: new[] { "node" }); @@ -110,13 +113,13 @@ namespace Squidex.Config.Domain .As().As(); services.AddSingletonAs() - .As().As>(); + .As().As>(); services.AddSingletonAs() - .As().As>(); + .As().As>(); services.AddSingletonAs(c => ActivatorUtilities.CreateInstance(c, GetDatabase(c, mongoContentDatabaseName))) - .As().As>(); + .As().As>(); services.AddSingletonAs() .AsSelf(); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/AppPatternJsonTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/AppPatternJsonTests.cs index 0b2f79947..51f6ca1de 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/AppPatternJsonTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/AppPatternJsonTests.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using FluentAssertions; using Squidex.Domain.Apps.Core.Apps; +using Squidex.Infrastructure; using Xunit; namespace Squidex.Domain.Apps.Core.Model.Apps @@ -19,9 +19,9 @@ namespace Squidex.Domain.Apps.Core.Model.Apps { var patterns = AppPatterns.Empty; - var guid1 = Guid.NewGuid(); - var guid2 = Guid.NewGuid(); - var guid3 = Guid.NewGuid(); + var guid1 = DomainId.NewGuid(); + var guid2 = DomainId.NewGuid(); + var guid3 = DomainId.NewGuid(); patterns = patterns.Add(guid1, "Name1", "Pattern1", "Default"); patterns = patterns.Add(guid2, "Name2", "Pattern2", "Default"); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/AppPatternsTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/AppPatternsTests.cs index 151a74b1d..7beb8f999 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/AppPatternsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/AppPatternsTests.cs @@ -5,10 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Linq; using FluentAssertions; using Squidex.Domain.Apps.Core.Apps; +using Squidex.Infrastructure; using Xunit; #pragma warning disable SA1310 // Field names must not contain underscore @@ -18,8 +18,8 @@ namespace Squidex.Domain.Apps.Core.Model.Apps public class AppPatternsTests { private readonly AppPatterns patterns_0; - private readonly Guid firstId = Guid.NewGuid(); - private readonly Guid id = Guid.NewGuid(); + private readonly DomainId firstId = DomainId.NewGuid(); + private readonly DomainId id = DomainId.NewGuid(); public AppPatternsTests() { diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/StatusTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/StatusTests.cs index 1f7f48ade..be9308356 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/StatusTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/StatusTests.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System.Collections.Generic; using System.ComponentModel; using Squidex.Domain.Apps.Core.Contents; using Xunit; @@ -108,5 +109,18 @@ namespace Squidex.Domain.Apps.Core.Model.Contents Assert.Equal(status, serialized); } + + [Fact] + public void Should_serialize_and_deserialize_as_dictionary_key() + { + var dictionary = new Dictionary + { + [Status.Draft] = 123 + }; + + var serialized = dictionary.SerializeAndDeserialize(); + + Assert.Equal(123, serialized[Status.Draft]); + } } } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsJsonTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsJsonTests.cs index 444fcbda2..ba06bbafe 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsJsonTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsJsonTests.cs @@ -5,10 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using FluentAssertions; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Infrastructure; using Xunit; namespace Squidex.Domain.Apps.Core.Model.Contents @@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Core.Model.Contents }, "#00ff00", NoUpdate.When("Expression", "Role1", "Role2")) - }, new List { Guid.NewGuid() }, "MyName"); + }, new List { DomainId.NewGuid() }, "MyName"); var serialized = workflow.SerializeAndDeserialize(); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsTests.cs index 8a3c485e8..b353af7da 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsTests.cs @@ -5,8 +5,8 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Infrastructure; using Xunit; #pragma warning disable SA1310 // Field names must not contain underscore @@ -31,13 +31,13 @@ namespace Squidex.Domain.Apps.Core.Model.Contents var workflows_1 = workflows_0.Set(Workflow.Default); Assert.Single(workflows_1); - Assert.Same(Workflow.Default, workflows_1[Guid.Empty]); + Assert.Same(Workflow.Default, workflows_1[DomainId.Empty]); } [Fact] public void Should_add_new_workflow_with_default_states() { - var id = Guid.NewGuid(); + var id = DomainId.NewGuid(); var workflows_1 = workflows_0.Add(id, "1"); @@ -47,7 +47,7 @@ namespace Squidex.Domain.Apps.Core.Model.Contents [Fact] public void Should_update_workflow() { - var id = Guid.NewGuid(); + var id = DomainId.NewGuid(); var workflows_1 = workflows_0.Add(id, "1"); var workflows_2 = workflows_1.Update(id, Workflow.Empty); @@ -58,7 +58,7 @@ namespace Squidex.Domain.Apps.Core.Model.Contents [Fact] public void Should_update_workflow_with_default_guid() { - var workflows_1 = workflows_0.Update(Guid.Empty, Workflow.Empty); + var workflows_1 = workflows_0.Update(default, Workflow.Empty); Assert.NotEmpty(workflows_1); } @@ -66,7 +66,7 @@ namespace Squidex.Domain.Apps.Core.Model.Contents [Fact] public void Should_do_nothing_if_workflow_to_update_not_found() { - var workflows_1 = workflows_0.Update(Guid.NewGuid(), Workflow.Empty); + var workflows_1 = workflows_0.Update(DomainId.NewGuid(), Workflow.Empty); Assert.Same(workflows_0, workflows_1); } @@ -74,7 +74,7 @@ namespace Squidex.Domain.Apps.Core.Model.Contents [Fact] public void Should_remove_workflow() { - var id = Guid.NewGuid(); + var id = DomainId.NewGuid(); var workflows_1 = workflows_0.Add(id, "1"); var workflows_2 = workflows_1.Remove(id); @@ -85,7 +85,7 @@ namespace Squidex.Domain.Apps.Core.Model.Contents [Fact] public void Should_do_nothing_if_workflow_to_remove_not_found() { - var workflows_1 = workflows_0.Remove(Guid.NewGuid()); + var workflows_1 = workflows_0.Remove(DomainId.NewGuid()); Assert.Empty(workflows_1); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ValueConvertersTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ValueConvertersTests.cs index 01762b092..88d749d52 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ValueConvertersTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ValueConvertersTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using FakeItEasy; using Squidex.Domain.Apps.Core.ConvertContent; using Squidex.Domain.Apps.Core.Schemas; @@ -18,16 +17,17 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent public class ValueConvertersTests { private readonly IUrlGenerator urlGenerator = A.Fake(); - private readonly Guid id1 = Guid.NewGuid(); - private readonly Guid id2 = Guid.NewGuid(); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly DomainId id1 = DomainId.NewGuid(); + private readonly DomainId id2 = DomainId.NewGuid(); private readonly RootField stringField = Fields.String(1, "1", Partitioning.Invariant); private readonly RootField jsonField = Fields.Json(1, "1", Partitioning.Invariant); private readonly RootField numberField = Fields.Number(1, "1", Partitioning.Invariant); public ValueConvertersTests() { - A.CallTo(() => urlGenerator.AssetContent(A._)) - .ReturnsLazily(ctx => $"url/to/{ctx.GetArgument(0)}"); + A.CallTo(() => urlGenerator.AssetContent(appId, A._)) + .ReturnsLazily(ctx => $"url/to/{ctx.GetArgument(1)}"); } [Fact] @@ -121,7 +121,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent var expected = JsonValue.Array($"url/to/{id1}", $"url/to/{id2}"); - var result = ValueConverters.ResolveAssetUrls(HashSet.Of(path), urlGenerator)(source, field); + var result = ValueConverters.ResolveAssetUrls(appId, HashSet.Of(path), urlGenerator)(source, field); Assert.Equal(expected, result); } @@ -137,7 +137,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent var expected = source; - var result = ValueConverters.ResolveAssetUrls(HashSet.Of(path), urlGenerator)(source, field); + var result = ValueConverters.ResolveAssetUrls(appId, HashSet.Of(path), urlGenerator)(source, field); Assert.Equal(expected, result); } @@ -153,7 +153,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent var expected = JsonValue.Array($"url/to/{id1}", $"url/to/{id2}"); - var result = ValueConverters.ResolveAssetUrls(HashSet.Of(path), urlGenerator)(source, field.Fields[0], field); + var result = ValueConverters.ResolveAssetUrls(appId, HashSet.Of(path), urlGenerator)(source, field.Fields[0], field); Assert.Equal(expected, result); } @@ -171,7 +171,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent var expected = source; - var result = ValueConverters.ResolveAssetUrls(HashSet.Of(path), urlGenerator)(source, field.Fields[0], field); + var result = ValueConverters.ResolveAssetUrls(appId, HashSet.Of(path), urlGenerator)(source, field.Fields[0], field); Assert.Equal(expected, result); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/EventSynchronization/SchemaSynchronizerTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/EventSynchronization/SchemaSynchronizerTests.cs index ed8ab0d7f..0ff28d8ee 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/EventSynchronization/SchemaSynchronizerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/EventSynchronization/SchemaSynchronizerTests.cs @@ -542,9 +542,6 @@ namespace Squidex.Domain.Apps.Core.Operations.EventSynchronization [Fact] public void Should_create_events_if_nested_fields_reordered() { - var id1 = NamedId.Of(1, "f1"); - var id2 = NamedId.Of(2, "f1"); - var sourceSchema = new Schema("source") .AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs index 16662a41d..447e1edc7 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using Squidex.Domain.Apps.Core.Contents; @@ -37,8 +36,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds [Fact] public void Should_get_ids_from_name_data() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); var input = new NamedContentData() @@ -46,7 +45,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds new ContentFieldData() .AddJsonValue(JsonValue.Array(id1.ToString(), id2.ToString()))); - var ids = new HashSet(); + var ids = new HashSet(); input.AddReferencedIds(schema, ids); @@ -56,8 +55,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds [Fact] public void Should_get_limited_ids_from_name_data() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); var input = new NamedContentData() @@ -65,7 +64,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds new ContentFieldData() .AddJsonValue(JsonValue.Array(id1.ToString(), id2.ToString()))); - var ids = new HashSet(); + var ids = new HashSet(); input.AddReferencedIds(schema, ids, 1); @@ -75,8 +74,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds [Fact] public void Should_cleanup_deleted_ids() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); var source = new NamedContentData() @@ -108,7 +107,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds JsonValue.Object() .Add("nested", JsonValue.Array(id2))))); - var cleaner = ValueReferencesConverter.CleanReferences(new HashSet { id2 }); + var cleaner = ValueReferencesConverter.CleanReferences(new HashSet { id2 }); var cleanNested = ValueConverters.ForNested(cleaner); var converter = FieldConverters.ForValues(cleaner, cleanNested); @@ -132,8 +131,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds [MemberData(nameof(ReferencingNestedFields))] public void Should_return_ids_from_nested_field(NestedField field) { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); var arrayField = Fields.Array(1, "my-array", Partitioning.Invariant, field); @@ -151,16 +150,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds [MemberData(nameof(ReferencingFields))] public void Should_return_empty_list_from_field_when_value_item_is_invalid(IField field) { - var result = field.GetReferencedIds(JsonValue.Array("invalid")).ToArray(); - - Assert.Empty(result); - } - - [Theory] - [MemberData(nameof(ReferencingFields))] - public void Should_return_empty_list_from_field_when_value_is_invalid(IField field) - { - var result = field.GetReferencedIds(JsonValue.Create("invalid")).ToArray(); + var result = field.GetReferencedIds(JsonValue.Array(1)).ToArray(); Assert.Empty(result); } @@ -196,14 +186,14 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds [MemberData(nameof(ReferencingFields))] public void Should_return_ids_from_field(IField field) { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); var value = CreateValue(id1, id2); var result = field.GetReferencedIds(value); - Assert.Equal(new HashSet { id1, id2 }, result); + Assert.Equal(new HashSet { id1, id2 }, result); } [Theory] @@ -219,8 +209,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds [MemberData(nameof(ReferencingFields))] public void Should_remove_deleted_ids_from_field(IField field) { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); var value = CreateValue(id1, id2); @@ -241,9 +231,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds yield return new object[] { Fields.Assets(1, "my-assets", Partitioning.Invariant) }; } - private static HashSet RandomIds() + private static HashSet RandomIds() { - return HashSet.Of(Guid.NewGuid()); + return HashSet.Of(DomainId.NewGuid()); } private static IJsonValue CreateValue(params object[] ids) diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterCompareTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterCompareTests.cs index e6e24824e..3cad5c98e 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterCompareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterCompareTests.cs @@ -34,11 +34,11 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules { private readonly IUser user = A.Fake(); private readonly IUrlGenerator urlGenerator = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly Instant now = SystemClock.Instance.GetCurrentInstant(); - private readonly Guid contentId = Guid.NewGuid(); - private readonly Guid assetId = Guid.NewGuid(); + private readonly DomainId contentId = Guid.NewGuid(); + private readonly DomainId assetId = Guid.NewGuid(); private readonly RuleEventFormatter sut; private class FakeContentResolver : IRuleEventFormatter @@ -53,7 +53,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules return default; } - private async ValueTask GetValueAsync() + private static async ValueTask GetValueAsync() { await Task.Delay(5); @@ -66,7 +66,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules A.CallTo(() => urlGenerator.ContentUI(appId, schemaId, contentId)) .Returns("content-url"); - A.CallTo(() => urlGenerator.AssetContent(assetId)) + A.CallTo(() => urlGenerator.AssetContent(appId, assetId)) .Returns("asset-content-url"); A.CallTo(() => user.Id) @@ -78,8 +78,6 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules A.CallTo(() => user.Claims) .Returns(new List { new Claim(SquidexClaimTypes.DisplayName, "me") }); - JintScriptEngine scriptEngine = BuildScriptEngine(); - var formatters = new IRuleEventFormatter[] { new PredefinedPatternsFormatter(urlGenerator), @@ -302,7 +300,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules )] public async Task Should_format_asset_content_url_from_event(string script) { - var @event = new EnrichedAssetEvent { Id = assetId }; + var @event = new EnrichedAssetEvent { Id = assetId, AppId = appId }; var result = await sut.FormatAsync(script, @event); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs index f57f7d6fb..875e69fd3 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; @@ -32,10 +31,10 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules { private readonly IUser user = A.Fake(); private readonly IUrlGenerator urlGenerator = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); - private readonly Guid contentId = Guid.NewGuid(); - private readonly Guid assetId = Guid.NewGuid(); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); + private readonly DomainId contentId = DomainId.NewGuid(); + private readonly DomainId assetId = DomainId.NewGuid(); private readonly RuleEventFormatter sut; private class FakeContentResolver : IRuleEventFormatter @@ -50,7 +49,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules return default; } - private async ValueTask GetValueAsync() + private static async ValueTask GetValueAsync() { await Task.Delay(5); @@ -63,7 +62,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules A.CallTo(() => urlGenerator.ContentUI(appId, schemaId, contentId)) .Returns("content-url"); - A.CallTo(() => urlGenerator.AssetContent(assetId)) + A.CallTo(() => urlGenerator.AssetContent(appId, assetId)) .Returns("asset-content-url"); A.CallTo(() => user.Id) @@ -75,8 +74,6 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules A.CallTo(() => user.Claims) .Returns(new List { new Claim(SquidexClaimTypes.DisplayName, "me") }); - JintScriptEngine scriptEngine = BuildScriptEngine(); - var formatters = new IRuleEventFormatter[] { new PredefinedPatternsFormatter(urlGenerator), diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs index 603dcc3a3..309c35121 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs @@ -39,8 +39,8 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules private readonly string actionDump = "MyDump"; private readonly string actionName = "ValidAction"; private readonly string actionDescription = "MyDescription"; - private readonly Guid ruleId = Guid.NewGuid(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly DomainId ruleId = DomainId.NewGuid(); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly TypeNameRegistry typeNameRegistry = new TypeNameRegistry(); private readonly RuleService sut; @@ -151,7 +151,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules { var @event = Envelope.Create(new ContentCreated()).SetTimestamp(clock.GetCurrentInstant().Minus(Duration.FromDays(3))); - var jobs = await sut.CreateJobsAsync(ValidRule(), ruleId, @event); + var jobs = await sut.CreateJobsAsync(ValidRule(), ruleId, @event, true); Assert.Empty(jobs); @@ -429,7 +429,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules Assert.Equal(now, job.Created); Assert.Equal(now.Plus(Duration.FromDays(30)), job.Expires); - Assert.NotEqual(Guid.Empty, job.Id); + Assert.NotEqual(DomainId.Empty, job.Id); } } } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/MockupHttpHandler.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/MockupHttpHandler.cs index a282c9ef8..ecc595966 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/MockupHttpHandler.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/MockupHttpHandler.cs @@ -40,7 +40,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { - await Task.Delay(1000); + await Task.Delay(1000, cancellationToken); madeRequest = request; diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Tags/TagNormalizerTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Tags/TagNormalizerTests.cs index 781eaed34..72e1df2fb 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Tags/TagNormalizerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Tags/TagNormalizerTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -13,6 +12,7 @@ using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Tags; using Squidex.Domain.Apps.Core.TestHelpers; +using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; using Xunit; @@ -21,8 +21,8 @@ namespace Squidex.Domain.Apps.Core.Operations.Tags public class TagNormalizerTests { private readonly ITagService tagService = A.Fake(); - private readonly Guid appId = Guid.NewGuid(); - private readonly Guid schemaId = Guid.NewGuid(); + private readonly DomainId appId = DomainId.NewGuid(); + private readonly DomainId schemaId = DomainId.NewGuid(); private readonly Schema schema; public TagNormalizerTests() diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs index 356b5fc44..04517c9cc 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs @@ -80,17 +80,6 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { "Field is required." }); } - [Fact] - public async Task Should_add_error_if_value_is_not_valid() - { - var sut = Field(new AssetsFieldProperties()); - - await sut.ValidateAsync(JsonValue.Create("invalid"), errors); - - errors.Should().BeEquivalentTo( - new[] { "Invalid json type, expected array of guid strings." }); - } - [Fact] public async Task Should_add_error_if_value_has_not_enough_items() { diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs index 7bafbcead..cf25a4ed0 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using FluentAssertions; using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; using Xunit; @@ -19,9 +19,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent public class ReferencesFieldTests { private readonly List errors = new List(); - private readonly Guid schemaId = Guid.NewGuid(); - private readonly Guid ref1 = Guid.NewGuid(); - private readonly Guid ref2 = Guid.NewGuid(); + private readonly DomainId schemaId = DomainId.NewGuid(); + private readonly DomainId ref1 = DomainId.NewGuid(); + private readonly DomainId ref2 = DomainId.NewGuid(); [Fact] public void Should_instantiate_field() @@ -93,17 +93,6 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { "Field is required." }); } - [Fact] - public async Task Should_add_error_if_value_is_not_valid() - { - var sut = Field(new ReferencesFieldProperties()); - - await sut.ValidateAsync(JsonValue.Create("invalid"), errors); - - errors.Should().BeEquivalentTo( - new[] { "Invalid json type, expected array of guid strings." }); - } - [Fact] public async Task Should_add_error_if_value_has_not_enough_items() { @@ -137,7 +126,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { "Must not contain duplicate values." }); } - private static IJsonValue CreateValue(params Guid[]? ids) + private static IJsonValue CreateValue(params DomainId[]? ids) { return ids == null ? JsonValue.Null : JsonValue.Array(ids.Select(x => (object)x.ToString()).ToArray()); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs index 88a79d9ca..00e9deeef 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs @@ -20,8 +20,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent { public static class ValidationTestExtensions { - private static readonly NamedId AppId = NamedId.Of(Guid.NewGuid(), "my-app"); - private static readonly NamedId SchemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private static readonly NamedId AppId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private static readonly NamedId SchemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private static readonly IValidatorsFactory Factory = new DefaultValidatorsFactory(); public static Task ValidateAsync(this IValidator validator, object? value, IList errors, @@ -94,7 +94,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent AppId, SchemaId, schema ?? new Schema(SchemaId.Name), - Guid.NewGuid(), + DomainId.NewGuid(), mode); if (updater != null) diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/AssetsValidatorTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/AssetsValidatorTests.cs index c818327a5..269f7981e 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/AssetsValidatorTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/AssetsValidatorTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -14,6 +13,7 @@ using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.ValidateContent; using Squidex.Domain.Apps.Core.ValidateContent.Validators; +using Squidex.Infrastructure; using Squidex.Infrastructure.Collections; using Xunit; @@ -25,7 +25,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators public sealed class AssetInfo : IAssetInfo { - public Guid AssetId { get; set; } + public DomainId AssetId { get; set; } public string FileName { get; set; } @@ -48,7 +48,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators private readonly AssetInfo document = new AssetInfo { - AssetId = Guid.NewGuid(), + AssetId = DomainId.NewGuid(), FileName = "MyDocument.pdf", FileSize = 1024 * 4, Type = AssetType.Unknown @@ -56,7 +56,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators private readonly AssetInfo image1 = new AssetInfo { - AssetId = Guid.NewGuid(), + AssetId = DomainId.NewGuid(), FileName = "MyImage.png", FileSize = 1024 * 8, Type = AssetType.Image, @@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators private readonly AssetInfo image2 = new AssetInfo { - AssetId = Guid.NewGuid(), + AssetId = DomainId.NewGuid(), FileName = "MyImage.png", FileSize = 1024 * 8, Type = AssetType.Image, @@ -91,7 +91,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators [Fact] public async Task Should_add_error_if_asset_are_not_valid() { - var assetId = Guid.NewGuid(); + var assetId = DomainId.NewGuid(); var sut = Validator(new AssetsFieldProperties()); @@ -104,7 +104,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators [Fact] public async Task Should_not_add_error_if_asset_are_not_valid_but_in_optimized_mode() { - var assetId = Guid.NewGuid(); + var assetId = DomainId.NewGuid(); var sut = Validator(new AssetsFieldProperties()); @@ -216,17 +216,17 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators }); } - private static object CreateValue(params Guid[] ids) + private static object CreateValue(params DomainId[] ids) { return ids.ToList(); } private IValidator Validator(AssetsFieldProperties properties) { - return new AssetsValidator(properties, new CheckAssets(ids => + return new AssetsValidator(properties, ids => { return Task.FromResult>(new List { document, image1, image2 }); - })); + }); } } } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/ReferencesValidatorTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/ReferencesValidatorTests.cs index 072999e06..b69bac1d4 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/ReferencesValidatorTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/ReferencesValidatorTests.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using FluentAssertions; using Squidex.Domain.Apps.Core.ValidateContent.Validators; +using Squidex.Infrastructure; using Xunit; namespace Squidex.Domain.Apps.Core.Operations.ValidateContent @@ -18,9 +18,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent public class ReferencesValidatorTests { private readonly List errors = new List(); - private readonly Guid schemaId = Guid.NewGuid(); - private readonly Guid ref1 = Guid.NewGuid(); - private readonly Guid ref2 = Guid.NewGuid(); + private readonly DomainId schemaId = DomainId.NewGuid(); + private readonly DomainId ref1 = DomainId.NewGuid(); + private readonly DomainId ref2 = DomainId.NewGuid(); [Fact] public async Task Should_add_error_if_references_are_not_valid() @@ -46,7 +46,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_not_add_error_if_schemas_not_defined() { - var sut = new ReferencesValidator(null, FoundReferences((Guid.NewGuid(), ref2))); + var sut = new ReferencesValidator(null, FoundReferences((DomainId.NewGuid(), ref2))); await sut.ValidateAsync(CreateValue(ref2), errors); @@ -56,7 +56,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_reference_schema_is_not_valid() { - var sut = new ReferencesValidator(Enumerable.Repeat(schemaId, 1), FoundReferences((Guid.NewGuid(), ref2))); + var sut = new ReferencesValidator(Enumerable.Repeat(schemaId, 1), FoundReferences((DomainId.NewGuid(), ref2))); await sut.ValidateAsync(CreateValue(ref2), errors); @@ -64,14 +64,14 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { $"Contains reference '{ref2}' to invalid schema." }); } - private static List CreateValue(params Guid[] ids) + private static List CreateValue(params DomainId[] ids) { return ids.ToList(); } - private static CheckContentsByIds FoundReferences(params (Guid SchemaId, Guid Id)[] references) + private static CheckContentsByIds FoundReferences(params (DomainId SchemaId, DomainId Id)[] references) { - return new CheckContentsByIds(x => Task.FromResult>(references.ToList())); + return x => Task.FromResult>(references.ToList()); } } } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/UniqueValidatorTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/UniqueValidatorTests.cs index 8372dea9f..f8024f0a1 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/UniqueValidatorTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/UniqueValidatorTests.cs @@ -10,13 +10,14 @@ using System.Collections.Generic; using System.Threading.Tasks; using FluentAssertions; using Squidex.Domain.Apps.Core.ValidateContent.Validators; +using Squidex.Infrastructure; using Xunit; namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators { public class UniqueValidatorTests { - private readonly Guid schemaId = Guid.NewGuid(); + private readonly DomainId schemaId = DomainId.NewGuid(); private readonly List errors = new List(); [Fact] @@ -24,7 +25,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators { var filter = string.Empty; - var sut = new UniqueValidator(Check(Guid.NewGuid(), f => filter = f)); + var sut = new UniqueValidator(Check(DomainId.NewGuid(), f => filter = f)); await sut.ValidateAsync("hi", errors, updater: c => c.Nested("property").Nested("iv")); @@ -39,7 +40,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators { var filter = string.Empty; - var sut = new UniqueValidator(Check(Guid.NewGuid(), f => filter = f)); + var sut = new UniqueValidator(Check(DomainId.NewGuid(), f => filter = f)); await sut.ValidateAsync(12.5, errors, updater: c => c.Nested("property").Nested("iv")); @@ -52,7 +53,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators [Fact] public async Task Should_not_add_error_if_string_value_not_found_but_in_optimized_mode() { - var sut = new UniqueValidator(Check(Guid.NewGuid())); + var sut = new UniqueValidator(Check(DomainId.NewGuid())); await sut.ValidateAsync(null, errors); @@ -83,14 +84,14 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators Assert.Empty(errors); } - private CheckUniqueness Check(Guid id, Action? filter = null) + private CheckUniqueness Check(DomainId id, Action? filter = null) { - return new CheckUniqueness(filterNode => + return filterNode => { filter?.Invoke(filterNode.ToString()); - return Task.FromResult>(new List<(Guid, Guid)> { (schemaId, id) }); - }); + return Task.FromResult>(new List<(DomainId, DomainId)> { (schemaId, id) }); + }; } } } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/TestUtils.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/TestUtils.cs index 878f82e69..2ece1d462 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/TestUtils.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/TestUtils.cs @@ -48,12 +48,14 @@ namespace Squidex.Domain.Apps.Core new AppPatternsConverter(), new ClaimsPrincipalConverter(), new ContentFieldDataConverter(), + new DomainIdConverter(), new EnvelopeHeadersConverter(), new FilterConverter(), new InstantConverter(), new JsonValueConverter(), new LanguageConverter(), new LanguagesConfigConverter(), + new NamedDomainIdConverter(), new NamedGuidIdConverter(), new NamedLongIdConverter(), new NamedStringIdConverter(), diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppCommandMiddlewareTests.cs index bc66ea0f8..1255c9278 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppCommandMiddlewareTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -14,6 +13,7 @@ using Orleans; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.State; using Squidex.Domain.Apps.Entities.TestHelpers; +using Squidex.Infrastructure; using Squidex.Infrastructure.Assets; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Validation; @@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Apps private readonly IContextProvider contextProvider = A.Fake(); private readonly IAppImageStore appImageStore = A.Fake(); private readonly IAssetThumbnailGenerator assetThumbnailGenerator = A.Fake(); - private readonly Guid appId = Guid.NewGuid(); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly Context requestContext = Context.Anonymous(); private readonly AppCommandMiddleware sut; @@ -36,9 +36,9 @@ namespace Squidex.Domain.Apps.Entities.Apps { } - protected override Guid Id + protected override DomainId Id { - get { return appId; } + get { return appId.Id; } } public AppCommandMiddlewareTests() @@ -79,7 +79,7 @@ namespace Squidex.Domain.Apps.Entities.Apps await sut.HandleAsync(context); - A.CallTo(() => appImageStore.UploadAsync(appId, stream, A._)) + A.CallTo(() => appImageStore.UploadAsync(appId.Id, stream, A._)) .MustHaveHappened(); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppDomainObjectTests.cs index e6b0e5794..a4c32a0b0 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppDomainObjectTests.cs @@ -32,20 +32,20 @@ namespace Squidex.Domain.Apps.Entities.Apps private readonly IAppPlanBillingManager appPlansBillingManager = A.Fake(); private readonly IUser user = A.Fake(); private readonly IUserResolver userResolver = A.Fake(); - private readonly string contributorId = Guid.NewGuid().ToString(); + private readonly string contributorId = DomainId.NewGuid().ToString(); private readonly string clientId = "client"; private readonly string clientNewName = "My Client"; private readonly string roleName = "My Role"; private readonly string planIdPaid = "premium"; private readonly string planIdFree = "free"; private readonly AppDomainObject sut; - private readonly Guid workflowId = Guid.NewGuid(); - private readonly Guid patternId1 = Guid.NewGuid(); - private readonly Guid patternId2 = Guid.NewGuid(); - private readonly Guid patternId3 = Guid.NewGuid(); + private readonly DomainId workflowId = DomainId.NewGuid(); + private readonly DomainId patternId1 = DomainId.NewGuid(); + private readonly DomainId patternId2 = DomainId.NewGuid(); + private readonly DomainId patternId3 = DomainId.NewGuid(); private readonly InitialPatterns initialPatterns; - protected override Guid Id + protected override DomainId Id { get { return AppId; } } @@ -224,7 +224,7 @@ namespace Squidex.Domain.Apps.Entities.Apps CreateEvent(new AppPlanChanged { PlanId = planIdPaid }) ); - A.CallTo(() => appPlansBillingManager.ChangePlanAsync(A._, A>._, A._)) + A.CallTo(() => appPlansBillingManager.ChangePlanAsync(A._, A>._, A._)) .MustNotHaveHappened(); } @@ -250,7 +250,7 @@ namespace Squidex.Domain.Apps.Entities.Apps CreateEvent(new AppPlanReset()) ); - A.CallTo(() => appPlansBillingManager.ChangePlanAsync(A._, A>._, planIdFree)) + A.CallTo(() => appPlansBillingManager.ChangePlanAsync(A._, A>._, planIdFree)) .MustNotHaveHappened(); } @@ -687,7 +687,7 @@ namespace Squidex.Domain.Apps.Entities.Apps private Task ExecuteCreateAsync() { - return PublishAsync(new CreateApp { Name = AppName }); + return PublishAsync(new CreateApp { Name = AppName, AppId = AppId }); } private Task ExecuteUploadImage() diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppSettingsSearchSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppSettingsSearchSourceTests.cs index ff94b275d..326f4cbc0 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppSettingsSearchSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppSettingsSearchSourceTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Security.Claims; using System.Threading.Tasks; using FakeItEasy; @@ -23,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Apps public sealed class AppSettingsSearchSourceTests { private readonly IUrlGenerator urlGenerator = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly AppSettingsSearchSource sut; public AppSettingsSearchSourceTests() diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsTests.cs index 1893bd16d..d36bac0e0 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsTests.cs @@ -5,10 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Orleans; +using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Orleans; using Xunit; @@ -37,7 +37,7 @@ namespace Squidex.Domain.Apps.Entities.Apps A.CallTo(() => grain.GetAsync()) .Returns(settings.AsJ()); - var result = await sut.GetAsync(Guid.NewGuid(), "user"); + var result = await sut.GetAsync(DomainId.NewGuid(), "user"); Assert.Same(settings, result); } @@ -47,7 +47,7 @@ namespace Squidex.Domain.Apps.Entities.Apps { var value = JsonValue.Object(); - await sut.SetAsync(Guid.NewGuid(), "user", "the.path", value); + await sut.SetAsync(DomainId.NewGuid(), "user", "the.path", value); A.CallTo(() => grain.SetAsync("the.path", A>.That.Matches(x => x.Value == value))) .MustHaveHappened(); @@ -58,7 +58,7 @@ namespace Squidex.Domain.Apps.Entities.Apps { var value = JsonValue.Object(); - await sut.SetAsync(Guid.NewGuid(), "user", value); + await sut.SetAsync(DomainId.NewGuid(), "user", value); A.CallTo(() => grain.SetAsync(A>.That.Matches(x => x.Value == value))) .MustHaveHappened(); @@ -67,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.Apps [Fact] public async Task Should_call_grain_when_removing_value() { - await sut.RemoveAsync(Guid.NewGuid(), "user", "the.path"); + await sut.RemoveAsync(DomainId.NewGuid(), "user", "the.path"); A.CallTo(() => grain.RemoveAsync("the.path")) .MustHaveHappened(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/BackupAppsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/BackupAppsTests.cs index 1c705d9a2..23dfd7ffe 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/BackupAppsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/BackupAppsTests.cs @@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Apps private readonly IAppsIndex index = A.Fake(); private readonly IAppUISettings appUISettings = A.Fake(); private readonly IAppImageStore appImageStore = A.Fake(); - private readonly Guid appId = Guid.NewGuid(); + private readonly DomainId appId = DomainId.NewGuid(); private readonly RefToken actor = new RefToken(RefTokenType.Subject, "123"); private readonly BackupApps sut; @@ -323,7 +323,7 @@ namespace Squidex.Domain.Apps.Entities.Apps HashSet? newIndex = null; A.CallTo(() => index.RebuildByContributorsAsync(appId, A>._)) - .Invokes(new Action>((_, i) => newIndex = i)); + .Invokes(new Action>((_, i) => newIndex = i)); await sut.CompleteRestoreAsync(context); @@ -341,7 +341,7 @@ namespace Squidex.Domain.Apps.Entities.Apps private RestoreContext CreateRestoreContext() { - return new RestoreContext(appId, CreateUserMapping(), A.Fake()); + return new RestoreContext(appId, CreateUserMapping(), A.Fake(), DomainId.NewGuid()); } private IUserMapping CreateUserMapping() diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppImageStoreTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppImageStoreTests.cs index b871b385e..371e7ab8e 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppImageStoreTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppImageStoreTests.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.IO; using System.Threading; using System.Threading.Tasks; using FakeItEasy; +using Squidex.Infrastructure; using Squidex.Infrastructure.Assets; using Xunit; @@ -18,7 +18,7 @@ namespace Squidex.Domain.Apps.Entities.Apps public class DefaultAppImageStoreTests { private readonly IAssetStore assetStore = A.Fake(); - private readonly Guid appId = Guid.NewGuid(); + private readonly DomainId appId = DomainId.NewGuid(); private readonly string fileName; private readonly DefaultAppImageStore sut; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppLogStoreTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppLogStoreTests.cs index a293a48f0..2f3a56cd7 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppLogStoreTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppLogStoreTests.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using FakeItEasy; +using Squidex.Infrastructure; using Squidex.Infrastructure.Log.Store; using Xunit; @@ -40,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.Apps var requestPath = "/my-path"; var userId = "user1"; - await sut.LogAsync(Guid.NewGuid(), default, requestMethod, requestPath, userId, clientId, elapsedMs, costs); + await sut.LogAsync(DomainId.NewGuid(), default, requestMethod, requestPath, userId, clientId, elapsedMs, costs); Assert.NotNull(recordedRequest); @@ -57,7 +58,7 @@ namespace Squidex.Domain.Apps.Entities.Apps var dateFrom = DateTime.UtcNow.Date.AddDays(-30); var dateTo = DateTime.UtcNow.Date; - var appId = Guid.NewGuid(); + var appId = DomainId.NewGuid(); A.CallTo(() => requestLogStore.QueryAllAsync(A>._, appId.ToString(), dateFrom, dateTo, default)) .Invokes(x => @@ -80,8 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Apps using (var reader = new StreamReader(stream)) { - string? line = null; - while ((line = reader.ReadLine()) != null) + while (await reader.ReadLineAsync() != null) { lines++; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppPatternsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppPatternsTests.cs index f4956692f..066eff453 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppPatternsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppPatternsTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.TestHelpers; @@ -19,7 +18,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards { public class GuardAppPatternsTests { - private readonly Guid patternId = Guid.NewGuid(); + private readonly DomainId patternId = DomainId.NewGuid(); private readonly AppPatterns patterns_0 = AppPatterns.Empty; [Fact] @@ -52,7 +51,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards [Fact] public void CanAdd_should_throw_exception_if_name_exists() { - var patterns_1 = patterns_0.Add(Guid.NewGuid(), "any", "[a-z]", "Message"); + var patterns_1 = patterns_0.Add(DomainId.NewGuid(), "any", "[a-z]", "Message"); var command = new AddPattern { PatternId = patternId, Name = "any", Pattern = ".*" }; @@ -63,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards [Fact] public void CanAdd_should_throw_exception_if_pattern_exists() { - var patterns_1 = patterns_0.Add(Guid.NewGuid(), "any", "[a-z]", "Message"); + var patterns_1 = patterns_0.Add(DomainId.NewGuid(), "any", "[a-z]", "Message"); var command = new AddPattern { PatternId = patternId, Name = "other", Pattern = "[a-z]" }; @@ -133,8 +132,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards [Fact] public void CanUpdate_should_throw_exception_if_name_exists() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); var patterns_1 = patterns_0.Add(id1, "Pattern1", "[0-5]", "Message"); var patterns_2 = patterns_1.Add(id2, "Pattern2", "[0-4]", "Message"); @@ -148,8 +147,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards [Fact] public void CanUpdate_should_throw_exception_if_pattern_exists() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); var patterns_1 = patterns_0.Add(id1, "Pattern1", "[0-5]", "Message"); var patterns_2 = patterns_1.Add(id2, "Pattern2", "[0-4]", "Message"); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppWorkflowTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppWorkflowTests.cs index aae856168..ae4decf2e 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppWorkflowTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppWorkflowTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Apps.Commands; @@ -18,7 +17,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards { public class GuardAppWorkflowTests { - private readonly Guid workflowId = Guid.NewGuid(); + private readonly DomainId workflowId = DomainId.NewGuid(); private readonly Workflows workflows; public GuardAppWorkflowTests() @@ -49,7 +48,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards var command = new UpdateWorkflow { Workflow = Workflow.Empty, - WorkflowId = Guid.NewGuid() + WorkflowId = DomainId.NewGuid() }; Assert.Throws(() => GuardAppWorkflows.CanUpdate(workflows, command)); @@ -197,7 +196,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards [Fact] public void CanDelete_should_throw_exception_if_workflow_not_found() { - var command = new DeleteWorkflow { WorkflowId = Guid.NewGuid() }; + var command = new DeleteWorkflow { WorkflowId = DomainId.NewGuid() }; Assert.Throws(() => GuardAppWorkflows.CanDelete(workflows, command)); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Indexes/AppsIndexTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Indexes/AppsIndexTests.cs index fa487905d..497d877c3 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Indexes/AppsIndexTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Indexes/AppsIndexTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -29,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes private readonly IAppsByNameIndexGrain indexByName = A.Fake(); private readonly IAppsByUserIndexGrain indexByUser = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly string userId = "user-1"; private readonly AppsIndex sut; @@ -50,7 +49,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes var expected = SetupApp(0, false); A.CallTo(() => indexByName.GetIdsAsync(A.That.IsSameSequenceAs(new[] { appId.Name }))) - .Returns(new List { appId.Id }); + .Returns(new List { appId.Id }); var actual = await sut.GetAppsForUserAsync(userId, new PermissionSet($"squidex.apps.{appId.Name}")); @@ -63,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes var expected = SetupApp(0, false); A.CallTo(() => indexByUser.GetIdsAsync()) - .Returns(new List { appId.Id }); + .Returns(new List { appId.Id }); var actual = await sut.GetAppsForUserAsync(userId, PermissionSet.Empty); @@ -76,10 +75,10 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes var expected = SetupApp(0, false); A.CallTo(() => indexByName.GetIdsAsync(A.That.IsSameSequenceAs(new[] { appId.Name }))) - .Returns(new List { appId.Id }); + .Returns(new List { appId.Id }); A.CallTo(() => indexByUser.GetIdsAsync()) - .Returns(new List { appId.Id }); + .Returns(new List { appId.Id }); var actual = await sut.GetAppsForUserAsync(userId, new PermissionSet($"squidex.apps.{appId.Name}")); @@ -93,7 +92,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes var expected = SetupApp(0, false); A.CallTo(() => indexByName.GetIdsAsync()) - .Returns(new List { appId.Id }); + .Returns(new List { appId.Id }); var actual = await sut.GetAppsAsync(); @@ -258,7 +257,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes [Fact] public async Task Should_add_app_to_index_on_contributor_assignment() { - var command = new AssignContributor { AppId = appId.Id, ContributorId = userId }; + var command = new AssignContributor { AppId = appId, ContributorId = userId }; var context = new CommandContext(command, commandBus) @@ -273,7 +272,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes [Fact] public async Task Should_remove_from_user_index_on_remove_of_contributor() { - var command = new RemoveContributor { AppId = appId.Id, ContributorId = userId }; + var command = new RemoveContributor { AppId = appId, ContributorId = userId }; var context = new CommandContext(command, commandBus) @@ -290,7 +289,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes { SetupApp(0, isArchived); - var command = new ArchiveApp { AppId = appId.Id }; + var command = new ArchiveApp { AppId = appId }; var context = new CommandContext(command, commandBus) @@ -308,7 +307,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes [Fact] public async Task Should_forward_call_when_rebuilding_for_contributors1() { - var apps = new HashSet(); + var apps = new HashSet(); await sut.RebuildByContributorsAsync(userId, apps); @@ -330,7 +329,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes [Fact] public async Task Should_forward_call_when_rebuilding() { - var apps = new Dictionary(); + var apps = new Dictionary(); await sut.RebuildAsync(apps); @@ -383,7 +382,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes A.CallTo(() => appGrain.GetStateAsync()) .Returns(J.Of(appEntity)); - A.CallTo(() => grainFactory.GetGrain(appId.Id, null)) + A.CallTo(() => grainFactory.GetGrain(appId.Id.ToString(), null)) .Returns(appGrain); return appEntity; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEventConsumerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEventConsumerTests.cs index 32bfa92d9..5968ee59a 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEventConsumerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEventConsumerTests.cs @@ -26,8 +26,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation.Notifications private readonly IUser assigner = A.Fake(); private readonly IUser assignee = A.Fake(); private readonly ISemanticLog log = A.Fake(); - private readonly string assignerId = Guid.NewGuid().ToString(); - private readonly string assigneeId = Guid.NewGuid().ToString(); + private readonly string assignerId = DomainId.NewGuid().ToString(); + private readonly string assigneeId = DomainId.NewGuid().ToString(); private readonly string appName = "my-app"; private readonly InvitationEventConsumer sut; @@ -177,7 +177,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation.Notifications var @event = new AppContributorAssigned { Actor = new RefToken(assignerType, assignerId), - AppId = NamedId.Of(Guid.NewGuid(), appName), + AppId = NamedId.Of(DomainId.NewGuid(), appName), ContributorId = assigneeId, IsCreated = isNewUser, IsAdded = isNewContributor diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs index 2915df56d..afdf08572 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Entities.Apps.Commands; @@ -20,7 +19,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation public class InviteUserCommandMiddlewareTests { private readonly IUserResolver userResolver = A.Fake(); - private readonly IAppEntity app = Mocks.App(NamedId.Of(Guid.NewGuid(), "my-app")); + private readonly IAppEntity app = Mocks.App(NamedId.Of(DomainId.NewGuid(), "my-app")); private readonly ICommandBus commandBus = A.Fake(); private readonly InviteUserCommandMiddleware sut; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/UsageGateTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/UsageGateTests.cs index 34fc2c65f..ebda99685 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/UsageGateTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/UsageGateTests.cs @@ -26,7 +26,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans private readonly IGrainFactory grainFactory = A.Fake(); private readonly IUsageNotifierGrain usageNotifierGrain = A.Fake(); private readonly DateTime today = new DateTime(2020, 04, 10); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly UsageGate sut; private long apiCallsBlocking; private long apiCallsMax; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/RolePermissionsProviderTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/RolePermissionsProviderTests.cs index 3a42f81fb..9ebcc15cb 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/RolePermissionsProviderTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/RolePermissionsProviderTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -22,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Apps { private readonly IAppEntity app; private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RolePermissionsProvider sut; public RolePermissionsProviderTests() @@ -35,11 +34,11 @@ namespace Squidex.Domain.Apps.Entities.Apps [Fact] public async Task Should_provide_all_permissions() { - A.CallTo(() => appProvider.GetSchemasAsync(A._)) + A.CallTo(() => appProvider.GetSchemasAsync(A._)) .Returns(new List { - Mocks.Schema(appId, NamedId.Of(Guid.NewGuid(), "schema1")), - Mocks.Schema(appId, NamedId.Of(Guid.NewGuid(), "schema2")) + Mocks.Schema(appId, NamedId.Of(DomainId.NewGuid(), "schema1")), + Mocks.Schema(appId, NamedId.Of(DomainId.NewGuid(), "schema2")) }); var result = await sut.GetPermissionsAsync(app); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/AlwaysCreateClientCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/AlwaysCreateClientCommandMiddlewareTests.cs index edd067d3a..895c787ee 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/AlwaysCreateClientCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/AlwaysCreateClientCommandMiddlewareTests.cs @@ -5,10 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Entities.Apps.Commands; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Xunit; @@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates [Fact] public async Task Should_create_client() { - var command = new CreateApp { AppId = Guid.NewGuid() }; + var command = new CreateApp { AppId = DomainId.NewGuid(), Name = "my-app" }; var context = new CommandContext(command, commandBus) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/TemplatesTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/TemplatesTests.cs index 1e5972f94..420034ba0 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/TemplatesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/TemplatesTests.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Schemas.Commands; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Xunit; @@ -31,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates [MemberData(nameof(TemplateTests))] public async Task Should_create_schemas(ICommandMiddleware middleware, string template) { - var command = new CreateApp { AppId = Guid.NewGuid(), Name = "my-app", Template = template }; + var command = new CreateApp { AppId = DomainId.NewGuid(), Name = "my-app", Template = template }; var context = new CommandContext(command, commandBus) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetChangedTriggerHandlerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetChangedTriggerHandlerTests.cs index 14d37bc2c..12b666f0f 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetChangedTriggerHandlerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetChangedTriggerHandlerTests.cs @@ -17,6 +17,7 @@ using Squidex.Domain.Apps.Core.Scripting; 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 Xunit; @@ -28,6 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Assets { private readonly IScriptEngine scriptEngine = A.Fake(); private readonly IAssetLoader assetLoader = A.Fake(); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly IRuleTriggerHandler sut; public AssetChangedTriggerHandlerTests() @@ -53,9 +55,11 @@ namespace Squidex.Domain.Apps.Entities.Assets [MemberData(nameof(TestEvents))] public async Task Should_create_enriched_events(AssetEvent @event, EnrichedAssetEventType type) { + @event.AppId = appId; + var envelope = Envelope.Create(@event).SetEventStreamNumber(12); - A.CallTo(() => assetLoader.GetAsync(@event.AssetId, 12)) + A.CallTo(() => assetLoader.GetAsync(appId.Id, @event.AssetId, 12)) .Returns(new AssetEntity()); var result = await sut.CreateEnrichedEventsAsync(envelope); @@ -80,7 +84,7 @@ namespace Squidex.Domain.Apps.Entities.Assets { TestForCondition(string.Empty, trigger => { - var result = sut.Trigger(new ContentCreated(), trigger, Guid.NewGuid()); + var result = sut.Trigger(new ContentCreated(), trigger, DomainId.NewGuid()); Assert.False(result); }); @@ -91,7 +95,7 @@ namespace Squidex.Domain.Apps.Entities.Assets { TestForCondition(string.Empty, trigger => { - var result = sut.Trigger(new AssetCreated(), trigger, Guid.NewGuid()); + var result = sut.Trigger(new AssetCreated(), trigger, DomainId.NewGuid()); Assert.True(result); }); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs index 97a00be7a..76c22f3e4 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs @@ -17,6 +17,7 @@ using Squidex.Domain.Apps.Core.Tags; using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.State; using Squidex.Domain.Apps.Entities.TestHelpers; +using Squidex.Infrastructure; using Squidex.Infrastructure.Assets; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Log; @@ -35,7 +36,7 @@ namespace Squidex.Domain.Apps.Entities.Assets private readonly IGrainFactory grainFactory = A.Fake(); private readonly IServiceProvider serviceProvider = A.Fake(); private readonly ITagService tagService = A.Fake(); - private readonly Guid assetId = Guid.NewGuid(); + private readonly DomainId assetId = DomainId.NewGuid(); private readonly Stream stream = new MemoryStream(); private readonly AssetDomainObjectGrain asset; private readonly AssetFile file; @@ -46,9 +47,9 @@ namespace Squidex.Domain.Apps.Entities.Assets { } - protected override Guid Id + protected override DomainId Id { - get { return assetId; } + get { return DomainId.Combine(AppId, assetId); } } public AssetCommandMiddlewareTests() @@ -61,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Assets .Returns(assetDomainObject); asset = new AssetDomainObjectGrain(serviceProvider, null!); - asset.ActivateAsync(Id).Wait(); + asset.ActivateAsync(Id.ToString()).Wait(); A.CallTo(() => contextProvider.Context) .Returns(requestContext); @@ -72,7 +73,7 @@ namespace Squidex.Domain.Apps.Entities.Assets A.CallTo(() => assetQuery.QueryByHashAsync(A.That.Matches(x => x.ShouldEnrichAsset()), AppId, A._)) .Returns(new List()); - A.CallTo(() => grainFactory.GetGrain(Id, null)) + A.CallTo(() => grainFactory.GetGrain(Id.ToString(), null)) .Returns(asset); sut = new AssetCommandMiddleware(grainFactory, @@ -280,14 +281,14 @@ namespace Squidex.Domain.Apps.Entities.Assets private Task ExecuteCreateAsync() { - return asset.ExecuteAsync(CreateCommand(new CreateAsset { AssetId = Id, File = file })); + return asset.ExecuteAsync(CreateCommand(new CreateAsset { AssetId = assetId, File = file })); } private void AssertAssetHasBeenUploaded(long version) { A.CallTo(() => assetFileStore.UploadAsync(A._, A._, CancellationToken.None)) .MustHaveHappened(); - A.CallTo(() => assetFileStore.CopyAsync(A._, Id, version, CancellationToken.None)) + A.CallTo(() => assetFileStore.CopyAsync(A._, AppId, assetId, version, CancellationToken.None)) .MustHaveHappened(); A.CallTo(() => assetFileStore.DeleteAsync(A._)) .MustHaveHappened(); @@ -301,7 +302,7 @@ namespace Squidex.Domain.Apps.Entities.Assets FileSize = fileSize }; - A.CallTo(() => assetQuery.QueryByHashAsync(A.That.Matches(x => !x.ShouldEnrichAsset()), A._, A._)) + A.CallTo(() => assetQuery.QueryByHashAsync(A.That.Matches(x => !x.ShouldEnrichAsset()), A._, A._)) .Returns(new List { duplicate }); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetDomainObjectTests.cs index 0a7c4fb1f..71c84f711 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetDomainObjectTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -29,19 +28,19 @@ namespace Squidex.Domain.Apps.Entities.Assets { private readonly ITagService tagService = A.Fake(); private readonly IAssetQueryService assetQuery = A.Fake(); - private readonly Guid parentId = Guid.NewGuid(); - private readonly Guid assetId = Guid.NewGuid(); + private readonly DomainId parentId = DomainId.NewGuid(); + private readonly DomainId assetId = DomainId.NewGuid(); private readonly AssetFile file = new AssetFile("my-image.png", "image/png", 1024, () => new MemoryStream()); private readonly AssetDomainObject sut; - protected override Guid Id + protected override DomainId Id { get { return assetId; } } public AssetDomainObjectTests() { - A.CallTo(() => assetQuery.FindAssetFolderAsync(parentId)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId, parentId)) .Returns(new List { A.Fake() }); A.CallTo(() => tagService.NormalizeTagsAsync(AppId, TagGroups.Assets, A>._, A>._)) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetFolderDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetFolderDomainObjectTests.cs index fd681cf60..30eb7b83d 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetFolderDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetFolderDomainObjectTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -23,18 +22,18 @@ namespace Squidex.Domain.Apps.Entities.Assets public class AssetFolderDomainObjectTests : HandlerTestBase { private readonly IAssetQueryService assetQuery = A.Fake(); - private readonly Guid parentId = Guid.NewGuid(); - private readonly Guid assetFolderId = Guid.NewGuid(); + private readonly DomainId parentId = DomainId.NewGuid(); + private readonly DomainId assetFolderId = DomainId.NewGuid(); private readonly AssetFolderDomainObject sut; - protected override Guid Id + protected override DomainId Id { - get { return assetFolderId; } + get { return DomainId.Combine(AppId, assetFolderId); } } public AssetFolderDomainObjectTests() { - A.CallTo(() => assetQuery.FindAssetFolderAsync(parentId)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId, parentId)) .Returns(new List { A.Fake() }); sut = new AssetFolderDomainObject(Store, assetQuery, A.Dummy()); @@ -63,10 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Assets LastEvents .ShouldHaveSameEvents( - CreateAssetFolderEvent(new AssetFolderCreated - { - FolderName = command.FolderName - }) + CreateAssetFolderEvent(new AssetFolderCreated { FolderName = command.FolderName }) ); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsSearchSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsSearchSourceTests.cs index 91b1b1c87..146eafb67 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsSearchSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsSearchSourceTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Security.Claims; using System.Threading.Tasks; using FakeItEasy; @@ -24,7 +23,7 @@ namespace Squidex.Domain.Apps.Entities.Assets { private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly IAssetQueryService assetQuery = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly AssetsSearchSource sut; public AssetsSearchSourceTests() @@ -41,7 +40,7 @@ namespace Squidex.Domain.Apps.Entities.Assets Assert.Empty(result); - A.CallTo(() => assetQuery.QueryAsync(A._, A._, A._)) + A.CallTo(() => assetQuery.QueryAsync(A._, A._, A._)) .MustNotHaveHappened(); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/BackupAssetsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/BackupAssetsTests.cs index 81f50ae40..a36003c30 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/BackupAssetsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/BackupAssetsTests.cs @@ -29,7 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Assets private readonly Rebuilder rebuilder = A.Fake(); private readonly IAssetFileStore assetFileStore = A.Fake(); private readonly ITagService tagService = A.Fake(); - private readonly Guid appId = Guid.NewGuid(); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RefToken actor = new RefToken(RefTokenType.Subject, "123"); private readonly BackupAssets sut; @@ -51,7 +51,7 @@ namespace Squidex.Domain.Apps.Entities.Assets var context = CreateBackupContext(); - A.CallTo(() => tagService.GetExportableTagsAsync(appId, TagGroups.Assets)) + A.CallTo(() => tagService.GetExportableTagsAsync(context.AppId, TagGroups.Assets)) .Returns(tags); await sut.BackupAsync(context); @@ -72,14 +72,14 @@ namespace Squidex.Domain.Apps.Entities.Assets await sut.RestoreAsync(context); - A.CallTo(() => tagService.RebuildTagsAsync(appId, TagGroups.Assets, tags)) + A.CallTo(() => tagService.RebuildTagsAsync(appId.Id, TagGroups.Assets, tags)) .MustHaveHappened(); } [Fact] public async Task Should_backup_created_asset() { - var @event = new AssetCreated { AssetId = Guid.NewGuid() }; + var @event = new AssetCreated { AssetId = DomainId.NewGuid() }; await TestBackupEventAsync(@event, 0); } @@ -87,7 +87,7 @@ namespace Squidex.Domain.Apps.Entities.Assets [Fact] public async Task Should_backup_updated_asset() { - var @event = new AssetUpdated { AssetId = Guid.NewGuid(), FileVersion = 3 }; + var @event = new AssetUpdated { AssetId = DomainId.NewGuid(), FileVersion = 3 }; await TestBackupEventAsync(@event, @event.FileVersion); } @@ -102,16 +102,16 @@ namespace Squidex.Domain.Apps.Entities.Assets A.CallTo(() => context.Writer.WriteBlobAsync($"{assetId}_{version}.asset", A>._)) .Invokes((string _, Func handler) => handler(assetStream)); - await sut.BackupEventAsync(Envelope.Create(@event), context); + await sut.BackupEventAsync(AppEvent(@event), context); - A.CallTo(() => assetFileStore.DownloadAsync(assetId, version, assetStream, default, default)) + A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, assetId, version, assetStream, default, default)) .MustHaveHappened(); } [Fact] public async Task Should_restore_created_asset() { - var @event = new AssetCreated { AssetId = Guid.NewGuid() }; + var @event = new AssetCreated { AssetId = DomainId.NewGuid() }; await TestRestoreAsync(@event, 0); } @@ -119,128 +119,131 @@ namespace Squidex.Domain.Apps.Entities.Assets [Fact] public async Task Should_restore_updated_asset() { - var @event = new AssetUpdated { AssetId = Guid.NewGuid(), FileVersion = 3 }; + var @event = new AssetUpdated { AppId = appId, AssetId = DomainId.NewGuid(), FileVersion = 3 }; await TestRestoreAsync(@event, @event.FileVersion); } private async Task TestRestoreAsync(AssetEvent @event, long version) { - var oldId = Guid.NewGuid(); - var assetStream = new MemoryStream(); var assetId = @event.AssetId; var context = CreateRestoreContext(); - A.CallTo(() => context.Reader.OldGuid(assetId)) - .Returns(oldId); - - A.CallTo(() => context.Reader.ReadBlobAsync($"{oldId}_{version}.asset", A>._)) + A.CallTo(() => context.Reader.ReadBlobAsync($"{assetId}_{version}.asset", A>._)) .Invokes((string _, Func handler) => handler(assetStream)); - await sut.RestoreEventAsync(Envelope.Create(@event), context); + await sut.RestoreEventAsync(AppEvent(@event), context); - A.CallTo(() => assetFileStore.UploadAsync(assetId, version, assetStream, default)) + A.CallTo(() => assetFileStore.UploadAsync(appId.Id, assetId, version, assetStream, default)) .MustHaveHappened(); } [Fact] public async Task Should_restore_states_for_all_assets() { - var assetId1 = Guid.NewGuid(); - var assetId2 = Guid.NewGuid(); + var assetId1 = DomainId.NewGuid(); + var assetId2 = DomainId.NewGuid(); var context = CreateRestoreContext(); - await sut.RestoreEventAsync(Envelope.Create(new AssetCreated + await sut.RestoreEventAsync(AppEvent(new AssetCreated { AssetId = assetId1 }), context); - await sut.RestoreEventAsync(Envelope.Create(new AssetCreated + await sut.RestoreEventAsync(AppEvent(new AssetCreated { AssetId = assetId2 }), context); - await sut.RestoreEventAsync(Envelope.Create(new AssetDeleted + await sut.RestoreEventAsync(AppEvent(new AssetDeleted { AssetId = assetId2 }), context); - var rebuildAssets = new HashSet(); - - var add = new Func(id => - { - rebuildAssets.Add(id); - - return Task.CompletedTask; - }); + var rebuildAssets = new HashSet(); - A.CallTo(() => rebuilder.InsertManyAsync(A._, A._)) - .Invokes((IdSource source, CancellationToken _) => source(add)); + A.CallTo(() => rebuilder.InsertManyAsync(A>._, A._)) + .Invokes((IEnumerable source, CancellationToken _) => rebuildAssets.AddRange(source)); await sut.RestoreAsync(context); - Assert.Equal(new HashSet + Assert.Equal(new HashSet { - assetId1, - assetId2 + DomainId.Combine(appId.Id, assetId1), + DomainId.Combine(appId.Id, assetId2) }, rebuildAssets); } [Fact] public async Task Should_restore_states_for_all_asset_folders() { - var assetFolderId1 = Guid.NewGuid(); - var assetFolderId2 = Guid.NewGuid(); + var assetFolderId1 = DomainId.NewGuid(); + var assetFolderId2 = DomainId.NewGuid(); var context = CreateRestoreContext(); - await sut.RestoreEventAsync(Envelope.Create(new AssetFolderCreated + await sut.RestoreEventAsync(AppEvent(new AssetFolderCreated { AssetFolderId = assetFolderId1 }), context); - await sut.RestoreEventAsync(Envelope.Create(new AssetFolderCreated + await sut.RestoreEventAsync(AppEvent(new AssetFolderCreated { AssetFolderId = assetFolderId2 }), context); - await sut.RestoreEventAsync(Envelope.Create(new AssetFolderDeleted + await sut.RestoreEventAsync(AppEvent(new AssetFolderDeleted { AssetFolderId = assetFolderId2 }), context); - var rebuildAssets = new HashSet(); + var rebuildAssetFolders = new HashSet(); - var add = new Func(id => - { - rebuildAssets.Add(id); - - return Task.CompletedTask; - }); - - A.CallTo(() => rebuilder.InsertManyAsync(A._, A._)) - .Invokes((IdSource source, CancellationToken _) => source(add)); + A.CallTo(() => rebuilder.InsertManyAsync(A>._, A._)) + .Invokes((IEnumerable source, CancellationToken _) => rebuildAssetFolders.AddRange(source)); await sut.RestoreAsync(context); - Assert.Equal(new HashSet + Assert.Equal(new HashSet { - assetFolderId1, - assetFolderId2 - }, rebuildAssets); + DomainId.Combine(appId.Id, assetFolderId1), + DomainId.Combine(appId.Id, assetFolderId2) + }, rebuildAssetFolders); } private BackupContext CreateBackupContext() { - return new BackupContext(appId, CreateUserMapping(), A.Fake()); + return new BackupContext(appId.Id, CreateUserMapping(), A.Fake()); } private RestoreContext CreateRestoreContext() { - return new RestoreContext(appId, CreateUserMapping(), A.Fake()); + return new RestoreContext(appId.Id, CreateUserMapping(), A.Fake(), DomainId.NewGuid()); + } + + private Envelope AppEvent(AssetEvent @event) + { + @event.AppId = appId; + + var envelope = Envelope.Create(@event); + + envelope.SetAggregateId(DomainId.Combine(appId.Id, @event.AssetId)); + + return envelope; + } + + private Envelope AppEvent(AssetFolderEvent @event) + { + @event.AppId = appId; + + var envelope = Envelope.Create(@event); + + envelope.SetAggregateId(DomainId.Combine(appId.Id, @event.AssetFolderId)); + + return envelope; } private IUserMapping CreateUserMapping() diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DefaultAssetFileStoreTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DefaultAssetFileStoreTests.cs index cde0f2b26..6f99d0231 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DefaultAssetFileStoreTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DefaultAssetFileStoreTests.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.IO; using System.Threading; using System.Threading.Tasks; using FakeItEasy; +using Squidex.Infrastructure; using Squidex.Infrastructure.Assets; using Xunit; @@ -18,46 +18,65 @@ namespace Squidex.Domain.Apps.Entities.Assets public class DefaultAssetFileStoreTests { private readonly IAssetStore assetStore = A.Fake(); - private readonly Guid assetId = Guid.NewGuid(); + private readonly DomainId appId = DomainId.NewGuid(); + private readonly DomainId assetId = DomainId.NewGuid(); private readonly long assetFileVersion = 21; - private readonly string fileName; + private readonly string fileNameOld; + private readonly string fileNameNew; private readonly DefaultAssetFileStore sut; public DefaultAssetFileStoreTests() { - fileName = $"{assetId}_{assetFileVersion}"; + fileNameOld = $"{assetId}_{assetFileVersion}"; + fileNameNew = $"{appId}_{assetId}_{assetFileVersion}"; sut = new DefaultAssetFileStore(assetStore); } [Fact] - public void Should_invoke_asset_store_to_generate_public_url() + public void Should_get_public_url_from_store() { var url = "http_//squidex.io/assets"; - A.CallTo(() => assetStore.GeneratePublicUrl(fileName)) + A.CallTo(() => assetStore.GeneratePublicUrl(fileNameNew)) .Returns(url); - var result = sut.GeneratePublicUrl(assetId, assetFileVersion); + var result = sut.GeneratePublicUrl(appId, assetId, assetFileVersion); Assert.Equal(url, result); } [Fact] - public async Task Should_invoke_asset_store_to_get_file_size() + public async Task Should_get_file_size_from_store() { var size = 1024L; - A.CallTo(() => assetStore.GetSizeAsync(fileName, default)) + A.CallTo(() => assetStore.GetSizeAsync(fileNameNew, default)) .Returns(size); - var result = await sut.GetFileSizeAsync(assetId, assetFileVersion); + var result = await sut.GetFileSizeAsync(appId, assetId, assetFileVersion); Assert.Equal(size, result); } [Fact] - public async Task Should_invoke_asset_store_to_temporary_upload_file() + public async Task Should_get_file_size_from_store_with_old_file_name_if_new_name_not_found() + { + var size = 1024L; + + A.CallTo(() => assetStore.GetSizeAsync(fileNameOld, default)) + .Throws(new AssetNotFoundException(fileNameOld)); + + A.CallTo(() => assetStore.GetSizeAsync(fileNameNew, default)) + .Returns(size); + + var result = await sut.GetFileSizeAsync(appId, assetId, assetFileVersion); + + Assert.Equal(size, result); + } + + [Fact] + public async Task Should_upload_temporary_filet_to_store() { var stream = new MemoryStream(); @@ -68,38 +87,55 @@ namespace Squidex.Domain.Apps.Entities.Assets } [Fact] - public async Task Should_invoke_asset_store_to_upload_file() + public async Task Should_upload_file_to_store() + { + var stream = new MemoryStream(); + + await sut.UploadAsync(appId, assetId, assetFileVersion, stream); + + A.CallTo(() => assetStore.UploadAsync(fileNameNew, stream, true, CancellationToken.None)) + .MustHaveHappened(); + } + + [Fact] + public async Task Should_download_file_from_store() { var stream = new MemoryStream(); - await sut.UploadAsync(assetId, assetFileVersion, stream); + await sut.DownloadAsync(appId, assetId, assetFileVersion, stream); - A.CallTo(() => assetStore.UploadAsync(fileName, stream, true, CancellationToken.None)) + A.CallTo(() => assetStore.DownloadAsync(fileNameNew, stream, default, CancellationToken.None)) .MustHaveHappened(); } [Fact] - public async Task Should_invoke_asset_store_to_download_file() + public async Task Should_download_file_from_store_with_old_file_name_if_new_name_not_found() { var stream = new MemoryStream(); - await sut.DownloadAsync(assetId, assetFileVersion, stream); + A.CallTo(() => assetStore.DownloadAsync(fileNameNew, stream, default, CancellationToken.None)) + .Throws(new AssetNotFoundException(fileNameNew)); + + await sut.DownloadAsync(appId, assetId, assetFileVersion, stream); + + A.CallTo(() => assetStore.DownloadAsync(fileNameOld, stream, default, CancellationToken.None)) + .MustHaveHappened(); - A.CallTo(() => assetStore.DownloadAsync(fileName, stream, default, CancellationToken.None)) + A.CallTo(() => assetStore.DownloadAsync(fileNameNew, stream, default, CancellationToken.None)) .MustHaveHappened(); } [Fact] - public async Task Should_invoke_asset_store_to_copy_from_temporary_file() + public async Task Should_copy_file_to_store() { - await sut.CopyAsync("Temp", assetId, assetFileVersion); + await sut.CopyAsync("Temp", appId, assetId, assetFileVersion); - A.CallTo(() => assetStore.CopyAsync("Temp", fileName, CancellationToken.None)) + A.CallTo(() => assetStore.CopyAsync("Temp", fileNameNew, CancellationToken.None)) .MustHaveHappened(); } [Fact] - public async Task Should_invoke_asset_store_to_delete_temporary_file() + public async Task Should_delete_temporary_file_from_store() { await sut.DeleteAsync("Temp"); @@ -108,11 +144,14 @@ namespace Squidex.Domain.Apps.Entities.Assets } [Fact] - public async Task Should_invoke_asset_store_to_delete_file() + public async Task Should_delete_file_from_store() { - await sut.DeleteAsync(assetId, assetFileVersion); + await sut.DeleteAsync(appId, assetId, assetFileVersion); + + A.CallTo(() => assetStore.DeleteAsync(fileNameNew)) + .MustHaveHappened(); - A.CallTo(() => assetStore.DeleteAsync(fileName)) + A.CallTo(() => assetStore.DeleteAsync(fileNameOld)) .MustHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/FileTagAssetMetadataSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/FileTagAssetMetadataSourceTests.cs index 30cc6050f..6d235325f 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/FileTagAssetMetadataSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/FileTagAssetMetadataSourceTests.cs @@ -121,7 +121,7 @@ namespace Squidex.Domain.Apps.Entities.Assets Assert.Empty(formatted); } - private UploadAssetCommand Command(string path) + private static UploadAssetCommand Command(string path) { var file = new FileInfo(Path.Combine("Assets", "TestFiles", path)); @@ -131,7 +131,7 @@ namespace Squidex.Domain.Apps.Entities.Assets }; } - private UploadAssetCommand FakeCommand(string name) + private static UploadAssetCommand FakeCommand(string name) { var stream = new MemoryStream(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Guards/GuardAssetFolderTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Guards/GuardAssetFolderTests.cs index 99edf6234..8ba59e598 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Guards/GuardAssetFolderTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Guards/GuardAssetFolderTests.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.TestHelpers; +using Squidex.Infrastructure; using Squidex.Infrastructure.Validation; using Xunit; @@ -19,13 +19,14 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards public class GuardAssetFolderTests { private readonly IAssetQueryService assetQuery = A.Fake(); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); [Fact] public async Task CanCreate_should_throw_exception_when_folder_name_not_defined() { - var command = new CreateAssetFolder(); + var command = new CreateAssetFolder { AppId = appId }; - A.CallTo(() => assetQuery.FindAssetFolderAsync(command.ParentId)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) .Returns(new List()); await ValidationAssert.ThrowsAsync(() => GuardAssetFolder.CanCreate(command, assetQuery), @@ -35,9 +36,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards [Fact] public async Task CanCreate_should_throw_exception_when_folder_not_found() { - var command = new CreateAssetFolder { FolderName = "My Folder", ParentId = Guid.NewGuid() }; + var command = new CreateAssetFolder { AppId = appId, FolderName = "My Folder", ParentId = DomainId.NewGuid() }; - A.CallTo(() => assetQuery.FindAssetFolderAsync(command.ParentId)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) .Returns(new List()); await ValidationAssert.ThrowsAsync(() => GuardAssetFolder.CanCreate(command, assetQuery), @@ -47,9 +48,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards [Fact] public async Task CanCreate_should_not_throw_exception_when_folder_found() { - var command = new CreateAssetFolder { FolderName = "My Folder", ParentId = Guid.NewGuid() }; + var command = new CreateAssetFolder { AppId = appId, FolderName = "My Folder", ParentId = DomainId.NewGuid() }; - A.CallTo(() => assetQuery.FindAssetFolderAsync(command.ParentId)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) .Returns(new List { CreateFolder() }); await GuardAssetFolder.CanCreate(command, assetQuery); @@ -58,7 +59,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards [Fact] public async Task CanCreate_should_not_throw_exception_when_added_to_root() { - var command = new CreateAssetFolder { FolderName = "My Folder" }; + var command = new CreateAssetFolder { AppId = appId, FolderName = "My Folder" }; await GuardAssetFolder.CanCreate(command, assetQuery); } @@ -66,64 +67,64 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards [Fact] public async Task CanMove_should_throw_exception_when_adding_to_its_own_child() { - var id = Guid.NewGuid(); + var id = DomainId.NewGuid(); - var command = new MoveAssetFolder { ParentId = Guid.NewGuid() }; + var command = new MoveAssetFolder { AppId = appId, ParentId = DomainId.NewGuid() }; - A.CallTo(() => assetQuery.FindAssetFolderAsync(command.ParentId)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) .Returns(new List { CreateFolder(id), CreateFolder(command.ParentId) }); - await ValidationAssert.ThrowsAsync(() => GuardAssetFolder.CanMove(command, assetQuery, id, Guid.NewGuid()), + await ValidationAssert.ThrowsAsync(() => GuardAssetFolder.CanMove(command, assetQuery, id, DomainId.NewGuid()), new ValidationError("Cannot add folder to its own child.", "ParentId")); } [Fact] public async Task CanMove_should_throw_exception_when_folder_not_found() { - var command = new MoveAssetFolder { ParentId = Guid.NewGuid() }; + var command = new MoveAssetFolder { AppId = appId, ParentId = DomainId.NewGuid() }; - A.CallTo(() => assetQuery.FindAssetFolderAsync(command.ParentId)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) .Returns(new List()); - await ValidationAssert.ThrowsAsync(() => GuardAssetFolder.CanMove(command, assetQuery, Guid.NewGuid(), Guid.NewGuid()), + await ValidationAssert.ThrowsAsync(() => GuardAssetFolder.CanMove(command, assetQuery, DomainId.NewGuid(), DomainId.NewGuid()), new ValidationError("Asset folder does not exist.", "ParentId")); } [Fact] public async Task CanMove_should_not_throw_exception_when_folder_found() { - var command = new MoveAssetFolder { ParentId = Guid.NewGuid() }; + var command = new MoveAssetFolder { AppId = appId, ParentId = DomainId.NewGuid() }; - A.CallTo(() => assetQuery.FindAssetFolderAsync(command.ParentId)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) .Returns(new List { CreateFolder() }); - await GuardAssetFolder.CanMove(command, assetQuery, Guid.NewGuid(), Guid.NewGuid()); + await GuardAssetFolder.CanMove(command, assetQuery, DomainId.NewGuid(), DomainId.NewGuid()); } [Fact] public async Task CanMove_should_not_throw_exception_when_folder_has_not_changed() { - var command = new MoveAssetFolder { ParentId = Guid.NewGuid() }; + var command = new MoveAssetFolder { AppId = appId, ParentId = DomainId.NewGuid() }; - await GuardAssetFolder.CanMove(command, assetQuery, Guid.NewGuid(), command.ParentId); + await GuardAssetFolder.CanMove(command, assetQuery, DomainId.NewGuid(), command.ParentId); } [Fact] public async Task CanMove_should_not_throw_exception_when_added_to_root() { - var command = new MoveAssetFolder(); + var command = new MoveAssetFolder { AppId = appId }; - await GuardAssetFolder.CanMove(command, assetQuery, Guid.NewGuid(), Guid.NewGuid()); + await GuardAssetFolder.CanMove(command, assetQuery, DomainId.NewGuid(), DomainId.NewGuid()); } [Fact] public void CanRename_should_throw_exception_if_folder_name_is_empty() { - var command = new RenameAssetFolder(); + var command = new RenameAssetFolder { AppId = appId }; ValidationAssert.Throws(() => GuardAssetFolder.CanRename(command), new ValidationError("Folder name is required.", "FolderName")); @@ -132,7 +133,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards [Fact] public void CanRename_should_not_throw_exception_if_names_are_different() { - var command = new RenameAssetFolder { FolderName = "New Folder Name" }; + var command = new RenameAssetFolder { AppId = appId, FolderName = "New Folder Name" }; GuardAssetFolder.CanRename(command); } @@ -140,12 +141,12 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards [Fact] public void CanDelete_should_not_throw_exception() { - var command = new DeleteAssetFolder(); + var command = new DeleteAssetFolder { AppId = appId }; GuardAssetFolder.CanDelete(command); } - private static IAssetFolderEntity CreateFolder(Guid id = default) + private static IAssetFolderEntity CreateFolder(DomainId id = default) { var assetFolder = A.Fake(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Guards/GuardAssetTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Guards/GuardAssetTests.cs index 7ed33e66b..bd7bccaf6 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Guards/GuardAssetTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Guards/GuardAssetTests.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.TestHelpers; +using Squidex.Infrastructure; using Squidex.Infrastructure.Validation; using Xunit; @@ -19,13 +19,14 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards public class GuardAssetTests { private readonly IAssetQueryService assetQuery = A.Fake(); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); [Fact] public async Task CanCreate_should_not_throw_exception_when_folder_found() { - var command = new CreateAsset { ParentId = Guid.NewGuid() }; + var command = new CreateAsset { AppId = appId, ParentId = DomainId.NewGuid() }; - A.CallTo(() => assetQuery.FindAssetFolderAsync(command.ParentId)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) .Returns(new List { CreateFolder() }); await GuardAsset.CanCreate(command, assetQuery); @@ -34,9 +35,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards [Fact] public async Task CanCreate_should_throw_exception_when_folder_not_found() { - var command = new CreateAsset { ParentId = Guid.NewGuid() }; + var command = new CreateAsset { AppId = appId, ParentId = DomainId.NewGuid() }; - A.CallTo(() => assetQuery.FindAssetFolderAsync(command.ParentId)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) .Returns(new List()); await ValidationAssert.ThrowsAsync(() => GuardAsset.CanCreate(command, assetQuery), @@ -46,7 +47,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards [Fact] public async Task CanCreate_should_not_throw_exception_when_added_to_root() { - var command = new CreateAsset(); + var command = new CreateAsset { AppId = appId }; await GuardAsset.CanCreate(command, assetQuery); } @@ -54,19 +55,19 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards [Fact] public async Task CanMove_should_throw_exception_when_folder_not_found() { - var command = new MoveAsset { ParentId = Guid.NewGuid() }; + var command = new MoveAsset { AppId = appId, ParentId = DomainId.NewGuid() }; - A.CallTo(() => assetQuery.FindAssetFolderAsync(command.ParentId)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) .Returns(new List()); - await ValidationAssert.ThrowsAsync(() => GuardAsset.CanMove(command, assetQuery, Guid.NewGuid()), + await ValidationAssert.ThrowsAsync(() => GuardAsset.CanMove(command, assetQuery, DomainId.NewGuid()), new ValidationError("Asset folder does not exist.", "ParentId")); } [Fact] public async Task CanMove_should_not_throw_exception_when_folder_has_not_changed() { - var command = new MoveAsset { ParentId = Guid.NewGuid() }; + var command = new MoveAsset { AppId = appId, ParentId = DomainId.NewGuid() }; await GuardAsset.CanMove(command, assetQuery, command.ParentId); } @@ -74,26 +75,26 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards [Fact] public async Task CanMove_should_not_throw_exception_when_folder_found() { - var command = new MoveAsset { ParentId = Guid.NewGuid() }; + var command = new MoveAsset { AppId = appId, ParentId = DomainId.NewGuid() }; - A.CallTo(() => assetQuery.FindAssetFolderAsync(command.ParentId)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) .Returns(new List { CreateFolder() }); - await GuardAsset.CanMove(command, assetQuery, Guid.NewGuid()); + await GuardAsset.CanMove(command, assetQuery, DomainId.NewGuid()); } [Fact] public async Task CanMove_should_not_throw_exception_when_added_to_root() { - var command = new MoveAsset(); + var command = new MoveAsset { AppId = appId }; - await GuardAsset.CanMove(command, assetQuery, Guid.NewGuid()); + await GuardAsset.CanMove(command, assetQuery, DomainId.NewGuid()); } [Fact] public void CanAnnotate_should_throw_exception_if_nothing_defined() { - var command = new AnnotateAsset(); + var command = new AnnotateAsset { AppId = appId }; ValidationAssert.Throws(() => GuardAsset.CanAnnotate(command), new ValidationError("At least one property must be defined.", "FileName", "IsProtected", "Metadata", "Slug", "Tags")); @@ -102,7 +103,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards [Fact] public void CanAnnotate_should_not_throw_exception_if_a_value_is_passed() { - var command = new AnnotateAsset { FileName = "new-name", Slug = "new-slug" }; + var command = new AnnotateAsset { AppId = appId, FileName = "new-name", Slug = "new-slug" }; GuardAsset.CanAnnotate(command); } @@ -110,7 +111,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards [Fact] public void CanUpdate_should_not_throw_exception() { - var command = new UpdateAsset(); + var command = new UpdateAsset { AppId = appId }; GuardAsset.CanUpdate(command); } @@ -118,12 +119,12 @@ namespace Squidex.Domain.Apps.Entities.Assets.Guards [Fact] public void CanDelete_should_not_throw_exception() { - var command = new DeleteAsset(); + var command = new DeleteAsset { AppId = appId }; GuardAsset.CanDelete(command); } - private static IAssetFolderEntity CreateFolder(Guid id = default) + private static IAssetFolderEntity CreateFolder(DomainId id = default) { var assetFolder = A.Fake(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs index 152bced7c..de2be8537 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs @@ -100,7 +100,7 @@ namespace Squidex.Domain.Apps.Entities.Assets { var source = new AssetEntity { - Metadata = new AssetMetadata() + Metadata = new AssetMetadata { ["pixelWidth"] = JsonValue.Create(128), ["pixelHeight"] = JsonValue.Create(55) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryFixture.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryFixture.cs index a976c8b1a..d44d5cbd2 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryFixture.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryFixture.cs @@ -30,10 +30,10 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb public IAssetRepository AssetRepository { get; } - public NamedId[] AppIds { get; } = new[] + public NamedId[] AppIds { get; } = { - NamedId.Of(Guid.Parse("3b5ba909-e5a5-4858-9d0d-df4ff922d452"), "my-app1"), - NamedId.Of(Guid.Parse("4b3672c1-97c6-4e0b-a067-71e9e9a29db9"), "my-app1") + NamedId.Of(DomainId.Create("3b5ba909-e5a5-4858-9d0d-df4ff922d452"), "my-app1"), + NamedId.Of(DomainId.Create("4b3672c1-97c6-4e0b-a067-71e9e9a29db9"), "my-app1") }; public AssetsQueryFixture() @@ -86,8 +86,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb var asset = new MongoAssetEntity { - Id = Guid.NewGuid(), - AppId = appId, + DocumentId = DomainId.NewGuid(), Tags = new HashSet { tag }, FileHash = fileName, FileName = fileName, @@ -123,7 +122,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb BsonJsonConvention.Register(jsonSerializer); } - public Guid RandomAppId() + public DomainId RandomAppId() { return AppIds[random.Next(0, AppIds.Length)].Id; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryTests.cs index ecab2057c..cf1265526 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -47,7 +46,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb [Fact] public async Task Should_verify_ids() { - var ids = Enumerable.Repeat(0, 50).Select(_ => Guid.NewGuid()).ToHashSet(); + var ids = Enumerable.Repeat(0, 50).Select(_ => DomainId.NewGuid()).ToHashSet(); var assets = await _.AssetRepository.QueryIdsAsync(_.RandomAppId(), ids); @@ -56,7 +55,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb [Theory] [MemberData(nameof(ParentIds))] - public async Task Should_query_assets_by_default(Guid? parentId) + public async Task Should_query_assets_by_default(DomainId? parentId) { var query = new ClrQuery(); @@ -67,7 +66,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb [Theory] [MemberData(nameof(ParentIds))] - public async Task Should_query_assets_by_tags(Guid? parentId) + public async Task Should_query_assets_by_tags(DomainId? parentId) { var query = new ClrQuery { @@ -81,7 +80,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb [Theory] [MemberData(nameof(ParentIds))] - public async Task Should_query_assets_by_tags_and_name(Guid? parentId) + public async Task Should_query_assets_by_tags_and_name(DomainId? parentId) { var query = new ClrQuery { @@ -95,7 +94,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb [Theory] [MemberData(nameof(ParentIds))] - public async Task Should_query_assets_by_fileName(Guid? parentId) + public async Task Should_query_assets_by_fileName(DomainId? parentId) { var query = new ClrQuery { @@ -109,7 +108,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb [Theory] [MemberData(nameof(ParentIds))] - public async Task Should_query_assets_by_fileName_and_tags(Guid? parentId) + public async Task Should_query_assets_by_fileName_and_tags(DomainId? parentId) { var query = new ClrQuery { @@ -124,10 +123,10 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb public static IEnumerable ParentIds() { yield return new object?[] { null }; - yield return new object?[] { Guid.Empty }; + yield return new object?[] { DomainId.Empty }; } - private async Task> QueryAsync(Guid? parentId, ClrQuery query) + private async Task> QueryAsync(DomainId? parentId, ClrQuery query) { query.Top = 1000; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/MongoDbQueryTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/MongoDbQueryTests.cs index b1fda6319..23e52cc54 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/MongoDbQueryTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/MongoDbQueryTests.cs @@ -30,6 +30,8 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb static MongoDbQueryTests() { InstantSerializer.Register(); + + DomainIdSerializer.Register(); } [Fact] diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs index d52b1492f..76b16c63d 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -23,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries private readonly IRequestCache requestCache = A.Fake(); private readonly IAssetMetadataSource assetMetadataSource1 = A.Fake(); private readonly IAssetMetadataSource assetMetadataSource2 = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly Context requestContext = Context.Anonymous(); private readonly AssetEnricher sut; @@ -51,11 +50,11 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries [Fact] public async Task Should_enrich_with_cache_dependencies() { - var source = new AssetEntity { AppId = appId, Id = Guid.NewGuid(), Version = 13 }; + var source = new AssetEntity { AppId = appId, Id = DomainId.NewGuid(), Version = 13 }; var result = await sut.EnrichAsync(source, requestContext); - A.CallTo(() => requestCache.AddDependency(result.Id, result.Version)) + A.CallTo(() => requestCache.AddDependency(result.UniqueId, result.Version)) .MustHaveHappened(); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetLoaderTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetLoaderTests.cs index 99f522b6b..2a769a1f9 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetLoaderTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetLoaderTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Orleans; @@ -19,12 +18,15 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries { private readonly IGrainFactory grainFactory = A.Fake(); private readonly IAssetGrain grain = A.Fake(); - private readonly Guid id = Guid.NewGuid(); + private readonly DomainId appId = DomainId.NewGuid(); + private readonly DomainId id = DomainId.NewGuid(); private readonly AssetLoader sut; public AssetLoaderTests() { - A.CallTo(() => grainFactory.GetGrain(id, null)) + var key = DomainId.Combine(appId, id).ToString(); + + A.CallTo(() => grainFactory.GetGrain(key, null)) .Returns(grain); sut = new AssetLoader(grainFactory); @@ -36,7 +38,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries A.CallTo(() => grain.GetStateAsync(10)) .Returns(J.Of(null!)); - await Assert.ThrowsAsync(() => sut.GetAsync(id, 10)); + await Assert.ThrowsAsync(() => sut.GetAsync(appId, id, 10)); } [Fact] @@ -47,7 +49,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries A.CallTo(() => grain.GetStateAsync(10)) .Returns(J.Of(content)); - await Assert.ThrowsAsync(() => sut.GetAsync(id, 10)); + await Assert.ThrowsAsync(() => sut.GetAsync(appId, id, 10)); } [Fact] @@ -58,7 +60,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries A.CallTo(() => grain.GetStateAsync(10)) .Returns(J.Of(content)); - await Assert.ThrowsAsync(() => sut.GetAsync(id, 10)); + await Assert.ThrowsAsync(() => sut.GetAsync(appId, id, 10)); } [Fact] @@ -69,7 +71,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries A.CallTo(() => grain.GetStateAsync(10)) .Returns(J.Of(content)); - var result = await sut.GetAsync(id, 10); + var result = await sut.GetAsync(appId, id, 10); Assert.Same(content, result); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryParserTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryParserTests.cs index 1ca3e039f..a96369156 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryParserTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryParserTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -22,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries public class AssetQueryParserTests { private readonly ITagService tagService = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly Context requestContext; private readonly AssetQueryParser sut; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryServiceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryServiceTests.cs index 8662640f9..e6a502187 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryServiceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryServiceTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -23,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries private readonly IAssetEnricher assetEnricher = A.Fake(); private readonly IAssetRepository assetRepository = A.Fake(); private readonly IAssetFolderRepository assetFolderRepository = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly Context requestContext; private readonly AssetQueryParser queryParser = A.Fake(); private readonly AssetQueryService sut; @@ -41,11 +40,11 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries [Fact] public async Task Should_find_asset_by_id_and_enrich_it() { - var found = new AssetEntity { Id = Guid.NewGuid() }; + var found = new AssetEntity { Id = DomainId.NewGuid() }; var enriched = new AssetEntity(); - A.CallTo(() => assetRepository.FindAssetAsync(found.Id)) + A.CallTo(() => assetRepository.FindAssetAsync(appId.Id, found.Id)) .Returns(found); A.CallTo(() => assetEnricher.EnrichAsync(found, requestContext)) @@ -59,7 +58,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries [Fact] public async Task Should_find_assets_by_hash_and_and_enrich_it() { - var found = new AssetEntity { Id = Guid.NewGuid() }; + var found = new AssetEntity { Id = DomainId.NewGuid() }; var enriched = new AssetEntity(); @@ -77,15 +76,15 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries [Fact] public async Task Should_load_assets_from_ids_and_resolve_tags() { - var found1 = new AssetEntity { Id = Guid.NewGuid() }; - var found2 = new AssetEntity { Id = Guid.NewGuid() }; + var found1 = new AssetEntity { Id = DomainId.NewGuid() }; + var found2 = new AssetEntity { Id = DomainId.NewGuid() }; var enriched1 = new AssetEntity(); var enriched2 = new AssetEntity(); var ids = HashSet.Of(found1.Id, found2.Id); - A.CallTo(() => assetRepository.QueryAsync(appId.Id, A>.That.Is(ids))) + A.CallTo(() => assetRepository.QueryAsync(appId.Id, A>.That.Is(ids))) .Returns(ResultList.CreateFrom(8, found1, found2)); A.CallTo(() => assetEnricher.EnrichAsync(A>.That.IsSameSequenceAs(found1, found2), requestContext)) @@ -101,13 +100,13 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries [Fact] public async Task Should_load_assets_with_query_and_resolve_tags() { - var found1 = new AssetEntity { Id = Guid.NewGuid() }; - var found2 = new AssetEntity { Id = Guid.NewGuid() }; + var found1 = new AssetEntity { Id = DomainId.NewGuid() }; + var found2 = new AssetEntity { Id = DomainId.NewGuid() }; var enriched1 = new AssetEntity(); var enriched2 = new AssetEntity(); - var parentId = Guid.NewGuid(); + var parentId = DomainId.NewGuid(); A.CallTo(() => assetRepository.QueryAsync(appId.Id, parentId, A._)) .Returns(ResultList.CreateFrom(8, found1, found2)); @@ -125,7 +124,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries [Fact] public async Task Should_load_assets_folders_from_repository() { - var parentId = Guid.NewGuid(); + var parentId = DomainId.NewGuid(); var assetFolders = ResultList.CreateFrom(10); @@ -140,13 +139,13 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries [Fact] public async Task Should_resolve_folder_path_from_root() { - var folderId1 = Guid.NewGuid(); + var folderId1 = DomainId.NewGuid(); var folder1 = CreateFolder(folderId1); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(folderId1)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1)) .Returns(folder1); - var result = await sut.FindAssetFolderAsync(folderId1); + var result = await sut.FindAssetFolderAsync(appId.Id, folderId1); Assert.Equal(result, new[] { folder1 }); } @@ -154,24 +153,24 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries [Fact] public async Task Should_resolve_folder_path_from_child() { - var folderId1 = Guid.NewGuid(); - var folderId2 = Guid.NewGuid(); - var folderId3 = Guid.NewGuid(); + var folderId1 = DomainId.NewGuid(); + var folderId2 = DomainId.NewGuid(); + var folderId3 = DomainId.NewGuid(); var folder1 = CreateFolder(folderId1); var folder2 = CreateFolder(folderId2, folderId1); var folder3 = CreateFolder(folderId3, folderId2); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(folderId1)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1)) .Returns(folder1); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(folderId2)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId2)) .Returns(folder2); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(folderId3)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId3)) .Returns(folder3); - var result = await sut.FindAssetFolderAsync(folderId3); + var result = await sut.FindAssetFolderAsync(appId.Id, folderId3); Assert.Equal(result, new[] { folder1, folder2, folder3 }); } @@ -179,12 +178,12 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries [Fact] public async Task Should_not_resolve_folder_path_if_root_not_found() { - var folderId1 = Guid.NewGuid(); + var folderId1 = DomainId.NewGuid(); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(folderId1)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1)) .Returns(Task.FromResult(null)); - var result = await sut.FindAssetFolderAsync(folderId1); + var result = await sut.FindAssetFolderAsync(appId.Id, folderId1); Assert.Empty(result); } @@ -192,19 +191,19 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries [Fact] public async Task Should_not_resolve_folder_path_if_parent_of_child_not_found() { - var folderId1 = Guid.NewGuid(); - var folderId2 = Guid.NewGuid(); + var folderId1 = DomainId.NewGuid(); + var folderId2 = DomainId.NewGuid(); var folder1 = CreateFolder(folderId1); var folder2 = CreateFolder(folderId2, folderId1); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(folderId1)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1)) .Returns(Task.FromResult(null)); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(folderId2)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId2)) .Returns(folder2); - var result = await sut.FindAssetFolderAsync(folderId2); + var result = await sut.FindAssetFolderAsync(appId.Id, folderId2); Assert.Empty(result); } @@ -212,24 +211,24 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries [Fact] public async Task Should_not_resolve_folder_path_if_recursion_detected() { - var folderId1 = Guid.NewGuid(); - var folderId2 = Guid.NewGuid(); + var folderId1 = DomainId.NewGuid(); + var folderId2 = DomainId.NewGuid(); var folder1 = CreateFolder(folderId1, folderId2); var folder2 = CreateFolder(folderId2, folderId1); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(folderId1)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1)) .Returns(Task.FromResult(null)); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(folderId2)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId2)) .Returns(folder2); - var result = await sut.FindAssetFolderAsync(folderId2); + var result = await sut.FindAssetFolderAsync(appId.Id, folderId2); Assert.Empty(result); } - private static IAssetFolderEntity CreateFolder(Guid id, Guid parentId = default) + private static IAssetFolderEntity CreateFolder(DomainId id, DomainId parentId = default) { var assetFolder = A.Fake(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/FilterTagTransformerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/FilterTagTransformerTests.cs index db1e7ab50..386b34ce3 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/FilterTagTransformerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/FilterTagTransformerTests.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Core.Tags; +using Squidex.Infrastructure; using Squidex.Infrastructure.Queries; using Xunit; @@ -18,7 +18,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries public class FilterTagTransformerTests { private readonly ITagService tagService = A.Fake(); - private readonly Guid appId = Guid.NewGuid(); + private readonly DomainId appId = DomainId.NewGuid(); [Fact] public async Task Should_normalize_tags() diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RecursiveDeleterTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RecursiveDeleterTests.cs index 6b55daf0a..cfd5382d1 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RecursiveDeleterTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RecursiveDeleterTests.cs @@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Assets private readonly IAssetRepository assetRepository = A.Fake(); private readonly IAssetFolderRepository assetFolderRepository = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RecursiveDeleter sut; public RecursiveDeleterTests() @@ -47,13 +47,13 @@ namespace Squidex.Domain.Apps.Entities.Assets [Fact] public async Task Should_invoke_delete_commands_for_all_subfolders() { - var @event = new AssetFolderDeleted { AppId = appId, AssetFolderId = Guid.NewGuid() }; + var @event = new AssetFolderDeleted { AppId = appId, AssetFolderId = DomainId.NewGuid() }; - var childFolderId1 = Guid.NewGuid(); - var childFolderId2 = Guid.NewGuid(); + var childFolderId1 = DomainId.NewGuid(); + var childFolderId2 = DomainId.NewGuid(); A.CallTo(() => assetFolderRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId)) - .Returns(new List { childFolderId1, childFolderId2 }); + .Returns(new List { childFolderId1, childFolderId2 }); await sut.On(Envelope.Create(@event)); @@ -67,13 +67,13 @@ namespace Squidex.Domain.Apps.Entities.Assets [Fact] public async Task Should_invoke_delete_commands_for_all_assets() { - var @event = new AssetFolderDeleted { AppId = appId, AssetFolderId = Guid.NewGuid() }; + var @event = new AssetFolderDeleted { AppId = appId, AssetFolderId = DomainId.NewGuid() }; - var childId1 = Guid.NewGuid(); - var childId2 = Guid.NewGuid(); + var childId1 = DomainId.NewGuid(); + var childId2 = DomainId.NewGuid(); A.CallTo(() => assetRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId)) - .Returns(new List { childId1, childId2 }); + .Returns(new List { childId1, childId2 }); await sut.On(Envelope.Create(@event)); @@ -87,16 +87,16 @@ namespace Squidex.Domain.Apps.Entities.Assets [Fact] public async Task Should_ignore_exceptions() { - var @event = new AssetFolderDeleted { AppId = appId, AssetFolderId = Guid.NewGuid() }; + var @event = new AssetFolderDeleted { AppId = appId, AssetFolderId = DomainId.NewGuid() }; - var childId1 = Guid.NewGuid(); - var childId2 = Guid.NewGuid(); + var childId1 = DomainId.NewGuid(); + var childId2 = DomainId.NewGuid(); A.CallTo(() => commandBus.PublishAsync(A.That.Matches(x => x.AssetId == childId1))) .Throws(new InvalidOperationException()); A.CallTo(() => assetRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId)) - .Returns(new List { childId1, childId2 }); + .Returns(new List { childId1, childId2 }); await sut.On(Envelope.Create(@event)); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupReaderWriterTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupReaderWriterTests.cs index 118178dd1..42d4808c4 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupReaderWriterTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupReaderWriterTests.cs @@ -31,13 +31,13 @@ namespace Squidex.Domain.Apps.Entities.Backup [TypeName(nameof(MyEvent))] public sealed class MyEvent : IEvent { - public Guid GuidRaw { get; set; } + public DomainId DomainIdRaw { get; set; } - public Guid GuidEmpty { get; set; } + public DomainId DomainIdEmpty { get; set; } - public NamedId GuidNamed { get; set; } + public NamedId DomainIdNamed { get; set; } - public Dictionary Values { get; set; } + public Dictionary Values { get; set; } } public BackupReaderWriterTests() @@ -45,9 +45,6 @@ namespace Squidex.Domain.Apps.Entities.Backup typeNameRegistry.Map(typeof(MyEvent)); formatter = new DefaultEventDataFormatter(typeNameRegistry, serializer); - - A.CallTo(() => streamNameResolver.WithNewId(A._, A>._)) - .ReturnsLazily(new Func, string>((stream, idGenerator) => stream + "^2")); } [Theory] @@ -58,16 +55,16 @@ namespace Squidex.Domain.Apps.Entities.Backup var stream = new MemoryStream(); var random = new Random(); - var randomGuids = new List(); + var randomDomainIds = new List(); for (var i = 0; i < 100; i++) { - randomGuids.Add(Guid.NewGuid()); + randomDomainIds.Add(DomainId.NewGuid()); } - Guid RandomGuid() + DomainId RandomDomainId() { - return randomGuids[random.Next(randomGuids.Count)]; + return randomDomainIds[random.Next(randomDomainIds.Count)]; } var sourceEvents = new List<(string Stream, Envelope Event)>(); @@ -76,21 +73,21 @@ namespace Squidex.Domain.Apps.Entities.Backup { var @event = new MyEvent { - GuidNamed = NamedId.Of(RandomGuid(), $"name{i}"), - GuidRaw = RandomGuid(), - Values = new Dictionary + DomainIdNamed = NamedId.Of(RandomDomainId(), $"name{i}"), + DomainIdRaw = RandomDomainId(), + Values = new Dictionary { - [RandomGuid()] = "Key" + [RandomDomainId()] = "Key" } }; var envelope = Envelope.Create(@event); - envelope.Headers.Add(RandomGuid().ToString(), i); - envelope.Headers.Add("Id", RandomGuid().ToString()); + envelope.Headers.Add(RandomDomainId().ToString(), i); + envelope.Headers.Add("Id", RandomDomainId().ToString()); envelope.Headers.Add("Index", i); - sourceEvents.Add(($"My-{RandomGuid()}", envelope)); + sourceEvents.Add(($"My-{RandomDomainId()}", envelope)); } using (var writer = new BackupWriter(serializer, stream, true, version)) @@ -151,24 +148,17 @@ namespace Squidex.Domain.Apps.Entities.Backup targetEvents.Add(@event); }); - void CompareGuid(Guid source, Guid target) - { - Assert.Equal(source, reader.OldGuid(target)); - Assert.NotEqual(source, target); - } - for (var i = 0; i < targetEvents.Count; i++) { var target = targetEvents[i].Event.To(); var source = sourceEvents[i].Event.To(); - CompareGuid(source.Payload.Values.First().Key, target.Payload.Values.First().Key); - CompareGuid(source.Payload.GuidRaw, target.Payload.GuidRaw); - CompareGuid(source.Payload.GuidNamed.Id, target.Payload.GuidNamed.Id); - CompareGuid(source.Headers.GetGuid("Id"), target.Headers.GetGuid("Id")); + Assert.Equal(source.Payload.Values.First().Key, target.Payload.Values.First().Key); + Assert.Equal(source.Payload.DomainIdRaw, target.Payload.DomainIdRaw); + Assert.Equal(source.Payload.DomainIdNamed.Id, target.Payload.DomainIdNamed.Id); - Assert.Equal(Guid.Empty, target.Payload.GuidEmpty); + Assert.Equal(DomainId.Empty, target.Payload.DomainIdEmpty); } } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupServiceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupServiceTests.cs index 96faca043..68cfe2e9f 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupServiceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupServiceTests.cs @@ -20,8 +20,8 @@ namespace Squidex.Domain.Apps.Entities.Backup public class BackupServiceTests { private readonly IGrainFactory grainFactory = A.Fake(); - private readonly Guid appId = Guid.NewGuid(); - private readonly Guid backupId = Guid.NewGuid(); + private readonly DomainId appId = DomainId.NewGuid(); + private readonly DomainId backupId = DomainId.NewGuid(); private readonly RefToken actor = new RefToken(RefTokenType.Subject, "me"); private readonly BackupService sut; @@ -72,7 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Backup { var grain = A.Fake(); - A.CallTo(() => grainFactory.GetGrain(appId, null)) + A.CallTo(() => grainFactory.GetGrain(appId.ToString(), null)) .Returns(grain); await sut.StartBackupAsync(appId, actor); @@ -91,7 +91,7 @@ namespace Squidex.Domain.Apps.Entities.Backup var grain = A.Fake(); - A.CallTo(() => grainFactory.GetGrain(appId, null)) + A.CallTo(() => grainFactory.GetGrain(appId.ToString(), null)) .Returns(grain); A.CallTo(() => grain.GetStateAsync()) @@ -112,14 +112,14 @@ namespace Squidex.Domain.Apps.Entities.Backup var grain = A.Fake(); - A.CallTo(() => grainFactory.GetGrain(appId, null)) + A.CallTo(() => grainFactory.GetGrain(appId.ToString(), null)) .Returns(grain); A.CallTo(() => grain.GetStateAsync()) .Returns(state.AsJ()); var result1 = await sut.GetBackupAsync(appId, backupId); - var result2 = await sut.GetBackupAsync(appId, Guid.NewGuid()); + var result2 = await sut.GetBackupAsync(appId, DomainId.NewGuid()); Assert.Same(state[0], result1); Assert.Null(result2); @@ -130,7 +130,7 @@ namespace Squidex.Domain.Apps.Entities.Backup { var grain = A.Fake(); - A.CallTo(() => grainFactory.GetGrain(appId, null)) + A.CallTo(() => grainFactory.GetGrain(appId.ToString(), null)) .Returns(grain); await sut.DeleteBackupAsync(appId, backupId); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/DefaultBackupArchiveStoreTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/DefaultBackupArchiveStoreTests.cs index 515aa7c57..ba45bbf3b 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/DefaultBackupArchiveStoreTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/DefaultBackupArchiveStoreTests.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.IO; using System.Threading; using System.Threading.Tasks; using FakeItEasy; +using Squidex.Infrastructure; using Squidex.Infrastructure.Assets; using Xunit; @@ -18,7 +18,7 @@ namespace Squidex.Domain.Apps.Entities.Backup public class DefaultBackupArchiveStoreTests { private readonly IAssetStore assetStore = A.Fake(); - private readonly Guid backupId = Guid.NewGuid(); + private readonly DomainId backupId = DomainId.NewGuid(); private readonly string fileName; private readonly DefaultBackupArchiveStore sut; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentTriggerHandlerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentTriggerHandlerTests.cs index addf2f834..9558dccec 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentTriggerHandlerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentTriggerHandlerTests.cs @@ -19,6 +19,7 @@ using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events.Comments; using Squidex.Domain.Apps.Events.Contents; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; using Squidex.Shared.Users; using Xunit; @@ -142,7 +143,7 @@ namespace Squidex.Domain.Apps.Entities.Comments { TestForCondition(string.Empty, trigger => { - var result = sut.Trigger(new ContentCreated(), trigger, Guid.NewGuid()); + var result = sut.Trigger(new ContentCreated(), trigger, DomainId.NewGuid()); Assert.False(result); }); @@ -153,7 +154,7 @@ namespace Squidex.Domain.Apps.Entities.Comments { TestForCondition(string.Empty, trigger => { - var result = sut.Trigger(new CommentCreated(), trigger, Guid.NewGuid()); + var result = sut.Trigger(new CommentCreated(), trigger, DomainId.NewGuid()); Assert.True(result); }); @@ -255,7 +256,7 @@ namespace Squidex.Domain.Apps.Entities.Comments }); } - private IUser CreateUser(string id, string email = "sebastian@squidex.io") + private static IUser CreateUser(string id, string email = "sebastian@squidex.io") { var user = A.Fake(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsCommandMiddlewareTests.cs index b2c06eb46..1f771b498 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsCommandMiddlewareTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Orleans; @@ -24,9 +23,9 @@ namespace Squidex.Domain.Apps.Entities.Comments private readonly IUserResolver userResolver = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); private readonly RefToken actor = new RefToken(RefTokenType.Subject, "me"); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly Guid commentsId = Guid.NewGuid(); - private readonly Guid commentId = Guid.NewGuid(); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly DomainId commentsId = DomainId.NewGuid(); + private readonly DomainId commentId = DomainId.NewGuid(); private readonly CommentsCommandMiddleware sut; public CommentsCommandMiddlewareTests() diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsGrainTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsGrainTests.cs index de5dca162..7cdc5eaaa 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsGrainTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsGrainTests.cs @@ -27,8 +27,8 @@ namespace Squidex.Domain.Apps.Entities.Comments { private readonly IEventStore eventStore = A.Fake(); private readonly IEventDataFormatter eventDataFormatter = A.Fake(); - private readonly Guid commentsId = Guid.NewGuid(); - private readonly Guid commentId = Guid.NewGuid(); + private readonly DomainId commentsId = DomainId.NewGuid(); + private readonly DomainId commentId = DomainId.NewGuid(); private readonly RefToken actor = new RefToken(RefTokenType.Subject, "me"); private readonly CommentsGrain sut; @@ -123,7 +123,7 @@ namespace Squidex.Domain.Apps.Entities.Comments sut.GetCommentsAsync(-1).Result.Should().BeEquivalentTo(new CommentsResult { Version = 2 }); sut.GetCommentsAsync(0).Result.Should().BeEquivalentTo(new CommentsResult { - DeletedComments = new List + DeletedComments = new List { commentId }, @@ -131,7 +131,7 @@ namespace Squidex.Domain.Apps.Entities.Comments }); sut.GetCommentsAsync(1).Result.Should().BeEquivalentTo(new CommentsResult { - DeletedComments = new List + DeletedComments = new List { commentId }, @@ -157,7 +157,7 @@ namespace Squidex.Domain.Apps.Entities.Comments protected T CreateCommentsEvent(T @event) where T : CommentsEvent { @event.Actor = actor; - @event.CommentsId = commentsId.ToString(); + @event.CommentsId = commentsId; @event.CommentId = commentId; return @event; @@ -166,7 +166,7 @@ namespace Squidex.Domain.Apps.Entities.Comments protected T CreateCommentsCommand(T command) where T : CommentsCommand { command.Actor = actor; - command.CommentsId = commentsId.ToString(); + command.CommentsId = commentsId; command.CommentId = commentId; return command; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsLoaderTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsLoaderTests.cs index 2ccc49147..da842560b 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsLoaderTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsLoaderTests.cs @@ -5,10 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Orleans; +using Squidex.Infrastructure; using Xunit; namespace Squidex.Domain.Apps.Entities.Comments @@ -26,7 +26,7 @@ namespace Squidex.Domain.Apps.Entities.Comments [Fact] public async Task Should_get_comments_from_grain() { - var commentsId = Guid.NewGuid().ToString(); + var commentsId = DomainId.NewGuid().ToString(); var comments = new CommentsResult(); var grain = A.Fake(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/Guards/GuardCommentsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/Guards/GuardCommentsTests.cs index 7b5d6e45c..4f0cf02a2 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/Guards/GuardCommentsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/Guards/GuardCommentsTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Squidex.Domain.Apps.Entities.Comments.Commands; using Squidex.Domain.Apps.Entities.TestHelpers; @@ -19,7 +18,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Guards { public class GuardCommentsTests { - private readonly string commentsId = Guid.NewGuid().ToString(); + private readonly string commentsId = DomainId.NewGuid().ToString(); private readonly RefToken user1 = new RefToken(RefTokenType.Subject, "1"); private readonly RefToken user2 = new RefToken(RefTokenType.Subject, "2"); @@ -43,7 +42,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Guards [Fact] public void CanUpdate_should_throw_exception_if_text_not_defined() { - var commentId = Guid.NewGuid(); + var commentId = DomainId.NewGuid(); var command = new UpdateComment { CommentId = commentId, Actor = user1 }; var events = new List> @@ -58,7 +57,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Guards [Fact] public void CanUpdate_should_throw_exception_if_comment_from_another_user() { - var commentId = Guid.NewGuid(); + var commentId = DomainId.NewGuid(); var command = new UpdateComment { CommentId = commentId, Actor = user2, Text = "text2" }; var events = new List> @@ -72,7 +71,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Guards [Fact] public void CanUpdate_should_throw_exception_if_comment_not_found() { - var commentId = Guid.NewGuid(); + var commentId = DomainId.NewGuid(); var command = new UpdateComment { CommentId = commentId, Actor = user1 }; var events = new List>(); @@ -83,7 +82,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Guards [Fact] public void CanUpdate_should_throw_exception_if_comment_deleted_found() { - var commentId = Guid.NewGuid(); + var commentId = DomainId.NewGuid(); var command = new UpdateComment { CommentId = commentId, Actor = user1 }; var events = new List> @@ -98,7 +97,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Guards [Fact] public void CanUpdate_should_not_throw_exception_if_comment_is_own_notification() { - var commentId = Guid.NewGuid(); + var commentId = DomainId.NewGuid(); var command = new UpdateComment { CommentId = commentId, Actor = user1, Text = "text2" }; var events = new List> @@ -112,7 +111,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Guards [Fact] public void CanUpdate_should_not_throw_exception_if_comment_from_same_user() { - var commentId = Guid.NewGuid(); + var commentId = DomainId.NewGuid(); var command = new UpdateComment { CommentId = commentId, Actor = user1, Text = "text2" }; var events = new List> @@ -126,7 +125,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Guards [Fact] public void CanDelete_should_throw_exception_if_comment_from_another_user() { - var commentId = Guid.NewGuid(); + var commentId = DomainId.NewGuid(); var command = new DeleteComment { CommentId = commentId, Actor = user2 }; var events = new List> @@ -140,7 +139,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Guards [Fact] public void CanDelete_should_throw_exception_if_comment_not_found() { - var commentId = Guid.NewGuid(); + var commentId = DomainId.NewGuid(); var command = new DeleteComment { CommentId = commentId, Actor = user1 }; var events = new List>(); @@ -151,7 +150,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Guards [Fact] public void CanDelete_should_throw_exception_if_comment_deleted() { - var commentId = Guid.NewGuid(); + var commentId = DomainId.NewGuid(); var command = new DeleteComment { CommentId = commentId, Actor = user1 }; var events = new List> @@ -166,7 +165,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Guards [Fact] public void CanDelete_should_not_throw_exception_if_comment_is_own_notification() { - var commentId = Guid.NewGuid(); + var commentId = DomainId.NewGuid(); var command = new DeleteComment { CommentId = commentId, Actor = user1 }; var events = new List> @@ -180,7 +179,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.Guards [Fact] public void CanDelete_should_not_throw_exception_if_comment_from_same_user() { - var commentId = Guid.NewGuid(); + var commentId = DomainId.NewGuid(); var command = new DeleteComment { CommentId = commentId, Actor = user1 }; var events = new List> diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BackupContentsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BackupContentsTests.cs index 531ee2b4c..97004c9bc 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BackupContentsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BackupContentsTests.cs @@ -23,6 +23,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { public class BackupContentsTests { + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly Rebuilder rebuilder = A.Fake(); private readonly BackupContents sut; @@ -40,36 +41,34 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public async Task Should_restore_states_for_all_contents() { - var appId = Guid.NewGuid(); + var schemaId1 = NamedId.Of(DomainId.NewGuid(), "my-schema1"); + var schemaId2 = NamedId.Of(DomainId.NewGuid(), "my-schema2"); - var schemaId1 = NamedId.Of(Guid.NewGuid(), "my-schema1"); - var schemaId2 = NamedId.Of(Guid.NewGuid(), "my-schema2"); + var contentId1 = DomainId.NewGuid(); + var contentId2 = DomainId.NewGuid(); + var contentId3 = DomainId.NewGuid(); - var contentId1 = Guid.NewGuid(); - var contentId2 = Guid.NewGuid(); - var contentId3 = Guid.NewGuid(); + var context = new RestoreContext(appId.Id, new UserMapping(new RefToken(RefTokenType.Subject, "123")), A.Fake(), DomainId.NewGuid()); - var context = new RestoreContext(appId, new UserMapping(new RefToken(RefTokenType.Subject, "123")), A.Fake()); - - await sut.RestoreEventAsync(Envelope.Create(new ContentCreated + await sut.RestoreEventAsync(ContentEvent(new ContentCreated { ContentId = contentId1, SchemaId = schemaId1 }), context); - await sut.RestoreEventAsync(Envelope.Create(new ContentCreated + await sut.RestoreEventAsync(ContentEvent(new ContentCreated { ContentId = contentId2, SchemaId = schemaId1 }), context); - await sut.RestoreEventAsync(Envelope.Create(new ContentCreated + await sut.RestoreEventAsync(ContentEvent(new ContentCreated { ContentId = contentId3, SchemaId = schemaId2 }), context); - await sut.RestoreEventAsync(Envelope.Create(new ContentDeleted + await sut.RestoreEventAsync(ContentEvent(new ContentDeleted { ContentId = contentId2, SchemaId = schemaId1 @@ -80,25 +79,29 @@ namespace Squidex.Domain.Apps.Entities.Contents SchemaId = schemaId2 }), context); - var rebuildContents = new HashSet(); - - var add = new Func(id => - { - rebuildContents.Add(id); + var rebuildContents = new HashSet(); - return Task.CompletedTask; - }); - - A.CallTo(() => rebuilder.InsertManyAsync(A._, A._)) - .Invokes((IdSource source, CancellationToken _) => source(add)); + A.CallTo(() => rebuilder.InsertManyAsync(A>._, A._)) + .Invokes((IEnumerable source, CancellationToken _) => rebuildContents.AddRange(source)); await sut.RestoreAsync(context); - Assert.Equal(new HashSet + Assert.Equal(new HashSet { - contentId1, - contentId2 + DomainId.Combine(appId.Id, contentId1), + DomainId.Combine(appId.Id, contentId2) }, rebuildContents); } + + private Envelope ContentEvent(ContentEvent @event) + { + @event.AppId = appId; + + var envelope = Envelope.Create(@event); + + envelope.SetAggregateId(DomainId.Combine(appId.Id, @event.ContentId)); + + return envelope; + } } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BulkUpdateCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BulkUpdateCommandMiddlewareTests.cs index 0d87c2fb2..b44fe7871 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BulkUpdateCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BulkUpdateCommandMiddlewareTests.cs @@ -27,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.Contents private readonly IContextProvider contextProvider = A.Fake(); private readonly ICommandBus commandBus = A.Dummy(); private readonly Context requestContext = Context.Anonymous(); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly BulkUpdateCommandMiddleware sut; public BulkUpdateCommandMiddlewareTests() @@ -103,7 +103,7 @@ namespace Squidex.Domain.Apps.Entities.Contents A.CallTo(() => domainObject.ExecuteAsync(A.That.Matches(x => x.Data == data))) .MustHaveHappenedOnceExactly(); - A.CallTo(() => domainObject.Setup(A._)) + A.CallTo(() => domainObject.Setup(A._)) .MustHaveHappenedOnceExactly(); } @@ -143,7 +143,7 @@ namespace Squidex.Domain.Apps.Entities.Contents A.CallTo(() => domainObject.ExecuteAsync(A.That.Matches(x => x.Data == data))) .MustHaveHappenedOnceExactly(); - A.CallTo(() => domainObject.Setup(A._)) + A.CallTo(() => domainObject.Setup(A._)) .MustHaveHappenedOnceExactly(); } @@ -373,7 +373,7 @@ namespace Squidex.Domain.Apps.Entities.Contents .MustNotHaveHappened(); } - private static (Guid Id, NamedContentData Data, Query? Query) CreateTestData(bool withQuery) + private static (DomainId Id, NamedContentData Data, Query? Query) CreateTestData(bool withQuery) { Query? query = withQuery ? new Query() : null; @@ -383,10 +383,10 @@ namespace Squidex.Domain.Apps.Entities.Contents new ContentFieldData() .AddJsonValue("iv", JsonValue.Create(1))); - return (Guid.NewGuid(), data, query); + return (DomainId.NewGuid(), data, query); } - private static IEnrichedContentEntity CreateContent(Guid id) + private static IEnrichedContentEntity CreateContent(DomainId id) { return new ContentEntity { Id = id }; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs index 85cf72960..7dea40b00 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs @@ -34,10 +34,11 @@ namespace Squidex.Domain.Apps.Entities.Contents private readonly IScriptEngine scriptEngine = A.Fake(); private readonly ILocalCache localCache = new AsyncLocalCache(); private readonly IContentLoader contentLoader = A.Fake(); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaMatch = NamedId.Of(DomainId.NewGuid(), "my-schema1"); + private readonly NamedId schemaNonMatch = NamedId.Of(DomainId.NewGuid(), "my-schema2"); + private readonly DomainId ruleId = DomainId.NewGuid(); private readonly IRuleTriggerHandler sut; - private readonly Guid ruleId = Guid.NewGuid(); - private static readonly NamedId SchemaMatch = NamedId.Of(Guid.NewGuid(), "my-schema1"); - private static readonly NamedId SchemaNonMatch = NamedId.Of(Guid.NewGuid(), "my-schema2"); public ContentChangedTriggerHandlerTests() { @@ -64,10 +65,12 @@ namespace Squidex.Domain.Apps.Entities.Contents [MemberData(nameof(TestEvents))] public async Task Should_create_enriched_events(ContentEvent @event, EnrichedContentEventType type) { + @event.AppId = appId; + var envelope = Envelope.Create(@event).SetEventStreamNumber(12); - A.CallTo(() => contentLoader.GetAsync(@event.ContentId, 12)) - .Returns(new ContentEntity { SchemaId = SchemaMatch }); + A.CallTo(() => contentLoader.GetAsync(appId.Id, @event.ContentId, 12)) + .Returns(new ContentEntity { AppId = appId, SchemaId = schemaMatch }); var result = await sut.CreateEnrichedEventsAsync(envelope); @@ -79,18 +82,18 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public async Task Should_enrich_with_old_data_when_updated() { - var @event = new ContentUpdated(); + var @event = new ContentUpdated { AppId = appId, ContentId = DomainId.NewGuid() }; var envelope = Envelope.Create(@event).SetEventStreamNumber(12); var dataNow = new NamedContentData(); var dataOld = new NamedContentData(); - A.CallTo(() => contentLoader.GetAsync(@event.ContentId, 12)) - .Returns(new ContentEntity { SchemaId = SchemaMatch, Version = 12, Data = dataNow }); + A.CallTo(() => contentLoader.GetAsync(appId.Id, @event.ContentId, 12)) + .Returns(new ContentEntity { AppId = appId, SchemaId = schemaMatch, Version = 12, Data = dataNow, Id = @event.ContentId }); - A.CallTo(() => contentLoader.GetAsync(@event.ContentId, 11)) - .Returns(new ContentEntity { SchemaId = SchemaMatch, Version = 11, Data = dataOld }); + A.CallTo(() => contentLoader.GetAsync(appId.Id, @event.ContentId, 11)) + .Returns(new ContentEntity { AppId = appId, SchemaId = schemaMatch, Version = 11, Data = dataOld }); var result = await sut.CreateEnrichedEventsAsync(envelope); @@ -116,7 +119,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { TestForTrigger(handleAll: false, schemaId: null, condition: null, action: trigger => { - var result = sut.Trigger(new ContentCreated { SchemaId = SchemaMatch }, trigger, ruleId); + var result = sut.Trigger(new ContentCreated { SchemaId = schemaMatch }, trigger, ruleId); Assert.False(result); }); @@ -125,9 +128,9 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public void Should_trigger_precheck_when_handling_all_events() { - TestForTrigger(handleAll: true, schemaId: SchemaMatch, condition: null, action: trigger => + TestForTrigger(handleAll: true, schemaId: schemaMatch, condition: null, action: trigger => { - var result = sut.Trigger(new ContentCreated { SchemaId = SchemaMatch }, trigger, ruleId); + var result = sut.Trigger(new ContentCreated { SchemaId = schemaMatch }, trigger, ruleId); Assert.True(result); }); @@ -136,9 +139,9 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public void Should_trigger_precheck_when_condition_is_empty() { - TestForTrigger(handleAll: false, schemaId: SchemaMatch, condition: string.Empty, action: trigger => + TestForTrigger(handleAll: false, schemaId: schemaMatch, condition: string.Empty, action: trigger => { - var result = sut.Trigger(new ContentCreated { SchemaId = SchemaMatch }, trigger, ruleId); + var result = sut.Trigger(new ContentCreated { SchemaId = schemaMatch }, trigger, ruleId); Assert.True(result); }); @@ -147,9 +150,9 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public void Should_not_trigger_precheck_when_schema_id_does_not_match() { - TestForTrigger(handleAll: false, schemaId: SchemaNonMatch, condition: null, action: trigger => + TestForTrigger(handleAll: false, schemaId: schemaNonMatch, condition: null, action: trigger => { - var result = sut.Trigger(new ContentCreated { SchemaId = SchemaMatch }, trigger, ruleId); + var result = sut.Trigger(new ContentCreated { SchemaId = schemaMatch }, trigger, ruleId); Assert.False(result); }); @@ -171,7 +174,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { TestForTrigger(handleAll: false, schemaId: null, condition: null, action: trigger => { - var result = sut.Trigger(new EnrichedContentEvent { SchemaId = SchemaMatch }, trigger); + var result = sut.Trigger(new EnrichedContentEvent { SchemaId = schemaMatch }, trigger); Assert.False(result); }); @@ -180,9 +183,9 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public void Should_trigger_check_when_handling_all_events() { - TestForTrigger(handleAll: true, schemaId: SchemaMatch, condition: null, action: trigger => + TestForTrigger(handleAll: true, schemaId: schemaMatch, condition: null, action: trigger => { - var result = sut.Trigger(new EnrichedContentEvent { SchemaId = SchemaMatch }, trigger); + var result = sut.Trigger(new EnrichedContentEvent { SchemaId = schemaMatch }, trigger); Assert.True(result); }); @@ -191,9 +194,9 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public void Should_trigger_check_when_condition_is_empty() { - TestForTrigger(handleAll: false, schemaId: SchemaMatch, condition: string.Empty, action: trigger => + TestForTrigger(handleAll: false, schemaId: schemaMatch, condition: string.Empty, action: trigger => { - var result = sut.Trigger(new EnrichedContentEvent { SchemaId = SchemaMatch }, trigger); + var result = sut.Trigger(new EnrichedContentEvent { SchemaId = schemaMatch }, trigger); Assert.True(result); }); @@ -202,9 +205,9 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public void Should_trigger_check_when_condition_matchs() { - TestForTrigger(handleAll: false, schemaId: SchemaMatch, condition: "true", action: trigger => + TestForTrigger(handleAll: false, schemaId: schemaMatch, condition: "true", action: trigger => { - var result = sut.Trigger(new EnrichedContentEvent { SchemaId = SchemaMatch }, trigger); + var result = sut.Trigger(new EnrichedContentEvent { SchemaId = schemaMatch }, trigger); Assert.True(result); }); @@ -213,9 +216,9 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public void Should_not_trigger_check_when_schema_id_does_not_match() { - TestForTrigger(handleAll: false, schemaId: SchemaNonMatch, condition: null, action: trigger => + TestForTrigger(handleAll: false, schemaId: schemaNonMatch, condition: null, action: trigger => { - var result = sut.Trigger(new EnrichedContentEvent { SchemaId = SchemaMatch }, trigger); + var result = sut.Trigger(new EnrichedContentEvent { SchemaId = schemaMatch }, trigger); Assert.False(result); }); @@ -224,15 +227,15 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public void Should_not_trigger_check_when_condition_does_not_matchs() { - TestForTrigger(handleAll: false, schemaId: SchemaMatch, condition: "false", action: trigger => + TestForTrigger(handleAll: false, schemaId: schemaMatch, condition: "false", action: trigger => { - var result = sut.Trigger(new EnrichedContentEvent { SchemaId = SchemaMatch }, trigger); + var result = sut.Trigger(new EnrichedContentEvent { SchemaId = schemaMatch }, trigger); Assert.False(result); }); } - private void TestForTrigger(bool handleAll, NamedId? schemaId, string? condition, Action action) + private void TestForTrigger(bool handleAll, NamedId? schemaId, string? condition, Action action) { var trigger = new ContentChangedTriggerV2 { HandleAll = handleAll }; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs index d6ef0b12e..d83c513fc 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs @@ -5,13 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Orleans; using Squidex.Domain.Apps.Entities.Contents.Queries; using Squidex.Domain.Apps.Entities.Contents.State; using Squidex.Domain.Apps.Entities.TestHelpers; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Xunit; @@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { private readonly IContentEnricher contentEnricher = A.Fake(); private readonly IContextProvider contextProvider = A.Fake(); - private readonly Guid contentId = Guid.NewGuid(); + private readonly DomainId contentId = DomainId.NewGuid(); private readonly Context requestContext = Context.Anonymous(); private readonly ContentCommandMiddleware sut; @@ -29,7 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { } - protected override Guid Id + protected override DomainId Id { get { return contentId; } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs index 24d54dc09..c6ebcda38 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Linq; using System.Threading.Tasks; using FakeItEasy; @@ -31,7 +30,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { public class ContentDomainObjectTests : HandlerTestBase { - private readonly Guid contentId = Guid.NewGuid(); + private readonly DomainId contentId = DomainId.NewGuid(); private readonly IAppEntity app; private readonly IAppProvider appProvider = A.Fake(); private readonly IContentWorkflow contentWorkflow = A.Fake(x => x.Wrapping(new DefaultContentWorkflow())); @@ -67,9 +66,9 @@ namespace Squidex.Domain.Apps.Entities.Contents private readonly NamedContentData patched; private readonly ContentDomainObject sut; - protected override Guid Id + protected override DomainId Id { - get { return contentId; } + get { return DomainId.Combine(AppId, contentId); } } public ContentDomainObjectTests() @@ -587,7 +586,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return A.That.Matches(x => M(x, newData, oldData, newStatus, oldStatus)); } - private ScriptOptions ScriptOptions() + private static ScriptOptions ScriptOptions() { return A.That.Matches(x => x.CanDisallow && x.CanReject && x.AsContext); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentsSearchSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentsSearchSourceTests.cs index ab816d538..0c1316405 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentsSearchSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentsSearchSourceTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; @@ -32,10 +31,10 @@ namespace Squidex.Domain.Apps.Entities.Contents private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly ITextIndex contentIndex = A.Fake(); private readonly IContentQueryService contentQuery = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId1 = NamedId.Of(Guid.NewGuid(), "my-schema1"); - private readonly NamedId schemaId2 = NamedId.Of(Guid.NewGuid(), "my-schema2"); - private readonly NamedId schemaId3 = NamedId.Of(Guid.NewGuid(), "my-schema3"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId1 = NamedId.Of(DomainId.NewGuid(), "my-schema1"); + private readonly NamedId schemaId2 = NamedId.Of(DomainId.NewGuid(), "my-schema2"); + private readonly NamedId schemaId3 = NamedId.Of(DomainId.NewGuid(), "my-schema3"); private readonly ContentsSearchSource sut; public ContentsSearchSourceTests() @@ -54,7 +53,7 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public async Task Should_return_content_with_default_name() { - var content = new ContentEntity { Id = Guid.NewGuid(), SchemaId = schemaId1 }; + var content = new ContentEntity { Id = DomainId.NewGuid(), SchemaId = schemaId1 }; await TestContentAsyc(content, "Content"); } @@ -64,7 +63,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { var content = new ContentEntity { - Id = Guid.NewGuid(), + Id = DomainId.NewGuid(), Data = new NamedContentData() .AddField("field1", @@ -89,7 +88,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { var content = new ContentEntity { - Id = Guid.NewGuid(), + Id = DomainId.NewGuid(), Data = new NamedContentData() .AddField("field", @@ -110,7 +109,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { var content = new ContentEntity { - Id = Guid.NewGuid(), + Id = DomainId.NewGuid(), Data = new NamedContentData() .AddField("field", @@ -131,7 +130,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { var content = new ContentEntity { - Id = Guid.NewGuid(), + Id = DomainId.NewGuid(), Data = new NamedContentData() .AddField("field", @@ -171,29 +170,31 @@ namespace Squidex.Domain.Apps.Entities.Contents var ctx = ContextWithPermissions(schemaId1, schemaId2); A.CallTo(() => contentIndex.SearchAsync("query~", ctx.App, A._, ctx.Scope())) - .Returns(new List()); + .Returns(new List()); var result = await sut.SearchAsync("query", ctx); Assert.Empty(result); - A.CallTo(() => contentQuery.QueryAsync(ctx, A>._)) + A.CallTo(() => contentQuery.QueryAsync(ctx, A>._)) .MustNotHaveHappened(); } - private async Task TestContentAsyc(IEnrichedContentEntity content, string expectedName) + private async Task TestContentAsyc(ContentEntity content, string expectedName) { + content.AppId = appId; + var ctx = ContextWithPermissions(schemaId1, schemaId2); var searchFilter = SearchFilter.MustHaveSchemas(schemaId1.Id, schemaId2.Id); - var ids = new List { content.Id }; + var ids = new List { content.Id }; A.CallTo(() => contentIndex.SearchAsync("query~", ctx.App, A.That.IsEqualTo(searchFilter), ctx.Scope())) .Returns(ids); A.CallTo(() => contentQuery.QueryAsync(ctx, ids)) - .Returns(ResultList.CreateFrom(1, content)); + .Returns(ResultList.CreateFrom(1, content)); A.CallTo(() => urlGenerator.ContentUI(appId, schemaId1, content.Id)) .Returns("content-url"); @@ -205,7 +206,7 @@ namespace Squidex.Domain.Apps.Entities.Contents .Add(expectedName, SearchResultType.Content, "content-url")); } - private Context ContextWithPermissions(params NamedId[] allowedSchemas) + private Context ContextWithPermissions(params NamedId[] allowedSchemas) { var claimsIdentity = new ClaimsIdentity(); var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterJintExtensionTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterJintExtensionTests.cs index 88b846d7d..b09d0e3a8 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterJintExtensionTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterJintExtensionTests.cs @@ -11,6 +11,7 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using Orleans; using Squidex.Domain.Apps.Core.Scripting; +using Squidex.Infrastructure; using Xunit; namespace Squidex.Domain.Apps.Entities.Contents.Counter @@ -39,9 +40,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Counter [Fact] public void Should_reset_counter() { - var appId = Guid.NewGuid(); + var appId = DomainId.NewGuid(); - A.CallTo(() => grainFactory.GetGrain(appId, null)) + A.CallTo(() => grainFactory.GetGrain(appId.ToString(), null)) .Returns(counter); A.CallTo(() => counter.ResetAsync("my", 4)) @@ -64,9 +65,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Counter [Fact] public void Should_increment_counter() { - var appId = Guid.NewGuid(); + var appId = DomainId.NewGuid(); - A.CallTo(() => grainFactory.GetGrain(appId, null)) + A.CallTo(() => grainFactory.GetGrain(appId.ToString(), null)) .Returns(counter); A.CallTo(() => counter.IncrementAsync("my")) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultWorkflowsValidatorTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultWorkflowsValidatorTests.cs index 43c5a26b5..9d61f4254 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultWorkflowsValidatorTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultWorkflowsValidatorTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -21,15 +20,15 @@ namespace Squidex.Domain.Apps.Entities.Contents public class DefaultWorkflowsValidatorTests { private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly DefaultWorkflowsValidator sut; public DefaultWorkflowsValidatorTests() { var schema = Mocks.Schema(appId, schemaId, new Schema(schemaId.Name)); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, false)) + A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, false)) .Returns(Task.FromResult(null)); A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false)) @@ -42,8 +41,8 @@ namespace Squidex.Domain.Apps.Entities.Contents public async Task Should_generate_error_if_multiple_workflows_cover_all_schemas() { var workflows = Workflows.Empty - .Add(Guid.NewGuid(), "workflow1") - .Add(Guid.NewGuid(), "workflow2"); + .Add(DomainId.NewGuid(), "workflow1") + .Add(DomainId.NewGuid(), "workflow2"); var errors = await sut.ValidateAsync(appId.Id, workflows); @@ -53,14 +52,14 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public async Task Should_generate_error_if_multiple_workflows_cover_specific_schema() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); var workflows = Workflows.Empty .Add(id1, "workflow1") .Add(id2, "workflow2") - .Update(id1, new Workflow(default, Workflow.EmptySteps, new List { schemaId.Id })) - .Update(id2, new Workflow(default, Workflow.EmptySteps, new List { schemaId.Id })); + .Update(id1, new Workflow(default, Workflow.EmptySteps, new List { schemaId.Id })) + .Update(id2, new Workflow(default, Workflow.EmptySteps, new List { schemaId.Id })); var errors = await sut.ValidateAsync(appId.Id, workflows); @@ -70,16 +69,16 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public async Task Should_not_generate_error_if_schema_deleted() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); - var oldSchemaId = Guid.NewGuid(); + var oldSchemaId = DomainId.NewGuid(); var workflows = Workflows.Empty .Add(id1, "workflow1") .Add(id2, "workflow2") - .Update(id1, new Workflow(default, Workflow.EmptySteps, new List { oldSchemaId })) - .Update(id2, new Workflow(default, Workflow.EmptySteps, new List { oldSchemaId })); + .Update(id1, new Workflow(default, Workflow.EmptySteps, new List { oldSchemaId })) + .Update(id2, new Workflow(default, Workflow.EmptySteps, new List { oldSchemaId })); var errors = await sut.ValidateAsync(appId.Id, workflows); @@ -89,13 +88,13 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public async Task Should_not_generate_errors_for_no_overlaps() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); var workflows = Workflows.Empty .Add(id1, "workflow1") .Add(id2, "workflow2") - .Update(id1, new Workflow(default, Workflow.EmptySteps, new List { schemaId.Id })); + .Update(id1, new Workflow(default, Workflow.EmptySteps, new List { schemaId.Id })); var errors = await sut.ValidateAsync(appId.Id, workflows); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DynamicContentWorkflowTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DynamicContentWorkflowTests.cs index 0f89f5878..3be1a1ea3 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DynamicContentWorkflowTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DynamicContentWorkflowTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -25,9 +24,9 @@ namespace Squidex.Domain.Apps.Entities.Contents { private readonly IAppEntity app; private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); - private readonly NamedId simpleSchemaId = NamedId.Of(Guid.NewGuid(), "my-simple-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); + private readonly NamedId simpleSchemaId = NamedId.Of(DomainId.NewGuid(), "my-simple-schema"); private readonly DynamicContentWorkflow sut; private readonly Workflow workflow = new Workflow( @@ -82,9 +81,9 @@ namespace Squidex.Domain.Apps.Entities.Contents }, StatusColors.Published) }, - new List { simpleSchemaId.Id }); + new List { simpleSchemaId.Id }); - var workflows = Workflows.Empty.Set(workflow).Set(Guid.NewGuid(), simpleWorkflow); + var workflows = Workflows.Empty.Set(workflow).Set(DomainId.NewGuid(), simpleWorkflow); A.CallTo(() => appProvider.GetAppAsync(appId.Id)) .Returns(app); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs index 3e0966faf..e7e0310a1 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -160,7 +159,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL } }"; - var asset = CreateAsset(Guid.NewGuid()); + var asset = CreateAsset(DomainId.NewGuid()); A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), null, A.That.HasOData("?$top=30&$skip=5&$filter=my-query"))) .Returns(ResultList.CreateFrom(0, asset)); @@ -253,7 +252,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL } }"; - var asset = CreateAsset(Guid.NewGuid()); + var asset = CreateAsset(DomainId.NewGuid()); A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), null, A.That.HasOData("?$top=30&$skip=5&$filter=my-query"))) .Returns(ResultList.CreateFrom(10, asset)); @@ -316,7 +315,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL [Fact] public async Task Should_return_null_single_asset() { - var assetId = Guid.NewGuid(); + var assetId = DomainId.NewGuid(); var query = @" query { @@ -344,7 +343,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL [Fact] public async Task Should_return_single_asset_when_finding_asset() { - var assetId = Guid.NewGuid(); + var assetId = DomainId.NewGuid(); var asset = CreateAsset(assetId); var query = @" @@ -442,7 +441,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL } }"; - var content = CreateContent(Guid.NewGuid(), Guid.Empty, Guid.Empty); + var content = CreateContent(DomainId.NewGuid(), DomainId.Empty, DomainId.Empty); A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.Id.ToString(), A.That.HasOData("?$top=30&$skip=5"))) .Returns(ResultList.CreateFrom(0, content)); @@ -560,7 +559,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL } }"; - var content = CreateContent(Guid.NewGuid(), Guid.Empty, Guid.Empty); + var content = CreateContent(DomainId.NewGuid(), DomainId.Empty, DomainId.Empty); A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.Id.ToString(), A.That.HasOData("?$top=30&$skip=5"))) .Returns(ResultList.CreateFrom(0, content)); @@ -701,7 +700,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL } }"; - var content = CreateContent(Guid.NewGuid(), Guid.Empty, Guid.Empty); + var content = CreateContent(DomainId.NewGuid(), DomainId.Empty, DomainId.Empty); A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.Id.ToString(), A.That.HasOData("?$top=30&$skip=5"))) .Returns(ResultList.CreateFrom(10, content)); @@ -786,8 +785,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL [Fact] public async Task Should_return_single_content_with_fixed_names() { - var contentId = Guid.NewGuid(); - var content = CreateContent(contentId, Guid.Empty, Guid.Empty); + var contentId = DomainId.NewGuid(); + var content = CreateContent(contentId, DomainId.Empty, DomainId.Empty); var query = @" query { @@ -871,7 +870,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL [Fact] public async Task Should_return_null_single_content() { - var contentId = Guid.NewGuid(); + var contentId = DomainId.NewGuid(); var query = @" query { @@ -899,8 +898,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL [Fact] public async Task Should_return_single_content_when_finding_content() { - var contentId = Guid.NewGuid(); - var content = CreateContent(contentId, Guid.Empty, Guid.Empty); + var contentId = DomainId.NewGuid(); + var content = CreateContent(contentId, DomainId.Empty, DomainId.Empty); var query = @" query { @@ -1019,11 +1018,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL [Fact] public async Task Should_also_fetch_referenced_contents_when_field_is_included_in_query() { - var contentRefId = Guid.NewGuid(); + var contentRefId = DomainId.NewGuid(); var contentRef = CreateRefContent(schemaRefId1, contentRefId, "ref1-field", "ref1"); - var contentId = Guid.NewGuid(); - var content = CreateContent(contentId, contentRefId, Guid.Empty); + var contentId = DomainId.NewGuid(); + var content = CreateContent(contentId, contentRefId, DomainId.Empty); var query = @" query { @@ -1044,7 +1043,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL } }".Replace("", contentId.ToString()); - A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A>._)) + A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A>._)) .Returns(ResultList.CreateFrom(0, contentRef)); A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), MatchId(contentId))) @@ -1089,11 +1088,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL [Fact] public async Task Should_also_fetch_union_contents_when_field_is_included_in_query() { - var contentRefId = Guid.NewGuid(); + var contentRefId = DomainId.NewGuid(); var contentRef = CreateRefContent(schemaRefId1, contentRefId, "ref1-field", "ref1"); - var contentId = Guid.NewGuid(); - var content = CreateContent(contentId, contentRefId, Guid.Empty); + var contentId = DomainId.NewGuid(); + var content = CreateContent(contentId, contentRefId, DomainId.Empty); var query = @" query { @@ -1119,7 +1118,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL } }".Replace("", contentId.ToString()); - A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A>._)) + A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A>._)) .Returns(ResultList.CreateFrom(0, contentRef)); A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), MatchId(contentId))) @@ -1165,11 +1164,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL [Fact] public async Task Should_also_fetch_referenced_assets_when_field_is_included_in_query() { - var assetRefId = Guid.NewGuid(); + var assetRefId = DomainId.NewGuid(); var assetRef = CreateAsset(assetRefId); - var contentId = Guid.NewGuid(); - var content = CreateContent(contentId, Guid.Empty, assetRefId); + var contentId = DomainId.NewGuid(); + var content = CreateContent(contentId, DomainId.Empty, assetRefId); var query = @" query { @@ -1223,8 +1222,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL [Fact] public async Task Should_make_multiple_queries() { - var assetId1 = Guid.NewGuid(); - var assetId2 = Guid.NewGuid(); + var assetId1 = DomainId.NewGuid(); + var assetId2 = DomainId.NewGuid(); var asset1 = CreateAsset(assetId1); var asset2 = CreateAsset(assetId2); @@ -1279,8 +1278,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL [Fact] public async Task Should_not_return_data_when_field_not_part_of_content() { - var contentId = Guid.NewGuid(); - var content = CreateContent(contentId, Guid.Empty, Guid.Empty, new NamedContentData()); + var contentId = DomainId.NewGuid(); + var content = CreateContent(contentId, DomainId.Empty, DomainId.Empty, new NamedContentData()); var query = @" query { @@ -1310,12 +1309,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL Assert.Contains("\"data\":null", json); } - private static IReadOnlyList MatchId(Guid contentId) + private static IReadOnlyList MatchId(DomainId contentId) { - return A>.That.Matches(x => x.Count == 1 && x[0] == contentId); + return A>.That.Matches(x => x.Count == 1 && x[0] == contentId); } - private static Q MatchIdQuery(Guid contentId) + private static Q MatchIdQuery(DomainId contentId) { return A.That.Matches(x => x.Ids.Count == 1 && x.Ids[0] == contentId); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs index 1eb9bcf4b..d62f08b12 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs @@ -45,10 +45,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL protected readonly ISchemaEntity schemaRef1; protected readonly ISchemaEntity schemaRef2; protected readonly Context requestContext; - protected readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - protected readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); - protected readonly NamedId schemaRefId1 = NamedId.Of(Guid.NewGuid(), "my-ref-schema1"); - protected readonly NamedId schemaRefId2 = NamedId.Of(Guid.NewGuid(), "my-ref-schema2"); + protected readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + protected readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); + protected readonly NamedId schemaRefId1 = NamedId.Of(DomainId.NewGuid(), "my-ref-schema1"); + protected readonly NamedId schemaRefId2 = NamedId.Of(DomainId.NewGuid(), "my-ref-schema2"); protected readonly IGraphQLService sut; public GraphQLTestBase() @@ -77,7 +77,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL .AddReferences(81, "my-union", Partitioning.Invariant, new ReferencesFieldProperties()) .AddReferences(9, "my-invalid", Partitioning.Invariant, - new ReferencesFieldProperties { SchemaId = Guid.NewGuid() }) + new ReferencesFieldProperties { SchemaId = DomainId.NewGuid() }) .AddGeolocation(10, "my-geolocation", Partitioning.Invariant, new GeolocationFieldProperties()) .AddTags(11, "my-tags", Partitioning.Invariant, @@ -115,7 +115,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL sut = CreateSut(); } - protected IEnrichedContentEntity CreateContent(Guid id, Guid refId, Guid assetId, NamedContentData? data = null) + protected IEnrichedContentEntity CreateContent(DomainId id, DomainId refId, DomainId assetId, NamedContentData? data = null) { var now = SystemClock.Instance.GetCurrentInstant(); @@ -192,7 +192,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return content; } - protected static IEnrichedContentEntity CreateRefContent(NamedId schemaId, Guid id, string field, string value) + protected static IEnrichedContentEntity CreateRefContent(NamedId schemaId, DomainId id, string field, string value) { var now = SystemClock.Instance.GetCurrentInstant(); @@ -219,7 +219,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return content; } - protected static IEnrichedAssetEntity CreateAsset(Guid id) + protected static IEnrichedAssetEntity CreateAsset(DomainId id) { var now = SystemClock.Instance.GetCurrentInstant(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs index f7377694c..20ed64558 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Security.Claims; using System.Threading.Tasks; using FakeItEasy; @@ -26,7 +25,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard public class GuardContentTests { private readonly IContentWorkflow contentWorkflow = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly ClaimsPrincipal user = Mocks.FrontendUser(); private readonly Instant dueTimeInPast = SystemClock.Instance.GetCurrentInstant().Minus(Duration.FromHours(1)); @@ -232,7 +231,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CreateDraft_should_throw_exception_if_not_published() { - var schema = CreateSchema(false); + CreateSchema(false); var content = CreateContent(Status.Draft); var command = new CreateContentDraft(); @@ -243,8 +242,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CreateDraft_should_not_throw_exception() { - var schema = CreateSchema(false); - var content = CreateContent(Status.Published); var command = new CreateContentDraft(); @@ -254,7 +251,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CanDeleteDraft_should_throw_exception_if_no_draft_found() { - var schema = CreateSchema(false); + CreateSchema(false); var content = new ContentState(); var command = new DeleteContentDraft(); @@ -265,8 +262,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CanDeleteDraft_should_not_throw_exception() { - var schema = CreateSchema(false); - var content = CreateDraftContent(Status.Draft); var command = new DeleteContentDraft(); @@ -307,10 +302,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard private ISchemaEntity CreateSchema(bool isSingleton) { - return Mocks.Schema(appId, NamedId.Of(Guid.NewGuid(), "my-schema"), new Schema("schema", isSingleton: isSingleton)); + return Mocks.Schema(appId, NamedId.Of(DomainId.NewGuid(), "my-schema"), new Schema("schema", isSingleton: isSingleton)); } - private ContentState CreateDraftContent(Status status) + private static ContentState CreateDraftContent(Status status) { return new ContentState { @@ -318,7 +313,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard }; } - private ContentState CreateContent(Status status) + private static ContentState CreateContent(Status status) { return new ContentState { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs index fc85d18db..e698dd29d 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs @@ -37,19 +37,19 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb public IContentRepository ContentRepository { get; } - public NamedId[] AppIds { get; } = new[] + public NamedId[] AppIds { get; } = { - NamedId.Of(Guid.Parse("3b5ba909-e5a5-4858-9d0d-df4ff922d452"), "my-app1"), - NamedId.Of(Guid.Parse("4b3672c1-97c6-4e0b-a067-71e9e9a29db9"), "my-app1") + NamedId.Of(DomainId.Create("3b5ba909-e5a5-4858-9d0d-df4ff922d452"), "my-app1"), + NamedId.Of(DomainId.Create("4b3672c1-97c6-4e0b-a067-71e9e9a29db9"), "my-app1") }; - public NamedId[] SchemaIds { get; } = new[] + public NamedId[] SchemaIds { get; } = { - NamedId.Of(Guid.Parse("3b5ba909-e5a5-4858-9d0d-df4ff922d452"), "my-schema1"), - NamedId.Of(Guid.Parse("4b3672c1-97c6-4e0b-a067-71e9e9a29db9"), "my-schema2"), - NamedId.Of(Guid.Parse("76357c9b-0514-4377-9fcc-a632e7ef960d"), "my-schema3"), - NamedId.Of(Guid.Parse("164c451e-e5a8-41f8-8aaf-e4b56603d7e7"), "my-schema4"), - NamedId.Of(Guid.Parse("741e902c-fdfa-41ad-8e5a-b7cb9d6e3d94"), "my-schema5") + NamedId.Of(DomainId.Create("3b5ba909-e5a5-4858-9d0d-df4ff922d452"), "my-schema1"), + NamedId.Of(DomainId.Create("4b3672c1-97c6-4e0b-a067-71e9e9a29db9"), "my-schema2"), + NamedId.Of(DomainId.Create("76357c9b-0514-4377-9fcc-a632e7ef960d"), "my-schema3"), + NamedId.Of(DomainId.Create("164c451e-e5a8-41f8-8aaf-e4b56603d7e7"), "my-schema4"), + NamedId.Of(DomainId.Create("741e902c-fdfa-41ad-8e5a-b7cb9d6e3d94"), "my-schema5") }; public ContentsQueryFixture() @@ -114,7 +114,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb var content = new MongoContentEntity { - Id = Guid.NewGuid(), + DocumentId = DomainId.NewGuid(), AppId = appId, DataByIds = data, IndexedAppId = appId.Id, @@ -143,8 +143,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb { var appProvider = A.Fake(); - A.CallTo(() => appProvider.GetSchemaAsync(A._, A._, false)) - .ReturnsLazily(x => Task.FromResult(CreateSchema(x.GetArgument(0)!, x.GetArgument(1)!))); + A.CallTo(() => appProvider.GetSchemaAsync(A._, A._, false)) + .ReturnsLazily(x => Task.FromResult(CreateSchema(x.GetArgument(0)!, x.GetArgument(1)!))); return appProvider; } @@ -154,7 +154,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb var textIndexer = A.Fake(); A.CallTo(() => textIndexer.SearchAsync(A._, A._, A._, A._)) - .Returns(new List { Guid.NewGuid() }); + .Returns(new List { DomainId.NewGuid() }); return textIndexer; } @@ -166,7 +166,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb BsonJsonConvention.Register(jsonSerializer); } - public Guid RandomAppId() + public DomainId RandomAppId() { return AppIds[random.Next(0, AppIds.Length)].Id; } @@ -176,7 +176,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb return CreateApp(RandomAppId()); } - public Guid RandomSchemaId() + public DomainId RandomSchemaId() { return SchemaIds[random.Next(0, SchemaIds.Length)].Id; } @@ -191,12 +191,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb return random.Next(0, numValues).ToString(); } - private static IAppEntity CreateApp(Guid appId) + private static IAppEntity CreateApp(DomainId appId) { return Mocks.App(NamedId.Of(appId, "my-app")); } - private static ISchemaEntity CreateSchema(Guid appId, Guid schemaId) + private static ISchemaEntity CreateSchema(DomainId appId, DomainId schemaId) { var schemaDef = new Schema("my-schema") diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryTests.cs index abb9142a3..948b4250f 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -32,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb [Fact] public async Task Should_verify_ids() { - var ids = Enumerable.Repeat(0, 50).Select(_ => Guid.NewGuid()).ToHashSet(); + var ids = Enumerable.Repeat(0, 50).Select(_ => DomainId.NewGuid()).ToHashSet(); var contents = await _.ContentRepository.QueryIdsAsync(_.RandomAppId(), ids, SearchScope.Published); @@ -42,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb [Fact] public async Task Should_query_contents_by_ids() { - var ids = Enumerable.Repeat(0, 50).Select(_ => Guid.NewGuid()).ToHashSet(); + var ids = Enumerable.Repeat(0, 50).Select(_ => DomainId.NewGuid()).ToHashSet(); var contents = await _.ContentRepository.QueryAsync(_.RandomApp(), ids, SearchScope.All); @@ -52,7 +51,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb [Fact] public async Task Should_query_contents_by_ids_and_schema() { - var ids = Enumerable.Repeat(0, 50).Select(_ => Guid.NewGuid()).ToHashSet(); + var ids = Enumerable.Repeat(0, 50).Select(_ => DomainId.NewGuid()).ToHashSet(); var contents = await _.ContentRepository.QueryAsync(_.RandomApp(), _.RandomSchema(), ids, SearchScope.All); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/MongoDbQueryTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/MongoDbQueryTests.cs index 72a3d32ae..166b585c8 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/MongoDbQueryTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/MongoDbQueryTests.cs @@ -69,12 +69,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb .Update(new SchemaProperties()); var schema = A.Dummy(); - A.CallTo(() => schema.Id).Returns(Guid.NewGuid()); + A.CallTo(() => schema.Id).Returns(DomainId.NewGuid()); A.CallTo(() => schema.Version).Returns(3); A.CallTo(() => schema.SchemaDef).Returns(schemaDef); var app = A.Dummy(); - A.CallTo(() => app.Id).Returns(Guid.NewGuid()); + A.CallTo(() => app.Id).Returns(DomainId.NewGuid()); A.CallTo(() => app.Version).Returns(3); A.CallTo(() => app.LanguagesConfig).Returns(languagesConfig); } @@ -91,7 +91,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb var id = Guid.NewGuid(); var i = _F(ClrFilter.Eq("id", id)); - var o = _C($"{{ '_id' : '{id}' }}"); + var o = _C($"{{ 'id' : '{id}' }}"); Assert.Equal(o, i); } @@ -99,10 +99,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb [Fact] public void Should_make_query_with_id_string() { - var id = Guid.NewGuid().ToString(); + var id = DomainId.NewGuid().ToString(); var i = _F(ClrFilter.Eq("id", id)); - var o = _C($"{{ '_id' : '{id}' }}"); + var o = _C($"{{ 'id' : '{id}' }}"); Assert.Equal(o, i); } @@ -113,7 +113,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb var id = Guid.NewGuid(); var i = _F(ClrFilter.In("id", new List { id })); - var o = _C($"{{ '_id' : {{ '$in' : ['{id}'] }} }}"); + var o = _C($"{{ 'id' : {{ '$in' : ['{id}'] }} }}"); Assert.Equal(o, i); } @@ -121,10 +121,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb [Fact] public void Should_make_query_with_id_string_list() { - var id = Guid.NewGuid().ToString(); + var id = DomainId.NewGuid().ToString(); var i = _F(ClrFilter.In("id", new List { id })); - var o = _C($"{{ '_id' : {{ '$in' : ['{id}'] }} }}"); + var o = _C($"{{ 'id' : {{ '$in' : ['{id}'] }} }}"); Assert.Equal(o, i); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs index c40297db7..b1c9d258a 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs @@ -23,8 +23,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries private readonly IContentQueryService contentQuery = A.Fake(); private readonly ISchemaEntity schema; private readonly Context requestContext; - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private sealed class ResolveSchema : IContentEnricherStep { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentLoaderTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentLoaderTests.cs index 3e6657b55..8e59d9636 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentLoaderTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentLoaderTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Orleans; @@ -19,12 +18,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { private readonly IGrainFactory grainFactory = A.Fake(); private readonly IContentGrain grain = A.Fake(); - private readonly Guid id = Guid.NewGuid(); + private readonly DomainId appId = DomainId.NewGuid(); + private readonly DomainId id = DomainId.NewGuid(); private readonly ContentLoader sut; public ContentLoaderTests() { - A.CallTo(() => grainFactory.GetGrain(id, null)) + var key = DomainId.Combine(appId, id).ToString(); + + A.CallTo(() => grainFactory.GetGrain(key, null)) .Returns(grain); sut = new ContentLoader(grainFactory); @@ -36,7 +38,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries A.CallTo(() => grain.GetStateAsync(10)) .Returns(J.Of(null!)); - await Assert.ThrowsAsync(() => sut.GetAsync(id, 10)); + await Assert.ThrowsAsync(() => sut.GetAsync(appId, id, 10)); } [Fact] @@ -47,7 +49,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries A.CallTo(() => grain.GetStateAsync(10)) .Returns(J.Of(content)); - await Assert.ThrowsAsync(() => sut.GetAsync(id, 10)); + await Assert.ThrowsAsync(() => sut.GetAsync(appId, id, 10)); } [Fact] @@ -58,7 +60,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries A.CallTo(() => grain.GetStateAsync(10)) .Returns(J.Of(content)); - await Assert.ThrowsAsync(() => sut.GetAsync(id, 10)); + await Assert.ThrowsAsync(() => sut.GetAsync(appId, id, 10)); } [Fact] @@ -69,7 +71,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries A.CallTo(() => grain.GetStateAsync(EtagVersion.Any)) .Returns(J.Of(content)); - await sut.GetAsync(id, EtagVersion.Any); + await sut.GetAsync(appId, id, EtagVersion.Any); } [Fact] @@ -80,7 +82,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries A.CallTo(() => grain.GetStateAsync(10)) .Returns(J.Of(content)); - var result = await sut.GetAsync(id, 10); + var result = await sut.GetAsync(appId, id, 10); Assert.Same(content, result); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs index 8276c57c4..c06a30db4 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; @@ -24,8 +23,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries public class ContentQueryParserTests { private readonly ISchemaEntity schema; - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly Context requestContext; private readonly ContentQueryParser sut; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryServiceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryServiceTests.cs index 990d923ee..b2171f0c6 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryServiceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryServiceTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; @@ -35,9 +34,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries private readonly IContentRepository contentRepository = A.Fake(); private readonly IContentLoader contentVersionLoader = A.Fake(); private readonly ISchemaEntity schema; - private readonly Guid contentId = Guid.NewGuid(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly DomainId contentId = DomainId.NewGuid(); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly NamedContentData contentData = new NamedContentData(); private readonly NamedContentData contentTransformed = new NamedContentData(); private readonly ContentQueryParser queryParser = A.Fake(); @@ -102,7 +101,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var ctx = CreateContext(isFrontend: false, allowSchema: true); - A.CallTo(() => appProvider.GetSchemaAsync(A._, A._)) + A.CallTo(() => appProvider.GetSchemaAsync(A._, A._)) .Returns((ISchemaEntity?)null); await Assert.ThrowsAsync(() => sut.GetSchemaOrThrowAsync(ctx, schemaId.Name)); @@ -159,7 +158,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries var content = CreateContent(contentId); - A.CallTo(() => contentVersionLoader.GetAsync(contentId, 13)) + A.CallTo(() => contentVersionLoader.GetAsync(appId.Id, contentId, 13)) .Returns(content); var result = await sut.FindContentAsync(ctx, schemaId.Name, contentId, 13); @@ -205,9 +204,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var ctx = CreateContext(isFrontend: false, allowSchema: false); - var ids = Enumerable.Range(0, 5).Select(x => Guid.NewGuid()).ToList(); + var ids = Enumerable.Range(0, 5).Select(x => DomainId.NewGuid()).ToList(); - A.CallTo(() => contentRepository.QueryAsync(ctx.App, A>._, SearchScope.All)) + A.CallTo(() => contentRepository.QueryAsync(ctx.App, A>._, SearchScope.All)) .Returns(ids.Select(x => (CreateContent(x), schema)).ToList()); var result = await sut.QueryAsync(ctx, ids); @@ -226,9 +225,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries CreateContext(isFrontend: isFrontend == 1, allowSchema: true) .WithUnpublished(unpublished == 1); - var ids = Enumerable.Range(0, 5).Select(x => Guid.NewGuid()).ToList(); + var ids = Enumerable.Range(0, 5).Select(x => DomainId.NewGuid()).ToList(); - A.CallTo(() => contentRepository.QueryAsync(ctx.App, A>._, scope)) + A.CallTo(() => contentRepository.QueryAsync(ctx.App, A>._, scope)) .Returns(ids.Select(x => (CreateContent(x), schema)).ToList()); var result = await sut.QueryAsync(ctx, ids); @@ -241,11 +240,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var ctx = CreateContext(isFrontend: false, allowSchema: true); - var result = await sut.QueryAsync(ctx, new List()); + var result = await sut.QueryAsync(ctx, new List()); Assert.Empty(result); - A.CallTo(() => contentRepository.QueryAsync(ctx.App, A>._, A._)) + A.CallTo(() => contentRepository.QueryAsync(ctx.App, A>._, A._)) .MustNotHaveHappened(); } @@ -280,7 +279,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries return new Context(claimsPrincipal, Mocks.App(appId)); } - private IContentEntity CreateContent(Guid id) + private IContentEntity CreateContent(DomainId id) { var content = new ContentEntity { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs index 69a02827c..ca6f55c1b 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -30,8 +29,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly IAssetRepository assetRepository = A.Fake(); private readonly IContentRepository contentRepository = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly ProvideSchema schemaProvider; private readonly ConvertData sut; @@ -65,8 +64,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries [Fact] public async Task Should_cleanup_references() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); var source = BuildTestData(id1, id2); @@ -87,11 +86,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries JsonValue.Object() .Add("nested", JsonValue.Array(id2))))); - A.CallTo(() => assetRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2))) - .Returns(new List { id2 }); + A.CallTo(() => assetRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2))) + .Returns(new List { id2 }); - A.CallTo(() => contentRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2), SearchScope.All)) - .Returns(new List<(Guid, Guid)> { (id2, id2) }); + A.CallTo(() => contentRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2), SearchScope.All)) + .Returns(new List<(DomainId, DomainId)> { (id2, id2) }); var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)); @@ -103,8 +102,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries [Fact] public async Task Should_cleanup_references_when_everything_deleted() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); var source = BuildTestData(id1, id2); @@ -125,11 +124,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries JsonValue.Object() .Add("nested", JsonValue.Array())))); - A.CallTo(() => assetRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2))) - .Returns(new List()); + A.CallTo(() => assetRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2))) + .Returns(new List()); - A.CallTo(() => contentRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2), SearchScope.All)) - .Returns(new List<(Guid, Guid)>()); + A.CallTo(() => contentRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2), SearchScope.All)) + .Returns(new List<(DomainId, DomainId)>()); var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)); @@ -138,7 +137,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries Assert.Equal(expected, content.Data); } - private static NamedContentData BuildTestData(Guid id1, Guid id2) + private static NamedContentData BuildTestData(DomainId id1, DomainId id2) { return new NamedContentData() .AddField("references", diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs index 29232686b..e780b1be3 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs @@ -24,8 +24,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries private readonly ISchemaEntity schema; private readonly IRequestCache requestCache = A.Fake(); private readonly Context requestContext; - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly ProvideSchema schemaProvider; private readonly EnrichForCaching sut; @@ -69,19 +69,19 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries await sut.EnrichAsync(requestContext, Enumerable.Repeat(content, 1), schemaProvider); - A.CallTo(() => requestCache.AddDependency(content.Id, content.Version)) + A.CallTo(() => requestCache.AddDependency(content.UniqueId, content.Version)) .MustHaveHappened(); - A.CallTo(() => requestCache.AddDependency(schema.Id, schema.Version)) + A.CallTo(() => requestCache.AddDependency(schema.UniqueId, schema.Version)) .MustHaveHappened(); - A.CallTo(() => requestCache.AddDependency(requestContext.App.Id, requestContext.App.Version)) + A.CallTo(() => requestCache.AddDependency(requestContext.App.UniqueId, requestContext.App.Version)) .MustHaveHappened(); } private ContentEntity CreateContent() { - return new ContentEntity { Id = Guid.NewGuid(), SchemaId = schemaId, Version = 13 }; + return new ContentEntity { AppId = appId, Id = DomainId.NewGuid(), SchemaId = schemaId, Version = 13 }; } } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs index af47861f3..74536301d 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Linq; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Contents.Queries.Steps; @@ -19,8 +18,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries public class EnrichWithSchemaTests { private readonly ISchemaEntity schema; - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly ProvideSchema schemaProvider; private readonly EnrichWithSchema sut; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs index 2a284f778..bd213f07c 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Linq; using System.Threading.Tasks; using FakeItEasy; @@ -21,8 +20,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { private readonly IContentWorkflow contentWorkflow = A.Fake(); private readonly Context requestContext; - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly RefToken user = new RefToken(RefTokenType.Subject, "me"); private readonly EnrichWithWorkflows sut; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/FilterTagTransformerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/FilterTagTransformerTests.cs index 803e2b228..c912cfd35 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/FilterTagTransformerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/FilterTagTransformerTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using FakeItEasy; using Squidex.Domain.Apps.Core; @@ -23,8 +22,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { private readonly ITagService tagService = A.Fake(); private readonly ISchemaEntity schema; - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); public FilterTagTransformerTests() { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs index 959711cce..7f345d431 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Linq; using System.Threading.Tasks; using FakeItEasy; @@ -29,8 +28,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries private readonly IAssetQueryService assetQuery = A.Fake(); private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly IRequestCache requestCache = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly ProvideSchema schemaProvider; private readonly Context requestContext; private readonly ResolveAssets sut; @@ -55,8 +54,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries }) .SetFieldsInLists("asset1", "asset2"); - A.CallTo(() => urlGenerator.AssetContent(A._)) - .ReturnsLazily(ctx => $"url/to/{ctx.GetArgument(0)}"); + A.CallTo(() => urlGenerator.AssetContent(appId, A._)) + .ReturnsLazily(ctx => $"url/to/{ctx.GetArgument(1)}"); schemaProvider = x => { @@ -76,8 +75,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries [Fact] public async Task Should_add_assets_id_and_versions_as_dependency() { - var document1 = CreateAsset(Guid.NewGuid(), 3, AssetType.Unknown, "Document1.docx"); - var document2 = CreateAsset(Guid.NewGuid(), 4, AssetType.Unknown, "Document2.docx"); + var document1 = CreateAsset(DomainId.NewGuid(), 3, AssetType.Unknown, "Document1.docx"); + var document2 = CreateAsset(DomainId.NewGuid(), 4, AssetType.Unknown, "Document2.docx"); var contents = new[] { @@ -94,21 +93,21 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries await sut.EnrichAsync(requestContext, contents, schemaProvider); - A.CallTo(() => requestCache.AddDependency(document1.Id, document1.Version)) + A.CallTo(() => requestCache.AddDependency(document1.UniqueId, document1.Version)) .MustHaveHappened(); - A.CallTo(() => requestCache.AddDependency(document2.Id, document2.Version)) + A.CallTo(() => requestCache.AddDependency(document2.UniqueId, document2.Version)) .MustHaveHappened(); } [Fact] public async Task Should_enrich_with_asset_urls() { - var image1 = CreateAsset(Guid.NewGuid(), 1, AssetType.Image, "Image1.png"); - var image2 = CreateAsset(Guid.NewGuid(), 2, AssetType.Image, "Image2.png"); + var image1 = CreateAsset(DomainId.NewGuid(), 1, AssetType.Image, "Image1.png"); + var image2 = CreateAsset(DomainId.NewGuid(), 2, AssetType.Image, "Image2.png"); - var document1 = CreateAsset(Guid.NewGuid(), 3, AssetType.Unknown, "Document1.png"); - var document2 = CreateAsset(Guid.NewGuid(), 4, AssetType.Unknown, "Document2.png"); + var document1 = CreateAsset(DomainId.NewGuid(), 3, AssetType.Unknown, "Document1.png"); + var document2 = CreateAsset(DomainId.NewGuid(), 4, AssetType.Unknown, "Document2.png"); var contents = new[] { @@ -151,7 +150,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var contents = new[] { - CreateContent(new[] { Guid.NewGuid() }, new Guid[0]) + CreateContent(new[] { DomainId.NewGuid() }, new DomainId[0]) }; var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)); @@ -169,7 +168,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var contents = new[] { - CreateContent(new[] { Guid.NewGuid() }, new Guid[0]) + CreateContent(new[] { DomainId.NewGuid() }, new DomainId[0]) }; var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)).WithoutContentEnrichment(true); @@ -187,7 +186,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var contents = new[] { - CreateContent(new Guid[0], new Guid[0]) + CreateContent(new DomainId[0], new DomainId[0]) }; await sut.EnrichAsync(requestContext, contents, schemaProvider); @@ -201,12 +200,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries [Fact] public async Task Should_only_query_first_assets() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid(); + var id2 = DomainId.NewGuid(); var contents = new[] { - CreateContent(new[] { id1, id2 }, new Guid[0]) + CreateContent(new[] { id1, id2 }, new DomainId[0]) }; await sut.EnrichAsync(requestContext, contents, schemaProvider); @@ -217,7 +216,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries .MustHaveHappened(); } - private ContentEntity CreateContent(Guid[] assets1, Guid[] assets2) + private ContentEntity CreateContent(DomainId[] assets1, DomainId[] assets2) { return new ContentEntity { @@ -233,9 +232,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries }; } - private static IEnrichedAssetEntity CreateAsset(Guid id, int version, AssetType type, string fileName) + private IEnrichedAssetEntity CreateAsset(DomainId id, int version, AssetType type, string fileName) { - return new AssetEntity { Id = id, Type = type, Version = version, FileName = fileName }; + return new AssetEntity { AppId = appId, Id = id, Type = type, Version = version, FileName = fileName }; } } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs index 36f3fd9b0..075285921 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs @@ -27,10 +27,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { private readonly IContentQueryService contentQuery = A.Fake(); private readonly IRequestCache requestCache = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId refSchemaId1 = NamedId.Of(Guid.NewGuid(), "my-ref1"); - private readonly NamedId refSchemaId2 = NamedId.Of(Guid.NewGuid(), "my-ref2"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId refSchemaId1 = NamedId.Of(DomainId.NewGuid(), "my-ref1"); + private readonly NamedId refSchemaId2 = NamedId.Of(DomainId.NewGuid(), "my-ref2"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly ProvideSchema schemaProvider; private readonly Context requestContext; private readonly ResolveReferences sut; @@ -91,10 +91,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries [Fact] public async Task Should_add_referenced_id_and__as_dependency() { - var ref1_1 = CreateRefContent(Guid.NewGuid(), 1, "ref1_1", 13, refSchemaId1); - var ref1_2 = CreateRefContent(Guid.NewGuid(), 2, "ref1_2", 17, refSchemaId1); - var ref2_1 = CreateRefContent(Guid.NewGuid(), 3, "ref2_1", 23, refSchemaId2); - var ref2_2 = CreateRefContent(Guid.NewGuid(), 4, "ref2_2", 29, refSchemaId2); + var ref1_1 = CreateRefContent(DomainId.NewGuid(), 1, "ref1_1", 13, refSchemaId1); + var ref1_2 = CreateRefContent(DomainId.NewGuid(), 2, "ref1_2", 17, refSchemaId1); + var ref2_1 = CreateRefContent(DomainId.NewGuid(), 3, "ref2_1", 23, refSchemaId2); + var ref2_2 = CreateRefContent(DomainId.NewGuid(), 4, "ref2_2", 29, refSchemaId2); var contents = new[] { @@ -102,39 +102,37 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries CreateContent(new[] { ref1_2.Id }, new[] { ref2_2.Id }) }; - A.CallTo(() => contentQuery.QueryAsync(A._, A>.That.Matches(x => x.Count == 4))) + A.CallTo(() => contentQuery.QueryAsync(A._, A>.That.Matches(x => x.Count == 4))) .Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2)); await sut.EnrichAsync(requestContext, contents, schemaProvider); - var enriched1 = contents[0]; - - A.CallTo(() => requestCache.AddDependency(refSchemaId1.Id, 0)) + A.CallTo(() => requestCache.AddDependency(DomainId.Combine(appId, refSchemaId1.Id), 0)) .MustHaveHappened(); - A.CallTo(() => requestCache.AddDependency(refSchemaId2.Id, 0)) + A.CallTo(() => requestCache.AddDependency(DomainId.Combine(appId, refSchemaId2.Id), 0)) .MustHaveHappened(); - A.CallTo(() => requestCache.AddDependency(ref1_1.Id, ref1_1.Version)) + A.CallTo(() => requestCache.AddDependency(ref1_1.UniqueId, ref1_1.Version)) .MustHaveHappened(); - A.CallTo(() => requestCache.AddDependency(ref2_1.Id, ref2_1.Version)) + A.CallTo(() => requestCache.AddDependency(ref2_1.UniqueId, ref2_1.Version)) .MustHaveHappened(); - A.CallTo(() => requestCache.AddDependency(ref1_2.Id, ref1_2.Version)) + A.CallTo(() => requestCache.AddDependency(ref1_2.UniqueId, ref1_2.Version)) .MustHaveHappened(); - A.CallTo(() => requestCache.AddDependency(ref2_2.Id, ref2_2.Version)) + A.CallTo(() => requestCache.AddDependency(ref2_2.UniqueId, ref2_2.Version)) .MustHaveHappened(); } [Fact] public async Task Should_enrich_with_reference_data() { - var ref1_1 = CreateRefContent(Guid.NewGuid(), 1, "ref1_1", 13, refSchemaId1); - var ref1_2 = CreateRefContent(Guid.NewGuid(), 2, "ref1_2", 17, refSchemaId1); - var ref2_1 = CreateRefContent(Guid.NewGuid(), 3, "ref2_1", 23, refSchemaId2); - var ref2_2 = CreateRefContent(Guid.NewGuid(), 3, "ref2_2", 29, refSchemaId2); + var ref1_1 = CreateRefContent(DomainId.NewGuid(), 1, "ref1_1", 13, refSchemaId1); + var ref1_2 = CreateRefContent(DomainId.NewGuid(), 2, "ref1_2", 17, refSchemaId1); + var ref2_1 = CreateRefContent(DomainId.NewGuid(), 3, "ref2_1", 23, refSchemaId2); + var ref2_2 = CreateRefContent(DomainId.NewGuid(), 3, "ref2_2", 29, refSchemaId2); var contents = new[] { @@ -142,7 +140,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries CreateContent(new[] { ref1_2.Id }, new[] { ref2_2.Id }) }; - A.CallTo(() => contentQuery.QueryAsync(A.That.Matches(x => !x.ShouldEnrichContent()), A>.That.Matches(x => x.Count == 4))) + A.CallTo(() => contentQuery.QueryAsync(A.That.Matches(x => !x.ShouldEnrichContent()), A>.That.Matches(x => x.Count == 4))) .Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2)); await sut.EnrichAsync(requestContext, contents, schemaProvider); @@ -183,10 +181,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries [Fact] public async Task Should_not_enrich_when_content_has_more_items() { - var ref1_1 = CreateRefContent(Guid.NewGuid(), 1, "ref1_1", 13, refSchemaId1); - var ref1_2 = CreateRefContent(Guid.NewGuid(), 2, "ref1_2", 17, refSchemaId1); - var ref2_1 = CreateRefContent(Guid.NewGuid(), 3, "ref2_1", 23, refSchemaId2); - var ref2_2 = CreateRefContent(Guid.NewGuid(), 4, "ref2_2", 29, refSchemaId2); + var ref1_1 = CreateRefContent(DomainId.NewGuid(), 1, "ref1_1", 13, refSchemaId1); + var ref1_2 = CreateRefContent(DomainId.NewGuid(), 2, "ref1_2", 17, refSchemaId1); + var ref2_1 = CreateRefContent(DomainId.NewGuid(), 3, "ref2_1", 23, refSchemaId2); + var ref2_2 = CreateRefContent(DomainId.NewGuid(), 4, "ref2_2", 29, refSchemaId2); var contents = new[] { @@ -194,7 +192,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries CreateContent(new[] { ref1_2.Id }, new[] { ref2_1.Id, ref2_2.Id }) }; - A.CallTo(() => contentQuery.QueryAsync(A.That.Matches(x => !x.ShouldEnrichContent()), A>.That.Matches(x => x.Count == 4))) + A.CallTo(() => contentQuery.QueryAsync(A.That.Matches(x => !x.ShouldEnrichContent()), A>.That.Matches(x => x.Count == 4))) .Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2)); await sut.EnrichAsync(requestContext, contents, schemaProvider); @@ -237,7 +235,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var contents = new[] { - CreateContent(new[] { Guid.NewGuid() }, new Guid[0]) + CreateContent(new[] { DomainId.NewGuid() }, new DomainId[0]) }; var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)); @@ -246,7 +244,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries Assert.Null(contents[0].ReferenceData); - A.CallTo(() => contentQuery.QueryAsync(A._, A>._)) + A.CallTo(() => contentQuery.QueryAsync(A._, A>._)) .MustNotHaveHappened(); } @@ -255,7 +253,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var contents = new[] { - CreateContent(new[] { Guid.NewGuid() }, new Guid[0]) + CreateContent(new[] { DomainId.NewGuid() }, new DomainId[0]) }; var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)).WithoutContentEnrichment(true); @@ -264,7 +262,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries Assert.Null(contents[0].ReferenceData); - A.CallTo(() => contentQuery.QueryAsync(A._, A>._)) + A.CallTo(() => contentQuery.QueryAsync(A._, A>._)) .MustNotHaveHappened(); } @@ -273,21 +271,22 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var contents = new[] { - CreateContent(new Guid[0], new Guid[0]) + CreateContent(new DomainId[0], new DomainId[0]) }; await sut.EnrichAsync(requestContext, contents, schemaProvider); Assert.NotNull(contents[0].ReferenceData); - A.CallTo(() => contentQuery.QueryAsync(A._, A>._)) + A.CallTo(() => contentQuery.QueryAsync(A._, A>._)) .MustNotHaveHappened(); } - private ContentEntity CreateContent(Guid[] ref1, Guid[] ref2) + private ContentEntity CreateContent(DomainId[] ref1, DomainId[] ref2) { return new ContentEntity { + Id = DomainId.NewGuid(), Data = new NamedContentData() .AddField("ref1", @@ -296,11 +295,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries .AddField("ref2", new ContentFieldData() .AddJsonValue("iv", JsonValue.Array(ref2.Select(x => x.ToString()).ToArray()))), - SchemaId = schemaId + SchemaId = schemaId, AppId = appId, + Version = 0 }; } - private static IEnrichedContentEntity CreateRefContent(Guid id, int version, string name, int number, NamedId schemaId) + private IEnrichedContentEntity CreateRefContent(DomainId id, int version, string name, int number, NamedId refSchemaId) { return new ContentEntity { @@ -313,7 +313,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries .AddField("number", new ContentFieldData() .AddValue("iv", number)), - SchemaId = schemaId, + SchemaId = refSchemaId, AppId = appId, Version = version }; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs index 3888b4528..9c1847069 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Core.Contents; @@ -22,9 +21,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries public class ScriptContentTests { private readonly IScriptEngine scriptEngine = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); - private readonly NamedId schemaWithScriptId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); + private readonly NamedId schemaWithScriptId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly ProvideSchema schemaProvider; private readonly ScriptContent sut; @@ -110,7 +109,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries .MustHaveHappened(); } - private ScriptOptions ScriptOptions() + private static ScriptOptions ScriptOptions() { return A.That.Matches(x => x.AsContext); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferenceFluidExtensionTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferenceFluidExtensionTests.cs index a02f7c6b6..3e168f7c3 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferenceFluidExtensionTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferenceFluidExtensionTests.cs @@ -23,7 +23,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { private readonly IContentQueryService contentQuery = A.Fake(); private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly FluidTemplateEngine sut; public ReferenceFluidExtensionTests() @@ -42,9 +42,9 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public async Task Should_resolve_references_in_loop() { - var referenceId1 = Guid.NewGuid(); + var referenceId1 = DomainId.NewGuid(); var reference1 = CreateReference(referenceId1, 1); - var referenceId2 = Guid.NewGuid(); + var referenceId2 = DomainId.NewGuid(); var reference2 = CreateReference(referenceId1, 2); var @event = new EnrichedContentEvent @@ -57,10 +57,10 @@ namespace Squidex.Domain.Apps.Entities.Contents AppId = appId }; - A.CallTo(() => contentQuery.QueryAsync(A._, A>.That.Contains(referenceId1))) + A.CallTo(() => contentQuery.QueryAsync(A._, A>.That.Contains(referenceId1))) .Returns(ResultList.CreateFrom(1, reference1)); - A.CallTo(() => contentQuery.QueryAsync(A._, A>.That.Contains(referenceId2))) + A.CallTo(() => contentQuery.QueryAsync(A._, A>.That.Contains(referenceId2))) .Returns(ResultList.CreateFrom(1, reference2)); var vars = new TemplateVars @@ -85,7 +85,7 @@ namespace Squidex.Domain.Apps.Entities.Contents Assert.Equal(expected, result); } - private IEnrichedContentEntity CreateReference(Guid referenceId, int index) + private static IEnrichedContentEntity CreateReference(DomainId referenceId, int index) { return new ContentEntity { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/TestData/FakeUrlGenerator.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/TestData/FakeUrlGenerator.cs index ef8d64e00..bfd4845ea 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/TestData/FakeUrlGenerator.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/TestData/FakeUrlGenerator.cs @@ -16,107 +16,107 @@ namespace Squidex.Domain.Apps.Entities.Contents.TestData { public bool CanGenerateAssetSourceUrl { get; } = true; - public string? AssetThumbnail(Guid assetId, AssetType assetType) + public string? AssetThumbnail(NamedId appId, DomainId assetId, AssetType assetType) { return $"assets/{assetId}?width=100"; } - public string? AssetSource(Guid assetId, long fileVersion) + public string? AssetSource(NamedId appId, DomainId assetId, long fileVersion) { return $"assets/source/{assetId}"; } - public string AssetContent(Guid assetId) + public string AssetContent(NamedId appId, DomainId assetId) { return $"assets/{assetId}"; } - public string ContentUI(NamedId appId, NamedId schemaId, Guid contentId) + public string ContentUI(NamedId appId, NamedId schemaId, DomainId contentId) { return $"contents/{schemaId.Name}/{contentId}"; } - public string AppSettingsUI(NamedId appId) + public string AppSettingsUI(NamedId appId) { throw new NotSupportedException(); } - public string AssetsUI(NamedId appId) + public string AssetsUI(NamedId appId) { throw new NotSupportedException(); } - public string AssetsUI(NamedId appId, string? query = null) + public string AssetsUI(NamedId appId, string? query = null) { throw new NotSupportedException(); } - public string BackupsUI(NamedId appId) + public string BackupsUI(NamedId appId) { throw new NotSupportedException(); } - public string ClientsUI(NamedId appId) + public string ClientsUI(NamedId appId) { throw new NotSupportedException(); } - public string ContentsUI(NamedId appId) + public string ContentsUI(NamedId appId) { throw new NotSupportedException(); } - public string ContentsUI(NamedId appId, NamedId schemaId) + public string ContentsUI(NamedId appId, NamedId schemaId) { throw new NotSupportedException(); } - public string ContributorsUI(NamedId appId) + public string ContributorsUI(NamedId appId) { throw new NotSupportedException(); } - public string DashboardUI(NamedId appId) + public string DashboardUI(NamedId appId) { throw new NotSupportedException(); } - public string LanguagesUI(NamedId appId) + public string LanguagesUI(NamedId appId) { throw new NotSupportedException(); } - public string PatternsUI(NamedId appId) + public string PatternsUI(NamedId appId) { throw new NotSupportedException(); } - public string PlansUI(NamedId appId) + public string PlansUI(NamedId appId) { throw new NotSupportedException(); } - public string RolesUI(NamedId appId) + public string RolesUI(NamedId appId) { throw new NotSupportedException(); } - public string RulesUI(NamedId appId) + public string RulesUI(NamedId appId) { throw new NotSupportedException(); } - public string SchemasUI(NamedId appId) + public string SchemasUI(NamedId appId) { throw new NotSupportedException(); } - public string SchemaUI(NamedId appId, NamedId schemaId) + public string SchemaUI(NamedId appId, NamedId schemaId) { throw new NotSupportedException(); } - public string WorkflowsUI(NamedId appId) + public string WorkflowsUI(NamedId appId) { throw new NotSupportedException(); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/CachingTextIndexerStateTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/CachingTextIndexerStateTests.cs index 0ea5d3574..69021f5cd 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/CachingTextIndexerStateTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/CachingTextIndexerStateTests.cs @@ -5,10 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Entities.Contents.Text.State; +using Squidex.Infrastructure; using Xunit; namespace Squidex.Domain.Apps.Entities.Contents.Text @@ -16,6 +16,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text public class CachingTextIndexerStateTests { private readonly ITextIndexerState inner = A.Fake(); + private readonly DomainId appId = DomainId.NewGuid(); + private readonly DomainId contentId = DomainId.NewGuid(); private readonly CachingTextIndexerState sut; public CachingTextIndexerStateTests() @@ -26,65 +28,60 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text [Fact] public async Task Should_retrieve_from_inner_when_not_cached() { - var contentId = Guid.NewGuid(); - var state = new TextContentState { ContentId = contentId }; - A.CallTo(() => inner.GetAsync(contentId)) + A.CallTo(() => inner.GetAsync(appId, contentId)) .Returns(state); - var found1 = await sut.GetAsync(contentId); - var found2 = await sut.GetAsync(contentId); + var found1 = await sut.GetAsync(appId, contentId); + var found2 = await sut.GetAsync(appId, contentId); Assert.Same(state, found1); Assert.Same(state, found2); - A.CallTo(() => inner.GetAsync(contentId)) + A.CallTo(() => inner.GetAsync(appId, contentId)) .MustHaveHappenedOnceExactly(); } [Fact] public async Task Should_not_retrieve_from_inner_when_cached() { - var contentId = Guid.NewGuid(); - var state = new TextContentState { ContentId = contentId }; - await sut.SetAsync(state); + await sut.SetAsync(appId, state); - var found1 = await sut.GetAsync(contentId); - var found2 = await sut.GetAsync(contentId); + var found1 = await sut.GetAsync(appId, contentId); + var found2 = await sut.GetAsync(appId, contentId); Assert.Same(state, found1); Assert.Same(state, found2); - A.CallTo(() => inner.SetAsync(state)) + A.CallTo(() => inner.SetAsync(appId, state)) .MustHaveHappenedOnceExactly(); - A.CallTo(() => inner.GetAsync(contentId)) + A.CallTo(() => inner.GetAsync(appId, contentId)) .MustNotHaveHappened(); } [Fact] public async Task Should_not_retrieve_from_inner_when_removed() { - var contentId = Guid.NewGuid(); - var state = new TextContentState { ContentId = contentId }; - await sut.SetAsync(state); - await sut.RemoveAsync(contentId); + await sut.SetAsync(appId, state); + + await sut.RemoveAsync(appId, contentId); - var found1 = await sut.GetAsync(contentId); - var found2 = await sut.GetAsync(contentId); + var found1 = await sut.GetAsync(appId, contentId); + var found2 = await sut.GetAsync(appId, contentId); Assert.Null(found1); Assert.Null(found2); - A.CallTo(() => inner.RemoveAsync(contentId)) + A.CallTo(() => inner.RemoveAsync(appId, contentId)) .MustHaveHappenedOnceExactly(); - A.CallTo(() => inner.GetAsync(contentId)) + A.CallTo(() => inner.GetAsync(appId, contentId)) .MustNotHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/IIndexerFactory.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/IIndexerFactory.cs index c690164d8..569467d58 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/IIndexerFactory.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/IIndexerFactory.cs @@ -5,14 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text { public interface IIndexerFactory { - Task CreateAsync(Guid schemaId); + Task CreateAsync(DomainId schemaId); Task CleanupAsync(); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/LuceneIndexFactory.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/LuceneIndexFactory.cs index 02cfa9ce4..979f11a77 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/LuceneIndexFactory.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/LuceneIndexFactory.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Orleans; using Squidex.Domain.Apps.Entities.Contents.Text.Lucene; +using Squidex.Infrastructure; using Squidex.Infrastructure.Log; namespace Squidex.Domain.Apps.Entities.Contents.Text @@ -24,17 +24,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text { this.storage = storage; - A.CallTo(() => grainFactory.GetGrain(A._, null)) + A.CallTo(() => grainFactory.GetGrain(A._, null)) .ReturnsLazily(() => grain); } - public async Task CreateAsync(Guid schemaId) + public async Task CreateAsync(DomainId schemaId) { var indexManager = new IndexManager(storage, A.Fake()); grain = new LuceneTextIndexGrain(indexManager); - await grain.ActivateAsync(schemaId); + await grain.ActivateAsync(schemaId.ToString()); return new LuceneTextIndex(grainFactory, indexManager); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs index e67d9d331..e6da5e97f 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -27,10 +26,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text { public abstract class TextIndexerTestsBase { - private readonly List ids1 = new List { Guid.NewGuid() }; - private readonly List ids2 = new List { Guid.NewGuid() }; - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly List ids1 = new List { DomainId.NewGuid() }; + private readonly List ids2 = new List { DomainId.NewGuid() }; + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly IAppEntity app; private delegate Task IndexOperation(TextIndexingProcess process); @@ -42,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text protected TextIndexerTestsBase() { app = - Mocks.App(NamedId.Of(Guid.NewGuid(), "my-app"), + Mocks.App(NamedId.Of(DomainId.NewGuid(), "my-app"), Language.DE, Language.EN); } @@ -312,7 +311,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text ); } - private IndexOperation Create(Guid id, string language, string text) + private IndexOperation Create(DomainId id, string language, string text) { var data = new NamedContentData() @@ -323,7 +322,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text return Op(id, new ContentCreated { Data = data }); } - private IndexOperation Update(Guid id, string language, string text) + private IndexOperation Update(DomainId id, string language, string text) { var data = new NamedContentData() @@ -334,7 +333,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text return Op(id, new ContentUpdated { Data = data }); } - private IndexOperation CreateDraftWithData(Guid id, string language, string text) + private IndexOperation CreateDraftWithData(DomainId id, string language, string text) { var data = new NamedContentData() @@ -345,32 +344,32 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text return Op(id, new ContentDraftCreated { MigratedData = data }); } - private IndexOperation CreateDraft(Guid id) + private IndexOperation CreateDraft(DomainId id) { return Op(id, new ContentDraftCreated()); } - private IndexOperation Publish(Guid id) + private IndexOperation Publish(DomainId id) { return Op(id, new ContentStatusChanged { Status = Status.Published }); } - private IndexOperation Unpublish( Guid id) + private IndexOperation Unpublish( DomainId id) { return Op(id, new ContentStatusChanged { Status = Status.Draft }); } - private IndexOperation DeleteDraft(Guid id) + private IndexOperation DeleteDraft(DomainId id) { return Op(id, new ContentDraftDeleted()); } - private IndexOperation Delete(Guid id) + private IndexOperation Delete(DomainId id) { return Op(id, new ContentDeleted()); } - private IndexOperation Op(Guid id, ContentEvent contentEvent) + private IndexOperation Op(DomainId id, ContentEvent contentEvent) { contentEvent.ContentId = id; contentEvent.AppId = appId; @@ -379,7 +378,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text return p => p.On(Envelope.Create(contentEvent)); } - private IndexOperation Search(List? expected, string text, SearchScope target = SearchScope.All) + private IndexOperation Search(List? expected, string text, SearchScope target = SearchScope.All) { return async p => { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/BackupRulesTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/BackupRulesTests.cs index 13f08d749..df5115263 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/BackupRulesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/BackupRulesTests.cs @@ -37,13 +37,13 @@ namespace Squidex.Domain.Apps.Entities.Rules [Fact] public async Task Should_restore_indices_for_all_non_deleted_rules() { - var appId = Guid.NewGuid(); + var appId = DomainId.NewGuid(); - var ruleId1 = Guid.NewGuid(); - var ruleId2 = Guid.NewGuid(); - var ruleId3 = Guid.NewGuid(); + var ruleId1 = DomainId.NewGuid(); + var ruleId2 = DomainId.NewGuid(); + var ruleId3 = DomainId.NewGuid(); - var context = new RestoreContext(appId, new UserMapping(new RefToken(RefTokenType.Subject, "123")), A.Fake()); + var context = new RestoreContext(appId, new UserMapping(new RefToken(RefTokenType.Subject, "123")), A.Fake(), DomainId.NewGuid()); await sut.RestoreEventAsync(Envelope.Create(new RuleCreated { @@ -65,14 +65,14 @@ namespace Squidex.Domain.Apps.Entities.Rules RuleId = ruleId3 }), context); - HashSet? newIndex = null; + HashSet? newIndex = null; - A.CallTo(() => index.RebuildAsync(appId, A>._)) - .Invokes(new Action>((_, i) => newIndex = i)); + A.CallTo(() => index.RebuildAsync(appId, A>._)) + .Invokes(new Action>((_, i) => newIndex = i)); await sut.RestoreAsync(context); - Assert.Equal(new HashSet + Assert.Equal(new HashSet { ruleId1, ruleId2 diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/GuardRuleTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/GuardRuleTests.cs index 7273c1468..84b1f430e 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/GuardRuleTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/GuardRuleTests.cs @@ -24,8 +24,8 @@ namespace Squidex.Domain.Apps.Entities.Rules.Guards public class GuardRuleTests { private readonly Uri validUrl = new Uri("https://squidex.io"); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly IAppProvider appProvider = A.Fake(); public sealed class TestAction : RuleAction diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/Triggers/ContentChangedTriggerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/Triggers/ContentChangedTriggerTests.cs index 10c05ec97..dc20f8964 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/Triggers/ContentChangedTriggerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/Triggers/ContentChangedTriggerTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -23,8 +22,8 @@ namespace Squidex.Domain.Apps.Entities.Rules.Guards.Triggers public class ContentChangedTriggerTests { private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); [Fact] public async Task Should_add_error_if_schema_id_is_not_defined() @@ -42,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Guards.Triggers new ValidationError("Schema id is required.", "Schemas") }); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, false)) + A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, false)) .MustNotHaveHappened(); } @@ -92,7 +91,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Guards.Triggers [Fact] public async Task Should_not_add_error_if_schemas_ids_are_valid() { - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, false)) + A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, false)) .Returns(Mocks.Schema(appId, schemaId)); var trigger = new ContentChangedTriggerV2 diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/Triggers/UsageTriggerValidationTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/Triggers/UsageTriggerValidationTests.cs index 927c5fa80..10b493694 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/Triggers/UsageTriggerValidationTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/Triggers/UsageTriggerValidationTests.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; using FluentAssertions; using Squidex.Domain.Apps.Core.Rules.Triggers; +using Squidex.Infrastructure; using Squidex.Infrastructure.Validation; using Xunit; @@ -19,7 +19,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Guards.Triggers public class UsageTriggerValidationTests { private readonly IAppProvider appProvider = A.Fake(); - private readonly Guid appId = Guid.NewGuid(); + private readonly DomainId appId = DomainId.NewGuid(); [Fact] public async Task Should_add_error_if_num_days_less_than_1() diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Indexes/RulesIndexTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Indexes/RulesIndexTests.cs index d8407428b..c8b3812aa 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Indexes/RulesIndexTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Indexes/RulesIndexTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -23,12 +22,12 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes private readonly IGrainFactory grainFactory = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); private readonly IRulesByAppIndexGrain index = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RulesIndex sut; public RulesIndexTests() { - A.CallTo(() => grainFactory.GetGrain(appId.Id, null)) + A.CallTo(() => grainFactory.GetGrain(appId.Id.ToString(), null)) .Returns(index); sut = new RulesIndex(grainFactory); @@ -40,7 +39,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes var rule = SetupRule(0, false); A.CallTo(() => index.GetIdsAsync()) - .Returns(new List { rule.Id }); + .Returns(new List { rule.Id }); var actual = await sut.GetRulesAsync(appId.Id); @@ -53,7 +52,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes var rule = SetupRule(-1, false); A.CallTo(() => index.GetIdsAsync()) - .Returns(new List { rule.Id }); + .Returns(new List { rule.Id }); var actual = await sut.GetRulesAsync(appId.Id); @@ -66,7 +65,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes var rule = SetupRule(-1, false); A.CallTo(() => index.GetIdsAsync()) - .Returns(new List { rule.Id }); + .Returns(new List { rule.Id }); var actual = await sut.GetRulesAsync(appId.Id); @@ -76,7 +75,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes [Fact] public async Task Should_add_rule_to_index_on_create() { - var ruleId = Guid.NewGuid(); + var ruleId = DomainId.NewGuid(); var command = new CreateRule { RuleId = ruleId, AppId = appId }; @@ -95,7 +94,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes { var rule = SetupRule(0, false); - var command = new DeleteRule { RuleId = rule.Id }; + var command = new DeleteRule { RuleId = rule.Id, AppId = appId }; var context = new CommandContext(command, commandBus) @@ -110,7 +109,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes [Fact] public async Task Should_forward_call_when_rebuilding() { - var rules = new HashSet(); + var rules = new HashSet(); await sut.RebuildAsync(appId.Id, rules); @@ -120,7 +119,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes private IRuleEntity SetupRule(long version, bool deleted) { - var ruleId = Guid.NewGuid(); + var ruleId = DomainId.NewGuid(); var ruleEntity = new RuleEntity { Id = ruleId, AppId = appId, Version = version, IsDeleted = deleted }; var ruleGrain = A.Fake(); @@ -128,7 +127,9 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes A.CallTo(() => ruleGrain.GetStateAsync()) .Returns(J.Of(ruleEntity)); - A.CallTo(() => grainFactory.GetGrain(ruleId, null)) + var key = DomainId.Combine(appId, ruleId).ToString(); + + A.CallTo(() => grainFactory.GetGrain(key, null)) .Returns(ruleGrain); return ruleEntity; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleEnricherTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleEnricherTests.cs index 1afcf66ac..c0484e661 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleEnricherTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleEnricherTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -21,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Queries { private readonly IRuleEventRepository ruleEventRepository = A.Fake(); private readonly IRequestCache requestCache = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly Context requestContext = Context.Anonymous(); private readonly RuleEnricher sut; @@ -42,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Queries Assert.Null(result.LastExecuted); - A.CallTo(() => requestCache.AddDependency(source.Id, source.Version)) + A.CallTo(() => requestCache.AddDependency(source.UniqueId, source.Version)) .MustHaveHappened(); A.CallTo(() => requestCache.AddDependency(null)) @@ -65,18 +64,18 @@ namespace Squidex.Domain.Apps.Entities.Rules.Queries A.CallTo(() => ruleEventRepository.QueryStatisticsByAppAsync(appId.Id)) .Returns(new List { stats }); - var result = await sut.EnrichAsync(source, requestContext); + await sut.EnrichAsync(source, requestContext); - A.CallTo(() => requestCache.AddDependency(source.Id, source.Version)) + A.CallTo(() => requestCache.AddDependency(source.UniqueId, source.Version)) .MustHaveHappened(); A.CallTo(() => requestCache.AddDependency(stats.LastExecuted)) .MustHaveHappened(); } - private RuleEntity CreateRule() + private IRuleEntity CreateRule() { - return new RuleEntity { AppId = appId, Id = Guid.NewGuid(), Version = 13 }; + return new RuleEntity { AppId = appId, Id = DomainId.NewGuid(), Version = 13 }; } } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleQueryServiceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleQueryServiceTests.cs index 6c04345c2..8b4e32a65 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleQueryServiceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleQueryServiceTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -20,7 +19,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Queries { private readonly IRulesIndex rulesIndex = A.Fake(); private readonly IRuleEnricher ruleEnricher = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly Context requestContext = Context.Anonymous(); private readonly RuleQueryService sut; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleCommandMiddlewareTests.cs index 320b37f28..818824110 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleCommandMiddlewareTests.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Orleans; using Squidex.Domain.Apps.Entities.Rules.State; using Squidex.Domain.Apps.Entities.TestHelpers; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Xunit; @@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.Rules { private readonly IRuleEnricher ruleEnricher = A.Fake(); private readonly IContextProvider contextProvider = A.Fake(); - private readonly Guid ruleId = Guid.NewGuid(); + private readonly DomainId ruleId = DomainId.NewGuid(); private readonly Context requestContext = Context.Anonymous(); private readonly RuleCommandMiddleware sut; @@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Rules { } - protected override Guid Id + protected override DomainId Id { get { return ruleId; } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDequeuerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDequeuerTests.cs index b4fded291..4f8863f64 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDequeuerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDequeuerTests.cs @@ -74,10 +74,10 @@ namespace Squidex.Domain.Apps.Entities.Rules [Fact] public async Task Should_not_execute_if_already_running() { - var id = Guid.NewGuid(); + var id = DomainId.NewGuid(); - var @event1 = CreateEvent(1, "MyAction", "{}", id); - var @event2 = CreateEvent(1, "MyAction", "{}", id); + var event1 = CreateEvent(1, "MyAction", "{}", id); + var event2 = CreateEvent(1, "MyAction", "{}", id); A.CallTo(() => ruleService.InvokeAsync(A._, A._)) .ReturnsLazily(async () => @@ -88,8 +88,8 @@ namespace Squidex.Domain.Apps.Entities.Rules }); await Task.WhenAll( - sut.HandleAsync(@event1), - sut.HandleAsync(@event2)); + sut.HandleAsync(event1), + sut.HandleAsync(event2)); A.CallTo(() => ruleService.InvokeAsync(A._, A._)) .MustHaveHappenedOnceExactly(); @@ -139,10 +139,10 @@ namespace Squidex.Domain.Apps.Entities.Rules private IRuleEventEntity CreateEvent(int numCalls, string actionName, string actionData) { - return CreateEvent(numCalls, actionName, actionData, Guid.NewGuid()); + return CreateEvent(numCalls, actionName, actionData, DomainId.NewGuid()); } - private IRuleEventEntity CreateEvent(int numCalls, string actionName, string actionData, Guid id) + private IRuleEventEntity CreateEvent(int numCalls, string actionName, string actionData, DomainId id) { var @event = A.Fake(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDomainObjectTests.cs index dd049faae..4171677b5 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDomainObjectTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Core.Rules; @@ -26,12 +25,12 @@ namespace Squidex.Domain.Apps.Entities.Rules { private readonly IAppProvider appProvider = A.Fake(); private readonly IRuleEnqueuer ruleEnqueuer = A.Fake(); - private readonly Guid ruleId = Guid.NewGuid(); + private readonly DomainId ruleId = DomainId.NewGuid(); private readonly RuleDomainObject sut; - protected override Guid Id + protected override DomainId Id { - get { return ruleId; } + get { return DomainId.Combine(AppId, ruleId); } } public sealed class TestAction : RuleAction @@ -165,7 +164,7 @@ namespace Squidex.Domain.Apps.Entities.Rules Assert.Null(result); - A.CallTo(() => ruleEnqueuer.Enqueue(sut.Snapshot.RuleDef, sut.Id, + A.CallTo(() => ruleEnqueuer.Enqueue(sut.Snapshot.RuleDef, sut.Snapshot.Id, A>.That.Matches(x => x.Payload is RuleManuallyTriggered))) .MustHaveHappened(); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs index a90ffc9ea..9c76043ed 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs @@ -31,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Rules private readonly ILocalCache localCache = A.Fake(); private readonly IRuleEventRepository ruleEventRepository = A.Fake(); private readonly Instant now = SystemClock.Instance.GetCurrentInstant(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RuleService ruleService = A.Fake(); private readonly RuleEnqueuer sut; @@ -59,7 +59,7 @@ namespace Squidex.Domain.Apps.Entities.Rules [Fact] public void Should_return_type_name_for_name() { - Assert.Equal(typeof(RuleEnqueuer).Name, sut.Name); + Assert.Equal(nameof(RuleEnqueuer), sut.Name); } [Fact] @@ -118,7 +118,7 @@ namespace Squidex.Domain.Apps.Entities.Rules { var rule = new Rule(new ContentChangedTriggerV2(), new TestAction { Url = new Uri("https://squidex.io") }); - return new RuleEntity { RuleDef = rule, Id = Guid.NewGuid() }; + return new RuleEntity { RuleDef = rule, Id = DomainId.NewGuid() }; } } } \ No newline at end of file diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/UsageTracking/UsageTriggerHandlerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/UsageTracking/UsageTriggerHandlerTests.cs index 94a0f9045..7e015f279 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/UsageTracking/UsageTriggerHandlerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/UsageTracking/UsageTriggerHandlerTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Linq; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.HandleRules; @@ -13,6 +12,7 @@ using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; using Squidex.Domain.Apps.Core.Rules.Triggers; using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events.Contents; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; using Xunit; @@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.UsageTracking { public class UsageTriggerHandlerTests { - private readonly Guid ruleId = Guid.NewGuid(); + private readonly DomainId ruleId = DomainId.NewGuid(); private readonly IRuleTriggerHandler sut = new UsageTriggerHandler(); [Fact] @@ -34,7 +34,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.UsageTracking [Fact] public void Should_not_trigger_precheck_when_rule_id_not_matchs() { - var result = sut.Trigger(new AppUsageExceeded { RuleId = Guid.NewGuid() }, new UsageTrigger(), ruleId); + var result = sut.Trigger(new AppUsageExceeded { RuleId = DomainId.NewGuid() }, new UsageTrigger(), ruleId); Assert.True(result); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/BackupSchemasTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/BackupSchemasTests.cs index 4db0f55f6..a4151fc83 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/BackupSchemasTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/BackupSchemasTests.cs @@ -37,13 +37,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas [Fact] public async Task Should_restore_indices_for_all_non_deleted_schemas() { - var appId = Guid.NewGuid(); + var appId = DomainId.NewGuid(); - var schemaId1 = NamedId.Of(Guid.NewGuid(), "my-schema1"); - var schemaId2 = NamedId.Of(Guid.NewGuid(), "my-schema2"); - var schemaId3 = NamedId.Of(Guid.NewGuid(), "my-schema3"); + var schemaId1 = NamedId.Of(DomainId.NewGuid(), "my-schema1"); + var schemaId2 = NamedId.Of(DomainId.NewGuid(), "my-schema2"); + var schemaId3 = NamedId.Of(DomainId.NewGuid(), "my-schema3"); - var context = new RestoreContext(appId, new UserMapping(new RefToken(RefTokenType.Subject, "123")), A.Fake()); + var context = new RestoreContext(appId, new UserMapping(new RefToken(RefTokenType.Subject, "123")), A.Fake(), DomainId.NewGuid()); await sut.RestoreEventAsync(Envelope.Create(new SchemaCreated { @@ -65,14 +65,14 @@ namespace Squidex.Domain.Apps.Entities.Schemas SchemaId = schemaId3 }), context); - Dictionary? newIndex = null; + Dictionary? newIndex = null; - A.CallTo(() => index.RebuildAsync(appId, A>._)) - .Invokes(new Action>((_, i) => newIndex = i)); + A.CallTo(() => index.RebuildAsync(appId, A>._)) + .Invokes(new Action>((_, i) => newIndex = i)); await sut.RestoreAsync(context); - Assert.Equal(new Dictionary + Assert.Equal(new Dictionary { [schemaId1.Name] = schemaId1.Id, [schemaId2.Name] = schemaId2.Id diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaTests.cs index 1b077b24f..519f4c66e 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Schemas; @@ -22,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards public class GuardSchemaTests { private readonly Schema schema_0; - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); public GuardSchemaTests() { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasIndexTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasIndexTests.cs index 60fc48cfe..a4203fcf1 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasIndexTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasIndexTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -27,13 +26,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes private readonly IGrainFactory grainFactory = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); private readonly ISchemasByAppIndexGrain index = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly SchemasIndex sut; public SchemasIndexTests() { - A.CallTo(() => grainFactory.GetGrain(appId.Id, null)) + A.CallTo(() => grainFactory.GetGrain(appId.Id.ToString(), null)) .Returns(index); sut = new SchemasIndex(grainFactory); @@ -68,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes var schema = SetupSchema(0, false); A.CallTo(() => index.GetIdsAsync()) - .Returns(new List { schema.Id }); + .Returns(new List { schema.Id }); var actual = await sut.GetSchemasAsync(appId.Id); @@ -81,7 +80,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes var schema = SetupSchema(-1, false); A.CallTo(() => index.GetIdsAsync()) - .Returns(new List { schema.Id }); + .Returns(new List { schema.Id }); var actual = await sut.GetSchemasAsync(appId.Id); @@ -195,7 +194,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes { var schema = SetupSchema(0, isDeleted); - var command = new DeleteSchema { SchemaId = schema.Id }; + var command = new DeleteSchema { SchemaId = schemaId, AppId = appId }; var context = new CommandContext(command, commandBus) @@ -210,7 +209,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes [Fact] public async Task Should_forward_call_when_rebuilding() { - var schemas = new Dictionary(); + var schemas = new Dictionary(); await sut.RebuildAsync(appId.Id, schemas); @@ -243,7 +242,9 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes A.CallTo(() => schemaGrain.GetStateAsync()) .Returns(J.Of(schemaEntity)); - A.CallTo(() => grainFactory.GetGrain(schemaId.Id, null)) + var key = DomainId.Combine(appId, schemaId.Id).ToString(); + + A.CallTo(() => grainFactory.GetGrain(key, null)) .Returns(schemaGrain); return schemaEntity; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaChangedTriggerHandlerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaChangedTriggerHandlerTests.cs index a3715157d..2dba39190 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaChangedTriggerHandlerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaChangedTriggerHandlerTests.cs @@ -17,6 +17,7 @@ using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events.Apps; using Squidex.Domain.Apps.Events.Schemas; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; using Xunit; @@ -67,7 +68,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas { TestForCondition(string.Empty, trigger => { - var result = sut.Trigger(new AppCreated(), trigger, Guid.NewGuid()); + var result = sut.Trigger(new AppCreated(), trigger, DomainId.NewGuid()); Assert.False(result); }); @@ -78,7 +79,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas { TestForCondition(string.Empty, trigger => { - var result = sut.Trigger(new SchemaCreated(), trigger, Guid.NewGuid()); + var result = sut.Trigger(new SchemaCreated(), trigger, DomainId.NewGuid()); Assert.True(result); }); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaCommandsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaCommandsTests.cs index ef81f7f73..8eaf6be7b 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaCommandsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaCommandsTests.cs @@ -72,7 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas }) .Publish(); - var actual = command.ToSchema("my-schema", false); + var actual = command.BuildSchema("my-schema", false); actual.Should().BeEquivalentTo(expected); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaDomainObjectTests.cs index e9e08d053..f9827cf6a 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaDomainObjectTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -32,9 +31,9 @@ namespace Squidex.Domain.Apps.Entities.Schemas private readonly NamedId nestedId = NamedId.Of(2L, "age"); private readonly SchemaDomainObject sut; - protected override Guid Id + protected override DomainId Id { - get { return SchemaId; } + get { return DomainId.Combine(AppId, SchemaId); } } public SchemaDomainObjectTests() @@ -695,7 +694,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas private Task ExecuteCreateAsync() { - return PublishAsync(new CreateSchema { Name = SchemaName }); + return PublishAsync(new CreateSchema { Name = SchemaName, SchemaId = SchemaId }); } private Task ExecuteAddArrayFieldAsync() @@ -743,7 +742,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas return new StringFieldProperties { MinLength = 10, MaxLength = 20 }; } - private async Task PublishIdempotentAsync(SchemaCommand command) + private async Task PublishIdempotentAsync(T command) where T : SquidexCommand, IAggregateCommand { var result = await PublishAsync(command); @@ -758,7 +757,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas return result; } - private async Task PublishAsync(SchemaCommand command) + private async Task PublishAsync(T command) where T : SquidexCommand, IAggregateCommand { var result = await sut.ExecuteAsync(CreateCommand(command)); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemasSearchSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemasSearchSourceTests.cs index 1dd3e16ab..e9c0e1dee 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemasSearchSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemasSearchSourceTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; @@ -26,7 +25,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas { private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly SchemasSearchSource sut; public SchemasSearchSourceTests() @@ -114,7 +113,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas private ISchemaEntity CreateSchema(string name, bool isSingleton) { - return Mocks.Schema(appId, NamedId.Of(Guid.NewGuid(), name), new Schema(name, null, isSingleton)); + return Mocks.Schema(appId, NamedId.Of(DomainId.NewGuid(), name), new Schema(name, null, isSingleton)); } private Context ContextWithPermission(string? permission = null) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Tags/GrainTagServiceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Tags/GrainTagServiceTests.cs index aac32efb0..dca427418 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Tags/GrainTagServiceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Tags/GrainTagServiceTests.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; using Orleans; using Squidex.Domain.Apps.Core.Tags; +using Squidex.Infrastructure; using Xunit; namespace Squidex.Domain.Apps.Entities.Tags @@ -19,7 +19,7 @@ namespace Squidex.Domain.Apps.Entities.Tags { private readonly IGrainFactory grainFactory = A.Fake(); private readonly ITagGrain grain = A.Fake(); - private readonly Guid appId = Guid.NewGuid(); + private readonly DomainId appId = DomainId.NewGuid(); private readonly GrainTagService sut; public GrainTagServiceTests() diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagGrainTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagGrainTests.cs index 47b111a77..fa7919ae1 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagGrainTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagGrainTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; @@ -21,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.Tags public class TagGrainTests { private readonly IGrainState grainState = A.Fake>(); - private readonly string id = Guid.NewGuid().ToString(); + private readonly string id = DomainId.NewGuid().ToString(); private readonly TagGrain sut; public TagGrainTests() @@ -108,9 +107,7 @@ namespace Squidex.Domain.Apps.Entities.Tags public async Task Should_remove_tags_from_grain() { var result1 = await sut.NormalizeTagsAsync(HashSet.Of("name1", "name2"), null); -#pragma warning disable IDE0059 // Unnecessary assignment of a value var result2 = await sut.NormalizeTagsAsync(HashSet.Of("name2", "name3"), null); -#pragma warning restore IDE0059 // Unnecessary assignment of a value await sut.NormalizeTagsAsync(null, new HashSet(result1.Values)); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs index 2a085349e..6965306f5 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs @@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers { public abstract class HandlerTestBase { - private readonly IStore store = A.Fake>(); + private readonly IStore store = A.Fake>(); private readonly IPersistence persistenceWithState = A.Fake>(); private readonly IPersistence persistence = A.Fake(); @@ -29,9 +29,9 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers protected RefToken ActorClient { get; } = new RefToken(RefTokenType.Client, "client"); - protected Guid AppId { get; } = Guid.NewGuid(); + protected DomainId AppId { get; } = DomainId.NewGuid(); - protected Guid SchemaId { get; } = Guid.NewGuid(); + protected DomainId SchemaId { get; } = DomainId.NewGuid(); protected string AppName { get; } = "my-app"; @@ -39,19 +39,19 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers protected ClaimsPrincipal User { get; } = Mocks.FrontendUser(); - protected NamedId AppNamedId + protected NamedId AppNamedId { get { return NamedId.Of(AppId, AppName); } } - protected NamedId SchemaNamedId + protected NamedId SchemaNamedId { get { return NamedId.Of(SchemaId, SchemaName); } } - protected abstract Guid Id { get; } + protected abstract DomainId Id { get; } - public IStore Store + public IStore Store { get { return store; } } @@ -81,11 +81,7 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers protected TCommand CreateCommand(TCommand command) where TCommand : SquidexCommand { command.ExpectedVersion = EtagVersion.Any; - - if (command.Actor == null) - { - command.Actor = Actor; - } + command.Actor ??= Actor; if (command.User == null && command.Actor.IsSubject) { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/JsonHelper.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/JsonHelper.cs index 01871cca9..470c92fa9 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/JsonHelper.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/JsonHelper.cs @@ -39,6 +39,7 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers new FilterConverter(), new JsonValueConverter(), new LanguageConverter(), + new NamedDomainIdConverter(), new NamedGuidIdConverter(), new NamedLongIdConverter(), new NamedStringIdConverter(), diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs index ad363bb6b..c1d25dcc0 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Security.Claims; using FakeItEasy; using Squidex.Domain.Apps.Core.Apps; @@ -20,7 +19,7 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers { public static class Mocks { - public static IAppEntity App(NamedId appId, params Language[] languages) + public static IAppEntity App(NamedId appId, params Language[] languages) { var config = LanguagesConfig.English; @@ -34,17 +33,19 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers A.CallTo(() => app.Id).Returns(appId.Id); A.CallTo(() => app.Name).Returns(appId.Name); A.CallTo(() => app.LanguagesConfig).Returns(config); + A.CallTo(() => app.UniqueId).Returns(appId.Id); return app; } - public static ISchemaEntity Schema(NamedId appId, NamedId schemaId, Schema? schemaDef = null) + public static ISchemaEntity Schema(NamedId appId, NamedId schemaId, Schema? schemaDef = null) { var schema = A.Fake(); A.CallTo(() => schema.Id).Returns(schemaId.Id); A.CallTo(() => schema.AppId).Returns(appId); A.CallTo(() => schema.SchemaDef).Returns(schemaDef ?? new Schema(schemaId.Name)); + A.CallTo(() => schema.UniqueId).Returns(DomainId.Combine(appId, schemaId.Id)); return schema; } diff --git a/backend/tests/Squidex.Infrastructure.Tests/BytesRangeTests.cs b/backend/tests/Squidex.Infrastructure.Tests/BytesRangeTests.cs index ce33ecc5f..5668991e7 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/BytesRangeTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/BytesRangeTests.cs @@ -75,7 +75,7 @@ namespace Squidex.Infrastructure TestBytesRange(sut, -5, -3, 0, false, null); } - private void TestBytesRange(BytesRange sut, long? from, long? to, long length, bool defined, string? formatted) + private static void TestBytesRange(BytesRange sut, long? from, long? to, long length, bool defined, string? formatted) { Assert.Equal(from, sut.From); Assert.Equal(to, sut.To); diff --git a/backend/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectTests.cs index e500d7af4..0afcc7d67 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectTests.cs @@ -20,14 +20,14 @@ namespace Squidex.Infrastructure.Commands { public class DomainObjectTests { - private readonly IStore store = A.Fake>(); + private readonly IStore store = A.Fake>(); private readonly IPersistence persistence = A.Fake>(); - private readonly Guid id = Guid.NewGuid(); + private readonly DomainId id = DomainId.NewGuid(); private readonly MyDomainObject sut; public sealed class MyDomainObject : DomainObject { - public MyDomainObject(IStore store) + public MyDomainObject(IStore store) : base(store, A.Dummy()) { } @@ -94,7 +94,7 @@ namespace Squidex.Infrastructure.Commands A.CallTo(() => persistence.ReadAsync(A._)) .MustNotHaveHappened(); - Assert.True(result is EntityCreatedResult); + Assert.True(result is EntityCreatedResult); Assert.Empty(sut.GetUncomittedEvents()); @@ -164,7 +164,7 @@ namespace Squidex.Infrastructure.Commands } [Fact] - public async Task Should_rebuild_state_async() + public async Task Should_rebuild_state() { SetupCreated(4); @@ -176,6 +176,14 @@ namespace Squidex.Infrastructure.Commands .MustNotHaveHappened(); } + [Fact] + public async Task Should_throw_on_rebuild_when_no_event_found() + { + SetupEmpty(); + + await Assert.ThrowsAsync(() => sut.RebuildStateAsync()); + } + [Fact] public async Task Should_not_update_when_snapshot_is_not_changed() { diff --git a/backend/tests/Squidex.Infrastructure.Tests/Commands/LogSnapshotDomainObjectTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Commands/LogSnapshotDomainObjectTests.cs index 4f78b0676..4ab8f3138 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Commands/LogSnapshotDomainObjectTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/Commands/LogSnapshotDomainObjectTests.cs @@ -21,15 +21,15 @@ namespace Squidex.Infrastructure.Commands { public class LogSnapshotDomainObjectTests { - private readonly IStore store = A.Fake>(); - private readonly ISnapshotStore snapshotStore = A.Fake>(); + private readonly IStore store = A.Fake>(); + private readonly ISnapshotStore snapshotStore = A.Fake>(); private readonly IPersistence persistence = A.Fake(); - private readonly Guid id = Guid.NewGuid(); + private readonly DomainId id = DomainId.NewGuid(); private readonly MyLogDomainObject sut; public sealed class MyLogDomainObject : LogSnapshotDomainObject { - public MyLogDomainObject(IStore store) + public MyLogDomainObject(IStore store) : base(store, A.Dummy()) { } @@ -147,7 +147,7 @@ namespace Squidex.Infrastructure.Commands A.CallTo(() => persistence.ReadAsync(A._)) .MustNotHaveHappened(); - Assert.True(result is EntityCreatedResult); + Assert.True(result is EntityCreatedResult); Assert.Empty(sut.GetUncomittedEvents()); @@ -217,7 +217,7 @@ namespace Squidex.Infrastructure.Commands } [Fact] - public async Task Should_rebuild_state_async() + public async Task Should_rebuild_state() { SetupCreated(4); @@ -229,6 +229,14 @@ namespace Squidex.Infrastructure.Commands .MustNotHaveHappened(); } + [Fact] + public async Task Should_throw_on_rebuild_when_no_event_found() + { + SetupEmpty(); + + await Assert.ThrowsAsync(() => sut.RebuildStateAsync()); + } + [Fact] public async Task Should_not_update_when_snapshot_is_not_changed() { @@ -293,7 +301,7 @@ namespace Squidex.Infrastructure.Commands { SetupEmpty(); - A.CallTo(() => snapshotStore.WriteAsync(A._, A._, -1, 0)) + A.CallTo(() => snapshotStore.WriteAsync(A._, A._, -1, 0)) .Throws(new InvalidOperationException()); await Assert.ThrowsAsync(() => sut.ExecuteAsync(new CreateAuto())); @@ -309,7 +317,7 @@ namespace Squidex.Infrastructure.Commands { SetupCreated(4); - A.CallTo(() => snapshotStore.WriteAsync(A._, A._, 0, 1)) + A.CallTo(() => snapshotStore.WriteAsync(A._, A._, 0, 1)) .Throws(new InvalidOperationException()); await Assert.ThrowsAsync(() => sut.ExecuteAsync(new UpdateAuto())); diff --git a/backend/tests/Squidex.Infrastructure.Tests/DomainIdTests.cs b/backend/tests/Squidex.Infrastructure.Tests/DomainIdTests.cs new file mode 100644 index 000000000..93ce4664e --- /dev/null +++ b/backend/tests/Squidex.Infrastructure.Tests/DomainIdTests.cs @@ -0,0 +1,140 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using Squidex.Infrastructure.TestHelpers; +using Xunit; + +namespace Squidex.Infrastructure +{ + public class DomainIdTests + { + private readonly TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(DomainId)); + + [Fact] + public void Should_initialize_default() + { + DomainId domainId = default; + + Assert.Equal(Guid.Empty.ToString(), domainId.ToString()); + } + + [Fact] + public void Should_initialize_default_from_string() + { + var domainId = DomainId.Create(Guid.Empty.ToString()); + + Assert.Equal(DomainId.Empty, domainId); + } + + [Fact] + public void Should_create_nullable_from_string() + { + var domainId = DomainId.CreateNullable(null); + + Assert.Null(domainId); + } + + [Fact] + public void Should_convert_from_string() + { + var text = "123"; + + var result = typeConverter.ConvertFromString(text); + + Assert.Equal(DomainId.Create(text), result); + } + + [Fact] + public void Should_convert_from_guid() + { + var guid = Guid.NewGuid(); + + var result = typeConverter.ConvertFrom(guid); + + Assert.Equal(guid.ToString(), result.ToString()); + } + + [Fact] + public void Should_convert_to_string() + { + var text = "123"; + + var result = typeConverter.ConvertToString(DomainId.Create(text)); + + Assert.Equal(text, result); + } + + [Fact] + public void Should_initialize_domainId_from_guid() + { + var guid = Guid.NewGuid(); + + var domainId = DomainId.Create(guid); + + Assert.Equal(guid.ToString(), domainId.ToString()); + } + + [Fact] + public void Should_initialize_domainId_from_string() + { + var text = "Custom"; + + var domainId = DomainId.Create(text); + + Assert.Equal(text, domainId.ToString()); + } + + [Fact] + public void Should_make_correct_equal_comparisons() + { + var domainId_1_a = DomainId.Create("1"); + var domainId_1_b = DomainId.Create("1"); + + var domainId2_a = DomainId.Create("2"); + + Assert.Equal(domainId_1_a, domainId_1_b); + Assert.Equal(domainId_1_a.GetHashCode(), domainId_1_b.GetHashCode()); + Assert.True(domainId_1_a.Equals((object)domainId_1_b)); + + Assert.NotEqual(domainId_1_a, domainId2_a); + Assert.NotEqual(domainId_1_a.GetHashCode(), domainId2_a.GetHashCode()); + Assert.False(domainId_1_a.Equals((object)domainId2_a)); + + Assert.True(domainId_1_a == domainId_1_b); + Assert.True(domainId_1_a != domainId2_a); + + Assert.False(domainId_1_a != domainId_1_b); + Assert.False(domainId_1_a == domainId2_a); + } + + [Fact] + public void Should_serialize_and_deserialize() + { + var domainId = DomainId.Create("123"); + + var serialized = domainId.SerializeAndDeserialize(); + + Assert.Equal(domainId, serialized); + } + + [Fact] + public void Should_serialize_and_deserialize_as_dictionary() + { + var dictionary = new Dictionary + { + [DomainId.Create("123")] = 321 + }; + + var serialized = dictionary.SerializeAndDeserialize(); + + Assert.Equal(321, serialized[DomainId.Create("123")]); + } + } +} diff --git a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/DefaultEventDataFormatterTests.cs b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/DefaultEventDataFormatterTests.cs index b83e40227..a142b4918 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/DefaultEventDataFormatterTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/DefaultEventDataFormatterTests.cs @@ -46,7 +46,7 @@ namespace Squidex.Infrastructure.EventSourcing var inputEvent = new Envelope(new MyEvent { MyProperty = "My-Property" }); - inputEvent.SetAggregateId(Guid.NewGuid()); + inputEvent.SetAggregateId(DomainId.NewGuid()); inputEvent.SetCommitId(commitId); inputEvent.SetEventId(Guid.NewGuid()); inputEvent.SetEventPosition("1"); diff --git a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/EnvelopeExtensionsTests.cs b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/EnvelopeExtensionsTests.cs index dbba8b617..9371596c4 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/EnvelopeExtensionsTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/EnvelopeExtensionsTests.cs @@ -55,12 +55,12 @@ namespace Squidex.Infrastructure.EventSourcing [Fact] public void Should_set_and_get_aggregate_id() { - var commitId = Guid.NewGuid(); + var commitId = DomainId.NewGuid(); sut.SetAggregateId(commitId); Assert.Equal(commitId, sut.Headers.AggregateId()); - Assert.Equal(commitId, sut.Headers.GetGuid("AggregateId")); + Assert.Equal(commitId.ToString(), sut.Headers.GetString("AggregateId")); } [Fact] diff --git a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/EventStoreTests.cs b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/EventStoreTests.cs index 99839be34..57c13c0e2 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/EventStoreTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/EventStoreTests.cs @@ -269,75 +269,11 @@ namespace Squidex.Infrastructure.EventSourcing Assert.Empty(readEvents); } - [Fact] - public async Task Should_query_events_by_property() - { - var keyed1 = new EnvelopeHeaders(); - var keyed2 = new EnvelopeHeaders(); - - keyed1.Add("key", Guid.NewGuid().ToString()); - keyed2.Add("key", Guid.NewGuid().ToString()); - - var streamName1 = $"test-{Guid.NewGuid()}"; - var streamName2 = $"test-{Guid.NewGuid()}"; - - var events1 = new[] - { - new EventData("Type1", keyed1, "1"), - new EventData("Type2", keyed2, "2") - }; - - var events2 = new[] - { - new EventData("Type3", keyed2, "3"), - new EventData("Type4", keyed1, "4") - }; - - await Sut.CreateIndexAsync("key"); - - await Sut.AppendAsync(Guid.NewGuid(), streamName1, events1); - await Sut.AppendAsync(Guid.NewGuid(), streamName2, events2); - - var readEvents = await QueryWithFilterAsync("key", keyed2["key"].ToString()); - - var expected = new[] - { - new StoredEvent(streamName1, "Position", 1, events1[1]), - new StoredEvent(streamName2, "Position", 0, events2[0]) - }; - - ShouldBeEquivalentTo(readEvents, expected); - } - private Task> QueryAsync(string streamName, long position = EtagVersion.Any) { return Sut.QueryAsync(streamName, position); } - private async Task?> QueryWithFilterAsync(string property, object value) - { - using (var cts = new CancellationTokenSource(30000)) - { - while (!cts.IsCancellationRequested) - { - var readEvents = new List(); - - await Sut.QueryAsync(x => { readEvents.Add(x); return Task.CompletedTask; }, property, value, null, cts.Token); - - await Task.Delay(500, cts.Token); - - if (readEvents.Count > 0) - { - return readEvents; - } - } - - cts.Token.ThrowIfCancellationRequested(); - - return null; - } - } - private async Task?> QueryWithCallbackAsync(string? streamFilter = null, string? position = null) { using (var cts = new CancellationTokenSource(30000)) diff --git a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/Grains/EventConsumerGrainTests.cs b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/Grains/EventConsumerGrainTests.cs index d1f398425..55d81c81c 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/Grains/EventConsumerGrainTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/Grains/EventConsumerGrainTests.cs @@ -70,7 +70,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains A.CallTo(() => eventConsumer.Handles(A._)) .Returns(true); - A.CallTo(() => formatter.Parse(eventData, null)) + A.CallTo(() => formatter.Parse(eventData)) .Returns(envelope); sut = new MyEventConsumerGrain( @@ -220,7 +220,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains [Fact] public async Task Should_ignore_old_events() { - A.CallTo(() => formatter.Parse(eventData, null)) + A.CallTo(() => formatter.Parse(eventData)) .Throws(new TypeNameNotFoundException()); var @event = new StoredEvent("Stream", Guid.NewGuid().ToString(), 123, eventData); @@ -354,7 +354,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains { var ex = new InvalidOperationException(); - A.CallTo(() => formatter.Parse(eventData, null)) + A.CallTo(() => formatter.Parse(eventData)) .Throws(ex); var @event = new StoredEvent("Stream", Guid.NewGuid().ToString(), 123, eventData); diff --git a/backend/tests/Squidex.Infrastructure.Tests/GuardTests.cs b/backend/tests/Squidex.Infrastructure.Tests/GuardTests.cs index 8761ccd94..57cee0b26 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/GuardTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/GuardTests.cs @@ -79,12 +79,24 @@ namespace Squidex.Infrastructure Assert.Throws(() => Guard.NotEmpty(Guid.Empty, "parameter")); } + [Fact] + public void NotEmpty_should_throw_for_empty_domainId() + { + Assert.Throws(() => Guard.NotEmpty((DomainId)default, "parameter")); + } + [Fact] public void NotEmpty_should_do_nothing_for_valid_guid() { Guard.NotEmpty(Guid.NewGuid(), "parameter"); } + [Fact] + public void NotEmpty_should_do_nothing_for_valid_id() + { + Guard.NotEmpty(DomainId.NewGuid(), "parameter"); + } + [Fact] public void HasType_should_throw_for_other_type() { diff --git a/backend/tests/Squidex.Infrastructure.Tests/MongoDb/DomainIdSerializerTests.cs b/backend/tests/Squidex.Infrastructure.Tests/MongoDb/DomainIdSerializerTests.cs new file mode 100644 index 000000000..a68bdf3d3 --- /dev/null +++ b/backend/tests/Squidex.Infrastructure.Tests/MongoDb/DomainIdSerializerTests.cs @@ -0,0 +1,93 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.IO; +using MongoDB.Bson; +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Attributes; +using Xunit; + +namespace Squidex.Infrastructure.MongoDb +{ + public class DomainIdSerializerTests + { + private sealed class StringEntity + { + [BsonRepresentation(BsonType.String)] + public T Id { get; set; } + } + + private sealed class IdEntity + { + public T Id { get; set; } + } + + public DomainIdSerializerTests() + { + DomainIdSerializer.Register(); + } + + [Fact] + public void Should_deserialize_from_string() + { + var id = Guid.NewGuid(); + + var source = new IdEntity { Id = id.ToString() }; + + var result = SerializeAndDeserialize, IdEntity>(source); + + Assert.Equal(result.Id.ToString(), id.ToString()); + } + + [Fact] + public void Should_deserialize_from_guid_string() + { + var id = Guid.NewGuid(); + + var source = new StringEntity { Id = id }; + + var result = SerializeAndDeserialize, IdEntity>(source); + + Assert.Equal(result.Id.ToString(), id.ToString()); + } + + [Fact] + public void Should_deserialize_from_guid_bytes() + { + var id = Guid.NewGuid(); + + var source = new IdEntity { Id = id }; + + var result = SerializeAndDeserialize, IdEntity>(source); + + Assert.Equal(result.Id.ToString(), id.ToString()); + } + + public TOut SerializeAndDeserialize(TIn source) + { + var stream = new MemoryStream(); + + using (var writer = new BsonBinaryWriter(stream)) + { + BsonSerializer.Serialize(writer, source); + + writer.Flush(); + } + + stream.Position = 0; + + using (var reader = new BsonBinaryReader(stream)) + { + var target = BsonSerializer.Deserialize(reader); + + return target; + } + } + } +} diff --git a/backend/tests/Squidex.Infrastructure.Tests/NamedIdTests.cs b/backend/tests/Squidex.Infrastructure.Tests/NamedIdTests.cs index 3833a3bf7..2f48922c2 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/NamedIdTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/NamedIdTests.cs @@ -94,6 +94,26 @@ namespace Squidex.Infrastructure Assert.Equal(value, serialized); } + [Fact] + public void Should_serialize_and_deserialize_null_id_token() + { + NamedId? value = null; + + var serialized = value.SerializeAndDeserialize(); + + Assert.Equal(value, serialized); + } + + [Fact] + public void Should_serialize_and_deserialize_valid_id_token() + { + var value = NamedId.Of(DomainId.NewGuid().ToString(), "my-name"); + + var serialized = value.SerializeAndDeserialize(); + + Assert.Equal(value, serialized); + } + [Fact] public void Should_throw_exception_if_string_id_is_not_valid() { diff --git a/backend/tests/Squidex.Infrastructure.Tests/Orleans/Indexes/IdsIndexGrainTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Orleans/Indexes/IdsIndexGrainTests.cs index e97512322..2f6edcc48 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Orleans/Indexes/IdsIndexGrainTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/Orleans/Indexes/IdsIndexGrainTests.cs @@ -15,17 +15,17 @@ namespace Squidex.Infrastructure.Orleans.Indexes { public class IdsIndexGrainTests { - private readonly IGrainState> grainState = A.Fake>>(); - private readonly Guid id1 = Guid.NewGuid(); - private readonly Guid id2 = Guid.NewGuid(); - private readonly IdsIndexGrain, Guid> sut; + private readonly IGrainState> grainState = A.Fake>>(); + private readonly DomainId id1 = DomainId.NewGuid(); + private readonly DomainId id2 = DomainId.NewGuid(); + private readonly IdsIndexGrain, DomainId> sut; public IdsIndexGrainTests() { A.CallTo(() => grainState.ClearAsync()) - .Invokes(() => grainState.Value = new IdsIndexState()); + .Invokes(() => grainState.Value = new IdsIndexState()); - sut = new IdsIndexGrain, Guid>(grainState); + sut = new IdsIndexGrain, DomainId>(grainState); } [Fact] @@ -36,7 +36,7 @@ namespace Squidex.Infrastructure.Orleans.Indexes var result = await sut.GetIdsAsync(); - Assert.Equal(new List { id1, id2 }, result); + Assert.Equal(new List { id1, id2 }, result); A.CallTo(() => grainState.WriteAsync()) .MustHaveHappenedTwiceExactly(); @@ -75,7 +75,7 @@ namespace Squidex.Infrastructure.Orleans.Indexes var result = await sut.GetIdsAsync(); - Assert.Equal(new List { id2 }, result); + Assert.Equal(new List { id2 }, result); A.CallTo(() => grainState.WriteAsync()) .MustHaveHappenedTwiceOrMore(); @@ -84,7 +84,7 @@ namespace Squidex.Infrastructure.Orleans.Indexes [Fact] public async Task Should_replace__ids_on_rebuild() { - var state = new HashSet + var state = new HashSet { id1, id2 @@ -94,7 +94,7 @@ namespace Squidex.Infrastructure.Orleans.Indexes var result = await sut.GetIdsAsync(); - Assert.Equal(new List { id1, id2 }, result); + Assert.Equal(new List { id1, id2 }, result); A.CallTo(() => grainState.WriteAsync()) .MustHaveHappened(); diff --git a/backend/tests/Squidex.Infrastructure.Tests/Queries/QueryJsonConversionTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Queries/QueryJsonConversionTests.cs index 5f2f5c49d..7dbdf8855 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Queries/QueryJsonConversionTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/Queries/QueryJsonConversionTests.cs @@ -457,7 +457,7 @@ namespace Squidex.Infrastructure.Queries public static IEnumerable BuildTests(string field, Predicate opFilter, object value, string valueString) { - var fields = new string[] + var fields = new[] { $"{field}", $"json.{field}", diff --git a/backend/tests/Squidex.Infrastructure.Tests/States/DefaultStreamNameResolverTests.cs b/backend/tests/Squidex.Infrastructure.Tests/States/DefaultStreamNameResolverTests.cs index bd38f19d5..af2e90a66 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/States/DefaultStreamNameResolverTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/States/DefaultStreamNameResolverTests.cs @@ -39,35 +39,5 @@ namespace Squidex.Infrastructure.States Assert.Equal($"myUser-{id}", name); } - - [Fact] - public void Should_calculate_new_stream_if_valid() - { - var oldStream = "myUser-123"; - - var newStream = sut.WithNewId(oldStream, x => "456"); - - Assert.Equal("myUser-456", newStream); - } - - [Fact] - public void Should_return_old_stream_if_format_not_valid() - { - var oldStream = "myUser|123"; - - var newStream = sut.WithNewId(oldStream, x => "456"); - - Assert.Equal(oldStream, newStream); - } - - [Fact] - public void Should_return_old_stream_if_new_id_not_valid() - { - var oldStream = "myUser-123"; - - var newStream = sut.WithNewId(oldStream, x => null); - - Assert.Equal(oldStream, newStream); - } } } diff --git a/backend/tests/Squidex.Infrastructure.Tests/States/PersistenceEventSourcingTests.cs b/backend/tests/Squidex.Infrastructure.Tests/States/PersistenceEventSourcingTests.cs index 64492f1d3..d8e85e50c 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/States/PersistenceEventSourcingTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/States/PersistenceEventSourcingTests.cs @@ -66,7 +66,7 @@ namespace Squidex.Infrastructure.States A.CallTo(() => eventStore.QueryAsync(key, 0)) .Returns(new List { storedEvent }); - A.CallTo(() => eventDataFormatter.Parse(storedEvent.Data, null)) + A.CallTo(() => eventDataFormatter.Parse(storedEvent.Data)) .Throws(new TypeNameNotFoundException()); var persistedEvents = new List(); @@ -274,7 +274,7 @@ namespace Squidex.Infrastructure.States eventsStored.Add(eventStored); - A.CallTo(() => eventDataFormatter.Parse(eventData, null)) + A.CallTo(() => eventDataFormatter.Parse(eventData)) .Returns(new Envelope(@event)); i++; diff --git a/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/JsonHelper.cs b/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/JsonHelper.cs index d4180f81b..54f9cb91c 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/JsonHelper.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/JsonHelper.cs @@ -52,7 +52,9 @@ namespace Squidex.Infrastructure.TestHelpers public static T SerializeAndDeserialize(this T value) { - return DefaultSerializer.Deserialize>(DefaultSerializer.Serialize(Tuple.Create(value))).Item1; + var json = DefaultSerializer.Serialize(Tuple.Create(value)); + + return DefaultSerializer.Deserialize>(json).Item1; } public static T Deserialize(string value) diff --git a/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyCommand.cs b/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyCommand.cs index 274d85baf..7eeea3f9d 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyCommand.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyCommand.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; using Squidex.Infrastructure.Commands; @@ -13,7 +12,7 @@ namespace Squidex.Infrastructure.TestHelpers { public class MyCommand : IAggregateCommand, ITimestampCommand { - public Guid AggregateId { get; set; } + public DomainId AggregateId { get; set; } public long ExpectedVersion { get; set; } = EtagVersion.Any; diff --git a/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyDomainObject.cs b/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyDomainObject.cs index d42aa25c2..e0c5d9777 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyDomainObject.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyDomainObject.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Squidex.Infrastructure.Commands; @@ -16,7 +15,7 @@ namespace Squidex.Infrastructure.TestHelpers { public sealed class MyDomainObject : DomainObject { - public MyDomainObject(IStore store) + public MyDomainObject(IStore store) : base(store, A.Dummy()) { } diff --git a/backend/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs b/backend/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs index b515e4cae..a130c0a28 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs @@ -128,6 +128,8 @@ namespace Squidex.Infrastructure.UsageTracking (dateFrom.AddDays(4), new Counters()) } }; + + Assert.Equal(expected, result); } [Fact] diff --git a/backend/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs b/backend/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs index 8697c4947..645806e20 100644 --- a/backend/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs +++ b/backend/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; @@ -63,7 +62,7 @@ namespace Squidex.Web [Fact] public async Task Should_make_permission_check_with_app_feature() { - actionExecutingContext.HttpContext.Features.Set(new AppFeature(NamedId.Of(Guid.NewGuid(), "my-app"))); + actionExecutingContext.HttpContext.Features.Set(new AppFeature(NamedId.Of(DomainId.NewGuid(), "my-app"))); user.AddClaim(new Claim(SquidexClaimTypes.Permissions, "squidex.apps.my-app")); @@ -80,8 +79,8 @@ namespace Squidex.Web [Fact] public async Task Should_make_permission_check_with_schema_feature() { - actionExecutingContext.HttpContext.Features.Set(new AppFeature(NamedId.Of(Guid.NewGuid(), "my-app"))); - actionExecutingContext.HttpContext.Features.Set(new SchemaFeature(NamedId.Of(Guid.NewGuid(), "my-schema"))); + actionExecutingContext.HttpContext.Features.Set(new AppFeature(NamedId.Of(DomainId.NewGuid(), "my-app"))); + actionExecutingContext.HttpContext.Features.Set(new SchemaFeature(NamedId.Of(DomainId.NewGuid(), "my-schema"))); user.AddClaim(new Claim(SquidexClaimTypes.Permissions, "squidex.apps.my-app.schemas.my-schema")); @@ -98,7 +97,7 @@ namespace Squidex.Web [Fact] public async Task Should_return_forbidden_when_user_has_wrong_permission() { - actionExecutingContext.HttpContext.Features.Set(new AppFeature(NamedId.Of(Guid.NewGuid(), "my-app"))); + actionExecutingContext.HttpContext.Features.Set(new AppFeature(NamedId.Of(DomainId.NewGuid(), "my-app"))); user.AddClaim(new Claim(SquidexClaimTypes.Permissions, "squidex.apps.other-app")); diff --git a/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs b/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs index b8f4017fd..b1481581e 100644 --- a/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs @@ -10,7 +10,6 @@ using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -22,7 +21,7 @@ namespace Squidex.Web.CommandMiddlewares { private readonly IContextProvider contextProvider = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly Context requestContext = Context.Anonymous(); private readonly EnrichWithAppIdCommandMiddleware sut; @@ -63,32 +62,10 @@ namespace Squidex.Web.CommandMiddlewares Assert.Equal(appId, command.AppId); } - [Fact] - public async Task Should_assign_app_id_to_app_self_command() - { - var command = new ChangePlan(); - var context = Ctx(command); - - await sut.HandleAsync(context); - - Assert.Equal(appId.Id, command.AppId); - } - - [Fact] - public async Task Should_not_override_app_id() - { - var command = new ChangePlan { AppId = Guid.NewGuid() }; - var context = Ctx(command); - - await sut.HandleAsync(context); - - Assert.NotEqual(appId.Id, command.AppId); - } - [Fact] public async Task Should_not_override_app_id_and_name() { - var command = new CreateContent { AppId = NamedId.Of(Guid.NewGuid(), "other-app") }; + var command = new CreateContent { AppId = NamedId.Of(DomainId.NewGuid(), "other-app") }; var context = Ctx(command); await sut.HandleAsync(context); diff --git a/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs b/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs index 5328eb81e..d0cd29125 100644 --- a/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs @@ -9,104 +9,57 @@ using System; using System.Threading.Tasks; using FakeItEasy; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Infrastructure; -using Microsoft.AspNetCore.Routing; -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities; -using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Contents.Commands; -using Squidex.Domain.Apps.Entities.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; +using Squidex.Web.Pipeline; using Xunit; namespace Squidex.Web.CommandMiddlewares { public class EnrichWithSchemaIdCommandMiddlewareTests { - private readonly IActionContextAccessor actionContextAccessor = A.Fake(); - private readonly IAppProvider appProvider = A.Fake(); + private readonly IHttpContextAccessor httpContextAccesor = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly HttpContext httpContext = new DefaultHttpContext(); - private readonly ActionContext actionContext = new ActionContext(); private readonly EnrichWithSchemaIdCommandMiddleware sut; public EnrichWithSchemaIdCommandMiddlewareTests() { - actionContext.RouteData = new RouteData(); - actionContext.HttpContext = httpContext; + A.CallTo(() => httpContextAccesor.HttpContext) + .Returns(httpContext); - A.CallTo(() => actionContextAccessor.ActionContext) - .Returns(actionContext); - - var app = A.Fake(); - - A.CallTo(() => app.Id).Returns(appId.Id); - A.CallTo(() => app.Name).Returns(appId.Name); - - httpContext.Context().App = app; - - var schema = A.Fake(); - - A.CallTo(() => schema.Id).Returns(schemaId.Id); - A.CallTo(() => schema.SchemaDef).Returns(new Schema(schemaId.Name)); - - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Name)) - .Returns(schema); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false)) - .Returns(schema); - - sut = new EnrichWithSchemaIdCommandMiddleware(appProvider, actionContextAccessor); + sut = new EnrichWithSchemaIdCommandMiddleware(httpContextAccesor); } [Fact] public async Task Should_throw_exception_if_schema_not_found() - { - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, "other-schema")) - .Returns(Task.FromResult(null)); - - actionContext.RouteData.Values["name"] = "other-schema"; - - var command = new CreateContent { AppId = appId }; - var context = Ctx(command); - - await Assert.ThrowsAsync(() => sut.HandleAsync(context)); - } - - [Fact] - public async Task Should_do_nothing_when_route_has_no_parameter() { var command = new CreateContent(); var context = Ctx(command); - await sut.HandleAsync(context); - - Assert.Null(command.Actor); + await Assert.ThrowsAsync(() => sut.HandleAsync(context)); } [Fact] - public async Task Should_assign_schema_id_and_name_from_name() + public async Task Should_do_nothing_if_http_context_not_found() { - actionContext.RouteData.Values["name"] = schemaId.Name; + A.CallTo(() => httpContextAccesor.HttpContext) + .Returns(null!); - var command = new CreateContent { AppId = appId }; + var command = new CreateContent(); var context = Ctx(command); await sut.HandleAsync(context); - - Assert.Equal(schemaId, command.SchemaId); } [Fact] - public async Task Should_assign_schema_id_and_name_from_id() + public async Task Should_assign_schema_id_and_name_to_app_command() { - actionContext.RouteData.Values["name"] = schemaId.Id; + httpContext.Features.Set(new SchemaFeature(schemaId)); - var command = new CreateContent { AppId = appId }; + var command = new CreateContent(); var context = Ctx(command); await sut.HandleAsync(context); @@ -114,39 +67,17 @@ namespace Squidex.Web.CommandMiddlewares Assert.Equal(schemaId, command.SchemaId); } - [Fact] - public async Task Should_assign_schema_id_from_id() - { - actionContext.RouteData.Values["name"] = schemaId.Name; - - var command = new UpdateSchema(); - var context = Ctx(command); - - await sut.HandleAsync(context); - - Assert.Equal(schemaId.Id, command.SchemaId); - } - - [Fact] - public async Task Should_not_override_schema_id() - { - var command = new CreateSchema { SchemaId = Guid.NewGuid() }; - var context = Ctx(command); - - await sut.HandleAsync(context); - - Assert.NotEqual(schemaId.Id, command.SchemaId); - } - [Fact] public async Task Should_not_override_schema_id_and_name() { - var command = new CreateContent { SchemaId = NamedId.Of(Guid.NewGuid(), "other-schema") }; + httpContext.Features.Set(new SchemaFeature(schemaId)); + + var command = new CreateContent { SchemaId = NamedId.Of(DomainId.NewGuid(), "other-app") }; var context = Ctx(command); await sut.HandleAsync(context); - Assert.NotEqual(appId, command.AppId); + Assert.NotEqual(schemaId, command.SchemaId); } private CommandContext Ctx(ICommand command) diff --git a/backend/tests/Squidex.Web.Tests/Pipeline/CachingFilterTests.cs b/backend/tests/Squidex.Web.Tests/Pipeline/CachingFilterTests.cs index e44b0e2df..e68730a39 100644 --- a/backend/tests/Squidex.Web.Tests/Pipeline/CachingFilterTests.cs +++ b/backend/tests/Squidex.Web.Tests/Pipeline/CachingFilterTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; @@ -18,6 +17,7 @@ using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; +using Squidex.Infrastructure; using Squidex.Infrastructure.Security; using Xunit; @@ -212,8 +212,8 @@ namespace Squidex.Web.Pipeline [Fact] public async Task Should_append_surrogate_keys() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid().ToString(); + var id2 = DomainId.NewGuid().ToString(); cachingOptions.MaxSurrogateKeysSize = 100; @@ -231,8 +231,8 @@ namespace Squidex.Web.Pipeline [Fact] public async Task Should_append_surrogate_keys_if_just_enough_space_for_one() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid().ToString(); + var id2 = DomainId.NewGuid().ToString(); cachingOptions.MaxSurrogateKeysSize = 36; @@ -250,8 +250,8 @@ namespace Squidex.Web.Pipeline [Fact] public async Task Should_not_append_surrogate_keys_if_maximum_is_exceeded() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid().ToString(); + var id2 = DomainId.NewGuid().ToString(); cachingOptions.MaxSurrogateKeysSize = 20; @@ -269,8 +269,8 @@ namespace Squidex.Web.Pipeline [Fact] public async Task Should_not_append_surrogate_keys_if_maximum_is_overriden() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid().ToString(); + var id2 = DomainId.NewGuid().ToString(); httpContext.Request.Headers[CachingManager.SurrogateKeySizeHeader] = "20"; @@ -288,8 +288,8 @@ namespace Squidex.Web.Pipeline [Fact] public async Task Should_generate_etag_from_ids_and_versions() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid().ToString(); + var id2 = DomainId.NewGuid().ToString(); await sut.OnActionExecutionAsync(executingContext, () => { @@ -306,8 +306,8 @@ namespace Squidex.Web.Pipeline [Fact] public async Task Should_not_generate_etag_when_already_added() { - var id1 = Guid.NewGuid(); - var id2 = Guid.NewGuid(); + var id1 = DomainId.NewGuid().ToString(); + var id2 = DomainId.NewGuid().ToString(); await sut.OnActionExecutionAsync(executingContext, () => { diff --git a/backend/tests/Squidex.Web.Tests/Pipeline/SchemaResolverTests.cs b/backend/tests/Squidex.Web.Tests/Pipeline/SchemaResolverTests.cs index 30db5353e..3240ba63c 100644 --- a/backend/tests/Squidex.Web.Tests/Pipeline/SchemaResolverTests.cs +++ b/backend/tests/Squidex.Web.Tests/Pipeline/SchemaResolverTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; @@ -33,8 +32,8 @@ namespace Squidex.Web.Pipeline private readonly ActionExecutingContext actionExecutingContext; private readonly ActionExecutionDelegate next; private readonly ClaimsIdentity user = new ClaimsIdentity(); - private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly SchemaResolver sut; private bool isNextCalled; @@ -65,7 +64,7 @@ namespace Squidex.Web.Pipeline actionExecutingContext.HttpContext.Features.Set(new AppFeature(appId)); actionContext.RouteData.Values["name"] = schemaId.Id.ToString(); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false)) + A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, false)) .Returns(Task.FromResult(null)); await sut.OnActionExecutionAsync(actionExecutingContext, next); diff --git a/backend/tests/Squidex.Web.Tests/Pipeline/UsageMiddlewareTests.cs b/backend/tests/Squidex.Web.Tests/Pipeline/UsageMiddlewareTests.cs index 2cbdad475..2e23a9129 100644 --- a/backend/tests/Squidex.Web.Tests/Pipeline/UsageMiddlewareTests.cs +++ b/backend/tests/Squidex.Web.Tests/Pipeline/UsageMiddlewareTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Threading.Tasks; using FakeItEasy; using Microsoft.AspNetCore.Http; @@ -24,7 +23,7 @@ namespace Squidex.Web.Pipeline private readonly IClock clock = A.Fake(); private readonly Instant instant = SystemClock.Instance.GetCurrentInstant(); private readonly HttpContext httpContext = new DefaultHttpContext(); - private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RequestDelegate next; private readonly UsageMiddleware sut; private bool isNextCalled;