Skip to content

Latest commit

 

History

History
309 lines (199 loc) · 15.9 KB

3.0.0.md

File metadata and controls

309 lines (199 loc) · 15.9 KB

Orchard Core 3.0.0

Release date: Not yet released

Before upgrading from version 2 to v3, it is important to first compile your project using the latest available v2 version, resolve any warnings, and then proceed with the upgrade to v3.

Breaking Changes

Email Module

Previously, emails sent from Orchard Core could have either a plain text body, or an HTML body, but not both. Now, they can have both. This also brings some code-level API changes, see below.

When interacting with email-related services from code, MailMessage, the class representing an e-mail, exposed a string Body property. This could contain either plain text or HTML, which was indicated by IsHtmlBody.

These two properties have now been replaced by the TextBody and HtmlBody properties, which contains a plain text and/or HTML body.

GraphQL Module

GraphQL Library Upgrade

The GraphQL libraries have been upgraded from version 7 to version 8. Below are important changes and considerations for your implementation:

  1. Removal of Default Implementation:
    The IContentTypeBuilder interface previously included a default implementation for the Clear() method. This implementation has been removed. If you have a custom implementation of IContentTypeBuilder, you must now provide your own Clear() method. The method can remain empty if no specific actions are needed.

  2. Sealed Classes:
    Several classes have been marked as sealed to prevent further inheritance. This change is intended to enhance stability and maintainability. The following classes are now sealed:

    • All implementations of InputObjectGraphType
    • All implementations of ObjectGraphType<>
    • All implementations of WhereInputObjectGraphType
    • All implementations of DynamicContentTypeBuilder
    • All implementations of IContentTypeBuilder
    • All implementations of GraphQLFilter
    • All implementations of ISchemaBuilder

Elasticsearch Module

Deprecation of the NEST Library

We previously relied on the NEST library to interface with the Elasticsearch service. However, due to the deprecation of NEST, we have migrated to its successor, Elastic.Clients.Elasticsearch. As part of this transition, the following interfaces and classes have been removed:

  • IElasticAnalyzer
  • IElasticSearchQueryService (use ElasticsearchQueryService as an alternative)
  • ElasticAnalyzer

To ensure consistency across our codebase, all classes and interfaces are now prefixed with Elasticsearch instead of Elastic or ElasticSearch. The only exception to this naming convention is for settings, which have been retained to minimize further breaking changes.

Additionally, the OrchardCore.Search.Elasticsearch.Abstractions project has been removed, and the following classes have been relocated to the OrchardCore.Search.Elasticsearch.Core project:

  • ElasticsearchOptions
  • ElasticsearchQueryResults
  • ElasticsearchTopDocs

The method ExecuteQueryAsync(string indexName, Query query, List<SortOptions> sort, int from, int size) has been removed from the ElasticsearchQueryService class. In its place, we have introduced the new method GetContentItemIdsAsync(ElasticsearchSearchContext request), which streamlines the query execution process by encapsulating the necessary parameters within a single context object.

Azure Search AI Module

Enhanced Multi-Source Indexing

The index management UI now supports multiple data sources. When the Contents feature is enabled, the Contents source is automatically added, allowing you to create indexes based on content types. To maintain backward compatibility, we've also introduced a migration process.

To add a custom source from your project, configure it as follows:

services.Configure<AzureAISearchOptions>(options =>
{
    options.AddIndexSource("CustomSource", o =>
    {
        o.DisplayName = S["Custom Source"];
        o.Description = S["Create an index based on custom data."];
    });
});

Expanded Customization Options

We've introduced the IAzureAISearchIndexSettingsHandler interface, enabling deeper customization of index settings. To simplify integration, you can extend AzureAISearchIndexSettingsHandlerBase. Additionally, the new IAzureAISearchEvents interface provides hooks for handling search-related events.

Key Changes

  • UI routes now accept index IDs instead of index names.
  • The following methods in AzureAISearchIndexSettingsService now use id instead of an index name:
    • GetAsync(id)
    • DeleteAsync(id)
  • New methods added to AzureAISearchIndexSettingsService:
    • Task<AzureAISearchIndexSettings> NewAsync(string source, JsonNode data = null)
    • Task<ValidationResultDetails> ValidateAsync(AzureAISearchIndexSettings settings)
    • Task SynchronizeAsync(AzureAISearchIndexSettings settings)

These enhancements provide greater flexibility, improved maintainability, and an easier integration experience.

!!! note If you use the azureai-index-create recipe to create indexes, make sure to update your recipe by adding "Source": "Contents" to each index. Otherwise, the step will fail due to a missing source.

Users Module

The user registration and login functionalities have been refactored for better extensibility:

  • Registration Improvements:

    • The IRegistrationFormEvents interface now includes Task RegisteringAsync(UserRegisteringContext context) for streamlined customization.
    • A new base class, RegistrationFormEventsBase, allows developers to override only necessary methods.
  • Login Improvements:

    • The ILoginFormEvent interface has a new method: Task<IActionResult> ValidatingLoginAsync(IUser user).
    • The LoginFormEventBase class enables overriding relevant methods. Note that the base implementation of LoggingInAsync() has been removed; you must now implement this method if using LoginFormEventBase.
  • User Service Update:

    • A new method in IUserService interface: Task<IUser> RegisterAsync(RegisterUserForm model, Action<string, string> reportError) facilitates registration with error reporting.

These enhancements make the user management system more modular and customizable.

Removed Old Settings

The following obsolete settings were removed from RegistrationSettings class

  • NoPasswordForExternalUsers
  • NoUsernameForExternalUsers
  • NoEmailForExternalUsers
  • UseScriptToGenerateUsername
  • GenerateUsernameScript
  • UsersCanRegister

The following obsolete settings were removed from LoginSettings class

  • UseExternalProviderIfOnlyOneDefined
  • UseScriptToSyncRoles
  • SyncRolesScript

Login View Update

The ExternalLogin action has been removed from the Account controller. If you are using a custom Login.cshtml view or Login template, please update the external login form action. As of this update, the ExternalLogin action has been relocated to the ExternalAuthentications controller.

AssignRoleToUsers Permission Update

The AssignRoleToUsers permission is no longer implicitly granted by EditUsers. To maintain the same behavior, make sure to explicitly assign the AssignRoleToUsers permission to any role that already has the EditUsers permission.

The Behavior of 'has_claim' Liquid Filter Changed.

The Administrator role no longer registers permission-based claims by default during login. This means that directly checking for specific claims in Liquid, such as:

{% assign isAuthorized = User | has_claim: "Permission", "AccessAdminPanel" %}

will return false for administrators, even though they still have full access. Non-admin users, however, may return true if they have the claim. It's important to use the has_permission filter for permission checks going forward:

{% assign isAuthorized = User | has_permission: "AccessAdminPanel" %}

LoginForm_Edit Shape Type Modification

To simplify the LoginForm.Edit.cshtml view, the following code has been moved to Views/Account/Login.cshtml:

<h1 class="fs-4">@T["Log in"]</h1>
<hr />

If you are overriding the Views/Account/Login.cshtml view, you may want to add the above code to your custom version for consistency.

ReCaptcha

In the previous implementation, the ReCaptcha module supported two modes: AlwaysShow and PreventRobots. To simplify the module and enhance integration, the PreventRobots mode and its related components have been removed. Going forward, only the AlwaysShow mode will be supported.

As part of this update, the following components have been deprecated and removed:

  • IDetectRobots
  • IPAddressRobotDetector
  • ReCaptchaMode

Furthermore, the ReCaptchaService class has been sealed to prevent inheritance. The following methods have also been removed:

  • MaybeThisIsARobot
  • IsThisARobot
  • ThisIsAHuman

Previously, the FormReCaptcha view was available to inject a ReCaptcha challenge from any display driver. This view has been removed. The recommended approach now is to return a shape directly, as shown below:

return Dynamic("ReCaptcha", (m) =>
{
    m.language = CultureInfo.CurrentUICulture.Name;
}).Location("Content:after");

Instead of using this approach:

return View("FormReCaptcha", model).Location("Content:after");

If you still need to render ReCaptcha using the deprecated FormReCaptcha, you can manually add the FormReCaptcha.cshtml view to your project. Here's the code for this:

<div class="mb-3">
    <captcha mode="AlwaysShow" language="@Orchard.CultureName()" />
</div>

This change is designed to simplify your integration process and make it easier to manage ReCaptcha usage in your project.

Content Module

Previously, the IContentHandler.UpdatingAsync and IContentHandler.UpdatedAsync methods were triggered for both creation and update events. This behavior has been corrected in this release. Now, if you are modifying or altering content items within the UpdatingAsync or UpdatedAsync handlers, you must also implement the Creating or Created events to maintain the previous functionality.

Additionally, when manually creating or updating content items in your project, ensure that you use ContentManager.CreateAsync exclusively for creating new items and ContentManager.UpdateAsync for updating existing ones. This guarantees that the Creating, Created, Updating, and Updated events are triggered appropriately.

Change Log

Roles Module

Permission Behavior Added to Roles Recipe Step

The Roles recipe now includes the ability to define specific permission behaviors, allowing you to control how permissions are managed within a role. The following behaviors are available:

  • Replace: This behavior removes all existing permissions associated with the role and replaces them with the new permissions from the Permissions collection. This is the default behavior.
  • Add: This behavior adds the new permission(s) from the Permissions collection to the role, but only if they do not already exist. It does not affect the existing permissions.
  • Remove: This behavior removes the specified permission(s) in the Permissions collection from the role’s existing permissions.

For more info about the new PermissionBehavior, check out the documentation.

ReCaptcha Module

New ReCaptcha Shape

A new ReCaptcha shape has been introduced, enabling you to render the ReCaptcha challenge using a customizable shape. For more details, please refer to the documentation.

Menu Module

Permission-Based Menu Visibility

The Menu module enables you to build frontend menus for your users through a user-friendly interface. We've enhanced this feature by allowing you to require one or more permissions before a menu item becomes visible to the user.

If you're using a custom MenuItem in your project and want to incorporate this functionality, you can achieve it by attaching the MenuItemPermissionPart to your custom MenuItem content type.

When caching your menu, it's crucial to include the cache-context to ensure the menu is properly cached and invalidated based on the user's roles. This ensures the menu is displayed correctly for each logged-in user, based on their specific roles.

For example, here's how you can add the menu with cache-context using Razor:

<menu alias="alias:main-menu" cache-id="main-menu" cache-fixed-duration="00:05:00" cache-tag="alias:main-menu" cache-context="user.roles" />

Notice the cache-context="user.roles" attribute.

Alternatively, here's how you can implement the same functionality using Liquid:

{% shape "menu", alias: "alias:main-menu", cache_id: "main-menu", cache_fixed_duration: "00:05:00", cache_tag: "alias:main-menu", cache_context: "user.roles" %}

Again, notice the inclusion of cache_context: "user.roles".

By default, permissions are enabled for new tenants. However, if you'd like to add permissions to an existing tenant, you can use the "Add Permissions to Menus" recipe either through the UI or by executing the recipe programmatically as shown below:

{
  "steps": [
    {
      "name": "recipes",
      "Values": [
        {
          "executionid": "MenuAddPermissions",
          "name": "MenuAddPermissions"
        }
      ]
    }
  ]
}

!!! note Be sure to update all instances where you create a menu shape by adding the cache-context attribute. This ensures the menu is properly cached and tailored based on the user's roles.

Permission-Based Content Menu Visibility

A new option, Check content permissions, has been added to the Content Menu Item. This feature allows you to control the visibility of a menu item based on the user's permissions. When this option is enabled, the system ensures that the current user has the View Content permission for the selected item before displaying it.

Asset Manager

Orchard Core now features a new Asset Manager, set to gradually replace the Gulp pipeline. While the Gulp pipeline remains for backward compatibility during the transition and refactoring period, a comprehensive documentation is available to guide users on the new Asset Manager.

The Gulp pipeline is being phased out as it is no longer suitable for bundling assets with tools like Webpack. The new Asset Manager leverages Concurrently, enabling the execution of shell commands directly from Node.js.This provides flexibility to use APIs from bundlers, compilers, and transpilers to perform various actions seamlessly.

For more information, see the corresponding page.

Miscellaneous

Sealing Types

Many type commonly used by classes can be sealed, which improves runtime performance. While it's not mandatory, we recommend that you consider applying this improvement to your own extensions as well. We've implemented this enhancement in pull request #16897.

New Extension Method for Adding IConfigureOptions<ResourceManagementOptions> Implementations

When adding an IConfigureOptions<ResourceManagementOptions> implementation, used to add static resources and commonly named ResourceManagementOptionsConfiguration, you previously had to do the following in the Startup classes:

services.AddTransient<IConfigureOptions<ResourceManagementOptions>, ResourceManagementOptionsConfiguration>();

To simplify this, we introduced a new extension method to do the same in a shorter form:

services.AddResourceConfiguration<ResourceManagementOptionsConfiguration>();

You can utilize this in your codebase by searching the AddTransient<IConfigureOptions<ResourceManagementOptions>, (.+)>\(\) regex pattern and replacing it with AddResourceConfiguration<$1>(). Projects using this have to reference the OrchardCore.ResourceManagement package.