diff --git a/BTCPayServer.Tests/ChangellyTests.cs b/BTCPayServer.Tests/ChangellyTests.cs index 0b8f18419..5d19036bc 100644 --- a/BTCPayServer.Tests/ChangellyTests.cs +++ b/BTCPayServer.Tests/ChangellyTests.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Net.Http; using System.Threading.Tasks; using BTCPayServer.Controllers; +using BTCPayServer.Data; using BTCPayServer.Models; using BTCPayServer.Models.StoreViewModels; using BTCPayServer.Payments.Changelly; @@ -112,7 +113,8 @@ namespace BTCPayServer.Tests user.GrantAccess(); var changellyController = tester.PayTester.GetController(user.UserId, user.StoreId); - + changellyController.IsTest = true; + //test non existing payment method Assert.IsType(Assert .IsType(await changellyController.GetCurrencyList(user.StoreId)) @@ -161,42 +163,24 @@ namespace BTCPayServer.Tests //save changelly settings var updateModel = new UpdateChangellySettingsViewModel() { - ApiSecret = "secret", - ApiKey = "key", - ApiUrl = "http://gozo.com", - ChangellyMerchantId = "aaa" + Enabled = true }; var storesController = tester.PayTester.GetController(user.UserId, user.StoreId); //confirm saved Assert.Equal("UpdateStore", Assert.IsType( await storesController.UpdateChangellySettings(user.StoreId, updateModel, "save")).ActionName); - - - var mockChangelly = new MockChangelly(new MockHttpClientFactory(), updateModel.ApiKey, updateModel.ApiSecret, updateModel.ApiUrl); - var mock = new MockChangellyClientProvider(mockChangelly, tester.PayTester.StoreRepository); var factory = UnitTest1.CreateBTCPayRateFactory(); var fetcher = new RateFetcher(factory); - - var changellyController = new ChangellyController(mock, tester.NetworkProvider, fetcher); - - - mockChangelly.GetCurrenciesFullResult = new List() - { - new CurrencyFull() - { - Name = "a", - Enable = true, - PayInConfirmations = 10, - FullName = "aa", - ImageLink = "" - } - }; + var httpClientFactory = new MockHttpClientFactory(); + var changellyController = new ChangellyController( + new ChangellyClientProvider(tester.PayTester.StoreRepository,httpClientFactory), tester.NetworkProvider, fetcher); + changellyController.IsTest = true; var result = Assert .IsType(await changellyController.GetCurrencyList(user.StoreId)) .Value as IEnumerable; - Assert.Equal(1, mockChangelly.GetCurrenciesFullCallCount); + Assert.True(result.Any()); } } @@ -213,41 +197,22 @@ namespace BTCPayServer.Tests var updateModel = new UpdateChangellySettingsViewModel() { - ApiSecret = "secret", - ApiKey = "key", - ApiUrl = "http://gozo.com", - ChangellyMerchantId = "aaa" + Enabled = true }; var storesController = tester.PayTester.GetController(user.UserId, user.StoreId); Assert.Equal("UpdateStore", Assert.IsType( await storesController.UpdateChangellySettings(user.StoreId, updateModel, "save")).ActionName); - var mockChangelly = new MockChangelly(new MockHttpClientFactory(), updateModel.ApiKey, updateModel.ApiSecret, updateModel.ApiUrl); - var mock = new MockChangellyClientProvider(mockChangelly, tester.PayTester.StoreRepository); - var factory = UnitTest1.CreateBTCPayRateFactory(); var fetcher = new RateFetcher(factory); - - var changellyController = new ChangellyController(mock,tester.NetworkProvider,fetcher); - - mockChangelly.GetExchangeAmountResult = (from, to, amount) => - { - Assert.Equal("A", from); - Assert.Equal("B", to); - - switch (mockChangelly.GetExchangeAmountCallCount) - { - case 1: - return 0.5m; - default: - return 1.01m; - } - }; - + var httpClientFactory = new MockHttpClientFactory(); + var changellyController = new ChangellyController( + new ChangellyClientProvider(tester.PayTester.StoreRepository,httpClientFactory), tester.NetworkProvider, fetcher); + changellyController.IsTest = true; Assert.IsType(Assert - .IsType(await changellyController.CalculateAmount(user.StoreId, "A", "B", 1.0m)).Value); - Assert.True(mockChangelly.GetExchangeAmountCallCount > 1); + .IsType(await changellyController.CalculateAmount(user.StoreId, "ltc", "btc", 1.0m)).Value); + } } } @@ -259,60 +224,4 @@ namespace BTCPayServer.Tests return new HttpClient(); } } - - public class MockChangelly : Changelly - { - public IEnumerable GetCurrenciesFullResult { get; set; } - - public delegate decimal ParamsFunc(T1 arg1, T2 arg2, T3 arg3); - - public ParamsFunc GetExchangeAmountResult - { - get; - set; - } - - public int GetCurrenciesFullCallCount { get; set; } = 0; - public int GetExchangeAmountCallCount { get; set; } = 0; - - public MockChangelly(IHttpClientFactory httpClientFactory, string apiKey, string apiSecret, string apiUrl) : base(httpClientFactory, apiKey, apiSecret, apiUrl) - { - } - -#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously - public override async Task> GetCurrenciesFull() -#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously - { - GetCurrenciesFullCallCount++; - return GetCurrenciesFullResult; - } - -#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously - public override async Task GetExchangeAmount(string fromCurrency, -#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously - string toCurrency, decimal amount) - { - GetExchangeAmountCallCount++; - return GetExchangeAmountResult.Invoke(fromCurrency, toCurrency, amount); - } - } - - public class MockChangellyClientProvider : ChangellyClientProvider - { - public MockChangelly MockChangelly; - - public MockChangellyClientProvider( - MockChangelly mockChangelly, - StoreRepository storeRepository) : base(storeRepository, new MockHttpClientFactory()) - { - MockChangelly = mockChangelly; - } - - public override bool TryGetChangellyClient(string storeId, out string error, out Changelly changelly) - { - error = null; - changelly = MockChangelly; - return true; - } - } } diff --git a/BTCPayServer/Controllers/ChangellyController.cs b/BTCPayServer/Controllers/ChangellyController.cs index 724d558f1..7568d96cb 100644 --- a/BTCPayServer/Controllers/ChangellyController.cs +++ b/BTCPayServer/Controllers/ChangellyController.cs @@ -29,13 +29,11 @@ namespace BTCPayServer.Controllers [Route("currencies")] public async Task GetCurrencyList(string storeId) { - if (!TryGetChangellyClient(storeId, out var actionResult, out var client)) - { - return actionResult; - } - try { + + var client = await TryGetChangellyClient(storeId); + return Ok(await client.GetCurrenciesFull()); } catch (Exception e) @@ -52,26 +50,16 @@ namespace BTCPayServer.Controllers public async Task CalculateAmount(string storeId, string fromCurrency, string toCurrency, decimal toCurrencyAmount) { - if (!TryGetChangellyClient(storeId, out var actionResult, out var client)) - { - return actionResult; - } - - - if (fromCurrency.Equals("usd", StringComparison.InvariantCultureIgnoreCase) - || fromCurrency.Equals("eur", StringComparison.InvariantCultureIgnoreCase)) - { - var store = HttpContext.GetStoreData(); - var rules = store.GetStoreBlob().GetRateRules(_btcPayNetworkProvider); - var rate = await _RateProviderFactory.FetchRate(new CurrencyPair(toCurrency, fromCurrency), rules); - if (rate.BidAsk == null) return BadRequest(); - var flatRate = rate.BidAsk.Center; - return Ok(flatRate * toCurrencyAmount); - } - - try { + var client = await TryGetChangellyClient(storeId); + + if (fromCurrency.Equals("usd", StringComparison.InvariantCultureIgnoreCase) + || fromCurrency.Equals("eur", StringComparison.InvariantCultureIgnoreCase)) + { + return await HandleCalculateFiatAmount(fromCurrency, toCurrency, toCurrencyAmount); + } + var callCounter = 0; var response1 = await client.GetExchangeAmount(fromCurrency, toCurrency, 1); var currentAmount = response1; @@ -105,21 +93,25 @@ namespace BTCPayServer.Controllers } } - private bool TryGetChangellyClient(string storeId, out IActionResult actionResult, - out Changelly changelly) + private async Task TryGetChangellyClient(string storeId) { - changelly = null; - actionResult = null; - storeId = storeId ?? HttpContext.GetStoreData()?.Id; - - if (_changellyClientProvider.TryGetChangellyClient(storeId, out var error, out changelly)) - return true; - actionResult = BadRequest(new BitpayErrorModel() - { - Error = error - }); - return false; + var store = IsTest? null: HttpContext.GetStoreData(); + storeId = storeId ?? store?.Id; + return await _changellyClientProvider.TryGetChangellyClient(storeId, store); } + + private async Task HandleCalculateFiatAmount(string fromCurrency, string toCurrency, + decimal toCurrencyAmount) + { + var store = HttpContext.GetStoreData(); + var rules = store.GetStoreBlob().GetRateRules(_btcPayNetworkProvider); + var rate = await _RateProviderFactory.FetchRate(new CurrencyPair(toCurrency, fromCurrency), rules); + if (rate.BidAsk == null) return BadRequest(); + var flatRate = rate.BidAsk.Center; + return Ok(flatRate * toCurrencyAmount); + } + + public bool IsTest { get; set; } = false; } } diff --git a/BTCPayServer/Payments/Changelly/ChangellyClientProvider.cs b/BTCPayServer/Payments/Changelly/ChangellyClientProvider.cs index f42ca8c38..a65cd85d4 100644 --- a/BTCPayServer/Payments/Changelly/ChangellyClientProvider.cs +++ b/BTCPayServer/Payments/Changelly/ChangellyClientProvider.cs @@ -1,6 +1,8 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Net.Http; +using System.Threading.Tasks; +using BTCPayServer.Data; using BTCPayServer.Services.Stores; using NBitcoin; @@ -29,47 +31,40 @@ namespace BTCPayServer.Payments.Changelly } - public virtual bool TryGetChangellyClient(string storeId, out string error, - out Changelly changelly) + public virtual async Task TryGetChangellyClient(string storeId, StoreData storeData = null) { if (_clientCache.ContainsKey(storeId)) { - changelly = _clientCache[storeId]; - error = null; - return true; + return _clientCache[storeId]; } - changelly = null; - - - var store = _storeRepository.FindStore(storeId).Result; - if (store == null) + if (storeData == null) { - error = "Store not found"; - return false; + storeData = await _storeRepository.FindStore(storeId); + if (storeData == null) + { + throw new ChangellyException("Store not found"); + } } - var blob = store.GetStoreBlob(); + var blob = storeData.GetStoreBlob(); var changellySettings = blob.ChangellySettings; if (changellySettings == null || !changellySettings.IsConfigured()) { - error = "Changelly not configured for this store"; - return false; + throw new ChangellyException("Changelly not configured for this store"); } if (!changellySettings.Enabled) { - error = "Changelly not enabled for this store"; - return false; + throw new ChangellyException("Changelly not enabled for this store"); } - changelly = new Changelly(_httpClientFactory, changellySettings.ApiKey, changellySettings.ApiSecret, + var changelly = new Changelly(_httpClientFactory, changellySettings.ApiKey, changellySettings.ApiSecret, changellySettings.ApiUrl, changellySettings.ShowFiat); _clientCache.AddOrReplace(storeId, changelly); - error = null; - return true; + return changelly; } } } diff --git a/BTCPayServer/Views/Stores/UpdateChangellySettings.cshtml b/BTCPayServer/Views/Stores/UpdateChangellySettings.cshtml index 7b0ab6e51..67c02c53a 100644 --- a/BTCPayServer/Views/Stores/UpdateChangellySettings.cshtml +++ b/BTCPayServer/Views/Stores/UpdateChangellySettings.cshtml @@ -11,6 +11,12 @@
+

+ You can obtain API keys at + + Changelly.com + +

@@ -25,17 +31,17 @@ -
+
-
+
-
+