diff --git a/BTCPayServer.Client/Models/StoreBaseData.cs b/BTCPayServer.Client/Models/StoreBaseData.cs index 148b00339..5cb07f3c9 100644 --- a/BTCPayServer.Client/Models/StoreBaseData.cs +++ b/BTCPayServer.Client/Models/StoreBaseData.cs @@ -1,3 +1,7 @@ +using BTCPayServer.Client.JsonConverters; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + namespace BTCPayServer.Client.Models { public abstract class StoreBaseData @@ -6,5 +10,55 @@ namespace BTCPayServer.Client.Models /// the name of the store /// public string Name { get; set; } + + public string Website { get; set; } + public int InvoiceExpiration { get; set; } = 15; + public int MonitoringExpiration { get; set; } = 60; + + [JsonConverter(typeof(StringEnumConverter))] + public SpeedPolicy SpeedPolicy { get; set; } + public string LightningDescriptionTemplate { get; set; } + public double PaymentTolerance { get; set; } = 0; + public bool AnyoneCanCreateInvoice { get; set; } + + public bool ShowRecommendedFee { get; set; } + + public int RecommendedFeeBlockTarget { get; set; } + + public string DefaultLang { get; set; } + public bool LightningAmountInSatoshi { get; set; } + + public string CustomLogo { get; set; } + + public string CustomCSS { get; set; } + + public string HtmlTitle { get; set; } + + public bool AnyoneCanInvoice { get; set; } + + public bool RedirectAutomatically { get; set; } + + public bool RequiresRefundEmail { get; set; } + + [JsonConverter(typeof(StringEnumConverter))] + public NetworkFeeMode NetworkFeeMode { get; set; } + + public bool PayJoinEnabled { get; set; } + + } + + public enum NetworkFeeMode + { + MultiplePaymentsOnly, + Always, + Never + } + + public enum SpeedPolicy + { + HighSpeed = 0, + MediumSpeed = 1, + LowSpeed = 2, + LowMediumSpeed = 3 } } diff --git a/BTCPayServer.Data/Data/StoreData.cs b/BTCPayServer.Data/Data/StoreData.cs index b5fe2097f..4f795f54a 100644 --- a/BTCPayServer.Data/Data/StoreData.cs +++ b/BTCPayServer.Data/Data/StoreData.cs @@ -1,16 +1,10 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; +using BTCPayServer.Client.Models; namespace BTCPayServer.Data { - public enum SpeedPolicy - { - HighSpeed = 0, - MediumSpeed = 1, - LowSpeed = 2, - LowMediumSpeed = 3 - } public class StoreData { @@ -48,10 +42,5 @@ namespace BTCPayServer.Data public IEnumerable APIKeys { get; set; } } - public enum NetworkFeeMode - { - MultiplePaymentsOnly, - Always, - Never - } + } diff --git a/BTCPayServer.Tests/CrowdfundTests.cs b/BTCPayServer.Tests/CrowdfundTests.cs index 3b3bb3fa1..aba5daeb9 100644 --- a/BTCPayServer.Tests/CrowdfundTests.cs +++ b/BTCPayServer.Tests/CrowdfundTests.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using BTCPayServer.Client.Models; using BTCPayServer.Controllers; using BTCPayServer.Data; using BTCPayServer.Events; diff --git a/BTCPayServer.Tests/TestAccount.cs b/BTCPayServer.Tests/TestAccount.cs index 01302d6a4..576de0d9a 100644 --- a/BTCPayServer.Tests/TestAccount.cs +++ b/BTCPayServer.Tests/TestAccount.cs @@ -23,6 +23,7 @@ using BTCPayServer.Data; using Microsoft.AspNetCore.Identity; using NBXplorer.Models; using BTCPayServer.Client; +using BTCPayServer.Client.Models; using BTCPayServer.Events; using BTCPayServer.Services; using BTCPayServer.Services.Stores; diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index a38bb8d5e..77241165b 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -63,6 +63,7 @@ using BTCPayServer.Security.Bitpay; using MemoryCache = Microsoft.Extensions.Caching.Memory.MemoryCache; using Newtonsoft.Json.Schema; using BTCPayServer.Client; +using BTCPayServer.Client.Models; namespace BTCPayServer.Tests { diff --git a/BTCPayServer/Controllers/GreenField/StoresController.cs b/BTCPayServer/Controllers/GreenField/StoresController.cs index 240812e25..e48455f67 100644 --- a/BTCPayServer/Controllers/GreenField/StoresController.cs +++ b/BTCPayServer/Controllers/GreenField/StoresController.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -101,22 +102,97 @@ namespace BTCPayServer.Controllers.GreenField private static Client.Models.StoreData FromModel(Data.StoreData data) { + var storeBlob = data.GetStoreBlob(); return new Client.Models.StoreData() { - Id = data.Id, - Name = data.StoreName + Id = data.Id, + Name = data.StoreName, + Website = data.StoreWebsite, + SpeedPolicy = data.SpeedPolicy, + //we do not include the default payment method in this model and instead opt to set it in the stores/storeid/payment-methods endpoints + //blob + //we do not include DefaultCurrencyPairs,Spread, PreferredExchange, RateScripting, RateScript in this model and instead opt to set it in stores/storeid/rates endpoints + //we do not include ChangellySettings in this model and instead opt to set it in stores/storeid/changelly endpoints + //we do not include CoinSwitchSettings in this model and instead opt to set it in stores/storeid/coinswitch endpoints + //we do not include ExcludedPaymentMethods in this model and instead opt to set it in stores/storeid/payment-methods endpoints + //we do not include EmailSettings in this model and instead opt to set it in stores/storeid/email endpoints + //we do not include OnChainMinValue and LightningMaxValue because moving the CurrencyValueJsonConverter to the Client csproj is hard and requires a refactor (#1571 & #1572) + NetworkFeeMode = storeBlob.NetworkFeeMode, + RequiresRefundEmail = storeBlob.RequiresRefundEmail, + ShowRecommendedFee = storeBlob.ShowRecommendedFee, + RecommendedFeeBlockTarget = storeBlob.RecommendedFeeBlockTarget, + DefaultLang = storeBlob.DefaultLang, + MonitoringExpiration = storeBlob.MonitoringExpiration, + InvoiceExpiration = storeBlob.InvoiceExpiration, + LightningAmountInSatoshi = storeBlob.LightningAmountInSatoshi, + CustomLogo = storeBlob.CustomLogo, + CustomCSS = storeBlob.CustomCSS, + HtmlTitle = storeBlob.HtmlTitle, + AnyoneCanInvoice = storeBlob.AnyoneCanInvoice, + LightningDescriptionTemplate = storeBlob.LightningDescriptionTemplate, + PaymentTolerance = storeBlob.PaymentTolerance, + RedirectAutomatically = storeBlob.RedirectAutomatically, + PayJoinEnabled = storeBlob.PayJoinEnabled }; } - - private static void ToModel(StoreBaseData restModel,Data.StoreData model) + + private static void ToModel(StoreBaseData restModel, Data.StoreData model) { + var blob = model.GetStoreBlob(); + model.StoreName = restModel.Name; + model.StoreName = restModel.Name; + model.StoreWebsite = restModel.Website; + model.SpeedPolicy = restModel.SpeedPolicy; + //we do not include the default payment method in this model and instead opt to set it in the stores/storeid/payment-methods endpoints + //blob + //we do not include DefaultCurrencyPairs;Spread; PreferredExchange; RateScripting; RateScript in this model and instead opt to set it in stores/storeid/rates endpoints + //we do not include ChangellySettings in this model and instead opt to set it in stores/storeid/changelly endpoints + //we do not include CoinSwitchSettings in this model and instead opt to set it in stores/storeid/coinswitch endpoints + //we do not include ExcludedPaymentMethods in this model and instead opt to set it in stores/storeid/payment-methods endpoints + //we do not include EmailSettings in this model and instead opt to set it in stores/storeid/email endpoints + //we do not include OnChainMinValue and LightningMaxValue because moving the CurrencyValueJsonConverter to the Client csproj is hard and requires a refactor (#1571 & #1572) + blob.NetworkFeeMode = restModel.NetworkFeeMode; + blob.RequiresRefundEmail = restModel.RequiresRefundEmail; + blob.ShowRecommendedFee = restModel.ShowRecommendedFee; + blob.RecommendedFeeBlockTarget = restModel.RecommendedFeeBlockTarget; + blob.DefaultLang = restModel.DefaultLang; + blob.MonitoringExpiration = restModel.MonitoringExpiration; + blob.InvoiceExpiration = restModel.InvoiceExpiration; + blob.LightningAmountInSatoshi = restModel.LightningAmountInSatoshi; + blob.CustomLogo = restModel.CustomLogo; + blob.CustomCSS = restModel.CustomCSS; + blob.HtmlTitle = restModel.HtmlTitle; + blob.AnyoneCanInvoice = restModel.AnyoneCanInvoice; + blob.LightningDescriptionTemplate = restModel.LightningDescriptionTemplate; + blob.PaymentTolerance = restModel.PaymentTolerance; + blob.RedirectAutomatically = restModel.RedirectAutomatically; + blob.PayJoinEnabled = restModel.PayJoinEnabled; + model.SetStoreBlob(blob); } private IActionResult Validate(StoreBaseData request) { - if (request?.Name is null) + if (request is null) + { + return BadRequest(); + } + + if (string.IsNullOrEmpty(request.Name)) ModelState.AddModelError(nameof(request.Name), "Name is missing"); + else if(request.Name.Length < 1 || request.Name.Length > 50) + ModelState.AddModelError(nameof(request.Name), "Name can only be between 1 and 50 characters"); + if (!string.IsNullOrEmpty(request.Website) && !Uri.TryCreate(request.Website, UriKind.Absolute, out _)) + { + ModelState.AddModelError(nameof(request.Website), "Website is not a valid url"); + } + if(request.InvoiceExpiration < 1 && request.InvoiceExpiration > 60 * 24 * 24) + ModelState.AddModelError(nameof(request.InvoiceExpiration), "InvoiceExpiration can only be between 1 and 34560 mins"); + if(request.MonitoringExpiration < 10 && request.MonitoringExpiration > 60 * 24 * 24) + ModelState.AddModelError(nameof(request.MonitoringExpiration), "InvoiceExpiration can only be between 10 and 34560 mins"); + if(request.PaymentTolerance < 0 && request.PaymentTolerance > 100) + ModelState.AddModelError(nameof(request.PaymentTolerance), "PaymentTolerance can only be between 0 and 100 percent"); + return !ModelState.IsValid ? BadRequest(new ValidationProblemDetails(ModelState)) : null; } } diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index c767707ed..ce58c4025 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -7,6 +7,7 @@ using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; using BTCPayServer.Client; +using BTCPayServer.Client.Models; using BTCPayServer.Data; using BTCPayServer.Events; using BTCPayServer.Filters; @@ -26,6 +27,7 @@ using NBitcoin; using NBitpayClient; using NBXplorer; using Newtonsoft.Json.Linq; +using StoreData = BTCPayServer.Data.StoreData; namespace BTCPayServer.Controllers { diff --git a/BTCPayServer/Controllers/InvoiceController.cs b/BTCPayServer/Controllers/InvoiceController.cs index 46568e6f5..299bbbc1d 100644 --- a/BTCPayServer/Controllers/InvoiceController.cs +++ b/BTCPayServer/Controllers/InvoiceController.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using BTCPayServer.Client.Models; using BTCPayServer.Data; using BTCPayServer.Events; using BTCPayServer.Logging; @@ -23,6 +24,7 @@ using Microsoft.AspNetCore.Mvc; using NBitcoin; using NBitpayClient; using Newtonsoft.Json; +using StoreData = BTCPayServer.Data.StoreData; namespace BTCPayServer.Controllers { diff --git a/BTCPayServer/Controllers/StoresController.cs b/BTCPayServer/Controllers/StoresController.cs index bd420f076..e2123b7bd 100644 --- a/BTCPayServer/Controllers/StoresController.cs +++ b/BTCPayServer/Controllers/StoresController.cs @@ -6,6 +6,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using BTCPayServer.Client; +using BTCPayServer.Client.Models; using BTCPayServer.Configuration; using BTCPayServer.Data; using BTCPayServer.HostedServices; @@ -31,6 +32,7 @@ using Microsoft.AspNetCore.Mvc.Rendering; using NBitcoin; using NBitcoin.DataEncoders; using NBXplorer; +using StoreData = BTCPayServer.Data.StoreData; namespace BTCPayServer.Controllers { diff --git a/BTCPayServer/Data/StoreBlob.cs b/BTCPayServer/Data/StoreBlob.cs index c91d313da..2e2d50296 100644 --- a/BTCPayServer/Data/StoreBlob.cs +++ b/BTCPayServer/Data/StoreBlob.cs @@ -10,6 +10,7 @@ using BTCPayServer.Rating; using BTCPayServer.Services.Mails; using Newtonsoft.Json; using System.Text; +using BTCPayServer.Client.Models; using BTCPayServer.Services.Rates; namespace BTCPayServer.Data diff --git a/BTCPayServer/MigrationStartupTask.cs b/BTCPayServer/MigrationStartupTask.cs index 3e4cb1aaf..143601ad3 100644 --- a/BTCPayServer/MigrationStartupTask.cs +++ b/BTCPayServer/MigrationStartupTask.cs @@ -9,6 +9,7 @@ using BTCPayServer.Services; using BTCPayServer.Services.Stores; using BTCPayServer.Logging; using System.Threading; +using BTCPayServer.Client.Models; using Npgsql; using Microsoft.AspNetCore.Identity; diff --git a/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs b/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs index f315ef81c..0ec56b2bb 100644 --- a/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs +++ b/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs @@ -1,6 +1,7 @@ using BTCPayServer.Validation; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using BTCPayServer.Client.Models; using BTCPayServer.Data; namespace BTCPayServer.Models.StoreViewModels @@ -79,7 +80,7 @@ namespace BTCPayServer.Models.StoreViewModels } [Display(Name = "Add additional fee (network fee) to invoice...")] - public Data.NetworkFeeMode NetworkFeeMode + public NetworkFeeMode NetworkFeeMode { get; set; } diff --git a/BTCPayServer/Payments/Bitcoin/BitcoinLikeOnChainPaymentMethod.cs b/BTCPayServer/Payments/Bitcoin/BitcoinLikeOnChainPaymentMethod.cs index 514f7eed9..7d6f2030a 100644 --- a/BTCPayServer/Payments/Bitcoin/BitcoinLikeOnChainPaymentMethod.cs +++ b/BTCPayServer/Payments/Bitcoin/BitcoinLikeOnChainPaymentMethod.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using BTCPayServer.Client.Models; using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Wallets; using NBitcoin; @@ -33,7 +34,7 @@ namespace BTCPayServer.Payments.Bitcoin { DepositAddress = newPaymentDestination; } - public Data.NetworkFeeMode NetworkFeeMode { get; set; } + public NetworkFeeMode NetworkFeeMode { get; set; } FeeRate _NetworkFeeRate; [JsonConverter(typeof(NBitcoin.JsonConverters.FeeRateJsonConverter))] diff --git a/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentData.cs b/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentData.cs index 2beb8d189..2bf306ac6 100644 --- a/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentData.cs +++ b/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentData.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using BTCPayServer.Client.Models; using BTCPayServer.Data; using BTCPayServer.Services.Invoices; using NBitcoin; diff --git a/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentHandler.cs b/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentHandler.cs index ed5e971e7..dfb5f0519 100644 --- a/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentHandler.cs +++ b/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentHandler.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using BTCPayServer.Client.Models; using BTCPayServer.Data; using BTCPayServer.HostedServices; using BTCPayServer.Logging; @@ -13,6 +14,7 @@ using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Rates; using NBitcoin; using NBXplorer.Models; +using StoreData = BTCPayServer.Data.StoreData; namespace BTCPayServer.Payments.Bitcoin { diff --git a/BTCPayServer/Payments/Lightning/LightningLikePaymentData.cs b/BTCPayServer/Payments/Lightning/LightningLikePaymentData.cs index 5143b7777..5cc6894a8 100644 --- a/BTCPayServer/Payments/Lightning/LightningLikePaymentData.cs +++ b/BTCPayServer/Payments/Lightning/LightningLikePaymentData.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using BTCPayServer.Client.Models; using BTCPayServer.Data; using BTCPayServer.JsonConverters; using BTCPayServer.Lightning; diff --git a/BTCPayServer/Services/Altcoins/Monero/Payments/MoneroLikePaymentData.cs b/BTCPayServer/Services/Altcoins/Monero/Payments/MoneroLikePaymentData.cs index 0c2df80a1..1a25316bf 100644 --- a/BTCPayServer/Services/Altcoins/Monero/Payments/MoneroLikePaymentData.cs +++ b/BTCPayServer/Services/Altcoins/Monero/Payments/MoneroLikePaymentData.cs @@ -1,3 +1,4 @@ +using BTCPayServer.Client.Models; using BTCPayServer.Data; using BTCPayServer.Services.Altcoins.Monero.Utils; using BTCPayServer.Payments; diff --git a/BTCPayServer/Services/Invoices/InvoiceEntity.cs b/BTCPayServer/Services/Invoices/InvoiceEntity.cs index 98c459fad..e99750c42 100644 --- a/BTCPayServer/Services/Invoices/InvoiceEntity.cs +++ b/BTCPayServer/Services/Invoices/InvoiceEntity.cs @@ -16,6 +16,7 @@ using BTCPayServer.Payments; using NBitpayClient; using BTCPayServer.Payments.Bitcoin; using System.ComponentModel.DataAnnotations.Schema; +using BTCPayServer.Client.Models; using BTCPayServer.JsonConverters; namespace BTCPayServer.Services.Invoices diff --git a/BTCPayServer/Services/Invoices/InvoiceRepository.cs b/BTCPayServer/Services/Invoices/InvoiceRepository.cs index 7953862bb..1c603d9f2 100644 --- a/BTCPayServer/Services/Invoices/InvoiceRepository.cs +++ b/BTCPayServer/Services/Invoices/InvoiceRepository.cs @@ -8,6 +8,7 @@ using Microsoft.EntityFrameworkCore; using System.Threading.Tasks; using BTCPayServer.Data; using System.Globalization; +using BTCPayServer.Client.Models; using BTCPayServer.Models.InvoicingModels; using BTCPayServer.Logging; using BTCPayServer.Payments; diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores.json index b69896b65..b4ca04f58 100644 --- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores.json +++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores.json @@ -40,15 +40,7 @@ "content": { "application/json": { "schema": { - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "type": "string", - "description": "The name of the new store", - "nullable": false - } - } + "$ref": "#/components/schemas/StoreBaseData" } } }, @@ -158,15 +150,7 @@ "content": { "application/json": { "schema": { - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "type": "string", - "description": "The name of the store", - "nullable": false - } - } + "$ref": "#/components/schemas/StoreData" } } }, @@ -269,20 +253,132 @@ } }, "StoreData": { + "allOf": [ + { + "$ref": "#/definitions/StoreBaseData" + }, + { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The id of the store", + "nullable": false + } + } + } + ] + }, + "StoreBaseData": { "type": "object", + "x-abstract": true, "additionalProperties": false, "properties": { - "id": { - "type": "string", - "description": "The id of the store", - "nullable": false - }, "name": { "type": "string", "description": "The name of the store", - "nullable": false + "nullable": true + }, + "website": { + "type": "string", + "description": "The absolute url of the store", + "format": "url", + "nullable": true + }, + "invoiceExpiration": { + "type": "integer", + "format": "int32" + }, + "monitoringExpiration": { + "type": "integer", + "format": "int32" + }, + "speedPolicy": { + "$ref": "#/components/schemas/SpeedPolicy" + }, + "lightningDescriptionTemplate": { + "type": "string", + "nullable": true + }, + "paymentTolerance": { + "type": "number", + "format": "double" + }, + "anyoneCanCreateInvoice": { + "type": "boolean" + }, + "showRecommendedFee": { + "type": "boolean" + }, + "recommendedFeeBlockTarget": { + "type": "integer", + "format": "int32" + }, + "defaultLang": { + "type": "string", + "nullable": true + }, + "lightningAmountInSatoshi": { + "type": "boolean" + }, + "customLogo": { + "type": "string", + "nullable": true + }, + "customCSS": { + "type": "string", + "nullable": true + }, + "htmlTitle": { + "type": "string", + "nullable": true + }, + "anyoneCanInvoice": { + "type": "boolean" + }, + "redirectAutomatically": { + "type": "boolean" + }, + "requiresRefundEmail": { + "type": "boolean" + }, + "networkFeeMode": { + "$ref": "#/components/schemas/NetworkFeeMode" + }, + "payJoinEnabled": { + "type": "boolean" } } + }, + "SpeedPolicy": { + "type": "string", + "description": "", + "x-enumNames": [ + "HighSpeed", + "MediumSpeed", + "LowSpeed", + "LowMediumSpeed" + ], + "enum": [ + "HighSpeed", + "MediumSpeed", + "LowSpeed", + "LowMediumSpeed" + ] + }, + "NetworkFeeMode": { + "type": "string", + "description": "", + "x-enumNames": [ + "MultiplePaymentsOnly", + "Always", + "Never" + ], + "enum": [ + "MultiplePaymentsOnly", + "Always", + "Never" + ] } } },