diff --git a/.github/workflows/publish-cloudsmith.yml b/.github/workflows/publish-cloudsmith.yml index c92bc592..e6203dce 100644 --- a/.github/workflows/publish-cloudsmith.yml +++ b/.github/workflows/publish-cloudsmith.yml @@ -8,7 +8,7 @@ on: jobs: publish-nuget: name: Publish to Cloudsmith - uses: Lombiq/GitHub-Actions/.github/workflows/publish-nuget.yml@dev + uses: Lombiq/GitHub-Actions/.github/workflows/publish-nuget.yml@issue/OSOE-925 with: source: https://nuget.cloudsmith.io/lombiq/open-source-orchard-core-extensions/v3/index.json secrets: diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml index 44a74afd..2b2a5e73 100644 --- a/.github/workflows/publish-nuget.yml +++ b/.github/workflows/publish-nuget.yml @@ -9,6 +9,6 @@ jobs: publish-nuget: name: Publish to NuGet if: ${{ !contains(github.ref_name, '-preview.') }} - uses: Lombiq/GitHub-Actions/.github/workflows/publish-nuget.yml@dev + uses: Lombiq/GitHub-Actions/.github/workflows/publish-nuget.yml@issue/OSOE-925 secrets: API_KEY: ${{ secrets.DEFAULT_NUGET_PUBLISH_API_KEY }} diff --git a/.github/workflows/validate-nuget-publish.yml b/.github/workflows/validate-nuget-publish.yml index 9f8979c5..f0fd6be1 100644 --- a/.github/workflows/validate-nuget-publish.yml +++ b/.github/workflows/validate-nuget-publish.yml @@ -9,4 +9,4 @@ on: jobs: validate-nuget-publish: name: Validate NuGet Publish - uses: Lombiq/GitHub-Actions/.github/workflows/validate-nuget-publish.yml@dev + uses: Lombiq/GitHub-Actions/.github/workflows/validate-nuget-publish.yml@issue/OSOE-925 diff --git a/Lombiq.HelpfulLibraries.AspNetCore/CompatibilitySuppressions.xml b/Lombiq.HelpfulLibraries.AspNetCore/CompatibilitySuppressions.xml new file mode 100644 index 00000000..8af156c8 --- /dev/null +++ b/Lombiq.HelpfulLibraries.AspNetCore/CompatibilitySuppressions.xml @@ -0,0 +1,8 @@ + + + + + PKV006 + net8.0 + + \ No newline at end of file diff --git a/Lombiq.HelpfulLibraries.AspNetCore/Extensions/ForwardedHeadersApplicationBuilderExtensions.cs b/Lombiq.HelpfulLibraries.AspNetCore/Extensions/ForwardedHeadersApplicationBuilderExtensions.cs index 97443767..0a0d6356 100644 --- a/Lombiq.HelpfulLibraries.AspNetCore/Extensions/ForwardedHeadersApplicationBuilderExtensions.cs +++ b/Lombiq.HelpfulLibraries.AspNetCore/Extensions/ForwardedHeadersApplicationBuilderExtensions.cs @@ -32,7 +32,7 @@ public static IApplicationBuilder UseForwardedHeadersForCloudflareAndAzure(this }; // These are not all known for Cloudflare and Azure. - forwardedHeadersOptions.KnownNetworks.Clear(); + forwardedHeadersOptions.KnownIPNetworks.Clear(); forwardedHeadersOptions.KnownProxies.Clear(); builder.UseForwardedHeaders(forwardedHeadersOptions); diff --git a/Lombiq.HelpfulLibraries.AspNetCore/Extensions/HttpRequestExtensions.cs b/Lombiq.HelpfulLibraries.AspNetCore/Extensions/HttpRequestExtensions.cs index 14e7c2c5..2d48580b 100644 --- a/Lombiq.HelpfulLibraries.AspNetCore/Extensions/HttpRequestExtensions.cs +++ b/Lombiq.HelpfulLibraries.AspNetCore/Extensions/HttpRequestExtensions.cs @@ -114,4 +114,27 @@ public static bool IsAction( string? area = null) where TController : ControllerBase => request.IsAction(actionSelector.StripResult(), area); + + /// + /// If the has a form body, it tries to find the value for amd + /// trims it. If that fails or if the result is an empty string, is returned instead. + /// + public static string? GetFormValueMaybe(this HttpRequest request, string key) + { + if (!request.HasFormContentType) return null; + + // We use try-catch in case the request is somehow broken or invalid because then just accessing the form can + // throw an exception. + try + { + return request.Form.TryGetValue(key, out var values) && + values.WhereNot(string.IsNullOrWhiteSpace).FirstOrDefault()?.Trim() is { } value + ? value + : null; + } + catch + { + return null; + } + } } diff --git a/Lombiq.HelpfulLibraries.AspNetCore/Extensions/ServiceCollectionExtensions.cs b/Lombiq.HelpfulLibraries.AspNetCore/Extensions/ServiceCollectionExtensions.cs index dedf02d3..5bdc9f54 100644 --- a/Lombiq.HelpfulLibraries.AspNetCore/Extensions/ServiceCollectionExtensions.cs +++ b/Lombiq.HelpfulLibraries.AspNetCore/Extensions/ServiceCollectionExtensions.cs @@ -11,5 +11,5 @@ public static class ServiceCollectionExtensions /// public static void AddAsyncResultFilter(this IServiceCollection services) where TFilter : IAsyncResultFilter => - services.Configure(options => options.Filters.Add(typeof(TFilter))); + services.Configure(options => options.Filters.Add()); } diff --git a/Lombiq.HelpfulLibraries.AspNetCore/Lombiq.HelpfulLibraries.AspNetCore.csproj b/Lombiq.HelpfulLibraries.AspNetCore/Lombiq.HelpfulLibraries.AspNetCore.csproj index 883d918b..9cac0600 100644 --- a/Lombiq.HelpfulLibraries.AspNetCore/Lombiq.HelpfulLibraries.AspNetCore.csproj +++ b/Lombiq.HelpfulLibraries.AspNetCore/Lombiq.HelpfulLibraries.AspNetCore.csproj @@ -1,28 +1,21 @@ - - + - net8.0 - $(DefaultItemExcludes);.git* + net10.0 enable + + + Lombiq Helpful Libraries - ASP.NET Core Libraries - Lombiq Technologies - Copyright © 2011, Lombiq Technologies Ltd. - Lombiq Helpful Libraries - ASP.NET Core Libraries: Some useful extensions and other helpers for ASP.NET Core. See the project website for detailed documentation. + 2011 + Some useful extensions and other helpers for ASP.NET Core. See the project website for detailed documentation. OrchardCore;Lombiq;AspNetCore; - NuGetIcon.png https://github.com/Lombiq/Helpful-Libraries https://github.com/Lombiq/Helpful-Libraries/blob/dev/Lombiq.HelpfulLibraries.AspNetCore/Readme.md - BSD-3-Clause - - - - - @@ -31,4 +24,6 @@ + + diff --git a/Lombiq.HelpfulLibraries.Attributes/Lombiq.HelpfulLibraries.Attributes.csproj b/Lombiq.HelpfulLibraries.Attributes/Lombiq.HelpfulLibraries.Attributes.csproj index 461e8356..b3421dda 100644 --- a/Lombiq.HelpfulLibraries.Attributes/Lombiq.HelpfulLibraries.Attributes.csproj +++ b/Lombiq.HelpfulLibraries.Attributes/Lombiq.HelpfulLibraries.Attributes.csproj @@ -1,27 +1,23 @@ - - + netstandard2.0 true enable - latest + 14.0 + + + Lombiq Helpful Libraries - Attributes for Orchard Core - Lombiq Technologies - Copyright © 2011, Lombiq Technologies Ltd. - Lombiq Helpful Libraries - Attributes for Orchard Core: Adds attributes used by other projects. See the project website for detailed documentation. - NuGetIcon.png + 2011 + Adds attributes used by other projects. See the project website for detailed documentation. OrchardCore;Lombiq;Attributes https://github.com/Lombiq/Helpful-Libraries https://github.com/Lombiq/Helpful-Libraries/blob/dev/Lombiq.HelpfulLibraries.Attributes/Readme.md - BSD-3-Clause - - - - - + + diff --git a/Lombiq.HelpfulLibraries.Cli/CompatibilitySuppressions.xml b/Lombiq.HelpfulLibraries.Cli/CompatibilitySuppressions.xml new file mode 100644 index 00000000..8af156c8 --- /dev/null +++ b/Lombiq.HelpfulLibraries.Cli/CompatibilitySuppressions.xml @@ -0,0 +1,8 @@ + + + + + PKV006 + net8.0 + + \ No newline at end of file diff --git a/Lombiq.HelpfulLibraries.Cli/Extensions/CommandExtensions.cs b/Lombiq.HelpfulLibraries.Cli/Extensions/CommandExtensions.cs index cc7b857d..17f37197 100644 --- a/Lombiq.HelpfulLibraries.Cli/Extensions/CommandExtensions.cs +++ b/Lombiq.HelpfulLibraries.Cli/Extensions/CommandExtensions.cs @@ -29,16 +29,15 @@ public static async Task ExecuteUntilOutputAsync( Action? stdErrHandler = default, CancellationToken cancellationToken = default) { - await using var enumerator = command.ListenAsync(cancellationToken).GetAsyncEnumerator(cancellationToken); - - while (await enumerator.MoveNextAsync(cancellationToken)) + await foreach (var commandEvent in command.ListenAsync(cancellationToken)) { - if (enumerator.Current is StandardOutputCommandEvent stdOut && stdOut.Text.ContainsOrdinalIgnoreCase(outputToWaitFor)) + if (commandEvent is StandardOutputCommandEvent stdOut && + stdOut.Text.ContainsOrdinalIgnoreCase(outputToWaitFor)) { return; } - if (enumerator.Current is StandardErrorCommandEvent stdErr) + if (commandEvent is StandardErrorCommandEvent stdErr) { stdErrHandler?.Invoke(stdErr); } diff --git a/Lombiq.HelpfulLibraries.Cli/Lombiq.HelpfulLibraries.Cli.csproj b/Lombiq.HelpfulLibraries.Cli/Lombiq.HelpfulLibraries.Cli.csproj index 9db687c4..92826952 100644 --- a/Lombiq.HelpfulLibraries.Cli/Lombiq.HelpfulLibraries.Cli.csproj +++ b/Lombiq.HelpfulLibraries.Cli/Lombiq.HelpfulLibraries.Cli.csproj @@ -1,27 +1,21 @@ - - + - net8.0 + net10.0 enable + + + Lombiq Helpful Libraries - Command Line Libraries - Lombiq Technologies - Copyright © 2011, Lombiq Technologies Ltd. - Lombiq Helpful Libraries - Command Line Libraries. This project helps with executing command line calls. See the project website for detailed documentation. + 2011 + This project helps with executing command line calls. See the project website for detailed documentation. Lombiq;cli;CliWrap - NuGetIcon.png https://github.com/Lombiq/Helpful-Libraries https://github.com/Lombiq/Helpful-Libraries/blob/dev/Lombiq.HelpfulLibraries.Cli/Readme.md - BSD-3-Clause - - - - - @@ -30,4 +24,6 @@ + + diff --git a/Lombiq.HelpfulLibraries.Common/CompatibilitySuppressions.xml b/Lombiq.HelpfulLibraries.Common/CompatibilitySuppressions.xml new file mode 100644 index 00000000..8af156c8 --- /dev/null +++ b/Lombiq.HelpfulLibraries.Common/CompatibilitySuppressions.xml @@ -0,0 +1,8 @@ + + + + + PKV006 + net8.0 + + \ No newline at end of file diff --git a/Lombiq.HelpfulLibraries.Common/Extensions/ArrayExtensions.cs b/Lombiq.HelpfulLibraries.Common/Extensions/ArrayExtensions.cs index fc6faac7..de3add81 100644 --- a/Lombiq.HelpfulLibraries.Common/Extensions/ArrayExtensions.cs +++ b/Lombiq.HelpfulLibraries.Common/Extensions/ArrayExtensions.cs @@ -11,7 +11,7 @@ public static class ArrayExtensions /// it's better to use this instead of the general `Any()` extension method. /// /// - public static bool Exists(this T?[] array, Predicate match) => Array.Exists(array, match); + public static bool Exists(this T[] array, Predicate match) => Array.Exists(array, match); /// /// A fluid alternative to . @@ -22,12 +22,12 @@ public static class ArrayExtensions /// it's better to use this instead of the general `FirstOrDefault()` extension method. /// /// - public static T? Find(this T?[] array, Predicate match) => Array.Find(array, match); + public static T? Find(this T[] array, Predicate match) => Array.Find(array, match); /// /// A fluid alternative to . /// - public static T?[] FindAll(this T?[] array, Predicate match) => Array.FindAll(array, match); + public static T[] FindAll(this T[] array, Predicate match) => Array.FindAll(array, match); /// /// A fluid alternative to . @@ -38,5 +38,5 @@ public static class ArrayExtensions /// it's better to use this instead of the general `All()` extension method. /// /// - public static bool TrueForAll(this T?[] array, Predicate match) => Array.TrueForAll(array, match); + public static bool TrueForAll(this T[] array, Predicate match) => Array.TrueForAll(array, match); } diff --git a/Lombiq.HelpfulLibraries.Common/Extensions/EnumerableExtensions.cs b/Lombiq.HelpfulLibraries.Common/Extensions/EnumerableExtensions.cs index 14f723c4..0945086b 100644 --- a/Lombiq.HelpfulLibraries.Common/Extensions/EnumerableExtensions.cs +++ b/Lombiq.HelpfulLibraries.Common/Extensions/EnumerableExtensions.cs @@ -93,7 +93,7 @@ public static async Task AwaitEachAsync( } /// - /// Awaits the tasks sequentially while the action returns . + /// Awaits the tasks sequentially while the action returns . /// /// if the was never broken. public static async Task AwaitWhileAsync( diff --git a/Lombiq.HelpfulLibraries.Common/Extensions/StringExtensions.cs b/Lombiq.HelpfulLibraries.Common/Extensions/StringExtensions.cs index 397f9cbb..e20e2fe6 100644 --- a/Lombiq.HelpfulLibraries.Common/Extensions/StringExtensions.cs +++ b/Lombiq.HelpfulLibraries.Common/Extensions/StringExtensions.cs @@ -98,6 +98,12 @@ public static string[] SplitByNewLines(this string? text) => public static bool ContainsLoose(this string? text, string? toFind) => text != null && toFind != null && text.Contains(toFind, StringComparison.InvariantCultureIgnoreCase); + /// + /// A shortcut for string.Equals(string, StringComparison.Ordinal). + /// + public static bool EqualsOrdinal(this string? text, string? value) => + text?.Equals(value, StringComparison.Ordinal) == true; + /// /// A shortcut for string.Equals(string, StringComparison.OrdinalIgnoreCase). /// @@ -435,4 +441,11 @@ public static string Concat(this string text, IList ranges) /// public static string Join(this IList ranges, string text) => text.Concat(ranges); + + /// + /// Returns if the is or whitespace. This + /// makes chaining with the null-coalescing operator (??) easier. + /// + public static string? NullIfWhiteSpace(this string value) => + string.IsNullOrWhiteSpace(value) ? null : value; } diff --git a/Lombiq.HelpfulLibraries.Common/Extensions/ZipArchiveExtensions.cs b/Lombiq.HelpfulLibraries.Common/Extensions/ZipArchiveExtensions.cs index c556a5e0..a210856d 100644 --- a/Lombiq.HelpfulLibraries.Common/Extensions/ZipArchiveExtensions.cs +++ b/Lombiq.HelpfulLibraries.Common/Extensions/ZipArchiveExtensions.cs @@ -10,7 +10,7 @@ public static class ZipArchiveExtensions /// public static async Task CreateTextEntryAsync(this ZipArchive zip, string entryName, IEnumerable? lines) { - await using var writer = new StreamWriter(zip.CreateEntry(entryName).Open()); + await using var writer = new StreamWriter(await zip.CreateEntry(entryName).OpenAsync()); if (lines == null) return; @@ -31,7 +31,7 @@ public static Task CreateTextEntryAsync(this ZipArchive zip, string entryName, s /// public static async Task CreateBinaryEntryAsync(this ZipArchive zip, string entryName, ReadOnlyMemory data) { - await using var stream = zip.CreateEntry(entryName).Open(); + await using var stream = await zip.CreateEntry(entryName).OpenAsync(); await stream.WriteAsync(data); } } diff --git a/Lombiq.HelpfulLibraries.Common/Lombiq.HelpfulLibraries.Common.csproj b/Lombiq.HelpfulLibraries.Common/Lombiq.HelpfulLibraries.Common.csproj index eea0b568..2c9ee7f1 100644 --- a/Lombiq.HelpfulLibraries.Common/Lombiq.HelpfulLibraries.Common.csproj +++ b/Lombiq.HelpfulLibraries.Common/Lombiq.HelpfulLibraries.Common.csproj @@ -1,33 +1,27 @@ - - + - net8.0 - $(DefaultItemExcludes);.git* + net10.0 enable + + + Lombiq Helpful Libraries - Common Libraries - Lombiq Technologies - Copyright © 2011, Lombiq Technologies Ltd. - Lombiq Helpful Libraries - Common Libraries: Various useful libraries that can be handy when developing for .NET. See the project website for detailed documentation. + 2011 + Various useful libraries that can be handy when developing for .NET. See the project website for detailed documentation. Lombiq;DateTime;DependencyInjection;Utilities - NuGetIcon.png https://github.com/Lombiq/Helpful-Libraries https://github.com/Lombiq/Helpful-Libraries/blob/dev/Lombiq.HelpfulLibraries.Common/Readme.md - BSD-3-Clause - - - - - - - - + + + + diff --git a/Lombiq.HelpfulLibraries.LinqToDb/CompatibilitySuppressions.xml b/Lombiq.HelpfulLibraries.LinqToDb/CompatibilitySuppressions.xml new file mode 100644 index 00000000..8af156c8 --- /dev/null +++ b/Lombiq.HelpfulLibraries.LinqToDb/CompatibilitySuppressions.xml @@ -0,0 +1,8 @@ + + + + + PKV006 + net8.0 + + \ No newline at end of file diff --git a/Lombiq.HelpfulLibraries.LinqToDb/Lombiq.HelpfulLibraries.LinqToDb.csproj b/Lombiq.HelpfulLibraries.LinqToDb/Lombiq.HelpfulLibraries.LinqToDb.csproj index c38f4763..55d8ed3e 100644 --- a/Lombiq.HelpfulLibraries.LinqToDb/Lombiq.HelpfulLibraries.LinqToDb.csproj +++ b/Lombiq.HelpfulLibraries.LinqToDb/Lombiq.HelpfulLibraries.LinqToDb.csproj @@ -1,30 +1,26 @@ - - + - net8.0 - $(DefaultItemExcludes);.git* + net10.0 enable + + + Lombiq Helpful Libraries - LINQ to DB Libraries for Orchard Core - Lombiq Technologies - Copyright © 2011, Lombiq Technologies Ltd. - Lombiq Helpful Libraries - LINQ to DB Libraries for Orchard Core: With the help of this project you can write LINQ expressions and run them with a YesSql ISession extension method to query from the DB instead of writing plain SQL queries. Uses the LINQ to DB project. See the project website for detailed documentation. + 2011 + With the help of this project you can write LINQ expressions and run them with a YesSql ISession extension method to query from the DB instead of writing plain SQL queries. Uses the LINQ to DB project. See the project website for detailed documentation. OrchardCore;Lombiq;YesSql;linq2db;LinqToDB - NuGetIcon.png https://github.com/Lombiq/Helpful-Libraries https://github.com/Lombiq/Helpful-Libraries/blob/dev/Lombiq.HelpfulLibraries.LinqToDb/Readme.md - BSD-3-Clause - - - - - - + + + + diff --git a/Lombiq.HelpfulLibraries.OrchardCore.Testing/CompatibilitySuppressions.xml b/Lombiq.HelpfulLibraries.OrchardCore.Testing/CompatibilitySuppressions.xml new file mode 100644 index 00000000..8af156c8 --- /dev/null +++ b/Lombiq.HelpfulLibraries.OrchardCore.Testing/CompatibilitySuppressions.xml @@ -0,0 +1,8 @@ + + + + + PKV006 + net8.0 + + \ No newline at end of file diff --git a/Lombiq.HelpfulLibraries.OrchardCore.Testing/Lombiq.HelpfulLibraries.OrchardCore.Testing.csproj b/Lombiq.HelpfulLibraries.OrchardCore.Testing/Lombiq.HelpfulLibraries.OrchardCore.Testing.csproj index 4d9a7f55..36c9f0cc 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore.Testing/Lombiq.HelpfulLibraries.OrchardCore.Testing.csproj +++ b/Lombiq.HelpfulLibraries.OrchardCore.Testing/Lombiq.HelpfulLibraries.OrchardCore.Testing.csproj @@ -1,34 +1,29 @@ - - + - net8.0 - $(DefaultItemExcludes);.git* + net10.0 enable + + + Lombiq Helpful Libraries - Testing Libraries for Orchard Core - Lombiq Technologies - Copyright © 2011, Lombiq Technologies Ltd. - Lombiq Helpful Libraries - Testing Libraries for Orchard Core: Various useful libraries that can be handy when writing unit and integration tests for Orchard Core apps. See the project website for detailed documentation. + 2011 + Various useful libraries that can be handy when writing unit and integration tests for Orchard Core apps. See the project website for detailed documentation. OrchardCore;Lombiq;AspNetCore;Moq;xUnit;UnitTesting;Testing - NuGetIcon.png https://github.com/Lombiq/Helpful-Libraries https://github.com/Lombiq/Helpful-Libraries/blob/dev/Lombiq.HelpfulLibraries.Testing/Readme.md - BSD-3-Clause - - - - - - + + + diff --git a/Lombiq.HelpfulLibraries.OrchardCore/CompatibilitySuppressions.xml b/Lombiq.HelpfulLibraries.OrchardCore/CompatibilitySuppressions.xml new file mode 100644 index 00000000..8af156c8 --- /dev/null +++ b/Lombiq.HelpfulLibraries.OrchardCore/CompatibilitySuppressions.xml @@ -0,0 +1,8 @@ + + + + + PKV006 + net8.0 + + \ No newline at end of file diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Contents/CommonContentDisplayTypes.cs b/Lombiq.HelpfulLibraries.OrchardCore/Contents/CommonContentDisplayTypes.cs index fbe43af9..a71c4733 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Contents/CommonContentDisplayTypes.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Contents/CommonContentDisplayTypes.cs @@ -4,7 +4,7 @@ namespace Lombiq.HelpfulLibraries.OrchardCore.Contents; /// /// Values that can be used with or to safely select the correct display type. +/// cref="ContentOrchardRazorHelperExtensions.DisplayAsync"/> to safely select the correct display type. /// public static class CommonContentDisplayTypes { diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentEnumerableExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentEnumerableExtensions.cs index 12808fc4..ca6ad13a 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentEnumerableExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentEnumerableExtensions.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; namespace OrchardCore.ContentManagement; @@ -8,7 +9,16 @@ public static class ContentEnumerableExtensions /// Retrieves an enumeration of a content part based on its type from an enumeration of content items. /// /// The content part enumeration or empty enumeration if it doesn't exist. + [Obsolete($"Use {nameof(GetOrCreate)} instead.")] public static IEnumerable As(this IEnumerable? contents) where TPart : ContentPart => (contents?.SelectWhere(content => content.As())).EmptyIfNull(); + + /// + /// Retrieves an enumeration of a content part based on its type from an enumeration of content items. + /// + /// The content part enumeration or empty enumeration if it doesn't exist. + public static IEnumerable GetOrCreate(this IEnumerable? contents) + where TPart : ContentPart, new() => + (contents?.SelectWhere(content => content.GetMaybe())).EmptyIfNull(); } diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentExtensions.cs index 50a9d3c5..5befb95a 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentExtensions.cs @@ -16,10 +16,20 @@ public static class ContentExtensions /// Gets a content part by its type. /// /// The content part or if it doesn't exist. + [Obsolete($"Use {nameof(GetOrCreate)} instead.")] public static TPart? As(this IContent content) where TPart : ContentPart => content.ContentItem.As(); + /// + /// Gets a content part by its type or create a new one. + /// + /// The type of the content part. + /// The content part instance or a new one if it doesn't exist. + public static TPart? GetMaybe(this IContent? content) + where TPart : ContentPart, new() => + content?.ContentItem?.TryGet(out var part) == true ? part : null; + /// /// Gets a content part by its type or create a new one. /// @@ -129,7 +139,7 @@ public static async Task SanitizeContentItemVersionsAsync(this IContent content, /// /// Content item containing . /// Alias of the content item. - public static string? GetAlias(this IContent content) => content.As()?.Alias; + public static string? GetAlias(this IContent content) => content.GetMaybe()?.Alias; /// /// Provides the most essential data for a enough to identify it in a text format. Can be diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentManagerExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentManagerExtensions.cs index 53219855..5cf9dd09 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentManagerExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentManagerExtensions.cs @@ -15,7 +15,7 @@ public static class ContentManagerExtensions /// The version data of the content item to retrieve. public static async Task GetAsync(this IContentManager contentManager, string id, VersionOptions? versionOptions = null) where T : ContentPart => - (await contentManager.GetAsync(id, versionOptions))?.As(); + (await contentManager.GetAsync(id, versionOptions))?.TryGet(out var result) == true ? result : null; /// /// Persists the given with a new version if it does not exist yet, or updates it @@ -54,7 +54,7 @@ public static async Task> GetTaxonomyTermsAsync( ? null : await contentManager.GetAsync(taxonomyContentItemId); - return taxonomy?.As()?.Terms ?? []; + return taxonomy?.GetOrCreate().Terms ?? []; } /// @@ -68,7 +68,7 @@ public static async Task> GetTaxonomyTermsDisplayTex this IContentManager contentManager, string taxonomyId) => (await contentManager.GetAsync(taxonomyId)) - .As() + .GetOrCreate() .Terms .ToDictionary(term => term.ContentItemId, term => term.DisplayText); diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentOrchardHelperExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentOrchardHelperExtensions.cs index 4616e30d..6cb64480 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentOrchardHelperExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Contents/ContentOrchardHelperExtensions.cs @@ -1,9 +1,9 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.Extensions.DependencyInjection; using OrchardCore.ContentManagement; +using OrchardCore.DisplayManagement.Extensions; using System; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; @@ -16,30 +16,60 @@ public static class ContentOrchardHelperExtensions /// /// Gets the given content item's edit URL. /// - [SuppressMessage("Design", "CA1055:URI-like return values should not be strings", Justification = "It only returns relative URL.")] + [SuppressMessage("Design", "CA1055:URI-like return values should not be strings", Justification = "It only returns a relative URL.")] + [Obsolete($"Use {nameof(GetItemEditUrlAsync)} instead.")] public static string GetItemEditUrl(this IOrchardHelper orchardHelper, ContentItem contentItem) => orchardHelper.GetItemEditUrl(contentItem.ContentItemId); /// /// Gets the given content item's edit URL. /// - [SuppressMessage("Design", "CA1055:URI-like return values should not be strings", Justification = "It only returns relative URL.")] + [SuppressMessage("Design", "CA1055:URI-like return values should not be strings", Justification = "It only returns a relative URL.")] + [Obsolete($"Use {nameof(GetItemEditUrlAsync)} instead.")] public static string GetItemEditUrl(this IOrchardHelper orchardHelper, string contentItemId) { var urlHelper = orchardHelper.GetUrlHelper(); return urlHelper.EditContentItem(contentItemId); } + /// + /// Gets the given content item's edit URL. + /// + [SuppressMessage("Design", "CA1055:URI-like return values should not be strings", Justification = "It only returns a relative URL.")] + public static Task GetItemEditUrlAsync(this IOrchardHelper orchardHelper, ContentItem contentItem) => + orchardHelper.GetItemEditUrlAsync(contentItem.ContentItemId); + + /// + /// Gets the given content item's edit URL. + /// + [SuppressMessage("Design", "CA1055:URI-like return values should not be strings", Justification = "It only returns a relative URL.")] + public static async Task GetItemEditUrlAsync(this IOrchardHelper orchardHelper, string contentItemId) + { + var urlHelper = await orchardHelper.GetUrlHelperAsync(); + return urlHelper.EditContentItem(contentItemId); + } + /// /// Gets the given content item's display URL. /// - [SuppressMessage("Design", "CA1055:URI-like return values should not be strings", Justification = "It only returns relative URL.")] + [SuppressMessage("Design", "CA1055:URI-like return values should not be strings", Justification = "It only returns a relative URL.")] + [Obsolete($"Use {nameof(GetItemDisplayUrlAsync)} instead.")] public static string GetItemDisplayUrl(this IOrchardHelper orchardHelper, string contentItemId) { var urlHelper = orchardHelper.GetUrlHelper(); return urlHelper.DisplayContentItem(contentItemId); } + /// + /// Gets the given content item's display URL. + /// + [SuppressMessage("Design", "CA1055:URI-like return values should not be strings", Justification = "It only returns a relative URL.")] + public static async Task GetItemDisplayUrlAsync(this IOrchardHelper orchardHelper, string contentItemId) + { + var urlHelper = await orchardHelper.GetUrlHelperAsync(); + return urlHelper.DisplayContentItem(contentItemId); + } + /// /// Runs a getter delegate to get a content item or loads the item currently viewed via Content Preview. /// @@ -52,17 +82,11 @@ public static Task GetContentItemOrPreviewAsync( { var httpContext = orchardHelper.HttpContext; - if (httpContext.Request.Method == "POST") - { - var previewContentItemId = httpContext.Request.Form["PreviewContentItemId"].ToString(); - if (!string.IsNullOrEmpty(previewContentItemId) && - httpContext.RequestServices.GetService() is { } contentManager) - { - return contentManager.GetAsync(previewContentItemId); - } - } - - return contentItemGetter(); + return httpContext.Request.GetFormValueMaybe("PreviewContentItemId") is { } previewContentItemId && + !string.IsNullOrEmpty(previewContentItemId) && + httpContext.RequestServices.GetService() is { } contentManager + ? contentManager.GetAsync(previewContentItemId) + : contentItemGetter(); } /// @@ -84,11 +108,19 @@ public static string Action( /// /// Constructs a new instance using the current . /// - public static IUrlHelper GetUrlHelper(this IOrchardHelper orchardHelper) + [Obsolete($"Use {nameof(GetUrlHelperAsync)} instead.")] + public static IUrlHelper GetUrlHelper(this IOrchardHelper orchardHelper) => + orchardHelper.GetUrlHelperAsync().Result; + + /// + /// Constructs a new instance using the current . + /// + public static async Task GetUrlHelperAsync(this IOrchardHelper orchardHelper) { var serviceProvider = orchardHelper.HttpContext.RequestServices; var urlHelperFactory = serviceProvider.GetRequiredService(); - var actionContext = serviceProvider.GetService()?.ActionContext ?? + + var actionContext = await orchardHelper.HttpContext.GetActionContextAsync() ?? throw new InvalidOperationException("Couldn't access the action context."); return urlHelperFactory.GetUrlHelper(actionContext); diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Contents/CreatingOrUpdatingPartHandler.cs b/Lombiq.HelpfulLibraries.OrchardCore/Contents/CreatingOrUpdatingPartHandler.cs new file mode 100644 index 00000000..b31aaf93 --- /dev/null +++ b/Lombiq.HelpfulLibraries.OrchardCore/Contents/CreatingOrUpdatingPartHandler.cs @@ -0,0 +1,23 @@ +using OrchardCore.ContentManagement; +using OrchardCore.ContentManagement.Handlers; +using System.Threading.Tasks; + +namespace Lombiq.HelpfulLibraries.OrchardCore.Contents; + +/// +/// Abstraction over , to assign a common event handler for +/// both and events. This replicates the behavior of handlers +/// before OC 3.0 that only used the latter. +/// +public abstract class CreatingOrUpdatingPartHandler : ContentPartHandler + where TPart : ContentPart, new() +{ + protected abstract Task CreatingOrUpdatingAsync(TPart part); + + public override Task CreatingAsync(CreateContentContext context, TPart part) => + CreatingOrUpdatingAsync(part); + + public override Task UpdatingAsync(UpdateContentContext context, TPart part) => + CreatingOrUpdatingAsync(part); +} diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Contents/SingleDisplayTypeContentPartDisplayDriver.cs b/Lombiq.HelpfulLibraries.OrchardCore/Contents/SingleDisplayTypeContentPartDisplayDriver.cs index 6aba2dc4..d45c8ceb 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Contents/SingleDisplayTypeContentPartDisplayDriver.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Contents/SingleDisplayTypeContentPartDisplayDriver.cs @@ -66,7 +66,7 @@ public FieldHiderPlacementInfoResolver(IServiceProvider provider) => if (placementContext.DisplayType == _driver.DisplayType && placementContext.Differentiator?.StartsWithOrdinal($"{typeof(TPart).Name}-") == true) { - return new PlacementInfo { Location = "-" }; + return new PlacementInfo(location: "-"); } return null; diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Contents/TaxonomyHelper.cs b/Lombiq.HelpfulLibraries.OrchardCore/Contents/TaxonomyHelper.cs index cc7bd390..df051b58 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Contents/TaxonomyHelper.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Contents/TaxonomyHelper.cs @@ -54,7 +54,7 @@ public static IList GetAllChildren(ContentItem? contentItem, bool i if (contentItem == null) return results; if (includeSelf) results.Add(contentItem); - var partTerms = contentItem.As()?.Terms ?? Enumerable.Empty(); + var partTerms = contentItem.GetOrCreate().Terms ?? Enumerable.Empty(); var itemTerms = contentItem.GetProperty>(nameof(TaxonomyPart.Terms)) ?? Enumerable.Empty(); foreach (var child in partTerms.Concat(itemTerms)) { diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Data/IndexExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Data/IndexExtensions.cs index eae597ee..ae903265 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Data/IndexExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Data/IndexExtensions.cs @@ -16,7 +16,7 @@ public static IGroupFor MapFor( this DescribeContext context, Func map, bool latest = true) - where TPart : ContentPart + where TPart : ContentPart, new() where TIndex : IIndex => context.For().Map(map, latest); @@ -28,9 +28,9 @@ public static IGroupFor Map( this IMapFor mapFor, Func mapPartToIndex, bool latest = true) - where TPart : ContentPart + where TPart : ContentPart, new() where TIndex : IIndex => mapFor .When(item => item.Has() && (item.Latest || !latest)) - .Map(item => mapPartToIndex(item.As())); + .Map(item => mapPartToIndex(item.GetOrCreate())); } diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Data/QueryExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Data/QueryExtensions.cs index 41d6014d..8c6e7471 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Data/QueryExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Data/QueryExtensions.cs @@ -52,9 +52,9 @@ public static Task> PaginateAsync( this IQuery query, int pageIndex = 0, int count = int.MaxValue) - where TPart : ContentPart => + where TPart : ContentPart, new() => PaginateAsync(query, pageIndex, count) - .ContinueWith(t => t.Result.As(), TaskScheduler.Default); + .ContinueWith(t => t.Result.GetOrCreate(), TaskScheduler.Default); /// /// Breaks the query up into pages and lists the page using the given zero-based index. If pageIndex is 0 and count diff --git a/Lombiq.HelpfulLibraries.OrchardCore/DateTime/LocalClockExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/DateTime/LocalClockExtensions.cs index 8ba82d03..fe37efb0 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/DateTime/LocalClockExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/DateTime/LocalClockExtensions.cs @@ -48,11 +48,13 @@ public static Task ConvertToUtcAsync( /// public static async Task LocalizeAndFormatAsync( this ILocalClock localClock, - DateTime? dateTimeUtc) + DateTime? dateTimeUtc, + IFormatProvider? formatProvider = null) { if (dateTimeUtc == null) return null; - return ((DateTime?)(await localClock.ConvertToLocalAsync(dateTime: dateTimeUtc.Value)).DateTime).ToString(); + var localTime = await localClock.ConvertToLocalAsync(dateTime: dateTimeUtc.Value); + return localTime.DateTime.ToString(formatProvider); } private static async Task ExecuteInDifferentTimeZoneAsync(HttpContext httpContext, string timeZoneId, Func> asyncAction) diff --git a/Lombiq.HelpfulLibraries.OrchardCore/DependencyInjection/ServiceCollectionExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/DependencyInjection/ServiceCollectionExtensions.cs index b3db16ef..7d4ad7d2 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/DependencyInjection/ServiceCollectionExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/DependencyInjection/ServiceCollectionExtensions.cs @@ -3,6 +3,8 @@ using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using OrchardCore.Environment.Shell; +using OrchardCore.Environment.Shell.Descriptor.Models; using OrchardCore.Modules; using System; using System.Threading.Tasks; @@ -44,4 +46,33 @@ public static IServiceCollection AddInlineStartup( Func? configureAsync = null, int order = 0) => services.AddSingleton(new InlineStartup(configureServices, configure, configureAsync, order)); + + /// + /// Enables the provided tenant features, but only for the tenant. + /// + public static IServiceCollection AddDefaultTenantFeatures( + this IServiceCollection services, + params string[] featureIds) + { + foreach (var id in featureIds) + { + services.AddTransient(sp => + { + var shellSettings = sp.GetRequiredService(); + return shellSettings.Name == ShellSettings.DefaultShellName + ? new ShellFeature(id, alwaysEnabled: true) + : new(); + }); + } + + return services; + } + + /// + /// Enables the provided tenant features, but only for the tenant. + /// + public static OrchardCoreBuilder AddDefaultTenantFeatures( + this OrchardCoreBuilder builder, + params string[] featureIds) => + builder.ConfigureServices(services => services.AddDefaultTenantFeatures(featureIds)); } diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Docs/Elasticsearch.md b/Lombiq.HelpfulLibraries.OrchardCore/Docs/Elasticsearch.md index 7f5f609e..6fa793d9 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Docs/Elasticsearch.md +++ b/Lombiq.HelpfulLibraries.OrchardCore/Docs/Elasticsearch.md @@ -3,5 +3,5 @@ ## Extensions - `ElasticIndexManagerExtensions`: Adds extension methods for the `ElasticIndexManager` like `DeleteAllIndexesAsync`. -- `ResponseExtensions`: Adds extension methods for handling response objects from the `IElasticClient` like `ThrowIfFailed`. -- `ConfigurationExtensions`: Adds extension methods for configuration like `CreateElasticClient`. +- `ResponseExtensions`: Adds extension methods for handling response objects from the `ElasticsearchClient` like `ThrowIfFailed`. +- `ConfigurationExtensions`: Adds extension methods for configuration like `CreateElasticsearchClient`. diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ConfigurationExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ConfigurationExtensions.cs index a22ebf5b..f9bc0355 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ConfigurationExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ConfigurationExtensions.cs @@ -1,16 +1,33 @@ +using Elastic.Clients.Elasticsearch; using Microsoft.Extensions.Configuration; -using Nest; -using OrchardCore.Search.Elasticsearch.Core.Models; +using Microsoft.Extensions.Logging.Abstractions; +using OrchardCore.Elasticsearch.Core.Models; +using OrchardCore.Elasticsearch.Core.Services; +using System; namespace OrchardCore.Environment.Shell.Configuration; public static class ConfigurationExtensions { - public static IElasticClient CreateElasticClient(this IShellConfiguration shellConfiguration) + [Obsolete($"Use {nameof(CreateElasticsearchClient)} instead.")] + public static ElasticsearchClient CreateElasticClient(this IShellConfiguration shellConfiguration) => + shellConfiguration.CreateElasticsearchClient(); + + /// + /// Returns a new instance of the client. + /// + /// + /// Same as the code found in . + /// + public static ElasticsearchClient CreateElasticsearchClient( + this IShellConfiguration shellConfiguration, + IElasticsearchClientFactory? factory = null) { - var configuration = shellConfiguration.GetSection("OrchardCore_Elasticsearch"); - var elasticConfiguration = configuration.Get(); + factory ??= new ElasticsearchClientFactory(NullLogger.Instance); + + var configuration = shellConfiguration.GetSection(ElasticsearchConnectionOptionsConfigurations.ConfigSectionName); + var connectionOptions = configuration.Get(); - return new ElasticClient(elasticConfiguration?.GetConnectionSettings()); + return connectionOptions == null ? new ElasticsearchClient() : factory.Create(connectionOptions); } } diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ElasticIndexManagerExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ElasticIndexManagerExtensions.cs index b3d433f2..864b5e2b 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ElasticIndexManagerExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ElasticIndexManagerExtensions.cs @@ -1,6 +1,8 @@ +using Elastic.Clients.Elasticsearch; +using System; using System.Threading.Tasks; -namespace OrchardCore.Search.Elasticsearch.Core.Services; +namespace OrchardCore.Elasticsearch.Core.Services; public static class ElasticIndexManagerExtensions { @@ -8,6 +10,7 @@ public static class ElasticIndexManagerExtensions /// Clear all indexes for the tenant (within the prefix, if there is one) by passing a wildcard /// character (*) as the index name. /// - public static Task DeleteAllIndexesAsync(this ElasticIndexManager manager) => - manager.DeleteIndex("*"); + [Obsolete($"Use the equivalent extension method for {nameof(ElasticsearchClient)} instead.")] + public static Task DeleteAllIndexesAsync(this ElasticsearchIndexManager manager) => + throw new NotSupportedException($"Use the equivalent extension method for {nameof(ElasticsearchClient)} instead."); } diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ElasticsearchClientExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ElasticsearchClientExtensions.cs new file mode 100644 index 00000000..638b72bc --- /dev/null +++ b/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ElasticsearchClientExtensions.cs @@ -0,0 +1,35 @@ +using Elastic.Clients.Elasticsearch.Core; +using Elastic.Clients.Elasticsearch.IndexManagement; +using Microsoft.Extensions.Configuration; +using OrchardCore.Elasticsearch; +using OrchardCore.Elasticsearch.Core.Services; +using OrchardCore.Environment.Shell.Configuration; +using System.Linq; +using System.Threading.Tasks; + +namespace Elastic.Clients.Elasticsearch; + +public static class ElasticIndexManagerExtensions +{ + /// + /// Clear all indexes for the tenant (within the prefix, if there is one) by passing a wildcard character (*) + /// as the index name. + /// + public static async Task DeleteAllIndexesAsync(this ElasticsearchClient client, string? prefix) + { + var index = string.IsNullOrWhiteSpace(prefix) ? Indices.All : Indices.Index($"{prefix}_*"); + var getRequest = new GetIndexRequest(index) { ExpandWildcards = [ExpandWildcard.All], AllowNoIndices = true }; + var getResponse = (await client.Indices.GetAsync(getRequest)).ThrowIfFailed($"get index \"{index}\""); + + if (getResponse.Indices.Count == 0) return; + (await client.Indices.DeleteAsync(getResponse.Indices.Keys.ToArray())).ThrowIfFailed($"delete index \"{index}\""); + } + + public static Task DeleteAllIndexesAsync(this ElasticsearchClient client, IShellConfiguration shellConfiguration) + { + var prefix = shellConfiguration + .GetSection(ElasticsearchConnectionOptionsConfigurations.ConfigSectionName) + .GetValue(nameof(ElasticsearchOptions.IndexPrefix)); + return client.DeleteAllIndexesAsync(prefix); + } +} diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ElasticsearchIndexProfileStoreExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ElasticsearchIndexProfileStoreExtensions.cs new file mode 100644 index 00000000..970af9dc --- /dev/null +++ b/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ElasticsearchIndexProfileStoreExtensions.cs @@ -0,0 +1,17 @@ +using OrchardCore.Elasticsearch; +using OrchardCore.Indexing.Models; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace OrchardCore.Indexing; + +public static class ElasticsearchIndexProfileStoreExtensions +{ + /// + /// Returns only the Elasticsearch indexes from the . + /// + public static async Task> GetAllElasticsearchIndexesAsync(this IIndexProfileStore store) => + (await store.GetAllAsync()) + .Where(profile => profile.ProviderName == ElasticsearchConstants.ProviderName); +} diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ResponseExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ResponseExtensions.cs index e1085c38..87b0aae5 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ResponseExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Elasticsearch/ResponseExtensions.cs @@ -1,13 +1,13 @@ +using Elastic.Transport.Products.Elasticsearch; using System; - -namespace Nest; +namespace Elastic.Clients.Elasticsearch.Core; public static class ResponseExtensions { public static T ThrowIfFailed(this T response, string? message = null) - where T : ResponseBase + where T : ElasticsearchResponse { - if (response.IsValid) return response; + if (response.IsValidResponse) return response; if (!string.IsNullOrWhiteSpace(message)) message = $" ({message.Trim()})"; var error = $"Elasticsearch operation failed{message}. {response.DebugInformation}"; diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Environment/HostingDefaultsOrchardCoreBuilderExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Environment/HostingDefaultsOrchardCoreBuilderExtensions.cs index 7f5ee9dc..d143cb37 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Environment/HostingDefaultsOrchardCoreBuilderExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Environment/HostingDefaultsOrchardCoreBuilderExtensions.cs @@ -1,3 +1,4 @@ +using Lombiq.HelpfulLibraries.OrchardCore.DependencyInjection; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; @@ -122,9 +123,8 @@ public static OrchardCoreBuilder ConfigureAzureHostingDefaults( if (webApplicationBuilder.Configuration.IsAzureHosting()) { builder - .AddTenantFeatures( - "OrchardCore.DataProtection.Azure", - "Lombiq.Hosting.BuildVersionDisplay") + .AddDefaultTenantFeatures("Lombiq.Hosting.BuildVersionDisplay") + .AddTenantFeatures("OrchardCore.DataProtection.Azure") .DisableResourceDebugMode(); if (hostingConfiguration.AlwaysEnableAzureMediaStorage) diff --git a/Lombiq.HelpfulLibraries.OrchardCore/GraphQL/TotalOfContentTypeBuilder.cs b/Lombiq.HelpfulLibraries.OrchardCore/GraphQL/TotalOfContentTypeBuilder.cs index 035473ff..da9db74b 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/GraphQL/TotalOfContentTypeBuilder.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/GraphQL/TotalOfContentTypeBuilder.cs @@ -47,4 +47,9 @@ public void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition .CountAsync(); }); } + + public void Clear() + { + // Nothing to do here. + } } diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Lombiq.HelpfulLibraries.OrchardCore.csproj b/Lombiq.HelpfulLibraries.OrchardCore/Lombiq.HelpfulLibraries.OrchardCore.csproj index 2d687e7a..426b2b45 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Lombiq.HelpfulLibraries.OrchardCore.csproj +++ b/Lombiq.HelpfulLibraries.OrchardCore/Lombiq.HelpfulLibraries.OrchardCore.csproj @@ -1,57 +1,50 @@ - - + - net8.0 - $(DefaultItemExcludes);.git* + net10.0 enable + + + Lombiq Helpful Libraries - Orchard Core Libraries - Lombiq Technologies - Copyright © 2011, Lombiq Technologies Ltd. - Lombiq Helpful Libraries - Orchard Core Libraries: Various useful libraries that can be handy when developing for Orchard Core, to be used from your own projects. See the project website for detailed documentation. + 2011 + Various useful libraries that can be handy when developing for Orchard Core, to be used from your own projects. See the project website for detailed documentation. OrchardCore;Lombiq;AspNetCore;YesSql;GraphQL;Liquid;DateTime;DependencyInjection - NuGetIcon.png https://github.com/Lombiq/Helpful-Libraries https://github.com/Lombiq/Helpful-Libraries/blob/dev/Lombiq.HelpfulLibraries.OrchardCore/Readme.md - BSD-3-Clause - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - + + @@ -59,4 +52,6 @@ + + diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Mvc/MvcActionContextExtensions.cs b/Lombiq.HelpfulLibraries.OrchardCore/Mvc/MvcActionContextExtensions.cs index f5858921..46df8a5d 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Mvc/MvcActionContextExtensions.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Mvc/MvcActionContextExtensions.cs @@ -18,13 +18,18 @@ public static bool IsMvcRoute( string? controller = null, string? area = null) { - var routeValues = context.ActionDescriptor.RouteValues; + static bool IsMatch(IDictionary routeValues, string key, string? expected) => + routeValues.TryGetValue(key, out var value) && + (expected?.EqualsOrdinalIgnoreCase(value) ?? value is null); - if (!string.IsNullOrEmpty(action) && routeValues["Action"]?.EqualsOrdinalIgnoreCase(action) != true) return false; - if (!string.IsNullOrEmpty(controller) && routeValues["Controller"]?.EqualsOrdinalIgnoreCase(controller) != true) return false; - if (!string.IsNullOrEmpty(area) && routeValues["Area"]?.EqualsOrdinalIgnoreCase(area) != true) return false; + var routeValues = new Dictionary( + context.ActionDescriptor.RouteValues, + StringComparer.OrdinalIgnoreCase); - return true; + return + IsMatch(routeValues, "Action", action) && + IsMatch(routeValues, "Controller", controller) && + IsMatch(routeValues, "Area", area); } /// diff --git a/Lombiq.HelpfulLibraries.OrchardCore/ResourceManagement/ResourceFilterBuilder.cs b/Lombiq.HelpfulLibraries.OrchardCore/ResourceManagement/ResourceFilterBuilder.cs index 913baef1..b8225125 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/ResourceManagement/ResourceFilterBuilder.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/ResourceManagement/ResourceFilterBuilder.cs @@ -164,12 +164,15 @@ private ResourceFilter WhenContentTypeInner(string displayType, params string[] } var session = context.RequestServices.GetRequiredService(); - var query = displayType.EqualsOrdinalIgnoreCase("Edit") ? - // We check for both published and draft content items. - session.QueryIndex(index => index.Published || (index.Latest && !index.Published)) + + // In case of Edit, we check for both published and draft content items. + var query = string.Equals(displayType, "Edit", StringComparison.Ordinal) + ? session.QueryIndex(index => index.Published || (index.Latest && !index.Published)) : session.QueryContentItemIndex(PublicationStatus.Published); - var contentItemIndex = await query.Where(index => index.ContentItemId == contentItemId) - .FirstOrDefaultAsync(); + + var contentItemIndex = await query + .Where(index => index.ContentItemId == contentItemId) + .FirstOrDefaultAsync(context.RequestAborted); return contentItemIndex?.ContentType is { } contentType && contentTypes.Contains(contentType, StringComparer.OrdinalIgnoreCase); }); @@ -181,11 +184,9 @@ private static bool GetContentItemId(string displayType, HttpContext context, ou { try { - if (HttpMethods.IsPost(context.Request.Method) - && (context.Request.ContentType?.ContainsOrdinalIgnoreCase("application/x-www-form-urlencoded") ?? false) - && context.Request.Form.TryGetValue("PreviewContentItemId", out var previewContentItemId)) + if (context.Request.GetFormValueMaybe("PreviewContentItemId") is { } previewContentItemId) { - contentItemId = previewContentItemId.FirstOrDefault(); + contentItemId = previewContentItemId; return true; } @@ -211,7 +212,6 @@ private static bool GetContentItemId(string displayType, HttpContext context, ou } contentItemId = null; - return false; } diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Security/ContentSecurityPolicyAttributeContentSecurityPolicyProvider.cs b/Lombiq.HelpfulLibraries.OrchardCore/Security/ContentSecurityPolicyAttributeContentSecurityPolicyProvider.cs index 2239147d..7241e8c2 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Security/ContentSecurityPolicyAttributeContentSecurityPolicyProvider.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Security/ContentSecurityPolicyAttributeContentSecurityPolicyProvider.cs @@ -1,10 +1,10 @@ using Lombiq.HelpfulLibraries.AspNetCore.Security; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Controllers; -using Microsoft.AspNetCore.Mvc.Infrastructure; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Reflection; using System.Threading.Tasks; using static Lombiq.HelpfulLibraries.AspNetCore.Security.ContentSecurityPolicyDirectives; @@ -60,16 +60,22 @@ public class ContentSecurityPolicyAttributeContentSecurityPolicyProvider : ICont { public ValueTask UpdateAsync(IDictionary securityPolicies, HttpContext context) { - if (context.RequestServices.GetService() is - { ActionContext.ActionDescriptor: ControllerActionDescriptor actionDescriptor }) + var actionDescriptor = context + .GetEndpoint()? + .Metadata + .CastWhere() + .FirstOrDefault(); + + var attributes = actionDescriptor? + .MethodInfo + .GetCustomAttributes() ?? []; + + foreach (var attribute in attributes) { - foreach (var attribute in actionDescriptor.MethodInfo.GetCustomAttributes()) - { - ContentSecurityPolicyProvider.MergeDirectiveValues( - securityPolicies, - attribute.DirectiveNames, - attribute.DirectiveValue); - } + ContentSecurityPolicyProvider.MergeDirectiveValues( + securityPolicies, + attribute.DirectiveNames, + attribute.DirectiveValue); } return ValueTask.CompletedTask; diff --git a/Lombiq.HelpfulLibraries.OrchardCore/Shapes/PerTenantShapeTableManager.cs b/Lombiq.HelpfulLibraries.OrchardCore/Shapes/PerTenantShapeTableManager.cs index 55e5c609..aebe61ed 100644 --- a/Lombiq.HelpfulLibraries.OrchardCore/Shapes/PerTenantShapeTableManager.cs +++ b/Lombiq.HelpfulLibraries.OrchardCore/Shapes/PerTenantShapeTableManager.cs @@ -9,7 +9,6 @@ using OrchardCore.Environment.Shell; using OrchardCore.Settings; using System; -using System.Collections.Concurrent; using System.Collections.Frozen; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -111,8 +110,6 @@ public async Task GetShapeTableAsync(string themeId) .Select((id, index) => new { id, index }) .ToDictionary(item => item.id, item => item.index); - var concurrentShapeDescriptors = new ConcurrentDictionary(shapeDescriptors); - // Using the dictionary for O(1) index retrieval instead of O(n) in a list. var descriptors = shapeDescriptors .Where(shapeDescriptor => featureIdIndexLookup.ContainsKey(shapeDescriptor.Value.Feature.Id) && @@ -121,9 +118,7 @@ public async Task GetShapeTableAsync(string themeId) .GroupBy(shapeDescriptor => shapeDescriptor.Value.ShapeType, StringComparer.OrdinalIgnoreCase) .Select(group => new ShapeDescriptorIndex( shapeType: group.Key, - alterationKeys: group.Select(kv => kv.Key), - descriptors: concurrentShapeDescriptors - )) + alterations: group.Select(pair => pair.Value))) .ToList(); shapeTable = new ShapeTable( diff --git a/Lombiq.HelpfulLibraries.Refit/Lombiq.HelpfulLibraries.Refit.csproj b/Lombiq.HelpfulLibraries.Refit/Lombiq.HelpfulLibraries.Refit.csproj index 38f9ada3..c1817163 100644 --- a/Lombiq.HelpfulLibraries.Refit/Lombiq.HelpfulLibraries.Refit.csproj +++ b/Lombiq.HelpfulLibraries.Refit/Lombiq.HelpfulLibraries.Refit.csproj @@ -1,30 +1,25 @@ - - + netstandard2.0 - $(DefaultItemExcludes);.git* enable + + + Lombiq Helpful Libraries - Refit Libraries for Orchard Core - Lombiq Technologies - Copyright © 2011, Lombiq Technologies Ltd. - Lombiq Helpful Libraries - Refit Libraries for Orchard Core: Adds helpers for working with the Refit RESTful API consumer library. See the project website for detailed documentation. - NuGetIcon.png + 2011 + Adds helpers for working with the Refit RESTful API consumer library. See the project website for detailed documentation. Lombiq;Refit;REST;RESTful;API https://github.com/Lombiq/Helpful-Libraries https://github.com/Lombiq/Helpful-Libraries/blob/dev/Lombiq.HelpfulLibraries.Refit/Readme.md - BSD-3-Clause - - - - - + + diff --git a/Lombiq.HelpfulLibraries.RestEase/CompatibilitySuppressions.xml b/Lombiq.HelpfulLibraries.RestEase/CompatibilitySuppressions.xml new file mode 100644 index 00000000..8af156c8 --- /dev/null +++ b/Lombiq.HelpfulLibraries.RestEase/CompatibilitySuppressions.xml @@ -0,0 +1,8 @@ + + + + + PKV006 + net8.0 + + \ No newline at end of file diff --git a/Lombiq.HelpfulLibraries.RestEase/Lombiq.HelpfulLibraries.RestEase.csproj b/Lombiq.HelpfulLibraries.RestEase/Lombiq.HelpfulLibraries.RestEase.csproj index 46919d65..67a22060 100644 --- a/Lombiq.HelpfulLibraries.RestEase/Lombiq.HelpfulLibraries.RestEase.csproj +++ b/Lombiq.HelpfulLibraries.RestEase/Lombiq.HelpfulLibraries.RestEase.csproj @@ -1,30 +1,23 @@ - - + - net8.0 - $(DefaultItemExcludes);.git* + net10.0 enable + + + Lombiq Helpful Libraries - RestEase Libraries for Orchard Core - Lombiq Technologies - Copyright © 2011, Lombiq Technologies Ltd. - Lombiq Helpful Libraries - RestEase Libraries for Orchard Core for Orchard Core: Adds a typed HTTP client to the service collection using RestEase, for dependency injection. See the project website for detailed documentation. - NuGetIcon.png + 2011 + Adds a typed HTTP client to the service collection using RestEase, for dependency injection. See the project website for detailed documentation. OrchardCore;Lombiq;RestEase https://github.com/Lombiq/Helpful-Libraries https://github.com/Lombiq/Helpful-Libraries/blob/dev/Lombiq.HelpfulLibraries.RestEase/Readme.md - BSD-3-Clause - - - - - - + all @@ -32,4 +25,6 @@ + + diff --git a/Lombiq.HelpfulLibraries.Samples.Tests.UI/Extensions/TestCaseUITestContextExtensions.AssertSimpleQueryAsync.approved.json b/Lombiq.HelpfulLibraries.Samples.Tests.UI/Extensions/TestCaseUITestContextExtensions.AssertSimpleQueryAsync.approved.json index 76c7f9f1..8b72aa13 100644 --- a/Lombiq.HelpfulLibraries.Samples.Tests.UI/Extensions/TestCaseUITestContextExtensions.AssertSimpleQueryAsync.approved.json +++ b/Lombiq.HelpfulLibraries.Samples.Tests.UI/Extensions/TestCaseUITestContextExtensions.AssertSimpleQueryAsync.approved.json @@ -1 +1 @@ -[{"documentId":7,"contentItemId":"","path":"tags/space","published":true,"latest":true,"containedContentItemId":"","jsonPath":"TaxonomyPart.Terms[2]","id":12},{"documentId":7,"contentItemId":"","path":"tags/exploration","published":true,"latest":true,"containedContentItemId":"","jsonPath":"TaxonomyPart.Terms[1]","id":11},{"documentId":7,"contentItemId":"","path":"tags/earth","published":true,"latest":true,"containedContentItemId":"","jsonPath":"TaxonomyPart.Terms[0]","id":10},{"documentId":7,"contentItemId":"","path":"tags","published":true,"latest":true,"containedContentItemId":"","jsonPath":null,"id":9},{"documentId":8,"contentItemId":"","path":"categories/travel","published":true,"latest":true,"containedContentItemId":"","jsonPath":"TaxonomyPart.Terms[0]","id":18},{"documentId":8,"contentItemId":"","path":"categories","published":true,"latest":true,"containedContentItemId":"","jsonPath":null,"id":17},{"documentId":23,"contentItemId":"","path":"carousel-widget-example","published":true,"latest":true,"containedContentItemId":"","jsonPath":null,"id":31},{"documentId":11,"contentItemId":"","path":"about","published":true,"latest":true,"containedContentItemId":"","jsonPath":null,"id":27}] \ No newline at end of file +[{"containedContentItemId":"","contentItemId":"","jsonPath":"TaxonomyPart.Terms[2]","latest":true,"path":"tags/space","published":true},{"containedContentItemId":"","contentItemId":"","jsonPath":"TaxonomyPart.Terms[1]","latest":true,"path":"tags/exploration","published":true},{"containedContentItemId":"","contentItemId":"","jsonPath":"TaxonomyPart.Terms[0]","latest":true,"path":"tags/earth","published":true},{"containedContentItemId":"","contentItemId":"","jsonPath":null,"latest":true,"path":"tags","published":true},{"containedContentItemId":"","contentItemId":"","jsonPath":"TaxonomyPart.Terms[0]","latest":true,"path":"categories/travel","published":true},{"containedContentItemId":"","contentItemId":"","jsonPath":null,"latest":true,"path":"categories","published":true},{"containedContentItemId":"","contentItemId":"","jsonPath":null,"latest":true,"path":"carousel-widget-example","published":true},{"containedContentItemId":"","contentItemId":"","jsonPath":null,"latest":true,"path":"about","published":true}] \ No newline at end of file diff --git a/Lombiq.HelpfulLibraries.Samples.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs b/Lombiq.HelpfulLibraries.Samples.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs index c9f8d379..41e7f14b 100644 --- a/Lombiq.HelpfulLibraries.Samples.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs +++ b/Lombiq.HelpfulLibraries.Samples.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs @@ -4,6 +4,8 @@ using Lombiq.Tests.UI.Services; using Shouldly; using System; +using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Text.Json; using System.Text.Json.Nodes; @@ -28,8 +30,22 @@ private static async Task AssertSimpleQueryAsync(UITestContext context, HttpClie { var simpleQueryUrl = context.GetAbsoluteUrlOfAction(controller => controller.SimpleQuery()); var simpleQueryOutput = await client.GetStringAsync(simpleQueryUrl, context.Configuration.TestCancellationToken); + var simpleQueryParsed = JsonSerializer.Deserialize>>(simpleQueryOutput); - simpleQueryOutput.ShouldMatchApproved( + // Cleanup received data. + simpleQueryParsed = simpleQueryParsed + .Select(item => item + // The "id" and "documentId" properties depend on the record's write order in the database. They are not + // guaranteed to be consistent on different setups, and they are not relevant for this query. + .Where(pair => pair.Key is not "id" and not "documentId") + // The order of these properties is not guaranteed either, so sorting them here makes it more reliable. + .OrderBy(pair => pair.Key) + .ToDictionary(pair => pair.Key, pair => pair.Value)) + .ToList(); + + // The results are re-serialized into JSON using standard options, so they can be compared in a consistent way. + var reserialized = JsonSerializer.Serialize(simpleQueryParsed, JOptions.Default); + reserialized.ShouldMatchApproved( options => options .WithScrubber(ScrubContentItemIds) .WithFileExtension("json"), diff --git a/Lombiq.HelpfulLibraries.Samples.Tests.UI/Lombiq.HelpfulLibraries.Samples.Tests.UI.csproj b/Lombiq.HelpfulLibraries.Samples.Tests.UI/Lombiq.HelpfulLibraries.Samples.Tests.UI.csproj index ef468d17..6fc47241 100644 --- a/Lombiq.HelpfulLibraries.Samples.Tests.UI/Lombiq.HelpfulLibraries.Samples.Tests.UI.csproj +++ b/Lombiq.HelpfulLibraries.Samples.Tests.UI/Lombiq.HelpfulLibraries.Samples.Tests.UI.csproj @@ -1,17 +1,15 @@ - - + - net8.0 - $(DefaultItemExcludes);.git* + net10.0 - - - + + - + + diff --git a/Lombiq.HelpfulLibraries.Samples/Lombiq.HelpfulLibraries.Samples.csproj b/Lombiq.HelpfulLibraries.Samples/Lombiq.HelpfulLibraries.Samples.csproj index 1e8e5b82..2f6d7912 100644 --- a/Lombiq.HelpfulLibraries.Samples/Lombiq.HelpfulLibraries.Samples.csproj +++ b/Lombiq.HelpfulLibraries.Samples/Lombiq.HelpfulLibraries.Samples.csproj @@ -1,27 +1,16 @@ - - + - net8.0 - true + net10.0 false - $(DefaultItemExcludes);.git* - - - - - - - - - - - - + + - + + + diff --git a/Lombiq.HelpfulLibraries.SourceGenerators/Lombiq.HelpfulLibraries.SourceGenerators.csproj b/Lombiq.HelpfulLibraries.SourceGenerators/Lombiq.HelpfulLibraries.SourceGenerators.csproj index 3d4dd97b..de3ed753 100644 --- a/Lombiq.HelpfulLibraries.SourceGenerators/Lombiq.HelpfulLibraries.SourceGenerators.csproj +++ b/Lombiq.HelpfulLibraries.SourceGenerators/Lombiq.HelpfulLibraries.SourceGenerators.csproj @@ -1,10 +1,9 @@ - - + netstandard2.0 true enable - latest + 14.0 true true @@ -16,25 +15,20 @@ Lombiq.HelpfulLibraries.SourceGenerators + + + Lombiq Helpful Libraries - Source Generators for Orchard Core - Lombiq Technologies - Copyright © 2011, Lombiq Technologies Ltd. - Lombiq Helpful Libraries - Source Generators for Orchard Core for Orchard Core: Adds helpful source generators. See the project website for detailed documentation. - NuGetIcon.png + 2011 + Adds helpful source generators. See the project website for detailed documentation. OrchardCore;Lombiq;SourceGenerators https://github.com/Lombiq/Helpful-Libraries https://github.com/Lombiq/Helpful-Libraries/blob/dev/Lombiq.HelpfulLibraries.SourceGenerators/Readme.md - BSD-3-Clause - - - - - - + @@ -44,7 +38,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -78,4 +72,6 @@ + + diff --git a/Lombiq.HelpfulLibraries.Tests/Lombiq.HelpfulLibraries.Tests.csproj b/Lombiq.HelpfulLibraries.Tests/Lombiq.HelpfulLibraries.Tests.csproj index dd478c7d..85989c92 100644 --- a/Lombiq.HelpfulLibraries.Tests/Lombiq.HelpfulLibraries.Tests.csproj +++ b/Lombiq.HelpfulLibraries.Tests/Lombiq.HelpfulLibraries.Tests.csproj @@ -1,14 +1,15 @@ - - + - net8.0 - Exe + net10.0 + + + - $(SolutionDir)src\Libraries\Lombiq.HelpfulLibraries\Lombiq.HelpfulLibraries.SourceGenerators\bin\Debug\netstandard2.0\Lombiq.HelpfulLibraries.SourceGenerators.dll + $(LombiqHelpfulLibrariesPath)\Lombiq.HelpfulLibraries.SourceGenerators\bin\Debug\netstandard2.0\Lombiq.HelpfulLibraries.SourceGenerators.dll - $(SolutionDir)src\Libraries\Lombiq.HelpfulLibraries\Lombiq.HelpfulLibraries.SourceGenerators\bin\Release\netstandard2.0\Lombiq.HelpfulLibraries.SourceGenerators.dll + $(LombiqHelpfulLibrariesPath)\Lombiq.HelpfulLibraries.SourceGenerators\bin\Release\netstandard2.0\Lombiq.HelpfulLibraries.SourceGenerators.dll @@ -17,16 +18,6 @@ - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - @@ -42,4 +33,6 @@ + + diff --git a/Lombiq.HelpfulLibraries.Tests/UnitTests/Extensions/SafeJsonTests.cs b/Lombiq.HelpfulLibraries.Tests/UnitTests/Extensions/SafeJsonTests.cs index 5c1b5dcd..17651618 100644 --- a/Lombiq.HelpfulLibraries.Tests/UnitTests/Extensions/SafeJsonTests.cs +++ b/Lombiq.HelpfulLibraries.Tests/UnitTests/Extensions/SafeJsonTests.cs @@ -120,7 +120,7 @@ private static async Task> SafeJsonToDictionaryAsync( private sealed record TestResults( ListLoggerProvider LoggerProvider, - Dictionary Failure, - Dictionary FailureAsync, - Dictionary Success); + IDictionary Failure, + IDictionary FailureAsync, + IDictionary Success); } diff --git a/Lombiq.HelpfulLibraries.Tests/UnitTests/Services/ManualConnectingIndexServiceFixture.cs b/Lombiq.HelpfulLibraries.Tests/UnitTests/Services/ManualConnectingIndexServiceFixture.cs index 0908a0fd..69be30c0 100644 --- a/Lombiq.HelpfulLibraries.Tests/UnitTests/Services/ManualConnectingIndexServiceFixture.cs +++ b/Lombiq.HelpfulLibraries.Tests/UnitTests/Services/ManualConnectingIndexServiceFixture.cs @@ -44,9 +44,9 @@ public async Task SessionAsync(Func action) { if (Store == null) await CreateDatabaseAsync(); - await using var session = Store.CreateSession(); + await using var session = Store!.CreateSession(); await action(session); - await session.FlushAsync(); + await session.FlushAsync(Xunit.TestContext.Current.CancellationToken); } // We could have a diff --git a/Lombiq.HelpfulLibraries.Tests/UnitTests/Services/ManualConnectingIndexServiceTests.cs b/Lombiq.HelpfulLibraries.Tests/UnitTests/Services/ManualConnectingIndexServiceTests.cs index 8aa64297..088c2c0b 100644 --- a/Lombiq.HelpfulLibraries.Tests/UnitTests/Services/ManualConnectingIndexServiceTests.cs +++ b/Lombiq.HelpfulLibraries.Tests/UnitTests/Services/ManualConnectingIndexServiceTests.cs @@ -1,6 +1,7 @@ using Lombiq.HelpfulLibraries.Tests.Models; using Shouldly; using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Xunit; @@ -22,12 +23,17 @@ public class ManualConnectingIndexServiceTests : IClassFixture _fixture.SessionAsync(async session => { - var indices = (await session.QueryIndex().ListAsync()).ToList(); + var indices = (await session.QueryIndex().ListAsync(TestContext.Current.CancellationToken)).ToList(); indices.ShouldNotBeEmpty(); - var documents = (await session.Query().ListAsync()) + IDictionary documents = + (await session.Query().ListAsync(TestContext.Current.CancellationToken)) .ToDictionary(document => document.Name); - foreach (var index in indices) documents.ShouldContainKey(NamePrefix + index.Number.ToTechnicalString()); + + foreach (var index in indices) + { + documents.ShouldContainKey(NamePrefix + index.Number.ToTechnicalString()); + } }); [Fact] @@ -36,7 +42,7 @@ public Task AllIndexShouldRetrieveItsDocument() => _fixture.SessionAsync(async s // In the example 3's index was intentionally skipped and 6's index was deleted after the fact. var numbers = Enumerable.Range(0, 10).Where(i => i is not 3 and not 6).ToList(); var query = session.Query(index => index.Number.IsIn(numbers)); - var list = await query.ListAsync(); + var list = await query.ListAsync(TestContext.Current.CancellationToken); var documents = list.ToList(); documents.Select(document => document.Name) .ShouldBe(_fixture.Documents.Where((_, index) => index is not 3 and not 6).Select(document => document.Name)); @@ -45,7 +51,10 @@ public Task AllIndexShouldRetrieveItsDocument() => _fixture.SessionAsync(async s [Fact] public Task MissingOrDeletedIndexShouldNotRetrieveAnyDocument() => _fixture.SessionAsync(async session => { - var documents = (await session.Query(index => index.Number.IsIn(Numbers)).ListAsync()).ToList(); + var documents = (await session + .Query(index => index.Number.IsIn(Numbers)) + .ListAsync(TestContext.Current.CancellationToken)) + .AsList(); documents.ShouldBeEmpty(); }); } diff --git a/Lombiq.HelpfulLibraries.sln b/Lombiq.HelpfulLibraries.sln deleted file mode 100644 index 6f5df29d..00000000 --- a/Lombiq.HelpfulLibraries.sln +++ /dev/null @@ -1,85 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.1.32319.34 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.HelpfulLibraries.Attributes", "Lombiq.HelpfulLibraries.Attributes\Lombiq.HelpfulLibraries.Attributes.csproj", "{5E533F4E-2C8C-4FD1-ADDE-551B61F7C416}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.HelpfulLibraries.SourceGenerators", "Lombiq.HelpfulLibraries.SourceGenerators\Lombiq.HelpfulLibraries.SourceGenerators.csproj", "{EEC5970E-7AF7-4360-9C6D-6F3937AEE8E6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lombiq.HelpfulLibraries", "Lombiq.HelpfulLibraries\Lombiq.HelpfulLibraries.csproj", "{5F3379C7-ED6B-46AA-B6C3-17CBC2284417}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lombiq.HelpfulLibraries.LinqToDb", "Lombiq.HelpfulLibraries.LinqToDb\Lombiq.HelpfulLibraries.LinqToDb.csproj", "{5F4C7938-BBC4-4A44-83E1-2F33B7717A76}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lombiq.HelpfulLibraries.RestEase", "Lombiq.HelpfulLibraries.RestEase\Lombiq.HelpfulLibraries.RestEase.csproj", "{2D7174D1-88E0-4063-8139-C7FCCC9B3326}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lombiq.HelpfulLibraries.AspNetCore", "Lombiq.HelpfulLibraries.AspNetCore\Lombiq.HelpfulLibraries.AspNetCore.csproj", "{5E5E1E2F-8096-4B91-809B-5F86A3E8ADCA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lombiq.HelpfulLibraries.OrchardCore", "Lombiq.HelpfulLibraries.OrchardCore\Lombiq.HelpfulLibraries.OrchardCore.csproj", "{741E56D8-C42C-4506-841E-DD2245B2E631}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lombiq.HelpfulLibraries.Common", "Lombiq.HelpfulLibraries.Common\Lombiq.HelpfulLibraries.Common.csproj", "{28D8FE01-5D8B-43EE-8B7A-927D3D3DC627}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lombiq.HelpfulLibraries.OrchardCore.Testing", "Lombiq.HelpfulLibraries.OrchardCore.Testing\Lombiq.HelpfulLibraries.OrchardCore.Testing.csproj", "{F87DC121-2ADD-458D-9E01-BC0032860188}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.HelpfulLibraries.Cli", "Lombiq.HelpfulLibraries.Cli\Lombiq.HelpfulLibraries.Cli.csproj", "{E4434D6F-7C4F-4CBD-AAA3-B57809DFF571}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.HelpfulLibraries.Refit", "Lombiq.HelpfulLibraries.Refit\Lombiq.HelpfulLibraries.Refit.csproj", "{5DC1A3D5-0626-4258-95C6-7E5CA5495A80}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5F3379C7-ED6B-46AA-B6C3-17CBC2284417}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5F3379C7-ED6B-46AA-B6C3-17CBC2284417}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5F3379C7-ED6B-46AA-B6C3-17CBC2284417}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5F3379C7-ED6B-46AA-B6C3-17CBC2284417}.Release|Any CPU.Build.0 = Release|Any CPU - {5F4C7938-BBC4-4A44-83E1-2F33B7717A76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5F4C7938-BBC4-4A44-83E1-2F33B7717A76}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5F4C7938-BBC4-4A44-83E1-2F33B7717A76}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5F4C7938-BBC4-4A44-83E1-2F33B7717A76}.Release|Any CPU.Build.0 = Release|Any CPU - {2D7174D1-88E0-4063-8139-C7FCCC9B3326}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2D7174D1-88E0-4063-8139-C7FCCC9B3326}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2D7174D1-88E0-4063-8139-C7FCCC9B3326}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2D7174D1-88E0-4063-8139-C7FCCC9B3326}.Release|Any CPU.Build.0 = Release|Any CPU - {5E5E1E2F-8096-4B91-809B-5F86A3E8ADCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5E5E1E2F-8096-4B91-809B-5F86A3E8ADCA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5E5E1E2F-8096-4B91-809B-5F86A3E8ADCA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5E5E1E2F-8096-4B91-809B-5F86A3E8ADCA}.Release|Any CPU.Build.0 = Release|Any CPU - {741E56D8-C42C-4506-841E-DD2245B2E631}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {741E56D8-C42C-4506-841E-DD2245B2E631}.Debug|Any CPU.Build.0 = Debug|Any CPU - {741E56D8-C42C-4506-841E-DD2245B2E631}.Release|Any CPU.ActiveCfg = Release|Any CPU - {741E56D8-C42C-4506-841E-DD2245B2E631}.Release|Any CPU.Build.0 = Release|Any CPU - {28D8FE01-5D8B-43EE-8B7A-927D3D3DC627}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {28D8FE01-5D8B-43EE-8B7A-927D3D3DC627}.Debug|Any CPU.Build.0 = Debug|Any CPU - {28D8FE01-5D8B-43EE-8B7A-927D3D3DC627}.Release|Any CPU.ActiveCfg = Release|Any CPU - {28D8FE01-5D8B-43EE-8B7A-927D3D3DC627}.Release|Any CPU.Build.0 = Release|Any CPU - {F87DC121-2ADD-458D-9E01-BC0032860188}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F87DC121-2ADD-458D-9E01-BC0032860188}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F87DC121-2ADD-458D-9E01-BC0032860188}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F87DC121-2ADD-458D-9E01-BC0032860188}.Release|Any CPU.Build.0 = Release|Any CPU - {E4434D6F-7C4F-4CBD-AAA3-B57809DFF571}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E4434D6F-7C4F-4CBD-AAA3-B57809DFF571}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E4434D6F-7C4F-4CBD-AAA3-B57809DFF571}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E4434D6F-7C4F-4CBD-AAA3-B57809DFF571}.Release|Any CPU.Build.0 = Release|Any CPU - {5DC1A3D5-0626-4258-95C6-7E5CA5495A80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5DC1A3D5-0626-4258-95C6-7E5CA5495A80}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5DC1A3D5-0626-4258-95C6-7E5CA5495A80}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5DC1A3D5-0626-4258-95C6-7E5CA5495A80}.Release|Any CPU.Build.0 = Release|Any CPU - {EEC5970E-7AF7-4360-9C6D-6F3937AEE8E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EEC5970E-7AF7-4360-9C6D-6F3937AEE8E6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EEC5970E-7AF7-4360-9C6D-6F3937AEE8E6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EEC5970E-7AF7-4360-9C6D-6F3937AEE8E6}.Release|Any CPU.Build.0 = Release|Any CPU - {5E533F4E-2C8C-4FD1-ADDE-551B61F7C416}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5E533F4E-2C8C-4FD1-ADDE-551B61F7C416}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5E533F4E-2C8C-4FD1-ADDE-551B61F7C416}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5E533F4E-2C8C-4FD1-ADDE-551B61F7C416}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {5F8B26CF-89E9-487E-B4B0-643F1A109459} - EndGlobalSection -EndGlobal diff --git a/Lombiq.HelpfulLibraries.slnx b/Lombiq.HelpfulLibraries.slnx new file mode 100644 index 00000000..c654aaf4 --- /dev/null +++ b/Lombiq.HelpfulLibraries.slnx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/Lombiq.HelpfulLibraries/CompatibilitySuppressions.xml b/Lombiq.HelpfulLibraries/CompatibilitySuppressions.xml new file mode 100644 index 00000000..8af156c8 --- /dev/null +++ b/Lombiq.HelpfulLibraries/CompatibilitySuppressions.xml @@ -0,0 +1,8 @@ + + + + + PKV006 + net8.0 + + \ No newline at end of file diff --git a/Lombiq.HelpfulLibraries/Lombiq.HelpfulLibraries.csproj b/Lombiq.HelpfulLibraries/Lombiq.HelpfulLibraries.csproj index 1f774ddf..c71386f2 100644 --- a/Lombiq.HelpfulLibraries/Lombiq.HelpfulLibraries.csproj +++ b/Lombiq.HelpfulLibraries/Lombiq.HelpfulLibraries.csproj @@ -1,34 +1,22 @@ - - + - net8.0 - $(DefaultItemExcludes);.git* + net10.0 enable + + + Lombiq Helpful Libraries - Lombiq Technologies - Copyright © 2011, Lombiq Technologies Ltd. - Lombiq Helpful Libraries: Various useful libraries that can be handy when developing for .NET, ASP.NET Core, and Orchard Core, to be used from your own projects. This package references all Helpful Libraries libraries, but you can use only the ones specific for your use-case, see the dependencies. See the project website for detailed documentation. + 2011 + Various useful libraries that can be handy when developing for .NET, ASP.NET Core, and Orchard Core, to be used from your own projects. This package references all Helpful Libraries libraries, but you can use only the ones specific for your use-case, see the dependencies. See the project website for detailed documentation. OrchardCore;Lombiq;AspNetCore;YesSql;DateTime;DependencyInjection;GraphQL;Liquid;Localization;Middlewares;Utilities;LinqToDB - NuGetIcon.png https://github.com/Lombiq/Helpful-Libraries - https://github.com/Lombiq/Helpful-Libraries - BSD-3-Clause - - - - - - - - - @@ -37,4 +25,6 @@ + + diff --git a/NuGet.config b/NuGet.config index 2ba9b219..2e8ae60a 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,15 +3,7 @@ - - - - - - - -