mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
Prevent payment request to be created when a wallet is not set up (#5620)
* Prevent payment request to be created when a wallet is not set up * Created an extension method for store wallet checks * fix for invoice and payment request selenium test * refactoring payment request controller * removing unused variable * Unify behaviour across controllers --------- Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
This commit is contained in:
committed by
GitHub
parent
e90414bded
commit
f7542c988d
@@ -565,9 +565,11 @@ namespace BTCPayServer.Tests
|
|||||||
s.RegisterNewUser(true);
|
s.RegisterNewUser(true);
|
||||||
s.CreateNewStore();
|
s.CreateNewStore();
|
||||||
s.GoToInvoices();
|
s.GoToInvoices();
|
||||||
s.Driver.FindElement(By.Id("CreateNewInvoice")).Click();
|
|
||||||
// Should give us an error message if we try to create an invoice before adding a wallet
|
// Should give us an error message if we try to create an invoice before adding a wallet
|
||||||
|
s.Driver.FindElement(By.Id("CreateNewInvoice")).Click();
|
||||||
Assert.Contains("To create an invoice, you need to", s.Driver.PageSource);
|
Assert.Contains("To create an invoice, you need to", s.Driver.PageSource);
|
||||||
|
|
||||||
s.AddDerivationScheme();
|
s.AddDerivationScheme();
|
||||||
s.GoToInvoices();
|
s.GoToInvoices();
|
||||||
s.CreateInvoice();
|
s.CreateInvoice();
|
||||||
@@ -1195,8 +1197,13 @@ namespace BTCPayServer.Tests
|
|||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
s.RegisterNewUser();
|
s.RegisterNewUser();
|
||||||
s.CreateNewStore();
|
s.CreateNewStore();
|
||||||
s.AddDerivationScheme();
|
s.Driver.FindElement(By.Id("StoreNav-PaymentRequests")).Click();
|
||||||
|
|
||||||
|
// Should give us an error message if we try to create a payment request before adding a wallet
|
||||||
|
s.Driver.FindElement(By.Id("CreatePaymentRequest")).Click();
|
||||||
|
Assert.Contains("To create a payment request, you need to", s.Driver.PageSource);
|
||||||
|
|
||||||
|
s.AddDerivationScheme();
|
||||||
s.Driver.FindElement(By.Id("StoreNav-PaymentRequests")).Click();
|
s.Driver.FindElement(By.Id("StoreNav-PaymentRequests")).Click();
|
||||||
s.Driver.FindElement(By.Id("CreatePaymentRequest")).Click();
|
s.Driver.FindElement(By.Id("CreatePaymentRequest")).Click();
|
||||||
s.Driver.FindElement(By.Id("Title")).SendKeys("Pay123");
|
s.Driver.FindElement(By.Id("Title")).SendKeys("Pay123");
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Mime;
|
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Reflection.Metadata;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Abstractions.Constants;
|
using BTCPayServer.Abstractions.Constants;
|
||||||
@@ -32,10 +29,8 @@ using Microsoft.AspNetCore.Mvc.Rendering;
|
|||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NBitcoin;
|
using NBitcoin;
|
||||||
using NBitpayClient;
|
|
||||||
using NBXplorer;
|
using NBXplorer;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using BitpayCreateInvoiceRequest = BTCPayServer.Models.BitpayCreateInvoiceRequest;
|
|
||||||
using StoreData = BTCPayServer.Data.StoreData;
|
using StoreData = BTCPayServer.Data.StoreData;
|
||||||
|
|
||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
@@ -1149,63 +1144,34 @@ namespace BTCPayServer.Controllers
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private SelectList GetPaymentMethodsSelectList()
|
|
||||||
{
|
|
||||||
var store = GetCurrentStore();
|
|
||||||
var excludeFilter = store.GetStoreBlob().GetExcludedPaymentMethods();
|
|
||||||
|
|
||||||
return new SelectList(store.GetSupportedPaymentMethods(_NetworkProvider)
|
|
||||||
.Where(s => !excludeFilter.Match(s.PaymentId))
|
|
||||||
.Select(method => new SelectListItem(method.PaymentId.ToPrettyString(), method.PaymentId.ToString())),
|
|
||||||
nameof(SelectListItem.Value),
|
|
||||||
nameof(SelectListItem.Text));
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool AnyPaymentMethodAvailable(StoreData store)
|
|
||||||
{
|
|
||||||
var storeBlob = store.GetStoreBlob();
|
|
||||||
var excludeFilter = storeBlob.GetExcludedPaymentMethods();
|
|
||||||
|
|
||||||
return store.GetSupportedPaymentMethods(_NetworkProvider).Where(s => !excludeFilter.Match(s.PaymentId)).Any();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("/stores/{storeId}/invoices/create")]
|
[HttpGet("/stores/{storeId}/invoices/create")]
|
||||||
[HttpGet("invoices/create")]
|
[HttpGet("invoices/create")]
|
||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||||
[BitpayAPIConstraint(false)]
|
[BitpayAPIConstraint(false)]
|
||||||
public async Task<IActionResult> CreateInvoice(InvoicesModel? model = null)
|
public async Task<IActionResult> CreateInvoice(InvoicesModel? model = null)
|
||||||
{
|
{
|
||||||
if (model?.StoreId != null)
|
if (string.IsNullOrEmpty(model?.StoreId))
|
||||||
{
|
|
||||||
var store = await _StoreRepository.FindStore(model.StoreId, GetUserId());
|
|
||||||
if (store == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
if (!AnyPaymentMethodAvailable(store))
|
|
||||||
{
|
|
||||||
TempData.SetStatusMessageModel(new StatusMessageModel
|
|
||||||
{
|
|
||||||
Severity = StatusMessageModel.StatusSeverity.Error,
|
|
||||||
Html = $"To create an invoice, you need to <a href='{Url.Action(nameof(UIStoresController.SetupWallet), "UIStores", new { cryptoCode = _NetworkProvider.DefaultNetwork.CryptoCode, storeId = store.Id })}' class='alert-link'>set up a wallet</a> first",
|
|
||||||
AllowDismiss = false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpContext.SetStoreData(store);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
TempData[WellKnownTempData.ErrorMessage] = "You need to select a store before creating an invoice.";
|
TempData[WellKnownTempData.ErrorMessage] = "You need to select a store before creating an invoice.";
|
||||||
return RedirectToAction(nameof(UIHomeController.Index), "UIHome");
|
return RedirectToAction(nameof(UIHomeController.Index), "UIHome");
|
||||||
}
|
}
|
||||||
|
|
||||||
var storeBlob = HttpContext.GetStoreData()?.GetStoreBlob();
|
var store = await _StoreRepository.FindStore(model.StoreId, GetUserId());
|
||||||
|
if (store == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (!store.AnyPaymentMethodAvailable(_NetworkProvider))
|
||||||
|
{
|
||||||
|
return NoPaymentMethodResult(store.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
var storeBlob = store.GetStoreBlob();
|
||||||
var vm = new CreateInvoiceModel
|
var vm = new CreateInvoiceModel
|
||||||
{
|
{
|
||||||
StoreId = model.StoreId,
|
StoreId = model.StoreId,
|
||||||
Currency = storeBlob?.DefaultCurrency,
|
Currency = storeBlob.DefaultCurrency,
|
||||||
CheckoutType = storeBlob?.CheckoutType ?? CheckoutType.V2,
|
CheckoutType = storeBlob.CheckoutType,
|
||||||
AvailablePaymentMethods = GetPaymentMethodsSelectList()
|
AvailablePaymentMethods = GetPaymentMethodsSelectList(store)
|
||||||
};
|
};
|
||||||
|
|
||||||
return View(vm);
|
return View(vm);
|
||||||
@@ -1218,9 +1184,14 @@ namespace BTCPayServer.Controllers
|
|||||||
public async Task<IActionResult> CreateInvoice(CreateInvoiceModel model, CancellationToken cancellationToken)
|
public async Task<IActionResult> CreateInvoice(CreateInvoiceModel model, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var store = HttpContext.GetStoreData();
|
var store = HttpContext.GetStoreData();
|
||||||
|
if (!store.AnyPaymentMethodAvailable(_NetworkProvider))
|
||||||
|
{
|
||||||
|
return NoPaymentMethodResult(store.Id);
|
||||||
|
}
|
||||||
|
|
||||||
var storeBlob = store.GetStoreBlob();
|
var storeBlob = store.GetStoreBlob();
|
||||||
model.CheckoutType = storeBlob.CheckoutType;
|
model.CheckoutType = storeBlob.CheckoutType;
|
||||||
model.AvailablePaymentMethods = GetPaymentMethodsSelectList();
|
model.AvailablePaymentMethods = GetPaymentMethodsSelectList(store);
|
||||||
|
|
||||||
JObject? metadataObj = null;
|
JObject? metadataObj = null;
|
||||||
if (!string.IsNullOrEmpty(model.Metadata))
|
if (!string.IsNullOrEmpty(model.Metadata))
|
||||||
@@ -1239,18 +1210,6 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AnyPaymentMethodAvailable(store))
|
|
||||||
{
|
|
||||||
TempData.SetStatusMessageModel(new StatusMessageModel
|
|
||||||
{
|
|
||||||
Severity = StatusMessageModel.StatusSeverity.Error,
|
|
||||||
Html = $"To create an invoice, you need to <a href='{Url.Action(nameof(UIStoresController.SetupWallet), "UIStores", new { cryptoCode = _NetworkProvider.DefaultNetwork.CryptoCode, storeId = store.Id })}' class='alert-link'>set up a wallet</a> first",
|
|
||||||
AllowDismiss = false
|
|
||||||
});
|
|
||||||
return View(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var metadata = metadataObj is null ? new InvoiceMetadata() : InvoiceMetadata.FromJObject(metadataObj);
|
var metadata = metadataObj is null ? new InvoiceMetadata() : InvoiceMetadata.FromJObject(metadataObj);
|
||||||
@@ -1396,5 +1355,26 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SelectList GetPaymentMethodsSelectList(StoreData store)
|
||||||
|
{
|
||||||
|
var excludeFilter = store.GetStoreBlob().GetExcludedPaymentMethods();
|
||||||
|
return new SelectList(store.GetSupportedPaymentMethods(_NetworkProvider)
|
||||||
|
.Where(s => !excludeFilter.Match(s.PaymentId))
|
||||||
|
.Select(method => new SelectListItem(method.PaymentId.ToPrettyString(), method.PaymentId.ToString())),
|
||||||
|
nameof(SelectListItem.Value),
|
||||||
|
nameof(SelectListItem.Text));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IActionResult NoPaymentMethodResult(string storeId)
|
||||||
|
{
|
||||||
|
TempData.SetStatusMessageModel(new StatusMessageModel
|
||||||
|
{
|
||||||
|
Severity = StatusMessageModel.StatusSeverity.Error,
|
||||||
|
Html = $"To create an invoice, you need to <a href='{Url.Action(nameof(UIStoresController.SetupWallet), "UIStores", new { cryptoCode = _NetworkProvider.DefaultNetwork.CryptoCode, storeId })}' class='alert-link'>set up a wallet</a> first",
|
||||||
|
AllowDismiss = false
|
||||||
|
});
|
||||||
|
return RedirectToAction(nameof(ListInvoices), new { storeId });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Abstractions.Constants;
|
using BTCPayServer.Abstractions.Constants;
|
||||||
|
using BTCPayServer.Abstractions.Extensions;
|
||||||
using BTCPayServer.Abstractions.Form;
|
using BTCPayServer.Abstractions.Form;
|
||||||
|
using BTCPayServer.Abstractions.Models;
|
||||||
using BTCPayServer.Client;
|
using BTCPayServer.Client;
|
||||||
using BTCPayServer.Client.Models;
|
using BTCPayServer.Client.Models;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
@@ -39,6 +41,7 @@ namespace BTCPayServer.Controllers
|
|||||||
private readonly DisplayFormatter _displayFormatter;
|
private readonly DisplayFormatter _displayFormatter;
|
||||||
private readonly InvoiceRepository _InvoiceRepository;
|
private readonly InvoiceRepository _InvoiceRepository;
|
||||||
private readonly StoreRepository _storeRepository;
|
private readonly StoreRepository _storeRepository;
|
||||||
|
private readonly BTCPayNetworkProvider _networkProvider;
|
||||||
|
|
||||||
private FormComponentProviders FormProviders { get; }
|
private FormComponentProviders FormProviders { get; }
|
||||||
public FormDataService FormDataService { get; }
|
public FormDataService FormDataService { get; }
|
||||||
@@ -54,7 +57,8 @@ namespace BTCPayServer.Controllers
|
|||||||
StoreRepository storeRepository,
|
StoreRepository storeRepository,
|
||||||
InvoiceRepository invoiceRepository,
|
InvoiceRepository invoiceRepository,
|
||||||
FormComponentProviders formProviders,
|
FormComponentProviders formProviders,
|
||||||
FormDataService formDataService)
|
FormDataService formDataService,
|
||||||
|
BTCPayNetworkProvider networkProvider)
|
||||||
{
|
{
|
||||||
_InvoiceController = invoiceController;
|
_InvoiceController = invoiceController;
|
||||||
_UserManager = userManager;
|
_UserManager = userManager;
|
||||||
@@ -67,6 +71,7 @@ namespace BTCPayServer.Controllers
|
|||||||
_InvoiceRepository = invoiceRepository;
|
_InvoiceRepository = invoiceRepository;
|
||||||
FormProviders = formProviders;
|
FormProviders = formProviders;
|
||||||
FormDataService = formDataService;
|
FormDataService = formDataService;
|
||||||
|
_networkProvider = networkProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("/stores/{storeId}/payment-requests")]
|
[HttpGet("/stores/{storeId}/payment-requests")]
|
||||||
@@ -107,11 +112,19 @@ namespace BTCPayServer.Controllers
|
|||||||
public async Task<IActionResult> EditPaymentRequest(string storeId, string payReqId)
|
public async Task<IActionResult> EditPaymentRequest(string storeId, string payReqId)
|
||||||
{
|
{
|
||||||
var store = GetCurrentStore();
|
var store = GetCurrentStore();
|
||||||
|
if (store == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
var paymentRequest = GetCurrentPaymentRequest();
|
var paymentRequest = GetCurrentPaymentRequest();
|
||||||
if (paymentRequest == null && !string.IsNullOrEmpty(payReqId))
|
if (paymentRequest == null && !string.IsNullOrEmpty(payReqId))
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
if (!store.AnyPaymentMethodAvailable(_networkProvider))
|
||||||
|
{
|
||||||
|
return NoPaymentMethodResult(storeId);
|
||||||
|
}
|
||||||
|
|
||||||
var storeBlob = store.GetStoreBlob();
|
var storeBlob = store.GetStoreBlob();
|
||||||
var prInvoices = payReqId is null ? null : (await _PaymentRequestService.GetPaymentRequest(payReqId, GetUserId())).Invoices;
|
var prInvoices = payReqId is null ? null : (await _PaymentRequestService.GetPaymentRequest(payReqId, GetUserId())).Invoices;
|
||||||
@@ -143,6 +156,10 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
if (!store.AnyPaymentMethodAvailable(_networkProvider))
|
||||||
|
{
|
||||||
|
return NoPaymentMethodResult(store.Id);
|
||||||
|
}
|
||||||
|
|
||||||
if (paymentRequest?.Archived is true && viewModel.Archived)
|
if (paymentRequest?.Archived is true && viewModel.Archived)
|
||||||
{
|
{
|
||||||
@@ -441,5 +458,16 @@ namespace BTCPayServer.Controllers
|
|||||||
private StoreData GetCurrentStore() => HttpContext.GetStoreData();
|
private StoreData GetCurrentStore() => HttpContext.GetStoreData();
|
||||||
|
|
||||||
private PaymentRequestData GetCurrentPaymentRequest() => HttpContext.GetPaymentRequestData();
|
private PaymentRequestData GetCurrentPaymentRequest() => HttpContext.GetPaymentRequestData();
|
||||||
|
|
||||||
|
private IActionResult NoPaymentMethodResult(string storeId)
|
||||||
|
{
|
||||||
|
TempData.SetStatusMessageModel(new StatusMessageModel
|
||||||
|
{
|
||||||
|
Severity = StatusMessageModel.StatusSeverity.Error,
|
||||||
|
Html = $"To create a payment request, you need to <a href='{Url.Action(nameof(UIStoresController.SetupWallet), "UIStores", new { cryptoCode = _networkProvider.DefaultNetwork.CryptoCode, storeId })}' class='alert-link'>set up a wallet</a> first",
|
||||||
|
AllowDismiss = false
|
||||||
|
});
|
||||||
|
return RedirectToAction(nameof(GetPaymentRequests), new { storeId });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,14 @@ namespace BTCPayServer.Data
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool AnyPaymentMethodAvailable(this StoreData storeData, BTCPayNetworkProvider networkProvider)
|
||||||
|
{
|
||||||
|
var storeBlob = GetStoreBlob(storeData);
|
||||||
|
var excludeFilter = storeBlob.GetExcludedPaymentMethods();
|
||||||
|
|
||||||
|
return GetSupportedPaymentMethods(storeData, networkProvider).Where(s => !excludeFilter.Match(s.PaymentId)).Any();
|
||||||
|
}
|
||||||
|
|
||||||
public static bool SetStoreBlob(this StoreData storeData, StoreBlob storeBlob)
|
public static bool SetStoreBlob(this StoreData storeData, StoreBlob storeBlob)
|
||||||
{
|
{
|
||||||
var original = new Serializer(null).ToString(storeData.GetStoreBlob());
|
var original = new Serializer(null).ToString(storeData.GetStoreBlob());
|
||||||
|
|||||||
Reference in New Issue
Block a user