bug fixes and optimizations

This commit is contained in:
Kukks 2019-01-05 19:47:39 +01:00
parent fb6d852827
commit 6e7f1151bc
8 changed files with 190 additions and 127 deletions

View file

@ -2,9 +2,12 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Controllers;
using BTCPayServer.Data;
using BTCPayServer.Events;
using BTCPayServer.Hubs;
using BTCPayServer.Models;
using BTCPayServer.Models.AppViewModels;
using BTCPayServer.Models.StoreViewModels;
@ -51,7 +54,7 @@ namespace BTCPayServer.Tests
vm.Name = "test";
vm.SelectedAppType = AppType.Crowdfund.ToString();
var redirectToAction = Assert.IsType<RedirectToActionResult>(apps.CreateApp(vm).Result);
Assert.Equal(nameof(apps.UpdatePointOfSale), redirectToAction.ActionName);
Assert.Equal(nameof(apps.UpdateCrowdfund), redirectToAction.ActionName);
var appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps().Result).Model);
var appList2 =
Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps2.ListApps().Result).Model);
@ -93,6 +96,7 @@ namespace BTCPayServer.Tests
//Scenario 1: Not Enabled - Not Allowed
var crowdfundViewModel = Assert.IsType<UpdateCrowdfundViewModel>(Assert
.IsType<ViewResult>(apps.UpdateCrowdfund(appId).Result).Model);
crowdfundViewModel.TargetCurrency = "BTC";
crowdfundViewModel.Enabled = false;
crowdfundViewModel.EndDate = null;
@ -115,14 +119,15 @@ namespace BTCPayServer.Tests
RedirectToCheckout = false,
Amount = new decimal(0.01)
}));
Assert.IsType<NotFoundResult>(await publicApps.ViewCrowdfund(appId, string.Empty));
Assert.IsType<ViewResult>(await publicApps.ViewCrowdfund(appId, string.Empty));
Assert.IsType<NotFoundResult>(await anonAppPubsController.ViewCrowdfund(appId, string.Empty));
//Scenario 3: Enabled But Start Date > Now - Not Allowed
crowdfundViewModel.StartDate= DateTime.Today.AddDays(2);
crowdfundViewModel.Enabled = true;
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(appId, crowdfundViewModel).Result);
Assert.IsType<NotFoundResult>(await anonAppPubsController.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
Assert.IsType<NotFoundObjectResult>(await anonAppPubsController.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
{
Amount = new decimal(0.01)
}));
@ -134,7 +139,7 @@ namespace BTCPayServer.Tests
crowdfundViewModel.Enabled = true;
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(appId, crowdfundViewModel).Result);
Assert.IsType<NotFoundResult>(await anonAppPubsController.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
Assert.IsType<NotFoundObjectResult>(await anonAppPubsController.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
{
Amount = new decimal(0.01)
}));
@ -148,13 +153,13 @@ namespace BTCPayServer.Tests
crowdfundViewModel.TargetCurrency = "BTC";
crowdfundViewModel.EnforceTargetAmount = true;
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(appId, crowdfundViewModel).Result);
Assert.IsType<NotFoundResult>(await anonAppPubsController.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
Assert.IsType<NotFoundObjectResult>(await anonAppPubsController.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
{
Amount = new decimal(1.01)
}));
//Scenario 6: Allowed
Assert.IsType<NotFoundResult>(await anonAppPubsController.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
Assert.IsType<OkObjectResult>(await anonAppPubsController.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
{
Amount = new decimal(0.05)
}));
@ -164,7 +169,7 @@ namespace BTCPayServer.Tests
[Fact]
[Trait("Integration", "Integration")]
public async Task CanComputeCrowdfundModel()
public void CanComputeCrowdfundModel()
{
using (var tester = ServerTester.Create())
{
@ -200,9 +205,10 @@ namespace BTCPayServer.Tests
Assert.Equal(crowdfundViewModel.EndDate, model.EndDate );
Assert.Equal(crowdfundViewModel.StartDate, model.StartDate );
Assert.Equal(crowdfundViewModel.TargetCurrency, model.TargetCurrency );
Assert.Equal(model.Info.CurrentAmount, 0m);
Assert.Equal(model.Info.CurrentPendingAmount, 0m);
Assert.Equal(model.Info.ProgressPercentage, 0m);
Assert.Equal(0m, model.Info.CurrentAmount );
Assert.Equal(0m, model.Info.CurrentPendingAmount);
Assert.Equal(0m, model.Info.ProgressPercentage);
var invoice = user.BitPay.CreateInvoice(new Invoice()
@ -211,8 +217,9 @@ namespace BTCPayServer.Tests
Price = 1m,
Currency = "BTC",
PosData = "posData",
OrderId = "orderId",
OrderId = $"{CrowdfundHubStreamer.CrowdfundInvoiceOrderIdPrefix}{appId}",
ItemDesc = "Some description",
TransactionSpeed = "high",
FullNotifications = true
}, Facade.Merchant);
@ -221,27 +228,18 @@ namespace BTCPayServer.Tests
.IsType<ViewResult>(publicApps.ViewCrowdfund(appId, String.Empty).Result).Model);
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, tester.ExplorerNode.Network);
Assert.Equal(model.Info.CurrentAmount, 0m);
Assert.Equal(model.Info.CurrentPendingAmount, 1m);
Assert.Equal(model.Info.ProgressPercentage, 0m);
Assert.Equal(model.Info.PendingProgressPercentage, 1m);
tester.ExplorerNode.SendToAddress(invoiceAddress,invoice.BtcDue);
Assert.Equal(0m ,model.Info.CurrentAmount );
Assert.Equal(1m, model.Info.CurrentPendingAmount);
Assert.Equal( 0m, model.Info.ProgressPercentage);
Assert.Equal(1m, model.Info.PendingProgressPercentage);
UnitTest1.Eventually(() =>
{
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
Assert.Equal(InvoiceState.ToString(InvoiceStatus.Complete), localInvoice.Status);
});
model = Assert.IsType<ViewCrowdfundViewModel>(Assert
.IsType<ViewResult>(publicApps.ViewCrowdfund(appId, String.Empty).Result).Model);
Assert.Equal(model.Info.CurrentAmount, 1m);
Assert.Equal(model.Info.CurrentPendingAmount, 0m);
Assert.Equal(model.Info.ProgressPercentage, 1m);
Assert.Equal(model.Info.PendingProgressPercentage, 0m);
}

View file

@ -326,7 +326,7 @@ namespace BTCPayServer.Tests
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, tester.ExplorerNode.Network);
tester.ExplorerNode.SendToAddress(invoiceAddress, Money.Satoshis((decimal)invoice.BtcDue.Satoshi * 0.75m));
Eventually(() =>
TestUtils.Eventually(() =>
{
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
Assert.Equal("paid", localInvoice.Status);
@ -448,7 +448,7 @@ namespace BTCPayServer.Tests
});
await Task.Delay(TimeSpan.FromMilliseconds(1000)); // Give time to listen the new invoices
await tester.SendLightningPaymentAsync(invoice);
await EventuallyAsync(async () =>
await TestUtils.EventuallyAsync(async () =>
{
var localInvoice = await user.BitPay.GetInvoiceAsync(invoice.Id);
Assert.Equal("complete", localInvoice.Status);
@ -651,7 +651,7 @@ namespace BTCPayServer.Tests
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, cashCow.Network);
var firstPayment = invoice.CryptoInfo[0].TotalDue - Money.Satoshis(10);
cashCow.SendToAddress(invoiceAddress, firstPayment);
Eventually(() =>
TestUtils.Eventually(() =>
{
invoice = acc.BitPay.GetInvoice(invoice.Id);
Assert.Equal(firstPayment, invoice.CryptoInfo[0].Paid);
@ -747,7 +747,7 @@ namespace BTCPayServer.Tests
var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, user.SupportedNetwork.NBitcoinNetwork);
Logs.Tester.LogInformation($"The invoice should be paidOver");
Eventually(() =>
TestUtils.Eventually(() =>
{
invoice = user.BitPay.GetInvoice(invoice.Id);
Assert.Equal(payment1, invoice.BtcPaid);
@ -776,7 +776,7 @@ namespace BTCPayServer.Tests
Assert.Equal(tx2, ((NewTransactionEvent)listener.NextEvent(cts.Token)).TransactionData.TransactionHash);
}
Logs.Tester.LogInformation($"The invoice should now not be paidOver anymore");
Eventually(() =>
TestUtils.Eventually(() =>
{
invoice = user.BitPay.GetInvoice(invoice.Id);
Assert.Equal(payment2, invoice.BtcPaid);
@ -1023,7 +1023,7 @@ namespace BTCPayServer.Tests
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, cashCow.Network);
var firstPayment = Money.Coins(0.1m);
cashCow.SendToAddress(invoiceAddress, firstPayment);
Eventually(() =>
TestUtils.Eventually(() =>
{
invoice = user.BitPay.GetInvoice(invoice.Id);
Assert.Equal(firstPayment, invoice.CryptoInfo[0].Paid);
@ -1044,7 +1044,7 @@ namespace BTCPayServer.Tests
Assert.NotEqual(invoice.BtcDue, invoice.CryptoInfo[0].Due); // Should be BTC rate
cashCow.SendToAddress(invoiceAddress, invoice.CryptoInfo[0].Due);
Eventually(() =>
TestUtils.Eventually(() =>
{
invoice = user.BitPay.GetInvoice(invoice.Id);
Assert.Equal("paid", invoice.Status);
@ -1142,7 +1142,7 @@ namespace BTCPayServer.Tests
var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network);
var firstPayment = Money.Coins(0.04m);
cashCow.SendToAddress(invoiceAddress, firstPayment);
Eventually(() =>
TestUtils.Eventually(() =>
{
invoice = user.BitPay.GetInvoice(invoice.Id);
Assert.True(invoice.BtcPaid == firstPayment);
@ -1184,7 +1184,7 @@ namespace BTCPayServer.Tests
firstPayment = Money.Coins(0.04m);
cashCow.SendToAddress(invoiceAddress, firstPayment);
Logs.Tester.LogInformation("First payment sent to " + invoiceAddress);
Eventually(() =>
TestUtils.Eventually(() =>
{
invoice = user.BitPay.GetInvoice(invoice.Id);
Assert.True(invoice.BtcPaid == firstPayment);
@ -1198,7 +1198,7 @@ namespace BTCPayServer.Tests
cashCow.Generate(2); // LTC is not worth a lot, so just to make sure we have money...
cashCow.SendToAddress(invoiceAddress, secondPayment);
Logs.Tester.LogInformation("Second payment sent to " + invoiceAddress);
Eventually(() =>
TestUtils.Eventually(() =>
{
invoice = user.BitPay.GetInvoice(invoice.Id);
Assert.Equal(Money.Zero, invoice.BtcDue);
@ -1632,7 +1632,7 @@ donation:
cashCow.SendToAddress(invoiceAddress, 4*networkFee);
Thread.Sleep(1000);
Eventually(() =>
TestUtils.Eventually(() =>
{
var jsonResultPaid = user.GetController<InvoiceController>().Export("json").GetAwaiter().GetResult();
var paidresult = Assert.IsType<ContentResult>(jsonResultPaid);
@ -1683,7 +1683,7 @@ donation:
var firstPayment = invoice.CryptoInfo[0].TotalDue - Money.Satoshis(10);
cashCow.SendToAddress(invoiceAddress, firstPayment);
Eventually(() =>
TestUtils.Eventually(() =>
{
var exportResultPaid = user.GetController<InvoiceController>().Export("csv").GetAwaiter().GetResult();
var paidresult = Assert.IsType<ContentResult>(exportResultPaid);
@ -1758,7 +1758,7 @@ donation:
Assert.Equal(0, invoice.CryptoInfo[0].TxCount);
Assert.True(invoice.MinerFees.ContainsKey("BTC"));
Assert.Contains(invoice.MinerFees["BTC"].SatoshiPerBytes, new[] { 100.0m, 20.0m });
Eventually(() =>
TestUtils.Eventually(() =>
{
var textSearchResult = tester.PayTester.InvoiceRepository.GetInvoices(new InvoiceQuery()
{
@ -1804,7 +1804,7 @@ donation:
Money secondPayment = Money.Zero;
Eventually(() =>
TestUtils.Eventually(() =>
{
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
Assert.Equal("new", localInvoice.Status);
@ -1827,7 +1827,7 @@ donation:
cashCow.SendToAddress(invoiceAddress, secondPayment);
Eventually(() =>
TestUtils.Eventually(() =>
{
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
Assert.Equal("paid", localInvoice.Status);
@ -1841,7 +1841,7 @@ donation:
cashCow.Generate(1); //The user has medium speed settings, so 1 conf is enough to be confirmed
Eventually(() =>
TestUtils.Eventually(() =>
{
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
Assert.Equal("confirmed", localInvoice.Status);
@ -1849,7 +1849,7 @@ donation:
cashCow.Generate(5); //Now should be complete
Eventually(() =>
TestUtils.Eventually(() =>
{
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
Assert.Equal("complete", localInvoice.Status);
@ -1871,7 +1871,7 @@ donation:
var txId = cashCow.SendToAddress(invoiceAddress, invoice.BtcDue + Money.Coins(1));
Eventually(() =>
TestUtils.Eventually(() =>
{
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
Assert.Equal("paid", localInvoice.Status);
@ -1888,7 +1888,7 @@ donation:
cashCow.Generate(1);
Eventually(() =>
TestUtils.Eventually(() =>
{
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
Assert.Equal("confirmed", localInvoice.Status);
@ -2078,36 +2078,39 @@ donation:
return ctx.AddressInvoices.FirstOrDefault(i => i.InvoiceDataId == invoice.Id && i.GetAddress() == h) != null;
}
public static void Eventually(Action act)
public static class TestUtils
{
CancellationTokenSource cts = new CancellationTokenSource(20000);
while (true)
public static void Eventually(Action act)
{
try
CancellationTokenSource cts = new CancellationTokenSource(20000);
while (true)
{
act();
break;
}
catch (XunitException) when (!cts.Token.IsCancellationRequested)
{
cts.Token.WaitHandle.WaitOne(500);
try
{
act();
break;
}
catch (XunitException) when (!cts.Token.IsCancellationRequested)
{
cts.Token.WaitHandle.WaitOne(500);
}
}
}
}
private async Task EventuallyAsync(Func<Task> act)
{
CancellationTokenSource cts = new CancellationTokenSource(20000);
while (true)
public static async Task EventuallyAsync(Func<Task> act)
{
try
CancellationTokenSource cts = new CancellationTokenSource(20000);
while (true)
{
await act();
break;
}
catch (XunitException) when (!cts.Token.IsCancellationRequested)
{
await Task.Delay(500);
try
{
await act();
break;
}
catch (XunitException) when (!cts.Token.IsCancellationRequested)
{
await Task.Delay(500);
}
}
}
}

View file

@ -11,6 +11,8 @@ namespace BTCPayServer.Controllers
public class CrowdfundAppUpdated
{
public string AppId { get; set; }
public CrowdfundSettings Settings { get; set; }
public string StoreId { get; set; }
}
public class CrowdfundSettings
@ -83,7 +85,7 @@ namespace BTCPayServer.Controllers
[Route("{appId}/settings/crowdfund")]
public async Task<IActionResult> UpdateCrowdfund(string appId, UpdateCrowdfundViewModel vm)
{
if (_AppsHelper.GetCurrencyData(vm.TargetCurrency, false) == null)
if (!string.IsNullOrEmpty( vm.TargetCurrency) && _AppsHelper.GetCurrencyData(vm.TargetCurrency, false) == null)
ModelState.AddModelError(nameof(vm.TargetCurrency), "Invalid currency");
try
@ -109,7 +111,8 @@ namespace BTCPayServer.Controllers
var app = await GetOwnedApp(appId, AppType.Crowdfund);
if (app == null)
return NotFound();
app.SetSettings(new CrowdfundSettings()
var newSettings = new CrowdfundSettings()
{
Title = vm.Title,
Enabled = vm.Enabled,
@ -133,11 +136,15 @@ namespace BTCPayServer.Controllers
ResetEvery = Enum.Parse<CrowdfundResetEvery>(vm.ResetEvery),
UseInvoiceAmount = vm.UseInvoiceAmount,
UseAllStoreInvoices = vm.UseAllStoreInvoices
});
};
app.SetSettings(newSettings);
await UpdateAppSettings(app);
_EventAggregator.Publish(new CrowdfundAppUpdated()
{
AppId = appId
AppId = appId,
StoreId = app.StoreDataId,
Settings = newSettings
});
StatusMessage = "App updated";
return RedirectToAction(nameof(ListApps));

View file

@ -47,7 +47,7 @@ namespace BTCPayServer.Controllers
public async Task<IActionResult> ListApps()
{
var apps = await GetAllApps();
var apps = await _AppsHelper.GetAllApps(GetUserId());
return View(new ListAppsViewModel()
{
Apps = apps
@ -61,7 +61,7 @@ namespace BTCPayServer.Controllers
var appData = await GetOwnedApp(appId);
if (appData == null)
return NotFound();
if (await DeleteApp(appData))
if (await _AppsHelper.DeleteApp(appData))
StatusMessage = "App removed successfully";
return RedirectToAction(nameof(ListApps));
}
@ -70,7 +70,7 @@ namespace BTCPayServer.Controllers
[Route("create")]
public async Task<IActionResult> CreateApp()
{
var stores = await GetOwnedStores();
var stores = await _AppsHelper.GetOwnedStores(GetUserId());
if (stores.Length == 0)
{
StatusMessage = "Error: You must have created at least one store";
@ -85,7 +85,7 @@ namespace BTCPayServer.Controllers
[Route("create")]
public async Task<IActionResult> CreateApp(CreateAppViewModel vm)
{
var stores = await GetOwnedStores();
var stores = await _AppsHelper.GetOwnedStores(GetUserId());
if (stores.Length == 0)
{
StatusMessage = "Error: You must own at least one store";
@ -153,50 +153,7 @@ namespace BTCPayServer.Controllers
return _AppsHelper.GetAppDataIfOwner(GetUserId(), appId, type);
}
private async Task<StoreData[]> GetOwnedStores()
{
var userId = GetUserId();
using (var ctx = _ContextFactory.CreateContext())
{
return await ctx.UserStore
.Where(us => us.ApplicationUserId == userId && us.Role == StoreRoles.Owner)
.Select(u => u.StoreData)
.ToArrayAsync();
}
}
private async Task<bool> DeleteApp(AppData appData)
{
using (var ctx = _ContextFactory.CreateContext())
{
ctx.Apps.Add(appData);
ctx.Entry<AppData>(appData).State = EntityState.Deleted;
return await ctx.SaveChangesAsync() == 1;
}
}
private async Task<ListAppsViewModel.ListAppViewModel[]> GetAllApps()
{
var userId = GetUserId();
using (var ctx = _ContextFactory.CreateContext())
{
return await ctx.UserStore
.Where(us => us.ApplicationUserId == userId)
.Join(ctx.Apps, us => us.StoreDataId, app => app.StoreDataId,
(us, app) =>
new ListAppsViewModel.ListAppViewModel()
{
IsOwner = us.Role == StoreRoles.Owner,
StoreId = us.StoreDataId,
StoreName = us.StoreData.StoreName,
AppName = app.Name,
AppType = app.AppType,
Id = app.Id
})
.ToArrayAsync();
}
}
private string GetUserId()
{
return _UserManager.GetUserId(User);

View file

@ -151,7 +151,7 @@ namespace BTCPayServer.Controllers
price = request.Amount;
}
if (isAdmin || (settings.EnforceTargetAmount && info.TargetAmount.HasValue && price >
if (!isAdmin && (settings.EnforceTargetAmount && info.TargetAmount.HasValue && price >
(info.TargetAmount - (info.Info.CurrentAmount + info.Info.CurrentPendingAmount))))
{
return NotFound("Contribution Amount is more than is currently allowed.");
@ -264,6 +264,49 @@ namespace BTCPayServer.Controllers
_Currencies = currencies;
}
public async Task<StoreData[]> GetOwnedStores(string userId)
{
using (var ctx = _ContextFactory.CreateContext())
{
return await ctx.UserStore
.Where(us => us.ApplicationUserId == userId && us.Role == StoreRoles.Owner)
.Select(u => u.StoreData)
.ToArrayAsync();
}
}
public async Task<bool> DeleteApp(AppData appData)
{
using (var ctx = _ContextFactory.CreateContext())
{
ctx.Apps.Add(appData);
ctx.Entry<AppData>(appData).State = EntityState.Deleted;
return await ctx.SaveChangesAsync() == 1;
}
}
public async Task<ListAppsViewModel.ListAppViewModel[]> GetAllApps(string userId, bool allowNoUser = false)
{
using (var ctx = _ContextFactory.CreateContext())
{
return await ctx.UserStore
.Where(us => (allowNoUser && string.IsNullOrEmpty(userId) ) || us.ApplicationUserId == userId)
.Join(ctx.Apps, us => us.StoreDataId, app => app.StoreDataId,
(us, app) =>
new ListAppsViewModel.ListAppViewModel()
{
IsOwner = us.Role == StoreRoles.Owner,
StoreId = us.StoreDataId,
StoreName = us.StoreData.StoreName,
AppName = app.Name,
AppType = app.AppType,
Id = app.Id
})
.ToArrayAsync();
}
}
public async Task<AppData> GetApp(string appId, AppType appType, bool includeStore = false)
{

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@ -15,6 +16,8 @@ using BTCPayServer.Services.Rates;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Primitives;
using NBitcoin;
using YamlDotNet.Core;
namespace BTCPayServer.Hubs
{
@ -28,6 +31,9 @@ namespace BTCPayServer.Hubs
private readonly RateFetcher _RateFetcher;
private readonly BTCPayNetworkProvider _BtcPayNetworkProvider;
private readonly InvoiceRepository _InvoiceRepository;
private readonly ConcurrentDictionary<string,(string appId, bool useAllStoreInvoices,bool useInvoiceAmount)> _QuickAppInvoiceLookup =
new ConcurrentDictionary<string, (string appId, bool useAllStoreInvoices, bool useInvoiceAmount)>();
public CrowdfundHubStreamer(EventAggregator eventAggregator,
IHubContext<CrowdfundHub> hubContext,
IMemoryCache memoryCache,
@ -43,9 +49,36 @@ namespace BTCPayServer.Hubs
_RateFetcher = rateFetcher;
_BtcPayNetworkProvider = btcPayNetworkProvider;
_InvoiceRepository = invoiceRepository;
#pragma warning disable 4014
InitLookup();
#pragma warning restore 4014
SubscribeToEvents();
}
private async Task InitLookup()
{
var apps = await _AppsHelper.GetAllApps(null, true);
apps = apps.Where(model => Enum.Parse<AppType>(model.AppType) == AppType.Crowdfund).ToArray();
var tasks = new List<Task>();
tasks.AddRange(apps.Select(app => Task.Run(async () =>
{
var fullApp = await _AppsHelper.GetApp(app.Id, AppType.Crowdfund, false);
var settings = fullApp.GetSettings<AppsController.CrowdfundSettings>();
UpdateLookup(app.Id, app.StoreId, settings);
})));
await Task.WhenAll(tasks);
}
private void UpdateLookup(string appId, string storeId, AppsController.CrowdfundSettings settings)
{
_QuickAppInvoiceLookup.AddOrReplace(storeId,
(
appId: appId,
useAllStoreInvoices: settings?.UseAllStoreInvoices ?? false,
useInvoiceAmount: settings?.UseInvoiceAmount ?? false
));
}
public Task<ViewCrowdfundViewModel> GetCrowdfundInfo(string appId)
{
return _MemoryCache.GetOrCreateAsync(GetCacheKey(appId), async entry =>
@ -80,6 +113,7 @@ namespace BTCPayServer.Hubs
_EventAggregator.Subscribe<InvoiceEvent>(OnInvoiceEvent);
_EventAggregator.Subscribe<AppsController.CrowdfundAppUpdated>(updated =>
{
UpdateLookup(updated.AppId, updated.StoreId, updated.Settings);
InvalidateCacheForApp(updated.AppId);
});
}
@ -95,12 +129,20 @@ namespace BTCPayServer.Hubs
{
return;
}
var appId = invoiceEvent.Invoice.OrderId.Replace(CrowdfundInvoiceOrderIdPrefix, "", StringComparison.InvariantCultureIgnoreCase);
if (!_QuickAppInvoiceLookup.TryGetValue(invoiceEvent.Invoice.StoreId, out var quickLookup) ||
(!quickLookup.useAllStoreInvoices &&
!invoiceEvent.Invoice.OrderId.Equals($"{CrowdfundInvoiceOrderIdPrefix}{quickLookup.appId}", StringComparison.InvariantCulture)
))
{
return;
}
switch (invoiceEvent.Name)
{
case InvoiceEvent.ReceivedPayment:
var data = invoiceEvent.Payment.GetCryptoPaymentData();
_HubContext.Clients.Group(appId).SendCoreAsync(CrowdfundHub.PaymentReceived, new object[]
_HubContext.Clients.Group(quickLookup.appId).SendCoreAsync(CrowdfundHub.PaymentReceived, new object[]
{
data.GetValue(),
invoiceEvent.Payment.GetCryptoCode(),
@ -108,10 +150,16 @@ namespace BTCPayServer.Hubs
invoiceEvent.Payment.GetPaymentMethodId().PaymentType)
} );
InvalidateCacheForApp(appId);
InvalidateCacheForApp(quickLookup.appId);
break;
case InvoiceEvent.Created:
if (quickLookup.useInvoiceAmount)
{
InvalidateCacheForApp(quickLookup.appId);
}
break;
case InvoiceEvent.Completed:
InvalidateCacheForApp(appId);
InvalidateCacheForApp(quickLookup.appId);
break;
}
}
@ -123,7 +171,7 @@ namespace BTCPayServer.Hubs
GetCrowdfundInfo(appId).ContinueWith(task =>
{
_HubContext.Clients.Group(appId).SendCoreAsync(CrowdfundHub.InfoUpdated, new object[]{ task.Result} );
}, TaskScheduler.Default);
}, TaskScheduler.Current);
}

View file

@ -40,6 +40,12 @@ namespace BTCPayServer.Models
//{"facade":"pos/invoice","data":{,}}
public class InvoiceResponse
{
[JsonIgnore]
public string StoreId
{
get; set;
}
//"url":"https://test.bitpay.com/invoice?id=9saCHtp1zyPcNoi3rDdBu8"
[JsonProperty("url")]
public string Url

View file

@ -344,6 +344,7 @@ namespace BTCPayServer.Services.Invoices
InvoiceResponse dto = new InvoiceResponse
{
Id = Id,
StoreId = StoreId,
OrderId = OrderId,
PosData = PosData,
CurrentTime = DateTimeOffset.UtcNow,