diff --git a/src/docs/reference/README.md b/src/docs/reference/README.md
index 46c8d6635a7..fb7ac7c3d48 100644
--- a/src/docs/reference/README.md
+++ b/src/docs/reference/README.md
@@ -75,6 +75,7 @@ Here's a categorized overview of all built-in Orchard Core features at a glance.
### Design
+- [Display Management](modules/DisplayManagement/README.md)
- [Layers](modules/Layers/README.md)
- [Widgets](modules/Widgets/README.md)
- [Templates](modules/Templates/README.md)
diff --git a/src/docs/reference/modules/DisplayManagement/README.md b/src/docs/reference/modules/DisplayManagement/README.md
new file mode 100644
index 00000000000..4c5cc2dd464
--- /dev/null
+++ b/src/docs/reference/modules/DisplayManagement/README.md
@@ -0,0 +1,158 @@
+# OrchardCore.DisplayManagement
+
+## Shapes
+
+### What is a shape?
+
+Please review the following videos to enhance your understanding of shapes:
+
+- [Understanding Shapes](https://youtu.be/gKLjtCIs4GU)
+- [Demystifying Shapes](https://www.youtube.com/watch?v=yaZhKuD2qoI)
+
+These videos will provide valuable insights and a clear explanation of various shapes and their properties.
+
+### Rendering a shape
+
+You can use the `` tag helper to render any shape, even pass properties.
+
+=== "Razor"
+
+ ``` html
+ @{
+ var intValue = 1;
+ var stringValue = "a";
+ }
+
+ @await DisplayAsync(await New.MyShape(Foo: 1, Bar: "a"))
+
+
+
+
+
+
+ ```
+
+=== "Liquid"
+
+ ``` liquid
+ {% assign customShape = "MyShape" | shape_new %}
+ {% shape_add_properties customShape my_string: "String Test 3", my_int: 1 %}
+ {{ customShape | shape_render }}
+
+ {% "MyShape" | shape_new | shape_properties: my_int: 3, my_string: "String Test 3" | shape_render %}
+ ```
+
+For rendering content items, you could also use the following tag helper.
+Note: you need to add `@addTagHelper *, OrchardCore.Contents.TagHelpers` to your `_ViewImports.cshtml` file to load this tag helper. Ensure your project file also has a reference to OrchardCore.Contents.TagHelpers.
+
+=== "Razor"
+
+ ``` html
+
+ ```
+
+=== "Liquid"
+
+ ``` liquid
+ {% contentitem alias: "alias:main-menu", display_type: "Detail" %}
+ ```
+
+#### Manipulating shape metadata
+
+It's possible to manipulate a shape's metadata by using the `metadata` tag helper as a child of the shape's tag helper. The metadata tag helper allows you to:
+
+- Change the display type
+- Add, remove, or clear alternates
+- Add, remove, or clear wrappers
+
+Metadata tag helper example:
+
+```xml
+
+```
+
+#### Adding properties with additional tag helpers
+
+Properties can be passed to a shape by adding attributes to the shape tag helper, as mentioned above. But you can also use the `` tag helper inside ``. This even lets you pass Razor code as properties with the `IHtmlContent` value, if you omit the `value` attribute. Something that can't be easily done otherwise.
+
+```xml
+
+
+
+
+
Some complicated HTML
+
+ You can even include shapes:
+
+
+
+
+```
+
+This is the same as `` where you'd have to construct `someHtmlContentVariable` separately. Of course, you can mix and match the different formats, for example, to only use `` when you want to pass HTML content as property.
+
+### Date Time shapes
+
+#### `DateTime`
+
+Renders a `Date` and `Time` value using the TimeZone of the request.
+
+| Parameter | Type | Description |
+| --------- | ---- |------------ |
+| `Utc` | `DateTime?` | The date and time to render. If not specified, the current time will be used. |
+| `Format` | `string` | The .NET format string. If not specified the long format `dddd, MMMM d, yyyy h:mm:ss tt` will be used. The accepted format can be found at |
+
+Tag helper example:
+
+```html
+
+```
+
+#### `TimeSpan`
+
+Renders a relative textual representation of a `Date` and `Time` interval.
+
+| Parameter | Type | Description |
+| --------- | ---- |------------ |
+| `Utc` | `DateTime?` | The initial date and time. If not specified, the current time will be used. |
+| `Origin` | `DateTime?` | The current date and time. If not specified, the current time will be used. |
+
+Tag helper example:
+
+```html
+
+```
+
+Result:
+
+```text
+3 days ago
+```
+
+#### `Duration`
+
+Renders a duration value using the given TimeSpan.
+
+| Parameter | Type | Description |
+| --------- | ---- |------------ |
+| `timeSpan` | `TimeSpan?` | The time span to render. |
+
+Tag helper example:
+
+```html
+
+```
+
+### Related Articles
+- [Placement](../Placement/README.md)
diff --git a/src/docs/reference/modules/Elasticsearch/README.md b/src/docs/reference/modules/Elasticsearch/README.md
index f15fcf6fcd1..11691dac3e9 100644
--- a/src/docs/reference/modules/Elasticsearch/README.md
+++ b/src/docs/reference/modules/Elasticsearch/README.md
@@ -28,8 +28,7 @@ Then exit any WSL instance, `wsl --shutdown`, and restart.
vm.max_map_count = 262144
```
-Elasticsearch v7.17.5 Docker Compose file :
-[docker-compose.yml](docker-compose.yml)
+Elasticsearch Docker Compose file (check the current Elasticsearch version in the file if you need to run a specific version): [docker-compose.yml](docker-compose.yml)
- Copy this file in a folder named Elasticsearch somewhere safe.
- Open up a Terminal or Command Shell in this folder.
diff --git a/src/docs/reference/modules/Elasticsearch/docker-compose.yml b/src/docs/reference/modules/Elasticsearch/docker-compose.yml
index 0115df5a788..0a6db08b8ee 100644
--- a/src/docs/reference/modules/Elasticsearch/docker-compose.yml
+++ b/src/docs/reference/modules/Elasticsearch/docker-compose.yml
@@ -1,7 +1,7 @@
version: '2.2'
services:
es01:
- image: docker.elastic.co/elasticsearch/elasticsearch:7.17.26
+ image: docker.elastic.co/elasticsearch/elasticsearch:8.17.0
container_name: es01
environment:
- node.name=es01
@@ -10,6 +10,10 @@ services:
- cluster.initial_master_nodes=es01,es02
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
+ # Disable security features
+ - xpack.security.enabled=false
+ - xpack.security.http.ssl.enabled=false
+ - xpack.security.transport.ssl.enabled=false
ulimits:
memlock:
soft: -1
@@ -21,7 +25,7 @@ services:
networks:
- elastic
es02:
- image: docker.elastic.co/elasticsearch/elasticsearch:7.17.26
+ image: docker.elastic.co/elasticsearch/elasticsearch:8.17.0
container_name: es02
environment:
- node.name=es02
@@ -30,6 +34,10 @@ services:
- cluster.initial_master_nodes=es01,es02
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
+ # Disable security features
+ - xpack.security.enabled=false
+ - xpack.security.http.ssl.enabled=false
+ - xpack.security.transport.ssl.enabled=false
ulimits:
memlock:
soft: -1
@@ -40,9 +48,13 @@ services:
- elastic
kibana:
container_name: kibana
- image: docker.elastic.co/kibana/kibana:7.17.26
+ image: docker.elastic.co/kibana/kibana:8.17.0
environment:
ELASTICSEARCH_HOSTS: '["http://es01:9200","http://es02:9200"]'
+ # Disable security features in Kibana
+ ELASTICSEARCH_USERNAME: elastic
+ ELASTICSEARCH_PASSWORD:
+ XPACK_SECURITY_ENABLED: false
networks:
- elastic
depends_on:
diff --git a/src/docs/reference/modules/Placement/README.md b/src/docs/reference/modules/Placement/README.md
index f5c416bf1e2..6b730222876 100644
--- a/src/docs/reference/modules/Placement/README.md
+++ b/src/docs/reference/modules/Placement/README.md
@@ -98,140 +98,8 @@ If a field named `City` was added to an `Address` part then its differentiator w
You can find information about shape differentiators in the [Templates documentation](../../modules/Templates/README.md#content-field-differentiator)
-## Shapes
-
-### What is a shape?
-
-Everything you need to know about Shapes is in [this video](https://youtu.be/gKLjtCIs4GU).
-
-### Rendering a shape
-
-You can use the `` tag helper to render any shape, even pass properties.
-
-=== "Razor"
-
- ``` html
- @{
- var intValue = 1;
- var stringValue = "a";
- }
-
- @await DisplayAsync(await New.MyShape(Foo: 1, Bar: "a"))
-
-
-
-
-
-
- ```
-
-=== "Liquid"
-
- ``` liquid
- {% assign customShape = "MyShape" | shape_new %}
- {% shape_add_properties customShape my_string: "String Test 3", my_int: 1 %}
- {{ customShape | shape_render }}
-
- {% "MyShape" | shape_new | shape_properties: my_int: 3, my_string: "String Test 3" | shape_render %}
- ```
-
-For rendering content items, you could also use the following tag helper.
-Note: you need to add `@addTagHelper *, OrchardCore.Contents.TagHelpers` to your `_ViewImports.cshtml` file to load this tag helper. Ensure your project file also has a reference to OrchardCore.Contents.TagHelpers.
-
-=== "Razor"
-
- ``` html
-
- ```
-
-=== "Liquid"
-
- ``` liquid
- {% contentitem alias: "alias:main-menu", display_type: "Detail" %}
- ```
-
-#### Manipulating shape metadata
-
-It's possible to manipulate a shape's metadata by using the `metadata` tag helper as a child of the shape's tag helper. The metadata tag helper allows you to:
-
-- Change the display type
-- Add, remove, or clear alternates
-- Add, remove, or clear wrappers
-
-Metadata tag helper example:
-
-```xml
-
-```
-
-#### Adding properties with additional tag helpers
-
-Properties can be passed to a shape by adding attributes to the shape tag helper, as mentioned above. But you can also use the `` tag helper inside ``. This even lets you pass Razor code as properties with the `IHtmlContent` value, if you omit the `value` attribute. Something that can't be easily done otherwise.
-
-```xml
-
-
-
-
-
Some complicated HTML
-
- You can even include shapes:
-
-
-
-
-```
-
-This is the same as `` where you'd have to construct `someHtmlContentVariable` separately. Of course, you can mix and match the different formats, for example, to only use `` when you want to pass HTML content as property.
-
-### Date Time shapes
-
-#### `DateTime`
-
-Renders a `Date` and `Time` value using the timezone of the request.
-
-| Parameter | Type | Description |
-| --------- | ---- |------------ |
-| `Utc` | `DateTime?` | The date and time to render. If not specified, the current time will be used. |
-| `Format` | `string` | The .NET format string. If not specified the long format `dddd, MMMM d, yyyy h:mm:ss tt` will be used. The accepted format can be found at |
-
-Tag helper example:
-
-```html
-
-```
-
-#### `TimeSpan`
-
-Renders a relative textual representation of a `Date` and `Time` interval.
-
-| Parameter | Type | Description |
-| --------- | ---- |------------ |
-| `Utc` | `DateTime?` | The initial date and time. If not specified, the current time will be used. |
-| `Origin` | `DateTime?` | The current date and time. If not specified, the current time will be used. |
-
-Tag helper example:
-
-```html
-
-```
-
-Result:
-
-```text
-3 days ago
-```
+## Related Articles
+- [Display Management](../DisplayManagement/README.md)
## Editor shape placement
diff --git a/src/docs/reference/modules/ReCaptcha/README.md b/src/docs/reference/modules/ReCaptcha/README.md
index 3d2e5366dfd..4113bb1e83d 100644
--- a/src/docs/reference/modules/ReCaptcha/README.md
+++ b/src/docs/reference/modules/ReCaptcha/README.md
@@ -17,7 +17,7 @@ When the threshold for login attempts are broken, a captcha is shown on the logi
### Forms
-You can add protection from robots to forms by including the recaptcha field when you design a form.
+You can add protection from robots to forms by including the reCaptcha field when you design a form.
### Workflow
@@ -40,3 +40,21 @@ you can create your own implementation of the IDetectRobots interface and it wil
## Using with a form post with Content-Type = "application/json" from a javascript framework
The ReCaptcha api uses the data-callback attribute to return the token generated when validating the ReCaptcha widget. This allows to post that token from an Angular, Vue.js form post. If you want to validate the ReCaptcha from the Workflow task you will need to pass the token in the header of your request as "g-recaptcha-response".
+
+## Shapes
+
+### ReCaptcha
+
+Display for a reCaptcha challenge if the service is configured.
+
+=== "Liquid"
+
+ ``` liquid
+ {% shape "ReCaptcha", language: "en-US" %}
+ ```
+
+=== "Razor"
+
+ ``` html
+
+ ```
diff --git a/src/docs/releases/2.0.0.md b/src/docs/releases/2.0.0.md
index 6768001c3e5..2789280fdeb 100644
--- a/src/docs/releases/2.0.0.md
+++ b/src/docs/releases/2.0.0.md
@@ -1,6 +1,6 @@
# Orchard Core 2.0.0
-Release date: September 9, 2024.
+Release date: September 9, 2024.
🎉 **Orchard Core 2.0 Is Here – Elevate Your Projects to the Next Level!** 🎉
@@ -86,7 +86,7 @@ services.AddJsonDerivedTypeInfo();
```csharp
public override IDisplayResult Edit(ContentPartFieldDefinition partFieldDefinition)
{
- return Initialize("NumericFieldSettings_Edit", model =>
+ return Initialize("NumericFieldSettings_Edit", model =>
{
var settings = partFieldDefinition.GetSettings();
model.Hint = settings.Hint;
@@ -99,7 +99,7 @@ services.AddJsonDerivedTypeInfo();
Previously, any query type had to inherit from `Query` and required its own distinct type (e.g., `SqlQuery`, `LuceneQuery`, `ElasticQuery`). However, with [pull request #16402](https://github.com/OrchardCMS/OrchardCore/pull/16402), creating a custom type for each query type is no longer necessary. This update involved changes to the `IQueryManager` and `IQuerySource` interfaces, as well as the `Query` class. Additionally, a new project, `OrchardCore.Queries.Core`, was introduced.
-A migration process has been implemented to transition existing queries into the new structure, ensuring no impact on existing tenants.
+A migration process has been implemented to transition existing queries into the new structure, ensuring no impact on existing tenants.
#### Key Changes
@@ -328,7 +328,7 @@ And the following methods have been removed, with updated alternatives:
To enhance your project's performance, address any warnings generated by the use of these obsolete methods. Please note that these methods will be removed in the next major release.
A new `SiteDisplayDriver` base class was introduced to simplify the process of adding a UI settings.
-
+
!!! note
With the new `SiteDisplayDriver` base class for custom settings, you no longer need explicit checks like `context.GroupId.Equals(GroupId, StringComparison.OrdinalIgnoreCase)` as the base class handles this check for you.
@@ -355,7 +355,7 @@ At the same time, the following method was added:
### GraphQL Module
-The GraphQL schema may change because fields are now always added to the correct part. Previously, additional fields may have been added to the parent content item type directly.
+The GraphQL schema may change because fields are now always added to the correct part. Previously, additional fields may have been added to the parent content item type directly.
You may have to adjust your GraphQL queries in that case.
@@ -447,7 +447,7 @@ Additionally, if an error occurs, a new custom exception, RecipeExecutionExcepti
### Workflows Module
- The method `Task TriggerEventAsync(string name, IDictionary input = null, string correlationId = null, bool isExclusive = false, bool isAlwaysCorrelated = false)`
+ The method `Task TriggerEventAsync(string name, IDictionary input = null, string correlationId = null, bool isExclusive = false, bool isAlwaysCorrelated = false)`
was changed to return `Task>` instead.
#### New Events
@@ -491,7 +491,7 @@ The `OrchardCore.Email` module has undergone a refactoring process with no break
- The `SMTP` related services are now part of a new module named `OrchardCore.Email.Smtp`. To use the SMTP provider for sending emails, enable the `OrchardCore.Email.Smtp` feature.
- If you were using the `OrchardCore_Email` configuration key to set up the SMTP provider for all tenants, please update the configuration key to `OrchardCore_Email_Smtp`. The `OrchardCore_Email` key continues to work but will be deprecated in a future release.
- A new email provider was added to allow you to send email using Azure Communication Services Email. Click [here](../reference/modules/Email.Azure/README.md) to read more about the ACS module.
-
+
### Menu
`Menus` and `AdminMenus` now support specifying the target property.
@@ -595,8 +595,8 @@ Introduces a new "Secure Media" feature for additional control over who can acce
### Users Module
-Enhanced functionality has been implemented, giving developers the ability to control the expiration time of different tokens, such as those for password reset, email confirmation, and email change, which are sent through the email service. Below, you'll find a comprehensive list of configurable options along with their default values:
-
+Enhanced functionality has been implemented, giving developers the ability to control the expiration time of different tokens, such as those for password reset, email confirmation, and email change, which are sent through the email service. Below, you'll find a comprehensive list of configurable options along with their default values:
+
| Class Name | Default Expiration Value |
| ---------- | ------------------------ |
| `ChangeEmailTokenProviderOptions` | The token is valid by default for **15 minutes**. |
@@ -748,14 +748,14 @@ A new filter named `supported_cultures` was added to allow you to get a list of
### Adding properties with additional tag helpers
-The new `` tag helper can be placed inside the `` tag helpers to add properties to the shape. This is similar to `prop-*` attributes, but you can also include Razor code as the `IHtmlContent` property value, which was impossible before. See more details [here](../reference/modules/Placement/README.md#adding-properties-with-additional-tag-helpers).
+The new `` tag helper can be placed inside the `` tag helpers to add properties to the shape. This is similar to `prop-*` attributes, but you can also include Razor code as the `IHtmlContent` property value, which was impossible before. See more details [here](../reference/modules/DisplayManagement/README.md#adding-properties-with-additional-tag-helpers).
### Sealing Types
Many type commonly used by modules 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 the following pull-requests:
- [16253](https://github.com/OrchardCMS/OrchardCore/pull/16253)
-- [16238](https://github.com/OrchardCMS/OrchardCore/pull/16238)
+- [16238](https://github.com/OrchardCMS/OrchardCore/pull/16238)
- [16464](https://github.com/OrchardCMS/OrchardCore/pull/16464)
- [16535](https://github.com/OrchardCMS/OrchardCore/pull/16535)
- [16536](https://github.com/OrchardCMS/OrchardCore/pull/16536)
@@ -770,8 +770,8 @@ The Workflows module now has a `Trimming` feature to automatically clean up old
### Obsoleting `TrimEnd`
-The methods `public static string TrimEnd(this string value, string trim = "")` from `OrchardCore.Mvc.Utilities` and `OrchardCore.ContentManagement.Utilities` are being obsoleted and replaced by
-`OrchardCore.ContentManagement.Utilities.TrimEndString(this string value, string suffix)`. This was done to prepare the code base for the next .NET 9.0 release which has a conflicting method
+The methods `public static string TrimEnd(this string value, string trim = "")` from `OrchardCore.Mvc.Utilities` and `OrchardCore.ContentManagement.Utilities` are being obsoleted and replaced by
+`OrchardCore.ContentManagement.Utilities.TrimEndString(this string value, string suffix)`. This was done to prepare the code base for the next .NET 9.0 release which has a conflicting method
with a different behavior.
### Miscellaneous
diff --git a/src/docs/releases/3.0.0.md b/src/docs/releases/3.0.0.md
index 90b7c91e0b3..3f96b53c08e 100644
--- a/src/docs/releases/3.0.0.md
+++ b/src/docs/releases/3.0.0.md
@@ -102,14 +102,61 @@ will return `false` for administrators, even though they still have full access.
{% assign isAuthorized = User | has_permission: "AccessAdminPanel" %}
```
-### Sealing Types
+### ReCaptcha
-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](https://github.com/OrchardCMS/OrchardCore/pull/16897).
+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:
+
+```csharp
+return Dynamic("ReCaptcha", (m) =>
+{
+ m.language = CultureInfo.CurrentUICulture.Name;
+}).Location("Content:after");
+```
+
+Instead of using this approach:
+
+```csharp
+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:
+
+```html
+
+
+
+```
+
+This change is designed to simplify your integration process and make it easier to manage ReCaptcha usage in your project.
## Change Log
+### ReCaptcha
+
+### 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](../reference/modules/ReCaptcha/README.md).
+
## 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](https://github.com/OrchardCMS/OrchardCore/pull/16897).
+
### New Extension Method for Adding `IConfigureOptions` Implementations
When adding an `IConfigureOptions` implementation, used to add static resources and commonly named `ResourceManagementOptionsConfiguration`, you previously had to do the following in the `Startup` classes:
diff --git a/test/OrchardCore.Tests/Modules/OrchardCore.Tenants/ProfilesTests.cs b/test/OrchardCore.Tests/Modules/OrchardCore.Tenants/ProfilesTests.cs
new file mode 100644
index 00000000000..9b929bd0569
--- /dev/null
+++ b/test/OrchardCore.Tests/Modules/OrchardCore.Tenants/ProfilesTests.cs
@@ -0,0 +1,58 @@
+using OrchardCore.Environment.Shell.Models;
+using OrchardCore.Tenants.Services;
+
+namespace OrchardCore.Modules.OrchardCore.Tenants.Tests;
+
+public class ProfilesTests
+{
+ [Fact]
+ public void FeatureProfilesSchemaService_ShouldCreateValidSchema()
+ {
+ var featureProfilesRuleOptions = new FeatureProfilesRuleOptions();
+ featureProfilesRuleOptions.Rules["Exclude"] = static (expression, name) => (true, true);
+ var options = Options.Create(featureProfilesRuleOptions);
+
+ var service = new FeatureProfilesSchemaService(options);
+
+ var expectedSchema = """
+ {
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Feature rules",
+ "type": "array",
+ "description": "An array of feature rules",
+ "items": {
+ "$ref": "#/definitions/FeatureRule"
+ },
+ "definitions": {
+ "FeatureRule": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "Rule",
+ "Expression"
+ ],
+ "properties": {
+ "Rule": {
+ "minLength": 1,
+ "$ref": "#/definitions/Rule"
+ },
+ "Expression": {
+ "type": "string",
+ "minLength": 1
+ }
+ }
+ },
+ "Rule": {
+ "type": "string",
+ "description": "The rule to apply to this expression",
+ "enum": [
+ "Exclude"
+ ]
+ }
+ }
+ }
+ """;
+
+ Assert.Equal(expectedSchema, service.GetJsonSchema());
+ }
+}