From f549ddc22db07888e110bc9c1f1c93aaa02df03b Mon Sep 17 00:00:00 2001 From: Georg von Kries Date: Mon, 1 Jul 2024 11:36:33 +0200 Subject: [PATCH 1/2] Allows deserializing the base 'Query' type in case a feature with a derived type gets deactivated. --- .../Services/QueriesDocumentUpdater.cs | 77 +++++++++++++++++++ .../OrchardCore.Queries/Startup.cs | 2 + .../OrchardCore.Queries.Abstractions/Query.cs | 11 ++- 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 src/OrchardCore.Modules/OrchardCore.Queries/Services/QueriesDocumentUpdater.cs diff --git a/src/OrchardCore.Modules/OrchardCore.Queries/Services/QueriesDocumentUpdater.cs b/src/OrchardCore.Modules/OrchardCore.Queries/Services/QueriesDocumentUpdater.cs new file mode 100644 index 00000000000..779b6b34cf4 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Queries/Services/QueriesDocumentUpdater.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Nodes; +using System.Threading.Tasks; +using OrchardCore.Documents; +using OrchardCore.Environment.Extensions; +using OrchardCore.Environment.Extensions.Features; +using OrchardCore.Environment.Shell; + +namespace OrchardCore.Queries.Services +{ + public sealed class QueriesDocumentUpdater : FeatureEventHandler + { + private readonly IDocumentManager _documentManager; + private readonly IEnumerable _querySources; + private readonly ITypeFeatureProvider _typeFeatureProvider; + + public QueriesDocumentUpdater( + IDocumentManager documentManager, + IEnumerable querySources, + ITypeFeatureProvider typeFeatureProvider) + { + _documentManager = documentManager; + _querySources = querySources; + _typeFeatureProvider = typeFeatureProvider; + } + + public override async Task EnabledAsync(IFeatureInfo feature) + { + // If the newly activated feature contains a IQuerySource, update the QueriesDocument in case that source + // type has been used before. + if (_querySources.Any(source => _typeFeatureProvider.GetFeaturesForDependency(source.GetType()).Any(f => f.Id == feature.Id))) + { + await FixupDocumentAsync(); + } + } + + private async Task FixupDocumentAsync() + { + var document = await _documentManager.GetOrCreateMutableAsync(); + + if (!ValidateDocument(document) && FixupDocument(document)) + { + await _documentManager.UpdateAsync(document); + } + } + + private bool FixupDocument(QueriesDocument document) + { + var hasChanged = false; + + // Check for any query that has no specific type information and try to fix it up with a derived type. + // The type information is lost if a user edits the document while it contains a query for a feature that + // has been disabled. + foreach (var kv in document.Queries.ToArray()) + { + var query = kv.Value; + if (query.GetType() == typeof(Query)) + { + var sample = _querySources.FirstOrDefault(x => x.Name == query.Source)?.Create(); + + if (sample != null) + { + var json = JObject.FromObject(query); + + document.Queries[kv.Key] = (Query)json.ToObject(sample.GetType()); + hasChanged = true; + } + } + } + + return hasChanged; + } + + private static bool ValidateDocument(QueriesDocument document) => document.Queries.All(kv => kv.Value.GetType() != typeof(Query)); + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Queries/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Queries/Startup.cs index 8b4b4f56893..c325b6866f8 100644 --- a/src/OrchardCore.Modules/OrchardCore.Queries/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Queries/Startup.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using OrchardCore.Deployment; using OrchardCore.DisplayManagement.Handlers; +using OrchardCore.Environment.Shell; using OrchardCore.Liquid; using OrchardCore.Modules; using OrchardCore.Navigation; @@ -26,6 +27,7 @@ public override void ConfigureServices(IServiceCollection services) { services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped, QueryDisplayDriver>(); services.AddRecipeExecutionStep(); services.AddScoped(); diff --git a/src/OrchardCore/OrchardCore.Queries.Abstractions/Query.cs b/src/OrchardCore/OrchardCore.Queries.Abstractions/Query.cs index 0d3e59062be..abe9e11a8ae 100644 --- a/src/OrchardCore/OrchardCore.Queries.Abstractions/Query.cs +++ b/src/OrchardCore/OrchardCore.Queries.Abstractions/Query.cs @@ -1,3 +1,7 @@ +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + namespace OrchardCore.Queries { /// @@ -14,6 +18,8 @@ protected Query(string source) Source = source; } + public Query() : this("Unknown") { } + /// /// Gets or sets the technical name of the query. /// @@ -22,7 +28,7 @@ protected Query(string source) /// /// Gets the name of the source for this query. /// - public string Source { get; } + public string Source { get; set; } /// /// Gets or sets the return schema of the query. @@ -31,5 +37,8 @@ protected Query(string source) public string Schema { get; set; } public virtual bool ResultsOfType() => typeof(T) == typeof(object); + + [JsonExtensionData] + public Dictionary ExtensionData { get; set; } } } From 9d900446a7f374afb18dd59d0586ecdf03da967c Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Mon, 1 Jul 2024 08:53:13 -0700 Subject: [PATCH 2/2] Fix formatting --- .../Services/QueriesDocumentUpdater.cs | 96 +++++++++---------- .../OrchardCore.Queries.Abstractions/Query.cs | 4 +- 2 files changed, 51 insertions(+), 49 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Queries/Services/QueriesDocumentUpdater.cs b/src/OrchardCore.Modules/OrchardCore.Queries/Services/QueriesDocumentUpdater.cs index 779b6b34cf4..0f6fa3d7bcc 100644 --- a/src/OrchardCore.Modules/OrchardCore.Queries/Services/QueriesDocumentUpdater.cs +++ b/src/OrchardCore.Modules/OrchardCore.Queries/Services/QueriesDocumentUpdater.cs @@ -7,71 +7,71 @@ using OrchardCore.Environment.Extensions.Features; using OrchardCore.Environment.Shell; -namespace OrchardCore.Queries.Services +namespace OrchardCore.Queries.Services; + +public sealed class QueriesDocumentUpdater : FeatureEventHandler { - public sealed class QueriesDocumentUpdater : FeatureEventHandler + private readonly IDocumentManager _documentManager; + private readonly IEnumerable _querySources; + private readonly ITypeFeatureProvider _typeFeatureProvider; + + public QueriesDocumentUpdater( + IDocumentManager documentManager, + IEnumerable querySources, + ITypeFeatureProvider typeFeatureProvider) { - private readonly IDocumentManager _documentManager; - private readonly IEnumerable _querySources; - private readonly ITypeFeatureProvider _typeFeatureProvider; + _documentManager = documentManager; + _querySources = querySources; + _typeFeatureProvider = typeFeatureProvider; + } - public QueriesDocumentUpdater( - IDocumentManager documentManager, - IEnumerable querySources, - ITypeFeatureProvider typeFeatureProvider) + public override async Task EnabledAsync(IFeatureInfo feature) + { + // If the newly activated feature contains a IQuerySource, update the QueriesDocument in case that source + // type has been used before. + if (_querySources.Any(source => _typeFeatureProvider.GetFeaturesForDependency(source.GetType()).Any(f => f.Id == feature.Id))) { - _documentManager = documentManager; - _querySources = querySources; - _typeFeatureProvider = typeFeatureProvider; + await FixupDocumentAsync(); } + } - public override async Task EnabledAsync(IFeatureInfo feature) - { - // If the newly activated feature contains a IQuerySource, update the QueriesDocument in case that source - // type has been used before. - if (_querySources.Any(source => _typeFeatureProvider.GetFeaturesForDependency(source.GetType()).Any(f => f.Id == feature.Id))) - { - await FixupDocumentAsync(); - } - } + private async Task FixupDocumentAsync() + { + var document = await _documentManager.GetOrCreateMutableAsync(); - private async Task FixupDocumentAsync() + if (!ValidateDocument(document) && FixupDocument(document)) { - var document = await _documentManager.GetOrCreateMutableAsync(); - - if (!ValidateDocument(document) && FixupDocument(document)) - { - await _documentManager.UpdateAsync(document); - } + await _documentManager.UpdateAsync(document); } + } - private bool FixupDocument(QueriesDocument document) - { - var hasChanged = false; + private bool FixupDocument(QueriesDocument document) + { + var hasChanged = false; - // Check for any query that has no specific type information and try to fix it up with a derived type. - // The type information is lost if a user edits the document while it contains a query for a feature that - // has been disabled. - foreach (var kv in document.Queries.ToArray()) + // Check for any query that has no specific type information and try to fix it up with a derived type. + // The type information is lost if a user edits the document while it contains a query for a feature that + // has been disabled. + foreach (var kv in document.Queries) + { + var query = kv.Value; + if (query.GetType() == typeof(Query)) { - var query = kv.Value; - if (query.GetType() == typeof(Query)) - { - var sample = _querySources.FirstOrDefault(x => x.Name == query.Source)?.Create(); + var sample = _querySources.FirstOrDefault(x => x.Name == query.Source)?.Create(); - if (sample != null) - { - var json = JObject.FromObject(query); + if (sample != null) + { + var json = JObject.FromObject(query); - document.Queries[kv.Key] = (Query)json.ToObject(sample.GetType()); - hasChanged = true; - } + document.Queries[kv.Key] = (Query)json.ToObject(sample.GetType()); + hasChanged = true; } } - - return hasChanged; } - private static bool ValidateDocument(QueriesDocument document) => document.Queries.All(kv => kv.Value.GetType() != typeof(Query)); + return hasChanged; } + + private static bool ValidateDocument(QueriesDocument document) + => document.Queries.All(kv => kv.Value.GetType() != typeof(Query)); } diff --git a/src/OrchardCore/OrchardCore.Queries.Abstractions/Query.cs b/src/OrchardCore/OrchardCore.Queries.Abstractions/Query.cs index abe9e11a8ae..c37579a823e 100644 --- a/src/OrchardCore/OrchardCore.Queries.Abstractions/Query.cs +++ b/src/OrchardCore/OrchardCore.Queries.Abstractions/Query.cs @@ -18,7 +18,9 @@ protected Query(string source) Source = source; } - public Query() : this("Unknown") { } + public Query() : this("Unknown") + { + } /// /// Gets or sets the technical name of the query.