Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade graphql to 7.7.2 #15129

Merged
merged 44 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
064cd9a
Upgrade to GraphQL 7.2.2
hishamco Feb 14, 2023
c3c2d82
Add media filenames on MediaFieldType
hyzx86 Jan 6, 2024
4cdec82
merge latest code
hyzx86 Jan 19, 2024
6998b7b
add logs to unit tests
hyzx86 Jan 19, 2024
eb287b3
merge test log function
hyzx86 Jan 19, 2024
acfa5ce
UseNLogHost()
hyzx86 Jan 19, 2024
32d8af3
restore changes
hyzx86 Jan 19, 2024
7d8674b
update test log
hyzx86 Jan 19, 2024
681dc52
fix LockedAsyncFieldResolver
hyzx86 Jan 20, 2024
9d71c8b
try upgrade graphql 7.7.2
hyzx86 Jan 20, 2024
6bc4238
Merge branch 'main' into upgrade-graphQL
hishamco Jan 20, 2024
5007446
try remove all schema.RegisterType()
hyzx86 Jan 21, 2024
53d0e91
Merge branch 'upgrade-graphQL' of https://github.com/hyzx86/OrchardCo…
hyzx86 Jan 21, 2024
2349912
update dynamic field
hyzx86 Jan 21, 2024
43e28bf
update MenuItemInterface
hyzx86 Jan 21, 2024
937c818
Merge remote-tracking branch 'origin/main' into upgrade-graphQL
Jan 22, 2024
a8b36e2
fix LuceneQueryFieldTypeProvider
Jan 22, 2024
b5d0338
Merge branch 'main' into upgrade-graphQL
hishamco Jan 22, 2024
c8e4062
add types cache
Jan 22, 2024
f114d76
Merge branch 'upgrade-graphQL' of https://github.com/hyzx86/OrchardCo…
Jan 22, 2024
6701ff0
try cache types
hyzx86 Jan 22, 2024
4afb0d2
search type from di
hyzx86 Jan 22, 2024
056120b
add log details
Jan 23, 2024
5e29e7d
Operation is not valid due to the current state of the object.
hyzx86 Jan 29, 2024
5eb2356
merge main
hyzx86 Jan 30, 2024
7e565c3
merge main
hyzx86 Jan 30, 2024
571b933
AutoroutePart Filter not work
hyzx86 Jan 30, 2024
a8b2adb
merge main
hyzx86 Jan 30, 2024
eb0b164
Merge branch 'main' into upgrade-graphQL
hyzx86 Jan 30, 2024
9d93d5c
Fix all unit test
hyzx86 Jan 30, 2024
74f8d8f
Merge branch 'upgrade-graphQL' of https://github.com/hyzx86/OrchardCo…
hyzx86 Jan 30, 2024
d0e949b
Merge branch 'main' into upgrade-graphQL
hyzx86 Jan 30, 2024
0851741
merge main
hyzx86 Jan 31, 2024
8b996b3
fix error
hyzx86 Jan 31, 2024
9b70bae
Merge branch 'upgrade-graphQL' of https://github.com/hyzx86/OrchardCo…
hyzx86 Jan 31, 2024
6a601a5
add function ResolveContentItems in unit test
Feb 2, 2024
6c18b6b
remove log in test
Feb 2, 2024
ba5f95c
remove log in test
Feb 2, 2024
8ae797d
cache graphType
Feb 2, 2024
a1d9686
Merge branch 'main' into upgrade-graphQL
hishamco Feb 2, 2024
815bb84
Merge branch 'main' into upgrade-graphQL
sebastienros Feb 6, 2024
da7ab9e
Fix build
sebastienros Feb 7, 2024
2a3b81f
Merge branch 'main' into upgrade-graphQL
sebastienros Feb 7, 2024
193bda0
Merge branch 'main' into upgrade-graphQL
MikeAlhayek Feb 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/OrchardCore.Build/Dependencies.props
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
<PackageManagement Include="Castle.Core" Version="5.1.1" />
<PackageManagement Include="DocumentFormat.OpenXml" Version="3.0.1" />
<PackageManagement Include="Fluid.Core" Version="2.5.0" />
<PackageManagement Include="GraphQL" Version="4.8.0" />
<PackageManagement Include="GraphQL.DataLoader" Version="4.8.0" />
<PackageManagement Include="GraphQL.MicrosoftDI" Version="4.8.0" />
<PackageManagement Include="GraphQL.SystemTextJson" Version="4.8.0" />
<PackageManagement Include="GraphQL" Version="7.7.2" />
<PackageManagement Include="GraphQL.DataLoader" Version="7.7.2" />
<PackageManagement Include="GraphQL.MicrosoftDI" Version="7.7.2" />
<PackageManagement Include="GraphQL.SystemTextJson" Version="7.7.2" />
<PackageManagement Include="Jint" Version="3.0.0" />
<PackageManagement Include="HtmlSanitizer" Version="8.1.839-beta" />
<PackageManagement Include="Irony.Core" Version="1.0.7" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace OrchardCore.Apis.GraphQL
{
internal static class DocumentWriterExtensions
{
public static async Task WriteErrorAsync(this IDocumentWriter documentWriter, HttpContext context, string message, Exception e = null)
public static async Task WriteErrorAsync(this IGraphQLSerializer graphQLSerializer, HttpContext context, string message, Exception e = null)
{
ArgumentNullException.ThrowIfNull(message);

Expand All @@ -30,7 +30,7 @@ public static async Task WriteErrorAsync(this IDocumentWriter documentWriter, Ht
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
context.Response.ContentType = MediaTypeNames.Application.Json;

await documentWriter.WriteAsync(context.Response.Body, errorResult);
await graphQLSerializer.WriteAsync(context.Response.Body, errorResult);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,72 +11,73 @@
using GraphQL.SystemTextJson;
using GraphQL.Validation;
using GraphQL.Validation.Complexity;
using GraphQL.Validation.Rules.Custom;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OrchardCore.Apis.GraphQL.Queries;
using OrchardCore.Apis.GraphQL.ValidationRules;
using OrchardCore.Routing;

namespace OrchardCore.Apis.GraphQL
{
public class GraphQLMiddleware
public class GraphQLMiddleware : IMiddleware
{
private readonly RequestDelegate _next;
private readonly GraphQLSettings _settings;
private readonly IGraphQLSerializer _serializer;
private readonly IDocumentExecuter _executer;
internal static readonly Encoding _utf8Encoding = new UTF8Encoding(false);
private static readonly MediaType _jsonMediaType = new("application/json");
private static readonly MediaType _graphQlMediaType = new("application/graphql");

public GraphQLMiddleware(
RequestDelegate next,
GraphQLSettings settings,
IDocumentExecuter executer)
IOptions<GraphQLSettings> settingsOption,
IDocumentExecuter executer,
IGraphQLSerializer serializer)
{
_next = next;
_settings = settings;
_settings = settingsOption.Value;
_executer = executer;
_serializer = serializer;
}

public async Task Invoke(HttpContext context, IAuthorizationService authorizationService, IAuthenticationService authenticationService, ISchemaFactory schemaService, IDocumentWriter documentWriter)
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
if (!IsGraphQLRequest(context))
{
await _next(context);
await next(context);
}
else
{
var authenticationService = context.RequestServices.GetService<IAuthenticationService>();
var authenticateResult = await authenticationService.AuthenticateAsync(context, "Api");

if (authenticateResult.Succeeded)
{
context.User = authenticateResult.Principal;
}

var authorizationService = context.RequestServices.GetService<IAuthorizationService>();
var authorized = await authorizationService.AuthorizeAsync(context.User, Permissions.ExecuteGraphQL);

if (authorized)
{
await ExecuteAsync(context, schemaService, documentWriter);
await ExecuteAsync(context);
}
else
{
await context.ChallengeAsync("Api");
}
}
}

private bool IsGraphQLRequest(HttpContext context)
{
return context.Request.Path.StartsWithNormalizedSegments(_settings.Path, StringComparison.OrdinalIgnoreCase);
}

private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaService, IDocumentWriter documentWriter)
private async Task ExecuteAsync(HttpContext context)
{
GraphQLRequest request = null;
GraphQLNamedQueryRequest request = null;

// c.f. https://graphql.org/learn/serving-over-http/#post-request

Expand All @@ -93,14 +94,14 @@ private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaServic
{
using var sr = new StreamReader(context.Request.Body);

request = new GraphQLRequest
request = new GraphQLNamedQueryRequest
{
Query = await sr.ReadToEndAsync()
};
}
else
{
request = await JsonSerializer.DeserializeAsync<GraphQLRequest>(context.Request.Body, JOptions.CamelCase);
request = await JsonSerializer.DeserializeAsync<GraphQLNamedQueryRequest>(context.Request.Body, JOptions.CamelCase);
}
}
else
Expand All @@ -120,7 +121,7 @@ private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaServic
}
catch (Exception e)
{
await documentWriter.WriteErrorAsync(context, "An error occurred while processing the GraphQL query", e);
await _serializer.WriteErrorAsync(context, "An error occurred while processing the GraphQL query", e);
return;
}

Expand All @@ -137,25 +138,26 @@ private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaServic
queryToExecute = queries[request.NamedQuery];
}

var schemaService = context.RequestServices.GetService<ISchemaFactory>();
var schema = await schemaService.GetSchemaAsync();
var dataLoaderDocumentListener = context.RequestServices.GetRequiredService<IDocumentExecutionListener>();
var result = await _executer.ExecuteAsync(_ =>
var result = await _executer.ExecuteAsync(options =>
{
_.Schema = schema;
_.Query = queryToExecute;
_.OperationName = request.OperationName;
_.Inputs = request.Variables.ToInputs();
_.UserContext = _settings.BuildUserContext?.Invoke(context);
_.ValidationRules = DocumentValidator.CoreRules
.Concat(context.RequestServices.GetServices<IValidationRule>());
_.ComplexityConfiguration = new ComplexityConfiguration
{
MaxDepth = _settings.MaxDepth,
MaxComplexity = _settings.MaxComplexity,
FieldImpact = _settings.FieldImpact
};
_.Listeners.Add(dataLoaderDocumentListener);
_.RequestServices = context.RequestServices;
options.Schema = schema;
options.Query = queryToExecute;
options.OperationName = request.OperationName;
options.Variables = request.Variables;
options.UserContext = _settings.BuildUserContext?.Invoke(context);
options.ValidationRules = DocumentValidator.CoreRules
.Concat(context.RequestServices.GetServices<IValidationRule>())
.Append(new ComplexityValidationRule(new ComplexityConfiguration
{
MaxDepth = _settings.MaxDepth,
MaxComplexity = _settings.MaxComplexity,
FieldImpact = _settings.FieldImpact
}));
options.Listeners.Add(dataLoaderDocumentListener);
options.RequestServices = context.RequestServices;
});

context.Response.StatusCode = (int)(result.Errors == null || result.Errors.Count == 0
Expand All @@ -166,10 +168,10 @@ private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaServic

context.Response.ContentType = MediaTypeNames.Application.Json;

await documentWriter.WriteAsync(context.Response.Body, result);
await _serializer.WriteAsync(context.Response.Body, result);
}

private static GraphQLRequest CreateRequestFromQueryString(HttpContext context, bool validateQueryKey = false)
private GraphQLNamedQueryRequest CreateRequestFromQueryString(HttpContext context, bool validateQueryKey = false)
{
if (!context.Request.Query.ContainsKey("query"))
{
Expand All @@ -181,14 +183,14 @@ private static GraphQLRequest CreateRequestFromQueryString(HttpContext context,
return null;
}

var request = new GraphQLRequest
var request = new GraphQLNamedQueryRequest
{
Query = context.Request.Query["query"]
};

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

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

using GraphQL.Transport;

namespace OrchardCore.Apis.GraphQL
{
public class GraphQLNamedQueryRequest : GraphQLRequest
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class name conflict, Maybe someone has a better name

{
public string NamedQuery { get; set; }
}
}
13 changes: 0 additions & 13 deletions src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLRequest.cs

This file was deleted.

10 changes: 6 additions & 4 deletions src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Text.Json;
using GraphQL;
using GraphQL.DataLoader;
using GraphQL.Execution;
Expand Down Expand Up @@ -36,7 +37,6 @@ public Startup(IOptions<AdminOptions> adminOptions, IHostEnvironment hostingEnvi
public override void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IDocumentExecuter, DocumentExecuter>();
services.AddSingleton<IDocumentWriter, DocumentWriter>();
services.AddSingleton<IDataLoaderContextAccessor, DataLoaderContextAccessor>();
services.AddSingleton<IDocumentExecutionListener, DataLoaderDocumentListener>();

Expand All @@ -47,11 +47,13 @@ public override void ConfigureServices(IServiceCollection services)
services.AddSingleton<IErrorInfoProvider>(services =>
{
var settings = services.GetRequiredService<IOptions<GraphQLSettings>>();
return new ErrorInfoProvider(new ErrorInfoProviderOptions { ExposeExceptionStackTrace = settings.Value.ExposeExceptions });
return new ErrorInfoProvider(new ErrorInfoProviderOptions { ExposeExceptionDetails = settings.Value.ExposeExceptions });
});

services.AddScoped<IPermissionProvider, Permissions>();
services.AddTransient<INavigationProvider, AdminMenu>();
services.AddSingleton<GraphQLMiddleware>();
services.AddGraphQL(builder => builder.AddSystemTextJson());

services.AddOptions<GraphQLSettings>().Configure<IShellConfiguration>((c, configuration) =>
{
Expand All @@ -72,7 +74,7 @@ public override void ConfigureServices(IServiceCollection services)
User = ctx.User,
};
c.ExposeExceptions = exposeExceptions;
c.MaxDepth = configuration.GetValue<int?>($"OrchardCore_Apis_GraphQL:{nameof(GraphQLSettings.MaxDepth)}") ?? 20;
c.MaxDepth = configuration.GetValue<int?>($"OrchardCore_Apis_GraphQL:{nameof(GraphQLSettings.MaxDepth)}") ?? 100;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix Query is too nested to execute. Depth is 59 levels, maximum allowed on this endpoint is 20.

c.MaxComplexity = configuration.GetValue<int?>($"OrchardCore_Apis_GraphQL:{nameof(GraphQLSettings.MaxComplexity)}");
c.FieldImpact = configuration.GetValue<double?>($"OrchardCore_Apis_GraphQL:{nameof(GraphQLSettings.FieldImpact)}");
c.MaxNumberOfResults = configuration.GetValue<int?>($"OrchardCore_Apis_GraphQL:{nameof(GraphQLSettings.MaxNumberOfResults)}") ?? 1000;
Expand All @@ -90,7 +92,7 @@ public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder ro
defaults: new { controller = typeof(AdminController).ControllerName(), action = nameof(AdminController.Index) }
);

app.UseMiddleware<GraphQLMiddleware>(serviceProvider.GetService<IOptions<GraphQLSettings>>().Value);
app.UseMiddleware<GraphQLMiddleware>();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Threading.Tasks;
using GraphQL.Language.AST;
using GraphQL.Validation;
using GraphQLParser.AST;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand All @@ -26,24 +27,24 @@ public MaxNumberOfResultsValidationRule(
_logger = logger;
}

public Task<INodeVisitor> ValidateAsync(ValidationContext validationContext)
public ValueTask<INodeVisitor> ValidateAsync(ValidationContext validationContext)
{
return Task.FromResult((INodeVisitor)new NodeVisitors(
new MatchingNodeVisitor<Argument>((arg, visitorContext) =>
return ValueTask.FromResult((INodeVisitor)new NodeVisitors(
new MatchingNodeVisitor<GraphQLArgument>((arg, visitorContext) =>
{
if ((arg.Name == "first" || arg.Name == "last") && arg.Value != null)
{
var context = (GraphQLUserContext)validationContext.UserContext;

int? value = null;

if (arg.Value is IntValue)
if (arg.Value is GraphQLIntValue)
{
value = ((IntValue)arg.Value)?.Value;
value = int.Parse((arg.Value as GraphQLIntValue).Value);
}
else
{
if (validationContext.Inputs.TryGetValue(arg.Value.ToString(), out var input))
if (validationContext.Variables.TryGetValue(arg.Value.ToString(), out var input))
{
value = (int?)input;
}
Expand All @@ -56,20 +57,16 @@ public Task<INodeVisitor> ValidateAsync(ValidationContext validationContext)
if (_maxNumberOfResultsValidationMode == MaxNumberOfResultsValidationMode.Enabled)
{
validationContext.ReportError(new ValidationError(
validationContext.Document.OriginalQuery,
validationContext.Document.Source,
"ArgumentInputError",
errorMessage,
arg));
}
else
{
_logger.LogInformation("'{IntValue}' exceeds the maximum number of results for '{ArgumentName}' ({MaxNumber})",
value.Value,
arg.Name,
_maxNumberOfResults);
_logger.LogInformation(errorMessage);

// If disabled mode we just log info and override the arg to be maxvalue.
arg = new Argument(arg.NameNode, new IntValue(_maxNumberOfResults));
arg = new GraphQLArgument(arg.Name, new GraphQLIntValue(_maxNumberOfResults)); // if disabled mode we just log info and override the arg to be maxvalue
}
}
}
Expand Down
Loading
Loading