diff --git a/build/Version.props b/build/Version.props index f281ec3d80..687396873e 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,7 +3,7 @@ - 6.1.3 + 6.1.4 5.0.0 10.0.0 7.0.0 diff --git a/build/package/winget/manifest/Tgstation.Server.installer.yaml b/build/package/winget/manifest/Tgstation.Server.installer.yaml index 5678bf542a..5d0ed20324 100644 --- a/build/package/winget/manifest/Tgstation.Server.installer.yaml +++ b/build/package/winget/manifest/Tgstation.Server.installer.yaml @@ -22,9 +22,6 @@ Installers: AppsAndFeaturesEntries: - DisplayName: tgstation-server Publisher: /tg/station 13 - Dependencies: - PackageDependencies: - - PackageIdentifier: Microsoft.DotNet.HostingBundle.8 ReleaseDate: 2023-06-24 # Do not change. Set before publish by push_manifest.ps1 ManifestType: installer ManifestVersion: 1.5.0 diff --git a/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs b/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs index 7e450874f5..ec763dd955 100644 --- a/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs +++ b/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs @@ -30,6 +30,11 @@ namespace Tgstation.Server.Host.Controllers /// public const string ControlPanelRoute = "/app"; + /// + /// The route to the control panel channel .json. + /// + public const string ChannelJsonRoute = "channel.json"; + /// /// Header for forcing channel.json to be fetched. /// @@ -70,7 +75,7 @@ namespace Tgstation.Server.Host.Controllers /// Returns the . /// /// A with the . - [Route("channel.json")] + [Route(ChannelJsonRoute)] [HttpGet] public IActionResult GetChannelJson() { diff --git a/src/Tgstation.Server.Host/Controllers/RootController.cs b/src/Tgstation.Server.Host/Controllers/RootController.cs index 32a7987857..df363970bb 100644 --- a/src/Tgstation.Server.Host/Controllers/RootController.cs +++ b/src/Tgstation.Server.Host/Controllers/RootController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq.Expressions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Hosting; @@ -61,6 +62,27 @@ namespace Tgstation.Server.Host.Controllers /// readonly ControlPanelConfiguration controlPanelConfiguration; + /// + /// Gets a giving the and action names for a given . + /// + /// An expression invoking the action on . + /// A containing the controller and action names. + static Tuple GetControlPanelActionLink(Expression> actionExpression) + { + var memberSelectorExpression = (MethodCallExpression)actionExpression.Body; + var method = memberSelectorExpression.Method; + + var controllerName = typeof(ControlPanelController).Name; + + const string ControllerSuffix = nameof(Controller); + if (controllerName.EndsWith(ControllerSuffix, StringComparison.Ordinal)) + controllerName = controllerName.Substring(0, controllerName.Length - ControllerSuffix.Length); + + var actionName = method.Name; + + return Tuple.Create(controllerName, actionName); + } + /// /// Initializes a new instance of the class. /// @@ -136,5 +158,19 @@ namespace Tgstation.Server.Host.Controllers return (IActionResult?)this.TryServeFile(hostEnvironment, logger, $"{logoFileName}.svg") ?? NotFound(); } + + /// + /// Workaround for the webpanel always expecting a trailing slash. + /// + /// A to the . + [HttpGet(ControlPanelController.ChannelJsonRoute)] + public RedirectToActionResult WebpanelChannelRedirect() + { + var actionTuple = GetControlPanelActionLink(controller => controller.GetChannelJson()); + + return RedirectToActionPermanent( + actionTuple.Item2, + actionTuple.Item1); + } } } diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 702ab054da..d533a167a0 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -503,6 +503,10 @@ namespace Tgstation.Server.Host.Core if (generalConfiguration.HostApiDocumentation) { + var siteDocPath = Routes.ApiRoot + $"doc/{SwaggerConfiguration.DocumentName}.json"; + if (!String.IsNullOrWhiteSpace(controlPanelConfiguration.PublicPath)) + siteDocPath = controlPanelConfiguration.PublicPath.TrimEnd('/') + siteDocPath; + applicationBuilder.UseSwagger(options => { options.RouteTemplate = Routes.ApiRoot + "doc/{documentName}.{json|yaml}"; @@ -510,7 +514,7 @@ namespace Tgstation.Server.Host.Core applicationBuilder.UseSwaggerUI(options => { options.RoutePrefix = SwaggerConfiguration.DocumentationSiteRouteExtension; - options.SwaggerEndpoint(Routes.ApiRoot + $"doc/{SwaggerConfiguration.DocumentName}.json", "TGS API"); + options.SwaggerEndpoint(siteDocPath, "TGS API"); }); logger.LogTrace("Swagger API generation enabled"); } @@ -524,6 +528,7 @@ namespace Tgstation.Server.Host.Core RequestPath = ControlPanelController.ControlPanelRoute, EnableDefaultFiles = true, EnableDirectoryBrowsing = false, + RedirectToAppendTrailingSlash = false, }); } else