Skip to content

Commit

Permalink
Fixes and simplified the angular integration. (#822)
Browse files Browse the repository at this point in the history
* Fixes and simplified the angular integration.

* More fixes.
  • Loading branch information
SebastianStehle committed Jan 5, 2022
1 parent 9abdbac commit 4c31931
Show file tree
Hide file tree
Showing 21 changed files with 412 additions and 493 deletions.
2 changes: 1 addition & 1 deletion backend/src/Squidex.Web/Pipeline/CachingManager.cs
Expand Up @@ -146,7 +146,7 @@ public void Finish(HttpResponse response, ObjectPool<StringBuilder> stringBuilde

if (headers.Count > 0)
{
response.Headers.Add(HeaderNames.Vary, new StringValues(headers.ToArray()));
response.Headers[HeaderNames.Vary] = new StringValues(headers.ToArray());
}
}

Expand Down
56 changes: 23 additions & 33 deletions backend/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs
Expand Up @@ -9,74 +9,64 @@
using System.Globalization;
using System.Net;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Squidex.Areas.Api.Controllers.UI;
using Squidex.Domain.Apps.Entities.History;
using Squidex.Infrastructure.Json;
using Squidex.Web;

namespace Squidex.Areas.Frontend.Middlewares
{
public static class IndexExtensions
{
private static readonly ConcurrentDictionary<string, string> Texts = new ConcurrentDictionary<string, string>();

public static bool IsIndex(this HttpContext context)
{
var path = context.Request.Path.Value;

return path == "/" || path?.EndsWith("/index.html", StringComparison.OrdinalIgnoreCase) == true;
}

public static bool IsHtmlPath(this HttpContext context)
private static readonly JsonSerializer JsonSerializer = JsonSerializer.CreateDefault(new JsonSerializerSettings
{
return context.Request.Path.Value?.EndsWith(".html", StringComparison.OrdinalIgnoreCase) == true;
}
ContractResolver = new CamelCasePropertyNamesContractResolver()
});

public static bool IsNotModified(this HttpResponse response)
public static bool IsIndex(this HttpContext context)
{
return response.StatusCode == (int)HttpStatusCode.NotModified;
return context.Request.Path.StartsWithSegments("/index.html", StringComparison.OrdinalIgnoreCase);
}

public static string AdjustBase(this string html, HttpContext httpContext)
public static string AddOptions(this string html, HttpContext httpContext)
{
if (httpContext.Request.PathBase != null)
var scripts = new List<string>
{
html = html.Replace("<base href=\"/\">", $"<base href=\"{httpContext.Request.PathBase}/\">", StringComparison.OrdinalIgnoreCase);
}
$"var texts = {GetText(CultureInfo.CurrentUICulture.Name)};"
};

return html;
}

public static string AddOptions(this string html, HttpContext httpContext)
{
var uiOptions = httpContext.RequestServices.GetService<IOptions<MyUIOptions>>()?.Value;

if (uiOptions != null)
{
var json = JObject.FromObject(uiOptions, JsonSerializer);

var values = httpContext.RequestServices.GetService<ExposedValues>();

if (values != null)
{
uiOptions.More["info"] = values.ToString();
json["more"] ??= new JObject();
json["more"]!["info"] = values.ToString();
}

var notifo = httpContext.RequestServices!.GetRequiredService<IOptions<NotifoOptions>>();
var notifo = httpContext.RequestServices!.GetService<IOptions<NotifoOptions>>();

if (notifo.Value.IsConfigured())
if (notifo?.Value.IsConfigured() == true)
{
uiOptions.More["notifoApi"] = notifo.Value.ApiUrl;
json["more"] ??= new JObject();
json["more"]!["notifoApi"] = notifo.Value.ApiUrl;
}

uiOptions.More["culture"] = CultureInfo.CurrentUICulture.Name;

var jsonSerializer = httpContext.RequestServices.GetRequiredService<IJsonSerializer>();
var jsonOptions = jsonSerializer.Serialize(uiOptions, true);

var texts = GetText(CultureInfo.CurrentUICulture.Name);

html = html.Replace("<body>", $"<body>\n<script>\nvar options = {jsonOptions};\nvar texts = {texts};</script>", StringComparison.OrdinalIgnoreCase);
scripts.Add($"var options = {json.ToString(Formatting.Indented)};");
}

html = html.Replace("<body>", $"<body>\n<script>{string.Join(Environment.NewLine, scripts)}</script>", StringComparison.OrdinalIgnoreCase);

return html;
}

Expand Down
57 changes: 0 additions & 57 deletions backend/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs

This file was deleted.

This file was deleted.

85 changes: 43 additions & 42 deletions backend/src/Squidex/Areas/Frontend/Startup.cs
Expand Up @@ -5,8 +5,10 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================

using Microsoft.Extensions.FileProviders;
using Microsoft.Net.Http.Headers;
using Squidex.Areas.Frontend.Middlewares;
using Squidex.Hosting.Web;
using Squidex.Pipeline.Squid;
using Squidex.Web.Pipeline;

Expand All @@ -18,74 +20,73 @@ public static void ConfigureFrontend(this IApplicationBuilder app)
{
var environment = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>();

app.Map("/squid.svg", builder => builder.UseMiddleware<SquidMiddleware>());
var fileProvider = environment.WebRootFileProvider;

app.UseMiddleware<NotifoMiddleware>();

var indexFile =
environment.IsProduction() ?
new PathString("/build/index.html") :
new PathString("/index.html");

app.Use((context, next) =>
if (environment.IsProduction())
{
if (context.Request.Path == "/client-callback-popup")
{
context.Request.Path = new PathString("/client-callback-popup.html");
}
else if (context.Request.Path == "/client-callback-silent")
{
context.Request.Path = new PathString("/client-callback-silent.html");
}
else if (!Path.HasExtension(context.Request.Path.Value))
fileProvider = new CompositeFileProvider(fileProvider,
new PhysicalFileProvider(Path.Combine(environment.WebRootPath, "build")));

app.Use((context, next) =>
{
context.Request.Path = indexFile;
}
if (!Path.HasExtension(context.Request.Path.Value))
{
context.Request.Path = new PathString("/index.html");
}
return next();
return next();
});
}

app.Map("/squid.svg", builder =>
{
builder.UseMiddleware<SquidMiddleware>();
});

app.UseWhen(x => x.Request.Path.StartsWithSegments(indexFile, StringComparison.Ordinal), builder =>
app.UseMiddleware<NotifoMiddleware>();

app.UseWhen(x => x.IsIndex(), builder =>
{
builder.UseMiddleware<SetupMiddleware>();
});

app.UseMiddleware<IndexMiddleware>();
app.UseHtmlTransform(new HtmlTransformOptions
{
Transform = (html, context) =>
{
if (context.IsIndex())
{
html = html.AddOptions(context);
}
app.ConfigureDev();
return new ValueTask<string>(html);
}
});

app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = context =>
{
var response = context.Context.Response;
var responseHeaders = response.GetTypedHeaders();
if (!string.Equals(response.ContentType, "text/html", StringComparison.OrdinalIgnoreCase))
if (!string.IsNullOrWhiteSpace(context.Context.Request.QueryString.ToString()))
{
responseHeaders.CacheControl = new CacheControlHeaderValue
{
MaxAge = TimeSpan.FromDays(60)
};
response.Headers[HeaderNames.CacheControl] = "max-age=5184000";
}
else
else if (string.Equals(response.ContentType, "text/html", StringComparison.OrdinalIgnoreCase))
{
responseHeaders.CacheControl = new CacheControlHeaderValue
{
NoCache = true
};
response.Headers[HeaderNames.CacheControl] = "no-cache";
}
}
},
FileProvider = fileProvider
});
}

public static void ConfigureDev(this IApplicationBuilder app)
{
var environment = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>();

if (environment.IsDevelopment())
{
app.UseMiddleware<WebpackMiddleware>();
app.UseSpa(builder =>
{
builder.UseProxyToSpaDevelopmentServer("https://localhost:3000");
});
}
}
}
Expand Down
Expand Up @@ -155,8 +155,8 @@ private static IEnumerable<(string, OpenIddictApplicationDescriptor)> CreateStat
RedirectUris =
{
new Uri(urlGenerator.BuildUrl("login;")),
new Uri(urlGenerator.BuildUrl("client-callback-silent", false)),
new Uri(urlGenerator.BuildUrl("client-callback-popup", false))
new Uri(urlGenerator.BuildUrl("client-callback-silent.html", false)),
new Uri(urlGenerator.BuildUrl("client-callback-popup.html", false))
},
PostLogoutRedirectUris =
{
Expand Down
Expand Up @@ -43,13 +43,6 @@ public class SetupController : IdentityServerController
this.userService = userService;
}

[HttpGet]
[Route("webpack/")]
public IActionResult Webpack()
{
return View();
}

[HttpGet]
[Route("setup/")]
public async Task<IActionResult> Setup()
Expand Down

0 comments on commit 4c31931

Please sign in to comment.