mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
Store centric UI: Part 3 (#3224)
* Set store context in cookie * Fix page id usages in view * Move Pay Button to nav * Move integrations to plugins nav * Store switch links to wallet if present * Test fixes * Nav fixes * Fix altcoin view * Main nav updates * Wallet setttings nav update * Move storeId cookie fallback to cookie auth handler * View fixes * Test fixes * Fix profile check * Rename integrations nav extension point to store-integrations-nav-list * Allow strings for Active page/category for plugins * Make invoice list filter based on store context * Do not set context if we are running authorizer through tag helper * Fix test and unfiltered invoices * Add permission helper for wallet links * Add sanity checks for payment requests and invoices * Store context in home controller * Fix PayjoinViaUI test * Store context for notifications * Minor UI improvements * Store context for userstores and vault controller * Bring back integrations page * Rename notifications nav pages file * Fix user stores controller policies * Controller policy fixes from code review * CookieAuthHandler: Simplify CanViewInvoices case * Revert "Controller policy fixes from code review" This reverts commit 97e8b8379c2f2f373bac15a96632d2c8913ef4bd. * Simplify LayoutSimple * Fix CanViewInvoices condition Co-authored-by: Kukks <evilkukka@gmail.com>
This commit is contained in:
@@ -13,13 +13,18 @@ namespace BTCPayServer.Abstractions.Extensions
|
|||||||
|
|
||||||
public static void SetActivePage<T>(this ViewDataDictionary viewData, T activePage, string title = null, string activeId = null)
|
public static void SetActivePage<T>(this ViewDataDictionary viewData, T activePage, string title = null, string activeId = null)
|
||||||
where T : IConvertible
|
where T : IConvertible
|
||||||
|
{
|
||||||
|
SetActivePage(viewData, activePage.ToString(), activePage.GetType().Name,title, activeId );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetActivePage(this ViewDataDictionary viewData, string activePage, string category, string title = null, string activeId = null)
|
||||||
{
|
{
|
||||||
// Page Title
|
// Page Title
|
||||||
viewData["Title"] = title ?? activePage.ToString();
|
viewData["Title"] = title ?? activePage;
|
||||||
// Navigation
|
// Navigation
|
||||||
viewData[ACTIVE_PAGE_KEY] = activePage;
|
viewData[ACTIVE_PAGE_KEY] = activePage;
|
||||||
viewData[ACTIVE_ID_KEY] = activeId;
|
viewData[ACTIVE_ID_KEY] = activeId;
|
||||||
SetActiveCategory(viewData, activePage.GetType());
|
SetActiveCategory(viewData, category);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetActiveCategory<T>(this ViewDataDictionary viewData, T activeCategory)
|
public static void SetActiveCategory<T>(this ViewDataDictionary viewData, T activeCategory)
|
||||||
@@ -27,30 +32,43 @@ namespace BTCPayServer.Abstractions.Extensions
|
|||||||
viewData[ACTIVE_CATEGORY_KEY] = activeCategory;
|
viewData[ACTIVE_CATEGORY_KEY] = activeCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetActiveCategory(this ViewDataDictionary viewData, string activeCategory)
|
||||||
|
{
|
||||||
|
viewData[ACTIVE_CATEGORY_KEY] = activeCategory;
|
||||||
|
}
|
||||||
|
|
||||||
public static string IsActiveCategory<T>(this ViewDataDictionary viewData, T category, object id = null)
|
public static string IsActiveCategory<T>(this ViewDataDictionary viewData, T category, object id = null)
|
||||||
|
{
|
||||||
|
return IsActiveCategory(viewData, category.ToString(), id);
|
||||||
|
}
|
||||||
|
public static string IsActiveCategory(this ViewDataDictionary viewData, string category, object id = null)
|
||||||
{
|
{
|
||||||
if (!viewData.ContainsKey(ACTIVE_CATEGORY_KEY))
|
if (!viewData.ContainsKey(ACTIVE_CATEGORY_KEY))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var activeId = viewData[ACTIVE_ID_KEY];
|
var activeId = viewData[ACTIVE_ID_KEY];
|
||||||
var activeCategory = (T)viewData[ACTIVE_CATEGORY_KEY];
|
var activeCategory = viewData[ACTIVE_CATEGORY_KEY]?.ToString();
|
||||||
var categoryMatch = category.Equals(activeCategory);
|
var categoryMatch = category.Equals(activeCategory, StringComparison.InvariantCultureIgnoreCase);
|
||||||
var idMatch = id == null || activeId == null || id.Equals(activeId);
|
var idMatch = id == null || activeId == null || id.Equals(activeId);
|
||||||
return categoryMatch && idMatch ? "active" : null;
|
return categoryMatch && idMatch ? "active" : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string IsActivePage<T>(this ViewDataDictionary viewData, T page, object id = null)
|
public static string IsActivePage<T>(this ViewDataDictionary viewData, T page, object id = null)
|
||||||
where T : IConvertible
|
where T : IConvertible
|
||||||
|
{
|
||||||
|
return IsActivePage(viewData, page.ToString(), page.GetType().Name, id );
|
||||||
|
}
|
||||||
|
public static string IsActivePage(this ViewDataDictionary viewData, string page,string category, object id = null)
|
||||||
{
|
{
|
||||||
if (!viewData.ContainsKey(ACTIVE_PAGE_KEY))
|
if (!viewData.ContainsKey(ACTIVE_PAGE_KEY))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var activeId = viewData[ACTIVE_ID_KEY];
|
var activeId = viewData[ACTIVE_ID_KEY];
|
||||||
var activePage = (T)viewData[ACTIVE_PAGE_KEY];
|
var activePage = viewData[ACTIVE_PAGE_KEY]?.ToString();
|
||||||
var activeCategory = viewData[ACTIVE_CATEGORY_KEY];
|
var activeCategory = viewData[ACTIVE_CATEGORY_KEY]?.ToString();
|
||||||
var categoryAndPageMatch = activeCategory.Equals(activePage.GetType()) && page.Equals(activePage);
|
var categoryAndPageMatch = ( category == null || activeCategory.Equals(category, StringComparison.InvariantCultureIgnoreCase )) && page.Equals(activePage, StringComparison.InvariantCultureIgnoreCase);
|
||||||
var idMatch = id == null || activeId == null || id.Equals(activeId);
|
var idMatch = id == null || activeId == null || id.Equals(activeId);
|
||||||
return categoryAndPageMatch && idMatch ? "active" : null;
|
return categoryAndPageMatch && idMatch ? "active" : null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -404,8 +404,6 @@ namespace BTCPayServer.Tests
|
|||||||
Assert.Contains("2.20000000 ₿", s.Driver.PageSource);
|
Assert.Contains("2.20000000 ₿", s.Driver.PageSource);
|
||||||
if (rateSelection == "RateThenText")
|
if (rateSelection == "RateThenText")
|
||||||
Assert.Contains("1.10000000 ₿", s.Driver.PageSource);
|
Assert.Contains("1.10000000 ₿", s.Driver.PageSource);
|
||||||
s.GoToHome();
|
|
||||||
s.GoToInvoices();
|
|
||||||
s.GoToInvoice(invoice.Id);
|
s.GoToInvoice(invoice.Id);
|
||||||
s.Driver.FindElement(By.Id("refundlink")).Click();
|
s.Driver.FindElement(By.Id("refundlink")).Click();
|
||||||
Assert.Contains("pull-payments", s.Driver.Url);
|
Assert.Contains("pull-payments", s.Driver.Url);
|
||||||
@@ -423,19 +421,19 @@ namespace BTCPayServer.Tests
|
|||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
s.GoToRegister();
|
s.GoToRegister();
|
||||||
s.RegisterNewUser();
|
s.RegisterNewUser();
|
||||||
var store = s.CreateNewStore();
|
(_, string storeId) = s.CreateNewStore();
|
||||||
s.AddDerivationScheme("BTC");
|
s.AddDerivationScheme("BTC");
|
||||||
|
|
||||||
//check that there is no dropdown since only one payment method is set
|
//check that there is no dropdown since only one payment method is set
|
||||||
var invoiceId = s.CreateInvoice(store.storeName, 10, "USD", "a@g.com");
|
var invoiceId = s.CreateInvoice(storeId, 10, "USD", "a@g.com");
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
s.Driver.FindElement(By.ClassName("payment__currencies_noborder"));
|
s.Driver.FindElement(By.ClassName("payment__currencies_noborder"));
|
||||||
s.GoToHome();
|
s.GoToHome();
|
||||||
s.GoToStore(store.storeId);
|
s.GoToStore(storeId);
|
||||||
s.AddDerivationScheme("LTC");
|
s.AddDerivationScheme("LTC");
|
||||||
s.AddLightningNode("BTC", LightningConnectionType.CLightning);
|
s.AddLightningNode("BTC", LightningConnectionType.CLightning);
|
||||||
//there should be three now
|
//there should be three now
|
||||||
invoiceId = s.CreateInvoice(store.storeName, 10, "USD", "a@g.com");
|
invoiceId = s.CreateInvoice(storeId, 10, "USD", "a@g.com");
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
var currencyDropdownButton = s.Driver.FindElement(By.ClassName("payment__currencies"));
|
var currencyDropdownButton = s.Driver.FindElement(By.ClassName("payment__currencies"));
|
||||||
Assert.Contains("BTC", currencyDropdownButton.Text);
|
Assert.Contains("BTC", currencyDropdownButton.Text);
|
||||||
|
|||||||
@@ -28,17 +28,17 @@ namespace BTCPayServer.Tests
|
|||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
s.GoToRegister();
|
s.GoToRegister();
|
||||||
s.RegisterNewUser();
|
s.RegisterNewUser();
|
||||||
var store = s.CreateNewStore();
|
(_, string storeId) = s.CreateNewStore();
|
||||||
s.AddDerivationScheme("BTC");
|
s.AddDerivationScheme("BTC");
|
||||||
s.GoToStore(store.storeId, StoreNavPages.CheckoutAppearance);
|
s.GoToStore(storeId, StoreNavPages.CheckoutAppearance);
|
||||||
s.Driver.FindElement(By.Id("RequiresRefundEmail")).Click();
|
s.Driver.FindElement(By.Id("RequiresRefundEmail")).Click();
|
||||||
s.Driver.FindElement(By.Name("command")).Click();
|
s.Driver.FindElement(By.Name("command")).Click();
|
||||||
|
|
||||||
var emailAlreadyThereInvoiceId = s.CreateInvoice(store.storeName, 100, "USD", "a@g.com");
|
var emailAlreadyThereInvoiceId = s.CreateInvoice(storeId, 100, "USD", "a@g.com");
|
||||||
s.GoToInvoiceCheckout(emailAlreadyThereInvoiceId);
|
s.GoToInvoiceCheckout(emailAlreadyThereInvoiceId);
|
||||||
s.Driver.AssertElementNotFound(By.Id("emailAddressFormInput"));
|
s.Driver.AssertElementNotFound(By.Id("emailAddressFormInput"));
|
||||||
s.GoToHome();
|
s.GoToHome();
|
||||||
var invoiceId = s.CreateInvoice(store.storeName);
|
s.CreateInvoice(storeId);
|
||||||
s.Driver.FindElement(By.ClassName("invoice-details-link")).Click();
|
s.Driver.FindElement(By.ClassName("invoice-details-link")).Click();
|
||||||
s.Driver.AssertNoError();
|
s.Driver.AssertNoError();
|
||||||
s.Driver.Navigate().Back();
|
s.Driver.Navigate().Back();
|
||||||
@@ -79,11 +79,11 @@ namespace BTCPayServer.Tests
|
|||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
s.GoToRegister();
|
s.GoToRegister();
|
||||||
s.RegisterNewUser();
|
s.RegisterNewUser();
|
||||||
var store = s.CreateNewStore();
|
(_, string storeId) = s.CreateNewStore();
|
||||||
s.AddDerivationScheme("BTC");
|
s.AddDerivationScheme("BTC");
|
||||||
|
|
||||||
// Now create an invoice that requires a refund email
|
// Now create an invoice that requires a refund email
|
||||||
var invoice = s.CreateInvoice(store.storeName, 100, "USD", "", null, true);
|
var invoice = s.CreateInvoice(storeId, 100, "USD", "", null, true);
|
||||||
s.GoToInvoiceCheckout(invoice);
|
s.GoToInvoiceCheckout(invoice);
|
||||||
|
|
||||||
var emailInput = s.Driver.FindElement(By.Id("emailAddressFormInput"));
|
var emailInput = s.Driver.FindElement(By.Id("emailAddressFormInput"));
|
||||||
@@ -106,7 +106,7 @@ namespace BTCPayServer.Tests
|
|||||||
s.GoToHome();
|
s.GoToHome();
|
||||||
|
|
||||||
// Now create an invoice that doesn't require a refund email
|
// Now create an invoice that doesn't require a refund email
|
||||||
s.CreateInvoice(store.storeName, 100, "USD", "", null, false);
|
s.CreateInvoice(storeId, 100, "USD", "", null, false);
|
||||||
s.Driver.FindElement(By.ClassName("invoice-details-link")).Click();
|
s.Driver.FindElement(By.ClassName("invoice-details-link")).Click();
|
||||||
s.Driver.AssertNoError();
|
s.Driver.AssertNoError();
|
||||||
s.Driver.Navigate().Back();
|
s.Driver.Navigate().Back();
|
||||||
@@ -119,7 +119,7 @@ namespace BTCPayServer.Tests
|
|||||||
s.GoToHome();
|
s.GoToHome();
|
||||||
|
|
||||||
// Now create an invoice that requires refund email but already has one set, email input shouldn't show up
|
// Now create an invoice that requires refund email but already has one set, email input shouldn't show up
|
||||||
s.CreateInvoice(store.storeName, 100, "USD", "a@g.com", null, true);
|
s.CreateInvoice(storeId, 100, "USD", "a@g.com", null, true);
|
||||||
s.Driver.FindElement(By.ClassName("invoice-details-link")).Click();
|
s.Driver.FindElement(By.ClassName("invoice-details-link")).Click();
|
||||||
s.Driver.AssertNoError();
|
s.Driver.AssertNoError();
|
||||||
s.Driver.Navigate().Back();
|
s.Driver.Navigate().Back();
|
||||||
@@ -139,10 +139,10 @@ namespace BTCPayServer.Tests
|
|||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
s.GoToRegister();
|
s.GoToRegister();
|
||||||
s.RegisterNewUser();
|
s.RegisterNewUser();
|
||||||
var store = s.CreateNewStore();
|
(_, string storeId) = s.CreateNewStore();
|
||||||
s.AddDerivationScheme("BTC");
|
s.AddDerivationScheme("BTC");
|
||||||
|
|
||||||
var invoiceId = s.CreateInvoice(store.storeName);
|
var invoiceId = s.CreateInvoice(storeId);
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
Assert.True(s.Driver.FindElement(By.Id("DefaultLang")).FindElements(By.TagName("option")).Count > 1);
|
Assert.True(s.Driver.FindElement(By.Id("DefaultLang")).FindElements(By.TagName("option")).Count > 1);
|
||||||
var payWithTextEnglish = s.Driver.FindElement(By.Id("pay-with-text")).Text;
|
var payWithTextEnglish = s.Driver.FindElement(By.Id("pay-with-text")).Text;
|
||||||
@@ -171,11 +171,11 @@ namespace BTCPayServer.Tests
|
|||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
s.GoToRegister();
|
s.GoToRegister();
|
||||||
s.RegisterNewUser(true);
|
s.RegisterNewUser(true);
|
||||||
var store = s.CreateNewStore();
|
(_, string storeId) = s.CreateNewStore();
|
||||||
s.AddLightningNode();
|
s.AddLightningNode();
|
||||||
s.AddDerivationScheme("BTC");
|
s.AddDerivationScheme("BTC");
|
||||||
|
|
||||||
var invoiceId = s.CreateInvoice(store.storeName, defaultPaymentMethod: "BTC_LightningLike");
|
var invoiceId = s.CreateInvoice(storeId, defaultPaymentMethod: "BTC_LightningLike");
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
|
|
||||||
Assert.Equal("Bitcoin (Lightning) (BTC)", s.Driver.FindElement(By.ClassName("payment__currencies")).Text);
|
Assert.Equal("Bitcoin (Lightning) (BTC)", s.Driver.FindElement(By.ClassName("payment__currencies")).Text);
|
||||||
@@ -193,7 +193,7 @@ namespace BTCPayServer.Tests
|
|||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
s.GoToRegister();
|
s.GoToRegister();
|
||||||
s.RegisterNewUser(true);
|
s.RegisterNewUser(true);
|
||||||
(string storeName, string storeId) = s.CreateNewStore();
|
(_, string storeId) = s.CreateNewStore();
|
||||||
s.AddLightningNode();
|
s.AddLightningNode();
|
||||||
s.GoToStore(storeId);
|
s.GoToStore(storeId);
|
||||||
s.Driver.FindElement(By.Id("Modify-LightningBTC")).Click();
|
s.Driver.FindElement(By.Id("Modify-LightningBTC")).Click();
|
||||||
@@ -201,7 +201,7 @@ namespace BTCPayServer.Tests
|
|||||||
s.Driver.FindElement(By.Id("save")).Click();
|
s.Driver.FindElement(By.Id("save")).Click();
|
||||||
Assert.Contains("BTC Lightning settings successfully updated", s.FindAlertMessage().Text);
|
Assert.Contains("BTC Lightning settings successfully updated", s.FindAlertMessage().Text);
|
||||||
|
|
||||||
var invoiceId = s.CreateInvoice(storeName, 10, "USD", "a@g.com");
|
var invoiceId = s.CreateInvoice(storeId, 10, "USD", "a@g.com");
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
Assert.Contains("Sats", s.Driver.FindElement(By.ClassName("payment__currencies_noborder")).Text);
|
Assert.Contains("Sats", s.Driver.FindElement(By.ClassName("payment__currencies_noborder")).Text);
|
||||||
}
|
}
|
||||||
@@ -215,10 +215,10 @@ namespace BTCPayServer.Tests
|
|||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
s.GoToRegister();
|
s.GoToRegister();
|
||||||
s.RegisterNewUser();
|
s.RegisterNewUser();
|
||||||
var store = s.CreateNewStore();
|
(_, string storeId) = s.CreateNewStore();
|
||||||
s.GoToStore(store.storeId);
|
s.GoToStore(storeId);
|
||||||
s.AddDerivationScheme();
|
s.AddDerivationScheme();
|
||||||
var invoiceId = s.CreateInvoice(store.storeId, 0.001m, "BTC", "a@x.com");
|
var invoiceId = s.CreateInvoice(storeId, 0.001m, "BTC", "a@x.com");
|
||||||
var invoice = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);
|
var invoice = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);
|
||||||
s.Driver.Navigate()
|
s.Driver.Navigate()
|
||||||
.GoToUrl(new Uri(s.ServerUri, $"tests/index.html?invoice={invoiceId}"));
|
.GoToUrl(new Uri(s.ServerUri, $"tests/index.html?invoice={invoiceId}"));
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ namespace BTCPayServer.Tests
|
|||||||
await s.FundStoreWallet(senderWalletId);
|
await s.FundStoreWallet(senderWalletId);
|
||||||
await s.FundStoreWallet(receiverWalletId);
|
await s.FundStoreWallet(receiverWalletId);
|
||||||
|
|
||||||
var invoiceId = s.CreateInvoice(receiver.storeName, null, "BTC");
|
var invoiceId = s.CreateInvoice(receiver.storeId, null, "BTC");
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
var bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
|
var bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
|
||||||
.GetAttribute("href");
|
.GetAttribute("href");
|
||||||
@@ -295,7 +295,7 @@ namespace BTCPayServer.Tests
|
|||||||
var receiverWalletId = new WalletId(receiver.storeId, cryptoCode);
|
var receiverWalletId = new WalletId(receiver.storeId, cryptoCode);
|
||||||
|
|
||||||
//payjoin is enabled by default.
|
//payjoin is enabled by default.
|
||||||
var invoiceId = s.CreateInvoice(receiver.storeName);
|
var invoiceId = s.CreateInvoice(receiver.storeId);
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
var bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
|
var bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
|
||||||
.GetAttribute("href");
|
.GetAttribute("href");
|
||||||
@@ -310,7 +310,7 @@ namespace BTCPayServer.Tests
|
|||||||
await s.Server.ExplorerNode.GenerateAsync(1);
|
await s.Server.ExplorerNode.GenerateAsync(1);
|
||||||
await s.FundStoreWallet(senderWalletId);
|
await s.FundStoreWallet(senderWalletId);
|
||||||
|
|
||||||
invoiceId = s.CreateInvoice(receiver.storeName);
|
invoiceId = s.CreateInvoice(receiver.storeId);
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
|
bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
|
||||||
.GetAttribute("href");
|
.GetAttribute("href");
|
||||||
@@ -343,7 +343,7 @@ namespace BTCPayServer.Tests
|
|||||||
StringComparison.InvariantCultureIgnoreCase));
|
StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
|
||||||
//let's do it all again, except now the receiver has funds and is able to payjoin
|
//let's do it all again, except now the receiver has funds and is able to payjoin
|
||||||
invoiceId = s.CreateInvoice(receiver.storeName);
|
invoiceId = s.CreateInvoice(receiver.storeId);
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
|
bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
|
||||||
.GetAttribute("href");
|
.GetAttribute("href");
|
||||||
@@ -393,7 +393,7 @@ namespace BTCPayServer.Tests
|
|||||||
var dto = invoice.EntityToDTO();
|
var dto = invoice.EntityToDTO();
|
||||||
Assert.Equal(InvoiceStatusLegacy.Paid, invoice.Status);
|
Assert.Equal(InvoiceStatusLegacy.Paid, invoice.Status);
|
||||||
});
|
});
|
||||||
s.GoToInvoices();
|
s.GoToInvoices(receiver.storeId);
|
||||||
paymentValueRowColumn = s.Driver.FindElement(By.Id($"invoice_details_{invoiceId}"))
|
paymentValueRowColumn = s.Driver.FindElement(By.Id($"invoice_details_{invoiceId}"))
|
||||||
.FindElement(By.ClassName("payment-value"));
|
.FindElement(By.ClassName("payment-value"));
|
||||||
Assert.False(paymentValueRowColumn.Text.Contains("payjoin",
|
Assert.False(paymentValueRowColumn.Text.Contains("payjoin",
|
||||||
|
|||||||
@@ -332,17 +332,10 @@ namespace BTCPayServer.Tests
|
|||||||
Driver.FindElement(By.Id("Password")).SendKeys(password);
|
Driver.FindElement(By.Id("Password")).SendKeys(password);
|
||||||
Driver.FindElement(By.Id("LoginButton")).Click();
|
Driver.FindElement(By.Id("LoginButton")).Click();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GoToApps()
|
|
||||||
{
|
|
||||||
Driver.FindElement(By.Id("StoreNav-Apps")).Click();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GoToStore(string storeId, StoreNavPages storeNavPage = StoreNavPages.PaymentMethods)
|
public void GoToStore(string storeId, StoreNavPages storeNavPage = StoreNavPages.PaymentMethods)
|
||||||
{
|
{
|
||||||
GoToHome();
|
GoToUrl($"/stores/{storeId}/");
|
||||||
Driver.WaitForAndClick(By.Id("StoreSelectorToggle"));
|
|
||||||
Driver.WaitForAndClick(By.Id($"StoreSelectorMenuItem-{storeId}"));
|
|
||||||
|
|
||||||
if (storeNavPage != StoreNavPages.PaymentMethods)
|
if (storeNavPage != StoreNavPages.PaymentMethods)
|
||||||
{
|
{
|
||||||
@@ -360,8 +353,15 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
public void GoToWalletSettings(string storeId, string cryptoCode = "BTC")
|
public void GoToWalletSettings(string storeId, string cryptoCode = "BTC")
|
||||||
{
|
{
|
||||||
GoToStore(storeId);
|
try
|
||||||
Driver.FindElement(By.Id($"Modify{cryptoCode}")).Click();
|
{
|
||||||
|
GoToStore(storeId);
|
||||||
|
Driver.FindElement(By.Id($"Modify{cryptoCode}")).Click();
|
||||||
|
}
|
||||||
|
catch (NoSuchElementException)
|
||||||
|
{
|
||||||
|
GoToWallet(new WalletId(storeId, cryptoCode), WalletsNavPages.Settings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GoToLightningSettings(string storeId, string cryptoCode = "BTC")
|
public void GoToLightningSettings(string storeId, string cryptoCode = "BTC")
|
||||||
@@ -377,10 +377,14 @@ namespace BTCPayServer.Tests
|
|||||||
CheckForJSErrors();
|
CheckForJSErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GoToInvoices()
|
public void GoToInvoice(string id)
|
||||||
{
|
{
|
||||||
GoToHome();
|
GoToUrl($"/invoices/{id}/");
|
||||||
Driver.FindElement(By.Id("Nav-Invoices")).Click();
|
}
|
||||||
|
|
||||||
|
public void GoToInvoices(string storeId = null)
|
||||||
|
{
|
||||||
|
GoToUrl(storeId == null ? "/invoices/" : $"/stores/{storeId}/invoices/");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GoToProfile(ManageNavPages navPages = ManageNavPages.Index)
|
public void GoToProfile(ManageNavPages navPages = ManageNavPages.Index)
|
||||||
@@ -394,11 +398,11 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
public void GoToLogin()
|
public void GoToLogin()
|
||||||
{
|
{
|
||||||
Driver.Navigate().GoToUrl(new Uri(ServerUri, "/login"));
|
GoToUrl("/login");
|
||||||
}
|
}
|
||||||
|
|
||||||
public string CreateInvoice(
|
public string CreateInvoice(
|
||||||
string storeName,
|
string storeId,
|
||||||
decimal? amount = 100,
|
decimal? amount = 100,
|
||||||
string currency = "USD",
|
string currency = "USD",
|
||||||
string refundEmail = "",
|
string refundEmail = "",
|
||||||
@@ -407,7 +411,7 @@ namespace BTCPayServer.Tests
|
|||||||
StatusMessageModel.StatusSeverity expectedSeverity = StatusMessageModel.StatusSeverity.Success
|
StatusMessageModel.StatusSeverity expectedSeverity = StatusMessageModel.StatusSeverity.Success
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
GoToInvoices();
|
GoToInvoices(storeId);
|
||||||
Driver.FindElement(By.Id("CreateNewInvoice")).Click();
|
Driver.FindElement(By.Id("CreateNewInvoice")).Click();
|
||||||
if (amount is decimal v)
|
if (amount is decimal v)
|
||||||
Driver.FindElement(By.Id("Amount")).SendKeys(v.ToString(CultureInfo.InvariantCulture));
|
Driver.FindElement(By.Id("Amount")).SendKeys(v.ToString(CultureInfo.InvariantCulture));
|
||||||
@@ -415,7 +419,6 @@ namespace BTCPayServer.Tests
|
|||||||
currencyEl.Clear();
|
currencyEl.Clear();
|
||||||
currencyEl.SendKeys(currency);
|
currencyEl.SendKeys(currency);
|
||||||
Driver.FindElement(By.Id("BuyerEmail")).SendKeys(refundEmail);
|
Driver.FindElement(By.Id("BuyerEmail")).SendKeys(refundEmail);
|
||||||
Driver.FindElement(By.Name("StoreId")).SendKeys(storeName);
|
|
||||||
if (defaultPaymentMethod is string)
|
if (defaultPaymentMethod is string)
|
||||||
new SelectElement(Driver.FindElement(By.Name("DefaultPaymentMethod"))).SelectByValue(defaultPaymentMethod);
|
new SelectElement(Driver.FindElement(By.Name("DefaultPaymentMethod"))).SelectByValue(defaultPaymentMethod);
|
||||||
if (requiresRefundEmail is bool)
|
if (requiresRefundEmail is bool)
|
||||||
@@ -501,18 +504,5 @@ namespace BTCPayServer.Tests
|
|||||||
Driver.FindElement(By.Id($"SectionNav-{navPages}")).Click();
|
Driver.FindElement(By.Id($"SectionNav-{navPages}")).Click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GoToInvoice(string id)
|
|
||||||
{
|
|
||||||
GoToInvoices();
|
|
||||||
foreach (var el in Driver.FindElements(By.ClassName("invoice-details-link")))
|
|
||||||
{
|
|
||||||
if (el.GetAttribute("href").Contains(id, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
el.Click();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ namespace BTCPayServer.Tests
|
|||||||
s.Server.ActivateLightning();
|
s.Server.ActivateLightning();
|
||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
var alice = s.RegisterNewUser(true);
|
var alice = s.RegisterNewUser(true);
|
||||||
var (storeName, storeId) = s.CreateNewStore();
|
(string storeName, string storeId) = s.CreateNewStore();
|
||||||
var onchainHint = "Set up your wallet to receive payments at your store.";
|
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.";
|
var offchainHint = "A connection to a Lightning node is required to receive Lightning payments.";
|
||||||
|
|
||||||
@@ -392,8 +392,8 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
var storeUrl = s.Driver.Url;
|
var storeUrl = s.Driver.Url;
|
||||||
s.ClickOnAllSectionLinks();
|
s.ClickOnAllSectionLinks();
|
||||||
s.GoToInvoices();
|
s.GoToInvoices(storeId);
|
||||||
var invoiceId = s.CreateInvoice(storeName);
|
var invoiceId = s.CreateInvoice(storeId);
|
||||||
s.FindAlertMessage();
|
s.FindAlertMessage();
|
||||||
s.Driver.FindElement(By.ClassName("invoice-details-link")).Click();
|
s.Driver.FindElement(By.ClassName("invoice-details-link")).Click();
|
||||||
var invoiceUrl = s.Driver.Url;
|
var invoiceUrl = s.Driver.Url;
|
||||||
@@ -402,16 +402,17 @@ namespace BTCPayServer.Tests
|
|||||||
Assert.DoesNotContain("Archived", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text);
|
Assert.DoesNotContain("Archived", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text);
|
||||||
s.Driver.FindElement(By.Id("btn-archive-toggle")).Click();
|
s.Driver.FindElement(By.Id("btn-archive-toggle")).Click();
|
||||||
Assert.Contains("Unarchive", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text);
|
Assert.Contains("Unarchive", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text);
|
||||||
|
|
||||||
//check that it no longer appears in list
|
//check that it no longer appears in list
|
||||||
s.GoToInvoices();
|
s.GoToInvoices(storeId);
|
||||||
|
|
||||||
Assert.DoesNotContain(invoiceId, s.Driver.PageSource);
|
Assert.DoesNotContain(invoiceId, s.Driver.PageSource);
|
||||||
|
|
||||||
//ok, let's unarchive and see that it shows again
|
//ok, let's unarchive and see that it shows again
|
||||||
s.Driver.Navigate().GoToUrl(invoiceUrl);
|
s.Driver.Navigate().GoToUrl(invoiceUrl);
|
||||||
s.Driver.FindElement(By.Id("btn-archive-toggle")).Click();
|
s.Driver.FindElement(By.Id("btn-archive-toggle")).Click();
|
||||||
s.FindAlertMessage();
|
s.FindAlertMessage();
|
||||||
Assert.DoesNotContain("Unarchive", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text);
|
Assert.DoesNotContain("Unarchive", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text);
|
||||||
s.GoToInvoices();
|
s.GoToInvoices(storeId);
|
||||||
Assert.Contains(invoiceId, s.Driver.PageSource);
|
Assert.Contains(invoiceId, s.Driver.PageSource);
|
||||||
|
|
||||||
// When logout out we should not be able to access store and invoice details
|
// When logout out we should not be able to access store and invoice details
|
||||||
@@ -614,7 +615,7 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
s.RegisterNewUser(true);
|
s.RegisterNewUser(true);
|
||||||
var (_, storeId) = s.CreateNewStore();
|
(_, string storeId) = s.CreateNewStore();
|
||||||
s.GenerateWallet("BTC", "", false, true);
|
s.GenerateWallet("BTC", "", false, true);
|
||||||
var walletId = new WalletId(storeId, "BTC");
|
var walletId = new WalletId(storeId, "BTC");
|
||||||
s.GoToWallet(walletId, WalletsNavPages.Receive);
|
s.GoToWallet(walletId, WalletsNavPages.Receive);
|
||||||
@@ -676,7 +677,7 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
s.RegisterNewUser(true);
|
s.RegisterNewUser(true);
|
||||||
var (storeName, storeId) = s.CreateNewStore();
|
(_, string storeId) = s.CreateNewStore();
|
||||||
s.GoToStore(storeId, StoreNavPages.Webhooks);
|
s.GoToStore(storeId, StoreNavPages.Webhooks);
|
||||||
|
|
||||||
TestLogs.LogInformation("Let's create two webhooks");
|
TestLogs.LogInformation("Let's create two webhooks");
|
||||||
@@ -733,7 +734,7 @@ namespace BTCPayServer.Tests
|
|||||||
TestLogs.LogInformation("Let's see if we can generate an event");
|
TestLogs.LogInformation("Let's see if we can generate an event");
|
||||||
s.GoToStore(storeId);
|
s.GoToStore(storeId);
|
||||||
s.AddDerivationScheme();
|
s.AddDerivationScheme();
|
||||||
s.CreateInvoice(storeName);
|
s.CreateInvoice(storeId);
|
||||||
var request = await server.GetNextRequest();
|
var request = await server.GetNextRequest();
|
||||||
var headers = request.Request.Headers;
|
var headers = request.Request.Headers;
|
||||||
var actualSig = headers["BTCPay-Sig"].First();
|
var actualSig = headers["BTCPay-Sig"].First();
|
||||||
@@ -745,14 +746,14 @@ namespace BTCPayServer.Tests
|
|||||||
server.Done();
|
server.Done();
|
||||||
|
|
||||||
TestLogs.LogInformation("Let's make a failed event");
|
TestLogs.LogInformation("Let's make a failed event");
|
||||||
s.CreateInvoice(storeName);
|
s.CreateInvoice(storeId);
|
||||||
request = await server.GetNextRequest();
|
request = await server.GetNextRequest();
|
||||||
request.Response.StatusCode = 404;
|
request.Response.StatusCode = 404;
|
||||||
server.Done();
|
server.Done();
|
||||||
|
|
||||||
// The delivery is done asynchronously, so small wait here
|
// The delivery is done asynchronously, so small wait here
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
s.GoToStore(storeId, Views.Stores.StoreNavPages.Webhooks);
|
s.GoToStore(storeId, StoreNavPages.Webhooks);
|
||||||
s.Driver.FindElement(By.LinkText("Modify")).Click();
|
s.Driver.FindElement(By.LinkText("Modify")).Click();
|
||||||
var elements = s.Driver.FindElements(By.ClassName("redeliver"));
|
var elements = s.Driver.FindElements(By.ClassName("redeliver"));
|
||||||
// One worked, one failed
|
// One worked, one failed
|
||||||
@@ -768,7 +769,7 @@ namespace BTCPayServer.Tests
|
|||||||
TestLogs.LogInformation("Can we browse the json content?");
|
TestLogs.LogInformation("Can we browse the json content?");
|
||||||
CanBrowseContent(s);
|
CanBrowseContent(s);
|
||||||
|
|
||||||
s.GoToInvoices();
|
s.GoToInvoices(storeId);
|
||||||
s.Driver.FindElement(By.LinkText("Details")).Click();
|
s.Driver.FindElement(By.LinkText("Details")).Click();
|
||||||
CanBrowseContent(s);
|
CanBrowseContent(s);
|
||||||
var element = s.Driver.FindElement(By.ClassName("redeliver"));
|
var element = s.Driver.FindElement(By.ClassName("redeliver"));
|
||||||
@@ -798,7 +799,7 @@ namespace BTCPayServer.Tests
|
|||||||
foreach (var isHotwallet in new[] { false, true })
|
foreach (var isHotwallet in new[] { false, true })
|
||||||
{
|
{
|
||||||
var cryptoCode = "BTC";
|
var cryptoCode = "BTC";
|
||||||
var (_, storeId) = s.CreateNewStore();
|
(_, string storeId) = s.CreateNewStore();
|
||||||
s.GenerateWallet(cryptoCode, "melody lizard phrase voice unique car opinion merge degree evil swift cargo", privkeys: isHotwallet);
|
s.GenerateWallet(cryptoCode, "melody lizard phrase voice unique car opinion merge degree evil swift cargo", privkeys: isHotwallet);
|
||||||
s.GoToWalletSettings(storeId, cryptoCode);
|
s.GoToWalletSettings(storeId, cryptoCode);
|
||||||
if (isHotwallet)
|
if (isHotwallet)
|
||||||
@@ -816,7 +817,7 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
s.RegisterNewUser(true);
|
s.RegisterNewUser(true);
|
||||||
(string storeName, string storeId) = s.CreateNewStore();
|
(_, string storeId) = s.CreateNewStore();
|
||||||
const string cryptoCode = "BTC";
|
const string cryptoCode = "BTC";
|
||||||
|
|
||||||
// In this test, we try to spend from a manual seed. We import the xpub 49'/0'/0',
|
// In this test, we try to spend from a manual seed. We import the xpub 49'/0'/0',
|
||||||
@@ -865,7 +866,7 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
Assert.NotEqual(receiveAddr, s.Driver.FindElement(By.Id("address")).GetAttribute("value"));
|
Assert.NotEqual(receiveAddr, s.Driver.FindElement(By.Id("address")).GetAttribute("value"));
|
||||||
|
|
||||||
var invoiceId = s.CreateInvoice(storeName);
|
var invoiceId = s.CreateInvoice(storeId);
|
||||||
var invoice = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);
|
var invoice = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);
|
||||||
var address = invoice.EntityToDTO().Addresses["BTC"];
|
var address = invoice.EntityToDTO().Addresses["BTC"];
|
||||||
|
|
||||||
@@ -878,7 +879,7 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
//lets import and save private keys
|
//lets import and save private keys
|
||||||
var root = mnemonic.DeriveExtKey();
|
var root = mnemonic.DeriveExtKey();
|
||||||
invoiceId = s.CreateInvoice(storeName);
|
invoiceId = s.CreateInvoice(storeId);
|
||||||
invoice = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);
|
invoice = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);
|
||||||
address = invoice.EntityToDTO().Addresses["BTC"];
|
address = invoice.EntityToDTO().Addresses["BTC"];
|
||||||
result = await s.Server.ExplorerNode.GetAddressInfoAsync(
|
result = await s.Server.ExplorerNode.GetAddressInfoAsync(
|
||||||
@@ -978,8 +979,8 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
s.RegisterNewUser(true);
|
s.RegisterNewUser(true);
|
||||||
(string _, string storeId) = s.CreateNewStore();
|
(_, string storeId) = s.CreateNewStore();
|
||||||
var cryptoCode = "BTC";
|
const string cryptoCode = "BTC";
|
||||||
var mnemonic = s.GenerateWallet(cryptoCode, "click chunk owner kingdom faint steak safe evidence bicycle repeat bulb wheel");
|
var mnemonic = s.GenerateWallet(cryptoCode, "click chunk owner kingdom faint steak safe evidence bicycle repeat bulb wheel");
|
||||||
|
|
||||||
// Make sure wallet info is correct
|
// Make sure wallet info is correct
|
||||||
@@ -1294,7 +1295,7 @@ namespace BTCPayServer.Tests
|
|||||||
new[] { s.Server.MerchantLightningD },
|
new[] { s.Server.MerchantLightningD },
|
||||||
new[] { s.Server.MerchantLnd.Client });
|
new[] { s.Server.MerchantLnd.Client });
|
||||||
s.RegisterNewUser(true);
|
s.RegisterNewUser(true);
|
||||||
(string storeName, string storeId) = s.CreateNewStore();
|
(_, string storeId) = s.CreateNewStore();
|
||||||
var network = s.Server.NetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode).NBitcoinNetwork;
|
var network = s.Server.NetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode).NBitcoinNetwork;
|
||||||
s.GoToStore(storeId);
|
s.GoToStore(storeId);
|
||||||
s.AddLightningNode(cryptoCode, LightningConnectionType.CLightning, false);
|
s.AddLightningNode(cryptoCode, LightningConnectionType.CLightning, false);
|
||||||
@@ -1307,7 +1308,7 @@ namespace BTCPayServer.Tests
|
|||||||
SudoForceSaveLightningSettingsRightNowAndFast(s, cryptoCode);
|
SudoForceSaveLightningSettingsRightNowAndFast(s, cryptoCode);
|
||||||
|
|
||||||
// Topup Invoice test
|
// Topup Invoice test
|
||||||
var i = s.CreateInvoice(storeName, null, cryptoCode);
|
var i = s.CreateInvoice(storeId, null, cryptoCode);
|
||||||
s.GoToInvoiceCheckout(i);
|
s.GoToInvoiceCheckout(i);
|
||||||
s.Driver.FindElement(By.Id("copy-tab")).Click();
|
s.Driver.FindElement(By.Id("copy-tab")).Click();
|
||||||
var lnurl = s.Driver.FindElement(By.CssSelector("input.checkoutTextbox")).GetAttribute("value");
|
var lnurl = s.Driver.FindElement(By.CssSelector("input.checkoutTextbox")).GetAttribute("value");
|
||||||
@@ -1339,8 +1340,8 @@ namespace BTCPayServer.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Standard invoice test
|
// Standard invoice test
|
||||||
s.GoToHome();
|
s.GoToStore(storeId);
|
||||||
i = s.CreateInvoice(storeName, 0.0000001m, cryptoCode);
|
i = s.CreateInvoice(storeId, 0.0000001m, cryptoCode);
|
||||||
s.GoToInvoiceCheckout(i);
|
s.GoToInvoiceCheckout(i);
|
||||||
s.Driver.FindElement(By.ClassName("payment__currencies")).Click();
|
s.Driver.FindElement(By.ClassName("payment__currencies")).Click();
|
||||||
// BOLT11 is also available for standard invoices
|
// BOLT11 is also available for standard invoices
|
||||||
@@ -1382,12 +1383,12 @@ namespace BTCPayServer.Tests
|
|||||||
s.Driver.FindElement(By.Id("save")).Click();
|
s.Driver.FindElement(By.Id("save")).Click();
|
||||||
Assert.Contains($"{cryptoCode} Lightning settings successfully updated", s.FindAlertMessage().Text);
|
Assert.Contains($"{cryptoCode} Lightning settings successfully updated", s.FindAlertMessage().Text);
|
||||||
|
|
||||||
i = s.CreateInvoice(storeName, 0.000001m, cryptoCode);
|
i = s.CreateInvoice(storeId, 0.000001m, cryptoCode);
|
||||||
s.GoToInvoiceCheckout(i);
|
s.GoToInvoiceCheckout(i);
|
||||||
s.Driver.FindElement(By.ClassName("payment__currencies_noborder"));
|
s.Driver.FindElement(By.ClassName("payment__currencies_noborder"));
|
||||||
|
|
||||||
s.GoToHome();
|
s.GoToStore(storeId);
|
||||||
i = s.CreateInvoice(storeName, null, cryptoCode);
|
i = s.CreateInvoice(storeId, null, cryptoCode);
|
||||||
s.GoToInvoiceCheckout(i);
|
s.GoToInvoiceCheckout(i);
|
||||||
s.Driver.FindElement(By.ClassName("payment__currencies_noborder"));
|
s.Driver.FindElement(By.ClassName("payment__currencies_noborder"));
|
||||||
|
|
||||||
@@ -1409,9 +1410,9 @@ namespace BTCPayServer.Tests
|
|||||||
//even though we set DisableBolt11PaymentMethod to true, logic when saving it turns it back off as otherwise no lightning option is available at all!
|
//even though we set DisableBolt11PaymentMethod to true, logic when saving it turns it back off as otherwise no lightning option is available at all!
|
||||||
Assert.False(s.Driver.FindElement(By.Id("DisableBolt11PaymentMethod")).Selected);
|
Assert.False(s.Driver.FindElement(By.Id("DisableBolt11PaymentMethod")).Selected);
|
||||||
// Invoice creation should fail, because it is a standard invoice with amount, but DisableBolt11PaymentMethod = true and LNURLStandardInvoiceEnabled = false
|
// Invoice creation should fail, because it is a standard invoice with amount, but DisableBolt11PaymentMethod = true and LNURLStandardInvoiceEnabled = false
|
||||||
s.CreateInvoice(storeName, 0.0000001m, cryptoCode,"",null, expectedSeverity: StatusMessageModel.StatusSeverity.Success);
|
s.CreateInvoice(storeId, 0.0000001m, cryptoCode,"",null, expectedSeverity: StatusMessageModel.StatusSeverity.Success);
|
||||||
|
|
||||||
i = s.CreateInvoice(storeName, null, cryptoCode);
|
i = s.CreateInvoice(storeId, null, cryptoCode);
|
||||||
s.GoToInvoiceCheckout(i);
|
s.GoToInvoiceCheckout(i);
|
||||||
s.Driver.FindElement(By.ClassName("payment__currencies_noborder"));
|
s.Driver.FindElement(By.ClassName("payment__currencies_noborder"));
|
||||||
s.Driver.FindElement(By.Id("copy-tab")).Click();
|
s.Driver.FindElement(By.Id("copy-tab")).Click();
|
||||||
@@ -1427,7 +1428,7 @@ namespace BTCPayServer.Tests
|
|||||||
s.Driver.SetCheckbox(By.Id("DisableBolt11PaymentMethod"), true);
|
s.Driver.SetCheckbox(By.Id("DisableBolt11PaymentMethod"), true);
|
||||||
s.Driver.FindElement(By.Id("save")).Click();
|
s.Driver.FindElement(By.Id("save")).Click();
|
||||||
Assert.Contains($"{cryptoCode} Lightning settings successfully updated", s.FindAlertMessage().Text);
|
Assert.Contains($"{cryptoCode} Lightning settings successfully updated", s.FindAlertMessage().Text);
|
||||||
var invForPP = s.CreateInvoice(newStore.storeName, 0.0000001m, cryptoCode);
|
var invForPP = s.CreateInvoice(newStore.storeId, 0.0000001m, cryptoCode);
|
||||||
s.GoToInvoiceCheckout(invForPP);
|
s.GoToInvoiceCheckout(invForPP);
|
||||||
s.Driver.FindElement(By.Id("copy-tab")).Click();
|
s.Driver.FindElement(By.Id("copy-tab")).Click();
|
||||||
lnurl = s.Driver.FindElement(By.CssSelector("input.checkoutTextbox")).GetAttribute("value");
|
lnurl = s.Driver.FindElement(By.CssSelector("input.checkoutTextbox")).GetAttribute("value");
|
||||||
@@ -1486,25 +1487,19 @@ namespace BTCPayServer.Tests
|
|||||||
s.RegisterNewUser(true);
|
s.RegisterNewUser(true);
|
||||||
//ln address tests
|
//ln address tests
|
||||||
s.CreateNewStore();
|
s.CreateNewStore();
|
||||||
s.GoToStore(s.StoreId, StoreNavPages.Integrations);
|
|
||||||
//ensure ln address is not available as Lightning is not enable
|
//ensure ln address is not available as Lightning is not enable
|
||||||
s.Driver.FindElement(By.Id("lightning-address-option"))
|
s.Driver.AssertElementNotFound(By.Id("StoreNav-LightningAddress"));
|
||||||
.FindElement(By.LinkText("You need to setup Lightning first"));
|
|
||||||
|
|
||||||
s.GoToStore(s.StoreId);
|
s.GoToStore(s.StoreId);
|
||||||
s.AddLightningNode("BTC", LightningConnectionType.LndREST, false);
|
s.AddLightningNode("BTC", LightningConnectionType.LndREST, false);
|
||||||
s.GoToStore(s.StoreId, StoreNavPages.Integrations);
|
|
||||||
//ensure ln address is not available as lnurl is not configured
|
//ensure ln address is not available as lnurl is not configured
|
||||||
s.Driver.FindElement(By.Id("lightning-address-option"))
|
s.Driver.AssertElementNotFound(By.Id("StoreNav-LightningAddress"));
|
||||||
.FindElement(By.LinkText("You need LNURL configured first"));
|
|
||||||
|
|
||||||
s.GoToLightningSettings(s.StoreId, cryptoCode);
|
s.GoToLightningSettings(s.StoreId, cryptoCode);
|
||||||
s.Driver.SetCheckbox(By.Id("LNURLEnabled"), true);
|
s.Driver.SetCheckbox(By.Id("LNURLEnabled"), true);
|
||||||
SudoForceSaveLightningSettingsRightNowAndFast(s, cryptoCode);
|
SudoForceSaveLightningSettingsRightNowAndFast(s, cryptoCode);
|
||||||
|
|
||||||
s.GoToStore(s.StoreId, StoreNavPages.Integrations);
|
s.Driver.FindElement(By.Id("StoreNav-LightningAddress")).Click();
|
||||||
s.Driver.FindElement(By.Id("lightning-address-option"))
|
|
||||||
.FindElement(By.Id("lightning-address-setup-link")).Click();
|
|
||||||
|
|
||||||
s.Driver.ToggleCollapse("AddAddress");
|
s.Driver.ToggleCollapse("AddAddress");
|
||||||
var lnaddress1 = Guid.NewGuid().ToString();
|
var lnaddress1 = Guid.NewGuid().ToString();
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ namespace BTCPayServer.Tests
|
|||||||
tester.PayTester.MockRates = false;
|
tester.PayTester.MockRates = false;
|
||||||
await tester.StartAsync();
|
await tester.StartAsync();
|
||||||
var user = tester.NewAccount();
|
var user = tester.NewAccount();
|
||||||
user.GrantAccess();
|
await user.GrantAccessAsync();
|
||||||
user.RegisterDerivationScheme("BTC");
|
user.RegisterDerivationScheme("BTC");
|
||||||
List<decimal> rates = new List<decimal>();
|
List<decimal> rates = new List<decimal>();
|
||||||
rates.Add(await CreateInvoice(tester, user, "coingecko"));
|
rates.Add(await CreateInvoice(tester, user, "coingecko"));
|
||||||
|
|||||||
@@ -794,11 +794,11 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
await tester.StartAsync();
|
await tester.StartAsync();
|
||||||
var acc = tester.NewAccount();
|
var acc = tester.NewAccount();
|
||||||
acc.GrantAccess();
|
await acc.GrantAccessAsync();
|
||||||
acc.RegisterDerivationScheme("BTC");
|
acc.RegisterDerivationScheme("BTC");
|
||||||
// First we try payment with a merchant having only BTC
|
// First we try payment with a merchant having only BTC
|
||||||
var invoice = acc.BitPay.CreateInvoice(
|
var invoice = await acc.BitPay.CreateInvoiceAsync(
|
||||||
new Invoice()
|
new Invoice
|
||||||
{
|
{
|
||||||
Price = 500,
|
Price = 500,
|
||||||
Currency = "USD",
|
Currency = "USD",
|
||||||
@@ -811,21 +811,22 @@ namespace BTCPayServer.Tests
|
|||||||
var cashCow = tester.ExplorerNode;
|
var cashCow = tester.ExplorerNode;
|
||||||
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, cashCow.Network);
|
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, cashCow.Network);
|
||||||
var firstPayment = invoice.CryptoInfo[0].TotalDue - Money.Satoshis(10);
|
var firstPayment = invoice.CryptoInfo[0].TotalDue - Money.Satoshis(10);
|
||||||
cashCow.SendToAddress(invoiceAddress, firstPayment);
|
await cashCow.SendToAddressAsync(invoiceAddress, firstPayment);
|
||||||
TestUtils.Eventually(() =>
|
TestUtils.Eventually(() =>
|
||||||
{
|
{
|
||||||
invoice = acc.BitPay.GetInvoice(invoice.Id);
|
invoice = acc.BitPay.GetInvoice(invoice.Id);
|
||||||
Assert.Equal(firstPayment, invoice.CryptoInfo[0].Paid);
|
Assert.Equal(firstPayment, invoice.CryptoInfo[0].Paid);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AssertSearchInvoice(acc, true, invoice.Id, null);
|
||||||
|
AssertSearchInvoice(acc, true, invoice.Id, null, acc.StoreId);
|
||||||
AssertSearchInvoice(acc, true, invoice.Id, $"storeid:{acc.StoreId}");
|
AssertSearchInvoice(acc, true, invoice.Id, $"storeid:{acc.StoreId}");
|
||||||
AssertSearchInvoice(acc, false, invoice.Id, $"storeid:blah");
|
AssertSearchInvoice(acc, false, invoice.Id, "storeid:doesnotexist");
|
||||||
AssertSearchInvoice(acc, true, invoice.Id, $"{invoice.Id}");
|
AssertSearchInvoice(acc, true, invoice.Id, $"{invoice.Id}");
|
||||||
AssertSearchInvoice(acc, true, invoice.Id, $"exceptionstatus:paidPartial");
|
AssertSearchInvoice(acc, true, invoice.Id, "exceptionstatus:paidPartial");
|
||||||
AssertSearchInvoice(acc, false, invoice.Id, $"exceptionstatus:paidOver");
|
AssertSearchInvoice(acc, false, invoice.Id, "exceptionstatus:paidOver");
|
||||||
AssertSearchInvoice(acc, true, invoice.Id, $"unusual:true");
|
AssertSearchInvoice(acc, true, invoice.Id, "unusual:true");
|
||||||
AssertSearchInvoice(acc, false, invoice.Id, $"unusual:false");
|
AssertSearchInvoice(acc, false, invoice.Id, "unusual:false");
|
||||||
|
|
||||||
var time = invoice.InvoiceTime;
|
var time = invoice.InvoiceTime;
|
||||||
AssertSearchInvoice(acc, true, invoice.Id, $"startdate:{time.ToString("yyyy-MM-dd HH:mm:ss")}");
|
AssertSearchInvoice(acc, true, invoice.Id, $"startdate:{time.ToString("yyyy-MM-dd HH:mm:ss")}");
|
||||||
@@ -929,11 +930,11 @@ namespace BTCPayServer.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AssertSearchInvoice(TestAccount acc, bool expected, string invoiceId, string filter)
|
private void AssertSearchInvoice(TestAccount acc, bool expected, string invoiceId, string filter, string storeId = null)
|
||||||
{
|
{
|
||||||
var result =
|
var result =
|
||||||
(InvoicesModel)((ViewResult)acc.GetController<InvoiceController>()
|
(InvoicesModel)((ViewResult)acc.GetController<InvoiceController>()
|
||||||
.ListInvoices(new InvoicesModel { SearchTerm = filter }).Result).Model;
|
.ListInvoices(new InvoicesModel { SearchTerm = filter, StoreId = storeId }).Result).Model;
|
||||||
Assert.Equal(expected, result.Invoices.Any(i => i.InvoiceId == invoiceId));
|
Assert.Equal(expected, result.Invoices.Any(i => i.InvoiceId == invoiceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,59 +23,7 @@
|
|||||||
<div class="accordion px-3 px-lg-4">
|
<div class="accordion px-3 px-lg-4">
|
||||||
@if (SignInManager.IsSignedIn(User))
|
@if (SignInManager.IsSignedIn(User))
|
||||||
{
|
{
|
||||||
@if (Model.Store == null)
|
@if (Model.Store != null)
|
||||||
{
|
|
||||||
<div class="accordion-item">
|
|
||||||
<header class="accordion-header" id="Nav-Payments-Header">
|
|
||||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#Nav-Payments" aria-expanded="true" aria-controls="Nav-Payments">
|
|
||||||
Payments
|
|
||||||
<vc:icon symbol="caret-down"/>
|
|
||||||
</button>
|
|
||||||
</header>
|
|
||||||
<div id="Nav-Payments" class="accordion-collapse collapse show" aria-labelledby="Nav-Payments-Header">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<ul class="navbar-nav">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a asp-area="" asp-controller="Invoice" asp-action="ListInvoices" class="nav-link js-scroll-trigger @ViewData.IsActiveCategory(typeof(InvoiceNavPages))" id="Nav-Invoices">
|
|
||||||
<vc:icon symbol="invoice"/>
|
|
||||||
<span>Invoices</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
@* FIXME: The wallets item is in here only for the tests *@
|
|
||||||
<li class="nav-item">
|
|
||||||
<a asp-area="" asp-controller="Wallets" asp-action="ListWallets" class="nav-link js-scroll-trigger @ViewData.IsActiveCategory(typeof(WalletsNavPages))" id="Nav-Wallets">
|
|
||||||
<vc:icon symbol="wallet-onchain"/>
|
|
||||||
<span>Wallets</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="accordion-item" permission="@Policies.CanModifyServerSettings">
|
|
||||||
<header class="accordion-header" id="Nav-Plugins-Header">
|
|
||||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#Nav-Plugins" aria-expanded="true" aria-controls="Nav-Plugins">
|
|
||||||
Plugins
|
|
||||||
<vc:icon symbol="caret-down"/>
|
|
||||||
</button>
|
|
||||||
</header>
|
|
||||||
<div id="Nav-Plugins" class="accordion-collapse collapse show" aria-labelledby="Nav-Plugins-Header">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<ul class="navbar-nav">
|
|
||||||
<vc:ui-extension-point location="header-nav" model="@Model"/>
|
|
||||||
@* TODO: Limit this to admins *@
|
|
||||||
<li class="nav-item">
|
|
||||||
<a asp-area="" asp-controller="Server" asp-action="ListPlugins" class="nav-link js-scroll-trigger @ViewData.IsActivePage(ServerNavPages.Plugins)" id="Nav-AddPlugin">
|
|
||||||
<vc:icon symbol="new"/>
|
|
||||||
<span>Add Plugin</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
<div class="accordion-item" permission="@Policies.CanModifyStoreSettings">
|
<div class="accordion-item" permission="@Policies.CanModifyStoreSettings">
|
||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
@@ -84,16 +32,16 @@
|
|||||||
{
|
{
|
||||||
var isSetUp = !string.IsNullOrWhiteSpace(scheme.Value);
|
var isSetUp = !string.IsNullOrWhiteSpace(scheme.Value);
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
@if (isSetUp)
|
@if (isSetUp && scheme.WalletSupported)
|
||||||
{
|
{
|
||||||
<a asp-area="" asp-controller="Stores" asp-action="WalletSettings" asp-route-cryptoCode="@scheme.Crypto" asp-route-storeId="@Model.Store.Id" class="nav-link" id="@($"StoreNav-Modify{scheme.Crypto}")">
|
<a asp-area="" asp-controller="Wallets" asp-action="WalletTransactions" asp-route-walletId="@scheme.WalletId"class="nav-link js-scroll-trigger @ViewData.IsActiveCategory(typeof(WalletsNavPages), scheme.WalletId.ToString()) @ViewData.IsActivePage(StoreNavPages.OnchainSettings)" id="@($"StoreNav-Wallet{scheme.Crypto}")">
|
||||||
<span class="me-2 btcpay-status btcpay-status--@(scheme.Enabled ? "enabled" : "disabled")"></span>
|
<span class="me-2 btcpay-status btcpay-status--@(scheme.Enabled ? "enabled" : "disabled")"></span>
|
||||||
<span>@(Model.AltcoinsBuild ? $"{scheme.Crypto} " : "")Wallet</span>
|
<span>@(Model.AltcoinsBuild ? $"{scheme.Crypto} " : "")Wallet</span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<a asp-area="" asp-controller="Stores" asp-action="SetupWallet" asp-route-cryptoCode="@scheme.Crypto" asp-route-storeId="@Model.Store.Id" class="nav-link" id="@($"StoreNav-Modify{scheme.Crypto}")">
|
<a asp-area="" asp-controller="Stores" 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}")">
|
||||||
<span class="me-2 btcpay-status btcpay-status--@(scheme.Enabled ? "enabled" : "disabled")"></span>
|
<span class="me-2 btcpay-status btcpay-status--@(scheme.Enabled ? "enabled" : "disabled")"></span>
|
||||||
<span>@(Model.AltcoinsBuild ? $"{scheme.Crypto} " : "")Wallet</span>
|
<span>@(Model.AltcoinsBuild ? $"{scheme.Crypto} " : "")Wallet</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -106,14 +54,14 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
@if (isSetUp)
|
@if (isSetUp)
|
||||||
{
|
{
|
||||||
<a asp-area="" asp-controller="Stores" asp-action="LightningSettings" asp-route-cryptoCode="@scheme.CryptoCode" asp-route-storeId="@Model.Store.Id" class="nav-link" id="@($"StoreNav-Lightning{scheme.CryptoCode}")">
|
<a asp-area="" asp-controller="Stores" asp-action="LightningSettings" asp-route-cryptoCode="@scheme.CryptoCode" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.IsActivePage(StoreNavPages.LightningSettings)" id="@($"StoreNav-Lightning{scheme.CryptoCode}")">
|
||||||
<span class="me-2 btcpay-status btcpay-status--@(scheme.Enabled ? "enabled" : "disabled")"></span>
|
<span class="me-2 btcpay-status btcpay-status--@(scheme.Enabled ? "enabled" : "disabled")"></span>
|
||||||
<span>@(Model.AltcoinsBuild ? $"{scheme.CryptoCode} " : "")Lightning</span>
|
<span>@(Model.AltcoinsBuild ? $"{scheme.CryptoCode} " : "")Lightning</span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<a asp-area="" asp-controller="Stores" asp-action="SetupLightningNode" asp-route-cryptoCode="@scheme.CryptoCode" asp-route-storeId="@Model.Store.Id" class="nav-link" id="@($"StoreNav-Lightning{scheme.CryptoCode}")">
|
<a asp-area="" asp-controller="Stores" asp-action="SetupLightningNode" asp-route-cryptoCode="@scheme.CryptoCode" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.IsActivePage(StoreNavPages.LightningSettings)" id="@($"StoreNav-Lightning{scheme.CryptoCode}")">
|
||||||
<span class="me-2 btcpay-status btcpay-status--disabled"></span>
|
<span class="me-2 btcpay-status btcpay-status--disabled"></span>
|
||||||
<span>@(Model.AltcoinsBuild ? $"{scheme.CryptoCode} " : "")Lightning</span>
|
<span>@(Model.AltcoinsBuild ? $"{scheme.CryptoCode} " : "")Lightning</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -134,19 +82,6 @@
|
|||||||
<div id="Nav-Payments" class="accordion-collapse collapse show" aria-labelledby="Nav-Payments-Header">
|
<div id="Nav-Payments" class="accordion-collapse collapse show" aria-labelledby="Nav-Payments-Header">
|
||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
@foreach (var scheme in Model.DerivationSchemes.OrderBy(scheme => scheme.Collapsed))
|
|
||||||
{
|
|
||||||
var isSetUp = !string.IsNullOrWhiteSpace(scheme.Value);
|
|
||||||
if (isSetUp && scheme.WalletSupported)
|
|
||||||
{
|
|
||||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
|
||||||
<a asp-area="" asp-controller="Wallets" asp-action="WalletTransactions" asp-route-walletId="@scheme.WalletId" class="nav-link js-scroll-trigger @ViewData.IsActiveCategory(typeof(WalletsNavPages), scheme.Crypto)" id="@($"StoreNav-Wallet{scheme.Crypto}")">
|
|
||||||
<vc:icon symbol="wallet-onchain"/>
|
|
||||||
<span>@(Model.AltcoinsBuild ? $"{scheme.Crypto} " : "")Wallet</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
||||||
<a asp-area="" asp-controller="Invoice" asp-action="ListInvoices" asp-route-storeId="@Model.Store.Id" class="nav-link js-scroll-trigger @ViewData.IsActiveCategory(typeof(InvoiceNavPages))" id="StoreNav-Invoices">
|
<a asp-area="" asp-controller="Invoice" asp-action="ListInvoices" asp-route-storeId="@Model.Store.Id" class="nav-link js-scroll-trigger @ViewData.IsActiveCategory(typeof(InvoiceNavPages))" id="StoreNav-Invoices">
|
||||||
<vc:icon symbol="invoice"/>
|
<vc:icon symbol="invoice"/>
|
||||||
@@ -171,6 +106,12 @@
|
|||||||
<span>Payouts</span>
|
<span>Payouts</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
||||||
|
<a asp-area="" asp-controller="Stores" asp-action="PayButton" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.IsActivePage(StoreNavPages.PayButton)" id="StoreNav-@(nameof(StoreNavPages.PayButton))">
|
||||||
|
<vc:icon symbol="payment-2"/>
|
||||||
|
<span>Pay Button</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -204,6 +145,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="accordion-item">
|
||||||
|
<header class="accordion-header" id="Nav-Plugins-Header">
|
||||||
|
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#Nav-Plugins" aria-expanded="true" aria-controls="Nav-Plugins">
|
||||||
|
Plugins
|
||||||
|
<vc:icon symbol="caret-down"/>
|
||||||
|
</button>
|
||||||
|
</header>
|
||||||
|
<div id="Nav-Plugins" class="accordion-collapse collapse show" aria-labelledby="Nav-Plugins-Header">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
<vc:ui-extension-point location="header-nav" model="@Model"/>
|
||||||
|
<vc:ui-extension-point location="store-integrations-nav" model="@Model" />
|
||||||
|
<li class="nav-item" permission="@Policies.CanModifyServerSettings">
|
||||||
|
<a asp-area="" asp-controller="Server" asp-action="ListPlugins" class="nav-link js-scroll-trigger @ViewData.IsActivePage(ServerNavPages.Plugins)" id="Nav-AddPlugin">
|
||||||
|
<vc:icon symbol="new"/>
|
||||||
|
<span>Add Plugin</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="accordion-item" permission="@Policies.CanModifyStoreSettings">
|
<div class="accordion-item" permission="@Policies.CanModifyStoreSettings">
|
||||||
<header class="accordion-header" id="Nav-Manage-Header">
|
<header class="accordion-header" id="Nav-Manage-Header">
|
||||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#Nav-Manage" aria-expanded="true" aria-controls="Nav-Manage">
|
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#Nav-Manage" aria-expanded="true" aria-controls="Nav-Manage">
|
||||||
@@ -215,7 +178,7 @@
|
|||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a asp-area="" asp-controller="Stores" asp-action="PaymentMethods" 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.GeneralSettings) @ViewData.IsActivePage(StoreNavPages.Tokens) @ViewData.IsActivePage(StoreNavPages.Users) @ViewData.IsActivePage(StoreNavPages.PayButton) @ViewData.IsActivePage(StoreNavPages.Integrations) @ViewData.IsActivePage(StoreNavPages.Webhooks)" id="StoreNav-Invoices">
|
<a asp-area="" asp-controller="Stores" asp-action="PaymentMethods" 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.GeneralSettings) @ViewData.IsActivePage(StoreNavPages.Tokens) @ViewData.IsActivePage(StoreNavPages.Users) @ViewData.IsActivePage(StoreNavPages.Webhooks)" id="StoreNav-StoreSettings">
|
||||||
<vc:icon symbol="settings"/>
|
<vc:icon symbol="settings"/>
|
||||||
<span>Store Settings</span>
|
<span>Store Settings</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -256,7 +219,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<ul id="mainNavSettings" class="navbar-nav border-top p-3 px-lg-4">
|
<ul id="mainNavSettings" class="navbar-nav border-top p-3 px-lg-4">
|
||||||
<li class="nav-item" permission="@Policies.CanModifyServerSettings">
|
<li class="nav-item" permission="@Policies.CanModifyServerSettings">
|
||||||
<a asp-area="" asp-controller="Server" asp-action="ListUsers" class="nav-link js-scroll-trigger @ViewData.IsActiveCategory(typeof(ServerNavPages))" id="Nav-ServerSettings">
|
<a asp-area="" asp-controller="Server" asp-action="ListUsers" class="nav-link js-scroll-trigger @ViewData.IsActivePage(ServerNavPages.Users) @ViewData.IsActivePage(ServerNavPages.Emails) @ViewData.IsActivePage(ServerNavPages.Policies) @ViewData.IsActivePage(ServerNavPages.Services) @ViewData.IsActivePage(ServerNavPages.Theme) @ViewData.IsActivePage(ServerNavPages.Maintenance) @ViewData.IsActivePage(ServerNavPages.Logs) @ViewData.IsActivePage(ServerNavPages.Files)" id="Nav-ServerSettings">
|
||||||
<vc:icon symbol="server-settings"/>
|
<vc:icon symbol="server-settings"/>
|
||||||
<span>Server Settings</span>
|
<span>Server Settings</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -264,7 +227,7 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a asp-area="" asp-controller="Manage" asp-action="Index" class="nav-link js-scroll-trigger @ViewData.IsActiveCategory(typeof(ManageNavPages))" id="Nav-Account">
|
<a asp-area="" asp-controller="Manage" asp-action="Index" class="nav-link js-scroll-trigger @ViewData.IsActiveCategory(typeof(ManageNavPages))" id="Nav-Account">
|
||||||
<vc:icon symbol="account"/>
|
<vc:icon symbol="account"/>
|
||||||
<span>Account</span>
|
<span class="text-truncate" style="max-width:195px">@User.Identity.Name</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@if (!theme.CustomTheme)
|
@if (!theme.CustomTheme)
|
||||||
|
|||||||
@@ -7,7 +7,16 @@
|
|||||||
<ul id="StoreSelectorMenu" class="dropdown-menu" aria-labelledby="StoreSelectorToggle">
|
<ul id="StoreSelectorMenu" class="dropdown-menu" aria-labelledby="StoreSelectorToggle">
|
||||||
@foreach (var option in Model.Options)
|
@foreach (var option in Model.Options)
|
||||||
{
|
{
|
||||||
<li><a asp-controller="Stores" asp-action="PaymentMethods" asp-route-storeId="@option.Value" class="dropdown-item@(option.Selected ? " active" : "")" id="StoreSelectorMenuItem-@option.Value">@option.Text</a></li>
|
<li>
|
||||||
|
@if (option.WalletId != null)
|
||||||
|
{
|
||||||
|
<a asp-controller="Wallets" asp-action="WalletTransactions" asp-route-walletId="@option.WalletId" class="dropdown-item@(option.Selected ? " active" : "")" id="StoreSelectorMenuItem-@option.Value">@option.Text</a>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a asp-controller="Stores" asp-action="PaymentMethods" asp-route-storeId="@option.Value" class="dropdown-item@(option.Selected ? " active" : "")" id="StoreSelectorMenuItem-@option.Value">@option.Text</a>
|
||||||
|
}
|
||||||
|
</li>
|
||||||
}
|
}
|
||||||
<li><hr class="dropdown-divider"></li>
|
<li><hr class="dropdown-divider"></li>
|
||||||
<li><a asp-controller="UserStores" asp-action="CreateStore" class="dropdown-item" id="StoreSelectorMenuItem-Create">Create Store</a></li>
|
<li><a asp-controller="UserStores" asp-action="CreateStore" class="dropdown-item" id="StoreSelectorMenuItem-Create">Create Store</a></li>
|
||||||
|
|||||||
@@ -5,20 +5,23 @@ using BTCPayServer.Services.Stores;
|
|||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
using NBitcoin.Secp256k1;
|
|
||||||
|
|
||||||
namespace BTCPayServer.Components.StoreSelector
|
namespace BTCPayServer.Components.StoreSelector
|
||||||
{
|
{
|
||||||
public class StoreSelector : ViewComponent
|
public class StoreSelector : ViewComponent
|
||||||
{
|
{
|
||||||
private const string RootName = "Global";
|
|
||||||
private readonly StoreRepository _storeRepo;
|
private readonly StoreRepository _storeRepo;
|
||||||
|
private readonly BTCPayNetworkProvider _networkProvider;
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
|
||||||
public StoreSelector(StoreRepository storeRepo, UserManager<ApplicationUser> userManager)
|
public StoreSelector(
|
||||||
|
StoreRepository storeRepo,
|
||||||
|
BTCPayNetworkProvider networkProvider,
|
||||||
|
UserManager<ApplicationUser> userManager)
|
||||||
{
|
{
|
||||||
_storeRepo = storeRepo;
|
_storeRepo = storeRepo;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
|
_networkProvider = networkProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IViewComponentResult> InvokeAsync()
|
public async Task<IViewComponentResult> InvokeAsync()
|
||||||
@@ -27,11 +30,21 @@ namespace BTCPayServer.Components.StoreSelector
|
|||||||
var stores = await _storeRepo.GetStoresByUserId(userId);
|
var stores = await _storeRepo.GetStoresByUserId(userId);
|
||||||
var currentStore = ViewContext.HttpContext.GetStoreData();
|
var currentStore = ViewContext.HttpContext.GetStoreData();
|
||||||
var options = stores
|
var options = stores
|
||||||
.Select(store => new SelectListItem
|
.Select(store =>
|
||||||
{
|
{
|
||||||
Text = store.StoreName,
|
var cryptoCode = store
|
||||||
Value = store.Id,
|
.GetSupportedPaymentMethods(_networkProvider)
|
||||||
Selected = store.Id == currentStore?.Id
|
.OfType<DerivationSchemeSettings>()
|
||||||
|
.FirstOrDefault()?
|
||||||
|
.Network.CryptoCode;
|
||||||
|
var walletId = cryptoCode != null ? new WalletId(store.Id, cryptoCode) : null;
|
||||||
|
return new StoreSelectorOption
|
||||||
|
{
|
||||||
|
Text = store.StoreName,
|
||||||
|
Value = store.Id,
|
||||||
|
Selected = store.Id == currentStore?.Id,
|
||||||
|
WalletId = walletId
|
||||||
|
};
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
@@ -39,7 +52,7 @@ namespace BTCPayServer.Components.StoreSelector
|
|||||||
{
|
{
|
||||||
Options = options,
|
Options = options,
|
||||||
CurrentStoreId = currentStore?.Id,
|
CurrentStoreId = currentStore?.Id,
|
||||||
CurrentDisplayName = currentStore?.StoreName ?? RootName
|
CurrentDisplayName = currentStore?.StoreName
|
||||||
};
|
};
|
||||||
|
|
||||||
return View(vm);
|
return View(vm);
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
|
||||||
|
|
||||||
namespace BTCPayServer.Components.StoreSelector
|
namespace BTCPayServer.Components.StoreSelector
|
||||||
{
|
{
|
||||||
public class StoreSelectorViewModel
|
public class StoreSelectorViewModel
|
||||||
{
|
{
|
||||||
public List<SelectListItem> Options { get; set; }
|
public List<StoreSelectorOption> Options { get; set; }
|
||||||
public string CurrentStoreId { get; set; }
|
public string CurrentStoreId { get; set; }
|
||||||
public string CurrentDisplayName { get; set; }
|
public string CurrentDisplayName { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class StoreSelectorOption
|
||||||
|
{
|
||||||
|
public bool Selected { get; set; }
|
||||||
|
public string Text { get; set; }
|
||||||
|
public string Value { get; set; }
|
||||||
|
public WalletId WalletId { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using BTCPayServer.Models.StoreViewModels;
|
|||||||
using BTCPayServer.Security;
|
using BTCPayServer.Security;
|
||||||
using BTCPayServer.Services;
|
using BTCPayServer.Services;
|
||||||
using BTCPayServer.Services.Apps;
|
using BTCPayServer.Services.Apps;
|
||||||
|
using BTCPayServer.Services.Stores;
|
||||||
using ExchangeSharp;
|
using ExchangeSharp;
|
||||||
using Google.Apis.Auth.OAuth2;
|
using Google.Apis.Auth.OAuth2;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@@ -26,6 +27,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.Extensions.FileProviders;
|
using Microsoft.Extensions.FileProviders;
|
||||||
using NBitcoin;
|
using NBitcoin;
|
||||||
using NBitcoin.Payment;
|
using NBitcoin.Payment;
|
||||||
|
using NBitpayClient;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
@@ -34,44 +36,59 @@ namespace BTCPayServer.Controllers
|
|||||||
public class HomeController : Controller
|
public class HomeController : Controller
|
||||||
{
|
{
|
||||||
private readonly ISettingsRepository _settingsRepository;
|
private readonly ISettingsRepository _settingsRepository;
|
||||||
|
private readonly StoreRepository _storeRepository;
|
||||||
private readonly IFileProvider _fileProvider;
|
private readonly IFileProvider _fileProvider;
|
||||||
|
private IHttpClientFactory HttpClientFactory { get; }
|
||||||
public IHttpClientFactory HttpClientFactory { get; }
|
private SignInManager<ApplicationUser> SignInManager { get; }
|
||||||
public LanguageService LanguageService { get; }
|
public LanguageService LanguageService { get; }
|
||||||
SignInManager<ApplicationUser> SignInManager { get; }
|
|
||||||
|
|
||||||
public HomeController(IHttpClientFactory httpClientFactory,
|
public HomeController(IHttpClientFactory httpClientFactory,
|
||||||
ISettingsRepository settingsRepository,
|
ISettingsRepository settingsRepository,
|
||||||
IWebHostEnvironment webHostEnvironment,
|
IWebHostEnvironment webHostEnvironment,
|
||||||
LanguageService languageService,
|
LanguageService languageService,
|
||||||
|
StoreRepository storeRepository,
|
||||||
SignInManager<ApplicationUser> signInManager)
|
SignInManager<ApplicationUser> signInManager)
|
||||||
{
|
{
|
||||||
_settingsRepository = settingsRepository;
|
_settingsRepository = settingsRepository;
|
||||||
HttpClientFactory = httpClientFactory;
|
HttpClientFactory = httpClientFactory;
|
||||||
LanguageService = languageService;
|
LanguageService = languageService;
|
||||||
|
_storeRepository = storeRepository;
|
||||||
_fileProvider = webHostEnvironment.WebRootFileProvider;
|
_fileProvider = webHostEnvironment.WebRootFileProvider;
|
||||||
SignInManager = signInManager;
|
SignInManager = signInManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("")]
|
[Route("")]
|
||||||
[DomainMappingConstraint()]
|
[DomainMappingConstraint]
|
||||||
public async Task<IActionResult> Index()
|
public async Task<IActionResult> Index()
|
||||||
{
|
{
|
||||||
if ((await _settingsRepository.GetTheme()).FirstRun)
|
if ((await _settingsRepository.GetTheme()).FirstRun)
|
||||||
{
|
{
|
||||||
return RedirectToAction(nameof(AccountController.Register), "Account");
|
return RedirectToAction(nameof(AccountController.Register), "Account");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SignInManager.IsSignedIn(User))
|
if (SignInManager.IsSignedIn(User))
|
||||||
|
{
|
||||||
|
var storeId = HttpContext.GetUserPrefsCookie()?.CurrentStoreId;
|
||||||
|
if (storeId != null)
|
||||||
|
{
|
||||||
|
var userId = SignInManager.UserManager.GetUserId(HttpContext.User);
|
||||||
|
var store = await _storeRepository.FindStore(storeId, userId);
|
||||||
|
if (store != null)
|
||||||
|
{
|
||||||
|
HttpContext.SetStoreData(store);
|
||||||
|
}
|
||||||
|
}
|
||||||
return View("Home");
|
return View("Home");
|
||||||
else
|
}
|
||||||
return Challenge();
|
|
||||||
|
return Challenge();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("misc/lang")]
|
[Route("misc/lang")]
|
||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie + "," + AuthenticationSchemes.Greenfield)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie + "," + AuthenticationSchemes.Greenfield)]
|
||||||
public IActionResult Languages()
|
public IActionResult Languages()
|
||||||
{
|
{
|
||||||
return Json(LanguageService.GetLanguages(), new JsonSerializerSettings() { Formatting = Formatting.Indented });
|
return Json(LanguageService.GetLanguages(), new JsonSerializerSettings { Formatting = Formatting.Indented });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -79,7 +96,7 @@ namespace BTCPayServer.Controllers
|
|||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie + "," + AuthenticationSchemes.Greenfield)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie + "," + AuthenticationSchemes.Greenfield)]
|
||||||
public IActionResult Permissions()
|
public IActionResult Permissions()
|
||||||
{
|
{
|
||||||
return Json(Client.Models.PermissionMetadata.PermissionNodes, new JsonSerializerSettings() { Formatting = Formatting.Indented });
|
return Json(Client.Models.PermissionMetadata.PermissionNodes, new JsonSerializerSettings { Formatting = Formatting.Indented });
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("swagger/v1/swagger.json")]
|
[Route("swagger/v1/swagger.json")]
|
||||||
@@ -108,7 +125,7 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Route("recovery-seed-backup")]
|
[Route("recovery-seed-backup")]
|
||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanModifyStoreSettings)]
|
||||||
public IActionResult RecoverySeedBackup(RecoverySeedBackupViewModel vm)
|
public IActionResult RecoverySeedBackup(RecoverySeedBackupViewModel vm)
|
||||||
{
|
{
|
||||||
return View("RecoverySeedBackup", vm);
|
return View("RecoverySeedBackup", vm);
|
||||||
|
|||||||
@@ -740,29 +740,22 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
[HttpGet("/stores/{storeId}/invoices")]
|
[HttpGet("/stores/{storeId}/invoices")]
|
||||||
[HttpGet("invoices")]
|
[HttpGet("invoices")]
|
||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanViewInvoices)]
|
||||||
[BitpayAPIConstraint(false)]
|
[BitpayAPIConstraint(false)]
|
||||||
public async Task<IActionResult> ListInvoices(InvoicesModel? model = null, string? storeId = null)
|
public async Task<IActionResult> ListInvoices(InvoicesModel? model = null)
|
||||||
{
|
{
|
||||||
model = this.ParseListQuery(model ?? new InvoicesModel());
|
model = this.ParseListQuery(model ?? new InvoicesModel());
|
||||||
|
|
||||||
var fs = new SearchString(model.SearchTerm);
|
var fs = new SearchString(model.SearchTerm);
|
||||||
var storeIds = storeId == null
|
var store = model.StoreId == null || fs.ContainsFilter("storeid") ? null : HttpContext.GetStoreData();
|
||||||
|
var storeIds = store == null
|
||||||
? fs.GetFilterArray("storeid") != null ? fs.GetFilterArray("storeid") : new List<string>().ToArray()
|
? fs.GetFilterArray("storeid") != null ? fs.GetFilterArray("storeid") : new List<string>().ToArray()
|
||||||
: new []{ storeId };
|
: new []{ store.Id };
|
||||||
|
|
||||||
model.StoreIds = storeIds;
|
model.StoreIds = storeIds;
|
||||||
|
|
||||||
if (storeId != null)
|
|
||||||
{
|
|
||||||
var store = await _StoreRepository.FindStore(storeId, GetUserId());
|
|
||||||
if (store == null)
|
|
||||||
return NotFound();
|
|
||||||
HttpContext.SetStoreData(store);
|
|
||||||
model.StoreId = store.Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
InvoiceQuery invoiceQuery = GetInvoiceQuery(model.SearchTerm, model.TimezoneOffset ?? 0);
|
InvoiceQuery invoiceQuery = GetInvoiceQuery(model.SearchTerm, model.TimezoneOffset ?? 0);
|
||||||
|
invoiceQuery.StoreId = storeIds;
|
||||||
var counting = _InvoiceRepository.GetInvoicesTotal(invoiceQuery);
|
var counting = _InvoiceRepository.GetInvoicesTotal(invoiceQuery);
|
||||||
invoiceQuery.Take = model.Count;
|
invoiceQuery.Take = model.Count;
|
||||||
invoiceQuery.Skip = model.Skip;
|
invoiceQuery.Skip = model.Skip;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Abstractions.Constants;
|
using BTCPayServer.Abstractions.Constants;
|
||||||
|
using BTCPayServer.Client;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Fido2;
|
using BTCPayServer.Fido2;
|
||||||
using BTCPayServer.Models;
|
using BTCPayServer.Models;
|
||||||
@@ -21,7 +22,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
|
|
||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanViewProfile)]
|
||||||
[Route("[controller]/[action]")]
|
[Route("[controller]/[action]")]
|
||||||
public partial class ManageController : Controller
|
public partial class ManageController : Controller
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Net.WebSockets;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Abstractions.Constants;
|
using BTCPayServer.Abstractions.Constants;
|
||||||
|
using BTCPayServer.Client;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Filters;
|
using BTCPayServer.Filters;
|
||||||
using BTCPayServer.Models.NotificationViewModels;
|
using BTCPayServer.Models.NotificationViewModels;
|
||||||
@@ -18,7 +19,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
[BitpayAPIConstraint(false)]
|
[BitpayAPIConstraint(false)]
|
||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanViewNotificationsForUser)]
|
||||||
[Route("[controller]/[action]")]
|
[Route("[controller]/[action]")]
|
||||||
public class NotificationsController : Controller
|
public class NotificationsController : Controller
|
||||||
{
|
{
|
||||||
@@ -46,8 +47,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
return ViewComponent("NotificationsDropdown");
|
return ViewComponent("NotificationsDropdown");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> SubscribeUpdates(CancellationToken cancellationToken)
|
public async Task<IActionResult> SubscribeUpdates(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
@@ -128,6 +128,7 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanManageNotificationsForUser)]
|
||||||
public async Task<IActionResult> FlipRead(string id)
|
public async Task<IActionResult> FlipRead(string id)
|
||||||
{
|
{
|
||||||
if (ValidUserClaim(out var userId))
|
if (ValidUserClaim(out var userId))
|
||||||
@@ -161,9 +162,9 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanManageNotificationsForUser)]
|
||||||
public async Task<IActionResult> MassAction(string command, string[] selectedItems)
|
public async Task<IActionResult> MassAction(string command, string[] selectedItems)
|
||||||
{
|
{
|
||||||
if (!ValidUserClaim(out var userId))
|
if (!ValidUserClaim(out var userId))
|
||||||
@@ -209,6 +210,7 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanManageNotificationsForUser)]
|
||||||
public async Task<IActionResult> MarkAllAsSeen(string returnUrl)
|
public async Task<IActionResult> MarkAllAsSeen(string returnUrl)
|
||||||
{
|
{
|
||||||
if (!ValidUserClaim(out var userId))
|
if (!ValidUserClaim(out var userId))
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
return View("Integrations", new IntegrationsViewModel());
|
return View("Integrations", new IntegrationsViewModel());
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Data.WebhookDeliveryData?> LastDeliveryForWebhook(string webhookId)
|
private async Task<Data.WebhookDeliveryData?> LastDeliveryForWebhook(string webhookId)
|
||||||
{
|
{
|
||||||
return (await _Repo.GetWebhookDeliveries(CurrentStore.Id, webhookId, 1)).ToList().FirstOrDefault();
|
return (await _Repo.GetWebhookDeliveries(CurrentStore.Id, webhookId, 1)).ToList().FirstOrDefault();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Abstractions.Constants;
|
using BTCPayServer.Abstractions.Constants;
|
||||||
|
using BTCPayServer.Client;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Models;
|
using BTCPayServer.Models;
|
||||||
using BTCPayServer.Models.StoreViewModels;
|
using BTCPayServer.Models.StoreViewModels;
|
||||||
@@ -14,40 +15,36 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
[Route("stores")]
|
[Route("stores")]
|
||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
|
||||||
[AutoValidateAntiforgeryToken]
|
[AutoValidateAntiforgeryToken]
|
||||||
public partial class UserStoresController : Controller
|
public class UserStoresController : Controller
|
||||||
{
|
{
|
||||||
private readonly StoreRepository _Repo;
|
private readonly StoreRepository _repo;
|
||||||
private readonly BTCPayNetworkProvider _NetworkProvider;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
private readonly UserManager<ApplicationUser> _UserManager;
|
|
||||||
|
|
||||||
public UserStoresController(
|
public UserStoresController(
|
||||||
UserManager<ApplicationUser> userManager,
|
UserManager<ApplicationUser> userManager,
|
||||||
BTCPayNetworkProvider networkProvider,
|
|
||||||
StoreRepository storeRepository)
|
StoreRepository storeRepository)
|
||||||
{
|
{
|
||||||
_Repo = storeRepository;
|
_repo = storeRepository;
|
||||||
_NetworkProvider = networkProvider;
|
_userManager = userManager;
|
||||||
_UserManager = userManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet("create")]
|
||||||
[Route("create")]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanModifyStoreSettingsUnscoped)]
|
||||||
public IActionResult CreateStore()
|
public IActionResult CreateStore()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost("create")]
|
||||||
[Route("create")]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanModifyStoreSettingsUnscoped)]
|
||||||
public async Task<IActionResult> CreateStore(CreateStoreViewModel vm)
|
public async Task<IActionResult> CreateStore(CreateStoreViewModel vm)
|
||||||
{
|
{
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
{
|
{
|
||||||
return View(vm);
|
return View(vm);
|
||||||
}
|
}
|
||||||
var store = await _Repo.CreateStore(GetUserId(), vm.Name);
|
var store = await _repo.CreateStore(GetUserId(), vm.Name);
|
||||||
CreatedStoreId = store.Id;
|
CreatedStoreId = store.Id;
|
||||||
TempData[WellKnownTempData.SuccessMessage] = "Store successfully created";
|
TempData[WellKnownTempData.SuccessMessage] = "Store successfully created";
|
||||||
return RedirectToAction(nameof(StoresController.PaymentMethods), "Stores", new
|
return RedirectToAction(nameof(StoresController.PaymentMethods), "Stores", new
|
||||||
@@ -62,6 +59,7 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{storeId}/me/delete")]
|
[HttpGet("{storeId}/me/delete")]
|
||||||
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanModifyStoreSettings)]
|
||||||
public IActionResult DeleteStore(string storeId)
|
public IActionResult DeleteStore(string storeId)
|
||||||
{
|
{
|
||||||
var store = HttpContext.GetStoreData();
|
var store = HttpContext.GetStoreData();
|
||||||
@@ -71,25 +69,27 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("{storeId}/me/delete")]
|
[HttpPost("{storeId}/me/delete")]
|
||||||
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanModifyStoreSettings)]
|
||||||
public async Task<IActionResult> DeleteStorePost(string storeId)
|
public async Task<IActionResult> DeleteStorePost(string storeId)
|
||||||
{
|
{
|
||||||
var userId = GetUserId();
|
var userId = GetUserId();
|
||||||
var store = HttpContext.GetStoreData();
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
await _Repo.RemoveStore(storeId, userId);
|
await _repo.RemoveStore(storeId, userId);
|
||||||
TempData[WellKnownTempData.SuccessMessage] = "Store removed successfully";
|
TempData[WellKnownTempData.SuccessMessage] = "Store removed successfully";
|
||||||
return RedirectToAction(nameof(ListStores));
|
return RedirectToAction(nameof(ListStores));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanViewStoreSettings)]
|
||||||
public async Task<IActionResult> ListStores(
|
public async Task<IActionResult> ListStores(
|
||||||
string sortOrder = null,
|
string sortOrder = null,
|
||||||
string sortOrderColumn = null
|
string sortOrderColumn = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
StoresViewModel result = new StoresViewModel();
|
StoresViewModel result = new StoresViewModel();
|
||||||
var stores = await _Repo.GetStoresByUserId(GetUserId());
|
var stores = await _repo.GetStoresByUserId(GetUserId());
|
||||||
if (sortOrder != null && sortOrderColumn != null)
|
if (sortOrder != null && sortOrderColumn != null)
|
||||||
{
|
{
|
||||||
stores = stores.OrderByDescending(store =>
|
stores = stores.OrderByDescending(store =>
|
||||||
@@ -134,9 +134,6 @@ namespace BTCPayServer.Controllers
|
|||||||
return View(result);
|
return View(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetUserId()
|
private string GetUserId() => _userManager.GetUserId(User);
|
||||||
{
|
|
||||||
return _UserManager.GetUserId(User);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Globalization;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Abstractions.Constants;
|
||||||
using BTCPayServer.Client;
|
using BTCPayServer.Client;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Hwi;
|
using BTCPayServer.Hwi;
|
||||||
@@ -18,6 +19,7 @@ using Newtonsoft.Json.Linq;
|
|||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
[Route("vault")]
|
[Route("vault")]
|
||||||
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanModifyStoreSettings)]
|
||||||
public class VaultController : Controller
|
public class VaultController : Controller
|
||||||
{
|
{
|
||||||
private readonly IAuthorizationService _authorizationService;
|
private readonly IAuthorizationService _authorizationService;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ using NBitcoin.Payment;
|
|||||||
using NBitpayClient;
|
using NBitpayClient;
|
||||||
using NBXplorer.DerivationStrategy;
|
using NBXplorer.DerivationStrategy;
|
||||||
using NBXplorer.Models;
|
using NBXplorer.Models;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using InvoiceCryptoInfo = BTCPayServer.Services.Invoices.InvoiceCryptoInfo;
|
using InvoiceCryptoInfo = BTCPayServer.Services.Invoices.InvoiceCryptoInfo;
|
||||||
|
|
||||||
@@ -409,6 +410,32 @@ namespace BTCPayServer
|
|||||||
result = default;
|
result = default;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UserPrefsCookie GetUserPrefsCookie(this HttpContext ctx)
|
||||||
|
{
|
||||||
|
var prefCookie = new UserPrefsCookie();
|
||||||
|
ctx.Request.Cookies.TryGetValue(nameof(UserPrefsCookie), out var strPrefCookie);
|
||||||
|
if (!string.IsNullOrEmpty(strPrefCookie))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
prefCookie = JsonConvert.DeserializeObject<UserPrefsCookie>(strPrefCookie);
|
||||||
|
}
|
||||||
|
catch { /* ignore cookie deserialization failures */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefCookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetCurrentStoreId(this HttpContext ctx, string storeId)
|
||||||
|
{
|
||||||
|
var prefCookie = ctx.GetUserPrefsCookie();
|
||||||
|
if (prefCookie.CurrentStoreId != storeId)
|
||||||
|
{
|
||||||
|
prefCookie.CurrentStoreId = storeId;
|
||||||
|
ctx.Response.Cookies.Append(nameof(UserPrefsCookie), JsonConvert.SerializeObject(prefCookie));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static StoreData GetStoreData(this HttpContext ctx)
|
public static StoreData GetStoreData(this HttpContext ctx)
|
||||||
{
|
{
|
||||||
@@ -418,12 +445,15 @@ namespace BTCPayServer
|
|||||||
public static void SetStoreData(this HttpContext ctx, StoreData storeData)
|
public static void SetStoreData(this HttpContext ctx, StoreData storeData)
|
||||||
{
|
{
|
||||||
ctx.Items["BTCPAY.STOREDATA"] = storeData;
|
ctx.Items["BTCPAY.STOREDATA"] = storeData;
|
||||||
|
|
||||||
|
SetCurrentStoreId(ctx, storeData.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StoreData[] GetStoresData(this HttpContext ctx)
|
public static StoreData[] GetStoresData(this HttpContext ctx)
|
||||||
{
|
{
|
||||||
return ctx.Items.TryGet("BTCPAY.STORESDATA") as StoreData[];
|
return ctx.Items.TryGet("BTCPAY.STORESDATA") as StoreData[];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetStoresData(this HttpContext ctx, StoreData[] storeData)
|
public static void SetStoresData(this HttpContext ctx, StoreData[] storeData)
|
||||||
{
|
{
|
||||||
ctx.Items["BTCPAY.STORESDATA"] = storeData;
|
ctx.Items["BTCPAY.STORESDATA"] = storeData;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace BTCPayServer
|
namespace BTCPayServer
|
||||||
{
|
{
|
||||||
// Classes here remember users preferences on certain pages and store them in unified blob cookie "UserPreferCookie"
|
// Classes here remember users preferences on certain pages and store them in unified blob cookie "UserPrefsCookie"
|
||||||
public static class ControllerBaseExtension
|
public static class ControllerBaseExtension
|
||||||
{
|
{
|
||||||
public static T ParseListQuery<T>(this ControllerBase ctrl, T model) where T : BasePagingViewModel
|
public static T ParseListQuery<T>(this ControllerBase ctrl, T model) where T : BasePagingViewModel
|
||||||
@@ -34,7 +34,7 @@ namespace BTCPayServer
|
|||||||
|
|
||||||
private static T ProcessParse<T>(ControllerBase ctrl, T model, PropertyInfo prop) where T : BasePagingViewModel
|
private static T ProcessParse<T>(ControllerBase ctrl, T model, PropertyInfo prop) where T : BasePagingViewModel
|
||||||
{
|
{
|
||||||
var prefCookie = parsePrefCookie(ctrl);
|
var prefCookie = ctrl.HttpContext.GetUserPrefsCookie();
|
||||||
|
|
||||||
// If the user enter an empty searchTerm, then the variable will be null and not empty string
|
// If the user enter an empty searchTerm, then the variable will be null and not empty string
|
||||||
// but we want searchTerm to be null only if the user is browsing the page via some link
|
// but we want searchTerm to be null only if the user is browsing the page via some link
|
||||||
@@ -46,7 +46,7 @@ namespace BTCPayServer
|
|||||||
if (searchTerm is null)
|
if (searchTerm is null)
|
||||||
{
|
{
|
||||||
var section = prop.GetValue(prefCookie) as ListQueryDataHolder;
|
var section = prop.GetValue(prefCookie) as ListQueryDataHolder;
|
||||||
if (section != null && !String.IsNullOrEmpty(section.SearchTerm))
|
if (section != null && !string.IsNullOrEmpty(section.SearchTerm))
|
||||||
{
|
{
|
||||||
model.SearchTerm = section.SearchTerm;
|
model.SearchTerm = section.SearchTerm;
|
||||||
model.TimezoneOffset = section.TimezoneOffset ?? 0;
|
model.TimezoneOffset = section.TimezoneOffset ?? 0;
|
||||||
@@ -60,45 +60,5 @@ namespace BTCPayServer
|
|||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UserPrefsCookie parsePrefCookie(ControllerBase ctrl)
|
|
||||||
{
|
|
||||||
var prefCookie = new UserPrefsCookie();
|
|
||||||
ctrl.Request.Cookies.TryGetValue(nameof(UserPrefsCookie), out var strPrefCookie);
|
|
||||||
if (!String.IsNullOrEmpty(strPrefCookie))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
prefCookie = JsonConvert.DeserializeObject<UserPrefsCookie>(strPrefCookie);
|
|
||||||
}
|
|
||||||
catch { /* ignore cookie deserialization failures */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefCookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
class UserPrefsCookie
|
|
||||||
{
|
|
||||||
public ListQueryDataHolder InvoicesQuery { get; set; }
|
|
||||||
|
|
||||||
public ListQueryDataHolder PaymentRequestsQuery { get; set; }
|
|
||||||
public ListQueryDataHolder UsersQuery { get; set; }
|
|
||||||
public ListQueryDataHolder PayoutsQuery { get; set; }
|
|
||||||
public ListQueryDataHolder PullPaymentsQuery { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
class ListQueryDataHolder
|
|
||||||
{
|
|
||||||
public ListQueryDataHolder() { }
|
|
||||||
|
|
||||||
public ListQueryDataHolder(string searchTerm, int? timezoneOffset)
|
|
||||||
{
|
|
||||||
SearchTerm = searchTerm;
|
|
||||||
TimezoneOffset = timezoneOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int? TimezoneOffset { get; set; }
|
|
||||||
public string SearchTerm { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
BTCPayServer/Extensions/UserPrefsCookie.cs
Normal file
26
BTCPayServer/Extensions/UserPrefsCookie.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace BTCPayServer
|
||||||
|
{
|
||||||
|
public class UserPrefsCookie
|
||||||
|
{
|
||||||
|
public ListQueryDataHolder InvoicesQuery { get; set; }
|
||||||
|
public ListQueryDataHolder PaymentRequestsQuery { get; set; }
|
||||||
|
public ListQueryDataHolder UsersQuery { get; set; }
|
||||||
|
public ListQueryDataHolder PayoutsQuery { get; set; }
|
||||||
|
public ListQueryDataHolder PullPaymentsQuery { get; set; }
|
||||||
|
public string CurrentStoreId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ListQueryDataHolder
|
||||||
|
{
|
||||||
|
public ListQueryDataHolder() { }
|
||||||
|
|
||||||
|
public ListQueryDataHolder(string searchTerm, int? timezoneOffset)
|
||||||
|
{
|
||||||
|
SearchTerm = searchTerm;
|
||||||
|
TimezoneOffset = timezoneOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? TimezoneOffset { get; set; }
|
||||||
|
public string SearchTerm { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -329,6 +329,8 @@ namespace BTCPayServer.Hosting
|
|||||||
services.AddSingleton<IPaymentMethodHandler>(provider => provider.GetService<LightningLikePaymentHandler>());
|
services.AddSingleton<IPaymentMethodHandler>(provider => provider.GetService<LightningLikePaymentHandler>());
|
||||||
services.AddSingleton<LNURLPayPaymentHandler>();
|
services.AddSingleton<LNURLPayPaymentHandler>();
|
||||||
services.AddSingleton<IPaymentMethodHandler>(provider => provider.GetService<LNURLPayPaymentHandler>());
|
services.AddSingleton<IPaymentMethodHandler>(provider => provider.GetService<LNURLPayPaymentHandler>());
|
||||||
|
services.AddSingleton<IUIExtension>(new UIExtension("LNURL/LightningAddressNav",
|
||||||
|
"store-integrations-nav"));
|
||||||
services.AddSingleton<IUIExtension>(new UIExtension("LNURL/LightningAddressOption",
|
services.AddSingleton<IUIExtension>(new UIExtension("LNURL/LightningAddressOption",
|
||||||
"store-integrations-list"));
|
"store-integrations-list"));
|
||||||
services.AddSingleton<IHostedService, LightningListener>();
|
services.AddSingleton<IHostedService, LightningListener>();
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ namespace BTCPayServer.Plugins.Shopify
|
|||||||
public override void Execute(IServiceCollection applicationBuilder)
|
public override void Execute(IServiceCollection applicationBuilder)
|
||||||
{
|
{
|
||||||
applicationBuilder.AddSingleton<IHostedService, ShopifyOrderMarkerHostedService>();
|
applicationBuilder.AddSingleton<IHostedService, ShopifyOrderMarkerHostedService>();
|
||||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("Shopify/StoreIntegrationShopifyOption",
|
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("Shopify/StoreIntegrationsNav",
|
||||||
|
"store-integrations-nav"));
|
||||||
|
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("Shopify/StoreIntegrationsList",
|
||||||
"store-integrations-list"));
|
"store-integrations-list"));
|
||||||
base.Execute(applicationBuilder);
|
base.Execute(applicationBuilder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,5 +77,7 @@ namespace BTCPayServer
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal bool ContainsFilter(string key) => Filters.ContainsKey(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Abstractions.Constants;
|
using BTCPayServer.Abstractions.Constants;
|
||||||
using BTCPayServer.Client;
|
using BTCPayServer.Client;
|
||||||
|
using BTCPayServer.Controllers;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.PaymentRequest;
|
|
||||||
using BTCPayServer.Services.Apps;
|
using BTCPayServer.Services.Apps;
|
||||||
using BTCPayServer.Services.Invoices;
|
using BTCPayServer.Services.Invoices;
|
||||||
using BTCPayServer.Services.PaymentRequests;
|
using BTCPayServer.Services.PaymentRequests;
|
||||||
@@ -37,28 +38,32 @@ namespace BTCPayServer.Security
|
|||||||
_invoiceRepository = invoiceRepository;
|
_invoiceRepository = invoiceRepository;
|
||||||
_paymentRequestRepository = paymentRequestRepository;
|
_paymentRequestRepository = paymentRequestRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PolicyRequirement requirement)
|
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PolicyRequirement requirement)
|
||||||
{
|
{
|
||||||
if (context.User.Identity.AuthenticationType != AuthenticationSchemes.Cookie)
|
if (context.User.Identity.AuthenticationType != AuthenticationSchemes.Cookie)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isAdmin = context.User.IsInRole(Roles.ServerAdmin);
|
|
||||||
switch (requirement.Policy)
|
|
||||||
{
|
|
||||||
case Policies.CanModifyServerSettings:
|
|
||||||
if (isAdmin)
|
|
||||||
context.Succeed(requirement);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var userId = _userManager.GetUserId(context.User);
|
var userId = _userManager.GetUserId(context.User);
|
||||||
if (string.IsNullOrEmpty(userId))
|
if (string.IsNullOrEmpty(userId))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
var isAdmin = context.User.IsInRole(Roles.ServerAdmin);
|
||||||
|
|
||||||
AppData app = null;
|
AppData app = null;
|
||||||
|
StoreData store = null;
|
||||||
InvoiceEntity invoice = null;
|
InvoiceEntity invoice = null;
|
||||||
PaymentRequestData paymentRequest = null;
|
PaymentRequestData paymentRequest = null;
|
||||||
string storeId = context.Resource is string s ? s : _httpContext.GetImplicitStoreId();
|
string storeId;
|
||||||
|
var explicitResource = false;
|
||||||
|
if (context.Resource is string s)
|
||||||
|
{
|
||||||
|
explicitResource = true;
|
||||||
|
storeId = s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
storeId = _httpContext.GetImplicitStoreId();
|
||||||
var routeData = _httpContext.GetRouteData();
|
var routeData = _httpContext.GetRouteData();
|
||||||
if (routeData != null)
|
if (routeData != null)
|
||||||
{
|
{
|
||||||
@@ -81,28 +86,52 @@ namespace BTCPayServer.Security
|
|||||||
{
|
{
|
||||||
string payReqId = vPayReqId as string;
|
string payReqId = vPayReqId as string;
|
||||||
paymentRequest = await _paymentRequestRepository.FindPaymentRequest(payReqId, userId);
|
paymentRequest = await _paymentRequestRepository.FindPaymentRequest(payReqId, userId);
|
||||||
storeId ??= paymentRequest?.StoreDataId;
|
if (storeId == null)
|
||||||
|
{
|
||||||
|
storeId = paymentRequest?.StoreDataId;
|
||||||
|
}
|
||||||
|
else if (paymentRequest?.StoreDataId != storeId)
|
||||||
|
{
|
||||||
|
paymentRequest = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// resolve from invoice
|
// resolve from invoice
|
||||||
if (routeData.Values.TryGetValue("invoiceId", out var vInvoiceId))
|
if (routeData.Values.TryGetValue("invoiceId", out var vInvoiceId))
|
||||||
{
|
{
|
||||||
string invoiceId = vInvoiceId as string;
|
string invoiceId = vInvoiceId as string;
|
||||||
invoice = await _invoiceRepository.GetInvoice(invoiceId);
|
invoice = await _invoiceRepository.GetInvoice(invoiceId);
|
||||||
storeId ??= invoice?.StoreId;
|
if (storeId == null)
|
||||||
|
{
|
||||||
|
storeId = invoice?.StoreId;
|
||||||
|
}
|
||||||
|
else if (invoice?.StoreId != storeId)
|
||||||
|
{
|
||||||
|
invoice = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// store could not be found
|
// Fall back to user prefs cookie
|
||||||
if (storeId == null)
|
if (storeId == null)
|
||||||
{
|
{
|
||||||
return;
|
storeId = _httpContext.GetUserPrefsCookie()?.CurrentStoreId;
|
||||||
}
|
}
|
||||||
|
|
||||||
var store = await _storeRepository.FindStore(storeId, userId);
|
if (storeId != null)
|
||||||
|
{
|
||||||
|
store = await _storeRepository.FindStore(storeId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
bool success = false;
|
|
||||||
switch (requirement.Policy)
|
switch (requirement.Policy)
|
||||||
{
|
{
|
||||||
|
case Policies.CanModifyServerSettings:
|
||||||
|
if (isAdmin)
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
case Policies.CanViewInvoices:
|
||||||
|
if (store == null || store.Role == StoreRoles.Owner || isAdmin)
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
case Policies.CanModifyStoreSettings:
|
case Policies.CanModifyStoreSettings:
|
||||||
if (store != null && (store.Role == StoreRoles.Owner || isAdmin))
|
if (store != null && (store.Role == StoreRoles.Owner || isAdmin))
|
||||||
success = true;
|
success = true;
|
||||||
@@ -115,17 +144,31 @@ namespace BTCPayServer.Security
|
|||||||
if (store != null || isAdmin)
|
if (store != null || isAdmin)
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
|
case Policies.CanViewProfile:
|
||||||
|
case Policies.CanViewNotificationsForUser:
|
||||||
|
case Policies.CanManageNotificationsForUser:
|
||||||
|
case Policies.CanModifyStoreSettingsUnscoped:
|
||||||
|
if (context.User != null)
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
context.Succeed(requirement);
|
context.Succeed(requirement);
|
||||||
_httpContext.SetStoreData(store);
|
if (!explicitResource)
|
||||||
|
{
|
||||||
// cache associated entities if present
|
|
||||||
if (app != null) _httpContext.SetAppData(app);
|
if (store != null)
|
||||||
if (invoice != null) _httpContext.SetInvoiceData(invoice);
|
{
|
||||||
if (paymentRequest != null) _httpContext.SetPaymentRequestData(paymentRequest);
|
_httpContext.SetStoreData(store);
|
||||||
|
|
||||||
|
// cache associated entities if present
|
||||||
|
if (app != null) _httpContext.SetAppData(app);
|
||||||
|
if (invoice != null) _httpContext.SetInvoiceData(invoice);
|
||||||
|
if (paymentRequest != null) _httpContext.SetPaymentRequestData(paymentRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace BTCPayServer.Security
|
|||||||
{
|
{
|
||||||
return scopes.All(s => context.User.HasClaim(c => c.Type.Equals("scope", StringComparison.InvariantCultureIgnoreCase) && c.Value.Split(' ').Contains(s)));
|
return scopes.All(s => context.User.HasClaim(c => c.Type.Equals("scope", StringComparison.InvariantCultureIgnoreCase) && c.Value.Split(' ').Contains(s)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetImplicitStoreId(this HttpContext httpContext)
|
public static string GetImplicitStoreId(this HttpContext httpContext)
|
||||||
{
|
{
|
||||||
// 1. Check in the routeData
|
// 1. Check in the routeData
|
||||||
|
|||||||
@@ -2,6 +2,5 @@
|
|||||||
@using BTCPayServer.Views
|
@using BTCPayServer.Views
|
||||||
@using BTCPayServer.Views.Apps
|
@using BTCPayServer.Views.Apps
|
||||||
@{
|
@{
|
||||||
ViewBag.CategoryTitle = "Apps";
|
|
||||||
ViewData.SetActiveCategory(typeof(AppsNavPages));
|
ViewData.SetActiveCategory(typeof(AppsNavPages));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
@{
|
@{
|
||||||
Layout = "_LayoutSimple";
|
Layout = "_LayoutSimple";
|
||||||
ViewBag.TopSmallMargin = true;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,7 @@
|
|||||||
@using BTCPayServer.Abstractions.Extensions
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
@model LNURLController.EditLightningAddressVM
|
@model LNURLController.EditLightningAddressVM
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
ViewData.SetActivePage("LightningAddress", nameof(StoreNavPages), "Lightning Address", Context.GetStoreData().Id);
|
||||||
ViewData["NavPartialName"] = "../Stores/_Nav";
|
|
||||||
ViewData.SetActivePage(StoreNavPages.Integrations, "Lightning Address Setup", Context.GetStoreData().StoreName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@section PageHeadContent {
|
@section PageHeadContent {
|
||||||
@@ -27,17 +25,19 @@
|
|||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<partial name="_StatusMessage" />
|
||||||
|
|
||||||
@if (Context.Request.PathBase.ToString() != string.Empty)
|
@if (Context.Request.PathBase.ToString() != string.Empty)
|
||||||
{
|
{
|
||||||
<div class="alert alert-warning" role="alert">
|
<div class="alert alert-warning" role="alert">
|
||||||
Your BTCPay Server installation is using the root path <span class="fw-bold">@Context.Request.PathBase</span>.<br /><br />
|
Your BTCPay Server installation is using the root path <span class="fw-bold">@Context.Request.PathBase</span>.<br /><br />
|
||||||
This is incompatible with wallets attempting to resolve <span class="fw-bold">@Context.Request.GetAbsoluteUriNoPathBase(new Uri("/.well-known/lnurlp/{username}", UriKind.Relative))</span> rather than <span class="fw-bold">@Context.Request.GetAbsoluteUri("/.well-known/lnurlp/{username}")</span>.<br /><br />
|
This is incompatible with wallets attempting to resolve <span class="fw-bold">@Context.Request.GetAbsoluteUriNoPathBase(new Uri("/.well-known/lnurlp/{username}", UriKind.Relative))</span> rather than <span class="fw-bold">@Context.Request.GetAbsoluteUri("/.well-known/lnurlp/{username}")</span>.<br /><br />
|
||||||
If the LN Address doesn't work, ask your integrator to redirect queries from <span class="fw-bold">@Context.Request.GetAbsoluteUriNoPathBase(new Uri("/.well-known/lnurlp/{username}", UriKind.Relative))</span> to <span class="fw-bold">@Context.Request.GetAbsoluteUri("/.well-known/lnurlp/{username}")</span>.
|
If the LN Address doesn't work, ask your integrator to redirect queries from <span class="fw-bold">@Context.Request.GetAbsoluteUriNoPathBase(new Uri("/.well-known/lnurlp/{username}", UriKind.Relative))</span> to <span class="fw-bold">@Context.Request.GetAbsoluteUri("/.well-known/lnurlp/{username}")</span>.
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="d-sm-flex align-items-center justify-content-between mb-2">
|
<div class="d-flex align-items-center justify-content-between mb-2">
|
||||||
<h2 class="mb-3 mb-sm-0">@ViewData["Title"]</h2>
|
<h2 class="mb-0">@ViewData["Title"]</h2>
|
||||||
<a data-bs-toggle="collapse" data-bs-target="#AddAddress" class="btn btn-primary" role="button">
|
<a data-bs-toggle="collapse" data-bs-target="#AddAddress" class="btn btn-primary" role="button">
|
||||||
<span class="fa fa-plus"></span>
|
<span class="fa fa-plus"></span>
|
||||||
Add Address
|
Add Address
|
||||||
@@ -50,16 +50,16 @@
|
|||||||
var showAdvancedOptions = !string.IsNullOrEmpty(Model.Add?.CurrencyCode) || Model.Add?.Min != null || Model.Add?.Max != null;
|
var showAdvancedOptions = !string.IsNullOrEmpty(Model.Add?.CurrencyCode) || Model.Add?.Min != null || Model.Add?.Max != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="row collapse @(showAddForm ? "show": "")" id="AddAddress">
|
<div class="collapse @(showAddForm ? "show": "")" id="AddAddress">
|
||||||
<div class="form-group pt-3">
|
<div class="form-group pt-2">
|
||||||
<label asp-for="Add.Username" class="form-label"></label>
|
<label asp-for="Add.Username" class="form-label"></label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input asp-for="Add.Username" class="form-control"/>
|
<input asp-for="Add.Username" class="form-control"/>
|
||||||
<span class="input-group-text" >@@@Context.Request.Host.ToUriComponent()@Context.Request.PathBase</span>
|
<span class="input-group-text">@@@Context.Request.Host.ToUriComponent()@Context.Request.PathBase</span>
|
||||||
</div>
|
</div>
|
||||||
<span asp-validation-for="Add.Username" class="text-danger"></span>
|
<span asp-validation-for="Add.Username" class="text-danger"></span>
|
||||||
</div>
|
</div>
|
||||||
<a class="mb-3" role="button" data-bs-toggle="collapse" data-bs-target="#AdvancedSettings">Advanced settings</a>
|
<a class="d-inline-block mb-3" role="button" data-bs-toggle="collapse" data-bs-target="#AdvancedSettings">Advanced settings</a>
|
||||||
<div id="AdvancedSettings" class="collapse @(showAdvancedOptions ? "show" : "")">
|
<div id="AdvancedSettings" class="collapse @(showAdvancedOptions ? "show" : "")">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-sm-auto">
|
<div class="col-12 col-sm-auto">
|
||||||
@@ -93,54 +93,58 @@
|
|||||||
|
|
||||||
@if (Model.Items.Any())
|
@if (Model.Items.Any())
|
||||||
{
|
{
|
||||||
<table class="table table-hover">
|
<div class="row">
|
||||||
<thead>
|
<div class="col">
|
||||||
<tr>
|
<table class="table table-hover">
|
||||||
<th>Address</th>
|
<thead>
|
||||||
<th>Settings</th>
|
<tr>
|
||||||
<th class="text-end">Actions</th>
|
<th>Address</th>
|
||||||
</tr>
|
<th>Settings</th>
|
||||||
</thead>
|
<th class="text-end">Actions</th>
|
||||||
<tbody>
|
</tr>
|
||||||
@for (var index = 0; index < Model.Items.Count; index++)
|
</thead>
|
||||||
{
|
<tbody>
|
||||||
<input asp-for="Items[index].CurrencyCode" type="hidden"/>
|
@for (var index = 0; index < Model.Items.Count; index++)
|
||||||
<input asp-for="Items[index].Min" type="hidden"/>
|
{
|
||||||
<input asp-for="Items[index].Max" type="hidden"/>
|
<input asp-for="Items[index].CurrencyCode" type="hidden"/>
|
||||||
<input asp-for="Items[index].Username" type="hidden"/>
|
<input asp-for="Items[index].Min" type="hidden"/>
|
||||||
var address = $"{Model.Items[index].Username}@{Context.Request.Host.ToUriComponent()}";
|
<input asp-for="Items[index].Max" type="hidden"/>
|
||||||
<tr>
|
<input asp-for="Items[index].Username" type="hidden"/>
|
||||||
<td>
|
var address = $"{Model.Items[index].Username}@{Context.Request.Host.ToUriComponent()}";
|
||||||
<div class="input-group" data-clipboard="@address">
|
<tr>
|
||||||
<input type="text" class="form-control copy-cursor lightning-address-value" readonly="readonly" value="@address"/>
|
<td>
|
||||||
<button type="button" class="btn btn-outline-secondary" data-clipboard-confirm>Copy</button>
|
<div class="input-group" data-clipboard="@address">
|
||||||
</div>
|
<input type="text" class="form-control copy-cursor lightning-address-value" readonly="readonly" value="@address"/>
|
||||||
|
<button type="button" class="btn btn-outline-secondary" data-clipboard-confirm>Copy</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td class="settings-holder align-middle">
|
<td class="settings-holder align-middle">
|
||||||
@if (Model.Items[index].Min.HasValue)
|
@if (Model.Items[index].Min.HasValue)
|
||||||
{
|
{
|
||||||
<span>@Safe.Raw($"{Model.Items[index].Min} min sats")</span>
|
<span>@Safe.Raw($"{Model.Items[index].Min} min sats")</span>
|
||||||
}
|
}
|
||||||
@if (Model.Items[index].Max.HasValue)
|
@if (Model.Items[index].Max.HasValue)
|
||||||
{
|
{
|
||||||
<span> @Safe.Raw($"{Model.Items[index].Max} max sats")</span>
|
<span> @Safe.Raw($"{Model.Items[index].Max} max sats")</span>
|
||||||
}
|
}
|
||||||
@if (!string.IsNullOrEmpty(Model.Items[index].CurrencyCode))
|
@if (!string.IsNullOrEmpty(Model.Items[index].CurrencyCode))
|
||||||
{
|
{
|
||||||
<span> @Safe.Raw($"tracked in {Model.Items[index].CurrencyCode}")</span>
|
<span> @Safe.Raw($"tracked in {Model.Items[index].CurrencyCode}")</span>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<button type="submit" title="Remove" name="command" value="@($"remove:{index}")"
|
<button type="submit" title="Remove" name="command" value="@($"remove:{index}")"
|
||||||
class="btn btn-link px-0 remove" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The Lightning Address <strong>@address</strong> will be removed." data-confirm-input="REMOVE">
|
class="btn btn-link px-0 remove" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The Lightning Address <strong>@address</strong> will be removed." data-confirm-input="REMOVE">
|
||||||
Remove
|
Remove
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,13 +16,11 @@
|
|||||||
|
|
||||||
<span class="text-capitalize badge bg-secondary">@item.Amount @cryptoCode</span>
|
<span class="text-capitalize badge bg-secondary">@item.Amount @cryptoCode</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<form method="post" class="list-group-item justify-content-center" id="pay-invoices-form">
|
<form method="post" class="list-group-item justify-content-center" id="pay-invoices-form">
|
||||||
<button type="submit" class="btn btn-primary xmx-2" style="min-width:25%;" id="Pay">Pay</button>
|
<button type="submit" class="btn btn-primary xmx-2" style="min-width:25%;" id="Pay">Pay</button>
|
||||||
<button type="button" class="btn btn-secondary mx-2" onclick="history.back(); return false;" style="min-width:25%;">Go back</button>
|
<button type="button" class="btn btn-secondary mx-2" onclick="history.back(); return false;" style="min-width:25%;">Go back</button>
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -30,12 +28,11 @@
|
|||||||
@section PageFootContent {
|
@section PageFootContent {
|
||||||
<partial name="_ValidationScriptsPartial" />
|
<partial name="_ValidationScriptsPartial" />
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
$("#pay-invoices-form").on("submit", function() {
|
$("#pay-invoices-form").on("submit", function() {
|
||||||
$(this).find("input[type='submit']").prop('disabled', true);
|
$(this).find("input[type='submit']").prop('disabled', true);
|
||||||
});
|
});
|
||||||
|
$("#pay-invoices-form input").on("input", function() {
|
||||||
$("#pay-invoices-form input").on("input", function () {
|
|
||||||
// Give it a timeout to make sure all form validation has completed by the time we run our callback
|
// Give it a timeout to make sure all form validation has completed by the time we run our callback
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
var validationErrors = $('.field-validation-error');
|
var validationErrors = $('.field-validation-error');
|
||||||
@@ -47,4 +44,3 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
</section>
|
|
||||||
|
|||||||
@@ -3,6 +3,5 @@
|
|||||||
@using BTCPayServer.Views.Manage
|
@using BTCPayServer.Views.Manage
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewBag.CategoryTitle = "Account";
|
|
||||||
ViewData.SetActiveCategory(typeof(ManageNavPages));
|
ViewData.SetActiveCategory(typeof(ManageNavPages));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData["NavPartialName"] = "../Stores/_Nav";
|
ViewData["NavPartialName"] = "../Stores/_Nav";
|
||||||
ViewData.SetActivePage(StoreNavPages.ActivePage, $"{Model.CryptoCode} Settings");
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, $"{Model.CryptoCode} Settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.ActivePage, "Monero Settings");
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Monero Settings");
|
||||||
ViewData["NavPartialName"] = "../Stores/_Nav";
|
ViewData["NavPartialName"] = "../Stores/_Nav";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
@model BTCPayServer.Models.PaymentRequestViewModels.UpdatePaymentRequestViewModel
|
@model BTCPayServer.Models.PaymentRequestViewModels.UpdatePaymentRequestViewModel
|
||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(PaymentRequestsNavPages.Create, (string.IsNullOrEmpty(Model.Id) ? "Create" : "Edit") + " Payment Request");
|
ViewData.SetActivePage(PaymentRequestsNavPages.Create, $"{(string.IsNullOrEmpty(Model.Id) ? "Create" : "Edit")} Payment Request", Model.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section PageHeadContent {
|
@section PageHeadContent {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
@model BTCPayServer.Controllers.ServerController.ListPluginsViewModel
|
@model BTCPayServer.Controllers.ServerController.ListPluginsViewModel
|
||||||
@inject BTCPayServerOptions BTCPayServerOptions
|
@inject BTCPayServerOptions BTCPayServerOptions
|
||||||
@{
|
@{
|
||||||
|
Layout = "_Layout";
|
||||||
ViewData.SetActivePage(ServerNavPages.Plugins);
|
ViewData.SetActivePage(ServerNavPages.Plugins);
|
||||||
var installed = Model.Installed.ToDictionary(plugin => plugin.Identifier.ToLowerInvariant(), plugin => plugin.Version);
|
var installed = Model.Installed.ToDictionary(plugin => plugin.Identifier.ToLowerInvariant(), plugin => plugin.Version);
|
||||||
var availableAndNotInstalled = Model.Available
|
var availableAndNotInstalled = Model.Available
|
||||||
@@ -95,6 +96,9 @@
|
|||||||
.version-switch .nav-link { display: inline; }
|
.version-switch .nav-link { display: inline; }
|
||||||
.version-switch .nav-link.active { display: none; }
|
.version-switch .nav-link.active { display: none; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<partial name="_StatusMessage" />
|
||||||
|
|
||||||
@if (Model.Disabled.Any())
|
@if (Model.Disabled.Any())
|
||||||
{
|
{
|
||||||
<div class="alert alert-danger mb-5">
|
<div class="alert alert-danger mb-5">
|
||||||
|
|||||||
@@ -13,6 +13,6 @@
|
|||||||
}
|
}
|
||||||
<a asp-controller="Server" id="SectionNav-@ServerNavPages.Logs" class="nav-link @ViewData.IsActivePage(ServerNavPages.Logs)" asp-action="LogsView">Logs</a>
|
<a asp-controller="Server" id="SectionNav-@ServerNavPages.Logs" class="nav-link @ViewData.IsActivePage(ServerNavPages.Logs)" asp-action="LogsView">Logs</a>
|
||||||
<a asp-controller="Server" id="SectionNav-@ServerNavPages.Files" class="nav-link @ViewData.IsActivePage(ServerNavPages.Files)" asp-action="Files">Files</a>
|
<a asp-controller="Server" id="SectionNav-@ServerNavPages.Files" class="nav-link @ViewData.IsActivePage(ServerNavPages.Files)" asp-action="Files">Files</a>
|
||||||
<a asp-controller="Server" id="SectionNav-@ServerNavPages.Plugins" class="nav-link @ViewData.IsActivePage(ServerNavPages.Plugins)" asp-action="ListPlugins">Plugins (experimental)</a>
|
|
||||||
<vc:ui-extension-point location="server-nav" model="@Model"/>
|
<vc:ui-extension-point location="server-nav" model="@Model"/>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,5 @@
|
|||||||
@using BTCPayServer.Views.Server
|
@using BTCPayServer.Views.Server
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewBag.CategoryTitle = "Server settings";
|
|
||||||
ViewData.SetActiveCategory(typeof(ServerNavPages));
|
ViewData.SetActiveCategory(typeof(ServerNavPages));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,21 +2,17 @@
|
|||||||
|
|
||||||
@if (!string.IsNullOrEmpty(Model.ProvidedComment))
|
@if (!string.IsNullOrEmpty(Model.ProvidedComment))
|
||||||
{
|
{
|
||||||
|
<tr>
|
||||||
<tr>
|
<td colspan="100% bg-tile">
|
||||||
<td colspan="100% bg-tile">
|
LNURL Comment: @Model.ProvidedComment
|
||||||
|
</td>
|
||||||
LNURL Comment: @Model.ProvidedComment
|
</tr>
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
}
|
}
|
||||||
@if (!string.IsNullOrEmpty(Model.ConsumedLightningAddress))
|
@if (!string.IsNullOrEmpty(Model.ConsumedLightningAddress))
|
||||||
{
|
{
|
||||||
|
<tr>
|
||||||
<tr>
|
<td colspan="100% bg-tile">
|
||||||
<td colspan="100% bg-tile">
|
Lightning address used: @Model.ConsumedLightningAddress
|
||||||
|
</td>
|
||||||
Lightning address used: @Model.ConsumedLightningAddress
|
</tr>
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
}
|
}
|
||||||
|
|||||||
23
BTCPayServer/Views/Shared/LNURL/LightningAddressNav.cshtml
Normal file
23
BTCPayServer/Views/Shared/LNURL/LightningAddressNav.cshtml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
@using BTCPayServer.Payments.Lightning
|
||||||
|
@using BTCPayServer.Views.Stores
|
||||||
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
|
@inject BTCPayNetworkProvider BTCPayNetworkProvider
|
||||||
|
@{
|
||||||
|
var store = Context.GetStoreData();
|
||||||
|
var isLightningEnabled = store.IsLightningEnabled(BTCPayNetworkProvider);
|
||||||
|
var isLNUrlEnabled = store.IsLNUrlEnabled(BTCPayNetworkProvider);
|
||||||
|
var possible =
|
||||||
|
isLightningEnabled &&
|
||||||
|
isLNUrlEnabled &&
|
||||||
|
store.GetSupportedPaymentMethods(BTCPayNetworkProvider).OfType<LNURLPaySupportedPaymentMethod>().Any(type => type.CryptoCode == "BTC");
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (possible)
|
||||||
|
{
|
||||||
|
<li class="nav-item">
|
||||||
|
<a asp-area="" asp-controller="LNURL" asp-action="EditLightningAddress" asp-route-storeId="@store.Id" class="nav-link js-scroll-trigger @ViewData.IsActivePage("LightningAddress", nameof(StoreNavPages))" id="StoreNav-LightningAddress">
|
||||||
|
<vc:icon symbol="wallet-lightning"/>
|
||||||
|
<span>Lightning Address</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
@using BTCPayServer.Views.Stores
|
||||||
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
|
@{
|
||||||
|
var store = Context.GetStoreData();
|
||||||
|
}
|
||||||
|
|
||||||
|
<li class="nav-item">
|
||||||
|
<a asp-area="" asp-controller="Shopify" asp-action="EditShopifyIntegration" asp-route-storeId="@store.Id" class="nav-link js-scroll-trigger @ViewData.IsActivePage("shopify", nameof(StoreNavPages))" id="StoreNav-Shopify">
|
||||||
|
<vc:icon symbol="shopify"/>
|
||||||
|
<span>Shopify</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
$text.removeAttribute('hidden')
|
$text.removeAttribute('hidden')
|
||||||
$continue.setAttribute('disabled', 'disabled')
|
$continue.setAttribute('disabled', 'disabled')
|
||||||
$inputText.textContent = confirmInput
|
$inputText.textContent = confirmInput
|
||||||
|
$input.setAttribute("autocomplete", "off");
|
||||||
$input.addEventListener('input', event => {
|
$input.addEventListener('input', event => {
|
||||||
event.target.value.trim() === confirmInput
|
event.target.value.trim() === confirmInput
|
||||||
? $continue.removeAttribute('disabled')
|
? $continue.removeAttribute('disabled')
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
@await RenderSectionAsync("PageHeadContent", false)
|
@await RenderSectionAsync("PageHeadContent", false)
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<section class="content-wrapper @(ViewBag.TopSmallMargin != null ? "pt-4" : "")">
|
<section class="content-wrapper">
|
||||||
<!-- Dummy navbar-brand, hackish way to keep test AssertNoError passing -->
|
<!-- Dummy navbar-brand, hackish way to keep test AssertNoError passing -->
|
||||||
<div class="navbar-brand d-none"></div>
|
<div class="navbar-brand d-none"></div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|||||||
@@ -2,23 +2,23 @@
|
|||||||
@using BTCPayServer.Abstractions.Extensions
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
@model BTCPayServer.Plugins.Shopify.Models.ShopifySettings
|
@model BTCPayServer.Plugins.Shopify.Models.ShopifySettings
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
ViewData.SetActivePage("shopify", nameof(StoreNavPages), "Shopify", Context.GetStoreData().Id);
|
||||||
|
|
||||||
ViewData["NavPartialName"] = "../Stores/_Nav";
|
|
||||||
ViewData.SetActivePage(StoreNavPages.Integrations, "Integrations");
|
|
||||||
|
|
||||||
var shopifyCredsSet = Model?.IntegratedAt.HasValue is true;
|
var shopifyCredsSet = Model?.IntegratedAt.HasValue is true;
|
||||||
var shopifyUrl = Model?.ShopifyUrl;
|
var shopifyUrl = Model?.ShopifyUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<partial name="_StatusMessage"/>
|
||||||
|
|
||||||
|
<h2 class="mt-1 mb-4">
|
||||||
|
@ViewData["Title"]
|
||||||
|
<small>
|
||||||
|
<a href="https://docs.btcpayserver.org/Shopify" target="_blank" rel="noreferrer noopener">
|
||||||
|
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||||
|
</a>
|
||||||
|
</small>
|
||||||
|
</h2>
|
||||||
<form method="post" id="shopifyForm">
|
<form method="post" id="shopifyForm">
|
||||||
<h4 class="mb-3">
|
|
||||||
Shopify
|
|
||||||
<small>
|
|
||||||
<a href="https://docs.btcpayserver.org/Shopify" target="_blank" rel="noreferrer noopener">
|
|
||||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
|
||||||
</a>
|
|
||||||
</small>
|
|
||||||
</h4>
|
|
||||||
@if (!shopifyCredsSet)
|
@if (!shopifyCredsSet)
|
||||||
{
|
{
|
||||||
<p class="alert alert-info">Create a Shopify Private App with the permissions "Orders - Read and write"</p>
|
<p class="alert alert-info">Create a Shopify Private App with the permissions "Orders - Read and write"</p>
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
{
|
{
|
||||||
<span class="input-group-text">https://</span>
|
<span class="input-group-text">https://</span>
|
||||||
}
|
}
|
||||||
<input asp-for="ShopName" class="form-control" readonly="@shopifyCredsSet" />
|
<input asp-for="ShopName" class="form-control" readonly="@shopifyCredsSet"/>
|
||||||
|
|
||||||
@if (!Model?.ShopName?.Contains(".") is true)
|
@if (!Model?.ShopName?.Contains(".") is true)
|
||||||
{
|
{
|
||||||
@@ -51,13 +51,13 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="ApiKey" class="form-label"></label>
|
<label asp-for="ApiKey" class="form-label"></label>
|
||||||
<input asp-for="ApiKey" class="form-control" readonly="@shopifyCredsSet" />
|
<input asp-for="ApiKey" class="form-control" readonly="@shopifyCredsSet"/>
|
||||||
<span asp-validation-for="ApiKey" class="text-danger"></span>
|
<span asp-validation-for="ApiKey" class="text-danger"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="Password" class="form-label"></label>
|
<label asp-for="Password" class="form-label"></label>
|
||||||
<input asp-for="Password" class="form-control" type="password" value="@Model?.Password" readonly="@shopifyCredsSet" />
|
<input asp-for="Password" class="form-control" type="password" value="@Model?.Password" readonly="@shopifyCredsSet"/>
|
||||||
<span asp-validation-for="Password" class="text-danger"></span>
|
<span asp-validation-for="Password" class="text-danger"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
In Shopify please paste following script at <a href="@shopifyUrl/admin/settings/checkout#PolarisTextField1" target="_blank" class="fw-bold" rel="noreferrer noopener"> Settings > Checkout > Order Processing > Additional Scripts</a>
|
In Shopify please paste following script at <a href="@shopifyUrl/admin/settings/checkout#PolarisTextField1" target="_blank" class="fw-bold" rel="noreferrer noopener"> Settings > Checkout > Order Processing > Additional Scripts</a>
|
||||||
</p>
|
</p>
|
||||||
<kbd style="display: block; word-break: break-all;">
|
<kbd style="display: block; word-break: break-all;">
|
||||||
@($"<script src='{Url.Action("ShopifyJavascript", "Shopify", new {storeId = Context.GetRouteValue("storeId")}, Context.Request.Scheme)}'></script>")
|
@($"<script src='{Url.Action("ShopifyJavascript", "Shopify", new { storeId = Context.GetRouteValue("storeId") }, Context.Request.Scheme)}'></script>")
|
||||||
</kbd>
|
</kbd>
|
||||||
</div>
|
</div>
|
||||||
<p class="alert alert-warning">
|
<p class="alert alert-warning">
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
@using BTCPayServer.Views.Stores
|
@using BTCPayServer.Views.Stores
|
||||||
@model BTCPayServer.Models.WalletViewModels.NewPullPaymentModel
|
@model BTCPayServer.Models.WalletViewModels.NewPullPaymentModel
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(StoreNavPages.PullPayments, "New pull payment", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.PullPayments, "New pull payment", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<partial name="_StatusMessage" />
|
<partial name="_StatusMessage" />
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h4 class="mb-3">@ViewData["Title"]</h4>
|
<h2 class="mb-3">@ViewData["Title"]</h2>
|
||||||
|
|
||||||
<form method="post"
|
<form method="post"
|
||||||
asp-route-walletId="@Context.GetRouteValue("walletId")"
|
asp-route-walletId="@Context.GetRouteValue("walletId")"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
@inject IEnumerable<IPayoutHandler> PayoutHandlers;
|
@inject IEnumerable<IPayoutHandler> PayoutHandlers;
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(StoreNavPages.Payouts, $"Payouts{(string.IsNullOrEmpty(Model.PullPaymentName) ? string.Empty : " for pull payment " + Model.PullPaymentName)}", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.Payouts, $"Payouts{(string.IsNullOrEmpty(Model.PullPaymentName) ? string.Empty : " for pull payment " + Model.PullPaymentName)}", Context.GetStoreData().Id);
|
||||||
Model.PaginationQuery ??= new Dictionary<string, object>();
|
Model.PaginationQuery ??= new Dictionary<string, object>();
|
||||||
Model.PaginationQuery.Add("pullPaymentId", Model.PullPaymentId);
|
Model.PaginationQuery.Add("pullPaymentId", Model.PullPaymentId);
|
||||||
Model.PaginationQuery.Add("paymentMethodId", Model.PaymentMethodId);
|
Model.PaginationQuery.Add("paymentMethodId", Model.PaymentMethodId);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
@using BTCPayServer.Client
|
@using BTCPayServer.Client
|
||||||
@model BTCPayServer.Models.WalletViewModels.PullPaymentsModel
|
@model BTCPayServer.Models.WalletViewModels.PullPaymentsModel
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(StoreNavPages.PullPayments, "Pull payments", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.PullPayments, "Pull payments", Context.GetStoreData().Id);
|
||||||
var nextStartDateSortOrder = (string)ViewData["NextStartSortOrder"];
|
var nextStartDateSortOrder = (string)ViewData["NextStartSortOrder"];
|
||||||
string startDateSortOrder = null;
|
string startDateSortOrder = null;
|
||||||
switch (nextStartDateSortOrder)
|
switch (nextStartDateSortOrder)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@model CheckoutAppearanceViewModel
|
@model CheckoutAppearanceViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.CheckoutAppearance, "Checkout experience", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.CheckoutAppearance, "Checkout experience", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model CreateTokenViewModel
|
@model CreateTokenViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.Tokens, "Create New Token", Context.GetStoreData()?.StoreName);
|
ViewData.SetActivePage(StoreNavPages.Tokens, "Create New Token", Context.GetStoreData()?.Id);
|
||||||
ViewBag.HidePublicKey = ViewBag.HidePublicKey ?? false;
|
ViewBag.HidePublicKey = ViewBag.HidePublicKey ?? false;
|
||||||
ViewBag.ShowStores = ViewBag.ShowStores ?? false;
|
ViewBag.ShowStores = ViewBag.ShowStores ?? false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model BTCPayServer.Models.ServerViewModels.EmailsViewModel
|
@model BTCPayServer.Models.ServerViewModels.EmailsViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.GeneralSettings, "Email Settings", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.GeneralSettings, "Email Settings", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<partial name="EmailsBody" model="Model" />
|
<partial name="EmailsBody" model="Model" />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model GeneralSettingsViewModel
|
@model GeneralSettingsViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.GeneralSettings, "General Settings", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.GeneralSettings, "General Settings", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
var isHotWallet = Model.Method == WalletSetupMethod.HotWallet;
|
var isHotWallet = Model.Method == WalletSetupMethod.HotWallet;
|
||||||
var type = isHotWallet ? "Hot" : "Watch-Only";
|
var type = isHotWallet ? "Hot" : "Watch-Only";
|
||||||
Layout = "_LayoutWalletSetup";
|
Layout = "_LayoutWalletSetup";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, $"Create {Model.CryptoCode} {type} Wallet", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, $"Create {Model.CryptoCode} {type} Wallet", Context.GetStoreData().Id);
|
||||||
ViewData.Add(nameof(Model.CanUseHotWallet), Model.CanUseHotWallet);
|
ViewData.Add(nameof(Model.CanUseHotWallet), Model.CanUseHotWallet);
|
||||||
ViewData.Add(nameof(Model.CanUseRPCImport), Model.CanUseRPCImport);
|
ViewData.Add(nameof(Model.CanUseRPCImport), Model.CanUseRPCImport);
|
||||||
ViewData.Add(nameof(Model.SupportSegwit), Model.SupportSegwit);
|
ViewData.Add(nameof(Model.SupportSegwit), Model.SupportSegwit);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@{
|
@{
|
||||||
Layout = "_LayoutWalletSetup";
|
Layout = "_LayoutWalletSetup";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, $"Generate {Model.CryptoCode} Wallet", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, $"Generate {Model.CryptoCode} Wallet", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Navbar {
|
@section Navbar {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@{
|
@{
|
||||||
Layout = "_LayoutWalletSetup";
|
Layout = "_LayoutWalletSetup";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, "Confirm addresses", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Confirm addresses", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Navbar {
|
@section Navbar {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@{
|
@{
|
||||||
Layout = "_LayoutWalletSetup";
|
Layout = "_LayoutWalletSetup";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, "Import your wallet file", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Import your wallet file", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Navbar {
|
@section Navbar {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@{
|
@{
|
||||||
Layout = "_LayoutWalletSetup";
|
Layout = "_LayoutWalletSetup";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, "Connect your hardware wallet", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Connect your hardware wallet", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Navbar {
|
@section Navbar {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@{
|
@{
|
||||||
Layout = "_LayoutWalletSetup";
|
Layout = "_LayoutWalletSetup";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, "Scan QR code", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Scan QR code", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Navbar {
|
@section Navbar {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@{
|
@{
|
||||||
Layout = "_LayoutWalletSetup";
|
Layout = "_LayoutWalletSetup";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, "Enter the wallet seed", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Enter the wallet seed", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Navbar {
|
@section Navbar {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@{
|
@{
|
||||||
Layout = "_LayoutWalletSetup";
|
Layout = "_LayoutWalletSetup";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, "Enter your extended public key", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Enter your extended public key", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Navbar {
|
@section Navbar {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@{
|
@{
|
||||||
Layout = "_LayoutWalletSetup";
|
Layout = "_LayoutWalletSetup";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, $"Import {Model.CryptoCode} Wallet", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, $"Import {Model.CryptoCode} Wallet", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Navbar {
|
@section Navbar {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model IntegrationsViewModel
|
@model IntegrationsViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.Integrations, "Integrations", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.Integrations, "Integrations", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
<ul class="list-group mb-3">
|
<ul class="list-group mb-3">
|
||||||
<vc:ui-extension-point location="store-integrations-list" model="@Model"></vc:ui-extension-point>
|
<vc:ui-extension-point location="store-integrations-list" model="@Model" />
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h4 class="mt-5 mb-3">Other Integrations</h4>
|
<h4 class="mt-5 mb-3">Other Integrations</h4>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@model LightningSettingsViewModel
|
@model LightningSettingsViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, $"{Model.CryptoCode} Lightning Settings", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.LightningSettings, $"{Model.CryptoCode} Lightning Settings", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model TokensViewModel
|
@model TokensViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.Tokens, "Access Tokens", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.Tokens, "Access Tokens", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (Model.StoreNotConfigured)
|
@if (Model.StoreNotConfigured)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@using BTCPayServer.Client.Models;
|
@using BTCPayServer.Client.Models;
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.Webhooks, "Webhook Settings", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.Webhooks, "Webhook Settings", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section PageHeadContent {
|
@section PageHeadContent {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
@inject BTCPayServer.Security.ContentSecurityPolicies csp
|
@inject BTCPayServer.Security.ContentSecurityPolicies csp
|
||||||
@model PayButtonViewModel
|
@model PayButtonViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
ViewData.SetActivePage(StoreNavPages.PayButton, "Pay Button", Context.GetStoreData().Id);
|
||||||
ViewData.SetActivePage(StoreNavPages.PayButton, "Pay Button", Context.GetStoreData().StoreName);
|
|
||||||
csp.AllowUnsafeHashes("onBTCPayFormSubmit(event);return false");
|
csp.AllowUnsafeHashes("onBTCPayFormSubmit(event);return false");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,10 +68,13 @@
|
|||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<partial name="_StatusMessage" />
|
||||||
|
|
||||||
|
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
|
||||||
|
|
||||||
<div id="payButtonCtrl">
|
<div id="payButtonCtrl">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-7">
|
<div class="col-lg-7">
|
||||||
<h3 class="mb-3">@ViewData["Title"]</h3>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<p>Configure your Pay Button, and the generated code will be displayed at the bottom of the page to copy into your project.</p>
|
<p>Configure your Pay Button, and the generated code will be displayed at the bottom of the page to copy into your project.</p>
|
||||||
<h4 class="mt-3 mb-3">General Settings</h4>
|
<h4 class="mt-3 mb-3">General Settings</h4>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
ViewData.SetActivePage(StoreNavPages.PayButton, "Pay Button", Context.GetStoreData().Id);
|
||||||
ViewData.SetActivePage(StoreNavPages.PayButton, "Pay Button", Context.GetStoreData().StoreName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-10">
|
<div class="col-md-10">
|
||||||
<h4 class="mb-3">@ViewData["Title"]</h4>
|
|
||||||
<p>
|
<p>
|
||||||
To start using Pay Button, you need to enable this feature explicitly.
|
To start using Pay Button, you need to enable this feature explicitly.
|
||||||
Once you do so, anyone could create an invoice on your store (via API, for example).
|
Once you do so, anyone could create an invoice on your store (via API, for example).
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
@using System.Text.RegularExpressions
|
@using System.Text.RegularExpressions
|
||||||
@using BTCPayServer.Lightning
|
@using BTCPayServer.Lightning
|
||||||
@using BTCPayServer.Services
|
|
||||||
@model PaymentMethodsViewModel
|
@model PaymentMethodsViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, "Wallets", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.PaymentMethods, "Wallets", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model BTCPayServer.Models.StoreViewModels.RatesViewModel
|
@model BTCPayServer.Models.StoreViewModels.RatesViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.Rates, "Rates", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.Rates, "Rates", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model PairingModel
|
@model PairingModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.Tokens, "Pairing Permission", Context.GetStoreData()?.StoreName);
|
ViewData.SetActivePage(StoreNavPages.Tokens, "Pairing Permission", Context.GetStoreData()?.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<h3 class="mb-0">@ViewData["Title"]</h3>
|
<h3 class="mb-0">@ViewData["Title"]</h3>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model LightningNodeViewModel
|
@model LightningNodeViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "_LayoutWalletSetup.cshtml";
|
Layout = "_LayoutWalletSetup.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, "Connect to a Lightning node", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.LightningSettings, "Connect to a Lightning node", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<header class="text-center">
|
<header class="text-center">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model WalletSetupViewModel
|
@model WalletSetupViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "_LayoutWalletSetup";
|
Layout = "_LayoutWalletSetup";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, $"Setup {Model.CryptoCode} Wallet", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, $"Setup {Model.CryptoCode} Wallet", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<h1 class="text-center">Let's get started</h1>
|
<h1 class="text-center">Let's get started</h1>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model BTCPayServer.Security.Bitpay.BitTokenEntity
|
@model BTCPayServer.Security.Bitpay.BitTokenEntity
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.Tokens, "Access Tokens", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.Tokens, "Access Tokens", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<h3 class="mb-4">@ViewData["Title"]</h3>
|
<h3 class="mb-4">@ViewData["Title"]</h3>
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ namespace BTCPayServer.Views.Stores
|
|||||||
{
|
{
|
||||||
public enum StoreNavPages
|
public enum StoreNavPages
|
||||||
{
|
{
|
||||||
Index, Create, Rates, PaymentMethods, CheckoutAppearance, GeneralSettings, Tokens, Users, PayButton, Integrations, Webhooks, ActivePage, PullPayments, Payouts
|
Index, Create, Rates, PaymentMethods, OnchainSettings, LightningSettings, CheckoutAppearance, GeneralSettings, Tokens, Users, PayButton, Integrations, Webhooks, PullPayments, Payouts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model StoreUsersViewModel
|
@model StoreUsersViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.Users, "Store Users", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.Users, "Store Users", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@using BTCPayServer.Client.Models;
|
@using BTCPayServer.Client.Models;
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.Webhooks, "Send a test event to a webhook endpoint", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.Webhooks, "Send a test event to a webhook endpoint", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
@model WalletSettingsViewModel
|
@model WalletSettingsViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.PaymentMethods, $"{Model.CryptoCode} Wallet Settings", Context.GetStoreData().StoreName);
|
ViewData["NavPartialName"] = "../Wallets/_Nav";
|
||||||
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, $"{Model.CryptoCode} Wallet Settings", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section PageHeadContent {
|
@section PageHeadContent {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model WebhooksViewModel
|
@model WebhooksViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.Webhooks, "Webhooks", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(StoreNavPages.Webhooks, "Webhooks", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.GeneralSettings))" class="nav-link @ViewData.IsActivePage(StoreNavPages.GeneralSettings)" asp-controller="Stores" asp-action="GeneralSettings" asp-route-storeId="@Context.GetRouteValue("storeId")">General Settings</a>
|
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.GeneralSettings))" class="nav-link @ViewData.IsActivePage(StoreNavPages.GeneralSettings)" asp-controller="Stores" asp-action="GeneralSettings" asp-route-storeId="@Context.GetRouteValue("storeId")">General Settings</a>
|
||||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Tokens))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Tokens)" asp-controller="Stores" asp-action="ListTokens" asp-route-storeId="@Context.GetRouteValue("storeId")">Access Tokens</a>
|
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Tokens))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Tokens)" asp-controller="Stores" asp-action="ListTokens" asp-route-storeId="@Context.GetRouteValue("storeId")">Access Tokens</a>
|
||||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Users))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Users)" asp-controller="Stores" asp-action="StoreUsers" asp-route-storeId="@Context.GetRouteValue("storeId")">Users</a>
|
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Users))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Users)" asp-controller="Stores" asp-action="StoreUsers" asp-route-storeId="@Context.GetRouteValue("storeId")">Users</a>
|
||||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.PayButton))" class="nav-link @ViewData.IsActivePage(StoreNavPages.PayButton)" asp-controller="Stores" asp-action="PayButton" asp-route-storeId="@Context.GetRouteValue("storeId")">Pay Button</a>
|
|
||||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Integrations))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Integrations)" asp-controller="Stores" asp-action="Integrations" asp-route-storeId="@Context.GetRouteValue("storeId")">Integrations</a>
|
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Integrations))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Integrations)" asp-controller="Stores" asp-action="Integrations" asp-route-storeId="@Context.GetRouteValue("storeId")">Integrations</a>
|
||||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Webhooks))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Webhooks)" asp-controller="Stores" asp-action="Webhooks" asp-route-storeId="@Context.GetRouteValue("storeId")">Webhooks</a>
|
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Webhooks))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Webhooks)" asp-controller="Stores" asp-action="Webhooks" asp-route-storeId="@Context.GetRouteValue("storeId")">Webhooks</a>
|
||||||
<vc:ui-extension-point location="store-nav" model="@Model" />
|
<vc:ui-extension-point location="store-nav" model="@Model" />
|
||||||
|
|||||||
@@ -3,6 +3,5 @@
|
|||||||
@using BTCPayServer.Views.Stores
|
@using BTCPayServer.Views.Stores
|
||||||
|
|
||||||
@{
|
@{
|
||||||
ViewBag.CategoryTitle = "Stores";
|
|
||||||
ViewData.SetActiveCategory(typeof(StoreNavPages));
|
ViewData.SetActiveCategory(typeof(StoreNavPages));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,13 +69,13 @@
|
|||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td style="text-align:right">
|
<td style="text-align:right">
|
||||||
<a asp-action="ListInvoices" asp-controller="Invoice" asp-route-searchTerm="storeid:@store.Id">Invoices</a><span> - </span>
|
<a asp-action="ListInvoices" asp-controller="Invoice" asp-route-storeId="@store.Id">Invoices</a><span> - </span>
|
||||||
<a asp-action="PullPayments" asp-controller="StorePullPayments" asp-route-storeId="@store.Id">Pull Payments</a>
|
<a asp-action="PullPayments" asp-controller="StorePullPayments" asp-route-storeId="@store.Id">Pull Payments</a>
|
||||||
@if (store.IsOwner)
|
@if (store.IsOwner)
|
||||||
{
|
{
|
||||||
<span> - </span>
|
<span> - </span>
|
||||||
<a asp-action="PaymentMethods" asp-controller="Stores" asp-route-storeId="@store.Id" id="update-store-@store.Id">Settings</a><span> - </span>
|
<a asp-action="PaymentMethods" asp-controller="Stores" asp-route-storeId="@store.Id" id="update-store-@store.Id">Settings</a><span> - </span>
|
||||||
<a asp-action="DeleteStore" asp-controller="Stores" asp-route-storeId="@store.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The store <strong>@store.Name</strong> will be permanently deleted. This action will also delete all invoices, apps and data associated with the store." data-confirm-input="DELETE">Delete</a><span> - </span>
|
<a asp-action="DeleteStore" asp-controller="Stores" asp-route-storeId="@store.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The store <strong>@store.Name</strong> will be permanently deleted. This action will also delete all invoices, apps and data associated with the store." data-confirm-input="DELETE">Delete</a>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
@model SignWithSeedViewModel
|
@model SignWithSeedViewModel
|
||||||
@{
|
@{
|
||||||
|
var walletId = Context.GetRouteValue("walletId").ToString();
|
||||||
Layout = "_LayoutWizard";
|
Layout = "_LayoutWizard";
|
||||||
ViewData.SetActivePage(WalletsNavPages.Send, "Sign PSBT", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(WalletsNavPages.Send, "Sign PSBT", walletId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Navbar {
|
@section Navbar {
|
||||||
<a asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" id="GoBack">
|
<a asp-action="WalletPSBT" asp-route-walletId="@walletId" id="GoBack">
|
||||||
<vc:icon symbol="back" />
|
<vc:icon symbol="back" />
|
||||||
</a>
|
</a>
|
||||||
<a asp-action="WalletSend" asp-route-walletId="@Context.GetRouteValue("walletId")" class="cancel">
|
<a asp-action="WalletSend" asp-route-walletId="@walletId" class="cancel">
|
||||||
<vc:icon symbol="close" />
|
<vc:icon symbol="close" />
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
@@ -39,7 +40,7 @@
|
|||||||
|
|
||||||
<div asp-validation-summary="All" class="text-danger"></div>
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
|
||||||
<form method="post" asp-action="SignWithSeed" asp-route-walletId="@Context.GetRouteValue("walletId")">
|
<form method="post" asp-action="SignWithSeed" asp-route-walletId="@walletId">
|
||||||
<partial name="SigningContext" for="SigningContext"/>
|
<partial name="SigningContext" for="SigningContext"/>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="SeedOrKey" class="form-label"></label>
|
<label asp-for="SeedOrKey" class="form-label"></label>
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
@model WalletPSBTViewModel
|
@model WalletPSBTViewModel
|
||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@{
|
@{
|
||||||
|
var walletId = Context.GetRouteValue("walletId").ToString();
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(WalletsNavPages.PSBT, "Decode PSBT", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(WalletsNavPages.PSBT, "Decode PSBT", walletId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section PageHeadContent {
|
@section PageHeadContent {
|
||||||
@@ -41,7 +42,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
<p>You can decode a PSBT by either pasting its content, uploading the file or scanning the wallet QR code.</p>
|
<p>You can decode a PSBT by either pasting its content, uploading the file or scanning the wallet QR code.</p>
|
||||||
<form class="form-group" method="post" asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" enctype="multipart/form-data">
|
<form class="form-group" method="post" asp-action="WalletPSBT" asp-route-walletId="@walletId" enctype="multipart/form-data">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="PSBT" class="form-label"></label>
|
<label asp-for="PSBT" class="form-label"></label>
|
||||||
<textarea class="form-control" rows="5" asp-for="PSBT"></textarea>
|
<textarea class="form-control" rows="5" asp-for="PSBT"></textarea>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
@model WalletPSBTCombineViewModel
|
@model WalletPSBTCombineViewModel
|
||||||
@{
|
@{
|
||||||
|
var walletId = Context.GetRouteValue("walletId").ToString();
|
||||||
Layout = "_LayoutWizard";
|
Layout = "_LayoutWizard";
|
||||||
ViewData.SetActivePage(WalletsNavPages.PSBT, "Combine PSBT", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(WalletsNavPages.PSBT, "Combine PSBT", walletId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Navbar {
|
@section Navbar {
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
@model WalletPSBTViewModel
|
@model WalletPSBTViewModel
|
||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@{
|
@{
|
||||||
|
var walletId = Context.GetRouteValue("walletId").ToString();
|
||||||
var isReady = !Model.HasErrors;
|
var isReady = !Model.HasErrors;
|
||||||
var isSignable = !isReady && Model.NBXSeedAvailable;
|
var isSignable = !isReady && Model.NBXSeedAvailable;
|
||||||
var needsExport = !isSignable && !isReady;
|
var needsExport = !isSignable && !isReady;
|
||||||
Layout = "_LayoutWizard";
|
Layout = "_LayoutWizard";
|
||||||
ViewData.SetActivePage(WalletsNavPages.PSBT, isReady ? "Confirm broadcasting this transaction" : "Transaction Details", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(WalletsNavPages.PSBT, isReady ? "Confirm broadcasting this transaction" : "Transaction Details", walletId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section PageHeadContent {
|
@section PageHeadContent {
|
||||||
@@ -49,7 +50,7 @@
|
|||||||
|
|
||||||
@if (isSignable)
|
@if (isSignable)
|
||||||
{
|
{
|
||||||
<form method="post" asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" class="my-5">
|
<form method="post" asp-action="WalletPSBT" asp-route-walletId="@walletId" class="my-5">
|
||||||
<input type="hidden" asp-for="CryptoCode"/>
|
<input type="hidden" asp-for="CryptoCode"/>
|
||||||
<input type="hidden" asp-for="NBXSeedAvailable"/>
|
<input type="hidden" asp-for="NBXSeedAvailable"/>
|
||||||
<input type="hidden" asp-for="PSBT"/>
|
<input type="hidden" asp-for="PSBT"/>
|
||||||
@@ -61,7 +62,7 @@
|
|||||||
}
|
}
|
||||||
else if (isReady)
|
else if (isReady)
|
||||||
{
|
{
|
||||||
<form method="post" asp-action="WalletPSBTReady" asp-route-walletId="@Context.GetRouteValue("walletId")" class="my-5">
|
<form method="post" asp-action="WalletPSBTReady" asp-route-walletId="@walletId" class="my-5">
|
||||||
<input type="hidden" asp-for="SigningKey" />
|
<input type="hidden" asp-for="SigningKey" />
|
||||||
<input type="hidden" asp-for="SigningKeyPath" />
|
<input type="hidden" asp-for="SigningKeyPath" />
|
||||||
<partial name="SigningContext" for="SigningContext" />
|
<partial name="SigningContext" for="SigningContext" />
|
||||||
@@ -97,7 +98,7 @@ else
|
|||||||
</h2>
|
</h2>
|
||||||
<div id="PSBTOptionsExportContent" class="accordion-collapse collapse @(needsExport ? "show" : "")" aria-labelledby="PSBTOptionsExportHeader" data-bs-parent="#PSBTOptions">
|
<div id="PSBTOptionsExportContent" class="accordion-collapse collapse @(needsExport ? "show" : "")" aria-labelledby="PSBTOptionsExportHeader" data-bs-parent="#PSBTOptions">
|
||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
<form method="post" asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" class="mb-2">
|
<form method="post" asp-action="WalletPSBT" asp-route-walletId="@walletId" class="mb-2">
|
||||||
<input type="hidden" asp-for="CryptoCode"/>
|
<input type="hidden" asp-for="CryptoCode"/>
|
||||||
<input type="hidden" asp-for="PSBT"/>
|
<input type="hidden" asp-for="PSBT"/>
|
||||||
<div class="d-flex flex-column flex-sm-row flex-wrap align-items-sm-center">
|
<div class="d-flex flex-column flex-sm-row flex-wrap align-items-sm-center">
|
||||||
@@ -146,7 +147,7 @@ else
|
|||||||
</h2>
|
</h2>
|
||||||
<div id="PSBTOptionsImportContent" class="accordion-collapse collapse" aria-labelledby="PSBTOptionsImportHeader" data-bs-parent="#PSBTOptions">
|
<div id="PSBTOptionsImportContent" class="accordion-collapse collapse" aria-labelledby="PSBTOptionsImportHeader" data-bs-parent="#PSBTOptions">
|
||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
<form method="post" asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" enctype="multipart/form-data" class="mb-2">
|
<form method="post" asp-action="WalletPSBT" asp-route-walletId="@walletId" enctype="multipart/form-data" class="mb-2">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="ImportedPSBT" class="form-label">PSBT content</label>
|
<label for="ImportedPSBT" class="form-label">PSBT content</label>
|
||||||
<textarea id="ImportedPSBT" name="PSBT" class="form-control" rows="5"></textarea>
|
<textarea id="ImportedPSBT" name="PSBT" class="form-control" rows="5"></textarea>
|
||||||
@@ -173,7 +174,7 @@ else
|
|||||||
</h2>
|
</h2>
|
||||||
<div id="PSBTOptionsAdvancedContent" class="accordion-collapse collapse" aria-labelledby="PSBTOptionsAdvancedHeader" data-bs-parent="#PSBTOptions">
|
<div id="PSBTOptionsAdvancedContent" class="accordion-collapse collapse" aria-labelledby="PSBTOptionsAdvancedHeader" data-bs-parent="#PSBTOptions">
|
||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
<form method="post" asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" class="mb-2">
|
<form method="post" asp-action="WalletPSBT" asp-route-walletId="@walletId" class="mb-2">
|
||||||
<input type="hidden" asp-for="CryptoCode"/>
|
<input type="hidden" asp-for="CryptoCode"/>
|
||||||
<input type="hidden" asp-for="NBXSeedAvailable"/>
|
<input type="hidden" asp-for="NBXSeedAvailable"/>
|
||||||
<input type="hidden" asp-for="PSBT"/>
|
<input type="hidden" asp-for="PSBT"/>
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@model BTCPayServer.Controllers.WalletReceiveViewModel
|
@model BTCPayServer.Controllers.WalletReceiveViewModel
|
||||||
@{
|
@{
|
||||||
|
var walletId = Context.GetRouteValue("walletId").ToString();
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(WalletsNavPages.Receive, $"Receive {Model.CryptoCode}", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(WalletsNavPages.Receive, $"Receive {Model.CryptoCode}", walletId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section PageHeadContent
|
@section PageHeadContent
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
@model RescanWalletModel
|
@model RescanWalletModel
|
||||||
@{
|
@{
|
||||||
|
var walletId = Context.GetRouteValue("walletId").ToString();
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(WalletsNavPages.Rescan, "Rescan wallet", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(WalletsNavPages.Rescan, "Rescan wallet", walletId);
|
||||||
}
|
}
|
||||||
|
|
||||||
<h4 class="mb-3">@ViewData["Title"]</h4>
|
<h4 class="mb-3">@ViewData["Title"]</h4>
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
@using Microsoft.AspNetCore.Mvc.ModelBinding
|
@using Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
@model WalletSendModel
|
@model WalletSendModel
|
||||||
@{
|
@{
|
||||||
|
var walletId = Context.GetRouteValue("walletId").ToString();
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(WalletsNavPages.Send, $"Send {Model.CryptoCode}", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(WalletsNavPages.Send, $"Send {Model.CryptoCode}", walletId);
|
||||||
csp.Add("worker-src", "blob:");
|
csp.Add("worker-src", "blob:");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-8 col-xl-7 @(!Model.InputSelection && Model.Outputs.Count == 1 ? "transaction-output-form" : "")">
|
<div class="col-lg-8 col-xl-7 @(!Model.InputSelection && Model.Outputs.Count == 1 ? "transaction-output-form" : "")">
|
||||||
<h4 class="mb-3">@ViewData["Title"]</h4>
|
<h4 class="mb-3">@ViewData["Title"]</h4>
|
||||||
<form method="post" asp-action="WalletSend" asp-route-walletId="@Context.GetRouteValue("walletId")">
|
<form method="post" asp-action="WalletSend" asp-route-walletId="@walletId">
|
||||||
<input type="hidden" asp-for="InputSelection" />
|
<input type="hidden" asp-for="InputSelection" />
|
||||||
<input type="hidden" asp-for="FiatDivisibility" />
|
<input type="hidden" asp-for="FiatDivisibility" />
|
||||||
<input type="hidden" asp-for="CryptoDivisibility" />
|
<input type="hidden" asp-for="CryptoDivisibility" />
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
@model WalletSendVaultModel
|
@model WalletSendVaultModel
|
||||||
@{
|
@{
|
||||||
|
var walletId = Context.GetRouteValue("walletId").ToString();
|
||||||
Layout = "_LayoutWizard";
|
Layout = "_LayoutWizard";
|
||||||
ViewData.SetActivePage(WalletsNavPages.Send, "Sign the transaction", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(WalletsNavPages.Send, "Sign the transaction", walletId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Navbar {
|
@section Navbar {
|
||||||
<a asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" id="GoBack">
|
<a asp-action="WalletPSBT" asp-route-walletId="@walletId" id="GoBack">
|
||||||
<vc:icon symbol="back" />
|
<vc:icon symbol="back" />
|
||||||
</a>
|
</a>
|
||||||
<a asp-action="WalletSend" asp-route-walletId="@Context.GetRouteValue("walletId")" class="cancel">
|
<a asp-action="WalletSend" asp-route-walletId="@walletId" class="cancel">
|
||||||
<vc:icon symbol="close" />
|
<vc:icon symbol="close" />
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
@@ -26,7 +27,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="body" class="my-4">
|
<div id="body" class="my-4">
|
||||||
<form id="broadcastForm" asp-action="WalletSendVault" asp-route-walletId="@Context.GetRouteValue("walletId")" method="post" style="display:none;">
|
<form id="broadcastForm" asp-action="WalletSendVault" asp-route-walletId="@walletId" method="post" style="display:none;">
|
||||||
<input type="hidden" id="WalletId" asp-for="WalletId" />
|
<input type="hidden" id="WalletId" asp-for="WalletId" />
|
||||||
<input type="hidden" asp-for="WebsocketPath" />
|
<input type="hidden" asp-for="WebsocketPath" />
|
||||||
<partial name="SigningContext" for="SigningContext" />
|
<partial name="SigningContext" for="SigningContext" />
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
@inject BTCPayNetworkProvider BTCPayNetworkProvider
|
@inject BTCPayNetworkProvider BTCPayNetworkProvider
|
||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@{
|
@{
|
||||||
Layout = "_LayoutWizard";
|
|
||||||
ViewData.SetActivePage(WalletsNavPages.Send, "Sign the transaction", Context.GetStoreData().StoreName);
|
|
||||||
var walletId = WalletId.Parse(Context.GetRouteValue("walletId").ToString());
|
var walletId = WalletId.Parse(Context.GetRouteValue("walletId").ToString());
|
||||||
|
Layout = "_LayoutWizard";
|
||||||
|
ViewData.SetActivePage(WalletsNavPages.Send, "Sign the transaction", walletId.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Navbar {
|
@section Navbar {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
@model ListTransactionsViewModel
|
@model ListTransactionsViewModel
|
||||||
@{
|
@{
|
||||||
|
var walletId = Context.GetRouteValue("walletId").ToString();
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(WalletsNavPages.Transactions, $"{Model.CryptoCode} Transactions", Context.GetStoreData().StoreName);
|
ViewData.SetActivePage(WalletsNavPages.Transactions, $"{Model.CryptoCode} Transactions", walletId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section PageHeadContent {
|
@section PageHeadContent {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace BTCPayServer.Views.Wallets
|
|||||||
Transactions,
|
Transactions,
|
||||||
Rescan,
|
Rescan,
|
||||||
PSBT,
|
PSBT,
|
||||||
Receive
|
Receive,
|
||||||
|
Settings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,25 @@
|
|||||||
@inject SignInManager<ApplicationUser> SignInManager
|
@using BTCPayServer.Views.Stores
|
||||||
@inject BTCPayNetworkProvider BtcPayNetworkProvider
|
@using BTCPayServer.Client
|
||||||
|
@inject BTCPayNetworkProvider _btcPayNetworkProvider
|
||||||
@{
|
@{
|
||||||
var wallet = WalletId.Parse(Context.GetRouteValue("walletId").ToString());
|
var walletId = Context.GetRouteValue("walletId")?.ToString();
|
||||||
var network = BtcPayNetworkProvider.GetNetwork<BTCPayNetwork>(wallet.CryptoCode);
|
var storeId = Context.GetRouteValue("storeId")?.ToString();
|
||||||
|
var cryptoCode = Context.GetRouteValue("cryptoCode")?.ToString();
|
||||||
|
var wallet = walletId != null ? WalletId.Parse(walletId) : new WalletId(storeId, cryptoCode);
|
||||||
|
var network = _btcPayNetworkProvider.GetNetwork<BTCPayNetwork>(wallet.CryptoCode);
|
||||||
}
|
}
|
||||||
<nav id="SectionNav" class="nav">
|
<nav id="SectionNav" class="nav">
|
||||||
<a class="nav-link @ViewData.IsActivePage(WalletsNavPages.Transactions)" asp-action="WalletTransactions" asp-route-walletId="@Context.GetRouteValue("walletId")" id="SectionNav-Transactions">Transactions</a>
|
<a class="nav-link @ViewData.IsActivePage(WalletsNavPages.Transactions)" asp-controller="Wallets" asp-action="WalletTransactions" asp-route-walletId="@wallet" id="SectionNav-Transactions" permission="@Policies.CanModifyStoreSettings">Transactions</a>
|
||||||
@if (!network.ReadonlyWallet)
|
@if (!network.ReadonlyWallet)
|
||||||
{
|
{
|
||||||
<a class="nav-link @ViewData.IsActivePage(WalletsNavPages.Send)" asp-action="WalletSend" asp-route-walletId="@Context.GetRouteValue("walletId")" id="SectionNav-Send">Send</a>
|
<a class="nav-link @ViewData.IsActivePage(WalletsNavPages.Send)" asp-controller="Wallets" asp-action="WalletSend" asp-route-walletId="@wallet" id="SectionNav-Send" permission="@Policies.CanModifyStoreSettings">Send</a>
|
||||||
}
|
}
|
||||||
<a class="nav-link @ViewData.IsActivePage(WalletsNavPages.Receive)" asp-action="WalletReceive" asp-route-walletId="@Context.GetRouteValue("walletId")" id="SectionNav-Receive">Receive</a>
|
<a class="nav-link @ViewData.IsActivePage(WalletsNavPages.Receive)" asp-controller="Wallets" asp-action="WalletReceive" asp-route-walletId="@wallet" id="SectionNav-Receive" permission="@Policies.CanModifyStoreSettings">Receive</a>
|
||||||
<a class="nav-link @ViewData.IsActivePage(WalletsNavPages.Rescan)" asp-action="WalletRescan" asp-route-walletId="@Context.GetRouteValue("walletId")" id="SectionNav-Rescan">Rescan</a>
|
<a class="nav-link @ViewData.IsActivePage(WalletsNavPages.Rescan)" asp-controller="Wallets" asp-action="WalletRescan" asp-route-walletId="@wallet" id="SectionNav-Rescan" permission="@Policies.CanModifyServerSettings">Rescan</a>
|
||||||
@if (!network.ReadonlyWallet)
|
@if (!network.ReadonlyWallet)
|
||||||
{
|
{
|
||||||
<a class="nav-link @ViewData.IsActivePage(WalletsNavPages.PSBT)" asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" id="SectionNav-PSBT">PSBT</a>
|
<a class="nav-link @ViewData.IsActivePage(WalletsNavPages.PSBT)" asp-controller="Wallets" asp-action="WalletPSBT" asp-route-walletId="@wallet" id="SectionNav-PSBT" permission="@Policies.CanModifyStoreSettings">PSBT</a>
|
||||||
}
|
}
|
||||||
<vc:ui-extension-point location="wallet-nav" model="@Model" />
|
<a class="nav-link @ViewData.IsActivePage(WalletsNavPages.Settings) @ViewData.IsActivePage(StoreNavPages.OnchainSettings)" asp-controller="Stores" asp-action="WalletSettings" asp-route-cryptoCode="@wallet.CryptoCode" asp-route-storeId="@wallet.StoreId" id="SectionNav-Settings" permission="@Policies.CanModifyStoreSettings">Settings</a>
|
||||||
|
<vc:ui-extension-point location="wallet-nav" model="@Model"/>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -2,6 +2,5 @@
|
|||||||
@using BTCPayServer.Views
|
@using BTCPayServer.Views
|
||||||
@using BTCPayServer.Views.Wallets
|
@using BTCPayServer.Views.Wallets
|
||||||
@{
|
@{
|
||||||
ViewBag.CategoryTitle = "Wallets";
|
|
||||||
ViewData.SetActiveCategory(typeof(WalletsNavPages));
|
ViewData.SetActiveCategory(typeof(WalletsNavPages));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,4 +29,5 @@
|
|||||||
<symbol id="payment-1" viewBox="0 0 24 24"><path d="M7.2 11.2h9.6v1.6H7.2v-1.6Zm0 4.8h5.6v-1.6H7.2V16ZM20 7.02v9.96c0 1.23-1.07 2.22-2.4 2.22H6.4c-1.31 0-2.4-1-2.4-2.22V7.02C4 5.81 5.09 4.8 6.4 4.8h11.2c1.31 0 2.4 1 2.4 2.22ZM18.4 12V7.02c0-.33-.38-.62-.8-.62H6.4c-.43 0-.8.29-.8.62v9.96c0 .33.37.62.8.62h11.2c.43 0 .8-.29.8-.62V12ZM7.2 9.6h9.6V8H7.2v1.6Z" fill="currentColor"/></symbol>
|
<symbol id="payment-1" viewBox="0 0 24 24"><path d="M7.2 11.2h9.6v1.6H7.2v-1.6Zm0 4.8h5.6v-1.6H7.2V16ZM20 7.02v9.96c0 1.23-1.07 2.22-2.4 2.22H6.4c-1.31 0-2.4-1-2.4-2.22V7.02C4 5.81 5.09 4.8 6.4 4.8h11.2c1.31 0 2.4 1 2.4 2.22ZM18.4 12V7.02c0-.33-.38-.62-.8-.62H6.4c-.43 0-.8.29-.8.62v9.96c0 .33.37.62.8.62h11.2c.43 0 .8-.29.8-.62V12ZM7.2 9.6h9.6V8H7.2v1.6Z" fill="currentColor"/></symbol>
|
||||||
<symbol id="payment-2" viewBox="0 0 24 24"><path d="M12 20a8 8 0 1 1 0-16 8 8 0 0 1 0 16Zm0-15.19a7.2 7.2 0 0 0 0 14.38A7.2 7.2 0 0 0 12 4.8Z" fill="currentColor" stroke="currentColor" stroke-width=".6"/><path d="M9.48 14.85a.44.44 0 0 1-.3-.14c-.14-.16-.14-.43.05-.57l5.02-4.31c.16-.14.43-.14.57.05.14.17.14.44-.05.57l-5.05 4.29c-.05.08-.16.1-.24.1Z" fill="currentColor" stroke="currentColor" stroke-width=".6"/><path d="M14.39 14.28a.4.4 0 0 1-.41-.4l.1-3.42-3.08-.17a.4.4 0 0 1-.38-.43c0-.22.19-.4.43-.38l3.47.19c.22 0 .38.19.38.4l-.13 3.83c.02.19-.17.38-.38.38Z" fill="currentColor" stroke="currentColor" stroke-width=".6"/></symbol>
|
<symbol id="payment-2" viewBox="0 0 24 24"><path d="M12 20a8 8 0 1 1 0-16 8 8 0 0 1 0 16Zm0-15.19a7.2 7.2 0 0 0 0 14.38A7.2 7.2 0 0 0 12 4.8Z" fill="currentColor" stroke="currentColor" stroke-width=".6"/><path d="M9.48 14.85a.44.44 0 0 1-.3-.14c-.14-.16-.14-.43.05-.57l5.02-4.31c.16-.14.43-.14.57.05.14.17.14.44-.05.57l-5.05 4.29c-.05.08-.16.1-.24.1Z" fill="currentColor" stroke="currentColor" stroke-width=".6"/><path d="M14.39 14.28a.4.4 0 0 1-.41-.4l.1-3.42-3.08-.17a.4.4 0 0 1-.38-.43c0-.22.19-.4.43-.38l3.47.19c.22 0 .38.19.38.4l-.13 3.83c.02.19-.17.38-.38.38Z" fill="currentColor" stroke="currentColor" stroke-width=".6"/></symbol>
|
||||||
<symbol id="invoice" viewBox="0 0 24 24"><path d="M17.1 20H6.9c-.83 0-1.53-.7-1.53-1.52V5.52c0-.82.7-1.52 1.52-1.52h10.22c.83 0 1.52.7 1.52 1.52v12.96c0 .82-.7 1.52-1.52 1.52ZM6.9 5.3c-.14 0-.23.1-.23.22v12.96c0 .13.1.22.22.22h10.22c.13 0 .22-.1.22-.22V5.52c0-.13-.09-.22-.22-.22H6.89Z" fill="currentColor"/><path d="M12.24 7.95H8.11c-.09 0-.13-.05-.13-.15v-1c0-.05.04-.1.09-.1h4.13c.04 0 .08.05.08.1v1c.05.1 0 .15-.04.15ZM16.2 17.6H8.1c-.08 0-.12-.08-.12-.12V9.87a.1.1 0 0 1 .09-.09h8.08a.1.1 0 0 1 .09.09v7.44c0 .11.06.3-.04.3Z" fill="currentColor"/></symbol>
|
<symbol id="invoice" viewBox="0 0 24 24"><path d="M17.1 20H6.9c-.83 0-1.53-.7-1.53-1.52V5.52c0-.82.7-1.52 1.52-1.52h10.22c.83 0 1.52.7 1.52 1.52v12.96c0 .82-.7 1.52-1.52 1.52ZM6.9 5.3c-.14 0-.23.1-.23.22v12.96c0 .13.1.22.22.22h10.22c.13 0 .22-.1.22-.22V5.52c0-.13-.09-.22-.22-.22H6.89Z" fill="currentColor"/><path d="M12.24 7.95H8.11c-.09 0-.13-.05-.13-.15v-1c0-.05.04-.1.09-.1h4.13c.04 0 .08.05.08.1v1c.05.1 0 .15-.04.15ZM16.2 17.6H8.1c-.08 0-.12-.08-.12-.12V9.87a.1.1 0 0 1 .09-.09h8.08a.1.1 0 0 1 .09.09v7.44c0 .11.06.3-.04.3Z" fill="currentColor"/></symbol>
|
||||||
|
<symbol id="shopify" viewBox="0 0 32 32"><path transform="scale(.7) translate(5, 5)" d="m20.45 31.97 9.62-2.08-3.5-23.64c-.03-.16-.15-.26-.28-.26l-2.57-.18s-1.7-1.7-1.92-1.88a.41.41 0 0 0-.16-.1l-1.22 28.14zm-4.83-16.9s-1.09-.56-2.37-.56c-1.93 0-2 1.2-2 1.52 0 1.64 4.31 2.29 4.31 6.17 0 3.06-1.92 5.01-4.54 5.01-3.14 0-4.72-1.95-4.72-1.95l.86-2.78s1.66 1.42 3.04 1.42c.9 0 1.3-.72 1.3-1.24 0-2.16-3.54-2.26-3.54-5.81-.04-2.98 2.1-5.9 6.44-5.9 1.68 0 2.5.49 2.5.49l-1.26 3.62zM14.9 1.1c.17 0 .36.06.53.19-1.31.62-2.75 2.18-3.34 5.32-.88.28-1.73.54-2.52.77.69-2.38 2.36-6.26 5.33-6.26zm1.64 3.94v.18l-3.2.98c.63-2.37 1.79-3.53 2.79-3.96.26.67.41 1.57.41 2.8zm.72-2.98c.92.1 1.52 1.15 1.9 2.34-.46.15-.98.3-1.54.49v-.34c0-1-.13-1.82-.36-2.5zm3.99 1.72-.1.03c-.03 0-.39.1-.96.28-.56-1.65-1.56-3.16-3.34-3.16h-.16C16.2.28 15.56 0 15.02 0 10.88 0 8.9 5.17 8.28 7.8c-1.6.48-2.75.84-2.88.9-.9.28-.93.3-1.03 1.15-.1.62-2.44 18.75-2.44 18.75L20.01 32z" fill="currentColor"/></symbol>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
@@ -8,9 +8,7 @@
|
|||||||
:root {
|
:root {
|
||||||
--mobile-header-height: 4rem;
|
--mobile-header-height: 4rem;
|
||||||
--desktop-header-height: 8rem;
|
--desktop-header-height: 8rem;
|
||||||
--sidebar-width: 15%;
|
--sidebar-width: 280px;
|
||||||
--sidebar-min-width: 250px;
|
|
||||||
--sidebar-max-width: 350px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Main Menu */
|
/* Main Menu */
|
||||||
@@ -278,8 +276,6 @@
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: var(--sidebar-width);
|
width: var(--sidebar-width);
|
||||||
min-width: var(--sidebar-min-width);
|
|
||||||
max-width: var(--sidebar-max-width);
|
|
||||||
z-index: 1045;
|
z-index: 1045;
|
||||||
color: var(--btcpay-body-text);
|
color: var(--btcpay-body-text);
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
@@ -381,8 +377,6 @@
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: var(--sidebar-width);
|
width: var(--sidebar-width);
|
||||||
min-width: var(--sidebar-min-width);
|
|
||||||
max-width: var(--sidebar-max-width);
|
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +406,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#mainContent {
|
#mainContent {
|
||||||
margin-left: clamp(var(--sidebar-min-width), var(--sidebar-width), var(--sidebar-max-width));
|
margin-left: var(--sidebar-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
#mainContent > section {
|
#mainContent > section {
|
||||||
|
|||||||
Reference in New Issue
Block a user