Can disable method of payments

This commit is contained in:
Andrew Camilleri 2018-07-27 13:37:16 +02:00 committed by nicolas.dorier
parent 3775317047
commit d480be925b
12 changed files with 185 additions and 42 deletions

View File

@ -123,9 +123,10 @@ namespace BTCPayServer.Controllers
HashSet<CurrencyPair> currencyPairsToFetch = new HashSet<CurrencyPair>();
var rules = storeBlob.GetRateRules(_NetworkProvider);
var excludeFilter = storeBlob.GetExcludedPaymentMethods(); // Here we can compose filters from other origin with PaymentFilter.Any()
foreach (var network in store.GetSupportedPaymentMethods(_NetworkProvider)
.Select(c => _NetworkProvider.GetNetwork(c.PaymentId.CryptoCode))
.Where(s => !excludeFilter.Match(s.PaymentId))
.Select(c => _NetworkProvider.GetNetwork(c.PaymentId.CryptoCode))
.Where(c => c != null))
{
currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, invoice.Currency));
@ -140,6 +141,7 @@ namespace BTCPayServer.Controllers
var fetchingAll = WhenAllFetched(logs, fetchingByCurrencyPair);
var supportedPaymentMethods = store.GetSupportedPaymentMethods(_NetworkProvider)
.Where(s => !excludeFilter.Match(s.PaymentId))
.Select(c =>
(Handler: (IPaymentMethodHandler)_ServiceProvider.GetService(typeof(IPaymentMethodHandler<>).MakeGenericType(c.GetType())),
SupportedPaymentMethod: c,

View File

@ -44,6 +44,7 @@ namespace BTCPayServer.Controllers
private void SetExistingValues(StoreData store, DerivationSchemeViewModel vm)
{
vm.DerivationScheme = GetExistingDerivationStrategy(vm.CryptoCode, store)?.DerivationStrategyBase.ToString();
vm.Enabled = !store.GetStoreBlob().IsExcluded(new PaymentMethodId(vm.CryptoCode, PaymentTypes.BTCLike));
}
private DerivationStrategy GetExistingDerivationStrategy(string cryptoCode, StoreData store)
@ -93,10 +94,8 @@ namespace BTCPayServer.Controllers
vm.Confirmation = false;
return View(vm);
}
if (!vm.Confirmation && strategy != null)
return ShowAddresses(vm, strategy);
if (vm.Confirmation && !string.IsNullOrWhiteSpace(vm.HintAddress))
{
BitcoinAddress address = null;
@ -132,6 +131,10 @@ namespace BTCPayServer.Controllers
if (strategy != null)
await wallet.TrackAsync(strategy.DerivationStrategyBase);
store.SetSupportedPaymentMethod(paymentMethodId, strategy);
var storeBlob = store.GetStoreBlob();
storeBlob.SetExcluded(paymentMethodId, !vm.Enabled);
store.SetStoreBlob(storeBlob);
}
catch
{

View File

@ -24,9 +24,11 @@ namespace BTCPayServer.Controllers
var store = HttpContext.GetStoreData();
if (store == null)
return NotFound();
LightningNodeViewModel vm = new LightningNodeViewModel();
vm.CryptoCode = cryptoCode;
vm.InternalLightningNode = GetInternalLighningNode(cryptoCode)?.ToString();
LightningNodeViewModel vm = new LightningNodeViewModel
{
CryptoCode = cryptoCode,
InternalLightningNode = GetInternalLighningNode(cryptoCode)?.ToString()
};
SetExistingValues(store, vm);
return View(vm);
}
@ -34,6 +36,7 @@ namespace BTCPayServer.Controllers
private void SetExistingValues(StoreData store, LightningNodeViewModel vm)
{
vm.ConnectionString = GetExistingLightningSupportedPaymentMethod(vm.CryptoCode, store)?.GetLightningUrl()?.ToString();
vm.Enabled = !store.GetStoreBlob().IsExcluded(new PaymentMethodId(vm.CryptoCode, PaymentTypes.LightningLike));
}
private LightningSupportedPaymentMethod GetExistingLightningSupportedPaymentMethod(string cryptoCode, StoreData store)
{
@ -132,41 +135,43 @@ namespace BTCPayServer.Controllers
CryptoCode = paymentMethodId.CryptoCode
};
paymentMethod.SetLightningUrl(connectionString);
var storeBlob = store.GetStoreBlob();
storeBlob.SetExcluded(paymentMethod.PaymentId , vm.Enabled);
store.SetStoreBlob(storeBlob);
}
if (command == "save")
switch (command)
{
store.SetSupportedPaymentMethod(paymentMethodId, paymentMethod);
await _Repo.UpdateStore(store);
StatusMessage = $"Lightning node modified ({network.CryptoCode})";
return RedirectToAction(nameof(UpdateStore), new { storeId = storeId });
}
else // if(command == "test")
{
if (paymentMethod == null)
{
case "save":
store.SetSupportedPaymentMethod(paymentMethodId, paymentMethod);
await _Repo.UpdateStore(store);
StatusMessage = $"Lightning node modified ({network.CryptoCode})";
return RedirectToAction(nameof(UpdateStore), new { storeId = storeId });
case "test" when paymentMethod == null:
ModelState.AddModelError(nameof(vm.ConnectionString), "Missing url parameter");
return View(vm);
}
var handler = (LightningLikePaymentHandler)_ServiceProvider.GetRequiredService<IPaymentMethodHandler<Payments.Lightning.LightningSupportedPaymentMethod>>();
try
{
var info = await handler.Test(paymentMethod, network);
if (!vm.SkipPortTest)
case "test":
var handler = (LightningLikePaymentHandler)_ServiceProvider.GetRequiredService<IPaymentMethodHandler<Payments.Lightning.LightningSupportedPaymentMethod>>();
try
{
using (CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
var info = await handler.Test(paymentMethod, network);
if (!vm.SkipPortTest)
{
await handler.TestConnection(info, cts.Token);
using (CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
{
await handler.TestConnection(info, cts.Token);
}
}
vm.StatusMessage = $"Connection to the lightning node succeeded ({info})";
}
catch (Exception ex)
{
vm.StatusMessage = $"Error: {ex.Message}";
return View(vm);
}
vm.StatusMessage = $"Connection to the lightning node succeeded ({info})";
}
catch (Exception ex)
{
vm.StatusMessage = $"Error: {ex.Message}";
return View(vm);
}
return View(vm);
default:
return View(vm);
}
}

View File

@ -404,7 +404,7 @@ namespace BTCPayServer.Controllers
vm.NetworkFee = !storeBlob.NetworkFeeDisabled;
vm.SpeedPolicy = store.SpeedPolicy;
vm.CanDelete = _Repo.CanDeleteStores();
AddPaymentMethods(store, vm);
AddPaymentMethods(store, storeBlob, vm);
vm.MonitoringExpiration = storeBlob.MonitoringExpiration;
vm.InvoiceExpiration = storeBlob.InvoiceExpiration;
vm.LightningDescriptionTemplate = storeBlob.LightningDescriptionTemplate;
@ -413,8 +413,9 @@ namespace BTCPayServer.Controllers
}
private void AddPaymentMethods(StoreData store, StoreViewModel vm)
private void AddPaymentMethods(StoreData store, StoreBlob storeBlob, StoreViewModel vm)
{
var excludeFilters = storeBlob.GetExcludedPaymentMethods();
var derivationByCryptoCode =
store
.GetSupportedPaymentMethods(_NetworkProvider)
@ -428,6 +429,7 @@ namespace BTCPayServer.Controllers
Crypto = network.CryptoCode,
Value = strategy?.DerivationStrategyBase?.ToString() ?? string.Empty,
WalletId = new WalletId(store.Id, network.CryptoCode),
Enabled = !excludeFilters.Match(new Payments.PaymentMethodId(network.CryptoCode, Payments.PaymentTypes.BTCLike))
});
}
@ -439,10 +441,12 @@ namespace BTCPayServer.Controllers
foreach (var network in _NetworkProvider.GetAll())
{
var lightning = lightningByCryptoCode.TryGet(network.CryptoCode);
var paymentId = new Payments.PaymentMethodId(network.CryptoCode, Payments.PaymentTypes.LightningLike);
vm.LightningNodes.Add(new StoreViewModel.LightningNode()
{
CryptoCode = network.CryptoCode,
Address = lightning?.GetLightningUrl()?.BaseUri.AbsoluteUri ?? string.Empty
Address = lightning?.GetLightningUrl()?.BaseUri.AbsoluteUri ?? string.Empty,
Enabled = !excludeFilters.Match(paymentId)
});
}
}

View File

@ -199,7 +199,7 @@ namespace BTCPayServer.Data
#pragma warning disable CS0618
public string GetDefaultCrypto(BTCPayNetworkProvider networkProvider = null)
{
return DefaultCrypto ?? (networkProvider == null? "BTC" : GetSupportedPaymentMethods(networkProvider).First().PaymentId.CryptoCode);
return DefaultCrypto ?? (networkProvider == null ? "BTC" : GetSupportedPaymentMethods(networkProvider).First().PaymentId.CryptoCode);
}
public void SetDefaultCrypto(string defaultCryptoCurrency)
{
@ -336,8 +336,8 @@ namespace BTCPayServer.Data
public BTCPayServer.Rating.RateRules GetRateRules(BTCPayNetworkProvider networkProvider)
{
if (!RateScripting ||
string.IsNullOrEmpty(RateScript) ||
if (!RateScripting ||
string.IsNullOrEmpty(RateScript) ||
!BTCPayServer.Rating.RateRules.TryParse(RateScript, out var rules))
{
return GetDefaultRateRules(networkProvider);
@ -373,5 +373,34 @@ namespace BTCPayServer.Data
rules.GlobalMultiplier = GetRateMultiplier();
return rules;
}
[Obsolete("Use GetExcludedPaymentMethods instead")]
public string[] ExcludedPaymentMethods { get; set; }
public IPaymentFilter GetExcludedPaymentMethods()
{
#pragma warning disable CS0618 // Type or member is obsolete
if (ExcludedPaymentMethods == null || ExcludedPaymentMethods.Length == 0)
return PaymentFilter.Never();
return PaymentFilter.Any(ExcludedPaymentMethods.Select(p => PaymentFilter.WhereIs(PaymentMethodId.Parse(p))).ToArray());
#pragma warning restore CS0618 // Type or member is obsolete
}
public bool IsExcluded(PaymentMethodId paymentMethodId)
{
return GetExcludedPaymentMethods().Match(paymentMethodId);
}
public void SetExcluded(PaymentMethodId paymentMethodId, bool value)
{
#pragma warning disable CS0618 // Type or member is obsolete
var methods = new HashSet<string>(ExcludedPaymentMethods ?? Array.Empty<string>());
if (value)
methods.Add(paymentMethodId.ToString());
else
methods.Remove(paymentMethodId.ToString());
ExcludedPaymentMethods = methods.ToArray();
#pragma warning restore CS0618 // Type or member is obsolete
}
}
}

View File

@ -27,6 +27,7 @@ namespace BTCPayServer.Models.StoreViewModels
[Display(Name = "Hint address")]
public string HintAddress { get; set; }
public bool Confirmation { get; set; }
public bool Enabled { get; set; } = true;
public string ServerUrl { get; set; }
public string StatusMessage { get; internal set; }

View File

@ -24,5 +24,6 @@ namespace BTCPayServer.Models.StoreViewModels
public string StatusMessage { get; set; }
public string InternalLightningNode { get; internal set; }
public bool SkipPortTest { get; set; }
public bool Enabled { get; set; } = true;
}
}

View File

@ -19,6 +19,7 @@ namespace BTCPayServer.Models.StoreViewModels
public string Crypto { get; set; }
public string Value { get; set; }
public WalletId WalletId { get; set; }
public bool Enabled { get; set; }
}
public StoreViewModel()
@ -83,6 +84,7 @@ namespace BTCPayServer.Models.StoreViewModels
{
public string CryptoCode { get; set; }
public string Address { get; set; }
public bool Enabled { get; set; }
}
public List<LightningNode> LightningNodes
{

View File

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BTCPayServer.Payments
{
public interface IPaymentFilter
{
bool Match(PaymentMethodId paymentMethodId);
}
public class PaymentFilter
{
class NeverPaymentFilter : IPaymentFilter
{
private static readonly NeverPaymentFilter _Instance = new NeverPaymentFilter();
public static NeverPaymentFilter Instance
{
get
{
return _Instance;
}
}
public bool Match(PaymentMethodId paymentMethodId)
{
return false;
}
}
class CompositePaymentFilter : IPaymentFilter
{
private readonly IPaymentFilter[] _filters;
public CompositePaymentFilter(IPaymentFilter[] filters)
{
_filters = filters;
}
public bool Match(PaymentMethodId paymentMethodId)
{
return _filters.Any(f => f.Match(paymentMethodId));
}
}
class PaymentIdFilter : IPaymentFilter
{
private readonly PaymentMethodId _paymentMethodId;
public PaymentIdFilter(PaymentMethodId paymentMethodId)
{
_paymentMethodId = paymentMethodId;
}
public bool Match(PaymentMethodId paymentMethodId)
{
return paymentMethodId == _paymentMethodId;
}
}
public static IPaymentFilter Never()
{
return NeverPaymentFilter.Instance;
}
public static IPaymentFilter Any(IPaymentFilter[] filters)
{
if (filters == null)
throw new ArgumentNullException(nameof(filters));
return new CompositePaymentFilter(filters);
}
public static IPaymentFilter WhereIs(PaymentMethodId paymentMethodId)
{
if (paymentMethodId == null)
throw new ArgumentNullException(nameof(paymentMethodId));
return new PaymentIdFilter(paymentMethodId);
}
}
}

View File

@ -1,7 +1,7 @@
@model DerivationSchemeViewModel
@{
Layout = "../Shared/_NavLayout.cshtml";
ViewData["Title"] = "Add derivation scheme";
ViewData["Title"] = $"{Model.CryptoCode} Derivation scheme";
ViewData.AddActivePage(BTCPayServer.Views.Stores.StoreNavPages.Index);
}
@ -77,7 +77,12 @@
</tbody>
</table>
</div>
<button name="command" type="submit" class="btn btn-primary">Continue</button>
<div class="form-check">
<input id="enabled" asp-for="Enabled" class="form-check-input" />
<label asp-for="Enabled" class="form-check-label"></label>
<span asp-validation-for="Enabled" class="text-danger"></span>
</div>
<button name="command" type="submit" class="btn btn-primary" value="save">Continue</button>
}
else
{
@ -87,6 +92,7 @@
</div>
<input type="hidden" asp-for="Confirmation" />
<input type="hidden" asp-for="DerivationScheme" />
<input type="hidden" asp-for="Enabled" />
<div class="form-group">
<table class="table table-sm table-responsive-md">
<thead>
@ -116,7 +122,7 @@
<input asp-for="HintAddress" class="form-control" />
<span asp-validation-for="HintAddress" class="text-danger"></span>
</div>
<button name="command" type="submit" class="btn btn-primary">Confirm</button>
<button name="command" type="submit" class="btn btn-primary" value="save">Confirm</button>
}
</form>
</div>

View File

@ -55,13 +55,18 @@
<label asp-for="ConnectionString"></label>
<input id="lightningurl" asp-for="ConnectionString" class="form-control" />
<span asp-validation-for="ConnectionString" class="text-danger"></span>
@if(Model.InternalLightningNode != null)
@if (Model.InternalLightningNode != null)
{
<p class="form-text text-muted">
You can use the internal lightning node by <a href="#" onclick="$('#lightningurl').val('@Model.InternalLightningNode'); return false;">clicking here</a>
</p>
}
</div>
<div class="form-check">
<input id="enabled" asp-for="Enabled" class="form-check-input" />
<label asp-for="Enabled" class="form-check-label"></label>
<span asp-validation-for="Enabled" class="text-danger"></span>
</div>
<button name="command" type="submit" value="save" class="btn btn-primary">Submit</button>
<button name="command" type="submit" value="test" class="btn btn-secondary">Test connection</button>
</form>

View File

@ -70,6 +70,7 @@
<tr>
<th>Crypto</th>
<th>Derivation Scheme</th>
<th>Status</th>
<th style="text-align:right">Actions</th>
</tr>
</thead>
@ -79,6 +80,12 @@
<tr>
<td>@scheme.Crypto</td>
<td style="max-width:300px;overflow:hidden;">@scheme.Value</td>
<td>
@if (!string.IsNullOrWhiteSpace(scheme.Value))
{
@(scheme.Enabled ? "Enabled" : "Disabled")
}
</td>
<td style="text-align:right">
@if(!string.IsNullOrWhiteSpace(scheme.Value))
{
@ -106,6 +113,7 @@
<tr>
<th>Crypto</th>
<th>Address</th>
<th>Status</th>
<th style="text-align:right">Actions</th>
</tr>
</thead>
@ -115,6 +123,9 @@
<tr>
<td>@scheme.CryptoCode</td>
<td>@scheme.Address</td>
<td>
@(scheme.Enabled ? "Enabled" : "Disabled")
</td>
<td style="text-align:right"><a asp-action="AddLightningNode" asp-route-cryptoCode="@scheme.CryptoCode">Modify</a></td>
</tr>
}