-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Replace ScriptsMiddleware(#15629) #16876
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using System.Globalization; | ||
using Microsoft.AspNetCore.Routing; | ||
using Microsoft.AspNetCore.Authorization; | ||
using Microsoft.AspNetCore.Builder; | ||
using Microsoft.AspNetCore.Http; | ||
using OrchardCore.ContentManagement; | ||
using OrchardCore.Settings; | ||
using OrchardCore.Facebook.Settings; | ||
|
||
namespace OrchardCore.Facebook; | ||
internal static class InitSdkEndpoint | ||
{ | ||
public static IEndpointRouteBuilder AddInitSdkEndpoint(this IEndpointRouteBuilder builder) | ||
{ | ||
builder.MapGet("orchardcore/facebook/sdk/fbsdk.js", HandleAsync) | ||
.AllowAnonymous() | ||
.DisableAntiforgery(); | ||
|
||
return builder; | ||
} | ||
|
||
[Authorize(AuthenticationSchemes = "Api")] | ||
private static async Task<IResult> HandleAsync( | ||
ContentItem model, | ||
ISiteService siteService, | ||
HttpContext httpContext, | ||
bool draft = false) | ||
{ | ||
ArgumentNullException.ThrowIfNull(httpContext); | ||
|
||
var script = await getInitSdkScript(siteService); | ||
|
||
if (script == null) | ||
{ | ||
return Results.NotFound(); | ||
} | ||
|
||
return Results.Ok(script); | ||
} | ||
|
||
private static async Task<string> getInitSdkScript(ISiteService siteService) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to be cached by culture (or split this script in two, one with culture and one using a variable name.). |
||
{ | ||
var settings = await siteService.GetSettingsAsync<FacebookSettings>(); | ||
var locale = CultureInfo.CurrentUICulture.Name.Replace('-', '_'); | ||
|
||
var script = $@"(function(d){{ | ||
var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {{ return; }} | ||
js = d.createElement('script'); js.id = id; js.async = true; | ||
js.src = ""https://connect.facebook.net/{locale}/{settings.SdkJs}""; | ||
d.getElementsByTagName('head')[0].appendChild(js); | ||
}} (document));"; | ||
|
||
return script; | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
using System.Globalization; | ||
using Microsoft.AspNetCore.Routing; | ||
using Microsoft.AspNetCore.Authorization; | ||
using Microsoft.AspNetCore.Builder; | ||
using Microsoft.AspNetCore.Http; | ||
using OrchardCore.ContentManagement; | ||
using OrchardCore.Settings; | ||
using OrchardCore.Facebook.Settings; | ||
|
||
namespace OrchardCore.Facebook; | ||
internal static class LoadSdkEndpoint | ||
{ | ||
public static IEndpointRouteBuilder AddLoadSdkEndpoint(this IEndpointRouteBuilder builder) | ||
{ | ||
builder.MapGet("orchardcore/facebook/sdk/fb.js", HandleAsync) | ||
.AllowAnonymous() | ||
.DisableAntiforgery(); | ||
|
||
return builder; | ||
} | ||
|
||
[Authorize(AuthenticationSchemes = "Api")] | ||
private static async Task<IResult> HandleAsync( | ||
ContentItem model, | ||
ISiteService siteService, | ||
HttpContext httpContext, | ||
bool draft = false) | ||
{ | ||
ArgumentNullException.ThrowIfNull(httpContext); | ||
|
||
var script = await getLoadSdkScript(siteService); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't this be cached and reused? |
||
|
||
if (script == null) | ||
{ | ||
return Results.NotFound(); | ||
} | ||
|
||
return Results.Ok(script); | ||
} | ||
|
||
private static async Task<string> getLoadSdkScript(ISiteService siteService) | ||
{ | ||
var settings = await siteService.GetSettingsAsync<FacebookSettings>(); | ||
var locale = CultureInfo.CurrentUICulture.Name.Replace('-', '_'); | ||
|
||
var script = default(string); | ||
|
||
if (!string.IsNullOrWhiteSpace(settings?.AppId)) | ||
{ | ||
var options = $"{{ appId:'{settings.AppId}',version:'{settings.Version}'"; | ||
options = string.IsNullOrWhiteSpace(settings.FBInitParams) | ||
? string.Concat(options, "}") | ||
: string.Concat(options, ",", settings.FBInitParams, "}"); | ||
|
||
script = $"window.fbAsyncInit = function(){{ FB.init({options});}};"; | ||
} | ||
|
||
return script; | ||
} | ||
} | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,8 @@ public sealed class Startup : StartupBase | |
{ | ||
public override void Configure(IApplicationBuilder builder, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) | ||
{ | ||
builder.UseMiddleware<ScriptsMiddleware>(); | ||
routes.AddInitSdkEndpoint(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you make it a single method, like |
||
routes.AddLoadSdkEndpoint(); | ||
} | ||
|
||
public override void ConfigureServices(IServiceCollection services) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
using Fluid; | ||
using System.Text; | ||
using Microsoft.AspNetCore.Authorization; | ||
using Microsoft.AspNetCore.Builder; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Routing; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Options; | ||
using Microsoft.Net.Http.Headers; | ||
using OrchardCore.ContentManagement; | ||
using OrchardCore.DisplayManagement.Liquid; | ||
using OrchardCore.Environment.Shell.Configuration; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.Caching.Memory; | ||
|
||
namespace OrchardCore.Liquid.Endpoints.Api; | ||
|
||
public static class GetIntellisenseEndpoint | ||
{ | ||
|
||
public static IEndpointRouteBuilder AddGetIntellisenseEndpoint(this IEndpointRouteBuilder builder) | ||
{ | ||
builder.MapGet("/OrchardCore.Liquid/Scripts/liquid-intellisense.js", HandleAsync) | ||
.AllowAnonymous() | ||
.DisableAntiforgery(); | ||
|
||
return builder; | ||
} | ||
|
||
[Authorize(AuthenticationSchemes = "Api")] | ||
private static Task<IResult> HandleAsync(HttpContext httpContext, IMemoryCache cache) | ||
{ | ||
const string cacheKey = "LiquidIntellisenseScript"; | ||
|
||
var cacheControl = $"public, max-age={TimeSpan.FromDays(30).TotalSeconds}, s-max-age={TimeSpan.FromDays(365.25).TotalSeconds}"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can the etag and caching headers be configured on the |
||
if (cache.TryGetValue(cacheKey, out (byte[] Bytes, string ETag) cachedData)) | ||
{ | ||
if (httpContext.Request.Headers.TryGetValue(HeaderNames.IfNoneMatch, out var etagHeader) && | ||
etagHeader.Contains(cachedData.ETag)) | ||
{ | ||
return Task.FromResult(Results.StatusCode(StatusCodes.Status304NotModified)); | ||
} | ||
|
||
httpContext.Response.Headers[HeaderNames.CacheControl] = cacheControl; | ||
httpContext.Response.Headers[HeaderNames.ContentType] = "application/javascript"; | ||
httpContext.Response.Headers[HeaderNames.ETag] = cachedData.ETag; | ||
|
||
return Task.FromResult(Results.Bytes(cachedData.Bytes, "application/javascript")); | ||
} | ||
|
||
var shellConfiguration = httpContext.RequestServices.GetRequiredService<IShellConfiguration>(); | ||
cacheControl = shellConfiguration.GetValue("StaticFileOptions:CacheControl", cacheControl); | ||
|
||
var templateOptions = httpContext.RequestServices.GetRequiredService<IOptions<TemplateOptions>>(); | ||
var liquidViewParser = httpContext.RequestServices.GetRequiredService<LiquidViewParser>(); | ||
|
||
var filters = string.Join(',', templateOptions.Value.Filters.Select(x => $"'{x.Key}'")); | ||
var tags = string.Join(',', liquidViewParser.RegisteredTags.Select(x => $"'{x.Key}'")); | ||
|
||
var script = $@"[{filters}].forEach(value=>{{if(!liquidFilters.includes(value)){{ liquidFilters.push(value);}}}}); | ||
[{tags}].forEach(value=>{{if(!liquidTags.includes(value)){{ liquidTags.push(value);}}}});"; | ||
|
||
var etag = Guid.NewGuid().ToString("n"); | ||
var bytes = Encoding.UTF8.GetBytes(script); | ||
cache.Set(cacheKey,(bytes,etag)); | ||
|
||
httpContext.Response.Headers[HeaderNames.CacheControl] = cacheControl; | ||
httpContext.Response.Headers[HeaderNames.ContentType] = "application/javascript"; | ||
httpContext.Response.Headers[HeaderNames.ETag] = etag; | ||
|
||
return Task.FromResult(Results.Bytes(bytes, "application/javascript")); | ||
} | ||
|
||
} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this return a utf8 encoded
byte[]
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If
Results
is not powerful enough , maybe use the response writer directly (PipeWriter?, TextWriter?).