diff --git a/Lombiq.HelpfulExtensions.Tests.UI/Constants/GeneratedMigrationCodes.cs b/Lombiq.HelpfulExtensions.Tests.UI/Constants/GeneratedMigrationCodes.cs index f03fda00..02626b98 100644 --- a/Lombiq.HelpfulExtensions.Tests.UI/Constants/GeneratedMigrationCodes.cs +++ b/Lombiq.HelpfulExtensions.Tests.UI/Constants/GeneratedMigrationCodes.cs @@ -1,39 +1,48 @@ -using System; +using Shouldly; +using System.Diagnostics.CodeAnalysis; namespace Lombiq.HelpfulExtensions.Tests.UI.Constants; internal static class GeneratedMigrationCodes { - // Environment.NewLine is used for this to work regardless of the mismatch of line ending style between the code - // file, the platform where it was compiled, and where it was executed. - public static string Page = - string.Join( - Environment.NewLine, - "_contentDefinitionManager.AlterTypeDefinition(\"Page\", type => type", - " .DisplayedAs(\"Page\")", - " .Creatable()", - " .Listable()", - " .Draftable()", - " .Versionable()", - " .Securable()", - " .WithPart(\"TitlePart\", part => part", - " .WithPosition(\"0\")", - " )", - " .WithPart(\"AutoroutePart\", part => part", - " .WithPosition(\"1\")", - " .WithSettings(new AutoroutePartSettings", - " {", - " AllowCustomPath = true,", - " ShowHomepageOption = true,", - " Pattern = \"{{ Model.ContentItem | display_text | slugify }}\",", - " })", - " )", - " .WithPart(\"FlowPart\", part => part", - " .WithPosition(\"2\")", - " )", - " .WithPart(\"Page\", part => part", - " .WithPosition(\"3\")", - " )", - ");", - string.Empty); + [SuppressMessage( + "Usage", + "MA0136:Raw String contains an implicit end of line character", + Justification = "It's wrapped to prevent issues related to that.")] + private const string Page = + """ + _contentDefinitionManager.AlterTypeDefinition("Page", type => type + .DisplayedAs("Page") + .Creatable() + .Listable() + .Draftable() + .Versionable() + .Securable() + .WithPart("TitlePart", part => part + .WithPosition("0") + ) + .WithPart("AutoroutePart", part => part + .WithPosition("1") + .WithSettings(new AutoroutePartSettings + { + AllowCustomPath = true, + Pattern = {{ Model.ContentItem | display_text | slugify }}, + ShowHomepageOption = true, + AllowUpdatePath = false, + AllowDisabled = false, + AllowRouteContainedItems = false, + ManageContainedItemRoutes = false, + AllowAbsolutePath = false, + }) + ) + .WithPart("FlowPart", part => part + .WithPosition("2") + ) + .WithPart("Page", part => part + .WithPosition("3") + ) + ); + """; + + public static void ShouldBePage(string actual) => actual.ShouldBeByLine(Page); } diff --git a/Lombiq.HelpfulExtensions.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs b/Lombiq.HelpfulExtensions.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs index 3765cc78..ef9a75a7 100644 --- a/Lombiq.HelpfulExtensions.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs +++ b/Lombiq.HelpfulExtensions.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs @@ -116,7 +116,8 @@ await context.RetryIfStaleOrFailAsync(async () => { await context.ClickReliablyOnAsync(By.ClassName("toggle-showing-generated-migration-code")); - context.Get(By.Id("generated-migration-code").OfAnyVisibility()).GetValue().ShouldBe(GeneratedMigrationCodes.Page); + GeneratedMigrationCodes.ShouldBePage( + context.Get(By.Id("generated-migration-code").OfAnyVisibility()).GetValue()); // Making sure that the collapsible area is open. context.Get(By.CssSelector("#generated-migration-code-container.collapse.show")); diff --git a/Lombiq.HelpfulExtensions.Tests.UI/Lombiq.HelpfulExtensions.Tests.UI.csproj b/Lombiq.HelpfulExtensions.Tests.UI/Lombiq.HelpfulExtensions.Tests.UI.csproj index ebf73a3f..4e7c80f8 100644 --- a/Lombiq.HelpfulExtensions.Tests.UI/Lombiq.HelpfulExtensions.Tests.UI.csproj +++ b/Lombiq.HelpfulExtensions.Tests.UI/Lombiq.HelpfulExtensions.Tests.UI.csproj @@ -36,7 +36,7 @@ - + diff --git a/Lombiq.HelpfulExtensions/Controllers/ContentSetController.cs b/Lombiq.HelpfulExtensions/Controllers/ContentSetController.cs index 18e73ed5..ab7a2559 100644 --- a/Lombiq.HelpfulExtensions/Controllers/ContentSetController.cs +++ b/Lombiq.HelpfulExtensions/Controllers/ContentSetController.cs @@ -7,7 +7,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.ContentSets.Controllers; [Feature(FeatureIds.ContentSets)] -public class ContentSetController : Controller +public sealed class ContentSetController : Controller { private readonly IContentSetManager _contentSetManager; private readonly IOrchardHelper _orchardHelper; diff --git a/Lombiq.HelpfulExtensions/Controllers/OrchardRecipeMigrationAdminController.cs b/Lombiq.HelpfulExtensions/Controllers/OrchardRecipeMigrationAdminController.cs index f2bf5e6f..5012ee14 100644 --- a/Lombiq.HelpfulExtensions/Controllers/OrchardRecipeMigrationAdminController.cs +++ b/Lombiq.HelpfulExtensions/Controllers/OrchardRecipeMigrationAdminController.cs @@ -16,7 +16,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.OrchardRecipeMigration.Controllers [Admin] [Feature(FeatureIds.OrchardRecipeMigration)] -public class OrchardRecipeMigrationAdminController : Controller +public sealed class OrchardRecipeMigrationAdminController : Controller { private readonly INotifier _notifier; private readonly IOrchardExportToRecipeConverter _converter; diff --git a/Lombiq.HelpfulExtensions/Extensions/CodeGeneration/CodeGenerationDisplayDriver.cs b/Lombiq.HelpfulExtensions/Extensions/CodeGeneration/CodeGenerationDisplayDriver.cs index 67edb7f2..82e1ff70 100644 --- a/Lombiq.HelpfulExtensions/Extensions/CodeGeneration/CodeGenerationDisplayDriver.cs +++ b/Lombiq.HelpfulExtensions/Extensions/CodeGeneration/CodeGenerationDisplayDriver.cs @@ -1,25 +1,29 @@ using Microsoft.Extensions.Localization; -using Newtonsoft.Json.Linq; using OrchardCore.ContentManagement.Metadata.Models; using OrchardCore.ContentManagement.Metadata.Settings; using OrchardCore.ContentTypes.Editors; +using OrchardCore.DisplayManagement.Handlers; using OrchardCore.DisplayManagement.Views; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; +using System.Text.Json.Nodes; namespace Lombiq.HelpfulExtensions.Extensions.CodeGeneration; -public class CodeGenerationDisplayDriver : ContentTypeDefinitionDisplayDriver +public sealed class CodeGenerationDisplayDriver : ContentTypeDefinitionDisplayDriver { + private const int IndentationDepth = 4; + private const string EmptyString = "\"\""; + private readonly IStringLocalizer T; public CodeGenerationDisplayDriver(IStringLocalizer stringLocalizer) => T = stringLocalizer; - public override IDisplayResult Edit(ContentTypeDefinition model) => + public override IDisplayResult Edit(ContentTypeDefinition model, BuildEditorContext context) => Initialize( "ContentTypeMigrations_Edit", viewModel => viewModel.MigrationCodeLazy = new Lazy(() => @@ -37,7 +41,7 @@ public override IDisplayResult Edit(ContentTypeDefinition model) => codeBuilder.AppendLine(CultureInfo.InvariantCulture, $" .DisplayedAs(\"{model.DisplayName}\")"); GenerateCodeForSettings(codeBuilder, model.GetSettings()); - AddSettingsWithout(codeBuilder, model.Settings, 4); + AddSettingsWithout(codeBuilder, model.Settings); GenerateCodeForParts(codeBuilder, model.Parts); codeBuilder.AppendLine(");"); @@ -63,7 +67,7 @@ private void GenerateCodeForParts(StringBuilder codeBuilder, IEnumerable(codeBuilder, part.Settings, 8); + AddSettingsWithout(codeBuilder, part.Settings, 2 * IndentationDepth); // Checking if anything was added to the part's settings. if (codeBuilder.Length == partStartingLength) @@ -102,7 +106,7 @@ private void GenerateCodeForPartsWithFields( AddWithLine(codeBuilder, nameof(partSettings.Description), partSettings.Description); AddWithLine(codeBuilder, nameof(partSettings.DefaultPosition), partSettings.DefaultPosition); - AddSettingsWithout(codeBuilder, part.Settings, 4); + AddSettingsWithout(codeBuilder, part.Settings); foreach (var field in part.Fields) { @@ -116,7 +120,7 @@ private void GenerateCodeForPartsWithFields( AddWithLine(codeBuilder, nameof(fieldSettings.DisplayMode), fieldSettings.DisplayMode); AddWithLine(codeBuilder, nameof(fieldSettings.Position), fieldSettings.Position); - AddSettingsWithout(codeBuilder, field.Settings, 8); + AddSettingsWithout(codeBuilder, field.Settings, 2 * IndentationDepth); codeBuilder.AppendLine(" )"); } @@ -125,32 +129,20 @@ private void GenerateCodeForPartsWithFields( } } - private string ConvertJToken(JToken jToken, int indentationDepth) - { - switch (jToken) + private string ConvertNode(JsonNode node, int indentationDepth) => + node switch { - case JValue jValue: - var value = jValue.Value; - return value switch - { - bool boolValue => boolValue ? "true" : "false", - string => $"\"{value}\"", - _ => value?.ToString()?.Replace(',', '.'), // Replace decimal commas. - }; - case JArray jArray: - return ConvertJArray(jArray, indentationDepth); - case JObject jObject: - return ConvertJObject(jObject, indentationDepth); - default: - throw new NotSupportedException($"Settings values of type {jToken.GetType()} are not supported."); - } - } + JsonValue jsonValue => jsonValue.ToString(), + JsonArray jsonArray => ConvertJsonArray(jsonArray, indentationDepth), + JsonObject jsonObject => ConvertJsonObject(jsonObject, indentationDepth), + _ => throw new NotSupportedException($"Settings values of type {node.GetType()} are not supported."), + }; - private string ConvertJArray(JArray jArray, int indentationDepth) + private string ConvertJsonArray(JsonArray jArray, int indentationDepth) { - var indentation = new string(' ', indentationDepth + 4); + var indentation = new string(' ', indentationDepth + IndentationDepth); - var items = jArray.Select(item => ConvertJToken(item, indentationDepth + 8)).ToList(); + var items = jArray.Select(item => ConvertNode(item, indentationDepth + (2 * IndentationDepth))).ToList(); // If the items are formatted (for ListValueOption) then don't inject line-by-line formatting. if (items.Exists(item => item.ContainsOrdinalIgnoreCase(Environment.NewLine))) @@ -164,7 +156,7 @@ private string ConvertJArray(JArray jArray, int indentationDepth) stringArrayCodeBuilder.AppendLine(); stringArrayCodeBuilder.AppendLine(CultureInfo.InvariantCulture, $"{indentation}{{"); - var itemIndentation = new string(' ', indentationDepth + 8); + var itemIndentation = new string(' ', indentationDepth + (2 * IndentationDepth)); foreach (var item in items) { @@ -176,53 +168,46 @@ private string ConvertJArray(JArray jArray, int indentationDepth) return stringArrayCodeBuilder.ToString(); } - private string ConvertJObject(JObject jObject, int indentationDepth) + private string ConvertJsonObject(JsonObject jsonObject, int indentationDepth) { var braceIndentation = new string(' ', indentationDepth); - var propertyIndentation = new string(' ', indentationDepth + 4); - if (jObject["name"] != null && jObject["value"] != null) + var propertyIndentation = new string(' ', indentationDepth + IndentationDepth); + if (jsonObject["name"] is { } name && jsonObject["value"] is { } value) { var objectCodeBuilder = new StringBuilder(); objectCodeBuilder.AppendLine(CultureInfo.InvariantCulture, $"{braceIndentation}new ListValueOption"); objectCodeBuilder.AppendLine(CultureInfo.InvariantCulture, $"{braceIndentation}{{"); - objectCodeBuilder.AppendLine(CultureInfo.InvariantCulture, $"{propertyIndentation}Name = \"{jObject["name"]}\","); - objectCodeBuilder.AppendLine(CultureInfo.InvariantCulture, $"{propertyIndentation}Value = \"{jObject["value"]}\","); + objectCodeBuilder.AppendLine(CultureInfo.InvariantCulture, $"{propertyIndentation}Name = \"{name}\","); + objectCodeBuilder.AppendLine(CultureInfo.InvariantCulture, $"{propertyIndentation}Value = \"{value}\","); objectCodeBuilder.AppendLine(CultureInfo.InvariantCulture, $"{braceIndentation}}},"); return objectCodeBuilder.ToString(); } // Using a quoted string so it doesn't mess up the syntax highlighting of the rest of the code. - return T["\"FIX ME! Couldn't determine the actual type to instantiate.\" {0}", jObject.ToString()]; + return T["\"FIX ME! Couldn't determine the actual type to instantiate.\" {0}", jsonObject.ToString()]; } - private void AddSettingsWithout(StringBuilder codeBuilder, JObject settings, int indentationDepth) + private void AddSettingsWithout(StringBuilder codeBuilder, JsonObject settings, int indentationDepth = IndentationDepth) { var indentation = new string(' ', indentationDepth); - var filteredSettings = ((IEnumerable>)settings) - .Where(setting => setting.Key != typeof(T).Name); + var filteredSettings = settings + .Where(pair => pair.Key != typeof(T).Name && pair.Value is JsonObject) + .Select(pair => (pair.Key, (JsonObject)pair.Value)); - foreach (var setting in filteredSettings) + foreach (var (typeName, properties) in filteredSettings) { - var properties = setting.Value.Where(property => property is JProperty).Cast().ToArray(); + if (properties.Count == 0) continue; - if (properties.Length == 0) continue; - - codeBuilder.AppendLine(CultureInfo.InvariantCulture, $"{indentation}.WithSettings(new {setting.Key}"); + codeBuilder.AppendLine(CultureInfo.InvariantCulture, $"{indentation}.WithSettings(new {typeName}"); codeBuilder.AppendLine(indentation + "{"); - // This doesn't support multi-level object hierarchies for settings but come on, who uses complex settings - // objects? - for (int i = 0; i < properties.Length; i++) + foreach (var (name, value) in properties) { - var property = properties[i]; - - var propertyValue = ConvertJToken(property.Value, indentationDepth); - - propertyValue ??= "\"\""; - - codeBuilder.AppendLine(CultureInfo.InvariantCulture, $"{indentation} {property.Name} = {propertyValue},"); + codeBuilder.AppendLine( + CultureInfo.InvariantCulture, + $"{indentation} {name} = {ConvertNode(value, indentationDepth) ?? EmptyString},"); } codeBuilder.AppendLine(indentation + "})"); diff --git a/Lombiq.HelpfulExtensions/Extensions/CodeGeneration/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/CodeGeneration/Startup.cs index 7bc42fed..7efbe83b 100644 --- a/Lombiq.HelpfulExtensions/Extensions/CodeGeneration/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/CodeGeneration/Startup.cs @@ -8,7 +8,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.CodeGeneration; [Feature(FeatureIds.CodeGeneration)] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) => services.AddScoped(); diff --git a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Drivers/ContentSetContentPickerFieldDisplayDriver.cs b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Drivers/ContentSetContentPickerFieldDisplayDriver.cs index dfe278f0..afbf003f 100644 --- a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Drivers/ContentSetContentPickerFieldDisplayDriver.cs +++ b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Drivers/ContentSetContentPickerFieldDisplayDriver.cs @@ -14,7 +14,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.ContentSets.Drivers; -public class ContentSetContentPickerFieldDisplayDriver : ContentFieldDisplayDriver +public sealed class ContentSetContentPickerFieldDisplayDriver : ContentFieldDisplayDriver { private readonly IContentDefinitionManager _contentDefinitionManager; private readonly IContentSetManager _contentSetManager; diff --git a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Drivers/ContentSetPartDisplayDriver.cs b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Drivers/ContentSetPartDisplayDriver.cs index 9b7f7cf1..7642a5ef 100644 --- a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Drivers/ContentSetPartDisplayDriver.cs +++ b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Drivers/ContentSetPartDisplayDriver.cs @@ -6,7 +6,7 @@ using Microsoft.Extensions.Localization; using OrchardCore.ContentManagement.Display.ContentDisplay; using OrchardCore.ContentManagement.Display.Models; -using OrchardCore.DisplayManagement.ModelBinding; +using OrchardCore.DisplayManagement.Handlers; using OrchardCore.DisplayManagement.Views; using OrchardCore.Entities; using System.Collections.Generic; @@ -14,7 +14,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.ContentSets.Drivers; -public class ContentSetPartDisplayDriver : ContentPartDisplayDriver +public sealed class ContentSetPartDisplayDriver : ContentPartDisplayDriver { private const string ShapeType = $"{nameof(ContentSetPart)}_{CommonContentDisplayTypes.SummaryAdmin}"; @@ -64,23 +64,17 @@ public override IDisplayResult Edit(ContentSetPart part, BuildPartEditorContext context.IsNew)) .Location($"Parts:0%{context.TypePartDefinition.Name};0"); - public override async Task UpdateAsync( - ContentSetPart part, - IUpdateModel updater, - UpdatePartEditorContext context) + public override async Task UpdateAsync(ContentSetPart part, UpdatePartEditorContext context) { - var viewModel = new ContentSetPartViewModel(); + var viewModel = await context.CreateModelAsync(Prefix); - if (await updater.TryUpdateModelAsync(viewModel, Prefix)) - { - part.Key = viewModel.Key; + part.Key = viewModel.Key; - // Need to do this here to support displaying the message to save before adding when the - // item has not been saved yet. - if (string.IsNullOrEmpty(part.ContentSet)) - { - part.ContentSet = _idGenerator.GenerateUniqueId(); - } + // Need to do this here to support displaying the message to save before adding when the item has not been saved + // yet. + if (string.IsNullOrEmpty(part.ContentSet)) + { + part.ContentSet = _idGenerator.GenerateUniqueId(); } return await EditAsync(part, context); diff --git a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Migrations.cs b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Migrations.cs index 46c3a4c4..d6285494 100644 --- a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Migrations.cs +++ b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Migrations.cs @@ -9,7 +9,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.ContentSets; -public class Migrations : DataMigration +public sealed class Migrations : DataMigration { private readonly IContentDefinitionManager _contentDefinitionManager; diff --git a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Startup.cs index ecb4456f..76136cc0 100644 --- a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Startup.cs @@ -13,7 +13,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.ContentSets; [Feature(FeatureIds.ContentSets)] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) { diff --git a/Lombiq.HelpfulExtensions/Extensions/ContentSets/ViewModels/ContentSetPartViewModel.cs b/Lombiq.HelpfulExtensions/Extensions/ContentSets/ViewModels/ContentSetPartViewModel.cs index 81bfca84..2ba3221a 100644 --- a/Lombiq.HelpfulExtensions/Extensions/ContentSets/ViewModels/ContentSetPartViewModel.cs +++ b/Lombiq.HelpfulExtensions/Extensions/ContentSets/ViewModels/ContentSetPartViewModel.cs @@ -8,6 +8,7 @@ using OrchardCore.ContentManagement.Metadata.Settings; using System.Collections.Generic; using System.Linq; +using System.Text.Json.Nodes; using System.Threading.Tasks; namespace Lombiq.HelpfulExtensions.Extensions.ContentSets.ViewModels; @@ -33,8 +34,7 @@ public class ContentSetPartViewModel public string DisplayName => Definition? .Settings? - .Property(nameof(ContentTypePartSettings))? - .Value + .GetMaybe(nameof(ContentTypePartSettings))? .ToObject()? .DisplayName ?? Definition?.Name; diff --git a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Drivers/ContentSetCreatingEventDisplayDriver.cs b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Drivers/ContentSetCreatingEventDisplayDriver.cs index e452782e..85f209de 100644 --- a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Drivers/ContentSetCreatingEventDisplayDriver.cs +++ b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Drivers/ContentSetCreatingEventDisplayDriver.cs @@ -10,7 +10,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.ContentSets.Workflows.Drivers; -public class ContentSetCreatingEventDisplayDriver : DocumentedEventActivityDisplayDriverBase +public sealed class ContentSetCreatingEventDisplayDriver : DocumentedEventActivityDisplayDriverBase { private readonly IHtmlLocalizer H; diff --git a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Drivers/ContentSetGetSupportedOptionsEventDisplayDriver.cs b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Drivers/ContentSetGetSupportedOptionsEventDisplayDriver.cs index b1bcd1df..78cf7529 100644 --- a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Drivers/ContentSetGetSupportedOptionsEventDisplayDriver.cs +++ b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Drivers/ContentSetGetSupportedOptionsEventDisplayDriver.cs @@ -12,7 +12,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.ContentSets.Workflows.Drivers; -public class ContentSetGetSupportedOptionsEventDisplayDriver : +public sealed class ContentSetGetSupportedOptionsEventDisplayDriver : DocumentedEventActivityDisplayDriverBase { private readonly IHtmlLocalizer H; diff --git a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Handlers/WorkflowContentSetEventHandler.cs b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Handlers/WorkflowContentSetEventHandler.cs index f7e34c3b..91621e9d 100644 --- a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Handlers/WorkflowContentSetEventHandler.cs +++ b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Handlers/WorkflowContentSetEventHandler.cs @@ -4,8 +4,6 @@ using Lombiq.HelpfulExtensions.Extensions.ContentSets.Workflows.Activities; using Lombiq.HelpfulExtensions.Extensions.ContentSets.Workflows.Models; using Lombiq.HelpfulLibraries.OrchardCore.Workflow; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using OrchardCore.ContentManagement; using OrchardCore.ContentManagement.Metadata.Models; using OrchardCore.Workflows.Models; @@ -13,6 +11,8 @@ using System.Collections.Generic; using System.Dynamic; using System.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; using System.Threading.Tasks; namespace Lombiq.HelpfulExtensions.Extensions.ContentSets.Workflows.Handlers; @@ -54,14 +54,16 @@ public async Task> GetSupportedOptionsAsync case ContentSetLinkViewModel viewModel: links.Add(viewModel); break; - case IEnumerable collection when collection.CastWhere() is { } objects && objects.Any(): - links.AddRange(JToken.FromObject(objects).ToObject>()); - break; case ExpandoObject expandoObject: - links.Add(JToken.FromObject(expandoObject).ToObject()); + links.Add(SerializeAndDeserialize(expandoObject)); + break; + case IEnumerable collection when + collection.CastWhere().ToList() is { } objects && + objects.Count != 0: + links.AddRange(SerializeAndDeserialize>(objects)); break; case string json when !string.IsNullOrWhiteSpace(json): - links.AddRange(JsonConvert.DeserializeObject>(json)); + links.AddRange(JsonSerializer.Deserialize>(json)); break; default: continue; } @@ -79,4 +81,7 @@ public Task CreatingAsync( new CreatingContext(content, definition, contentSet, newKey), $"{nameof(WorkflowContentSetEventHandler)}.{nameof(CreatingAsync)}" + $"({content.ContentItemId}, {definition.Name}, {contentSet}, {newKey})"); + + private static T SerializeAndDeserialize(object source) => + JNode.FromObject(source).ToObject(); } diff --git a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Startup.cs index 1d8a7e8b..7b186714 100644 --- a/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/ContentSets/Workflows/Startup.cs @@ -10,7 +10,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.ContentSets.Workflows; [Feature(FeatureIds.ContentSets)] [RequireFeatures("OrchardCore.Workflows")] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) { diff --git a/Lombiq.HelpfulExtensions/Extensions/ContentTypes/Migrations.cs b/Lombiq.HelpfulExtensions/Extensions/ContentTypes/Migrations.cs index 946d2380..c787a166 100644 --- a/Lombiq.HelpfulExtensions/Extensions/ContentTypes/Migrations.cs +++ b/Lombiq.HelpfulExtensions/Extensions/ContentTypes/Migrations.cs @@ -7,7 +7,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.ContentTypes; -public class Migrations : DataMigration +public sealed class Migrations : DataMigration { private readonly IContentDefinitionManager _contentDefinitionManager; diff --git a/Lombiq.HelpfulExtensions/Extensions/ContentTypes/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/ContentTypes/Startup.cs index fda56a78..a61e8105 100644 --- a/Lombiq.HelpfulExtensions/Extensions/ContentTypes/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/ContentTypes/Startup.cs @@ -8,7 +8,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.ContentTypes; [Feature(FeatureIds.ContentTypes)] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) => services.AddDataMigration(); diff --git a/Lombiq.HelpfulExtensions/Extensions/Emails/Extensions/EmailSenderShellScopeExtensions.cs b/Lombiq.HelpfulExtensions/Extensions/Emails/Extensions/EmailSenderShellScopeExtensions.cs index 0b3dd43f..d6629e1e 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Emails/Extensions/EmailSenderShellScopeExtensions.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Emails/Extensions/EmailSenderShellScopeExtensions.cs @@ -18,8 +18,8 @@ public static class EmailSenderShellScopeExtensions public static void SendEmailDeferred(this ShellScope shellScope, EmailParameters parameters) => shellScope.AddDeferredTask(async scope => { - var smtpService = scope.ServiceProvider.GetRequiredService(); - var result = await smtpService.SendAsync(new MailMessage + var emailService = scope.ServiceProvider.GetRequiredService(); + var result = await emailService.SendAsync(new MailMessage { Sender = parameters.Sender, To = parameters.To?.Join(","), diff --git a/Lombiq.HelpfulExtensions/Extensions/Emails/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/Emails/Startup.cs index 6af711be..35a68ed3 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Emails/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Emails/Startup.cs @@ -9,7 +9,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.Emails; [Feature(FeatureIds.Emails)] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) { diff --git a/Lombiq.HelpfulExtensions/Extensions/Flows/Drivers/AdditionalStylingPartDisplay.cs b/Lombiq.HelpfulExtensions/Extensions/Flows/Drivers/AdditionalStylingPartDisplay.cs index f53d18f6..a106123a 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Flows/Drivers/AdditionalStylingPartDisplay.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Flows/Drivers/AdditionalStylingPartDisplay.cs @@ -1,21 +1,21 @@ using Lombiq.HelpfulExtensions.Extensions.Flows.Models; using OrchardCore.ContentManagement; using OrchardCore.ContentManagement.Display.ContentDisplay; -using OrchardCore.DisplayManagement.ModelBinding; +using OrchardCore.DisplayManagement.Handlers; using OrchardCore.DisplayManagement.Views; using System.Threading.Tasks; namespace Lombiq.HelpfulExtensions.Extensions.Flows.Drivers; -public class AdditionalStylingPartDisplay : ContentDisplayDriver +public sealed class AdditionalStylingPartDisplay : ContentDisplayDriver { - public override IDisplayResult Edit(ContentItem model, IUpdateModel updater) => + public override IDisplayResult Edit(ContentItem model, BuildEditorContext context) => Initialize( $"{nameof(AdditionalStylingPart)}_Edit", viewModel => PopulateViewModel(model, viewModel)) .PlaceInZone("Footer", 3); - public override async Task UpdateAsync(ContentItem model, IUpdateModel updater) + public override async Task UpdateAsync(ContentItem model, UpdateEditorContext context) { var additionalStylingPart = model.As(); @@ -24,9 +24,9 @@ public override async Task UpdateAsync(ContentItem model, IUpdat return null; } - await model.AlterAsync(model => updater.TryUpdateModelAsync(model, Prefix)); + await model.AlterAsync(model => context.Updater.TryUpdateModelAsync(model, Prefix)); - return await EditAsync(model, updater); + return await EditAsync(model, context); } private static void PopulateViewModel(ContentItem model, AdditionalStylingPart viewModel) diff --git a/Lombiq.HelpfulExtensions/Extensions/Flows/FlowPartShapeTableProvider.cs b/Lombiq.HelpfulExtensions/Extensions/Flows/FlowPartShapeTableProvider.cs index bd729f62..10464bfc 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Flows/FlowPartShapeTableProvider.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Flows/FlowPartShapeTableProvider.cs @@ -1,10 +1,16 @@ using OrchardCore.DisplayManagement.Descriptors; +using System.Threading.Tasks; namespace Lombiq.HelpfulExtensions.Extensions.Flows; internal sealed class FlowPartShapeTableProvider : IShapeTableProvider { - public void Discover(ShapeTableBuilder builder) => builder - .Describe("FlowPart") - .OnDisplaying(displaying => displaying.Shape.Metadata.Alternates.Add("Lombiq_HelpfulExtensions_Flows_FlowPart")); + public ValueTask DiscoverAsync(ShapeTableBuilder builder) + { + builder + .Describe("FlowPart") + .OnDisplaying(displaying => displaying.Shape.Metadata.Alternates.Add("Lombiq_HelpfulExtensions_Flows_FlowPart")); + + return ValueTask.CompletedTask; + } } diff --git a/Lombiq.HelpfulExtensions/Extensions/Flows/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/Flows/Startup.cs index 3bcc4430..45dea147 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Flows/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Flows/Startup.cs @@ -14,7 +14,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.Flows; [Feature(FeatureIds.Flows)] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) { diff --git a/Lombiq.HelpfulExtensions/Extensions/GoogleTag/GoogleTagLiquidParserTag.cs b/Lombiq.HelpfulExtensions/Extensions/GoogleTag/GoogleTagLiquidParserTag.cs new file mode 100644 index 00000000..303f7969 --- /dev/null +++ b/Lombiq.HelpfulExtensions/Extensions/GoogleTag/GoogleTagLiquidParserTag.cs @@ -0,0 +1,50 @@ +using Fluid; +using Fluid.Ast; +using Fluid.Values; +using Lombiq.HelpfulLibraries.OrchardCore.Liquid; +using OrchardCore.DisplayManagement.Liquid.Tags; +using System.Collections.Generic; +using System.IO; +using System.Text.Encodings.Web; +using System.Threading.Tasks; + +namespace Lombiq.HelpfulExtensions.Extensions.GoogleTag; + +public class GoogleTagLiquidParserTag : ILiquidParserTag +{ + public async ValueTask WriteToAsync( + IReadOnlyList argumentsList, + TextWriter writer, + TextEncoder encoder, + TemplateContext context) + { + var arguments = new List + { + new(null, new LiteralExpression(new StringValue(GoogleTagViewModel.ShapeType))), + }; + + foreach (var argument in argumentsList) + { + if (argument.Name == "property_id") + { + await AddStringAsync(arguments, nameof(GoogleTagViewModel.GoogleTagPropertyId), argument, context); + } + else if (argument.Name == "cookie_domain") + { + await AddStringAsync(arguments, nameof(GoogleTagViewModel.CookieDomain), argument, context); + } + } + + return await ShapeTag.WriteToAsync(arguments, writer, encoder, context); + } + + private static async Task AddStringAsync( + List arguments, + string newName, + FilterArgument argument, + TemplateContext context) + { + var newValue = await argument.Expression.EvaluateAsync(context); + arguments.Add(new(newName, new LiteralExpression(newValue))); + } +} diff --git a/Lombiq.HelpfulExtensions/Extensions/GoogleTag/GoogleTagTagHelper.cs b/Lombiq.HelpfulExtensions/Extensions/GoogleTag/GoogleTagTagHelper.cs new file mode 100644 index 00000000..366e8694 --- /dev/null +++ b/Lombiq.HelpfulExtensions/Extensions/GoogleTag/GoogleTagTagHelper.cs @@ -0,0 +1,26 @@ +using Lombiq.HelpfulLibraries.OrchardCore.TagHelpers; +using Microsoft.AspNetCore.Razor.TagHelpers; +using OrchardCore.DisplayManagement; +using System.Threading.Tasks; + +namespace Lombiq.HelpfulExtensions.Extensions.GoogleTag; + +[HtmlTargetElement("google-tag")] +public class GoogleTagTagHelper : ShapeTagHelperBase +{ + [HtmlAttributeName("property-id")] + public string PropertyId { get; set; } + + [HtmlAttributeName("cookie-domain")] + public string CookieDomain { get; set; } + + public GoogleTagTagHelper(IDisplayHelper displayHelper, IShapeFactory shapeFactory) + : base(displayHelper, shapeFactory) + { + } + + protected override string ShapeType => GoogleTagViewModel.ShapeType; + + protected override ValueTask GetViewModelAsync(TagHelperContext context, TagHelperOutput output) => + ValueTask.FromResult(new GoogleTagViewModel(PropertyId, CookieDomain)); +} diff --git a/Lombiq.HelpfulExtensions/Extensions/GoogleTag/GoogleTagViewModel.cs b/Lombiq.HelpfulExtensions/Extensions/GoogleTag/GoogleTagViewModel.cs new file mode 100644 index 00000000..8064e1c3 --- /dev/null +++ b/Lombiq.HelpfulExtensions/Extensions/GoogleTag/GoogleTagViewModel.cs @@ -0,0 +1,20 @@ +using OrchardCore.DisplayManagement.Views; + +namespace Lombiq.HelpfulExtensions.Extensions.GoogleTag; + +public class GoogleTagViewModel : ShapeViewModel +{ + public const string ShapeType = "GoogleTag"; + + public string GoogleTagPropertyId { get; set; } + public string CookieDomain { get; set; } + + public GoogleTagViewModel() => Metadata.Type = ShapeType; + + public GoogleTagViewModel(string googleTagPropertyId, string cookieDomain) + : this() + { + GoogleTagPropertyId = googleTagPropertyId; + CookieDomain = cookieDomain; + } +} diff --git a/Lombiq.HelpfulExtensions/Extensions/GoogleTag/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/GoogleTag/Startup.cs new file mode 100644 index 00000000..ca3e1429 --- /dev/null +++ b/Lombiq.HelpfulExtensions/Extensions/GoogleTag/Startup.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.DependencyInjection; +using OrchardCore.Modules; + +namespace Lombiq.HelpfulExtensions.Extensions.GoogleTag; + +[Feature(FeatureIds.GoogleTag)] +public sealed class Startup : StartupBase +{ + public override void ConfigureServices(IServiceCollection services) + { + services.AddTagHelpers(); + services.AddLiquidParserTag("google_tag"); + } +} diff --git a/Lombiq.HelpfulExtensions/Extensions/OrchardRecipeMigration/Navigation/AdminMenu.cs b/Lombiq.HelpfulExtensions/Extensions/OrchardRecipeMigration/Navigation/AdminMenu.cs index 3ada4e8a..c745bdc8 100644 --- a/Lombiq.HelpfulExtensions/Extensions/OrchardRecipeMigration/Navigation/AdminMenu.cs +++ b/Lombiq.HelpfulExtensions/Extensions/OrchardRecipeMigration/Navigation/AdminMenu.cs @@ -8,7 +8,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.OrchardRecipeMigration.Navigation; -public class AdminMenu : INavigationProvider +public sealed class AdminMenu : INavigationProvider { private readonly IHttpContextAccessor _hca; private readonly IStringLocalizer T; @@ -19,9 +19,9 @@ public AdminMenu(IHttpContextAccessor hca, IStringLocalizer stringLoc T = stringLocalizer; } - public Task BuildNavigationAsync(string name, NavigationBuilder builder) + public ValueTask BuildNavigationAsync(string name, NavigationBuilder builder) { - if (!name.EqualsOrdinalIgnoreCase("admin")) return Task.CompletedTask; + if (!name.EqualsOrdinalIgnoreCase("admin")) return ValueTask.CompletedTask; builder.Add(T["Configuration"], configuration => configuration .Add(T["Import/Export"], importExport => importExport @@ -30,6 +30,6 @@ public Task BuildNavigationAsync(string name, NavigationBuilder builder) .LocalNav() ))); - return Task.CompletedTask; + return ValueTask.CompletedTask; } } diff --git a/Lombiq.HelpfulExtensions/Extensions/OrchardRecipeMigration/Services/OrchardExportToRecipeConverter.cs b/Lombiq.HelpfulExtensions/Extensions/OrchardRecipeMigration/Services/OrchardExportToRecipeConverter.cs index 6c13dcef..42290669 100644 --- a/Lombiq.HelpfulExtensions/Extensions/OrchardRecipeMigration/Services/OrchardExportToRecipeConverter.cs +++ b/Lombiq.HelpfulExtensions/Extensions/OrchardRecipeMigration/Services/OrchardExportToRecipeConverter.cs @@ -1,4 +1,3 @@ -using Newtonsoft.Json.Linq; using OrchardCore.ContentManagement; using OrchardCore.ContentManagement.Metadata; using OrchardCore.Entities; @@ -6,6 +5,7 @@ using OrchardCore.Users.Models; using System.Collections.Generic; using System.Linq; +using System.Text.Json.Nodes; using System.Threading.Tasks; using System.Xml.Linq; using System.Xml.XPath; @@ -72,8 +72,8 @@ await _contentConverters await converter.UpdateContentItemsAsync(export, contentItems); } - var recipe = JObject.FromObject(new RecipeDescriptor()); - recipe["steps"] = JArray.FromObject(new[] { new { name = "content", data = contentItems } }); + var recipe = JObject.FromObject(new RecipeDescriptor())!; + recipe["steps"] = JObject.FromObject(new[] { new { name = "content", data = contentItems } }); return recipe.ToString(); } diff --git a/Lombiq.HelpfulExtensions/Extensions/OrchardRecipeMigration/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/OrchardRecipeMigration/Startup.cs index fedf1f51..88cfcb6d 100644 --- a/Lombiq.HelpfulExtensions/Extensions/OrchardRecipeMigration/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/OrchardRecipeMigration/Startup.cs @@ -7,7 +7,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.OrchardRecipeMigration; [Feature(FeatureIds.OrchardRecipeMigration)] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) { @@ -17,6 +17,6 @@ public override void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddScoped(); - services.AddScoped(); + services.AddNavigationProvider(); } } diff --git a/Lombiq.HelpfulExtensions/Extensions/Security/Driver/StrictSecuritySettingsDisplayDriver.cs b/Lombiq.HelpfulExtensions/Extensions/Security/Driver/StrictSecuritySettingsDisplayDriver.cs index f3b60b79..2d4e1c35 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Security/Driver/StrictSecuritySettingsDisplayDriver.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Security/Driver/StrictSecuritySettingsDisplayDriver.cs @@ -3,14 +3,15 @@ using OrchardCore.ContentManagement.Metadata.Models; using OrchardCore.ContentManagement.Metadata.Settings; using OrchardCore.ContentTypes.Editors; +using OrchardCore.DisplayManagement.Handlers; using OrchardCore.DisplayManagement.Views; using System.Threading.Tasks; namespace Lombiq.HelpfulExtensions.Extensions.Security.Driver; -public class StrictSecuritySettingsDisplayDriver : ContentTypeDefinitionDisplayDriver +public sealed class StrictSecuritySettingsDisplayDriver : ContentTypeDefinitionDisplayDriver { - public override IDisplayResult Edit(ContentTypeDefinition model) => + public override IDisplayResult Edit(ContentTypeDefinition model, BuildEditorContext context) => Initialize("StrictSecuritySetting_Edit", viewModel => { var settings = model.GetSettings(); @@ -20,16 +21,13 @@ public override IDisplayResult Edit(ContentTypeDefinition model) => public override async Task UpdateAsync(ContentTypeDefinition model, UpdateTypeEditorContext context) { - var viewModel = new StrictSecuritySettingsViewModel(); + var viewModel = await context.CreateModelAsync(Prefix); - if (await context.Updater.TryUpdateModelAsync(viewModel, Prefix)) - { - // Securable must be enabled for Strict Securable to make sense. Also checked on the client side too. - if (model.GetSettings()?.Securable != true) viewModel.Enabled = false; + // Securable must be enabled for Strict Securable to make sense. Also checked on the client side too. + if (model.GetSettings()?.Securable != true) viewModel.Enabled = false; - context.Builder.MergeSettings(settings => settings.Enabled = viewModel.Enabled); - } + context.Builder.MergeSettings(settings => settings.Enabled = viewModel.Enabled); - return Edit(model); + return await EditAsync(model, context); } } diff --git a/Lombiq.HelpfulExtensions/Extensions/Security/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/Security/Startup.cs index 2afd37e9..26f68d29 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Security/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Security/Startup.cs @@ -9,7 +9,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.Security; [Feature(FeatureIds.Security)] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) { diff --git a/Lombiq.HelpfulExtensions/Extensions/ShapeTracing/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/ShapeTracing/Startup.cs index 288ae47c..7cd3b0e3 100644 --- a/Lombiq.HelpfulExtensions/Extensions/ShapeTracing/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/ShapeTracing/Startup.cs @@ -5,7 +5,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.ShapeTracing; [Feature(FeatureIds.ShapeTracing)] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) => services.AddScoped(); diff --git a/Lombiq.HelpfulExtensions/Extensions/SiteTexts/LocalizationMigrations.cs b/Lombiq.HelpfulExtensions/Extensions/SiteTexts/LocalizationMigrations.cs index f52bdd82..9f2ea27c 100644 --- a/Lombiq.HelpfulExtensions/Extensions/SiteTexts/LocalizationMigrations.cs +++ b/Lombiq.HelpfulExtensions/Extensions/SiteTexts/LocalizationMigrations.cs @@ -6,7 +6,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.SiteTexts; -public class LocalizationMigrations : DataMigration +public sealed class LocalizationMigrations : DataMigration { private readonly IContentDefinitionManager _contentDefinitionManager; diff --git a/Lombiq.HelpfulExtensions/Extensions/SiteTexts/SiteTextMigrations.cs b/Lombiq.HelpfulExtensions/Extensions/SiteTexts/SiteTextMigrations.cs index b7fb7ffe..444e3dca 100644 --- a/Lombiq.HelpfulExtensions/Extensions/SiteTexts/SiteTextMigrations.cs +++ b/Lombiq.HelpfulExtensions/Extensions/SiteTexts/SiteTextMigrations.cs @@ -10,7 +10,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.SiteTexts; -public class SiteTextMigrations : DataMigration +public sealed class SiteTextMigrations : DataMigration { private readonly IContentDefinitionManager _contentDefinitionManager; diff --git a/Lombiq.HelpfulExtensions/Extensions/SiteTexts/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/SiteTexts/Startup.cs index 36b3bf94..0cd92cb8 100644 --- a/Lombiq.HelpfulExtensions/Extensions/SiteTexts/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/SiteTexts/Startup.cs @@ -6,7 +6,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.SiteTexts; [Feature(FeatureIds.SiteTexts)] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) { @@ -17,11 +17,11 @@ public override void ConfigureServices(IServiceCollection services) } [RequireFeatures("OrchardCore.ContentLocalization")] -public class ContentLocalizationStartup : StartupBase +public sealed class ContentLocalizationStartup : StartupBase { public override void ConfigureServices(IServiceCollection services) { - services.RemoveImplementations(); + services.RemoveImplementationsOf(); services.AddScoped(); } } diff --git a/Lombiq.HelpfulExtensions/Extensions/TargetBlank/Filters/TargetBlankFilter.cs b/Lombiq.HelpfulExtensions/Extensions/TargetBlank/Filters/TargetBlankFilter.cs index d89bfc13..79204157 100644 --- a/Lombiq.HelpfulExtensions/Extensions/TargetBlank/Filters/TargetBlankFilter.cs +++ b/Lombiq.HelpfulExtensions/Extensions/TargetBlank/Filters/TargetBlankFilter.cs @@ -6,7 +6,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.TargetBlank.Filters; -public class TargetBlankFilter : IAsyncResultFilter +public sealed class TargetBlankFilter : IAsyncResultFilter { private readonly IResourceManager _resourceManager; diff --git a/Lombiq.HelpfulExtensions/Extensions/TargetBlank/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/TargetBlank/Startup.cs index 4cab442a..3af621a0 100644 --- a/Lombiq.HelpfulExtensions/Extensions/TargetBlank/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/TargetBlank/Startup.cs @@ -11,7 +11,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.TargetBlank; [Feature(FeatureIds.TargetBlank)] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) { diff --git a/Lombiq.HelpfulExtensions/Extensions/Trumbowyg/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/Trumbowyg/Startup.cs index 339ac552..64a1b050 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Trumbowyg/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Trumbowyg/Startup.cs @@ -6,7 +6,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.Trumbowyg; [Feature(FeatureIds.Trumbowyg)] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) => services.AddTransient, TrumbowygResourceManagementOptionsConfiguration>(); diff --git a/Lombiq.HelpfulExtensions/Extensions/Trumbowyg/TrumbowygResourceManagementOptionsConfiguration.cs b/Lombiq.HelpfulExtensions/Extensions/Trumbowyg/TrumbowygResourceManagementOptionsConfiguration.cs index eb026898..d9a76a60 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Trumbowyg/TrumbowygResourceManagementOptionsConfiguration.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Trumbowyg/TrumbowygResourceManagementOptionsConfiguration.cs @@ -1,11 +1,9 @@ using Microsoft.Extensions.Options; -using OrchardCore.Modules; using OrchardCore.ResourceManagement; using static Lombiq.HelpfulExtensions.Constants.ResourceNames; namespace Lombiq.HelpfulExtensions.Extensions.Trumbowyg; -[Feature(FeatureIds.Trumbowyg)] public class TrumbowygResourceManagementOptionsConfiguration : IConfigureOptions { private const string WwwRoot = "~/" + FeatureIds.Base + "/"; diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/ConditionDisplayDriver.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/ConditionDisplayDriver.cs index 2143a528..2408be61 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/ConditionDisplayDriver.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/ConditionDisplayDriver.cs @@ -10,12 +10,12 @@ namespace Lombiq.HelpfulExtensions.Extensions.Widgets.Drivers; public abstract class ConditionDisplayDriver : DisplayDriver where TCondition : Condition { - public override IDisplayResult Display(TCondition model) => + public override IDisplayResult Display(TCondition model, BuildDisplayContext context) => Combine( InitializeDisplayType(CommonContentDisplayTypes.Summary, model), InitializeDisplayType(CommonContentDisplayTypes.Thumbnail, model)); - public override IDisplayResult Edit(TCondition model) => + public override IDisplayResult Edit(TCondition model, BuildEditorContext context) => Combine( InitializeDisplayType(CommonContentDisplayTypes.Detail, model, "Title"), GetEditor(model)); diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionDisplayDriver.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionDisplayDriver.cs index 54df6e64..2693e76e 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionDisplayDriver.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionDisplayDriver.cs @@ -3,18 +3,19 @@ using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc.Localization; using Microsoft.Extensions.Localization; -using Newtonsoft.Json; -using OrchardCore.DisplayManagement.ModelBinding; +using OrchardCore.DisplayManagement.Handlers; using OrchardCore.DisplayManagement.Views; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; namespace Lombiq.HelpfulExtensions.Extensions.Widgets.Drivers; -public class MvcConditionDisplayDriver : ConditionDisplayDriver +public sealed class MvcConditionDisplayDriver : ConditionDisplayDriver { private readonly IHtmlLocalizer H; private readonly IStringLocalizer T; + public MvcConditionDisplayDriver( IHtmlLocalizer htmlLocalizer, IStringLocalizer stringLocalizer) @@ -37,30 +38,28 @@ protected override IDisplayResult GetEditor(MvcCondition model) => } }).PlaceInContent(); - public override async Task UpdateAsync(MvcCondition model, IUpdateModel updater) + public override async Task UpdateAsync(MvcCondition model, UpdateEditorContext context) { - var viewModel = new MvcConditionViewModel(); - if (await updater.TryUpdateModelAsync(viewModel, Prefix)) + var viewModel = await context.CreateModelAsync(Prefix); + + if (viewModel.OtherRouteNames.Count != viewModel.OtherRouteValues.Count) { - if (viewModel.OtherRouteNames.Count != viewModel.OtherRouteValues.Count) - { - updater.ModelState.AddModelError( - nameof(viewModel.OtherRouteNames), - T["The count of other route value names didn't match the count of other route values."]); - } + context.Updater.ModelState.AddModelError( + nameof(viewModel.OtherRouteNames), + T["The count of other route value names didn't match the count of other route values."]); + } - model.Area = viewModel.Area; - model.Controller = viewModel.Controller; - model.Action = viewModel.Action; + model.Area = viewModel.Area; + model.Controller = viewModel.Controller; + model.Action = viewModel.Action; - model.OtherRouteValues.Clear(); - for (var i = 0; i < viewModel.OtherRouteNames.Count; i++) - { - model.OtherRouteValues[viewModel.OtherRouteNames[i]] = viewModel.OtherRouteValues[i]; - } + model.OtherRouteValues.Clear(); + for (var i = 0; i < viewModel.OtherRouteNames.Count; i++) + { + model.OtherRouteValues[viewModel.OtherRouteNames[i]] = viewModel.OtherRouteValues[i]; } - return Edit(model); + return await EditAsync(model, context); } protected override ConditionViewModel GetConditionViewModel(MvcCondition condition) @@ -77,7 +76,7 @@ static IHtmlContentBuilder AppendIfNotEmpty(IHtmlContentBuilder summaryHint, str if (condition.OtherRouteValues.Any()) { summaryHint = summaryHint.AppendHtml( - H["Other route values: {0}", JsonConvert.SerializeObject(condition.OtherRouteValues)]); + H["Other route values: {0}", JsonSerializer.Serialize(condition.OtherRouteValues)]); } return new ConditionViewModel diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionEvaluatorDriver.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionEvaluatorDriver.cs index 7a29c2c1..019ea078 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionEvaluatorDriver.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionEvaluatorDriver.cs @@ -8,7 +8,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.Widgets.Drivers; -public class MvcConditionEvaluatorDriver : ContentDisplayDriver, IConditionEvaluator +public sealed class MvcConditionEvaluatorDriver : ContentDisplayDriver, IConditionEvaluator { private readonly IHttpContextAccessor _hca; diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Liquid/MenuWidgetLiquidFilter.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Liquid/MenuWidgetLiquidFilter.cs index 6254aca8..5f2e7c50 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Widgets/Liquid/MenuWidgetLiquidFilter.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Liquid/MenuWidgetLiquidFilter.cs @@ -6,13 +6,14 @@ using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.Extensions.Localization; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using OrchardCore.Liquid; using OrchardCore.Navigation; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace Lombiq.HelpfulExtensions.Extensions.Widgets.Liquid; @@ -45,23 +46,18 @@ public ValueTask ProcessAsync(FluidValue input, FilterArguments argu localNav = arguments[nameof(localNav)].ToBooleanValue(); classes = arguments[nameof(classes)].ToStringValue(); - var converter = new LocalizedStringJsonConverter(T); - var serializer = new JsonSerializer(); - serializer.Converters.Add(converter); - var serializerSettings = new JsonSerializerSettings(); - serializerSettings.Converters.Add(converter); - + var serializerOptions = LocalizedStringJsonConverter.Add(T); var menuItems = input?.Type switch { - FluidValues.String => JsonConvert.DeserializeObject>( + FluidValues.String => JsonSerializer.Deserialize>( input!.ToStringValue(), - serializerSettings), + serializerOptions), FluidValues.Object => input!.ToObjectValue() switch { IEnumerable enumerable => enumerable.AsList(), MenuItem single => [single], - JArray jArray => jArray.ToObject>(serializer), - JObject jObject => [jObject.ToObject(serializer)], + JsonArray jsonArray => jsonArray.ToObject>(serializerOptions), + JsonObject jsonObject => [jsonObject.ToObject(serializerOptions)], _ => null, }, _ => null, @@ -102,32 +98,36 @@ public class LocalizedStringJsonConverter : JsonConverter { private readonly IStringLocalizer T; - public LocalizedStringJsonConverter(IStringLocalizer stringLocalizer) => + private LocalizedStringJsonConverter(IStringLocalizer stringLocalizer) => T = stringLocalizer; - public override void WriteJson(JsonWriter writer, LocalizedString value, JsonSerializer serializer) => - writer.WriteValue(value?.Value); + public override void Write(Utf8JsonWriter writer, LocalizedString value, JsonSerializerOptions options) => + writer.WriteStringValue(value?.Value); [SuppressMessage("Style", "IDE0010:Add missing cases", Justification = "We don't want to handle other token types.")] - public override LocalizedString ReadJson( - JsonReader reader, - Type objectType, - LocalizedString existingValue, - bool hasExistingValue, - JsonSerializer serializer) + public override LocalizedString Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { switch (reader.TokenType) { - case JsonToken.String: - return JToken.ReadFrom(reader).ToObject() is { } text ? T[text] : null; - case JsonToken.StartObject: + case JsonTokenType.String: + return JsonSerializer.Deserialize(ref reader, options) is { } text ? T[text] : null; + case JsonTokenType.StartObject: var data = new Dictionary( - JToken.ReadFrom(reader).ToObject>(), + JsonSerializer.Deserialize>(ref reader, options), StringComparer.OrdinalIgnoreCase); return new LocalizedString(data[nameof(LocalizedString.Name)], data[nameof(LocalizedString.Value)]); default: throw new InvalidOperationException("Unable to parse JSON!"); } } + + public static JsonSerializerOptions Add(IStringLocalizer stringLocalizer, JsonSerializerOptions options = null) + { + options ??= new JsonSerializerOptions(JsonSerializerOptions.Default); + options.Converters.RemoveAll(converter => converter is JsonConverter); + options.Converters.Add(new LocalizedStringJsonConverter(stringLocalizer)); + + return options; + } } } diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Migrations.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Migrations.cs index 00147782..1f6d5ffb 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Widgets/Migrations.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Migrations.cs @@ -9,7 +9,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.Widgets; -public class Migrations : DataMigration +public sealed class Migrations : DataMigration { private readonly IContentDefinitionManager _contentDefinitionManager; diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Startup.cs index 3308e134..49c3eb32 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Widgets/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Startup.cs @@ -18,7 +18,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.Widgets; [Feature(FeatureIds.Widgets)] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) { @@ -26,7 +26,7 @@ public override void ConfigureServices(IServiceCollection services) services .AddScoped, MvcConditionDisplayDriver>() - .AddCondition>() + .AddRuleCondition>() .AddScoped(sp => (IContentDisplayDriver)sp.GetRequiredService()); services.AddTagHelpers(); diff --git a/Lombiq.HelpfulExtensions/Extensions/Workflows/Drivers/GenerateResetPasswordTokenTaskDisplayDriver.cs b/Lombiq.HelpfulExtensions/Extensions/Workflows/Drivers/GenerateResetPasswordTokenTaskDisplayDriver.cs index 32be3ce2..25496d64 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Workflows/Drivers/GenerateResetPasswordTokenTaskDisplayDriver.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Workflows/Drivers/GenerateResetPasswordTokenTaskDisplayDriver.cs @@ -1,16 +1,14 @@ using Lombiq.HelpfulExtensions.Extensions.Workflows.Activities; using Lombiq.HelpfulExtensions.Extensions.Workflows.ViewModels; using Microsoft.Extensions.Localization; -using OrchardCore.DisplayManagement.ModelBinding; +using OrchardCore.DisplayManagement.Handlers; using OrchardCore.DisplayManagement.Views; -using OrchardCore.Users.Models; using OrchardCore.Workflows.Display; -using OrchardCore.Workflows.Models; using System.Threading.Tasks; namespace Lombiq.HelpfulExtensions.Extensions.Workflows.Drivers; -public class GenerateResetPasswordTokenTaskDisplayDriver : ActivityDisplayDriver< +public sealed class GenerateResetPasswordTokenTaskDisplayDriver : ActivityDisplayDriver< GenerateResetPasswordTokenTask, GenerateResetPasswordTokenTaskViewModel> { @@ -26,16 +24,14 @@ protected override void EditActivity(GenerateResetPasswordTokenTask activity, Ge model.ResetPasswordUrlPropertyKey = activity.ResetPasswordUrlPropertyKey; } - public override async Task UpdateAsync(GenerateResetPasswordTokenTask model, IUpdateModel updater) + public override async Task UpdateAsync(GenerateResetPasswordTokenTask activity, UpdateEditorContext context) { - var viewModel = new GenerateResetPasswordTokenTaskViewModel(); - if (await updater.TryUpdateModelAsync(viewModel, Prefix)) - { - model.User = new WorkflowExpression(viewModel.UserExpression); - model.ResetPasswordTokenPropertyKey = viewModel.ResetPasswordTokenPropertyKey; - model.ResetPasswordUrlPropertyKey = viewModel.ResetPasswordUrlPropertyKey; - } + var viewModel = await context.CreateModelAsync(Prefix); - return Edit(model); + activity.User = new(viewModel.UserExpression); + activity.ResetPasswordTokenPropertyKey = viewModel.ResetPasswordTokenPropertyKey; + activity.ResetPasswordUrlPropertyKey = viewModel.ResetPasswordUrlPropertyKey; + + return await EditAsync(activity, context); } } diff --git a/Lombiq.HelpfulExtensions/Extensions/Workflows/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/Workflows/Startup.cs index 0a71351e..07a89b2f 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Workflows/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Workflows/Startup.cs @@ -9,7 +9,7 @@ namespace Lombiq.HelpfulExtensions.Extensions.Workflows; [Feature(FeatureIds.ResetPasswordActivity)] -public class Startup : StartupBase +public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) { diff --git a/Lombiq.HelpfulExtensions/FeatureIds.cs b/Lombiq.HelpfulExtensions/FeatureIds.cs index 3cd3b3ee..180370db 100644 --- a/Lombiq.HelpfulExtensions/FeatureIds.cs +++ b/Lombiq.HelpfulExtensions/FeatureIds.cs @@ -19,4 +19,5 @@ public static class FeatureIds public const string Workflows = FeatureIdPrefix + nameof(Workflows); public const string Trumbowyg = FeatureIdPrefix + nameof(Trumbowyg); public const string ResetPasswordActivity = Workflows + "." + nameof(ResetPasswordActivity); + public const string GoogleTag = FeatureIdPrefix + nameof(GoogleTag); } diff --git a/Lombiq.HelpfulExtensions/Lombiq.HelpfulExtensions.csproj b/Lombiq.HelpfulExtensions/Lombiq.HelpfulExtensions.csproj index c3a4c031..22b4df16 100644 --- a/Lombiq.HelpfulExtensions/Lombiq.HelpfulExtensions.csproj +++ b/Lombiq.HelpfulExtensions/Lombiq.HelpfulExtensions.csproj @@ -35,18 +35,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -56,7 +56,7 @@ - + diff --git a/Lombiq.HelpfulExtensions/Manifest.cs b/Lombiq.HelpfulExtensions/Manifest.cs index 29ff8210..265e8f3a 100644 --- a/Lombiq.HelpfulExtensions/Manifest.cs +++ b/Lombiq.HelpfulExtensions/Manifest.cs @@ -89,6 +89,7 @@ Dependencies = [ "OrchardCore.Email", + "OrchardCore.Email.Smtp", ] )] @@ -145,3 +146,10 @@ Category = "Content", Description = "Adds option for inserting code snippets in Trumbowyg editor." )] + +[assembly: Feature( + Id = GoogleTag, + Name = "Lombiq Helpful Extensions - Google Tag", + Category = "Content", + Description = "Adds a shape along with Razor and Liquid tag helpers for Google Analytics." +)] diff --git a/Lombiq.HelpfulExtensions/Views/ContentSetContentPickerField.cshtml b/Lombiq.HelpfulExtensions/Views/ContentSetContentPickerField.cshtml index 4e5884f1..62ea50f2 100644 --- a/Lombiq.HelpfulExtensions/Views/ContentSetContentPickerField.cshtml +++ b/Lombiq.HelpfulExtensions/Views/ContentSetContentPickerField.cshtml @@ -2,12 +2,13 @@ @using OrchardCore @using OrchardCore.ContentManagement.Metadata.Settings @using OrchardCore.Mvc.Utilities +@using System.Text.Json.Nodes @{ var name = (Model.PartFieldDefinition.PartDefinition.Name + "-" + Model.PartFieldDefinition.Name).HtmlClassify(); - var settings = Model.PartFieldDefinition.Settings.GetMaybe(nameof(ContentPartFieldSettings)); - var displayName = settings?.ToObject()?.DisplayName ?? Model.PartFieldDefinition.Name; + var settings = Model.PartFieldDefinition.Settings?.ToObject(); + var displayName = settings?.DisplayName ?? Model.PartFieldDefinition.Name; var links = Model .MemberLinks diff --git a/Lombiq.HelpfulExtensions/Views/ContentSetPart.MemberLink.cshtml b/Lombiq.HelpfulExtensions/Views/ContentSetPart.MemberLink.cshtml index bc6f1ec2..aa371ffc 100644 --- a/Lombiq.HelpfulExtensions/Views/ContentSetPart.MemberLink.cshtml +++ b/Lombiq.HelpfulExtensions/Views/ContentSetPart.MemberLink.cshtml @@ -13,8 +13,7 @@
  • @if (!string.IsNullOrEmpty(link.ContentItemId)) { - var url = Orchard.Action(controller => controller.Edit( - link.ContentItemId)); + var url = Orchard.Action(controller => controller.Edit(link.ContentItemId)); @link.DisplayText diff --git a/Lombiq.HelpfulExtensions/Views/GoogleTag.cshtml b/Lombiq.HelpfulExtensions/Views/GoogleTag.cshtml new file mode 100644 index 00000000..2d592612 --- /dev/null +++ b/Lombiq.HelpfulExtensions/Views/GoogleTag.cshtml @@ -0,0 +1,38 @@ +@model dynamic + +@using Lombiq.HelpfulLibraries.OrchardCore.Security +@using Microsoft.AspNetCore.Http.Features; +@using Microsoft.Extensions.Hosting; +@using Lombiq.HelpfulExtensions.Extensions.GoogleTag + +@inject IHostEnvironment HostEnvironment + +@{ + var trackingConsentFeature = ViewContext.HttpContext.Features.Get(); +} + +@if (HostEnvironment.IsProduction() && trackingConsentFeature is not { CanTrack: false }) +{ + GoogleAnalyticsContentSecurityPolicyProvider.EnableForCurrentRequest(Context); + + var viewModel = Model as GoogleTagViewModel ?? new GoogleTagViewModel + { + GoogleTagPropertyId = Model.GoogleTagPropertyId, + CookieDomain = Model.CookieDomain, + }; + var cookieDomain = string.Empty; + + if (!string.IsNullOrEmpty(viewModel.CookieDomain)) + { + cookieDomain = $", {{'cookie_domain': '{viewModel.CookieDomain}' }}"; + } + + + +} diff --git a/Lombiq.HelpfulExtensions/Views/MvcCondition.Fields.Edit.cshtml b/Lombiq.HelpfulExtensions/Views/MvcCondition.Fields.Edit.cshtml index f75783b8..34df5816 100644 --- a/Lombiq.HelpfulExtensions/Views/MvcCondition.Fields.Edit.cshtml +++ b/Lombiq.HelpfulExtensions/Views/MvcCondition.Fields.Edit.cshtml @@ -1,4 +1,5 @@ -@using Newtonsoft.Json +@using System.Text.Json +@using Lombiq.HelpfulLibraries.OrchardCore.TagHelpers @model MvcConditionViewModel @{ @@ -19,7 +20,7 @@
    diff --git a/Lombiq.HelpfulExtensions/Views/StrictSecuritySetting.Edit.cshtml b/Lombiq.HelpfulExtensions/Views/StrictSecuritySetting.Edit.cshtml index d590018f..d6effe07 100644 --- a/Lombiq.HelpfulExtensions/Views/StrictSecuritySetting.Edit.cshtml +++ b/Lombiq.HelpfulExtensions/Views/StrictSecuritySetting.Edit.cshtml @@ -14,7 +14,7 @@