From a230e21737ed963084b66a75f967049796e076ce Mon Sep 17 00:00:00 2001 From: Kukks Date: Sat, 21 Sep 2019 16:22:26 +0200 Subject: [PATCH 1/5] Store Nav extension support --- BTCPayServer/Contracts/IStoreNavExtension.cs | 7 +++++++ BTCPayServer/Views/Stores/_Nav.cshtml | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 BTCPayServer/Contracts/IStoreNavExtension.cs diff --git a/BTCPayServer/Contracts/IStoreNavExtension.cs b/BTCPayServer/Contracts/IStoreNavExtension.cs new file mode 100644 index 000000000..2a642a440 --- /dev/null +++ b/BTCPayServer/Contracts/IStoreNavExtension.cs @@ -0,0 +1,7 @@ +namespace BTCPayServer.Contracts +{ + public interface IStoreNavExtension + { + string Partial { get; } + } +} diff --git a/BTCPayServer/Views/Stores/_Nav.cshtml b/BTCPayServer/Views/Stores/_Nav.cshtml index 41befb647..5477dac52 100644 --- a/BTCPayServer/Views/Stores/_Nav.cshtml +++ b/BTCPayServer/Views/Stores/_Nav.cshtml @@ -5,5 +5,9 @@ Access Tokens Users Pay Button + @inject IEnumerable Extensions; + @foreach (var extension in Extensions) + { + + } - From bf9dd57177367ddf7e96499d3f4a80d86a80cf8e Mon Sep 17 00:00:00 2001 From: Kukks Date: Sat, 21 Sep 2019 16:24:01 +0200 Subject: [PATCH 2/5] move css logic to global css file as it makes more sense --- BTCPayServer/Views/Stores/UpdateStore.cshtml | 13 ------------- BTCPayServer/wwwroot/main/css/site.css | 12 +++++++++++- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/BTCPayServer/Views/Stores/UpdateStore.cshtml b/BTCPayServer/Views/Stores/UpdateStore.cshtml index 4efd89deb..a3a31343c 100644 --- a/BTCPayServer/Views/Stores/UpdateStore.cshtml +++ b/BTCPayServer/Views/Stores/UpdateStore.cshtml @@ -4,19 +4,6 @@ ViewData.SetActivePageAndTitle(StoreNavPages.Index, "Profile"); } - - -
diff --git a/BTCPayServer/wwwroot/main/css/site.css b/BTCPayServer/wwwroot/main/css/site.css index bbbf59d9c..568af150f 100644 --- a/BTCPayServer/wwwroot/main/css/site.css +++ b/BTCPayServer/wwwroot/main/css/site.css @@ -118,4 +118,14 @@ a.nav-link { .invoice-details a{ /* Prevent layout from breaking on hyperlinks with very long URLs as the visible text */ word-break: break-word; -} \ No newline at end of file +} + +.smMaxWidth { + max-width: 150px; +} + +@media (min-width: 768px) { + .smMaxWidth { + max-width: 300px; + } +} From fa18bd9a6953f9054f66d706eed72d1fd713ec77 Mon Sep 17 00:00:00 2001 From: Kukks Date: Sat, 21 Sep 2019 16:28:04 +0200 Subject: [PATCH 3/5] allow nav layout for store to not have a main title specified --- BTCPayServer/Views/Shared/_NavLayout.cshtml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/BTCPayServer/Views/Shared/_NavLayout.cshtml b/BTCPayServer/Views/Shared/_NavLayout.cshtml index d63956933..fc6cd8b95 100644 --- a/BTCPayServer/Views/Shared/_NavLayout.cshtml +++ b/BTCPayServer/Views/Shared/_NavLayout.cshtml @@ -1,13 +1,18 @@ @{ -Layout = "/Views/Shared/_Layout.cshtml"; -ViewBag.ShowMenu = ViewBag.ShowMenu ?? true; + Layout = "/Views/Shared/_Layout.cshtml"; + ViewBag.ShowMenu = ViewBag.ShowMenu ?? true; + if (!ViewData.ContainsKey("NavPartialName")) + { + ViewData["NavPartialName"] = "_Nav"; + } + var title = $"{(ViewData.ContainsKey("MainTitle")? $"{ViewData["MainTitle"]}:" : String.Empty)} {ViewData["Title"]}"; }
-

@ViewData["MainTitle"]: @ViewData["Title"]

+

@title


@@ -17,7 +22,7 @@ ViewBag.ShowMenu = ViewBag.ShowMenu ?? true;
@if (ViewBag.ShowMenu) { - @await Html.PartialAsync("_Nav") + @await Html.PartialAsync(ViewData["NavPartialName"].ToString()) }
@@ -28,9 +33,9 @@ ViewBag.ShowMenu = ViewBag.ShowMenu ?? true;
@section HeadScripts { -@RenderSection("HeadScripts", required: false) + @RenderSection("HeadScripts", required: false) } @section Scripts { -@RenderSection("Scripts", required: false) + @RenderSection("Scripts", required: false) } From 59839a3332043548df78687116f14cf4a64c04f8 Mon Sep 17 00:00:00 2001 From: Kukks Date: Sat, 21 Sep 2019 16:39:44 +0200 Subject: [PATCH 4/5] make sure networks are abstracted properly --- BTCPayServer.Common/BTCPayNetwork.cs | 6 ++---- BTCPayServer/Data/StoreDataExtensions.cs | 2 +- BTCPayServer/HostedServices/InvoiceWatcher.cs | 5 +++-- BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentData.cs | 2 +- BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentHandler.cs | 4 +++- .../Payments/Lightning/LightningLikePaymentHandler.cs | 7 +++++-- BTCPayServer/Services/Invoices/InvoiceEntity.cs | 4 ++-- BTCPayServer/Services/Invoices/InvoiceRepository.cs | 4 ++-- .../Views/Shared/ViewBitcoinLikePaymentData.cshtml | 5 +++-- 9 files changed, 22 insertions(+), 17 deletions(-) diff --git a/BTCPayServer.Common/BTCPayNetwork.cs b/BTCPayServer.Common/BTCPayNetwork.cs index 0733ee98c..3cdfc0d5b 100644 --- a/BTCPayServer.Common/BTCPayNetwork.cs +++ b/BTCPayServer.Common/BTCPayNetwork.cs @@ -54,7 +54,8 @@ namespace BTCPayServer public KeyPath CoinType { get; internal set; } public Dictionary ElectrumMapping = new Dictionary(); - + public int MaxTrackedConfirmation { get; internal set; } = 6; + public string UriScheme { get; internal set; } public KeyPath GetRootKeyPath(DerivationType type) { KeyPath baseKey; @@ -105,7 +106,6 @@ namespace BTCPayServer public string CryptoCode { get; internal set; } public string BlockExplorerLink { get; internal set; } - public string UriScheme { get; internal set; } public string DisplayName { get; set; } [Obsolete("Should not be needed")] @@ -118,8 +118,6 @@ namespace BTCPayServer } public string CryptoImagePath { get; set; } - - public int MaxTrackedConfirmation { get; internal set; } = 6; public string[] DefaultRateRules { get; internal set; } = Array.Empty(); public override string ToString() { diff --git a/BTCPayServer/Data/StoreDataExtensions.cs b/BTCPayServer/Data/StoreDataExtensions.cs index 7614752f3..2179726ab 100644 --- a/BTCPayServer/Data/StoreDataExtensions.cs +++ b/BTCPayServer/Data/StoreDataExtensions.cs @@ -108,7 +108,7 @@ namespace BTCPayServer.Data foreach (var strat in strategies.Properties()) { var paymentMethodId = PaymentMethodId.Parse(strat.Name); - var network = networks.GetNetwork(paymentMethodId.CryptoCode); + var network = networks.GetNetwork(paymentMethodId.CryptoCode); if (network != null) { if (network == networks.BTC && paymentMethodId.PaymentType == PaymentTypes.BTCLike && btcReturned) diff --git a/BTCPayServer/HostedServices/InvoiceWatcher.cs b/BTCPayServer/HostedServices/InvoiceWatcher.cs index 79ad1f773..82f84de06 100644 --- a/BTCPayServer/HostedServices/InvoiceWatcher.cs +++ b/BTCPayServer/HostedServices/InvoiceWatcher.cs @@ -315,8 +315,9 @@ namespace BTCPayServer.HostedServices var paymentData = payment.GetCryptoPaymentData(); if (paymentData is Payments.Bitcoin.BitcoinLikePaymentData onChainPaymentData) { + var network = payment.Network as BTCPayNetwork; // Do update if confirmation count in the paymentData is not up to date - if ((onChainPaymentData.ConfirmationCount < payment.Network.MaxTrackedConfirmation && payment.Accounted) + if ((onChainPaymentData.ConfirmationCount < network.MaxTrackedConfirmation && payment.Accounted) && (onChainPaymentData.Legacy || invoice.MonitoringExpiration < DateTimeOffset.UtcNow)) { var transactionResult = await _ExplorerClientProvider.GetExplorerClient(payment.GetCryptoCode())?.GetTransactionAsync(onChainPaymentData.Outpoint.Hash); @@ -325,7 +326,7 @@ namespace BTCPayServer.HostedServices payment.SetCryptoPaymentData(onChainPaymentData); // we want to extend invoice monitoring until we reach max confirmations on all onchain payment methods - if (confirmationCount < payment.Network.MaxTrackedConfirmation) + if (confirmationCount < network.MaxTrackedConfirmation) extendInvoiceMonitoring = true; return payment; diff --git a/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentData.cs b/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentData.cs index 8778b1af8..3ded51cbb 100644 --- a/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentData.cs +++ b/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentData.cs @@ -59,7 +59,7 @@ namespace BTCPayServer.Payments.Bitcoin public bool PaymentCompleted(PaymentEntity entity) { - return ConfirmationCount >= Network.MaxTrackedConfirmation; + return ConfirmationCount >= ((BTCPayNetwork)Network).MaxTrackedConfirmation; } public bool PaymentConfirmed(PaymentEntity entity, SpeedPolicy speedPolicy) diff --git a/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentHandler.cs b/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentHandler.cs index cc5b3c7d4..0b0abba36 100644 --- a/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentHandler.cs +++ b/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentHandler.cs @@ -87,7 +87,9 @@ namespace BTCPayServer.Payments.Bitcoin public override IEnumerable GetSupportedPaymentMethods() { - return _networkProvider.GetAll() + return _networkProvider + .GetAll() + .OfType() .Select(network => new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike)); } diff --git a/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs b/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs index abd3b5b49..af957ce3c 100644 --- a/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs +++ b/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs @@ -67,7 +67,7 @@ namespace BTCPayServer.Payments.Lightning } catch (OperationCanceledException) when (cts.IsCancellationRequested) { - throw new PaymentMethodUnavailableException($"The lightning node did not reply in a timely maner"); + throw new PaymentMethodUnavailableException($"The lightning node did not reply in a timely manner"); } catch (Exception ex) { @@ -139,7 +139,10 @@ namespace BTCPayServer.Payments.Lightning public override IEnumerable GetSupportedPaymentMethods() { - return _networkProvider.GetAll() + return _networkProvider + .GetAll() + .OfType() + .Where(network => network.NBitcoinNetwork.Consensus.SupportSegwit) .Select(network => new PaymentMethodId(network.CryptoCode, PaymentTypes.LightningLike)); } diff --git a/BTCPayServer/Services/Invoices/InvoiceEntity.cs b/BTCPayServer/Services/Invoices/InvoiceEntity.cs index 3edebb2d2..d18f8c109 100644 --- a/BTCPayServer/Services/Invoices/InvoiceEntity.cs +++ b/BTCPayServer/Services/Invoices/InvoiceEntity.cs @@ -461,7 +461,7 @@ namespace BTCPayServer.Services.Invoices } else if (paymentId.PaymentType == PaymentTypes.BTCLike) { - var scheme = info.Network.UriScheme; + var scheme = ((BTCPayNetwork)info.Network).UriScheme; var minerInfo = new MinerFeeInfo(); minerInfo.TotalFee = accounting.NetworkFee.Satoshi; @@ -911,7 +911,7 @@ namespace BTCPayServer.Services.Invoices { [NotMapped] [JsonIgnore] - public BTCPayNetwork Network { get; set; } + public BTCPayNetworkBase Network { get; set; } public int Version { get; set; } public DateTimeOffset ReceivedTime { diff --git a/BTCPayServer/Services/Invoices/InvoiceRepository.cs b/BTCPayServer/Services/Invoices/InvoiceRepository.cs index bc83edb33..0a578c185 100644 --- a/BTCPayServer/Services/Invoices/InvoiceRepository.cs +++ b/BTCPayServer/Services/Invoices/InvoiceRepository.cs @@ -441,7 +441,7 @@ retry: entity.Payments = invoice.Payments.Select(p => { var paymentEntity = ToObject(p.Blob, null); - paymentEntity.Network = _Networks.GetNetwork(paymentEntity.CryptoCode); + paymentEntity.Network = _Networks.GetNetwork(paymentEntity.CryptoCode); paymentEntity.Accounted = p.Accounted; // PaymentEntity on version 0 does not have their own fee, because it was assumed that the payment method have fixed fee. // We want to hide this legacy detail in InvoiceRepository, so we fetch the fee from the PaymentMethod and assign it to the PaymentEntity. @@ -663,7 +663,7 @@ retry: ReceivedTime = date.UtcDateTime, Accounted = accounted, NetworkFee = paymentMethodDetails.GetNextNetworkFee(), - Network = network as BTCPayNetwork + Network = network }; entity.SetCryptoPaymentData(paymentData); diff --git a/BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml b/BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml index 79ecfb538..d6626082d 100644 --- a/BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml +++ b/BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml @@ -12,9 +12,10 @@ m.DepositAddress = onChainPaymentData.GetDestination(); int confirmationCount = onChainPaymentData.ConfirmationCount; - if (confirmationCount >= payment.Network.MaxTrackedConfirmation) + var network = payment.Network as BTCPayNetwork; + if (confirmationCount >= network.MaxTrackedConfirmation) { - m.Confirmations = "At least " + (payment.Network.MaxTrackedConfirmation); + m.Confirmations = "At least " + (network.MaxTrackedConfirmation); } else { From f3aa67e0f1f2a597d58734f8b0523d5723aba384 Mon Sep 17 00:00:00 2001 From: Kukks Date: Sat, 21 Sep 2019 17:07:48 +0200 Subject: [PATCH 5/5] make invoice repository able to query more extensively --- .../Controllers/InvoiceController.API.cs | 2 +- .../Controllers/InvoiceController.UI.cs | 4 +- .../Payments/Bitcoin/NBXplorerListener.cs | 3 +- .../Services/Invoices/InvoiceRepository.cs | 43 ++++++++++--------- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/BTCPayServer/Controllers/InvoiceController.API.cs b/BTCPayServer/Controllers/InvoiceController.API.cs index c949f8e26..6e90700a7 100644 --- a/BTCPayServer/Controllers/InvoiceController.API.cs +++ b/BTCPayServer/Controllers/InvoiceController.API.cs @@ -41,7 +41,7 @@ namespace BTCPayServer.Controllers { var invoice = (await _InvoiceRepository.GetInvoices(new InvoiceQuery() { - InvoiceId = id, + InvoiceId = new[] {id}, StoreId = new[] { HttpContext.GetStoreData().Id } })).FirstOrDefault(); if (invoice == null) diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index bb1b76014..7c4cb3be2 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -37,7 +37,7 @@ namespace BTCPayServer.Controllers { var invoice = (await _InvoiceRepository.GetInvoices(new InvoiceQuery() { - InvoiceId = invoiceId, + InvoiceId = new[] {invoiceId}, UserId = GetUserId(), IncludeAddresses = true, IncludeEvents = true @@ -582,7 +582,7 @@ namespace BTCPayServer.Controllers { var invoice = (await _InvoiceRepository.GetInvoices(new InvoiceQuery() { - InvoiceId = invoiceId, + InvoiceId = new[] {invoiceId}, UserId = GetUserId() })).FirstOrDefault(); diff --git a/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs b/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs index bd01ab410..94b7672c3 100644 --- a/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs +++ b/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs @@ -149,7 +149,8 @@ namespace BTCPayServer.Payments.Bitcoin foreach (var txCoin in evt.TransactionData.Transaction.Outputs.AsCoins() .Where(o => o.ScriptPubKey == output.ScriptPubKey)) { - var invoice = await _InvoiceRepository.GetInvoiceFromScriptPubKey(output.ScriptPubKey, network.CryptoCode); + var key = output.ScriptPubKey.Hash + "#" + network.CryptoCode; + var invoice = (await _InvoiceRepository.GetInvoicesFromAddresses(new [] {key})).FirstOrDefault(); if (invoice != null) { var paymentData = new BitcoinLikePaymentData(txCoin, evt.TransactionData.Transaction.RBF); diff --git a/BTCPayServer/Services/Invoices/InvoiceRepository.cs b/BTCPayServer/Services/Invoices/InvoiceRepository.cs index 0a578c185..e0ce31cad 100644 --- a/BTCPayServer/Services/Invoices/InvoiceRepository.cs +++ b/BTCPayServer/Services/Invoices/InvoiceRepository.cs @@ -1,6 +1,7 @@ using DBriize; using Microsoft.Extensions.Logging; using System; +using System.Collections; using System.Collections.Generic; using System.Text; using NBitpayClient; @@ -80,30 +81,31 @@ retry: } } - public async Task GetInvoiceFromScriptPubKey(Script scriptPubKey, string cryptoCode) + public async Task> GetInvoicesFromAddresses(string[] addresses) { using (var db = _ContextFactory.CreateContext()) { - var key = scriptPubKey.Hash.ToString() + "#" + cryptoCode; - var result = (await db.AddressInvoices + return (await db.AddressInvoices #pragma warning disable CS0618 - .Where(a => a.Address == key) + .Where(a => addresses.Contains(a.Address)) #pragma warning restore CS0618 - .Select(a => a.InvoiceData) - .Include(a => a.Payments) - .Include(a => a.RefundAddresses) - .ToListAsync()).FirstOrDefault(); - if (result == null) - return null; - return ToEntity(result); + .Select(a => a.InvoiceData) + .Include(a => a.Payments) + .Include(a => a.RefundAddresses) + .ToListAsync()).Select(ToEntity); } } - public async Task GetPendingInvoices() + public async Task GetPendingInvoices(Func, IQueryable> filter = null ) { using (var ctx = _ContextFactory.CreateContext()) { - return await ctx.PendingInvoices.Select(p => p.Id).ToArrayAsync(); + var queryable = ctx.PendingInvoices.AsQueryable(); + if (filter != null) + { + queryable = filter.Invoke(queryable); + } + return await queryable.Select(p => p.Id).ToArrayAsync(); } } @@ -239,7 +241,7 @@ retry: return paymentMethod.GetPaymentMethodDetails().GetPaymentDestination(); } - public async Task NewAddress(string invoiceId, Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod paymentMethod, BTCPayNetworkBase network) + public async Task NewAddress(string invoiceId, IPaymentMethodDetails paymentMethod, BTCPayNetworkBase network) { using (var context = _ContextFactory.CreateContext()) { @@ -252,7 +254,7 @@ retry: if (currencyData == null) return false; - var existingPaymentMethod = (Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod)currencyData.GetPaymentMethodDetails(); + var existingPaymentMethod = currencyData.GetPaymentMethodDetails(); if (existingPaymentMethod.GetPaymentDestination() != null) { MarkUnassigned(invoiceId, invoiceEntity, context, currencyData.GetId()); @@ -487,11 +489,12 @@ retry: { IQueryable query = context.Invoices; - if (!string.IsNullOrEmpty(queryObject.InvoiceId)) + if (queryObject.InvoiceId != null && queryObject.InvoiceId.Length > 0) { - query = query.Where(i => i.Id == queryObject.InvoiceId); + var statusSet = queryObject.InvoiceId.ToHashSet(); + query = query.Where(i => statusSet.Contains(i.Id)); } - + if (queryObject.StoreId != null && queryObject.StoreId.Length > 0) { var stores = queryObject.StoreId.ToHashSet(); @@ -666,7 +669,7 @@ retry: Network = network }; entity.SetCryptoPaymentData(paymentData); - + //TODO: abstract if (paymentMethodDetails is Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod bitcoinPaymentMethod && bitcoinPaymentMethod.NetworkFeeMode == NetworkFeeMode.MultiplePaymentsOnly && bitcoinPaymentMethod.NextNetworkFee == Money.Zero) @@ -811,7 +814,7 @@ retry: get; set; } - public string InvoiceId + public string[] InvoiceId { get; set;