Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
f1ec3b0c75 | |||
b5d55a2066 | |||
0d2c9fe377 | |||
2c7cc9a796 | |||
2e1d623755 | |||
52fee8f842 | |||
6ba17e8e30 | |||
ac3432920a | |||
63c88be533 | |||
3cb577e6ba | |||
1e0d64c548 | |||
bc1b9ff59c |
@ -1298,6 +1298,25 @@ namespace BTCPayServer.Tests
|
||||
Assert.True(invoice.SupportedTransactionCurrencies["LTC"].Enabled);
|
||||
Assert.True(invoice.PaymentSubtotals.ContainsKey("LTC"));
|
||||
Assert.True(invoice.PaymentTotals.ContainsKey("LTC"));
|
||||
|
||||
|
||||
// Check if we can disable LTC
|
||||
invoice = user.BitPay.CreateInvoice(new Invoice()
|
||||
{
|
||||
Price = 5000.0m,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true,
|
||||
SupportedTransactionCurrencies = new Dictionary<string, InvoiceSupportedTransactionCurrency>()
|
||||
{
|
||||
{ "BTC", new InvoiceSupportedTransactionCurrency() { Enabled = true } }
|
||||
}
|
||||
}, Facade.Merchant);
|
||||
|
||||
Assert.Single(invoice.CryptoInfo.Where(c => c.CryptoCode == "BTC"));
|
||||
Assert.Empty(invoice.CryptoInfo.Where(c => c.CryptoCode == "LTC"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<Version>1.0.3.55</Version>
|
||||
<Version>1.0.3.60</Version>
|
||||
<NoWarn>NU1701,CA1816,CA1308,CA1810,CA2208</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
@ -33,7 +33,7 @@
|
||||
<EmbeddedResource Include="Currencies.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BTCPayServer.Lightning.All" Version="1.1.0.5" />
|
||||
<PackageReference Include="BTCPayServer.Lightning.All" Version="1.1.0.9" />
|
||||
<PackageReference Include="BuildBundlerMinifier" Version="2.7.385" />
|
||||
<PackageReference Include="DigitalRuby.ExchangeSharp" Version="0.5.3" />
|
||||
<PackageReference Include="HtmlSanitizer" Version="4.0.199" />
|
||||
@ -139,7 +139,7 @@
|
||||
<Content Update="Views\Server\LightningChargeServices.cshtml">
|
||||
<Pack>$(IncludeRazorContentInPack)</Pack>
|
||||
</Content>
|
||||
<Content Update="Views\Server\SparkServices.cshtml">
|
||||
<Content Update="Views\Server\LightningWalletServices.cshtml">
|
||||
<Pack>$(IncludeRazorContentInPack)</Pack>
|
||||
</Content>
|
||||
<Content Update="Views\Server\SSHService.cshtml">
|
||||
|
@ -144,15 +144,30 @@ namespace BTCPayServer.Configuration
|
||||
externalLnd<ExternalLndGrpc>($"{net.CryptoCode}.external.lnd.grpc", "lnd-grpc");
|
||||
externalLnd<ExternalLndRest>($"{net.CryptoCode}.external.lnd.rest", "lnd-rest");
|
||||
|
||||
var spark = conf.GetOrDefault<string>($"{net.CryptoCode}.external.spark", string.Empty);
|
||||
if (spark.Length != 0)
|
||||
{
|
||||
if (!SparkConnectionString.TryParse(spark, out var connectionString))
|
||||
var spark = conf.GetOrDefault<string>($"{net.CryptoCode}.external.spark", string.Empty);
|
||||
if (spark.Length != 0)
|
||||
{
|
||||
throw new ConfigException($"Invalid setting {net.CryptoCode}.external.spark, " + Environment.NewLine +
|
||||
$"Valid example: 'server=https://btcpay.example.com/spark/btc/;cookiefile=/etc/clightning_bitcoin_spark/.cookie'");
|
||||
if (!SparkConnectionString.TryParse(spark, out var connectionString))
|
||||
{
|
||||
throw new ConfigException($"Invalid setting {net.CryptoCode}.external.spark, " + Environment.NewLine +
|
||||
$"Valid example: 'server=https://btcpay.example.com/spark/btc/;cookiefile=/etc/clightning_bitcoin_spark/.cookie'");
|
||||
}
|
||||
ExternalServicesByCryptoCode.Add(net.CryptoCode, new ExternalSpark(connectionString));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rtl = conf.GetOrDefault<string>($"{net.CryptoCode}.external.rtl", string.Empty);
|
||||
if (rtl.Length != 0)
|
||||
{
|
||||
if (!SparkConnectionString.TryParse(rtl, out var connectionString))
|
||||
{
|
||||
throw new ConfigException($"Invalid setting {net.CryptoCode}.external.rtl, " + Environment.NewLine +
|
||||
$"Valid example: 'server=https://btcpay.example.com/rtl/btc/;cookiefile=/etc/clightning_bitcoin_rtl/.cookie'");
|
||||
}
|
||||
ExternalServicesByCryptoCode.Add(net.CryptoCode, new ExternalRTL(connectionString));
|
||||
}
|
||||
ExternalServicesByCryptoCode.Add(net.CryptoCode, new ExternalSpark(connectionString));
|
||||
}
|
||||
|
||||
var charge = conf.GetOrDefault<string>($"{net.CryptoCode}.external.charge", string.Empty);
|
||||
|
19
BTCPayServer/Configuration/External/ExternalRTL.cs
vendored
Normal file
19
BTCPayServer/Configuration/External/ExternalRTL.cs
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Configuration.External
|
||||
{
|
||||
public class ExternalRTL : ExternalService, IAccessKeyService
|
||||
{
|
||||
public SparkConnectionString ConnectionString { get; }
|
||||
|
||||
public ExternalRTL(SparkConnectionString connectionString)
|
||||
{
|
||||
if (connectionString == null)
|
||||
throw new ArgumentNullException(nameof(connectionString));
|
||||
ConnectionString = connectionString;
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,11 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Configuration.External
|
||||
{
|
||||
public class ExternalSpark : ExternalService
|
||||
public interface IAccessKeyService
|
||||
{
|
||||
SparkConnectionString ConnectionString { get; }
|
||||
}
|
||||
public class ExternalSpark : ExternalService, IAccessKeyService
|
||||
{
|
||||
public SparkConnectionString ConnectionString { get; }
|
||||
|
||||
|
@ -172,7 +172,7 @@ namespace BTCPayServer.Controllers
|
||||
store.AdditionalClaims.Add(new Claim(Policies.CanCreateInvoice.Key, store.Id));
|
||||
try
|
||||
{
|
||||
var invoice = await _InvoiceController.CreateInvoiceCore(new Invoice()
|
||||
var invoice = await _InvoiceController.CreateInvoiceCore(new CreateInvoiceRequest()
|
||||
{
|
||||
Currency = settings.TargetCurrency,
|
||||
ItemCode = request.ChoiceKey ?? string.Empty,
|
||||
@ -250,7 +250,7 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
var store = await _AppService.GetStore(app);
|
||||
store.AdditionalClaims.Add(new Claim(Policies.CanCreateInvoice.Key, store.Id));
|
||||
var invoice = await _InvoiceController.CreateInvoiceCore(new NBitpayClient.Invoice()
|
||||
var invoice = await _InvoiceController.CreateInvoiceCore(new CreateInvoiceRequest()
|
||||
{
|
||||
ItemCode = choice?.Id,
|
||||
ItemDesc = title,
|
||||
|
@ -32,8 +32,10 @@ namespace BTCPayServer.Controllers
|
||||
[HttpPost]
|
||||
[Route("invoices")]
|
||||
[MediaTypeConstraint("application/json")]
|
||||
public async Task<DataWrapper<InvoiceResponse>> CreateInvoice([FromBody] Invoice invoice)
|
||||
public async Task<DataWrapper<InvoiceResponse>> CreateInvoice([FromBody] CreateInvoiceRequest invoice)
|
||||
{
|
||||
if (invoice == null)
|
||||
throw new BitpayHttpException(400, "Invalid invoice");
|
||||
return await _InvoiceController.CreateInvoiceCore(invoice, HttpContext.GetStoreData(), HttpContext.Request.GetAbsoluteRoot());
|
||||
}
|
||||
|
||||
|
@ -578,7 +578,7 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
try
|
||||
{
|
||||
var result = await CreateInvoiceCore(new Invoice()
|
||||
var result = await CreateInvoiceCore(new CreateInvoiceRequest()
|
||||
{
|
||||
Price = model.Amount.Value,
|
||||
Currency = model.Currency,
|
||||
|
@ -62,7 +62,7 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
|
||||
|
||||
internal async Task<DataWrapper<InvoiceResponse>> CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl, List<string> additionalTags = null)
|
||||
internal async Task<DataWrapper<InvoiceResponse>> CreateInvoiceCore(CreateInvoiceRequest invoice, StoreData store, string serverUrl, List<string> additionalTags = null)
|
||||
{
|
||||
if (!store.HasClaim(Policies.CanCreateInvoice.Key))
|
||||
throw new UnauthorizedAccessException();
|
||||
@ -89,7 +89,7 @@ namespace BTCPayServer.Controllers
|
||||
entity.NotificationURL = notificationUri.AbsoluteUri;
|
||||
}
|
||||
entity.NotificationEmail = invoice.NotificationEmail;
|
||||
entity.BuyerInformation = Map<Invoice, BuyerInformation>(invoice);
|
||||
entity.BuyerInformation = Map<CreateInvoiceRequest, BuyerInformation>(invoice);
|
||||
entity.PaymentTolerance = storeBlob.PaymentTolerance;
|
||||
if (additionalTags != null)
|
||||
entity.InternalTags.AddRange(additionalTags);
|
||||
@ -102,17 +102,19 @@ namespace BTCPayServer.Controllers
|
||||
entity.RefundMail = entity.BuyerInformation.BuyerEmail;
|
||||
}
|
||||
|
||||
var taxIncluded = invoice.TaxIncluded.HasValue ? invoice.TaxIncluded.Value : 0m;
|
||||
|
||||
var currencyInfo = _CurrencyNameTable.GetNumberFormatInfo(invoice.Currency, false);
|
||||
if (currencyInfo != null)
|
||||
{
|
||||
invoice.Price = Math.Round(invoice.Price, currencyInfo.CurrencyDecimalDigits);
|
||||
invoice.TaxIncluded = Math.Round(invoice.TaxIncluded, currencyInfo.CurrencyDecimalDigits);
|
||||
invoice.TaxIncluded = Math.Round(taxIncluded, currencyInfo.CurrencyDecimalDigits);
|
||||
}
|
||||
invoice.Price = Math.Max(0.0m, invoice.Price);
|
||||
invoice.TaxIncluded = Math.Max(0.0m, invoice.TaxIncluded);
|
||||
invoice.TaxIncluded = Math.Min(invoice.TaxIncluded, invoice.Price);
|
||||
invoice.TaxIncluded = Math.Max(0.0m, taxIncluded);
|
||||
invoice.TaxIncluded = Math.Min(taxIncluded, invoice.Price);
|
||||
|
||||
entity.ProductInformation = Map<Invoice, ProductInformation>(invoice);
|
||||
entity.ProductInformation = Map<CreateInvoiceRequest, ProductInformation>(invoice);
|
||||
|
||||
|
||||
entity.RedirectURL = invoice.RedirectURL ?? store.StoreWebsite;
|
||||
@ -125,6 +127,17 @@ 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()
|
||||
|
||||
if (invoice.SupportedTransactionCurrencies != null && invoice.SupportedTransactionCurrencies.Count != 0)
|
||||
{
|
||||
var supportedTransactionCurrencies = invoice.SupportedTransactionCurrencies
|
||||
.Where(c => c.Value.Enabled)
|
||||
.Select(c => PaymentMethodId.TryParse(c.Key, out var p) ? p : null)
|
||||
.ToHashSet();
|
||||
excludeFilter = PaymentFilter.Or(excludeFilter,
|
||||
PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p)));
|
||||
}
|
||||
|
||||
foreach (var network in store.GetSupportedPaymentMethods(_NetworkProvider)
|
||||
.Where(s => !excludeFilter.Match(s.PaymentId))
|
||||
.Select(c => _NetworkProvider.GetNetwork(c.PaymentId.CryptoCode))
|
||||
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Filters;
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Models.StoreViewModels;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
@ -45,7 +46,7 @@ namespace BTCPayServer.Controllers
|
||||
if (!ModelState.IsValid)
|
||||
return View();
|
||||
|
||||
var invoice = await _InvoiceController.CreateInvoiceCore(new NBitpayClient.Invoice()
|
||||
var invoice = await _InvoiceController.CreateInvoiceCore(new CreateInvoiceRequest()
|
||||
{
|
||||
Price = model.Price,
|
||||
Currency = model.Currency,
|
||||
|
@ -27,6 +27,7 @@ using Renci.SshNet;
|
||||
using BTCPayServer.Logging;
|
||||
using BTCPayServer.Lightning;
|
||||
using BTCPayServer.Configuration.External;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace BTCPayServer.Controllers
|
||||
{
|
||||
@ -474,7 +475,17 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
Crypto = cryptoCode,
|
||||
Type = "Spark server",
|
||||
Action = nameof(SparkServices),
|
||||
Action = nameof(SparkService),
|
||||
Index = i++,
|
||||
});
|
||||
}
|
||||
foreach (var rtlService in _Options.ExternalServicesByCryptoCode.GetServices<ExternalRTL>(cryptoCode))
|
||||
{
|
||||
result.LNDServices.Add(new ServicesViewModel.LNDServiceViewModel()
|
||||
{
|
||||
Crypto = cryptoCode,
|
||||
Type = "Ride the lightning server",
|
||||
Action = nameof(RTLService),
|
||||
Index = i++,
|
||||
});
|
||||
}
|
||||
@ -548,21 +559,31 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
|
||||
[Route("server/services/spark/{cryptoCode}/{index}")]
|
||||
public async Task<IActionResult> SparkServices(string cryptoCode, int index, bool showQR = false)
|
||||
public async Task<IActionResult> SparkService(string cryptoCode, int index, bool showQR = false)
|
||||
{
|
||||
return await LightningWalletServicesCore<ExternalSpark>(cryptoCode, showQR, "Spark Wallet");
|
||||
}
|
||||
[Route("server/services/rtl/{cryptoCode}/{index}")]
|
||||
public async Task<IActionResult> RTLService(string cryptoCode, int index, bool showQR = false)
|
||||
{
|
||||
return await LightningWalletServicesCore<ExternalRTL>(cryptoCode, showQR, "Ride the Lightning Wallet");
|
||||
}
|
||||
private async Task<IActionResult> LightningWalletServicesCore<T>(string cryptoCode, bool showQR, string walletName) where T : ExternalService, IAccessKeyService
|
||||
{
|
||||
if (!_dashBoard.IsFullySynched(cryptoCode, out var unusud))
|
||||
{
|
||||
StatusMessage = $"Error: {cryptoCode} is not fully synched";
|
||||
return RedirectToAction(nameof(Services));
|
||||
}
|
||||
var spark = _Options.ExternalServicesByCryptoCode.GetServices<ExternalSpark>(cryptoCode).Select(c => c.ConnectionString).FirstOrDefault();
|
||||
var spark = _Options.ExternalServicesByCryptoCode.GetServices<T>(cryptoCode).Select(c => c.ConnectionString).FirstOrDefault();
|
||||
if (spark == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
SparkServicesViewModel vm = new SparkServicesViewModel();
|
||||
LightningWalletServices vm = new LightningWalletServices();
|
||||
vm.ShowQR = showQR;
|
||||
vm.WalletName = walletName;
|
||||
try
|
||||
{
|
||||
var cookie = (spark.CookeFile == "fake"
|
||||
@ -570,7 +591,7 @@ namespace BTCPayServer.Controllers
|
||||
: await System.IO.File.ReadAllTextAsync(spark.CookeFile)).Split(':');
|
||||
if (cookie.Length >= 3)
|
||||
{
|
||||
vm.SparkLink = $"{spark.Server.AbsoluteUri}?access-key={cookie[2]}";
|
||||
vm.ServiceLink = $"{spark.Server.AbsoluteUri}?access-key={cookie[2]}";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -578,7 +599,7 @@ namespace BTCPayServer.Controllers
|
||||
StatusMessage = $"Error: {ex.Message}";
|
||||
return RedirectToAction(nameof(Services));
|
||||
}
|
||||
return View(vm);
|
||||
return View("LightningWalletServices", vm);
|
||||
}
|
||||
|
||||
[Route("server/services/lnd/{cryptoCode}/{index}")]
|
||||
|
83
BTCPayServer/Models/CreateInvoiceRequest.cs
Normal file
83
BTCPayServer/Models/CreateInvoiceRequest.cs
Normal file
@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NBitcoin;
|
||||
using NBitcoin.JsonConverters;
|
||||
using NBitpayClient;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Models
|
||||
{
|
||||
public class CreateInvoiceRequest
|
||||
{
|
||||
[JsonProperty(PropertyName = "buyer")]
|
||||
public Buyer Buyer { get; set; }
|
||||
[JsonProperty(PropertyName = "buyerEmail", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string BuyerEmail { get; set; }
|
||||
[JsonProperty(PropertyName = "buyerCountry", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string BuyerCountry { get; set; }
|
||||
[JsonProperty(PropertyName = "buyerZip", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string BuyerZip { get; set; }
|
||||
[JsonProperty(PropertyName = "buyerState", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string BuyerState { get; set; }
|
||||
[JsonProperty(PropertyName = "buyerCity", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string BuyerCity { get; set; }
|
||||
[JsonProperty(PropertyName = "buyerAddress2", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string BuyerAddress2 { get; set; }
|
||||
[JsonProperty(PropertyName = "buyerAddress1", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string BuyerAddress1 { get; set; }
|
||||
[JsonProperty(PropertyName = "buyerName", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string BuyerName { get; set; }
|
||||
[JsonProperty(PropertyName = "physical", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public bool Physical { get; set; }
|
||||
[JsonProperty(PropertyName = "redirectURL", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string RedirectURL { get; set; }
|
||||
[JsonProperty(PropertyName = "notificationURL", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string NotificationURL { get; set; }
|
||||
[JsonProperty(PropertyName = "extendedNotifications", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public bool ExtendedNotifications { get; set; }
|
||||
[JsonProperty(PropertyName = "fullNotifications", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public bool FullNotifications { get; set; }
|
||||
[JsonProperty(PropertyName = "transactionSpeed", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string TransactionSpeed { get; set; }
|
||||
[JsonProperty(PropertyName = "buyerPhone", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string BuyerPhone { get; set; }
|
||||
[JsonProperty(PropertyName = "posData", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string PosData { get; set; }
|
||||
[JsonProperty(PropertyName = "itemCode", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string ItemCode { get; set; }
|
||||
[JsonProperty(PropertyName = "itemDesc", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string ItemDesc { get; set; }
|
||||
[JsonProperty(PropertyName = "orderId", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string OrderId { get; set; }
|
||||
[JsonProperty(PropertyName = "currency", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string Currency { get; set; }
|
||||
[JsonProperty(PropertyName = "price", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public decimal Price { get; set; }
|
||||
[JsonProperty(PropertyName = "notificationEmail", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string NotificationEmail { get; set; }
|
||||
[JsonConverter(typeof(DateTimeJsonConverter))]
|
||||
[JsonProperty(PropertyName = "expirationTime", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public DateTimeOffset? ExpirationTime { get; set; }
|
||||
[JsonProperty(PropertyName = "status", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string Status { get; set; }
|
||||
[JsonProperty(PropertyName = "minerFees", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public Dictionary<string, MinerFeeInfo> MinerFees { get; set; }
|
||||
[JsonProperty(PropertyName = "supportedTransactionCurrencies", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public Dictionary<string, InvoiceSupportedTransactionCurrency> SupportedTransactionCurrencies { get; set; }
|
||||
[JsonProperty(PropertyName = "exchangeRates", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public Dictionary<string, Dictionary<string, decimal>> ExchangeRates { get; set; }
|
||||
[JsonProperty(PropertyName = "refundable", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public bool Refundable { get; set; }
|
||||
[JsonProperty(PropertyName = "taxIncluded", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public decimal? TaxIncluded { get; set; }
|
||||
[JsonProperty(PropertyName = "nonce", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public long Nonce { get; set; }
|
||||
[JsonProperty(PropertyName = "guid", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string Guid { get; set; }
|
||||
[JsonProperty(PropertyName = "token", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string Token { get; set; }
|
||||
}
|
||||
}
|
@ -5,9 +5,10 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Models.ServerViewModels
|
||||
{
|
||||
public class SparkServicesViewModel
|
||||
public class LightningWalletServices
|
||||
{
|
||||
public string SparkLink { get; set; }
|
||||
public string ServiceLink { get; set; }
|
||||
public bool ShowQR { get; set; }
|
||||
public string WalletName { get; internal set; }
|
||||
}
|
||||
}
|
@ -12,6 +12,21 @@ namespace BTCPayServer.Payments
|
||||
|
||||
public class PaymentFilter
|
||||
{
|
||||
class OrPaymentFilter : IPaymentFilter
|
||||
{
|
||||
private readonly IPaymentFilter _a;
|
||||
private readonly IPaymentFilter _b;
|
||||
|
||||
public OrPaymentFilter(IPaymentFilter a, IPaymentFilter b)
|
||||
{
|
||||
_a = a;
|
||||
_b = b;
|
||||
}
|
||||
public bool Match(PaymentMethodId paymentMethodId)
|
||||
{
|
||||
return _a.Match(paymentMethodId) || _b.Match(paymentMethodId);
|
||||
}
|
||||
}
|
||||
class NeverPaymentFilter : IPaymentFilter
|
||||
{
|
||||
|
||||
@ -54,6 +69,34 @@ namespace BTCPayServer.Payments
|
||||
return paymentMethodId == _paymentMethodId;
|
||||
}
|
||||
}
|
||||
class PredicateFilter : IPaymentFilter
|
||||
{
|
||||
private Func<PaymentMethodId, bool> predicate;
|
||||
|
||||
public PredicateFilter(Func<PaymentMethodId, bool> predicate)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public bool Match(PaymentMethodId paymentMethodId)
|
||||
{
|
||||
return this.predicate(paymentMethodId);
|
||||
}
|
||||
}
|
||||
public static IPaymentFilter Where(Func<PaymentMethodId, bool> predicate)
|
||||
{
|
||||
if (predicate == null)
|
||||
throw new ArgumentNullException(nameof(predicate));
|
||||
return new PredicateFilter(predicate);
|
||||
}
|
||||
public static IPaymentFilter Or(IPaymentFilter a, IPaymentFilter b)
|
||||
{
|
||||
if (a == null)
|
||||
throw new ArgumentNullException(nameof(a));
|
||||
if (b == null)
|
||||
throw new ArgumentNullException(nameof(b));
|
||||
return new OrPaymentFilter(a, b);
|
||||
}
|
||||
public static IPaymentFilter Never()
|
||||
{
|
||||
return NeverPaymentFilter.Instance;
|
||||
|
@ -67,10 +67,37 @@ namespace BTCPayServer.Payments
|
||||
return CryptoCode + "_" + PaymentType.ToString();
|
||||
}
|
||||
|
||||
public static bool TryParse(string str, out PaymentMethodId paymentMethodId)
|
||||
{
|
||||
paymentMethodId = null;
|
||||
var parts = str.Split('_', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length == 0 || parts.Length > 2)
|
||||
return false;
|
||||
PaymentTypes type = PaymentTypes.BTCLike;
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
switch (parts[1].ToLowerInvariant())
|
||||
{
|
||||
case "btclike":
|
||||
case "onchain":
|
||||
type = PaymentTypes.BTCLike;
|
||||
break;
|
||||
case "lightninglike":
|
||||
case "offchain":
|
||||
type = PaymentTypes.LightningLike;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
paymentMethodId = new PaymentMethodId(parts[0], type);
|
||||
return true;
|
||||
}
|
||||
public static PaymentMethodId Parse(string str)
|
||||
{
|
||||
var parts = str.Split('_');
|
||||
return new PaymentMethodId(parts[0], parts.Length == 1 ? PaymentTypes.BTCLike : Enum.Parse<PaymentTypes>(parts[1]));
|
||||
if (!TryParse(str, out var result))
|
||||
throw new FormatException("Invalid PaymentMethodId");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
<h1>Welcome to BTCPay Server</h1>
|
||||
<hr />
|
||||
<p>BTCPay Server is a free and open source server for merchants wanting to accept Bitcoin for their business.</p>
|
||||
<a style="background-color: #fff;color: #222;display:inline-block;text-align: center;white-space: nowrap;vertical-align: middle;user-select: none;line-height: 1.25;font-size: 1rem;text-decoration:none;font-weight: 700; text-transform: uppercase;border: none;border-radius: 300px;padding: 15px 30px;" href="https://docs.btcpayserver.org">Getting started</a>
|
||||
<a style="background-color: #fff;color: #222;display:inline-block;text-align: center;white-space: nowrap;vertical-align: middle;user-select: none;line-height: 1.25;font-size: 1rem;text-decoration:none;font-weight: 700; text-transform: uppercase;border: none;border-radius: 300px;padding: 15px 30px;" href="https://btcpayserver.org" target="_blank">Official website</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
@ -128,13 +128,19 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-4 ml-auto text-center">
|
||||
<a href="http://slack.forkbitpay.ninja/">
|
||||
<div class="col-lg-3 ml-auto text-center">
|
||||
<a href="https://chat.btcpayserver.org/">
|
||||
<img src="~/img/mattermost.png" height="100" />
|
||||
</a>
|
||||
<p><a href="https://chat.btcpayserver.org/">On Mattermost</a></p>
|
||||
</div>
|
||||
<div class="col-lg-3 ml-auto text-center">
|
||||
<a href="https://slack.btcpayserver.org/">
|
||||
<img src="~/img/slack.png" height="100" />
|
||||
</a>
|
||||
<p><a href="http://slack.forkbitpay.ninja/">On Slack</a></p>
|
||||
</div>
|
||||
<div class="col-lg-4 mr-auto text-center">
|
||||
<div class="col-lg-3 mr-auto text-center">
|
||||
<a href="https://twitter.com/BtcpayServer">
|
||||
<img src="~/img/twitter.png" height="100" />
|
||||
</a>
|
||||
@ -142,7 +148,7 @@
|
||||
<a href="https://twitter.com/BtcpayServer">On Twitter</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-lg-4 mr-auto text-center">
|
||||
<div class="col-lg-3 mr-auto text-center">
|
||||
<a href="https://github.com/btcpayserver/btcpayserver">
|
||||
<img src="~/img/github.png" height="100" />
|
||||
</a>
|
||||
|
@ -1,10 +1,10 @@
|
||||
@model SparkServicesViewModel
|
||||
@model LightningWalletServices
|
||||
@{
|
||||
ViewData.SetActivePageAndTitle(ServerNavPages.Services);
|
||||
}
|
||||
|
||||
|
||||
<h4>Spark service</h4>
|
||||
<h4>@Model.WalletName</h4>
|
||||
<partial name="_StatusMessage" for="@TempData["StatusMessage"]" />
|
||||
|
||||
@if (Model.ShowQR)
|
||||
@ -30,7 +30,7 @@
|
||||
<div class="form-group">
|
||||
<h5>Browser connection</h5>
|
||||
<p>
|
||||
<span>You can go to spark from your browser by <a href="@Model.SparkLink" target="_blank">clicking here</a><br /></span>
|
||||
<span>You can go to @Model.WalletName from your browser by <a href="@Model.ServiceLink" target="_blank">clicking here</a><br /></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
{
|
||||
<div class="form-group">
|
||||
<div id="qrCode"></div>
|
||||
<div id="qrCodeData" data-url="@Html.Raw(Model.SparkLink)"></div>
|
||||
<div id="qrCodeData" data-url="@Html.Raw(Model.ServiceLink)"></div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@ -70,7 +70,7 @@
|
||||
<script type="text/javascript">
|
||||
new QRCode(document.getElementById("qrCode"),
|
||||
{
|
||||
text: "@Html.Raw(Model.SparkLink)",
|
||||
text: "@Html.Raw(Model.ServiceLink)",
|
||||
width: 150,
|
||||
height: 150
|
||||
});
|
BIN
BTCPayServer/wwwroot/img/mattermost.png
Normal file
BIN
BTCPayServer/wwwroot/img/mattermost.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
@ -44,7 +44,7 @@
|
||||
"Node Info": "Informácia o uzle",
|
||||
"txCount": "{{count}} transakcia",
|
||||
"txCount_plural": "{{count}} transakcií",
|
||||
"Pay with CoinSwitch": "Pay with CoinSwitch",
|
||||
"Pay with Changelly": "Pay with Changelly",
|
||||
"Close": "Close"
|
||||
"Pay with CoinSwitch": "Zaplatiť cez CoinSwitch",
|
||||
"Pay with Changelly": "Zaplatiť cez Changelly",
|
||||
"Close": "Zatvoriť"
|
||||
}
|
@ -61,7 +61,7 @@ Altcoins are maintained by their respective communities.
|
||||
|
||||
## Documentation
|
||||
|
||||
Please check out our [complete documentation](https://github.com/btcpayserver/btcpayserver-doc) and [FAQ](https://github.com/btcpayserver/btcpayserver-doc/tree/master/FAQ#btcpay-frequently-asked-questions-and-common-issues) for more details.
|
||||
Please check out our [official website](https://btcpayserver.org/), our [complete documentation](https://github.com/btcpayserver/btcpayserver-doc) and [FAQ](https://github.com/btcpayserver/btcpayserver-doc/tree/master/FAQ#btcpay-frequently-asked-questions-and-common-issues) for more details.
|
||||
|
||||
If you have any troubles with BTCPay, please file a [Github issue](https://github.com/btcpayserver/btcpayserver/issues).
|
||||
For general questions, please join the community chat on [Mattermost](https://chat.btcpayserver.org/).
|
||||
|
Reference in New Issue
Block a user