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