mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
Use nicer urls, part2 (Fix #921)
This commit is contained in:
@@ -143,8 +143,8 @@ namespace BTCPayServer.Tests
|
|||||||
s.Driver.AssertNoError();
|
s.Driver.AssertNoError();
|
||||||
Assert.Contains("/login", s.Driver.Url);
|
Assert.Contains("/login", s.Driver.Url);
|
||||||
|
|
||||||
s.GoToUrl("/UIManage/Index");
|
s.GoToUrl("/account");
|
||||||
Assert.Contains("ReturnUrl=%2FUIManage%2FIndex", s.Driver.Url);
|
Assert.Contains("ReturnUrl=%2Faccount", s.Driver.Url);
|
||||||
|
|
||||||
// We should be redirected to login
|
// We should be redirected to login
|
||||||
//Same User Can Log Back In
|
//Same User Can Log Back In
|
||||||
@@ -153,7 +153,7 @@ namespace BTCPayServer.Tests
|
|||||||
s.Driver.FindElement(By.Id("LoginButton")).Click();
|
s.Driver.FindElement(By.Id("LoginButton")).Click();
|
||||||
|
|
||||||
// We should be redirected to invoice
|
// We should be redirected to invoice
|
||||||
Assert.EndsWith("/UIManage/Index", s.Driver.Url);
|
Assert.EndsWith("/account", s.Driver.Url);
|
||||||
|
|
||||||
// Should not be able to reach server settings
|
// Should not be able to reach server settings
|
||||||
s.GoToUrl("/server/users");
|
s.GoToUrl("/server/users");
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ namespace BTCPayServer.Controllers
|
|||||||
DescriptionHtml = true,
|
DescriptionHtml = true,
|
||||||
Description = $"Any application using the API key <strong>{key.Label ?? key.Id}<strong> will immediately lose access.",
|
Description = $"Any application using the API key <strong>{key.Label ?? key.Id}<strong> will immediately lose access.",
|
||||||
Action = "Delete",
|
Action = "Delete",
|
||||||
ActionUrl = Url.ActionLink(nameof(DeleteAPIKeyPost), values: new { id })
|
ActionName = nameof(DeleteAPIKeyPost)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
public partial class UIManageController
|
public partial class UIManageController
|
||||||
{
|
{
|
||||||
[HttpGet("notifications")]
|
[HttpGet("/notifications/settings")]
|
||||||
public async Task<IActionResult> NotificationSettings([FromServices] IEnumerable<INotificationHandler> notificationHandlers)
|
public async Task<IActionResult> NotificationSettings([FromServices] IEnumerable<INotificationHandler> notificationHandlers)
|
||||||
{
|
{
|
||||||
var user = await _userManager.GetUserAsync(User);
|
var user = await _userManager.GetUserAsync(User);
|
||||||
@@ -32,7 +32,7 @@ namespace BTCPayServer.Controllers
|
|||||||
return View(new NotificationSettingsViewModel() { DisabledNotifications = notifications });
|
return View(new NotificationSettingsViewModel() { DisabledNotifications = notifications });
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("notifications")]
|
[HttpPost("/notifications/settings")]
|
||||||
public async Task<IActionResult> NotificationSettings(NotificationSettingsViewModel vm, string command)
|
public async Task<IActionResult> NotificationSettings(NotificationSettingsViewModel vm, string command)
|
||||||
{
|
{
|
||||||
var user = await _userManager.GetUserAsync(User);
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
|
|
||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanViewProfile)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanViewProfile)]
|
||||||
[Route("[controller]/[action]")]
|
[Route("account/{action:lowercase=Index}")]
|
||||||
public partial class UIManageController : Controller
|
public partial class UIManageController : Controller
|
||||||
{
|
{
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
[BitpayAPIConstraint(false)]
|
[BitpayAPIConstraint(false)]
|
||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanViewNotificationsForUser)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanViewNotificationsForUser)]
|
||||||
[Route("[controller]/[action]")]
|
[Route("notifications/{action:lowercase=Index}")]
|
||||||
public class UINotificationsController : Controller
|
public class UINotificationsController : Controller
|
||||||
{
|
{
|
||||||
private readonly BTCPayServerEnvironment _env;
|
private readonly BTCPayServerEnvironment _env;
|
||||||
|
|||||||
23
BTCPayServer/Hosting/LowercaseTransformer.cs
Normal file
23
BTCPayServer/Hosting/LowercaseTransformer.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Hosting
|
||||||
|
{
|
||||||
|
public class LowercaseTransformer : IOutboundParameterTransformer
|
||||||
|
{
|
||||||
|
public static void Register(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddRouting(opts =>
|
||||||
|
{
|
||||||
|
opts.ConstraintMap["lowercase"] = typeof(LowercaseTransformer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public string TransformOutbound(object value)
|
||||||
|
{
|
||||||
|
if (value is not string str)
|
||||||
|
return null;
|
||||||
|
return str.ToLowerInvariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -141,6 +141,8 @@ namespace BTCPayServer.Hosting
|
|||||||
.AddRazorRuntimeCompilation()
|
.AddRazorRuntimeCompilation()
|
||||||
.AddPlugins(services, Configuration, LoggerFactory)
|
.AddPlugins(services, Configuration, LoggerFactory)
|
||||||
.AddControllersAsServices();
|
.AddControllersAsServices();
|
||||||
|
|
||||||
|
LowercaseTransformer.Register(services);
|
||||||
ValidateControllerNameTransformer.Register(services);
|
ValidateControllerNameTransformer.Register(services);
|
||||||
|
|
||||||
services.TryAddScoped<ContentSecurityPolicies>();
|
services.TryAddScoped<ContentSecurityPolicies>();
|
||||||
@@ -270,7 +272,7 @@ namespace BTCPayServer.Hosting
|
|||||||
PaymentRequestHub.Register(endpoints);
|
PaymentRequestHub.Register(endpoints);
|
||||||
endpoints.MapRazorPages();
|
endpoints.MapRazorPages();
|
||||||
endpoints.MapControllers();
|
endpoints.MapControllers();
|
||||||
endpoints.MapControllerRoute("default", "{controller:validate=UIHome}/{action=Index}/{id?}");
|
endpoints.MapControllerRoute("default", "{controller:validate=UIHome}/{action:lowercase=Index}/{id?}");
|
||||||
});
|
});
|
||||||
app.UsePlugins();
|
app.UsePlugins();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,26 +8,27 @@ namespace BTCPayServer.Models
|
|||||||
|
|
||||||
public ConfirmModel() { }
|
public ConfirmModel() { }
|
||||||
|
|
||||||
public ConfirmModel(string title, string desc, string action = null, string buttonClass = ButtonClassDefault, string actionUrl = null)
|
public ConfirmModel(string title, string desc, string action = null, string buttonClass = ButtonClassDefault, string actionName = null, string controllerName = null)
|
||||||
{
|
{
|
||||||
Title = title;
|
Title = title;
|
||||||
Description = desc;
|
Description = desc;
|
||||||
Action = action;
|
Action = action;
|
||||||
|
ActionName = actionName;
|
||||||
|
ControllerName = controllerName;
|
||||||
ButtonClass = buttonClass;
|
ButtonClass = buttonClass;
|
||||||
|
|
||||||
if (Description.Contains("<strong>", StringComparison.InvariantCultureIgnoreCase))
|
if (Description.Contains("<strong>", StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
DescriptionHtml = true;
|
DescriptionHtml = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionUrl = actionUrl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public bool DescriptionHtml { get; set; }
|
public bool DescriptionHtml { get; set; }
|
||||||
public string Action { get; set; }
|
public string Action { get; set; }
|
||||||
|
public string ActionName { get; set; }
|
||||||
|
public string ControllerName { get; set; }
|
||||||
public string ButtonClass { get; set; } = ButtonClassDefault;
|
public string ButtonClass { get; set; } = ButtonClassDefault;
|
||||||
public string ActionUrl { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
@model ConfirmModel
|
@model ConfirmModel
|
||||||
|
@inject LinkGenerator linkGenerator
|
||||||
|
@{
|
||||||
|
string actionUrl = null;
|
||||||
|
if (Model.ActionName is not null)
|
||||||
|
{
|
||||||
|
var controllerName = Model.ControllerName ?? ((Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)this.Url.ActionContext.ActionDescriptor).ControllerName;
|
||||||
|
actionUrl = linkGenerator.GetPathByAction(Model.ActionName, controllerName, pathBase: this.Context.Request.PathBase);
|
||||||
|
}
|
||||||
|
}
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
@@ -24,7 +32,7 @@
|
|||||||
|
|
||||||
@if (!string.IsNullOrEmpty(Model.Action))
|
@if (!string.IsNullOrEmpty(Model.Action))
|
||||||
{
|
{
|
||||||
<form id="ConfirmForm" method="post" action="@Model.ActionUrl" rel="noreferrer noopener">
|
<form id="ConfirmForm" method="post" action="@actionUrl" rel="noreferrer noopener">
|
||||||
<div class="modal-body pt-0" id="ConfirmText" hidden>
|
<div class="modal-body pt-0" id="ConfirmText" hidden>
|
||||||
<label for="ConfirmInput" class="form-label">Confirm the action by typing <strong id="ConfirmInputText"></strong>:</label>
|
<label for="ConfirmInput" class="form-label">Confirm the action by typing <strong id="ConfirmInputText"></strong>:</label>
|
||||||
<input id="ConfirmInput" class="form-control"/>
|
<input id="ConfirmInput" class="form-control"/>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
@model ConfirmModel
|
@model ConfirmModel
|
||||||
|
|
||||||
<div class="modal fade" id="ConfirmModal" tabindex="-1" aria-labelledby="ConfirmTitle" aria-hidden="true">
|
<div class="modal fade" id="ConfirmModal" tabindex="-1" aria-labelledby="ConfirmTitle" aria-hidden="true">
|
||||||
<partial name="ConfirmModal" model="Model" />
|
<partial name="ConfirmModal" model="Model" />
|
||||||
</div>
|
</div>
|
||||||
@@ -19,8 +18,8 @@
|
|||||||
const action = $target.dataset.action || ($target.nodeName === 'A'
|
const action = $target.dataset.action || ($target.nodeName === 'A'
|
||||||
? $target.getAttribute('href')
|
? $target.getAttribute('href')
|
||||||
: $target.form.getAttribute('action'))
|
: $target.form.getAttribute('action'))
|
||||||
|
|
||||||
if ($form) $form.setAttribute('action', action)
|
if ($form && !$form.hasAttribute('action')) $form.setAttribute('action', action)
|
||||||
if (title) $title.textContent = title
|
if (title) $title.textContent = title
|
||||||
if (description) $description.innerHTML = description
|
if (description) $description.innerHTML = description
|
||||||
if (confirm) $continue.textContent = confirm
|
if (confirm) $continue.textContent = confirm
|
||||||
|
|||||||
@@ -37,12 +37,12 @@
|
|||||||
<button type="submit" id="save" class="btn btn-primary">Save</button>
|
<button type="submit" id="save" class="btn btn-primary">Save</button>
|
||||||
<h4 class="mt-5 mb-3">Delete Account</h4>
|
<h4 class="mt-5 mb-3">Delete Account</h4>
|
||||||
<div id="danger-zone">
|
<div id="danger-zone">
|
||||||
<a id="delete-user" class="btn btn-outline-danger mb-5" data-confirm-input="DELETE" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-action="DeleteUserPost" data-description="This action will also delete all stores, invoices, apps and data associated with the user.">Delete Account</a>
|
<a id="delete-user" class="btn btn-outline-danger mb-5" data-confirm-input="DELETE" data-bs-toggle="modal" data-bs-target="#ConfirmModal" asp-action="DeleteUserPost" data-description="This action will also delete all stores, invoices, apps and data associated with the user.">Delete Account</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<partial name="_Confirm"
|
<partial name="_Confirm"
|
||||||
model="@(new ConfirmModel("Delete user", "The user will be permanently deleted. This action will also delete all stores, invoices, apps and data associated with your user.", "Delete", actionUrl:"DeleteUserPost"))"/>
|
model="@(new ConfirmModel("Delete user", "The user will be permanently deleted. This action will also delete all stores, invoices, apps and data associated with your user.", "Delete", actionName: nameof(BTCPayServer.Controllers.UIManageController.DeleteUserPost)))"/>
|
||||||
|
|
||||||
@section PageFootContent {
|
@section PageFootContent {
|
||||||
<partial name="_ValidationScriptsPartial"/>
|
<partial name="_ValidationScriptsPartial"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user