Change the UX to set lightning node or derivation schemes

This commit is contained in:
nicolas.dorier 2018-03-21 02:48:11 +09:00
parent 21b91ac8f7
commit 265cddc38b
11 changed files with 58 additions and 98 deletions

View file

@ -80,11 +80,10 @@ namespace BTCPayServer.Tests
await store.AddDerivationScheme(StoreId, new DerivationSchemeViewModel()
{
CryptoCurrency = cryptoCode,
DerivationSchemeFormat = "BTCPay",
DerivationScheme = DerivationScheme.ToString(),
Confirmation = true
});
}, cryptoCode);
}
public DerivationStrategyBase DerivationScheme { get; set; }
@ -125,11 +124,10 @@ namespace BTCPayServer.Tests
var storeController = parent.PayTester.GetController<StoresController>(UserId);
await storeController.AddLightningNode(StoreId, new LightningNodeViewModel()
{
CryptoCurrency = "BTC",
Url = connectionType == LightningConnectionType.Charge ? parent.MerchantCharge.Client.Uri.AbsoluteUri :
connectionType == LightningConnectionType.CLightning ? parent.MerchantLightningD.Address.AbsoluteUri
: throw new NotSupportedException(connectionType.ToString())
}, "save");
}, "save", "BTC");
if (storeController.ModelState.ErrorCount != 0)
Assert.False(true, storeController.ModelState.FirstOrDefault().Value.Errors[0].ErrorMessage);
}

View file

@ -303,24 +303,22 @@ namespace BTCPayServer.Tests
user.GrantAccess();
var storeController = tester.PayTester.GetController<StoresController>(user.UserId);
Assert.IsType<ViewResult>(storeController.UpdateStore(user.StoreId).GetAwaiter().GetResult());
Assert.IsType<ViewResult>(storeController.AddLightningNode(user.StoreId).GetAwaiter().GetResult());
Assert.IsType<ViewResult>(storeController.AddLightningNode(user.StoreId, "BTC").GetAwaiter().GetResult());
var testResult = storeController.AddLightningNode(user.StoreId, new LightningNodeViewModel()
{
CryptoCurrency = "BTC",
Url = tester.MerchantCharge.Client.Uri.AbsoluteUri
}, "test").GetAwaiter().GetResult();
}, "test", "BTC").GetAwaiter().GetResult();
Assert.DoesNotContain("Error", ((LightningNodeViewModel)Assert.IsType<ViewResult>(testResult).Model).StatusMessage, StringComparison.OrdinalIgnoreCase);
Assert.True(storeController.ModelState.IsValid);
Assert.IsType<RedirectToActionResult>(storeController.AddLightningNode(user.StoreId, new LightningNodeViewModel()
{
CryptoCurrency = "BTC",
Url = tester.MerchantCharge.Client.Uri.AbsoluteUri
}, "save").GetAwaiter().GetResult());
}, "save", "BTC").GetAwaiter().GetResult());
var storeVm = Assert.IsType<Models.StoreViewModels.StoreViewModel>(Assert.IsType<ViewResult>(storeController.UpdateStore(user.StoreId).GetAwaiter().GetResult()).Model);
Assert.Single(storeVm.LightningNodes);
Assert.Single(storeVm.LightningNodes.Where(l => !string.IsNullOrEmpty(l.Address)));
}
}

View file

@ -20,40 +20,37 @@ namespace BTCPayServer.Controllers
public partial class StoresController
{
[HttpGet]
[Route("{storeId}/derivations")]
public async Task<IActionResult> AddDerivationScheme(string storeId, string selectedScheme = null)
[Route("{storeId}/derivations/{cryptoCode}")]
public async Task<IActionResult> AddDerivationScheme(string storeId, string cryptoCode)
{
selectedScheme = selectedScheme ?? "BTC";
var store = await _Repo.FindStore(storeId, GetUserId());
if (store == null)
return NotFound();
DerivationSchemeViewModel vm = new DerivationSchemeViewModel();
vm.ServerUrl = GetStoreUrl(storeId);
vm.SetCryptoCurrencies(_ExplorerProvider, selectedScheme);
vm.CryptoCode = cryptoCode;
return View(vm);
}
[HttpPost]
[Route("{storeId}/derivations")]
public async Task<IActionResult> AddDerivationScheme(string storeId, DerivationSchemeViewModel vm)
[Route("{storeId}/derivations/{cryptoCode}")]
public async Task<IActionResult> AddDerivationScheme(string storeId, DerivationSchemeViewModel vm, string cryptoCode)
{
vm.ServerUrl = GetStoreUrl(storeId);
vm.CryptoCode = cryptoCode;
var store = await _Repo.FindStore(storeId, GetUserId());
if (store == null)
return NotFound();
var network = vm.CryptoCurrency == null ? null : _ExplorerProvider.GetNetwork(vm.CryptoCurrency);
vm.SetCryptoCurrencies(_ExplorerProvider, vm.CryptoCurrency);
var network = cryptoCode == null ? null : _ExplorerProvider.GetNetwork(cryptoCode);
if (network == null)
{
ModelState.AddModelError(nameof(vm.CryptoCurrency), "Invalid network");
return View(vm);
return NotFound();
}
var wallet = _WalletProvider.GetWallet(network);
if (wallet == null)
{
ModelState.AddModelError(nameof(vm.CryptoCurrency), "Invalid network");
return View(vm);
return NotFound();
}
PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike);

View file

@ -15,23 +15,21 @@ namespace BTCPayServer.Controllers
public partial class StoresController
{
[HttpGet]
[Route("{storeId}/lightning")]
public async Task<IActionResult> AddLightningNode(string storeId, string selectedCrypto = null)
[Route("{storeId}/lightning/{cryptoCode}")]
public async Task<IActionResult> AddLightningNode(string storeId, string cryptoCode)
{
selectedCrypto = selectedCrypto ?? "BTC";
var store = await _Repo.FindStore(storeId, GetUserId());
if (store == null)
return NotFound();
LightningNodeViewModel vm = new LightningNodeViewModel();
vm.SetCryptoCurrencies(_NetworkProvider, selectedCrypto);
vm.InternalLightningNode = GetInternalLighningNode(selectedCrypto)?.ToUri(true)?.AbsoluteUri;
vm.CryptoCode = cryptoCode;
vm.InternalLightningNode = GetInternalLighningNode(cryptoCode)?.ToUri(true)?.AbsoluteUri;
return View(vm);
}
private LightningConnectionString GetInternalLighningNode(string selectedCrypto)
private LightningConnectionString GetInternalLighningNode(string cryptoCode)
{
selectedCrypto = "BTC";
if (_BtcpayServerOptions.InternalLightningByCryptoCode.TryGetValue(selectedCrypto, out var connectionString))
if (_BtcpayServerOptions.InternalLightningByCryptoCode.TryGetValue(cryptoCode, out var connectionString))
{
return CanUseInternalLightning() ? connectionString : null;
}
@ -39,20 +37,20 @@ namespace BTCPayServer.Controllers
}
[HttpPost]
[Route("{storeId}/lightning")]
public async Task<IActionResult> AddLightningNode(string storeId, LightningNodeViewModel vm, string command)
[Route("{storeId}/lightning/{cryptoCode}")]
public async Task<IActionResult> AddLightningNode(string storeId, LightningNodeViewModel vm, string command, string cryptoCode)
{
vm.CryptoCode = cryptoCode;
var store = await _Repo.FindStore(storeId, GetUserId());
if (store == null)
return NotFound();
var network = vm.CryptoCurrency == null ? null : _ExplorerProvider.GetNetwork(vm.CryptoCurrency);
vm.SetCryptoCurrencies(_NetworkProvider, vm.CryptoCurrency);
var network = vm.CryptoCode == null ? null : _ExplorerProvider.GetNetwork(vm.CryptoCode);
var internalLightning = GetInternalLighningNode(network.CryptoCode);
vm.InternalLightningNode = internalLightning?.ToUri(true)?.AbsoluteUri;
if (network == null)
{
ModelState.AddModelError(nameof(vm.CryptoCurrency), "Invalid network");
ModelState.AddModelError(nameof(vm.CryptoCode), "Invalid network");
return View(vm);
}

View file

@ -228,25 +228,33 @@ namespace BTCPayServer.Controllers
private void AddPaymentMethods(StoreData store, StoreViewModel vm)
{
foreach(var strategy in store
.GetSupportedPaymentMethods(_NetworkProvider)
.OfType<DerivationStrategy>())
var derivationByCryptoCode =
store
.GetSupportedPaymentMethods(_NetworkProvider)
.OfType<DerivationStrategy>()
.ToDictionary(c => c.Network.CryptoCode);
foreach (var network in _NetworkProvider.GetAll())
{
var strategy = derivationByCryptoCode.TryGet(network.CryptoCode);
vm.DerivationSchemes.Add(new StoreViewModel.DerivationScheme()
{
Crypto = strategy.PaymentId.CryptoCode,
Value = strategy.DerivationStrategyBase.ToString()
Crypto = network.CryptoCode,
Value = strategy?.DerivationStrategyBase?.ToString() ?? string.Empty
});
}
foreach(var lightning in store
var lightningByCryptoCode = store
.GetSupportedPaymentMethods(_NetworkProvider)
.OfType<Payments.Lightning.LightningSupportedPaymentMethod>())
.OfType<Payments.Lightning.LightningSupportedPaymentMethod>()
.ToDictionary(c => c.CryptoCode);
foreach (var network in _NetworkProvider.GetAll())
{
var lightning = lightningByCryptoCode.TryGet(network.CryptoCode);
vm.LightningNodes.Add(new StoreViewModel.LightningNode()
{
CryptoCode = lightning.CryptoCode,
Address = lightning.GetLightningUrl().BaseUri.AbsoluteUri
CryptoCode = network.CryptoCode,
Address = lightning?.GetLightningUrl()?.BaseUri.AbsoluteUri ?? string.Empty
});
}
}

View file

@ -41,26 +41,11 @@ namespace BTCPayServer.Models.StoreViewModels
set;
}
[Display(Name = "Crypto currency")]
public string CryptoCurrency
{
get;
set;
}
public string CryptoCode { get; set; }
public bool Confirmation { get; set; }
public SelectList CryptoCurrencies { get; set; }
public SelectList DerivationSchemeFormats { get; set; }
public string ServerUrl { get; set; }
public void SetCryptoCurrencies(ExplorerClientProvider explorerProvider, string selectedScheme)
{
var choices = explorerProvider.GetAll().Select(o => new Format() { Name = o.Item1.CryptoCode, Value = o.Item1.CryptoCode }).ToArray();
var chosen = choices.FirstOrDefault(f => f.Name == selectedScheme) ?? choices.FirstOrDefault();
CryptoCurrencies = new SelectList(choices, nameof(chosen.Value), nameof(chosen.Name), chosen);
CryptoCurrency = chosen.Name;
}
}
}

View file

@ -9,11 +9,6 @@ namespace BTCPayServer.Models.StoreViewModels
{
public class LightningNodeViewModel
{
class Format
{
public string Name { get; set; }
public string Value { get; set; }
}
[Display(Name = "Lightning charge url")]
public string Url
{
@ -21,23 +16,12 @@ namespace BTCPayServer.Models.StoreViewModels
set;
}
[Display(Name = "Crypto currency")]
public string CryptoCurrency
public string CryptoCode
{
get;
set;
}
public SelectList CryptoCurrencies { get; set; }
public string StatusMessage { get; set; }
public string InternalLightningNode { get; internal set; }
public void SetCryptoCurrencies(BTCPayNetworkProvider networkProvider, string selectedScheme)
{
var choices = networkProvider.GetAll()
.Select(o => new Format() { Name = o.CryptoCode, Value = o.CryptoCode }).ToArray();
var chosen = choices.FirstOrDefault(f => f.Name == selectedScheme) ?? choices.FirstOrDefault();
CryptoCurrencies = new SelectList(choices, nameof(chosen.Value), nameof(chosen.Name), chosen);
CryptoCurrency = chosen.Name;
}
}
}

View file

@ -21,10 +21,6 @@
<h5>Derivation Scheme</h5>
<span>The DerivationScheme represents the destination of the funds received by your invoice. It is generated by your wallet software. Please, verify that you are generating the right addresses by clicking on 'Check ExtPubKey'</span>
</div>
<div class="form-group">
<label asp-for="CryptoCurrency"></label>
<select asp-for="CryptoCurrency" asp-items="Model.CryptoCurrencies" class="form-control"></select>
</div>
<div class="form-group">
<label asp-for="DerivationScheme"></label>
@ -89,10 +85,9 @@
else
{
<div class="form-group">
<h5>Confirm the addresses (@Model.CryptoCurrency)</h5>
<span>Please check that your @Model.CryptoCurrency wallet is generating the same addresses as below.</span>
<h5>Confirm the addresses (@Model.CryptoCode)</h5>
<span>Please check that your @Model.CryptoCode wallet is generating the same addresses as below.</span>
</div>
<input type="hidden" asp-for="CryptoCurrency" />
<input type="hidden" asp-for="Confirmation" />
<input type="hidden" asp-for="DerivationScheme" />
<input type="hidden" asp-for="DerivationSchemeFormat" />

View file

@ -33,13 +33,8 @@
<form method="post">
<div class="form-group">
<h5>Lightning node url</h5>
<span>This URL should point to an installed lightning charge server</span>
<span>This URL should point to an installed lightning charge server for @Model.CryptoCode</span>
</div>
<div class="form-group">
<label asp-for="CryptoCurrency"></label>
<select asp-for="CryptoCurrency" asp-items="Model.CryptoCurrencies" class="form-control"></select>
</div>
<div class="form-group">
<label asp-for="Url"></label>
<input id="lightningurl" asp-for="Url" class="form-control" />

View file

@ -28,7 +28,7 @@
<th>Name</th>
<th>Website</th>
<th>Balances</th>
<th>Actions</th>
<th style="text-align:right">Actions</th>
</tr>
</thead>
<tbody>
@ -52,7 +52,7 @@
}
}
</td>
<td><a asp-action="UpdateStore" asp-route-storeId="@store.Id">Settings</a> - <a asp-action="DeleteStore" asp-route-storeId="@store.Id">Remove</a></td>
<td style="text-align:right"><a asp-action="UpdateStore" asp-route-storeId="@store.Id">Settings</a> - <a asp-action="DeleteStore" asp-route-storeId="@store.Id">Remove</a></td>
</tr>
}
</tbody>

View file

@ -80,21 +80,22 @@
</div>
<div class="form-group">
<a asp-action="AddDerivationScheme" class="btn btn-success" role="button"><span class="glyphicon glyphicon-plus"></span>Add or modify a derivation scheme</a>
<table class="table">
<thead class="thead-inverse">
<tr>
<th>Crypto</th>
<th>Derivation Scheme</th>
<th style="text-align:right">Actions</th>
</tr>
</thead>
<tbody>
@foreach (var scheme in Model.DerivationSchemes)
{
<tr>
<td>@scheme.Crypto</td>
<td style="max-width:400px;overflow:hidden;">@scheme.Value</td>
</tr>
<tr>
<td>@scheme.Crypto</td>
<td style="max-width:400px;overflow:hidden;">@scheme.Value</td>
<td style="text-align:right"><a asp-action="AddDerivationScheme" asp-route-cryptoCode="@scheme.Crypto">Modify</a></td>
</tr>
}
</tbody>
</table>
@ -109,12 +110,12 @@
</p>
</div>
<div class="form-group">
<a asp-action="AddLightningNode" class="btn btn-success" role="button"><span class="glyphicon glyphicon-plus"></span>Add or modify a lightning node</a>
<table class="table">
<thead class="thead-inverse">
<tr>
<th>Crypto</th>
<th>Address</th>
<th style="text-align:right">Actions</th>
</tr>
</thead>
<tbody>
@ -123,6 +124,7 @@
<tr>
<td>@scheme.CryptoCode</td>
<td>@scheme.Address</td>
<td style="text-align:right"><a asp-action="AddLightningNode" asp-route-cryptoCode="@scheme.CryptoCode">Modify</a></td>
</tr>
}
</tbody>