mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-01-18 21:32:27 +01:00
Remove redundant payment methods from store settings (#3323)
* Add enabled toggle to wallet settings view * Add enabled toggle to Lightning settings view * Remove redundant payment methods from store settings * Rename Payment Methods to Payments * Adapt tests * Fix invoice state toggle on details page * Add spacing on Lightning sett8ings page
This commit is contained in:
parent
51c486c15a
commit
c419ad68bb
@ -70,42 +70,42 @@ namespace BTCPayServer.Tests
|
||||
|
||||
Assert.Equal(3, invoice.CryptoInfo.Length);
|
||||
|
||||
// Setup Lightning
|
||||
var controller = user.GetController<UIStoresController>();
|
||||
var lightningVm = (LightningNodeViewModel)Assert.IsType<ViewResult>(await controller.SetupLightningNode(user.StoreId, cryptoCode)).Model;
|
||||
Assert.True(lightningVm.Enabled);
|
||||
var response = await controller.SetLightningNodeEnabled(user.StoreId, cryptoCode, false);
|
||||
Assert.IsType<RedirectToActionResult>(response);
|
||||
|
||||
// Get enabled state from overview action
|
||||
PaymentMethodsViewModel paymentMethodsModel;
|
||||
response = controller.PaymentMethods();
|
||||
paymentMethodsModel = (PaymentMethodsViewModel)Assert.IsType<ViewResult>(response).Model;
|
||||
var lnNode = paymentMethodsModel.LightningNodes.Find(node => node.CryptoCode == cryptoCode);
|
||||
Assert.NotNull(lnNode);
|
||||
Assert.False(lnNode.Enabled);
|
||||
// Get enabled state from settings
|
||||
LightningSettingsViewModel lnSettingsModel;
|
||||
response = controller.LightningSettings(user.StoreId, cryptoCode).GetAwaiter().GetResult();
|
||||
lnSettingsModel = (LightningSettingsViewModel)Assert.IsType<ViewResult>(response).Model;
|
||||
Assert.NotNull(lnSettingsModel?.ConnectionString);
|
||||
Assert.False(lnSettingsModel.Enabled);
|
||||
|
||||
// Setup wallet
|
||||
WalletSetupViewModel setupVm;
|
||||
var storeId = user.StoreId;
|
||||
response = await controller.GenerateWallet(storeId, cryptoCode, WalletSetupMethod.GenerateOptions, new WalletSetupRequest());
|
||||
Assert.IsType<ViewResult>(response);
|
||||
|
||||
// Get enabled state from overview action
|
||||
response = controller.PaymentMethods();
|
||||
paymentMethodsModel = (PaymentMethodsViewModel)Assert.IsType<ViewResult>(response).Model;
|
||||
var derivationScheme = paymentMethodsModel.DerivationSchemes.Find(scheme => scheme.Crypto == cryptoCode);
|
||||
Assert.NotNull(derivationScheme);
|
||||
Assert.True(derivationScheme.Enabled);
|
||||
// Get enabled state from settings
|
||||
response = controller.WalletSettings(user.StoreId, cryptoCode).GetAwaiter().GetResult();
|
||||
var onchainSettingsModel = (WalletSettingsViewModel)Assert.IsType<ViewResult>(response).Model;
|
||||
Assert.NotNull(onchainSettingsModel?.DerivationScheme);
|
||||
Assert.True(onchainSettingsModel.Enabled);
|
||||
|
||||
// Disable wallet
|
||||
response = controller.SetWalletEnabled(storeId, cryptoCode, false).GetAwaiter().GetResult();
|
||||
onchainSettingsModel.Enabled = false;
|
||||
response = controller.UpdateWalletSettings(onchainSettingsModel).GetAwaiter().GetResult();
|
||||
Assert.IsType<RedirectToActionResult>(response);
|
||||
response = controller.PaymentMethods();
|
||||
paymentMethodsModel = (PaymentMethodsViewModel)Assert.IsType<ViewResult>(response).Model;
|
||||
derivationScheme = paymentMethodsModel.DerivationSchemes.Find(scheme => scheme.Crypto == cryptoCode);
|
||||
Assert.NotNull(derivationScheme);
|
||||
Assert.False(derivationScheme.Enabled);
|
||||
response = controller.WalletSettings(user.StoreId, cryptoCode).GetAwaiter().GetResult();
|
||||
onchainSettingsModel = (WalletSettingsViewModel)Assert.IsType<ViewResult>(response).Model;
|
||||
Assert.NotNull(onchainSettingsModel?.DerivationScheme);
|
||||
Assert.False(onchainSettingsModel.Enabled);
|
||||
|
||||
var oldScheme = derivationScheme.Value;
|
||||
var oldScheme = onchainSettingsModel.DerivationScheme;
|
||||
|
||||
invoice = await user.BitPay.CreateInvoiceAsync(
|
||||
new Invoice
|
||||
@ -430,7 +430,7 @@ namespace BTCPayServer.Tests
|
||||
s.GoToInvoiceCheckout(invoiceId);
|
||||
s.Driver.FindElement(By.ClassName("payment__currencies_noborder"));
|
||||
s.GoToHome();
|
||||
s.GoToStore(StoreNavPages.PaymentMethods);
|
||||
s.GoToStore(StoreNavPages.Payment);
|
||||
s.AddDerivationScheme("LTC");
|
||||
s.AddLightningNode(LightningConnectionType.CLightning);
|
||||
//there should be three now
|
||||
|
@ -204,7 +204,7 @@ namespace BTCPayServer.Tests
|
||||
s.GoToRegister();
|
||||
s.RegisterNewUser();
|
||||
s.CreateNewStore();
|
||||
s.GoToStore(StoreNavPages.PaymentMethods);
|
||||
s.GoToStore(StoreNavPages.Payment);
|
||||
s.AddDerivationScheme();
|
||||
var invoiceId = s.CreateInvoice(0.001m, "BTC", "a@x.com");
|
||||
var invoice = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);
|
||||
|
@ -289,7 +289,8 @@ namespace BTCPayServer.Tests
|
||||
.GetAttribute("href");
|
||||
Assert.Contains($"{PayjoinClient.BIP21EndpointKey}=", bip21);
|
||||
|
||||
s.GoToWalletSettings(receiver.storeId, cryptoCode);
|
||||
s.GoToStore(receiver.storeId);
|
||||
s.GoToWalletSettings(cryptoCode);
|
||||
Assert.True(s.Driver.FindElement(By.Id("PayJoinEnabled")).Selected);
|
||||
|
||||
var sender = s.CreateNewStore();
|
||||
|
@ -3,6 +3,7 @@ using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.BIP78.Sender;
|
||||
@ -155,7 +156,7 @@ namespace BTCPayServer.Tests
|
||||
Driver.FindElement(By.Id("StoreNav-StoreSettings")).Click();
|
||||
Driver.FindElement(By.Id($"SectionNav-{StoreNavPages.General.ToString()}")).Click();
|
||||
var storeId = Driver.WaitForElement(By.Id("Id")).GetAttribute("value");
|
||||
Driver.FindElement(By.Id($"SectionNav-{StoreNavPages.PaymentMethods.ToString()}")).Click();
|
||||
Driver.FindElement(By.Id($"SectionNav-{StoreNavPages.Payment.ToString()}")).Click();
|
||||
if (keepId)
|
||||
StoreId = storeId;
|
||||
return (name, storeId);
|
||||
@ -164,7 +165,7 @@ namespace BTCPayServer.Tests
|
||||
public Mnemonic GenerateWallet(string cryptoCode = "BTC", string seed = "", bool importkeys = false, bool privkeys = false, ScriptPubKeyType format = ScriptPubKeyType.Segwit)
|
||||
{
|
||||
var isImport = !string.IsNullOrEmpty(seed);
|
||||
Driver.FindElement(By.Id($"Modify{cryptoCode}")).Click();
|
||||
GoToWalletSettings(cryptoCode);
|
||||
|
||||
// Replace previous wallet case
|
||||
if (Driver.PageSource.Contains("id=\"ChangeWalletLink\""))
|
||||
@ -228,10 +229,7 @@ namespace BTCPayServer.Tests
|
||||
/// <param name="derivationScheme"></param>
|
||||
public void AddDerivationScheme(string cryptoCode = "BTC", string derivationScheme = "xpub661MyMwAqRbcGABgHMUXDzPzH1tU7eZaAaJQXhDXsSxsqyQzQeU6kznNfSuAyqAK9UaWSaZaMFdNiY5BCF4zBPAzSnwfUAwUhwttuAKwfRX-[legacy]")
|
||||
{
|
||||
if (Driver.PageSource.Contains($"id=\"Modify{cryptoCode}\""))
|
||||
{
|
||||
Driver.FindElement(By.Id($"Modify{cryptoCode}")).Click();
|
||||
}
|
||||
GoToWalletSettings(cryptoCode);
|
||||
|
||||
Driver.FindElement(By.Id("ImportWalletOptionsLink")).Click();
|
||||
Driver.FindElement(By.Id("ImportXpubLink")).Click();
|
||||
@ -254,11 +252,7 @@ namespace BTCPayServer.Tests
|
||||
public void AddLightningNode(string cryptoCode = null, LightningConnectionType? connectionType = null, bool test = true)
|
||||
{
|
||||
cryptoCode ??= "BTC";
|
||||
if (Driver.PageSource.Contains($"id=\"Modify-Lightning{cryptoCode}\""))
|
||||
{
|
||||
Driver.FindElement(By.Id($"Modify-Lightning{cryptoCode}")).Click();
|
||||
}
|
||||
|
||||
Driver.FindElement(By.Id($"StoreNav-Lightning{cryptoCode}")).Click();
|
||||
if (Driver.PageSource.Contains("id=\"SetupLightningNodeLink\""))
|
||||
{
|
||||
Driver.FindElement(By.Id("SetupLightningNodeLink")).Click();
|
||||
@ -392,22 +386,18 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
}
|
||||
|
||||
public void GoToWalletSettings(string storeId, string cryptoCode = "BTC")
|
||||
public void GoToWalletSettings(string cryptoCode = "BTC")
|
||||
{
|
||||
try
|
||||
Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
||||
if (Driver.PageSource.Contains("id=\"SectionNav-Settings\""))
|
||||
{
|
||||
GoToStore(storeId, StoreNavPages.PaymentMethods);
|
||||
Driver.FindElement(By.Id($"Modify{cryptoCode}")).Click();
|
||||
}
|
||||
catch (NoSuchElementException)
|
||||
{
|
||||
GoToWallet(new WalletId(storeId, cryptoCode), WalletsNavPages.Settings);
|
||||
Driver.FindElement(By.Id("SectionNav-Settings")).Click();
|
||||
}
|
||||
}
|
||||
|
||||
public void GoToLightningSettings(string cryptoCode = "BTC")
|
||||
{
|
||||
GoToStore(StoreNavPages.PaymentMethods);
|
||||
GoToStore(StoreNavPages.Payment);
|
||||
Driver.FindElement(By.Id($"StoreNav-Lightning{cryptoCode}")).Click();
|
||||
// if Lightning is already set up we need to navigate to the settings
|
||||
if (Driver.PageSource.Contains("id=\"SectionNav-LightningSettings\""))
|
||||
|
@ -335,6 +335,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
Assert.DoesNotContain("/server/services/dynamic-dns/pouet.hello.com/delete", s.Driver.PageSource);
|
||||
}
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
public async Task CanCreateInvoiceInUI()
|
||||
{
|
||||
@ -402,18 +403,9 @@ namespace BTCPayServer.Tests
|
||||
var alice = s.RegisterNewUser(true);
|
||||
(string storeName, string storeId) = s.CreateNewStore();
|
||||
var storeUrl = $"/stores/{storeId}";
|
||||
var onchainHint = "Set up your wallet to receive payments at your store.";
|
||||
var offchainHint = "A connection to a Lightning node is required to receive Lightning payments.";
|
||||
|
||||
// verify that hints are displayed on the store page
|
||||
Assert.True(s.Driver.PageSource.Contains(onchainHint), "Wallet hint not present");
|
||||
Assert.True(s.Driver.PageSource.Contains(offchainHint), "Lightning hint not present");
|
||||
|
||||
s.GoToStore(StoreNavPages.PaymentMethods);
|
||||
s.GoToStore(StoreNavPages.Payment);
|
||||
Assert.Contains(storeName, s.Driver.PageSource);
|
||||
Assert.True(s.Driver.PageSource.Contains(onchainHint), "Wallet hint should be present at this point");
|
||||
Assert.True(s.Driver.PageSource.Contains(offchainHint),
|
||||
"Lightning hint should be present at this point");
|
||||
|
||||
// verify steps for wallet setup are displayed correctly
|
||||
s.GoToStore(StoreNavPages.Dashboard);
|
||||
@ -423,11 +415,8 @@ namespace BTCPayServer.Tests
|
||||
|
||||
// setup onchain wallet
|
||||
s.Driver.FindElement(By.Id("SetupGuide-Wallet")).Click();
|
||||
Thread.Sleep(10000);
|
||||
s.AddDerivationScheme();
|
||||
s.Driver.AssertNoError();
|
||||
Assert.False(s.Driver.PageSource.Contains(onchainHint),
|
||||
"Wallet hint not dismissed on derivation scheme add");
|
||||
|
||||
s.GoToStore(StoreNavPages.Dashboard);
|
||||
Assert.True(s.Driver.FindElement(By.Id("SetupGuide-WalletDone")).Displayed);
|
||||
@ -438,8 +427,6 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.AssertNoError();
|
||||
var successAlert = s.FindAlertMessage();
|
||||
Assert.Contains("BTC Lightning node updated.", successAlert.Text);
|
||||
Assert.False(s.Driver.PageSource.Contains(offchainHint),
|
||||
"Lightning hint should be dismissed at this point");
|
||||
|
||||
s.ClickOnAllSectionLinks();
|
||||
|
||||
@ -541,7 +528,7 @@ namespace BTCPayServer.Tests
|
||||
s.CreateNewStore();
|
||||
s.AddDerivationScheme();
|
||||
|
||||
s.Driver.FindElement(By.Id("SectionNav-Tokens")).Click();
|
||||
s.GoToStore(StoreNavPages.Tokens);
|
||||
s.Driver.FindElement(By.Id("CreateNewToken")).Click();
|
||||
s.Driver.FindElement(By.Id("RequestPairing")).Click();
|
||||
var pairingCode = AssertUrlHasPairingCode(s);
|
||||
@ -794,7 +781,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Contains(server.ServerUri.AbsoluteUri, s.Driver.PageSource);
|
||||
|
||||
TestLogs.LogInformation("Let's see if we can generate an event");
|
||||
s.GoToStore(StoreNavPages.PaymentMethods);
|
||||
s.GoToStore(StoreNavPages.Payment);
|
||||
s.AddDerivationScheme();
|
||||
s.CreateInvoice();
|
||||
var request = await server.GetNextRequest();
|
||||
@ -859,9 +846,9 @@ namespace BTCPayServer.Tests
|
||||
foreach (var isHotwallet in new[] { false, true })
|
||||
{
|
||||
var cryptoCode = "BTC";
|
||||
(_, string storeId) = s.CreateNewStore();
|
||||
s.CreateNewStore();
|
||||
s.GenerateWallet(cryptoCode, "melody lizard phrase voice unique car opinion merge degree evil swift cargo", privkeys: isHotwallet);
|
||||
s.GoToWalletSettings(storeId, cryptoCode);
|
||||
s.GoToWalletSettings(cryptoCode);
|
||||
if (isHotwallet)
|
||||
Assert.Contains("View seed", s.Driver.PageSource);
|
||||
else
|
||||
@ -916,10 +903,8 @@ namespace BTCPayServer.Tests
|
||||
receiveAddr = s.Driver.FindElement(By.Id("address")).GetAttribute("value");
|
||||
|
||||
//change the wallet and ensure old address is not there and generating a new one does not result in the prev one
|
||||
s.GoToStore(storeId, StoreNavPages.PaymentMethods);
|
||||
s.GenerateWallet(cryptoCode, "", true);
|
||||
s.Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
||||
s.Driver.FindElement(By.Id("SectionNav-Receive")).Click();
|
||||
s.GoToWallet(null, WalletsNavPages.Receive);
|
||||
s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
|
||||
|
||||
Assert.NotEqual(receiveAddr, s.Driver.FindElement(By.Id("address")).GetAttribute("value"));
|
||||
@ -932,7 +917,7 @@ namespace BTCPayServer.Tests
|
||||
var result =
|
||||
await s.Server.ExplorerNode.GetAddressInfoAsync(BitcoinAddress.Create(address, Network.RegTest));
|
||||
Assert.True(result.IsWatchOnly);
|
||||
s.GoToStore(storeId, StoreNavPages.PaymentMethods);
|
||||
s.GoToStore(storeId, StoreNavPages.Payment);
|
||||
var mnemonic = s.GenerateWallet(cryptoCode, "", true, true);
|
||||
|
||||
//lets import and save private keys
|
||||
@ -953,7 +938,7 @@ namespace BTCPayServer.Tests
|
||||
s.ClickOnAllSectionLinks();
|
||||
|
||||
// Make sure wallet info is correct
|
||||
s.GoToWalletSettings(storeId, cryptoCode);
|
||||
s.GoToWalletSettings(cryptoCode);
|
||||
Assert.Contains(mnemonic.DeriveExtKey().GetPublicKey().GetHDFingerPrint().ToString(),
|
||||
s.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).GetAttribute("value"));
|
||||
Assert.Contains("m/84'/1'/0'",
|
||||
@ -1011,7 +996,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal(parsedBip21.Address.ToString(),
|
||||
s.Driver.FindElement(By.Id("Outputs_0__DestinationAddress")).GetAttribute("value"));
|
||||
|
||||
s.GoToWalletSettings(storeId, cryptoCode);
|
||||
s.GoToWalletSettings(cryptoCode);
|
||||
var settingsUrl = s.Driver.Url;
|
||||
s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click();
|
||||
s.Driver.FindElement(By.Id("ViewSeed")).Click();
|
||||
@ -1035,12 +1020,12 @@ namespace BTCPayServer.Tests
|
||||
using var s = CreateSeleniumTester();
|
||||
await s.StartAsync();
|
||||
s.RegisterNewUser(true);
|
||||
(_, string storeId) = s.CreateNewStore();
|
||||
s.CreateNewStore();
|
||||
const string cryptoCode = "BTC";
|
||||
var mnemonic = s.GenerateWallet(cryptoCode, "click chunk owner kingdom faint steak safe evidence bicycle repeat bulb wheel");
|
||||
|
||||
// Make sure wallet info is correct
|
||||
s.GoToWalletSettings(storeId, cryptoCode);
|
||||
s.GoToWalletSettings(cryptoCode);
|
||||
Assert.Contains(mnemonic.DeriveExtKey().GetPublicKey().GetHDFingerPrint().ToString(),
|
||||
s.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).GetAttribute("value"));
|
||||
Assert.Contains("m/84'/1'/0'",
|
||||
@ -1305,7 +1290,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
s.RegisterNewUser(true);
|
||||
s.CreateNewStore();
|
||||
s.GoToStore(StoreNavPages.PaymentMethods);
|
||||
s.GoToStore(StoreNavPages.Payment);
|
||||
s.AddLightningNode(LightningConnectionType.CLightning, false);
|
||||
s.GoToLightningSettings();
|
||||
s.Driver.SetCheckbox(By.Id("LNURLEnabled"), true);
|
||||
@ -1348,7 +1333,7 @@ namespace BTCPayServer.Tests
|
||||
s.RegisterNewUser(true);
|
||||
(_, string storeId) = s.CreateNewStore();
|
||||
var network = s.Server.NetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode).NBitcoinNetwork;
|
||||
s.GoToStore(StoreNavPages.PaymentMethods);
|
||||
s.GoToStore(StoreNavPages.Payment);
|
||||
s.AddLightningNode(LightningConnectionType.CLightning, false);
|
||||
s.GoToLightningSettings();
|
||||
// LNURL is false by default
|
||||
@ -1561,7 +1546,7 @@ namespace BTCPayServer.Tests
|
||||
//ensure ln address is not available as Lightning is not enable
|
||||
s.Driver.AssertElementNotFound(By.Id("StoreNav-LightningAddress"));
|
||||
|
||||
s.GoToStore(s.StoreId, StoreNavPages.PaymentMethods);
|
||||
s.GoToStore(s.StoreId, StoreNavPages.Payment);
|
||||
s.AddLightningNode(LightningConnectionType.LndREST, false);
|
||||
//ensure ln address is not available as lnurl is not configured
|
||||
s.Driver.AssertElementNotFound(By.Id("StoreNav-LightningAddress"));
|
||||
|
@ -133,13 +133,13 @@ namespace BTCPayServer.Tests
|
||||
});
|
||||
}
|
||||
|
||||
public async Task ModifyPayment(Action<PaymentMethodsViewModel> modify)
|
||||
public async Task ModifyPayment(Action<PaymentViewModel> modify)
|
||||
{
|
||||
var storeController = GetController<UIStoresController>();
|
||||
var response = storeController.PaymentMethods();
|
||||
PaymentMethodsViewModel paymentMethods = (PaymentMethodsViewModel)((ViewResult)response).Model;
|
||||
modify(paymentMethods);
|
||||
await storeController.PaymentMethods(paymentMethods);
|
||||
var response = storeController.Payment();
|
||||
PaymentViewModel payment = (PaymentViewModel)((ViewResult)response).Model;
|
||||
modify(payment);
|
||||
await storeController.Payment(payment);
|
||||
}
|
||||
|
||||
public async Task ModifyWalletSettings(Action<WalletSettingsViewModel> modify)
|
||||
|
@ -275,11 +275,11 @@ namespace BTCPayServer.Tests
|
||||
|
||||
// Set tolerance to 50%
|
||||
var stores = user.GetController<UIStoresController>();
|
||||
var response = stores.PaymentMethods();
|
||||
var vm = Assert.IsType<PaymentMethodsViewModel>(Assert.IsType<ViewResult>(response).Model);
|
||||
var response = stores.Payment();
|
||||
var vm = Assert.IsType<PaymentViewModel>(Assert.IsType<ViewResult>(response).Model);
|
||||
Assert.Equal(0.0, vm.PaymentTolerance);
|
||||
vm.PaymentTolerance = 50.0;
|
||||
Assert.IsType<RedirectToActionResult>(stores.PaymentMethods(vm).Result);
|
||||
Assert.IsType<RedirectToActionResult>(stores.Payment(vm).Result);
|
||||
|
||||
var invoice = user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
@ -417,7 +417,7 @@ namespace BTCPayServer.Tests
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess(true);
|
||||
var storeController = user.GetController<UIStoresController>();
|
||||
var storeResponse = storeController.PaymentMethods();
|
||||
var storeResponse = storeController.Payment();
|
||||
Assert.IsType<ViewResult>(storeResponse);
|
||||
Assert.IsType<ViewResult>(await storeController.SetupLightningNode(user.StoreId, "BTC"));
|
||||
|
||||
@ -441,11 +441,11 @@ namespace BTCPayServer.Tests
|
||||
new LightningNodeViewModel { ConnectionString = tester.MerchantCharge.Client.Uri.AbsoluteUri },
|
||||
"save", "BTC").GetAwaiter().GetResult());
|
||||
|
||||
storeResponse = storeController.PaymentMethods();
|
||||
storeResponse = storeController.LightningSettings(user.StoreId, "BTC").GetAwaiter().GetResult();
|
||||
var storeVm =
|
||||
Assert.IsType<PaymentMethodsViewModel>(Assert
|
||||
Assert.IsType<LightningSettingsViewModel>(Assert
|
||||
.IsType<ViewResult>(storeResponse).Model);
|
||||
Assert.Single(storeVm.LightningNodes.Where(l => !string.IsNullOrEmpty(l.Address)));
|
||||
Assert.NotEmpty(storeVm.ConnectionString);
|
||||
}
|
||||
|
||||
[Fact(Timeout = 60 * 2 * 1000)]
|
||||
|
@ -35,7 +35,7 @@
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a asp-area="" asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@Model.Store.Id" class="nav-link js-scroll-trigger @ViewData.IsActivePage(StoreNavPages.PaymentMethods) @ViewData.IsActivePage(StoreNavPages.Rates) @ViewData.IsActivePage(StoreNavPages.CheckoutAppearance) @ViewData.IsActivePage(StoreNavPages.General) @ViewData.IsActivePage(StoreNavPages.Tokens) @ViewData.IsActivePage(StoreNavPages.Users) @ViewData.IsActivePage(StoreNavPages.Integrations) @ViewData.IsActivePage(StoreNavPages.Webhooks)" id="StoreNav-StoreSettings">
|
||||
<a asp-area="" asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@Model.Store.Id" class="nav-link js-scroll-trigger @ViewData.IsActivePage(StoreNavPages.Payment) @ViewData.IsActivePage(StoreNavPages.Rates) @ViewData.IsActivePage(StoreNavPages.CheckoutAppearance) @ViewData.IsActivePage(StoreNavPages.General) @ViewData.IsActivePage(StoreNavPages.Tokens) @ViewData.IsActivePage(StoreNavPages.Users) @ViewData.IsActivePage(StoreNavPages.Integrations) @ViewData.IsActivePage(StoreNavPages.Webhooks)" id="StoreNav-StoreSettings">
|
||||
<vc:icon symbol="settings"/>
|
||||
<span>Settings</span>
|
||||
</a>
|
||||
@ -65,7 +65,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<a asp-area="" asp-controller="UIStores" asp-action="SetupWallet" asp-route-cryptoCode="@scheme.Crypto" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.IsActivePage(StoreNavPages.OnchainSettings)" id="@($"StoreNav-Modify{scheme.Crypto}")">
|
||||
<a asp-area="" asp-controller="UIStores" asp-action="SetupWallet" asp-route-cryptoCode="@scheme.Crypto" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.IsActivePage(StoreNavPages.OnchainSettings)" id="@($"StoreNav-Wallet{scheme.Crypto}")">
|
||||
<span class="me-2 btcpay-status btcpay-status--@(scheme.Enabled ? "enabled" : "disabled")"></span>
|
||||
<span>@(Model.AltcoinsBuild ? $"{scheme.Crypto} " : "")Wallet</span>
|
||||
</a>
|
||||
|
@ -101,7 +101,7 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
StoreId = store.Id,
|
||||
StoreName = store.StoreName,
|
||||
StoreLink = Url.Action(nameof(UIStoresController.PaymentMethods), "UIStores", new { storeId = store.Id }),
|
||||
StoreLink = Url.Action(nameof(UIStoresController.Payment), "UIStores", new { storeId = store.Id }),
|
||||
PaymentRequestLink = Url.Action(nameof(UIPaymentRequestController.ViewPaymentRequest), "UIPaymentRequest", new { payReqId = invoice.Metadata.PaymentRequestId }),
|
||||
Id = invoice.Id,
|
||||
State = invoiceState,
|
||||
@ -898,7 +898,7 @@ namespace BTCPayServer.Controllers
|
||||
TempData.SetStatusMessageModel(new StatusMessageModel
|
||||
{
|
||||
Severity = StatusMessageModel.StatusSeverity.Error,
|
||||
Html = $"To create an invoice, you need to <a href='{Url.Action(nameof(UIStoresController.PaymentMethods), "UIStores", new { storeId = store.Id })}' class='alert-link'>set up a payment method</a> first",
|
||||
Html = $"To create an invoice, you need to <a href='{Url.Action(nameof(UIStoresController.Payment), "UIStores", new { storeId = store.Id })}' class='alert-link'>set up a payment method</a> first",
|
||||
AllowDismiss = false
|
||||
});
|
||||
return View(model);
|
||||
|
@ -463,7 +463,7 @@ namespace BTCPayServer
|
||||
Message = "LNURL is required for lightning addresses but has not yet been enabled.",
|
||||
Severity = StatusMessageModel.StatusSeverity.Error
|
||||
});
|
||||
return RedirectToAction("PaymentMethods", "UIStores", new { storeId });
|
||||
return RedirectToAction("Payment", "UIStores", new { storeId });
|
||||
}
|
||||
var lightningAddressSettings = await _settingsRepository.GetSettingAsync<LightningAddressSettings>() ??
|
||||
new LightningAddressSettings();
|
||||
|
@ -74,7 +74,7 @@ namespace BTCPayServer.Controllers
|
||||
Message = "You must enable at least one payment method before creating a pull payment.",
|
||||
Severity = StatusMessageModel.StatusSeverity.Error
|
||||
});
|
||||
return RedirectToAction("PaymentMethods", "UIStores", new { storeId });
|
||||
return RedirectToAction("Payment", "UIStores", new { storeId });
|
||||
}
|
||||
return View(new NewPullPaymentModel
|
||||
{
|
||||
@ -439,7 +439,7 @@ namespace BTCPayServer.Controllers
|
||||
Message = "You must enable at least one payment method before creating a payout.",
|
||||
Severity = StatusMessageModel.StatusSeverity.Error
|
||||
});
|
||||
return RedirectToAction("PaymentMethods", "UIStores", new { storeId });
|
||||
return RedirectToAction("Payment", "UIStores", new { storeId });
|
||||
}
|
||||
|
||||
var vm = this.ParseListQuery(new PayoutsModel
|
||||
|
@ -167,7 +167,7 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
await _Repo.UpdateStore(store);
|
||||
TempData[WellKnownTempData.SuccessMessage] = $"{network.CryptoCode} Lightning node updated.";
|
||||
return RedirectToAction(nameof(PaymentMethods), new { storeId });
|
||||
return RedirectToAction(nameof(LightningSettings), new { storeId, cryptoCode });
|
||||
|
||||
case "test":
|
||||
var handler = _ServiceProvider.GetRequiredService<LightningLikePaymentHandler>();
|
||||
@ -201,10 +201,13 @@ namespace BTCPayServer.Controllers
|
||||
return NotFound();
|
||||
|
||||
var storeBlob = store.GetStoreBlob();
|
||||
var excludeFilters = storeBlob.GetExcludedPaymentMethods();
|
||||
var lightning = GetExistingLightningSupportedPaymentMethod(cryptoCode, store);
|
||||
var vm = new LightningSettingsViewModel
|
||||
{
|
||||
CryptoCode = cryptoCode,
|
||||
StoreId = storeId,
|
||||
Enabled = !excludeFilters.Match(lightning.PaymentId),
|
||||
LightningDescriptionTemplate = storeBlob.LightningDescriptionTemplate,
|
||||
LightningAmountInSatoshi = storeBlob.LightningAmountInSatoshi,
|
||||
LightningPrivateRouteHints = storeBlob.LightningPrivateRouteHints,
|
||||
@ -212,7 +215,6 @@ namespace BTCPayServer.Controllers
|
||||
};
|
||||
await SetExistingValues(store, vm);
|
||||
|
||||
var lightning = GetExistingLightningSupportedPaymentMethod(vm.CryptoCode, store);
|
||||
var lnSet = lightning != null;
|
||||
if (lnSet)
|
||||
{
|
||||
@ -297,10 +299,10 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
await _Repo.UpdateStore(store);
|
||||
|
||||
TempData[WellKnownTempData.SuccessMessage] = $"{network.CryptoCode} Lightning settings successfully updated";
|
||||
TempData[WellKnownTempData.SuccessMessage] = $"{network.CryptoCode} Lightning settings successfully updated.";
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(PaymentMethods), new { vm.StoreId });
|
||||
return RedirectToAction(nameof(LightningSettings), new { vm.StoreId, vm.CryptoCode });
|
||||
}
|
||||
|
||||
[HttpPost("{storeId}/lightning/{cryptoCode}/status")]
|
||||
@ -329,7 +331,7 @@ namespace BTCPayServer.Controllers
|
||||
await _Repo.UpdateStore(store);
|
||||
TempData[WellKnownTempData.SuccessMessage] = $"{network.CryptoCode} Lightning payments are now {(enabled ? "enabled" : "disabled")} for this store.";
|
||||
|
||||
return RedirectToAction(nameof(PaymentMethods), new { storeId });
|
||||
return RedirectToAction(nameof(LightningSettings), new { storeId, cryptoCode });
|
||||
}
|
||||
|
||||
private async Task<bool> CanUseInternalLightning()
|
||||
|
@ -178,7 +178,7 @@ namespace BTCPayServer.Controllers
|
||||
TempData[WellKnownTempData.SuccessMessage] = $"Wallet settings for {network.CryptoCode} have been updated.";
|
||||
|
||||
// This is success case when derivation scheme is added to the store
|
||||
return RedirectToAction(nameof(PaymentMethods), new { storeId = vm.StoreId });
|
||||
return RedirectToAction(nameof(WalletSettings), new { storeId = vm.StoreId, cryptoCode = vm.CryptoCode });
|
||||
}
|
||||
return ConfirmAddresses(vm, strategy);
|
||||
}
|
||||
@ -362,7 +362,7 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
TempData[WellKnownTempData.SuccessMessage] = $"Wallet settings for {network.CryptoCode} have been updated.";
|
||||
|
||||
return RedirectToAction(nameof(PaymentMethods), new { storeId });
|
||||
return RedirectToAction(nameof(Payment), new { storeId });
|
||||
}
|
||||
|
||||
[HttpGet("{storeId}/onchain/{cryptoCode}/settings")]
|
||||
@ -381,6 +381,7 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
|
||||
var storeBlob = store.GetStoreBlob();
|
||||
var excludeFilters = storeBlob.GetExcludedPaymentMethods();
|
||||
(bool canUseHotWallet, bool rpcImport) = await CanUseHotWallet();
|
||||
var client = _ExplorerProvider.GetExplorerClient(network);
|
||||
|
||||
@ -389,6 +390,7 @@ namespace BTCPayServer.Controllers
|
||||
StoreId = storeId,
|
||||
CryptoCode = cryptoCode,
|
||||
WalletId = new WalletId(storeId, cryptoCode),
|
||||
Enabled = !excludeFilters.Match(derivation.PaymentId),
|
||||
Network = network,
|
||||
IsHotWallet = derivation.IsHotWallet,
|
||||
Source = derivation.Source,
|
||||
@ -447,8 +449,19 @@ namespace BTCPayServer.Controllers
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
bool needUpdate = false;
|
||||
var storeBlob = store.GetStoreBlob();
|
||||
var excludeFilters = storeBlob.GetExcludedPaymentMethods();
|
||||
var currentlyEnabled = !excludeFilters.Match(derivation.PaymentId);
|
||||
bool enabledChanged = currentlyEnabled != vm.Enabled;
|
||||
bool needUpdate = enabledChanged;
|
||||
string errorMessage = null;
|
||||
|
||||
if (enabledChanged)
|
||||
{
|
||||
storeBlob.SetExcluded(derivation.PaymentId, !vm.Enabled);
|
||||
store.SetStoreBlob(storeBlob);
|
||||
}
|
||||
|
||||
if (derivation.Label != vm.Label)
|
||||
{
|
||||
needUpdate = true;
|
||||
@ -466,8 +479,8 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
for (int i = 0; i < derivation.AccountKeySettings.Length; i++)
|
||||
{
|
||||
KeyPath accountKeyPath = null;
|
||||
HDFingerprint? rootFingerprint = null;
|
||||
KeyPath accountKeyPath;
|
||||
HDFingerprint? rootFingerprint;
|
||||
|
||||
try
|
||||
{
|
||||
@ -512,7 +525,14 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
if (string.IsNullOrEmpty(errorMessage))
|
||||
{
|
||||
TempData[WellKnownTempData.SuccessMessage] = "Wallet settings successfully updated";
|
||||
var successMessage = "Wallet settings successfully updated.";
|
||||
if (enabledChanged)
|
||||
{
|
||||
_EventAggregator.Publish(new WalletChangedEvent { WalletId = new WalletId(vm.StoreId, vm.CryptoCode) });
|
||||
successMessage += $" {vm.CryptoCode} on-chain payments are now {(vm.Enabled ? "enabled" : "disabled")} for this store.";
|
||||
}
|
||||
|
||||
TempData[WellKnownTempData.SuccessMessage] = successMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -690,40 +710,6 @@ namespace BTCPayServer.Controllers
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("{storeId}/onchain/{cryptoCode}/status")]
|
||||
public async Task<IActionResult> SetWalletEnabled(string storeId, string cryptoCode, bool enabled)
|
||||
{
|
||||
var checkResult = IsAvailable(cryptoCode, out var store, out var network);
|
||||
if (checkResult != null)
|
||||
{
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
var derivation = GetExistingDerivationStrategy(cryptoCode, store);
|
||||
if (derivation == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var wallet = _WalletProvider.GetWallet(network);
|
||||
if (wallet == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike);
|
||||
var storeBlob = store.GetStoreBlob();
|
||||
storeBlob.SetExcluded(paymentMethodId, !enabled);
|
||||
store.SetStoreBlob(storeBlob);
|
||||
await _Repo.UpdateStore(store);
|
||||
_EventAggregator.Publish(new WalletChangedEvent { WalletId = new WalletId(storeId, cryptoCode) });
|
||||
|
||||
TempData[WellKnownTempData.SuccessMessage] =
|
||||
$"{network.CryptoCode} on-chain payments are now {(enabled ? "enabled" : "disabled")} for this store.";
|
||||
|
||||
return RedirectToAction(nameof(PaymentMethods), new { storeId });
|
||||
}
|
||||
|
||||
[HttpPost("{storeId}/onchain/{cryptoCode}/delete")]
|
||||
public async Task<IActionResult> ConfirmDeleteWallet(string storeId, string cryptoCode)
|
||||
{
|
||||
@ -748,7 +734,7 @@ namespace BTCPayServer.Controllers
|
||||
TempData[WellKnownTempData.SuccessMessage] =
|
||||
$"On-Chain payment for {network.CryptoCode} has been removed.";
|
||||
|
||||
return RedirectToAction(nameof(PaymentMethods), new { storeId });
|
||||
return RedirectToAction(nameof(Payment), new { storeId });
|
||||
}
|
||||
|
||||
private IActionResult ConfirmAddresses(WalletSetupViewModel vm, DerivationSchemeSettings strategy)
|
||||
|
@ -589,19 +589,17 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("{storeId}/payment-methods")]
|
||||
public IActionResult PaymentMethods()
|
||||
[HttpGet("{storeId}/payment")]
|
||||
public IActionResult Payment()
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
if (store == null)
|
||||
return NotFound();
|
||||
|
||||
var storeBlob = store.GetStoreBlob();
|
||||
var vm = new PaymentMethodsViewModel
|
||||
var vm = new PaymentViewModel
|
||||
{
|
||||
Id = store.Id,
|
||||
HintWallet = storeBlob.Hints.Wallet,
|
||||
HintLightning = storeBlob.Hints.Lightning,
|
||||
NetworkFeeMode = storeBlob.NetworkFeeMode,
|
||||
AnyoneCanCreateInvoice = storeBlob.AnyoneCanInvoice,
|
||||
PaymentTolerance = storeBlob.PaymentTolerance,
|
||||
@ -609,17 +607,11 @@ namespace BTCPayServer.Controllers
|
||||
DefaultCurrency = storeBlob.DefaultCurrency
|
||||
};
|
||||
|
||||
AddPaymentMethods(store, storeBlob,
|
||||
out var derivationSchemes, out var lightningNodes);
|
||||
|
||||
vm.DerivationSchemes = derivationSchemes;
|
||||
vm.LightningNodes = lightningNodes;
|
||||
|
||||
return View(vm);
|
||||
}
|
||||
|
||||
[HttpPost("{storeId}/payment-methods")]
|
||||
public async Task<IActionResult> PaymentMethods(PaymentMethodsViewModel model, string command = null)
|
||||
[HttpPost("{storeId}/payment")]
|
||||
public async Task<IActionResult> Payment(PaymentViewModel model, string command = null)
|
||||
{
|
||||
bool needUpdate = false;
|
||||
var blob = CurrentStore.GetStoreBlob();
|
||||
@ -641,7 +633,7 @@ namespace BTCPayServer.Controllers
|
||||
TempData[WellKnownTempData.SuccessMessage] = "Payment settings successfully updated";
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(PaymentMethods), new
|
||||
return RedirectToAction(nameof(Payment), new
|
||||
{
|
||||
storeId = CurrentStore.Id
|
||||
});
|
||||
|
@ -1,16 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Models.StoreViewModels
|
||||
{
|
||||
public class PaymentMethodsViewModel
|
||||
public class PaymentViewModel
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public List<StoreDerivationScheme> DerivationSchemes { get; set; }
|
||||
public List<StoreLightningNode> LightningNodes { get; set; }
|
||||
public bool HintWallet { get; set; }
|
||||
public bool HintLightning { get; set; }
|
||||
|
||||
[Display(Name = "Allow anyone to create invoice")]
|
||||
public bool AnyoneCanCreateInvoice { get; set; }
|
@ -10,6 +10,7 @@ namespace BTCPayServer.Models.StoreViewModels
|
||||
public WalletId WalletId { get; set; }
|
||||
public string StoreId { get; set; }
|
||||
public bool IsHotWallet { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public bool CanUsePayJoin { get; set; }
|
||||
|
||||
[Display(Name = "Enable Payjoin/P2EP")]
|
||||
|
@ -30,7 +30,7 @@
|
||||
{
|
||||
if (!isLightningEnabled)
|
||||
{
|
||||
<a asp-action="PaymentMethods" asp-controller="UIStores" asp-route-storeId="@store.Id" class="btn btn-link p-0">
|
||||
<a asp-action="Payment" asp-controller="UIStores" asp-route-storeId="@store.Id" class="btn btn-link p-0">
|
||||
You need to setup Lightning first
|
||||
</a>
|
||||
}
|
||||
|
@ -79,7 +79,7 @@
|
||||
<td>
|
||||
@if (app.IsOwner)
|
||||
{
|
||||
<span><a asp-action="PaymentMethods" asp-controller="UIStores" asp-route-storeId="@app.StoreId">@app.StoreName</a></span>
|
||||
<span><a asp-action="Payment" asp-controller="UIStores" asp-route-storeId="@app.StoreId">@app.StoreName</a></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -31,7 +31,7 @@
|
||||
{
|
||||
<div class="alert alert-warning text-center sticky-top mb-0 rounded-0" role="alert">
|
||||
LNURL is not enabled on your store, which this print feature relies on.
|
||||
<a asp-action="PaymentMethods" asp-controller="UIStores" asp-route-storeId="@Model.Store.Id" class="alert-link p-0">
|
||||
<a asp-action="Payment" asp-controller="UIStores" asp-route-storeId="@Model.Store.Id" class="alert-link p-0">
|
||||
Enable LNURL
|
||||
</a>
|
||||
</div>
|
||||
|
@ -14,18 +14,17 @@
|
||||
|
||||
@section PageFootContent {
|
||||
<script>
|
||||
const alertClasses = { "Settled (marked)": 'success', "Invalid (marked)": 'danger' }
|
||||
|
||||
function changeInvoiceState(invoiceId, newState) {
|
||||
var toggleButton = $("#markStatusDropdownMenuButton");
|
||||
console.log(invoiceId, newState)
|
||||
const toggleButton = $("#markStatusDropdownMenuButton");
|
||||
toggleButton.attr("disabled", "disabled");
|
||||
|
||||
$.post(invoiceId + "/changestate/" + newState)
|
||||
.done(function (data) {
|
||||
var alertClassModifier = {
|
||||
"settled (marked)": 'success',
|
||||
"invalid (marked)": 'danger'
|
||||
}[data.statusString];
|
||||
var statusHtml = "<span class='fs-6 fw-normal badge bg-" + alertClassModifier + "'>" + data.statusString + " <span class='fa fa-check'></span></span>"
|
||||
toggleButton.replaceWith(statusHtml);
|
||||
$.post(`${invoiceId}/changestate/${newState}`)
|
||||
.done(({ statusString }) => {
|
||||
const alertClass = alertClasses[statusString];
|
||||
toggleButton.replaceWith(`<span class="fs-6 fw-normal badge bg-${alertClass}">${statusString} <span class="fa fa-check"></span></span>`);
|
||||
})
|
||||
.fail(function () {
|
||||
toggleButton.removeAttr("disabled");
|
||||
@ -33,14 +32,11 @@
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
$("[data-change-invoice-status-button]").click(function (e) {
|
||||
var id = e.currentTarget.getAttribute('data-id');
|
||||
var status = e.currentTarget.getAttribute('data-status');
|
||||
|
||||
changeInvoiceState(id, status);
|
||||
});
|
||||
});
|
||||
delegate('click', '[data-change-invoice-status-button]', e => {
|
||||
const button = e.target.closest('[data-change-invoice-status-button]')
|
||||
const { id, status } = button.dataset
|
||||
changeInvoiceState(id, status)
|
||||
})
|
||||
</script>
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ else
|
||||
}
|
||||
else
|
||||
{
|
||||
<a asp-controller="UIStores" asp-action="PaymentMethods" asp-route-storeId="@Model.StoreId" id="SetupGuide-Wallet" class="list-group-item list-group-item-action d-flex align-items-center order-1">
|
||||
<a asp-controller="UIStores" asp-action="Payment" asp-route-storeId="@Model.StoreId" id="SetupGuide-Wallet" class="list-group-item list-group-item-action d-flex align-items-center order-1">
|
||||
<vc:icon symbol="new-wallet"/>
|
||||
<div class="content">
|
||||
<h5 class="mb-0">Set up a wallet</h5>
|
||||
@ -95,7 +95,7 @@ else
|
||||
}
|
||||
else
|
||||
{
|
||||
<a asp-controller="UIStores" asp-action="PaymentMethods" asp-route-storeId="@Model.StoreId" id="SetupGuide-Lightning" class="list-group-item list-group-item-action d-flex align-items-center order-1">
|
||||
<a asp-controller="UIStores" asp-action="Payment" asp-route-storeId="@Model.StoreId" id="SetupGuide-Lightning" class="list-group-item list-group-item-action d-flex align-items-center order-1">
|
||||
<vc:icon symbol="new-wallet"/>
|
||||
<div class="content">
|
||||
<h5 class="mb-0">Set up a Lightning node</h5>
|
||||
|
@ -10,7 +10,7 @@
|
||||
<div class="col-lg-10 col-xl-9">
|
||||
<div class="mb-5">
|
||||
<h4 class="mb-3">@ViewData["Title"]</h4>
|
||||
<div class="text-break">
|
||||
<div class="text-break mb-3">
|
||||
<span class="me-2">@Model.LightningNodeType Node</span>
|
||||
@if (Model.LightningNodeType != LightningNodeType.Internal)
|
||||
{
|
||||
@ -39,6 +39,19 @@
|
||||
Change connection
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<form method="post"
|
||||
asp-action="SetLightningNodeEnabled"
|
||||
asp-route-cryptoCode="@Model.CryptoCode"
|
||||
asp-route-storeId="@Model.StoreId"
|
||||
class="d-flex align-items-center"
|
||||
style="min-width:7rem">
|
||||
<button type="submit" class="btcpay-toggle me-2 @if (Model.Enabled) { @("btcpay-toggle--active") }" name="Enabled" value="@(Model.Enabled ? "false" : "true")" id="@($"{Model.CryptoCode}LightningEnabled")">@(Model.Enabled ? "Disable" : "Enable")</button>
|
||||
<span>
|
||||
Enabled
|
||||
</span>
|
||||
</form>
|
||||
|
||||
<form method="post" class="mt-n2 text-center">
|
||||
<div class="text-start">
|
||||
<h4 class="mt-5 mb-3">Payment</h4>
|
||||
|
68
BTCPayServer/Views/UIStores/Payment.cshtml
Normal file
68
BTCPayServer/Views/UIStores/Payment.cshtml
Normal file
@ -0,0 +1,68 @@
|
||||
@model PaymentViewModel
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
ViewData.SetActivePage(StoreNavPages.Payment, "Wallets", Context.GetStoreData().Id);
|
||||
}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-10 col-xl-9">
|
||||
@if (!ViewContext.ModelState.IsValid)
|
||||
{
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
}
|
||||
<form method="post">
|
||||
<h3 class="mb-3">Payment</h3>
|
||||
<div class="form-group">
|
||||
<label asp-for="DefaultCurrency" class="form-label"></label>
|
||||
<input asp-for="DefaultCurrency" class="form-control" style="max-width:10ch;" />
|
||||
<span asp-validation-for="DefaultCurrency" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group d-flex align-items-center">
|
||||
<input asp-for="AnyoneCanCreateInvoice" type="checkbox" class="btcpay-toggle me-2"/>
|
||||
<label asp-for="AnyoneCanCreateInvoice" class="form-label mb-0 me-1"></label>
|
||||
<a href="https://docs.btcpayserver.org/FAQ/Stores/#allow-anyone-to-create-invoice" target="_blank" rel="noreferrer noopener">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="form-group mt-4">
|
||||
<label asp-for="NetworkFeeMode" class="form-label"></label>
|
||||
<a href="https://docs.btcpayserver.org/FAQ/Stores/#add-network-fee-to-invoice-vary-with-mining-fees" target="_blank" rel="noreferrer noopener">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
</a>
|
||||
<select asp-for="NetworkFeeMode" class="form-select">
|
||||
<option value="MultiplePaymentsOnly">... only if the customer makes more than one payment for the invoice</option>
|
||||
<option value="Always">... on every payment</option>
|
||||
<option value="Never">Never add network fee</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="InvoiceExpiration" class="form-label"></label>
|
||||
<a href="https://docs.btcpayserver.org/FAQ/Stores/#invoice-expires-if-the-full-amount-has-not-been-paid-after-minutes" target="_blank" rel="noreferrer noopener">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
</a>
|
||||
<div class="input-group">
|
||||
<input asp-for="InvoiceExpiration" class="form-control" style="max-width:10ch;"/>
|
||||
<span class="input-group-text">minutes</span>
|
||||
</div>
|
||||
<span asp-validation-for="InvoiceExpiration" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="PaymentTolerance" class="form-label"></label>
|
||||
<a href="https://docs.btcpayserver.org/FAQ/Stores/#consider-the-invoice-paid-even-if-the-paid-amount-is-less-than-expected" target="_blank" rel="noreferrer noopener">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
</a>
|
||||
<div class="input-group">
|
||||
<input asp-for="PaymentTolerance" class="form-control" style="max-width:10ch;"/>
|
||||
<span class="input-group-text">percent</span>
|
||||
</div>
|
||||
<span asp-validation-for="PaymentTolerance" class="text-danger"></span>
|
||||
</div>
|
||||
|
||||
<button name="command" type="submit" class="btn btn-primary px-4 mt-3" value="Save" id="Save">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section PageFootContent {
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
}
|
@ -1,241 +0,0 @@
|
||||
@using System.Text.RegularExpressions
|
||||
@using BTCPayServer.Lightning
|
||||
@model PaymentMethodsViewModel
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, "Wallets", Context.GetStoreData().Id);
|
||||
}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-10 col-xl-9">
|
||||
@if (!ViewContext.ModelState.IsValid)
|
||||
{
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
}
|
||||
<div class="mb-5">
|
||||
<h3 class="mb-3">Wallet</h3>
|
||||
@if (Model.HintWallet)
|
||||
{
|
||||
<p>Set up your wallet to receive payments at your store.</p>
|
||||
}
|
||||
<ul class="list-group mb-3">
|
||||
@foreach (var scheme in Model.DerivationSchemes.OrderBy(scheme => scheme.Collapsed))
|
||||
{
|
||||
var isSetUp = !string.IsNullOrWhiteSpace(scheme.Value);
|
||||
|
||||
<li class="list-group-item bg-tile @(scheme.Collapsed ? "assets-collapsed": "")">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="d-flex flex-wrap flex-fill flex-column flex-sm-row">
|
||||
<strong class="me-3">@scheme.Crypto</strong>
|
||||
@if (isSetUp)
|
||||
{
|
||||
<span title="@scheme.Value" data-bs-toggle="tooltip" class="d-flex me-3">
|
||||
<span class="text-truncate text-secondary" style="max-width:8ch">@scheme.Value</span>
|
||||
@if (scheme.Value.Length > 20)
|
||||
{
|
||||
<span class="text-nowrap text-secondary">@Regex.Match(scheme.Value, @"((?:-\[(?:[^\]])+\])+|\S{6})$").Value</span>
|
||||
}
|
||||
</span>
|
||||
@if (scheme.WalletSupported)
|
||||
{
|
||||
<a asp-action="WalletTransactions" asp-controller="UIWallets" asp-route-walletId="@scheme.WalletId" class="text-secondary me-3">Manage Wallet</a>
|
||||
}
|
||||
}
|
||||
</span>
|
||||
<span class="d-flex align-items-center fw-semibold">
|
||||
@if (isSetUp)
|
||||
{
|
||||
<form method="post"
|
||||
asp-action="SetWalletEnabled"
|
||||
asp-route-cryptoCode="@scheme.Crypto"
|
||||
asp-route-storeId="@Model.Id"
|
||||
class="d-flex align-items-center"
|
||||
style="min-width:7rem">
|
||||
<button type="submit" class="btcpay-toggle me-2 @if (scheme.Enabled) { @("btcpay-toggle--active") }" name="Enabled" value="@(scheme.Enabled ? "false" : "true")" id="@($"{scheme.Crypto}WalletEnabled")">@(scheme.Enabled ? "Disable" : "Enable")</button>
|
||||
@if (scheme.Enabled)
|
||||
{
|
||||
<span class="text-primary">
|
||||
Enabled
|
||||
</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="text-muted">
|
||||
Disabled
|
||||
</span>
|
||||
}
|
||||
</form>
|
||||
<span class="text-light mx-2">|</span>
|
||||
<a asp-action="WalletSettings" asp-route-cryptoCode="@scheme.Crypto" asp-route-storeId="@Model.Id" id="@($"Modify{scheme.Crypto}")" class="btn btn-link px-1 py-1 fw-semibold">
|
||||
Settings
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a asp-action="SetupWallet" asp-route-cryptoCode="@scheme.Crypto" asp-route-storeId="@Model.Id" id="@($"Modify{scheme.Crypto}")" class="btn btn-primary btn-sm ms-4 px-3 py-1 fw-semibold">
|
||||
Setup
|
||||
</a>
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
@if (Model.DerivationSchemes.Any(scheme => scheme.Collapsed))
|
||||
{
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", (event) => {
|
||||
var collapsed = document.getElementsByClassName("assets-collapsed");
|
||||
for (let collapsedElement of collapsed) {
|
||||
collapsedElement.style.display = 'none';
|
||||
}
|
||||
document
|
||||
.getElementById("toggle-assets")
|
||||
.addEventListener("click", function (){
|
||||
var collapsed = document.getElementsByClassName("assets-collapsed");
|
||||
for (let collapsedElement of collapsed) {
|
||||
collapsedElement.style.display = 'block';
|
||||
}
|
||||
document.getElementById("toggle-assets").style.display="none";
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<button class="btn btn-link text-secondary mb-3 p-0 only-for-js" id="toggle-assets" type="button">Show additional assets</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="mb-5">
|
||||
<h3 class="mb-3">Lightning</h3>
|
||||
@if (Model.HintLightning)
|
||||
{
|
||||
<p>A connection to a Lightning node is required to receive Lightning payments.</p>
|
||||
}
|
||||
<ul class="list-group mb-3">
|
||||
@foreach (var scheme in Model.LightningNodes)
|
||||
{
|
||||
var isSetUp = !string.IsNullOrWhiteSpace(scheme.Address);
|
||||
|
||||
<li class="list-group-item bg-tile">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="d-flex flex-wrap flex-fill flex-column flex-sm-row">
|
||||
<strong class="me-3">@scheme.CryptoCode</strong>
|
||||
@if (isSetUp)
|
||||
{
|
||||
<span class="text-truncate text-secondary me-3" style="max-width:150px;">
|
||||
@if (LightningConnectionString.TryParse(scheme.Address, out var cs))
|
||||
{
|
||||
<span>@typeof(LightningConnectionType).DisplayName(cs.ConnectionType.ToString())</span>
|
||||
<span>@cs.BaseUri.Host</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
@scheme.Address
|
||||
}
|
||||
</span>
|
||||
<a class="text-secondary me-3"
|
||||
asp-controller="UIPublicLightningNodeInfo"
|
||||
asp-action="ShowLightningNodeInfo"
|
||||
asp-route-cryptoCode="@scheme.CryptoCode"
|
||||
asp-route-storeId="@Model.Id"
|
||||
target="_blank">
|
||||
Public Node Info
|
||||
</a>
|
||||
}
|
||||
</span>
|
||||
<span class="d-flex align-items-center fw-semibold">
|
||||
@if (isSetUp)
|
||||
{
|
||||
<form method="post"
|
||||
asp-action="SetLightningNodeEnabled"
|
||||
asp-route-cryptoCode="@scheme.CryptoCode"
|
||||
asp-route-storeId="@Model.Id"
|
||||
class="d-flex align-items-center"
|
||||
style="min-width:7rem">
|
||||
<button type="submit" class="btcpay-toggle me-2 @if (scheme.Enabled) { @("btcpay-toggle--active") }" name="Enabled" value="@(scheme.Enabled ? "false" : "true")" id="@($"{scheme.CryptoCode}LightningEnabled")">@(scheme.Enabled ? "Disable" : "Enable")e</button>
|
||||
@if (scheme.Enabled)
|
||||
{
|
||||
<span class="text-primary">
|
||||
Enabled
|
||||
</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="text-muted">
|
||||
Disabled
|
||||
</span>
|
||||
}
|
||||
</form>
|
||||
<span class="text-light mx-2">|</span>
|
||||
<a asp-action="LightningSettings" asp-route-cryptoCode="@scheme.CryptoCode" asp-route-storeId="@Model.Id" id="@($"Modify-Lightning{scheme.CryptoCode}")" class="btn btn-link px-1 py-1 fw-semibold">
|
||||
Settings
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a asp-action="SetupLightningNode" asp-route-cryptoCode="@scheme.CryptoCode" asp-route-storeId="@Model.Id" id="@($"Modify-Lightning{scheme.CryptoCode}")" class="btn btn-primary btn-sm ms-4 px-3 py-1 fw-semibold">
|
||||
Setup
|
||||
</a>
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<h3 class="mb-3">Payment</h3>
|
||||
<div class="form-group">
|
||||
<label asp-for="DefaultCurrency" class="form-label"></label>
|
||||
<input asp-for="DefaultCurrency" class="form-control" style="max-width:10ch;" />
|
||||
<span asp-validation-for="DefaultCurrency" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group d-flex align-items-center">
|
||||
<input asp-for="AnyoneCanCreateInvoice" type="checkbox" class="btcpay-toggle me-2"/>
|
||||
<label asp-for="AnyoneCanCreateInvoice" class="form-label mb-0 me-1"></label>
|
||||
<a href="https://docs.btcpayserver.org/FAQ/Stores/#allow-anyone-to-create-invoice" target="_blank" rel="noreferrer noopener">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="form-group mt-4">
|
||||
<label asp-for="NetworkFeeMode" class="form-label"></label>
|
||||
<a href="https://docs.btcpayserver.org/FAQ/Stores/#add-network-fee-to-invoice-vary-with-mining-fees" target="_blank" rel="noreferrer noopener">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
</a>
|
||||
<select asp-for="NetworkFeeMode" class="form-select">
|
||||
<option value="MultiplePaymentsOnly">... only if the customer makes more than one payment for the invoice</option>
|
||||
<option value="Always">... on every payment</option>
|
||||
<option value="Never">Never add network fee</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="InvoiceExpiration" class="form-label"></label>
|
||||
<a href="https://docs.btcpayserver.org/FAQ/Stores/#invoice-expires-if-the-full-amount-has-not-been-paid-after-minutes" target="_blank" rel="noreferrer noopener">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
</a>
|
||||
<div class="input-group">
|
||||
<input asp-for="InvoiceExpiration" class="form-control" style="max-width:10ch;"/>
|
||||
<span class="input-group-text">minutes</span>
|
||||
</div>
|
||||
<span asp-validation-for="InvoiceExpiration" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="PaymentTolerance" class="form-label"></label>
|
||||
<a href="https://docs.btcpayserver.org/FAQ/Stores/#consider-the-invoice-paid-even-if-the-paid-amount-is-less-than-expected" target="_blank" rel="noreferrer noopener">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
</a>
|
||||
<div class="input-group">
|
||||
<input asp-for="PaymentTolerance" class="form-control" style="max-width:10ch;"/>
|
||||
<span class="input-group-text">percent</span>
|
||||
</div>
|
||||
<span asp-validation-for="PaymentTolerance" class="text-danger"></span>
|
||||
</div>
|
||||
|
||||
<button name="command" type="submit" class="btn btn-primary px-4 mt-3" value="Save" id="Save">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section PageFootContent {
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
}
|
@ -2,6 +2,6 @@ namespace BTCPayServer.Views.Stores
|
||||
{
|
||||
public enum StoreNavPages
|
||||
{
|
||||
Create, Dashboard, Rates, PaymentMethods, OnchainSettings, LightningSettings, Lightning, CheckoutAppearance, General, Tokens, Users, PayButton, Integrations, Webhooks, PullPayments, Payouts
|
||||
Create, Dashboard, Rates, Payment, OnchainSettings, LightningSettings, Lightning, CheckoutAppearance, General, Tokens, Users, PayButton, Integrations, Webhooks, PullPayments, Payouts
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,13 @@
|
||||
</div>
|
||||
|
||||
<form method="post" asp-action="UpdateWalletSettings" asp-route-storeId="@Model.StoreId" asp-route-cryptoCode="@Model.CryptoCode">
|
||||
<div class="form-group">
|
||||
<div class="d-flex align-items-center">
|
||||
<input asp-for="Enabled" type="checkbox" class="btcpay-toggle me-2"/>
|
||||
<label asp-for="Enabled" class="form-label mb-0 me-1"></label>
|
||||
</div>
|
||||
<span asp-validation-for="PayJoinEnabled" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Label" class="form-label"></label>
|
||||
<input asp-for="Label" class="form-control" style="max-width:24em;" />
|
||||
|
@ -13,7 +13,7 @@
|
||||
@section Navbar {
|
||||
@await RenderSectionAsync("Navbar", false)
|
||||
|
||||
<a asp-controller="UIStores" asp-action="PaymentMethods" asp-route-storeId="@Context.GetRouteValue("storeId")" class="cancel">
|
||||
<a asp-controller="UIStores" asp-action="Payment" asp-route-storeId="@Context.GetRouteValue("storeId")" class="cancel">
|
||||
<vc:icon symbol="close" />
|
||||
</a>
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
@using BTCPayServer.Client
|
||||
<nav id="SectionNav" class="nav">
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.General))" class="nav-link @ViewData.IsActivePage(StoreNavPages.General)" asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@Context.GetRouteValue("storeId")">General</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.PaymentMethods))" class="nav-link @ViewData.IsActivePage(StoreNavPages.PaymentMethods)" asp-controller="UIStores" asp-action="PaymentMethods" asp-route-storeId="@Context.GetRouteValue("storeId")">Payment Methods</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Payment))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Payment)" asp-controller="UIStores" asp-action="Payment" asp-route-storeId="@Context.GetRouteValue("storeId")">Payment</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Rates))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Rates)" asp-controller="UIStores" asp-action="Rates" asp-route-storeId="@Context.GetRouteValue("storeId")">Rates</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.CheckoutAppearance))" class="nav-link @ViewData.IsActivePage(StoreNavPages.CheckoutAppearance)" asp-controller="UIStores" asp-action="CheckoutAppearance" asp-route-storeId="@Context.GetRouteValue("storeId")">Checkout Appearance</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Tokens))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Tokens)" asp-controller="UIStores" asp-action="ListTokens" asp-route-storeId="@Context.GetRouteValue("storeId")">Access Tokens</a>
|
||||
|
@ -44,7 +44,7 @@
|
||||
<tr>
|
||||
@if (wallet.IsOwner)
|
||||
{
|
||||
<td><a asp-action="PaymentMethods" asp-controller="UIStores" asp-route-storeId="@wallet.StoreId">@wallet.StoreName</a></td>
|
||||
<td><a asp-action="Payment" asp-controller="UIStores" asp-route-storeId="@wallet.StoreId">@wallet.StoreName</a></td>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user