diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml index 4b26cfcf..c2bac93e 100644 --- a/.github/workflows/publish-nuget.yml +++ b/.github/workflows/publish-nuget.yml @@ -7,6 +7,7 @@ on: jobs: publish-nuget: + if: ${{ !contains(github.ref_name, '-preview.') }} uses: Lombiq/GitHub-Actions/.github/workflows/publish-nuget.yml@dev secrets: API_KEY: ${{ secrets.DEFAULT_NUGET_PUBLISH_API_KEY }} diff --git a/Lombiq.HelpfulLibraries.AspNetCore/Localization/LocalizedHtmlStringConverter.cs b/Lombiq.HelpfulLibraries.AspNetCore/Localization/LocalizedHtmlStringConverter.cs deleted file mode 100644 index 382db97f..00000000 --- a/Lombiq.HelpfulLibraries.AspNetCore/Localization/LocalizedHtmlStringConverter.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Microsoft.AspNetCore.Mvc.Localization; -using System; -using System.Collections.Generic; -using System.Text.Json; -using System.Text.Json.Nodes; -using System.Text.Json.Serialization; - -namespace Lombiq.HelpfulLibraries.AspNetCore.Localization; - -public class LocalizedHtmlStringConverter : JsonConverter -{ - public override void Write(Utf8JsonWriter writer, LocalizedHtmlString value, JsonSerializerOptions options) - { - writer.WriteStartObject(); - - writer.WriteString(nameof(LocalizedHtmlString.Name), value.Name); - writer.WriteString(nameof(LocalizedHtmlString.Value), value.Html()); - writer.WriteBoolean(nameof(LocalizedHtmlString.IsResourceNotFound), value.IsResourceNotFound); - - writer.WriteEndObject(); - } - - public override LocalizedHtmlString Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var token = JsonNode.Parse(ref reader); - - if (token is JsonValue jsonValue) - { - var text = jsonValue.GetValue(); - return new LocalizedHtmlString(text, text); - } - - if (token is JsonObject jsonObject) - { - var dictionary = jsonObject.ToDictionaryIgnoreCase(); - var name = dictionary.GetMaybe(nameof(LocalizedHtmlString.Name))?.Deserialize(); - var value = dictionary.GetMaybe(nameof(LocalizedHtmlString.Value))?.Deserialize() ?? name; - var isResourceNotFound = dictionary.GetMaybe(nameof(LocalizedHtmlString.IsResourceNotFound))?.Deserialize(); - - name ??= value; - if (string.IsNullOrEmpty(name)) throw new InvalidOperationException("Missing name."); - - return new LocalizedHtmlString(name, value, isResourceNotFound == true); - } - - throw new InvalidOperationException($"Can't parse token \"{token}\". It should be an object or a string"); - } -} diff --git a/Lombiq.HelpfulLibraries.AspNetCore/Mvc/HttpRequestInfo.cs b/Lombiq.HelpfulLibraries.AspNetCore/Mvc/HttpRequestInfo.cs new file mode 100644 index 00000000..8317fa41 --- /dev/null +++ b/Lombiq.HelpfulLibraries.AspNetCore/Mvc/HttpRequestInfo.cs @@ -0,0 +1,37 @@ +#nullable enable + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; +using System.Collections.Generic; +using System.Text.Json; + +namespace Lombiq.HelpfulLibraries.AspNetCore.Mvc; + +/// +/// A simplified intermediate type that can be used to debug . +/// +public record HttpRequestInfo( + string Url, + string? ContentType, + IHeaderDictionary Headers, + IDictionary Form, + IRequestCookieCollection Cookies) +{ + public HttpRequestInfo(HttpRequest request) + : this( + request.GetDisplayUrl(), + request.ContentType, + request.Headers, + request.HasFormContentType ? + request.Form.ToDictionaryIgnoreCase(pair => pair.Key, pair => pair.Value.ToString()) : + new Dictionary(), + request.Cookies) + { + } + + public override string ToString() => $"HTTP Request at \"{Url}\""; + + public string ToJson() => JsonSerializer.Serialize(this); + + public static string? ToJson(HttpRequest? request) => request == null ? null : new HttpRequestInfo(request).ToJson(); +} diff --git a/Lombiq.HelpfulLibraries.LinqToDb/Lombiq.HelpfulLibraries.LinqToDb.csproj b/Lombiq.HelpfulLibraries.LinqToDb/Lombiq.HelpfulLibraries.LinqToDb.csproj index 03e25dcd..015a3004 100644 --- a/Lombiq.HelpfulLibraries.LinqToDb/Lombiq.HelpfulLibraries.LinqToDb.csproj +++ b/Lombiq.HelpfulLibraries.LinqToDb/Lombiq.HelpfulLibraries.LinqToDb.csproj @@ -24,6 +24,6 @@ - + diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Contents/BuildEditorContextExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Contents/BuildEditorContextExtensions.cs index b4abd2c3..d6be0fe7 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Contents/BuildEditorContextExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Contents/BuildEditorContextExtensions.cs @@ -1,16 +1,38 @@ -using System; +using OrchardCore.DisplayManagement.Entities; +using System; using System.Threading.Tasks; namespace OrchardCore.DisplayManagement.Handlers; public static class BuildEditorContextExtensions { - public static async Task CreateModelMaybeAsync( + /// + /// Creates a new instance of and tries to populate it from the with the . + /// + /// The editor context of the current update request. + /// The name prefix of the fields being edited. + /// + /// If not , it's needed to check the group (e.g. in . The value is checked against the and if they don't match is returned. + /// + /// + /// If not and the awaited result is , then is + /// returned. + /// + /// The expected view-model type. + /// + /// A new instance of , populated with data from . Unless + /// at least one of and are provided and the checks + /// failed, at which case is returned. + /// + public static async Task CreateModelMaybeAsync( this BuildEditorContext context, string prefix, string groupId = null, Func> authorizeAsync = null) - where T : class, new() + where TViewModel : class, new() { if (!string.IsNullOrEmpty(groupId) && context.GroupId != groupId) return null; @@ -19,9 +41,8 @@ public static async Task CreateModelMaybeAsync( return null; } - var viewModel = new T(); - return await context.Updater.TryUpdateModelAsync(viewModel, prefix) - ? viewModel - : null; + var viewModel = new TViewModel(); + await context.Updater.TryUpdateModelAsync(viewModel, prefix); + return viewModel; } } diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentOrchardHelperExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentOrchardHelperExtensions.cs index cfe0057e..1fe6a432 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentOrchardHelperExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentOrchardHelperExtensions.cs @@ -61,7 +61,7 @@ public static Task GetContentItemOrPreviewAsync( if (httpContext.Request.Method == "POST") { - var previewContentItemId = httpContext.Request.Form["PreviewContentItemId"]; + var previewContentItemId = httpContext.Request.Form["PreviewContentItemId"].ToString(); if (!string.IsNullOrEmpty(previewContentItemId)) { return httpContext.RequestServices.GetService().GetAsync(previewContentItemId); diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Contents/JsonSectionDisplayDriver.cs b/Lombiq.HelpfulLibraries.OrchardCore/Contents/JsonSectionDisplayDriver.cs index 1e81d4c1..3169a880 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Contents/JsonSectionDisplayDriver.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Contents/JsonSectionDisplayDriver.cs @@ -45,11 +45,7 @@ await AuthorizeAsync() public override async Task UpdateAsync(TSection section, UpdateEditorContext context) { - var viewModel = new JsonViewModel(); - - if (context.GroupId == GroupId && - await AuthorizeAsync() && - await context.Updater.TryUpdateModelAsync(viewModel, Prefix) && + if (await context.CreateModelMaybeAsync>(Prefix, GroupId, AuthorizeAsync) is { } viewModel && TryParseJson(viewModel.Json, out var result)) { await UpdateAsync(section, context, result); diff --git a/Lombiq.HelpfulLibraries.OrchardCore/DependencyInjection/InlineStartup.cs b/Lombiq.HelpfulLibraries.OrchardCore/DependencyInjection/InlineStartup.cs index 2d45f6ca..eb6d72d7 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/DependencyInjection/InlineStartup.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/DependencyInjection/InlineStartup.cs @@ -1,8 +1,11 @@ -using Microsoft.AspNetCore.Builder; +#nullable enable + +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using OrchardCore.Modules; using System; +using System.Threading.Tasks; namespace Lombiq.HelpfulLibraries.OrchardCore.DependencyInjection; @@ -11,28 +14,31 @@ namespace Lombiq.HelpfulLibraries.OrchardCore.DependencyInjection; /// public class InlineStartup : StartupBase { - private readonly Action _configureServices; - private readonly Action _configure; - private readonly int _order; + private readonly Action? _configureServices; + private readonly Action? _configure; + private readonly Func? _configureAsync; - public override int Order => _order; + public override int Order { get; } public InlineStartup( - Action configureServices, + Action? configureServices, Action configure, + Func? configureAsync = null, int order = 0) - : this(configureServices, (app, _, _) => configure(app), order) + : this(configureServices, (app, _, _) => configure(app), configureAsync, order) { } public InlineStartup( - Action configureServices, - Action configure = null, + Action? configureServices = null, + Action? configure = null, + Func? configureAsync = null, int order = 0) { _configureServices = configureServices; _configure = configure; - _order = order; + _configureAsync = configureAsync; + Order = order; } public override void ConfigureServices(IServiceCollection services) => @@ -40,4 +46,7 @@ public override void ConfigureServices(IServiceCollection services) => public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) => _configure?.Invoke(app, routes, serviceProvider); + + public override ValueTask ConfigureAsync(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) => + _configureAsync?.Invoke(app, routes, serviceProvider) ?? ValueTask.CompletedTask; } diff --git a/Lombiq.HelpfulLibraries.OrchardCore/DependencyInjection/ServiceCollectionExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/DependencyInjection/ServiceCollectionExtensions.cs index 8a282561..6f5115f1 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/DependencyInjection/ServiceCollectionExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/DependencyInjection/ServiceCollectionExtensions.cs @@ -1,3 +1,5 @@ +#nullable enable + using Lombiq.HelpfulLibraries.Common.DependencyInjection; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Routing; @@ -5,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using OrchardCore.Modules; using System; +using System.Threading.Tasks; namespace Lombiq.HelpfulLibraries.OrchardCore.DependencyInjection; @@ -26,10 +29,11 @@ public static void AddOrchardServices(this IServiceCollection services) /// public static IServiceCollection AddInlineStartup( this IServiceCollection services, - Action configureServices, - Action configure, + Action? configureServices = null, + Action? configure = null, + Func? configureAsync = null, int order = 0) => - services.AddSingleton(new InlineStartup(configureServices, configure, order)); + services.AddSingleton(new InlineStartup(configureServices, configure, configureAsync, order)); /// /// Creates a new instance using the provided parameters, and adds it to the service @@ -37,8 +41,9 @@ public static IServiceCollection AddInlineStartup( /// public static IServiceCollection AddInlineStartup( this IServiceCollection services, - Action configureServices, + Action? configureServices, Action configure, + Func? configureAsync = null, int order = 0) => - services.AddSingleton(new InlineStartup(configureServices, configure, order)); + services.AddSingleton(new InlineStartup(configureServices, configure, configureAsync, order)); } diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Environment/OrchardCoreBuilderExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Environment/OrchardCoreBuilderExtensions.cs index 3e611531..70911a18 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Environment/OrchardCoreBuilderExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Environment/OrchardCoreBuilderExtensions.cs @@ -2,6 +2,7 @@ using OrchardCore.Email; using OrchardCore.Environment.Shell.Configuration; using OrchardCore.ResourceManagement; +using System; namespace Microsoft.Extensions.DependencyInjection; @@ -29,6 +30,7 @@ public static OrchardCoreBuilder AddDatabaseShellsConfigurationIfAvailable( /// If set to the settings coming from the configuration provider will override the ones set /// up from the admin UI. /// + [Obsolete("The email configuration has changed in OC 2.0, see https://docs.orchardcore.net/en/latest/releases/2.0.0/#email-module.")] public static OrchardCoreBuilder ConfigureSmtpSettings( this OrchardCoreBuilder builder, bool overrideAdminSettings = true) diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Environment/ShellFeaturesManagerExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Environment/ShellFeaturesManagerExtensions.cs deleted file mode 100644 index c4f3548d..00000000 --- a/Lombiq.HelpfulLibraries.OrchardCore/Environment/ShellFeaturesManagerExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Threading.Tasks; - -namespace OrchardCore.Environment.Shell; - -/// -/// Shortcuts for . -/// -public static class ShellFeaturesManagerExtensions -{ - /// - /// Checks whether the given module feature is enabled for the current shell. - /// - /// Technical ID of the module feature. - public static async Task IsFeatureEnabledAsync(this IShellFeaturesManager shellFeaturesManager, string featureId) => - (await shellFeaturesManager.GetEnabledFeaturesAsync()).Any(featureId); -} diff --git a/Lombiq.HelpfulLibraries.OrchardCore/GraphQL/PartIndexAliasProvider.cs b/Lombiq.HelpfulLibraries.OrchardCore/GraphQL/PartIndexAliasProvider.cs index 12155827..868b0dfd 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/GraphQL/PartIndexAliasProvider.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/GraphQL/PartIndexAliasProvider.cs @@ -2,6 +2,7 @@ using OrchardCore.ContentManagement.GraphQL.Queries; using System; using System.Collections.Generic; +using System.Threading.Tasks; using YesSql.Indexes; namespace Lombiq.HelpfulLibraries.OrchardCore.GraphQL; @@ -13,7 +14,7 @@ namespace Lombiq.HelpfulLibraries.OrchardCore.GraphQL; public class PartIndexAliasProvider : IIndexAliasProvider where TIndex : class, IIndex { - private static readonly IndexAlias[] _aliases = + private static readonly IEnumerable _aliases = [ new() { @@ -29,5 +30,5 @@ public class PartIndexAliasProvider : IIndexAliasProvider /// /// Gets indexes with a name ending in PartIndex. /// - public IEnumerable GetAliases() => _aliases; + public ValueTask> GetAliasesAsync() => ValueTask.FromResult(_aliases); } diff --git a/Lombiq.HelpfulLibraries.OrchardCore/GraphQL/TotalOfContentTypeBuilder.cs b/Lombiq.HelpfulLibraries.OrchardCore/GraphQL/TotalOfContentTypeBuilder.cs index 58df67a9..035473ff 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/GraphQL/TotalOfContentTypeBuilder.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/GraphQL/TotalOfContentTypeBuilder.cs @@ -27,7 +27,7 @@ public TotalOfContentTypeBuilder(IStringLocalizer str /// /// The content item type to be extended with the totalOfContentType integer field. /// - public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefinition, ContentItemType contentItemType) + public void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition contentTypeDefinition, ContentItemType contentItemType) { var name = contentTypeDefinition.Name; diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Lombiq.HelpfulLibraries.OrchardCore.csproj b/Lombiq.HelpfulLibraries.OrchardCore/Lombiq.HelpfulLibraries.OrchardCore.csproj index 3d270396..f83516af 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Lombiq.HelpfulLibraries.OrchardCore.csproj +++ b/Lombiq.HelpfulLibraries.OrchardCore/Lombiq.HelpfulLibraries.OrchardCore.csproj @@ -24,31 +24,31 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - + + diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Mvc/AdminRouteAttributeRouteMapper.cs b/Lombiq.HelpfulLibraries.OrchardCore/Mvc/AdminRouteAttributeRouteMapper.cs index 6cc61afc..1c276ddc 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Mvc/AdminRouteAttributeRouteMapper.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Mvc/AdminRouteAttributeRouteMapper.cs @@ -1,56 +1,23 @@ -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using OrchardCore.Admin; using OrchardCore.Mvc.Routing; using System; -using System.Reflection; namespace Lombiq.HelpfulLibraries.OrchardCore.Mvc; -// Mark this class and AdminRouteAttribute as Obsolete when upgrading to the first Orchard Core version that contains -// https://github.com/OrchardCMS/OrchardCore/pull/15251. The message should inform to use [Admin(template)] instead. - -/// -/// A route mapper that maps a route comprised of the and the provided -/// template string to any action that has the . -/// -/// -/// -/// In practice this mapper makes [AdminRoute("My/Path/{id}")] work the same way as if you used -/// [Route("Admin/My/Path/{id}")] except the admin prefix is no longer hard coded. -/// -/// -/// It can be added to the DI service collection using the static method. -/// -/// [Obsolete("Use the [Admin(route)] attribute instead of [AdminRoute(route)].")] public class AdminRouteAttributeRouteMapper : IAreaControllerRouteMapper { - private readonly string _adminUrlPrefix; - - // Must take precedence over AdminAreaControllerRouteMapper whose Order value is -1000. - public int Order => -2000; - - public AdminRouteAttributeRouteMapper(IOptions adminOptions) => - _adminUrlPrefix = adminOptions.Value.AdminUrlPrefix; - - public bool TryMapAreaControllerRoute(IEndpointRouteBuilder routes, ControllerActionDescriptor descriptor) - { - if (descriptor.MethodInfo.GetCustomAttribute() is not { } routeAttribute) return false; + public int Order => 0; - routes.MapAreaControllerRoute( - name: descriptor.DisplayName, - areaName: descriptor.RouteValues["area"], - pattern: $"{_adminUrlPrefix}/{routeAttribute.Template.TrimStart('/')}", - defaults: new { controller = descriptor.ControllerName, action = descriptor.ActionName } - ); + public bool TryMapAreaControllerRoute(IEndpointRouteBuilder routes, ControllerActionDescriptor descriptor) => + ThrowNotSupported(); - return true; - } + public static void AddToServices(IServiceCollection services) => ThrowNotSupported(); - public static void AddToServices(IServiceCollection services) => - services.AddTransient(); + private static bool ThrowNotSupported() => + throw new NotSupportedException( + $"Please disable {nameof(AdminRouteAttributeRouteMapper)} and if you still have controllers or actions " + + $"with the [AdminRoute(route)] attribute, replace them with OrchardCore's built-in [Admin(route)]."); } diff --git a/Lombiq.HelpfulLibraries.OrchardCore/ResourceManagement/HtmlShape.cs b/Lombiq.HelpfulLibraries.OrchardCore/ResourceManagement/HtmlShape.cs new file mode 100644 index 00000000..3300bf7b --- /dev/null +++ b/Lombiq.HelpfulLibraries.OrchardCore/ResourceManagement/HtmlShape.cs @@ -0,0 +1,59 @@ +#nullable enable + +using Microsoft.AspNetCore.Html; +using OrchardCore.DisplayManagement; +using OrchardCore.DisplayManagement.Html; +using OrchardCore.DisplayManagement.Shapes; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Text.Encodings.Web; +using System.Threading.Tasks; + +namespace Lombiq.HelpfulLibraries.OrchardCore.ResourceManagement; + +public class HtmlShape : IHtmlContent, IPositioned, IShape +{ + private static readonly IDictionary _dummyAttributes = new Dictionary().ToFrozenDictionary(); + private static readonly IDictionary _dummyProperties = new Dictionary().ToFrozenDictionary(); + + private readonly Func _getHtml; + + public string? Position { get; set; } + + public ShapeMetadata Metadata { get; set; } = new(); + + public string? Id { get; set; } + + public string? TagName { get; set; } + + public IList Classes => []; + + public IDictionary Attributes => _dummyAttributes; + + public IDictionary Properties => _dummyProperties; + + public IReadOnlyList Items => []; + + public HtmlShape(Func getHtml, string? position = null) + { + _getHtml = getHtml; + Position = position; + } + + public HtmlShape(IHtmlContent? value, string? position = null) + : this(() => value, position) + { + } + + public HtmlShape(string? value, string? position = null) + : this(new HtmlContentString(value ?? string.Empty), position) + { + } + + public void WriteTo(TextWriter writer, HtmlEncoder encoder) => _getHtml.Invoke()?.WriteTo(writer, encoder); + + public ValueTask AddAsync(object item, string position) => throw new ReadOnlyException(); +} diff --git a/Lombiq.HelpfulLibraries.OrchardCore/ResourceManagement/ScriptModuleResourceFilter.cs b/Lombiq.HelpfulLibraries.OrchardCore/ResourceManagement/ScriptModuleResourceFilter.cs index 1c341e13..18bcb35b 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/ResourceManagement/ScriptModuleResourceFilter.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/ResourceManagement/ScriptModuleResourceFilter.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using OrchardCore.DisplayManagement.Implementation; using OrchardCore.DisplayManagement.Layout; using OrchardCore.ResourceManagement; using System; @@ -25,11 +24,11 @@ public record ScriptModuleResourceFilter(ILayoutAccessor LayoutAccessor) : IAsyn { public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) { - var shape = await context.HttpContext.RequestServices.CreateAdHocShapeForCurrentThemeAsync( - nameof(ScriptModuleResourceFilter), - displayContext => Task.FromResult(DisplayScriptModuleResources(displayContext.ServiceProvider))); + await LayoutAccessor.AddShapeToZoneAsync( + CommonLocationNames.Content, + new HtmlShape(() => DisplayScriptModuleResources(context.HttpContext.RequestServices)), + "After"); - await LayoutAccessor.AddShapeToZoneAsync("Content", shape, "After"); await next(); } diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Shapes/PerTenantShapeTableManager.cs b/Lombiq.HelpfulLibraries.OrchardCore/Shapes/PerTenantShapeTableManager.cs index 8b858328..f2710480 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Shapes/PerTenantShapeTableManager.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Shapes/PerTenantShapeTableManager.cs @@ -10,6 +10,7 @@ using OrchardCore.Settings; using System; using System.Collections.Concurrent; +using System.Collections.Frozen; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -124,8 +125,8 @@ public async Task GetShapeTableAsync(string themeId) .ToList(); shapeTable = new ShapeTable( - descriptors: descriptors.ToDictionary(sd => sd.ShapeType, x => (ShapeDescriptor)x, StringComparer.OrdinalIgnoreCase), - bindings: descriptors.SelectMany(sd => sd.Bindings).ToDictionary(kv => kv.Key, kv => kv.Value, StringComparer.OrdinalIgnoreCase) + descriptors: descriptors.ToFrozenDictionary(sd => sd.ShapeType, x => (ShapeDescriptor)x, StringComparer.OrdinalIgnoreCase), + bindings: descriptors.SelectMany(sd => sd.Bindings).ToFrozenDictionary(kv => kv.Key, kv => kv.Value, StringComparer.OrdinalIgnoreCase) ); if (_logger.IsEnabled(LogLevel.Information)) diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Shapes/ShapeExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Shapes/ShapeExtensions.cs index 147c0c5c..29cd9303 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Shapes/ShapeExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Shapes/ShapeExtensions.cs @@ -1,3 +1,4 @@ +using Lombiq.HelpfulLibraries.OrchardCore.ResourceManagement; using Microsoft.AspNetCore.Html; using Microsoft.Extensions.DependencyInjection; using OrchardCore.DisplayManagement.Descriptors; @@ -60,6 +61,7 @@ public static T As(this IShape shape) /// name="shapeTable"/>, then a new descriptor is added with binding that uses . /// If is null or empty, a new random unique name is generated. /// + [Obsolete($"This no longer works with the {nameof(DefaultShapeTableManager)}. Use {nameof(HtmlShape)} instead.")] public static IShape CreateAdHocShape(this ShapeTable shapeTable, string type, Func> displayAsync) { if (string.IsNullOrEmpty(type)) type = $"AdHocShape_{Guid.NewGuid():D}"; @@ -102,6 +104,7 @@ public static IShape CreateAdHocShape(this ShapeTable shapeTable, string type, F /// uses . If is null or empty, a new random unique name is /// generated. /// + [Obsolete($"This no longer works with the {nameof(DefaultShapeTableManager)}. Use {nameof(HtmlShape)} instead.")] public static async Task CreateAdHocShapeForCurrentThemeAsync( this IServiceProvider provider, string type, diff --git a/Lombiq.HelpfulLibraries.Refit/Lombiq.HelpfulLibraries.Refit.csproj b/Lombiq.HelpfulLibraries.Refit/Lombiq.HelpfulLibraries.Refit.csproj index ab61c41c..bc029657 100644 --- a/Lombiq.HelpfulLibraries.Refit/Lombiq.HelpfulLibraries.Refit.csproj +++ b/Lombiq.HelpfulLibraries.Refit/Lombiq.HelpfulLibraries.Refit.csproj @@ -24,7 +24,7 @@ - + diff --git a/Lombiq.HelpfulLibraries.Samples/Lombiq.HelpfulLibraries.Samples.csproj b/Lombiq.HelpfulLibraries.Samples/Lombiq.HelpfulLibraries.Samples.csproj index 25f1b628..ea31099d 100644 --- a/Lombiq.HelpfulLibraries.Samples/Lombiq.HelpfulLibraries.Samples.csproj +++ b/Lombiq.HelpfulLibraries.Samples/Lombiq.HelpfulLibraries.Samples.csproj @@ -12,12 +12,12 @@ - - - - - - + + + + + + diff --git a/Lombiq.HelpfulLibraries.Tests/UnitTests/Converters/LocalizedHtmlStringConverterTests.cs b/Lombiq.HelpfulLibraries.Tests/UnitTests/Converters/LocalizedHtmlStringConverterTests.cs deleted file mode 100644 index 6cbd5f45..00000000 --- a/Lombiq.HelpfulLibraries.Tests/UnitTests/Converters/LocalizedHtmlStringConverterTests.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Lombiq.HelpfulLibraries.AspNetCore.Localization; -using Microsoft.AspNetCore.Mvc.Localization; -using Shouldly; -using System.Text.Json; -using Xunit; - -namespace Lombiq.HelpfulLibraries.Tests.UnitTests.Converters; - -public class LocalizedHtmlStringConverterTests -{ - private const string Name = "my text"; - - private static readonly JsonSerializerOptions _options = new() - { - Converters = { new LocalizedHtmlStringConverter() }, - }; - - [Theory] - [InlineData(Name, Name, null, "{\"Name\":\"my text\",\"Value\":\"my text\",\"IsResourceNotFound\":false}")] - [InlineData(Name, Name, false, "{\"Name\":\"my text\",\"Value\":\"my text\",\"IsResourceNotFound\":false}")] - [InlineData(Name, Name, true, "{\"Name\":\"my text\",\"Value\":\"my text\",\"IsResourceNotFound\":true}")] - [InlineData( - Name, - "az én szövegem", // #spell-check-ignore-line - null, - "{\"Name\":\"my text\",\"Value\":\"az \\u00E9n sz\\u00F6vegem\",\"IsResourceNotFound\":false}")] // #spell-check-ignore-line - public void LocalizedHtmlStringShouldBeSerializedCorrectly(string name, string value, bool? notFound, string expected) - { - var localized = notFound == null - ? new LocalizedHtmlString(name, value) - : new LocalizedHtmlString(name, value, notFound.Value); - - JsonSerializer.Serialize(localized, _options).ShouldBe(expected); - } - - [Theory] - [InlineData("\"my text\"", Name, Name, false)] - [InlineData("{ \"name\": \"my text\", \"value\": \"my text\", \"isResourceNotFound\": true }", Name, Name, true)] - [InlineData("{ \"name\": \"my text\", \"value\": \"some other text\" }", Name, "some other text", false)] - [InlineData("{ \"value\": \"my text\" }", Name, Name, false)] - [InlineData("{ \"NAME\": \"my text\" }", Name, Name, false)] - public void LocalizedHtmlStringShouldBeDeserializedCorrectly(string json, string name, string value, bool notFound) - { - var localized = JsonSerializer.Deserialize(json, _options); - - localized.Name.ShouldBe(name); - localized.Value.ShouldBe(value); - localized.IsResourceNotFound.ShouldBe(notFound); - } -} diff --git a/NuGet.config b/NuGet.config new file mode 100644 index 00000000..ed23fc59 --- /dev/null +++ b/NuGet.config @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Readme.md b/Readme.md index b68b6166..3759a1bb 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # Lombiq Helpful Libraries -[![Lombiq.HelpfulLibraries NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries?label=Lombiq.HelpfulLibraries)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries/) [![Lombiq.HelpfulLibraries.AspNetCore NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.AspNetCore?label=Lombiq.HelpfulLibraries.AspNetCore)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.AspNetCore/) [![Lombiq.HelpfulLibraries.Cli NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.Cli?label=Lombiq.HelpfulLibraries.Cli)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.Cli/) [![Lombiq.HelpfulLibraries.Common NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.Common?label=Lombiq.HelpfulLibraries.Common)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.Common/) [![Lombiq.HelpfulLibraries.LinqToDb NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.LinqToDb?label=Lombiq.HelpfulLibraries.LinqToDb)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.LinqToDb/) [![Lombiq.HelpfulLibraries.OrchardCore NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.OrchardCore?label=Lombiq.HelpfulLibraries.OrchardCore)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.OrchardCore/) [![Lombiq.HelpfulLibraries.OrchardCore.Testing NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.OrchardCore.Testing?label=Lombiq.HelpfulLibraries.OrchardCore.Testing)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.OrchardCore.Testing/) [![Lombiq.HelpfulLibraries.Refit NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.Refit?label=Lombiq.HelpfulLibraries.Refit)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.Refit/) [![Lombiq.HelpfulLibraries.RestEase NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.RestEase?label=Lombiq.HelpfulLibraries.RestEase)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.RestEase/) [![Lombiq.HelpfulLibraries.SourceGenerators NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.SourceGenerators?label=Lombiq.HelpfulLibraries.SourceGenerators)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.SourceGenerators/) [![Lombiq.HelpfulLibraries.Attributes NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.Attributes?label=Lombiq.HelpfulLibraries.Attributes)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.Attributes/) +[![Lombiq.HelpfulLibraries NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries?label=Lombiq.HelpfulLibraries)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries/) [![Lombiq.HelpfulLibraries.AspNetCore NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.AspNetCore?label=Lombiq.HelpfulLibraries.AspNetCore)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.AspNetCore/) [![Lombiq.HelpfulLibraries.Cli NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.Cli?label=Lombiq.HelpfulLibraries.Cli)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.Cli/) [![Lombiq.HelpfulLibraries.Common NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.Common?label=Lombiq.HelpfulLibraries.Common)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.Common/) [![Lombiq.HelpfulLibraries.LinqToDb NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.LinqToDb?label=Lombiq.HelpfulLibraries.LinqToDb)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.LinqToDb/) [![Lombiq.HelpfulLibraries.OrchardCore NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.OrchardCore?label=Lombiq.HelpfulLibraries.OrchardCore)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.OrchardCore/) [![Lombiq.HelpfulLibraries.OrchardCore.Testing NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.OrchardCore.Testing?label=Lombiq.HelpfulLibraries.OrchardCore.Testing)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.OrchardCore.Testing/) [![Lombiq.HelpfulLibraries.Refit NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.Refit?label=Lombiq.HelpfulLibraries.Refit)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.Refit/) [![Lombiq.HelpfulLibraries.RestEase NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.RestEase?label=Lombiq.HelpfulLibraries.RestEase)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.RestEase/) [![Lombiq.HelpfulLibraries.SourceGenerators NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.SourceGenerators?label=Lombiq.HelpfulLibraries.SourceGenerators)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.SourceGenerators/) [![Lombiq.HelpfulLibraries.Attributes NuGet](https://img.shields.io/nuget/v/Lombiq.HelpfulLibraries.Attributes?label=Lombiq.HelpfulLibraries.Attributes)](https://www.nuget.org/packages/Lombiq.HelpfulLibraries.Attributes/) [![Latest version of 'Lombiq.HelpfulLibraries' @ Cloudsmith](https://api-prd.cloudsmith.io/v1/badges/version/lombiq/open-source-orchard-core-extensions/nuget/Lombiq.HelpfulLibraries/latest/xsp=True/?render=true&show_latest=true)](https://cloudsmith.io/~lombiq/repos/open-source-orchard-core-extensions/packages/detail/nuget/Lombiq.HelpfulLibraries/latest/xsp=True/) ## About