diff --git a/BTCPayServer.Rating/AvailableRateProvider.cs b/BTCPayServer.Rating/AvailableRateProvider.cs index 884da39ac..b21e0189f 100644 --- a/BTCPayServer.Rating/AvailableRateProvider.cs +++ b/BTCPayServer.Rating/AvailableRateProvider.cs @@ -1,3 +1,5 @@ +using System; + namespace BTCPayServer.Rating { public enum RateSource @@ -25,5 +27,13 @@ namespace BTCPayServer.Rating Url = url; Source = source; } + + public string DisplayName => + Source switch + { + RateSource.Direct => Name, + RateSource.Coingecko => $"{Name} (via CoinGecko)", + _ => throw new NotSupportedException(Source.ToString()) + }; } } diff --git a/BTCPayServer/Controllers/UIStoresController.cs b/BTCPayServer/Controllers/UIStoresController.cs index 408a051e9..99a36b4a5 100644 --- a/BTCPayServer/Controllers/UIStoresController.cs +++ b/BTCPayServer/Controllers/UIStoresController.cs @@ -104,7 +104,6 @@ namespace BTCPayServer.Controllers private readonly EventAggregator _EventAggregator; private readonly NBXplorerDashboard _Dashboard; private readonly IOptions _externalServiceOptions; - public string CreatedStoreId { get; set; } [TempData] public bool StoreNotConfigured diff --git a/BTCPayServer/Controllers/UIUserStoresController.cs b/BTCPayServer/Controllers/UIUserStoresController.cs index 188580751..94e711492 100644 --- a/BTCPayServer/Controllers/UIUserStoresController.cs +++ b/BTCPayServer/Controllers/UIUserStoresController.cs @@ -1,3 +1,5 @@ +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using BTCPayServer.Abstractions.Constants; @@ -5,12 +7,13 @@ using BTCPayServer.Client; using BTCPayServer.Data; using BTCPayServer.Models; using BTCPayServer.Models.StoreViewModels; -using BTCPayServer.Security; +using BTCPayServer.Rating; +using BTCPayServer.Services.Rates; using BTCPayServer.Services.Stores; -using ExchangeSharp; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Rendering; namespace BTCPayServer.Controllers { @@ -20,20 +23,30 @@ namespace BTCPayServer.Controllers { private readonly StoreRepository _repo; private readonly UserManager _userManager; + private readonly RateFetcher _rateFactory; + public string CreatedStoreId { get; set; } public UIUserStoresController( UserManager userManager, - StoreRepository storeRepository) + StoreRepository storeRepository, + RateFetcher rateFactory) { _repo = storeRepository; _userManager = userManager; + _rateFactory = rateFactory; } [HttpGet("create")] [Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanModifyStoreSettingsUnscoped)] public IActionResult CreateStore() { - return View(); + var vm = new CreateStoreViewModel + { + DefaultCurrency = StoreBlob.StandardDefaultCurrency, + Exchanges = GetExchangesSelectList(CoinGeckoRateProvider.CoinGeckoName) + }; + + return View(vm); } [HttpPost("create")] @@ -42,10 +55,13 @@ namespace BTCPayServer.Controllers { if (!ModelState.IsValid) { + vm.Exchanges = GetExchangesSelectList(vm.PreferredExchange); return View(vm); } - var store = await _repo.CreateStore(GetUserId(), vm.Name); + + var store = await _repo.CreateStore(GetUserId(), vm.Name, vm.DefaultCurrency, vm.PreferredExchange); CreatedStoreId = store.Id; + TempData[WellKnownTempData.SuccessMessage] = "Store successfully created"; return RedirectToAction(nameof(UIStoresController.Dashboard), "UIStores", new { @@ -53,11 +69,6 @@ namespace BTCPayServer.Controllers }); } - public string CreatedStoreId - { - get; set; - } - [HttpGet("{storeId}/me/delete")] [Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanModifyStoreSettings)] public IActionResult DeleteStore(string storeId) @@ -82,5 +93,14 @@ namespace BTCPayServer.Controllers } private string GetUserId() => _userManager.GetUserId(User); + + private SelectList GetExchangesSelectList(string selected) { + var exchanges = _rateFactory.RateProviderFactory + .GetSupportedExchanges() + .Where(r => !string.IsNullOrWhiteSpace(r.Name)) + .OrderBy(s => s.Id, StringComparer.OrdinalIgnoreCase); + var chosen = exchanges.FirstOrDefault(f => f.Id == selected) ?? exchanges.First(); + return new SelectList(exchanges, nameof(chosen.Id), nameof(chosen.Name), chosen.Id); + } } } diff --git a/BTCPayServer/Data/StoreBlob.cs b/BTCPayServer/Data/StoreBlob.cs index 3f96564b3..ffe3dd792 100644 --- a/BTCPayServer/Data/StoreBlob.cs +++ b/BTCPayServer/Data/StoreBlob.cs @@ -18,6 +18,8 @@ namespace BTCPayServer.Data { public class StoreBlob { + public static string StandardDefaultCurrency = "USD"; + public StoreBlob() { InvoiceExpiration = TimeSpan.FromMinutes(15); @@ -27,8 +29,7 @@ namespace BTCPayServer.Data RecommendedFeeBlockTarget = 1; PaymentMethodCriteria = new List(); } - - + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public NetworkFeeMode NetworkFeeMode { get; set; } @@ -45,7 +46,7 @@ namespace BTCPayServer.Data { get { - return string.IsNullOrEmpty(_DefaultCurrency) ? "USD" : _DefaultCurrency; + return string.IsNullOrEmpty(_DefaultCurrency) ? StandardDefaultCurrency : _DefaultCurrency; } set { diff --git a/BTCPayServer/Models/StoreViewModels/CreateStoreViewModel.cs b/BTCPayServer/Models/StoreViewModels/CreateStoreViewModel.cs index b465f63fe..17b61d0ec 100644 --- a/BTCPayServer/Models/StoreViewModels/CreateStoreViewModel.cs +++ b/BTCPayServer/Models/StoreViewModels/CreateStoreViewModel.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc.Rendering; namespace BTCPayServer.Models.StoreViewModels { @@ -7,9 +8,17 @@ namespace BTCPayServer.Models.StoreViewModels [Required] [MaxLength(50)] [MinLength(1)] - public string Name - { - get; set; - } + public string Name { get; set; } + + [Required] + [MaxLength(10)] + [Display(Name = "Default currency")] + public string DefaultCurrency { get; set; } + + [Required] + [Display(Name = "Preferred Price Source")] + public string PreferredExchange { get; set; } + + public SelectList Exchanges { get; set; } } } diff --git a/BTCPayServer/Models/StoreViewModels/RatesViewModel.cs b/BTCPayServer/Models/StoreViewModels/RatesViewModel.cs index 34a978270..6ee96f1e6 100644 --- a/BTCPayServer/Models/StoreViewModels/RatesViewModel.cs +++ b/BTCPayServer/Models/StoreViewModels/RatesViewModel.cs @@ -16,27 +16,15 @@ namespace BTCPayServer.Models.StoreViewModels public string Rule { get; set; } public bool Error { get; set; } } + public void SetExchangeRates(IEnumerable supportedList, string preferredExchange) { var defaultStore = preferredExchange ?? CoinGeckoRateProvider.CoinGeckoName; - supportedList = supportedList.Select(a => new AvailableRateProvider(a.Id, a.SourceId, GetName(a), a.Url, a.Source)).ToArray(); + supportedList = supportedList.Select(a => new AvailableRateProvider(a.Id, a.SourceId, a.DisplayName, a.Url, a.Source)).ToArray(); var chosen = supportedList.FirstOrDefault(f => f.Id == defaultStore) ?? supportedList.FirstOrDefault(); Exchanges = new SelectList(supportedList, nameof(chosen.Id), nameof(chosen.Name), chosen); - PreferredExchange = chosen.Id; - RateSource = chosen.Url; - } - - private string GetName(AvailableRateProvider a) - { - switch (a.Source) - { - case Rating.RateSource.Direct: - return a.Name; - case Rating.RateSource.Coingecko: - return $"{a.Name} (via CoinGecko)"; - default: - throw new NotSupportedException(a.Source.ToString()); - } + PreferredExchange = chosen?.Id; + RateSource = chosen?.Url; } public List TestRateRules { get; set; } @@ -56,19 +44,11 @@ namespace BTCPayServer.Models.StoreViewModels [Display(Name = "Add Exchange Rate Spread")] [Range(0.0, 100.0)] - public double Spread - { - get; - set; - } + public double Spread { get; set; } [Display(Name = "Preferred Price Source")] public string PreferredExchange { get; set; } - public string RateSource - { - get; - set; - } + public string RateSource { get; set; } } } diff --git a/BTCPayServer/Services/Stores/StoreRepository.cs b/BTCPayServer/Services/Stores/StoreRepository.cs index b1b96c694..d19dd1c21 100644 --- a/BTCPayServer/Services/Stores/StoreRepository.cs +++ b/BTCPayServer/Services/Stores/StoreRepository.cs @@ -186,10 +186,14 @@ namespace BTCPayServer.Services.Stores await ctx.SaveChangesAsync(); } - public async Task CreateStore(string ownerId, string name) + public async Task CreateStore(string ownerId, string name, string defaultCurrency, string preferredExchange) { - var store = new StoreData() { StoreName = name }; - SetNewStoreHints(ref store); + var store = new StoreData { StoreName = name }; + var blob = store.GetStoreBlob(); + blob.DefaultCurrency = defaultCurrency; + blob.PreferredExchange = preferredExchange; + store.SetStoreBlob(blob); + await CreateStore(ownerId, store); return store; } diff --git a/BTCPayServer/Views/UIUserStores/CreateStore.cshtml b/BTCPayServer/Views/UIUserStores/CreateStore.cshtml index e46cba62d..95ab70072 100644 --- a/BTCPayServer/Views/UIUserStores/CreateStore.cshtml +++ b/BTCPayServer/Views/UIUserStores/CreateStore.cshtml @@ -19,6 +19,16 @@ +
+ + + +
+
+ + + +