diff --git a/src/Squidex.Web/ApiController.cs b/src/Squidex.Web/ApiController.cs index 5eb10a7bfd..2d4a8d5179 100644 --- a/src/Squidex.Web/ApiController.cs +++ b/src/Squidex.Web/ApiController.cs @@ -51,7 +51,9 @@ protected ApiController(ICommandBus commandBus) public override void OnActionExecuting(ActionExecutingContext context) { - if (!context.HttpContext.Request.PathBase.StartsWithSegments("/api")) + var request = context.HttpContext.Request; + + if (!request.PathBase.HasValue || !request.PathBase.Value.EndsWith("/api", StringComparison.OrdinalIgnoreCase)) { context.Result = new RedirectResult("/"); } diff --git a/src/Squidex/Areas/Api/Controllers/ApiController.cs b/src/Squidex/Areas/Api/Controllers/ApiController.cs deleted file mode 100644 index 03ccc89c1c..0000000000 --- a/src/Squidex/Areas/Api/Controllers/ApiController.cs +++ /dev/null @@ -1,61 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Infrastructure; -using Squidex.Infrastructure.Commands; -using Squidex.Web; - -namespace Squidex.Areas.Api.Controllers -{ - [Area("Api")] - [ApiController] - [ApiExceptionFilter] - [ApiModelValidation(false)] - public abstract class ApiController : Controller - { - protected ICommandBus CommandBus { get; } - - protected IAppEntity App - { - get - { - var appFeature = HttpContext.Features.Get(); - - if (appFeature == null) - { - throw new InvalidOperationException("Not in a app context."); - } - - return appFeature.App; - } - } - - protected Guid AppId - { - get { return App.Id; } - } - - protected ApiController(ICommandBus commandBus) - { - Guard.NotNull(commandBus, nameof(commandBus)); - - CommandBus = commandBus; - } - - public override void OnActionExecuting(ActionExecutingContext context) - { - if (!context.HttpContext.Request.PathBase.StartsWithSegments("/api")) - { - context.Result = new RedirectResult("/"); - } - } - } -} diff --git a/src/Squidex/Areas/Api/Controllers/Docs/DocsController.cs b/src/Squidex/Areas/Api/Controllers/Docs/DocsController.cs index 0feb14f90f..0e8bfe1b94 100644 --- a/src/Squidex/Areas/Api/Controllers/Docs/DocsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Docs/DocsController.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc; using Squidex.Infrastructure.Commands; +using Squidex.Web; namespace Squidex.Areas.Api.Controllers.Docs { diff --git a/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs b/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs index b904b0e9ae..13db98ab4d 100644 --- a/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs +++ b/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs @@ -12,14 +12,14 @@ namespace Squidex.Areas.Frontend.Middlewares { public static class IndexExtensions { - public static bool IsIndexHtml(this HttpContext context) + public static bool IsIndex(this HttpContext context) { - return context.IsIndex() && context.IsHtml(); + return context.Request.Path.Value.EndsWith("/index.html", StringComparison.OrdinalIgnoreCase); } - public static bool IsIndex(this HttpContext context) + public static bool IsHtmlPath(this HttpContext context) { - return context.Request.Path.Value.EndsWith("/index.html", StringComparison.OrdinalIgnoreCase); + return context.Request.Path.Value.EndsWith(".html", StringComparison.OrdinalIgnoreCase); } public static bool IsHtml(this HttpContext context) diff --git a/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs b/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs index 65dea1c281..9925e05133 100644 --- a/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs +++ b/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs @@ -25,7 +25,7 @@ public async Task Invoke(HttpContext context) { var basePath = context.Request.PathBase; - if (context.IsIndex() && basePath.HasValue) + if (context.IsHtmlPath() && basePath.HasValue) { var responseBuffer = new MemoryStream(); var responseBody = context.Response.Body; @@ -36,21 +36,14 @@ public async Task Invoke(HttpContext context) context.Response.Body = responseBody; - if (context.Response.StatusCode == 200 && context.IsIndexHtml()) - { - var response = Encoding.UTF8.GetString(responseBuffer.ToArray()); + var response = Encoding.UTF8.GetString(responseBuffer.ToArray()); - response = AdjustBase(response, basePath); + response = AdjustBase(response, basePath); - context.Response.ContentLength = Encoding.UTF8.GetByteCount(response); - context.Response.Body = responseBody; + context.Response.ContentLength = Encoding.UTF8.GetByteCount(response); + context.Response.Body = responseBody; - await context.Response.WriteAsync(response); - } - else if (context.Response.StatusCode != 304) - { - await responseBuffer.CopyToAsync(responseBody); - } + await context.Response.WriteAsync(response); } else { diff --git a/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs b/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs index e02d78ae90..2dc98b9bb4 100644 --- a/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs +++ b/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs @@ -28,7 +28,7 @@ public WebpackMiddleware(RequestDelegate next) public async Task Invoke(HttpContext context) { - if (context.IsIndex()) + if (context.IsHtmlPath()) { var responseBuffer = new MemoryStream(); var responseBody = context.Response.Body; @@ -39,22 +39,25 @@ public async Task Invoke(HttpContext context) context.Response.Body = responseBody; - if (context.Response.StatusCode == 200 && context.IsIndexHtml()) - { - var response = Encoding.UTF8.GetString(responseBuffer.ToArray()); + var response = Encoding.UTF8.GetString(responseBuffer.ToArray()); + if (context.IsIndex()) + { response = InjectStyles(response); response = InjectScripts(response); + } - context.Response.ContentLength = Encoding.UTF8.GetByteCount(response); - context.Response.Body = responseBody; + var basePath = context.Request.PathBase; - await context.Response.WriteAsync(response); - } - else if (context.Response.StatusCode != 304) + if (basePath.HasValue) { - await responseBuffer.CopyToAsync(responseBody); + response = AdjustBase(response, basePath.Value); } + + context.Response.ContentLength = Encoding.UTF8.GetByteCount(response); + context.Response.Body = responseBody; + + await context.Response.WriteAsync(response); } else { @@ -99,5 +102,10 @@ private static string InjectScripts(string response) return response; } + + private static string AdjustBase(string response, string baseUrl) + { + return response.Replace("", $""); + } } } diff --git a/src/Squidex/Areas/IdentityServer/Controllers/IdentityServerController.cs b/src/Squidex/Areas/IdentityServer/Controllers/IdentityServerController.cs index ad714b9869..efafc7dc73 100644 --- a/src/Squidex/Areas/IdentityServer/Controllers/IdentityServerController.cs +++ b/src/Squidex/Areas/IdentityServer/Controllers/IdentityServerController.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; @@ -15,7 +16,9 @@ public abstract class IdentityServerController : Controller { public override void OnActionExecuting(ActionExecutingContext context) { - if (!context.HttpContext.Request.PathBase.StartsWithSegments("/identity-server")) + var request = context.HttpContext.Request; + + if (!request.PathBase.HasValue || !request.PathBase.Value.EndsWith("/identity-server", StringComparison.OrdinalIgnoreCase)) { context.Result = new NotFoundResult(); } diff --git a/src/Squidex/app-config/webpack.config.js b/src/Squidex/app-config/webpack.config.js index 3af7f467cc..fccfc99bca 100644 --- a/src/Squidex/app-config/webpack.config.js +++ b/src/Squidex/app-config/webpack.config.js @@ -9,6 +9,8 @@ const plugins = { TsconfigPathsPlugin: require('tsconfig-paths-webpack-plugin') }; +const isDevServer = path.basename(require.main.filename) === 'webpack-dev-server.js'; + module.exports = { /** * Options affecting the resolving of modules. @@ -83,16 +85,22 @@ module.exports = { }, { test: /\.(woff|woff2|ttf|eot)(\?.*$|$)/, use: [{ - loader: 'file-loader?name=assets/[name].[hash].[ext]', + loader: 'file-loader?name=[name].[hash].[ext]', options: { - publicPath: 'assets/', - outputPath: 'assets' + outputPath: 'assets', + /* + * Use custom public path as ./ is not supported by fonts. + */ + publicPath: isDevServer ? undefined : 'assets' } }] }, { test: /\.(png|jpe?g|gif|svg|ico)(\?.*$|$)/, use: [{ - loader: 'file-loader?name=assets/[name].[hash].[ext]' + loader: 'file-loader?name=[name].[hash].[ext]', + options: { + outputPath: 'assets' + } }] }, { test: /\.css$/, diff --git a/src/Squidex/app-config/webpack.run.base.js b/src/Squidex/app-config/webpack.run.base.js index 1f3c207270..3fd8ea67c9 100644 --- a/src/Squidex/app-config/webpack.run.base.js +++ b/src/Squidex/app-config/webpack.run.base.js @@ -28,7 +28,7 @@ module.exports = webpackMerge(commonConfig, { }), new plugins.HtmlWebpackPlugin({ - template: 'wwwroot/theme.html', hash: true, chunksSortMode: 'none', filename: 'theme.html' + template: 'wwwroot/_theme.html', hash: true, chunksSortMode: 'none', filename: 'theme.html' }) ] }); \ No newline at end of file diff --git a/src/Squidex/app/app.component.html b/src/Squidex/app/app.component.html index 13f8dc54ee..488f5451ad 100644 --- a/src/Squidex/app/app.component.html +++ b/src/Squidex/app/app.component.html @@ -3,7 +3,7 @@
- Loading + Loading
Loading Squidex
diff --git a/src/Squidex/app/app.module.ts b/src/Squidex/app/app.module.ts index b65f53064d..43724634c7 100644 --- a/src/Squidex/app/app.module.ts +++ b/src/Squidex/app/app.module.ts @@ -32,7 +32,22 @@ import { SqxShellModule } from './shell'; import { routing } from './app.routes'; export function configApiUrl() { - return new ApiUrlConfig(window.location.protocol + '//' + window.location.host + '/'); + let bases = document.getElementsByTagName('base'); + let baseHref = null; + + if (bases.length > 0) { + baseHref = bases[0].href; + } + + if (!baseHref) { + baseHref = '/'; + } + + if (baseHref.indexOf(window.location.protocol) === 0) { + return new ApiUrlConfig(baseHref); + } else { + return new ApiUrlConfig(window.location.protocol + '//' + window.location.host + baseHref); + } } export function configTitles() { diff --git a/src/Squidex/app/features/apps/pages/apps-page.component.html b/src/Squidex/app/features/apps/pages/apps-page.component.html index 7451b1e7ba..3e81c2ffa2 100644 --- a/src/Squidex/app/features/apps/pages/apps-page.component.html +++ b/src/Squidex/app/features/apps/pages/apps-page.component.html @@ -30,7 +30,7 @@

{{app.name}}

- +

New App

@@ -44,7 +44,7 @@

New App

- +

New Blog Sample

@@ -61,7 +61,7 @@

New Blog Sample

- +

New Profile Sample

@@ -78,7 +78,7 @@

New Profile Sample

- +

New Identity App

diff --git a/src/Squidex/app/features/apps/pages/onboarding-dialog.component.html b/src/Squidex/app/features/apps/pages/onboarding-dialog.component.html index d60e4716b7..dce2eaed4e 100644 --- a/src/Squidex/app/features/apps/pages/onboarding-dialog.component.html +++ b/src/Squidex/app/features/apps/pages/onboarding-dialog.component.html @@ -3,7 +3,7 @@ Skip Tour
- +

Welcome to Squidex CMS

@@ -34,7 +34,7 @@

Apps

- +
@@ -59,7 +59,7 @@

Schemas

- +
@@ -84,7 +84,7 @@

Contents

- +
@@ -109,7 +109,7 @@

Assets

- +
@@ -119,7 +119,7 @@

Assets

- +

Awesome, now you know the basics!

diff --git a/src/Squidex/app/features/apps/pages/onboarding-dialog.component.scss b/src/Squidex/app/features/apps/pages/onboarding-dialog.component.scss index f2c725f3b3..a2dadddb30 100644 --- a/src/Squidex/app/features/apps/pages/onboarding-dialog.component.scss +++ b/src/Squidex/app/features/apps/pages/onboarding-dialog.component.scss @@ -31,7 +31,7 @@ p { &-content { color: $color-dark-foreground; background-color: $color-dark-onboarding; - background-image: url('/images/onboarding-background.png'); + background-image: url('./images/onboarding-background.png'); position: relative; } diff --git a/src/Squidex/app/features/dashboard/pages/dashboard-page.component.html b/src/Squidex/app/features/dashboard/pages/dashboard-page.component.html index f9b597d001..78b0002c04 100644 --- a/src/Squidex/app/features/dashboard/pages/dashboard-page.component.html +++ b/src/Squidex/app/features/dashboard/pages/dashboard-page.component.html @@ -15,7 +15,7 @@

Hi {{authState.user?.displayName}}

- +

New Schema

@@ -29,7 +29,7 @@

New Schema

- +

API Documentation

@@ -43,7 +43,7 @@

API Documentation

- +

Feedback & Support

@@ -57,7 +57,7 @@

Feedback & Support

- +

Github

diff --git a/src/Squidex/app/shared/components/pipes.ts b/src/Squidex/app/shared/components/pipes.ts index 17e01c3adb..a947138430 100644 --- a/src/Squidex/app/shared/components/pipes.ts +++ b/src/Squidex/app/shared/components/pipes.ts @@ -202,7 +202,7 @@ export class UserPictureRefPipe extends UserAsyncPipe implements PipeTransform { if (parts[0] === 'subject') { return users.getUser(parts[1]).pipe(map(u => this.apiUrl.buildUrl(`api/users/${u.id}/picture`))); } else { - return of('/images/client.png'); + return of('./images/client.png'); } }); } @@ -259,6 +259,6 @@ export class FileIconPipe implements PipeTransform { mimeIcon = knownTypes.indexOf(asset.fileType) >= 0 ? asset.fileType : 'generic'; } - return `/images/asset_${mimeIcon}.png`; + return `./images/asset_${mimeIcon}.png`; } } \ No newline at end of file diff --git a/src/Squidex/app/shell/pages/home/home-page.component.html b/src/Squidex/app/shell/pages/home/home-page.component.html index 1623b53073..6d93c2dc41 100644 --- a/src/Squidex/app/shell/pages/home/home-page.component.html +++ b/src/Squidex/app/shell/pages/home/home-page.component.html @@ -1,7 +1,7 @@