diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index 69057f5a9..963003055 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -213,6 +213,8 @@ namespace BTCPayServer.Controllers OrderId = invoice.OrderId, InvoiceId = invoice.Id, DefaultLang = storeBlob.DefaultLang ?? "en-US", + CustomCSSLink = storeBlob.CustomCSS?.AbsoluteUri, + CustomLogoLink = storeBlob.CustomLogo?.AbsoluteUri, BtcAddress = paymentMethodDetails.GetPaymentDestination(), OrderAmount = (accounting.TotalDue - accounting.NetworkFee).ToString(), BtcDue = accounting.Due.ToString(), diff --git a/BTCPayServer/Controllers/StoresController.cs b/BTCPayServer/Controllers/StoresController.cs index d11045b29..f63e3c7e7 100644 --- a/BTCPayServer/Controllers/StoresController.cs +++ b/BTCPayServer/Controllers/StoresController.cs @@ -196,6 +196,8 @@ namespace BTCPayServer.Controllers vm.SetLanguages(_LangService, storeBlob.DefaultLang); vm.LightningMaxValue = storeBlob.LightningMaxValue?.ToString() ?? ""; vm.AllowCoinConversion = storeBlob.AllowCoinConversion; + vm.CustomCSS = storeBlob.CustomCSS; + vm.CustomLogo = storeBlob.CustomLogo; return View(vm); } @@ -226,6 +228,8 @@ namespace BTCPayServer.Controllers blob.DefaultLang = model.DefaultLang; blob.AllowCoinConversion = model.AllowCoinConversion; blob.LightningMaxValue = currencyValue; + blob.CustomLogo = model.CustomLogo; + blob.CustomCSS = model.CustomCSS; if (store.SetStoreBlob(blob)) { needUpdate = true; diff --git a/BTCPayServer/Data/StoreData.cs b/BTCPayServer/Data/StoreData.cs index 5e6985d10..5eb4dcfee 100644 --- a/BTCPayServer/Data/StoreData.cs +++ b/BTCPayServer/Data/StoreData.cs @@ -258,6 +258,11 @@ namespace BTCPayServer.Data [JsonConverter(typeof(CurrencyValueJsonConverter))] public CurrencyValue LightningMaxValue { get; set; } + [JsonConverter(typeof(UriJsonConverter))] + public Uri CustomLogo { get; set; } + [JsonConverter(typeof(UriJsonConverter))] + public Uri CustomCSS { get; set; } + public IRateProvider ApplyRateRules(BTCPayNetwork network, IRateProvider rateProvider) { if (!PreferredExchange.IsCoinAverage()) diff --git a/BTCPayServer/JsonConverters/CurrencyValueJsonConverter.cs b/BTCPayServer/JsonConverters/CurrencyValueJsonConverter.cs index 533ccca20..a767b520c 100644 --- a/BTCPayServer/JsonConverters/CurrencyValueJsonConverter.cs +++ b/BTCPayServer/JsonConverters/CurrencyValueJsonConverter.cs @@ -15,7 +15,6 @@ namespace BTCPayServer.JsonConverters return typeof(CurrencyValue).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); } - Type longType = typeof(long).GetTypeInfo(); public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { try diff --git a/BTCPayServer/JsonConverters/UriJsonConverter.cs b/BTCPayServer/JsonConverters/UriJsonConverter.cs new file mode 100644 index 000000000..5aaf73320 --- /dev/null +++ b/BTCPayServer/JsonConverters/UriJsonConverter.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Reflection; +using Newtonsoft.Json; +using NBitcoin.JsonConverters; + +namespace BTCPayServer.JsonConverters +{ + public class UriJsonConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return typeof(Uri).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + try + { + return reader.TokenType == JsonToken.Null ? null : + Uri.TryCreate((string)reader.Value, UriKind.Absolute, out var result) ? result : + throw new JsonObjectException("Invalid Currency value", reader); + } + catch (InvalidCastException) + { + throw new JsonObjectException("Invalid Currency value", reader); + } + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value != null) + writer.WriteValue(((Uri)value).AbsoluteUri); + } + } +} diff --git a/BTCPayServer/Models/InvoicingModels/PaymentModel.cs b/BTCPayServer/Models/InvoicingModels/PaymentModel.cs index 922d93d3f..f638abab4 100644 --- a/BTCPayServer/Models/InvoicingModels/PaymentModel.cs +++ b/BTCPayServer/Models/InvoicingModels/PaymentModel.cs @@ -13,7 +13,8 @@ namespace BTCPayServer.Models.InvoicingModels public string CryptoImage { get; set; } public string Link { get; set; } } - + public string CustomCSSLink { get; set; } + public string CustomLogoLink { get; set; } public string DefaultLang { get; set; } public List AvailableCryptos { get; set; } = new List(); public bool IsLightning { get; set; } diff --git a/BTCPayServer/Models/StoreViewModels/CheckoutExperienceViewModel.cs b/BTCPayServer/Models/StoreViewModels/CheckoutExperienceViewModel.cs index 55f4dc05a..6d21bc7fd 100644 --- a/BTCPayServer/Models/StoreViewModels/CheckoutExperienceViewModel.cs +++ b/BTCPayServer/Models/StoreViewModels/CheckoutExperienceViewModel.cs @@ -30,6 +30,13 @@ namespace BTCPayServer.Models.StoreViewModels [Display(Name = "Do not propose lightning payment if value of the invoice is above...")] [MaxLength(20)] public string LightningMaxValue { get; set; } + + [Display(Name = "Link to a custom CSS stylesheet")] + [Url] + public Uri CustomCSS { get; set; } + [Display(Name = "Link to a custom logo")] + [Url] + public Uri CustomLogo { get; set; } public void SetCryptoCurrencies(ExplorerClientProvider explorerProvider, string defaultCrypto) { var choices = explorerProvider.GetAll().Select(o => new Format() { Name = o.Item1.CryptoCode, Value = o.Item1.CryptoCode }).ToArray(); diff --git a/BTCPayServer/Views/Invoice/Checkout-Body.cshtml b/BTCPayServer/Views/Invoice/Checkout-Body.cshtml index b59bdd697..5f5f439ed 100644 --- a/BTCPayServer/Views/Invoice/Checkout-Body.cshtml +++ b/BTCPayServer/Views/Invoice/Checkout-Body.cshtml @@ -3,7 +3,14 @@
- + @if(Model.CustomLogoLink != null) + { + + } + else + { + + }
@@ -26,7 +33,7 @@
- @if (Model.AvailableCryptos.Count > 1) + @if(Model.AvailableCryptos.Count > 1) {
@@ -36,7 +43,7 @@
- @foreach (var crypto in Model.AvailableCryptos) + @foreach(var crypto in Model.AvailableCryptos) { @crypto.PaymentMethodId @@ -101,7 +108,7 @@
{{$t("Copy")}}
- @if (Model.AllowCoinConversion) + @if(Model.AllowCoinConversion) {
{{$t("Conversion")}} @@ -193,7 +200,7 @@
- @if (Model.AllowCoinConversion) + @if(Model.AllowCoinConversion) {
@@ -218,10 +225,10 @@ @*Changelly doesn't have TO_AMOUNT support so we can't include it - - - Changelly - *@ + + + Changelly + *@
diff --git a/BTCPayServer/Views/Invoice/Checkout.cshtml b/BTCPayServer/Views/Invoice/Checkout.cshtml index fb5efd55a..08325e6a3 100644 --- a/BTCPayServer/Views/Invoice/Checkout.cshtml +++ b/BTCPayServer/Views/Invoice/Checkout.cshtml @@ -20,6 +20,12 @@ + + + @if(Model.CustomCSSLink != null) + { + + }