Skip to content

Commit

Permalink
Merge branch 'main' into tbNews
Browse files Browse the repository at this point in the history
  • Loading branch information
urbanit committed Mar 26, 2024
2 parents fb83b1e + 9a67e6d commit 80aeca8
Show file tree
Hide file tree
Showing 105 changed files with 1,155 additions and 563 deletions.
27 changes: 27 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -2834,6 +2834,33 @@
"contributions": [
"code"
]
},
{
"login": "aliamiras",
"name": "aliamiras",
"avatar_url": "https://avatars.githubusercontent.com/u/107989021?v=4",
"profile": "https://github.com/aliamiras",
"contributions": [
"code"
]
},
{
"login": "xtomas",
"name": "Tomáš Jákl",
"avatar_url": "https://avatars.githubusercontent.com/u/10938220?v=4",
"profile": "https://github.com/xtomas",
"contributions": [
"code"
]
},
{
"login": "porgabi",
"name": "Gábor Pór",
"avatar_url": "https://avatars.githubusercontent.com/u/51411356?v=4",
"profile": "https://github.com/porgabi",
"contributions": [
"code"
]
}
],
"skipCi": true,
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Do you need some help with Orchard Core? Don't worry, there are ways to get help

- [X (Twitter)](https://twitter.com/orchardcms)
- [LinkedIn](https://www.linkedin.com/groups/13605669/)
- [Meta (Facebook)](https://www.facebook.com/groups/244928199422062/user/100063629920864)
- [Meta (Facebook)](https://www.facebook.com/OrchardCore)

## Local Communities

Expand All @@ -82,6 +82,16 @@ First, clone the repository using the command `git clone https://github.com/Orch
2. Launch the solution by clicking on `OrchardCore.sln`. Give Visual Studio time to restore all missing Nuget packages.
3. Ensure `OrchardCore.Cms.Web` is set as the startup project. Then run the app.

## Preview Package Feed

[![Hosted By: Cloudsmith](https://img.shields.io/badge/OSS%20hosting%20by-cloudsmith-blue?logo=cloudsmith&style=for-the-badge)](https://cloudsmith.com)

NuGet package repository hosting for the preview feed is graciously provided by [Cloudsmith](https://cloudsmith.com).

Cloudsmith is the only fully hosted, cloud-native, universal package management solution, that
enables your organization to create, store, and share packages in any format, to any place, with total
confidence.

## Code of Conduct

See [our Code of Conduct](./CODE-OF-CONDUCT.md).
Expand Down
5 changes: 3 additions & 2 deletions src/OrchardCore.Build/Dependencies.props
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@
<PackageManagement Include="BenchmarkDotNet" Version="0.13.12" />
<PackageManagement Include="Castle.Core" Version="5.1.1" />
<PackageManagement Include="DocumentFormat.OpenXml" Version="3.0.2" />
<PackageManagement Include="Fluid.Core" Version="2.6.0" />
<PackageManagement Include="Fluid.Core" Version="2.7.0" />
<PackageManagement Include="GraphQL" Version="7.8.0" />
<PackageManagement Include="GraphQL.DataLoader" Version="7.8.0" />
<PackageManagement Include="GraphQL.MicrosoftDI" Version="7.8.0" />
<PackageManagement Include="GraphQL.SystemTextJson" Version="7.8.0" />
<PackageManagement Include="Jint" Version="3.0.1" />
<PackageManagement Include="HtmlSanitizer" Version="8.1.844-beta" />
<PackageManagement Include="JsonPath.Net" Version="1.0.0" />
<PackageManagement Include="HtmlSanitizer" Version="8.1.860-beta" />
<PackageManagement Include="Irony.Core" Version="1.0.7" />
<PackageManagement Include="libphonenumber-csharp" Version="8.13.32" />
<PackageManagement Include="Lorem.Universal.NET" Version="4.0.80" />
Expand Down
39 changes: 39 additions & 0 deletions src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using Fluid;
using Fluid.Values;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
Expand All @@ -9,10 +11,13 @@
using OrchardCore.Admin.Controllers;
using OrchardCore.Admin.Drivers;
using OrchardCore.Admin.Models;
using OrchardCore.DisplayManagement;
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.ModelBinding;
using OrchardCore.DisplayManagement.Theming;
using OrchardCore.Environment.Shell.Configuration;
using OrchardCore.Environment.Shell.Scope;
using OrchardCore.Liquid;
using OrchardCore.Modules;
using OrchardCore.Mvc.Core.Utilities;
using OrchardCore.Mvc.Routing;
Expand Down Expand Up @@ -93,4 +98,38 @@ public override void ConfigureServices(IServiceCollection services)
services.AddSiteSettingsPropertyDeploymentStep<AdminSettings, DeploymentStartup>(S => S["Admin settings"], S => S["Exports the admin settings."]);
}
}

[RequireFeatures("OrchardCore.Liquid")]
public class LiquidStartup : StartupBase
{
public override void ConfigureServices(IServiceCollection services)
{
services.Configure<TemplateOptions>(o =>
{
o.Scope.SetValue(nameof(Navbar), new FunctionValue(async (args, ctx) =>
{
if (ctx is LiquidTemplateContext context)
{
var displayManager = context.Services.GetRequiredService<IDisplayManager<Navbar>>();
var updateModelAccessor = context.Services.GetRequiredService<IUpdateModelAccessor>();

var shape = await displayManager.BuildDisplayAsync(updateModelAccessor.ModelUpdater);

return FluidValue.Create(shape, ctx.Options);
}

return NilValue.Instance;
}));

o.MemberAccessStrategy.Register<Navbar, FluidValue>((navbar, name, context) =>
{
return name switch
{
nameof(Navbar.Properties) => new ObjectValue(navbar.Properties),
_ => NilValue.Instance
};
});
});
}
}
}
16 changes: 15 additions & 1 deletion src/OrchardCore.Modules/OrchardCore.Admin/Views/Navbar.cshtml
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
@using OrchardCore.Admin.Models
@using OrchardCore.DisplayManagement
@using OrchardCore.DisplayManagement.ModelBinding

@inject IDisplayManager<Navbar> DisplayManager
@inject IUpdateModelAccessor UpdateModelAccessor

@if (Model.Content == null)
{
return;
dynamic shape = await DisplayAsync(await DisplayManager.BuildDisplayAsync(UpdateModelAccessor.ModelUpdater, (string)Model.Metadata.DisplayType));

if (shape.Content == null)
{
return;
}

Model.Content = shape.Content;
}

<ul class="navbar-nav user-top-navbar">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Net;
using System.Net.Mime;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using GraphQL;
using GraphQL.Execution;
Expand All @@ -18,6 +17,7 @@
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OrchardCore.Apis.GraphQL.Queries;
using OrchardCore.Apis.GraphQL.ValidationRules;
Expand All @@ -27,7 +27,9 @@ namespace OrchardCore.Apis.GraphQL
{
public class GraphQLMiddleware : IMiddleware
{
private readonly ILogger _logger;
private readonly GraphQLSettings _settings;
private readonly IGraphQLTextSerializer _graphQLTextSerializer;
private readonly IGraphQLSerializer _serializer;
private readonly IDocumentExecuter _executer;
internal static readonly Encoding _utf8Encoding = new UTF8Encoding(false);
Expand All @@ -37,11 +39,15 @@ public class GraphQLMiddleware : IMiddleware
public GraphQLMiddleware(
IOptions<GraphQLSettings> settingsOption,
IDocumentExecuter executer,
IGraphQLSerializer serializer)
IGraphQLSerializer serializer,
IGraphQLTextSerializer graphQLTextSerializer,
ILogger<GraphQLMiddleware> logger)
{
_settings = settingsOption.Value;
_executer = executer;
_serializer = serializer;
_graphQLTextSerializer = graphQLTextSerializer;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
Expand Down Expand Up @@ -89,19 +95,17 @@ private async Task ExecuteAsync(HttpContext context)

if (mediaType.IsSubsetOf(_jsonMediaType) || mediaType.IsSubsetOf(_graphQlMediaType))
{

using var sr = new StreamReader(context.Request.Body);
if (mediaType.IsSubsetOf(_graphQlMediaType))
{
using var sr = new StreamReader(context.Request.Body);

request = new GraphQLNamedQueryRequest
{
Query = await sr.ReadToEndAsync()
};
}
else
{
request = await JsonSerializer.DeserializeAsync<GraphQLNamedQueryRequest>(context.Request.Body, JOptions.CamelCase);
request = _graphQLTextSerializer.Deserialize<GraphQLNamedQueryRequest>(await sr.ReadToEndAsync());
}
}
else
Expand All @@ -122,6 +126,8 @@ private async Task ExecuteAsync(HttpContext context)
catch (Exception e)
{
await _serializer.WriteErrorAsync(context, "An error occurred while processing the GraphQL query", e);
_logger.LogError(e, "An error occurred while processing the GraphQL query.");

return;
}

Expand Down Expand Up @@ -171,7 +177,7 @@ private async Task ExecuteAsync(HttpContext context)
await _serializer.WriteAsync(context.Response.Body, result);
}

private static GraphQLNamedQueryRequest CreateRequestFromQueryString(HttpContext context, bool validateQueryKey = false)
private GraphQLNamedQueryRequest CreateRequestFromQueryString(HttpContext context, bool validateQueryKey = false)
{
if (!context.Request.Query.ContainsKey("query"))
{
Expand All @@ -190,7 +196,7 @@ private static GraphQLNamedQueryRequest CreateRequestFromQueryString(HttpContext

if (context.Request.Query.ContainsKey("variables"))
{
request.Variables = JsonSerializer.Deserialize<Inputs>(context.Request.Query["variables"], JOptions.CamelCase);
request.Variables = _graphQLTextSerializer.Deserialize<Inputs>(context.Request.Query["variables"]);
}

if (context.Request.Query.ContainsKey("operationName"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@

using GraphQL.Transport;
using OrchardCore.Apis.GraphQL.Queries;

namespace OrchardCore.Apis.GraphQL
{
public class GraphQLNamedQueryRequest : GraphQLRequest
{
/// <summary>
/// Used to store some graphql query on the server, and then the client only needs to submit the name of that query to reduce the size of the network request
/// <see cref="INamedQueryProvider"/>
/// </summary>
public string NamedQuery { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using GraphQL;

namespace OrchardCore.Apis.GraphQL.Json;

public class GraphQLNamedQueryRequestJsonConverter : JsonConverter<GraphQLNamedQueryRequest>
{
public static readonly GraphQLNamedQueryRequestJsonConverter Instance = new();

/// <summary>
/// Name for the operation name parameter.
/// See https://github.com/graphql/graphql-over-http/blob/master/spec/GraphQLOverHTTP.md#request-parameters
/// </summary>
private const string _operationNameKey = "operationName";

/// <summary>
/// Name for the query parameter.
/// See https://github.com/graphql/graphql-over-http/blob/master/spec/GraphQLOverHTTP.md#request-parameters
/// </summary>
private const string _queryKey = "query";

/// <summary>
/// Name for the variables parameter.
/// See https://github.com/graphql/graphql-over-http/blob/master/spec/GraphQLOverHTTP.md#request-parameters
/// </summary>
private const string _variablesKey = "variables";

/// <summary>
/// Name for the extensions parameter.
/// See https://github.com/graphql/graphql-over-http/blob/master/spec/GraphQLOverHTTP.md#request-parameters
/// </summary>
private const string _extensionsKey = "extensions";

/// <summary>
/// Name for the namedQuery parameter.
/// </summary>
private const string _namedQueryKey = "namedQuery";

public override void Write(Utf8JsonWriter writer, GraphQLNamedQueryRequest value, JsonSerializerOptions options)
{
writer.WriteStartObject();
if (value.Query != null)
{
writer.WritePropertyName(_queryKey);
writer.WriteStringValue(value.Query);
}

if (value.OperationName != null)
{
writer.WritePropertyName(_operationNameKey);
writer.WriteStringValue(value.OperationName);
}

if (value.Variables != null)
{
writer.WritePropertyName(_variablesKey);
JsonSerializer.Serialize(writer, value.Variables, options);
}

if (value.Extensions != null)
{
writer.WritePropertyName(_extensionsKey);
JsonSerializer.Serialize(writer, value.Extensions, options);
}

if (value.NamedQuery != null)
{
writer.WritePropertyName(_namedQueryKey);
JsonSerializer.Serialize(writer, value.NamedQuery, options);
}

writer.WriteEndObject();
}

public override GraphQLNamedQueryRequest Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}

var request = new GraphQLNamedQueryRequest();

while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return request;
}

if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}

var key = reader.GetString()!;

// Unexpected end of data.
if (!reader.Read())
throw new JsonException();

switch (key)
{
case _queryKey:
request.Query = reader.GetString()!;
break;
case _operationNameKey:
request.OperationName = reader.GetString()!;
break;
case _namedQueryKey:
request.NamedQuery = reader.GetString();
break;
case _variablesKey:
request.Variables = JsonSerializer.Deserialize<Inputs>(ref reader, options);
break;
case _extensionsKey:
request.Extensions = JsonSerializer.Deserialize<Inputs>(ref reader, options);
break;
default:
reader.Skip();
break;
}
}

// Unexpected end of data.
throw new JsonException();
}
}
Loading

0 comments on commit 80aeca8

Please sign in to comment.