Cache resolved store items in HTTP context

This commit is contained in:
Dennis Reimann 2021-12-16 17:37:19 +01:00 committed by Andrew Camilleri
parent 38ff3e5e89
commit 3a59e2a5c4
13 changed files with 273 additions and 231 deletions

View File

@ -615,10 +615,11 @@ namespace BTCPayServer.Tests
vm.AppName = "test";
vm.SelectedAppType = AppType.PointOfSale.ToString();
Assert.IsType<RedirectToActionResult>(apps.CreateApp(user.StoreId, vm).Result);
var appId = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model)
.Apps[0].Id;
var appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
var app = appList.Apps[0];
apps.HttpContext.SetAppData(new AppData { Id = app.Id, StoreDataId = app.StoreId, Name = app.AppName });
var vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
.IsType<ViewResult>(apps.UpdatePointOfSale(app.Id)).Model);
vmpos.Title = "hello";
vmpos.Currency = "CAD";
vmpos.ButtonText = "{0} Purchase";
@ -635,15 +636,15 @@ donation:
price: 1.02
custom: true
";
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result);
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(app.Id, vmpos).Result);
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
.IsType<ViewResult>(apps.UpdatePointOfSale(app.Id)).Model);
Assert.Equal("hello", vmpos.Title);
var publicApps = user.GetController<AppsPublicController>();
var vmview =
Assert.IsType<ViewPointOfSaleViewModel>(Assert
.IsType<ViewResult>(publicApps.ViewPointOfSale(appId, PosViewType.Cart).Result).Model);
.IsType<ViewResult>(publicApps.ViewPointOfSale(app.Id, PosViewType.Cart).Result).Model);
Assert.Equal("hello", vmview.Title);
Assert.Equal(3, vmview.Items.Length);
Assert.Equal("good apple", vmview.Items[0].Title);
@ -655,7 +656,7 @@ donation:
Assert.Equal("Wanna tip?", vmview.CustomTipText);
Assert.Equal("15,18,20", string.Join(',', vmview.CustomTipPercentages));
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(appId, PosViewType.Cart, 0, null, null, null, null, "orange").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, null, null, null, null, "orange").Result);
//
var invoices = await user.BitPay.GetInvoicesAsync();
@ -664,7 +665,7 @@ donation:
Assert.Equal("CAD", orangeInvoice.Currency);
Assert.Equal("orange", orangeInvoice.ItemDesc);
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(appId, PosViewType.Cart, 0, null, null, null, null, "apple").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, null, null, null, null, "apple").Result);
invoices = user.BitPay.GetInvoices();
var appleInvoice = invoices.SingleOrDefault(invoice => invoice.ItemCode.Equals("apple"));
@ -673,7 +674,7 @@ donation:
// testing custom amount
var action = Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(appId, PosViewType.Cart, 6.6m, null, null, null, null, "donation").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 6.6m, null, null, null, null, "donation").Result);
Assert.Equal(nameof(InvoiceController.Checkout), action.ActionName);
invoices = user.BitPay.GetInvoices();
var donationInvoice = invoices.Single(i => i.Price == 6.6m);
@ -695,7 +696,7 @@ donation:
{
TestLogs.LogInformation($"Testing for {test.Code}");
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
.IsType<ViewResult>(apps.UpdatePointOfSale(app.Id)).Model);
vmpos.Title = "hello";
vmpos.Currency = test.Item1;
vmpos.ButtonText = "{0} Purchase";
@ -711,10 +712,10 @@ donation:
price: 1.02
custom: true
";
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result);
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(app.Id, vmpos).Result);
publicApps = user.GetController<AppsPublicController>();
vmview = Assert.IsType<ViewPointOfSaleViewModel>(Assert
.IsType<ViewResult>(publicApps.ViewPointOfSale(appId, PosViewType.Cart).Result).Model);
.IsType<ViewResult>(publicApps.ViewPointOfSale(app.Id, PosViewType.Cart).Result).Model);
Assert.Equal(test.Code, vmview.CurrencyCode);
Assert.Equal(test.ExpectedSymbol,
vmview.CurrencySymbol.Replace("¥", "¥")); // Hack so JPY test pass on linux as well);
@ -727,11 +728,10 @@ donation:
Assert.Equal(test.ExpectedDivisibility, vmview.CurrencyInfo.Divisibility);
Assert.Equal(test.ExpectedSymbolSpace, vmview.CurrencyInfo.SymbolSpace);
}
//test inventory related features
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
.IsType<ViewResult>(apps.UpdatePointOfSale(app.Id)).Model);
vmpos.Title = "hello";
vmpos.Currency = "BTC";
vmpos.Template = @"
@ -741,26 +741,26 @@ inventoryitem:
inventory: 1
noninventoryitem:
price: 10.0";
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result);
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(app.Id, vmpos).Result);
//inventoryitem has 1 item available
await tester.WaitForEvent<AppInventoryUpdaterHostedService.UpdateAppInventory>(() =>
{
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(appId, PosViewType.Cart, 1, null, null, null, null, "inventoryitem").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, null, null, null, null, "inventoryitem").Result);
return Task.CompletedTask;
});
//we already bought all available stock so this should fail
await Task.Delay(100);
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(appId, PosViewType.Cart, 1, null, null, null, null, "inventoryitem").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, null, null, null, null, "inventoryitem").Result);
//inventoryitem has unlimited items available
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(appId, PosViewType.Cart, 1, null, null, null, null, "noninventoryitem").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, null, null, null, null, "noninventoryitem").Result);
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(appId, PosViewType.Cart, 1, null, null, null, null, "noninventoryitem").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, null, null, null, null, "noninventoryitem").Result);
//verify invoices where created
invoices = user.BitPay.GetInvoices();
@ -778,14 +778,14 @@ noninventoryitem:
TestUtils.Eventually(() =>
{
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
.IsType<ViewResult>(apps.UpdatePointOfSale(app.Id)).Model);
Assert.Equal(1,
appService.Parse(vmpos.Template, "BTC").Single(item => item.Id == "inventoryitem").Inventory);
}, 10000);
//test payment methods option
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
.IsType<ViewResult>(apps.UpdatePointOfSale(app.Id)).Model);
vmpos.Title = "hello";
vmpos.Currency = "BTC";
vmpos.Template = @"
@ -796,11 +796,11 @@ btconly:
- BTC
normal:
price: 1.0";
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result);
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(app.Id, vmpos).Result);
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(appId, PosViewType.Cart, 1, null, null, null, null, "btconly").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, null, null, null, null, "btconly").Result);
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(appId, PosViewType.Cart, 1, null, null, null, null, "normal").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, null, null, null, null, "normal").Result);
invoices = user.BitPay.GetInvoices();
var normalInvoice = invoices.Single(invoice => invoice.ItemCode == "normal");
var btcOnlyInvoice = invoices.Single(invoice => invoice.ItemCode == "btconly");
@ -840,9 +840,9 @@ g:
custom: topup
";
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result);
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(app.Id, vmpos).Result);
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
.IsType<ViewResult>(await apps.UpdatePointOfSale(appId)).Model);
.IsType<ViewResult>(apps.UpdatePointOfSale(app.Id)).Model);
Assert.DoesNotContain("custom", vmpos.Template);
var items = appService.Parse(vmpos.Template, vmpos.Currency);
Assert.Contains(items, item => item.Id == "a" && item.Price.Type == ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Fixed);
@ -854,7 +854,7 @@ g:
Assert.Contains(items, item => item.Id == "g" && item.Price.Type == ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Topup);
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(appId, PosViewType.Static, null, null, null, null, null, "g").Result);
.ViewPointOfSale(app.Id, PosViewType.Static, null, null, null, null, null, "g").Result);
invoices = user.BitPay.GetInvoices();
var topupInvoice = invoices.Single(invoice => invoice.ItemCode == "g");
Assert.Equal(0, topupInvoice.Price);

View File

@ -2,6 +2,7 @@ using System;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
using BTCPayServer.Controllers;
using BTCPayServer.Data;
using BTCPayServer.Models.AppViewModels;
using BTCPayServer.Services.Apps;
using BTCPayServer.Services.Invoices;
@ -42,6 +43,8 @@ namespace BTCPayServer.Tests
var redirectToAction = Assert.IsType<RedirectToActionResult>(apps.CreateApp(user.StoreId, vm).Result);
Assert.Equal(nameof(apps.UpdateCrowdfund), redirectToAction.ActionName);
var appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
var app = appList.Apps[0];
apps.HttpContext.SetAppData(new AppData { Id = app.Id, StoreDataId = app.StoreId, Name = app.AppName });
var appList2 =
Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps2.ListApps(user2.StoreId).Result).Model);
Assert.Single(appList.Apps);
@ -50,8 +53,8 @@ namespace BTCPayServer.Tests
Assert.Equal(apps.CreatedAppId, appList.Apps[0].Id);
Assert.True(appList.Apps[0].IsOwner);
Assert.Equal(user.StoreId, appList.Apps[0].StoreId);
Assert.IsType<NotFoundResult>(apps2.DeleteApp(appList.Apps[0].Id).Result);
Assert.IsType<ViewResult>(apps.DeleteApp(appList.Apps[0].Id).Result);
Assert.IsType<NotFoundResult>(apps2.DeleteApp(appList.Apps[0].Id));
Assert.IsType<ViewResult>(apps.DeleteApp(appList.Apps[0].Id));
redirectToAction = Assert.IsType<RedirectToActionResult>(apps.DeleteAppPost(appList.Apps[0].Id).Result);
Assert.Equal(nameof(apps.ListApps), redirectToAction.ActionName);
appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
@ -74,43 +77,44 @@ namespace BTCPayServer.Tests
vm.AppName = "test";
vm.SelectedAppType = AppType.Crowdfund.ToString();
Assert.IsType<RedirectToActionResult>(apps.CreateApp(user.StoreId, vm).Result);
var appId = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model)
.Apps[0].Id;
var appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
var app = appList.Apps[0];
apps.HttpContext.SetAppData(new AppData { Id = app.Id, StoreDataId = app.StoreId, Name = app.AppName });
//Scenario 1: Not Enabled - Not Allowed
var crowdfundViewModel = Assert.IsType<UpdateCrowdfundViewModel>(Assert
.IsType<ViewResult>(apps.UpdateCrowdfund(appId).Result).Model);
.IsType<ViewResult>(apps.UpdateCrowdfund(app.Id)).Model);
crowdfundViewModel.TargetCurrency = "BTC";
crowdfundViewModel.Enabled = false;
crowdfundViewModel.EndDate = null;
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(appId, crowdfundViewModel, "save").Result);
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(app.Id, crowdfundViewModel, "save").Result);
var anonAppPubsController = tester.PayTester.GetController<AppsPublicController>();
var publicApps = user.GetController<AppsPublicController>();
Assert.IsType<NotFoundObjectResult>(await anonAppPubsController.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
Assert.IsType<NotFoundObjectResult>(await anonAppPubsController.ContributeToCrowdfund(app.Id, new ContributeToCrowdfund()
{
Amount = new decimal(0.01)
}, default));
Assert.IsType<NotFoundResult>(await anonAppPubsController.ViewCrowdfund(appId, string.Empty));
Assert.IsType<NotFoundResult>(await anonAppPubsController.ViewCrowdfund(app.Id, string.Empty));
//Scenario 2: Not Enabled But Admin - Allowed
Assert.IsType<OkObjectResult>(await publicApps.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
Assert.IsType<OkObjectResult>(await publicApps.ContributeToCrowdfund(app.Id, new ContributeToCrowdfund()
{
RedirectToCheckout = false,
Amount = new decimal(0.01)
}, default));
Assert.IsType<ViewResult>(await publicApps.ViewCrowdfund(appId, string.Empty));
Assert.IsType<NotFoundResult>(await anonAppPubsController.ViewCrowdfund(appId, string.Empty));
Assert.IsType<ViewResult>(await publicApps.ViewCrowdfund(app.Id, string.Empty));
Assert.IsType<NotFoundResult>(await anonAppPubsController.ViewCrowdfund(app.Id, 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, "save").Result);
Assert.IsType<NotFoundObjectResult>(await anonAppPubsController.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(app.Id, crowdfundViewModel, "save").Result);
Assert.IsType<NotFoundObjectResult>(await anonAppPubsController.ContributeToCrowdfund(app.Id, new ContributeToCrowdfund()
{
Amount = new decimal(0.01)
}, default));
@ -120,8 +124,8 @@ namespace BTCPayServer.Tests
crowdfundViewModel.EndDate = DateTime.Today.AddDays(-1);
crowdfundViewModel.Enabled = true;
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(appId, crowdfundViewModel, "save").Result);
Assert.IsType<NotFoundObjectResult>(await anonAppPubsController.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(app.Id, crowdfundViewModel, "save").Result);
Assert.IsType<NotFoundObjectResult>(await anonAppPubsController.ContributeToCrowdfund(app.Id, new ContributeToCrowdfund()
{
Amount = new decimal(0.01)
}, default));
@ -133,14 +137,14 @@ namespace BTCPayServer.Tests
crowdfundViewModel.TargetAmount = 1;
crowdfundViewModel.TargetCurrency = "BTC";
crowdfundViewModel.EnforceTargetAmount = true;
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(appId, crowdfundViewModel, "save").Result);
Assert.IsType<NotFoundObjectResult>(await anonAppPubsController.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(app.Id, crowdfundViewModel, "save").Result);
Assert.IsType<NotFoundObjectResult>(await anonAppPubsController.ContributeToCrowdfund(app.Id, new ContributeToCrowdfund()
{
Amount = new decimal(1.01)
}, default));
//Scenario 6: Allowed
Assert.IsType<OkObjectResult>(await anonAppPubsController.ContributeToCrowdfund(appId, new ContributeToCrowdfund()
Assert.IsType<OkObjectResult>(await anonAppPubsController.ContributeToCrowdfund(app.Id, new ContributeToCrowdfund()
{
Amount = new decimal(0.05)
}, default));
@ -163,25 +167,26 @@ namespace BTCPayServer.Tests
vm.AppName = "test";
vm.SelectedAppType = AppType.Crowdfund.ToString();
Assert.IsType<RedirectToActionResult>(apps.CreateApp(user.StoreId, vm).Result);
var appId = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model)
.Apps[0].Id;
var appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
var app = appList.Apps[0];
apps.HttpContext.SetAppData(new AppData { Id = app.Id, StoreDataId = app.StoreId, Name = app.AppName });
TestLogs.LogInformation("We create an invoice with a hardcap");
var crowdfundViewModel = Assert.IsType<UpdateCrowdfundViewModel>(Assert
.IsType<ViewResult>(apps.UpdateCrowdfund(appId).Result).Model);
.IsType<ViewResult>(apps.UpdateCrowdfund(app.Id)).Model);
crowdfundViewModel.Enabled = true;
crowdfundViewModel.EndDate = null;
crowdfundViewModel.TargetAmount = 100;
crowdfundViewModel.TargetCurrency = "BTC";
crowdfundViewModel.UseAllStoreInvoices = true;
crowdfundViewModel.EnforceTargetAmount = true;
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(appId, crowdfundViewModel, "save").Result);
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(app.Id, crowdfundViewModel, "save").Result);
var anonAppPubsController = tester.PayTester.GetController<AppsPublicController>();
var publicApps = user.GetController<AppsPublicController>();
var model = Assert.IsType<ViewCrowdfundViewModel>(Assert
.IsType<ViewResult>(publicApps.ViewCrowdfund(appId, String.Empty).Result).Model);
.IsType<ViewResult>(publicApps.ViewCrowdfund(app.Id, String.Empty).Result).Model);
Assert.Equal(crowdfundViewModel.TargetAmount, model.TargetAmount);
Assert.Equal(crowdfundViewModel.EndDate, model.EndDate);
@ -205,7 +210,7 @@ namespace BTCPayServer.Tests
}, Facade.Merchant);
model = Assert.IsType<ViewCrowdfundViewModel>(Assert
.IsType<ViewResult>(publicApps.ViewCrowdfund(appId, string.Empty).Result).Model);
.IsType<ViewResult>(publicApps.ViewCrowdfund(app.Id, string.Empty).Result).Model);
Assert.Equal(0m, model.Info.CurrentAmount);
Assert.Equal(1m, model.Info.CurrentPendingAmount);
@ -219,7 +224,7 @@ namespace BTCPayServer.Tests
TestUtils.Eventually(() =>
{
model = Assert.IsType<ViewCrowdfundViewModel>(Assert
.IsType<ViewResult>(publicApps.ViewCrowdfund(appId, String.Empty).Result).Model);
.IsType<ViewResult>(publicApps.ViewCrowdfund(app.Id, String.Empty).Result).Model);
Assert.Equal(1m, model.Info.CurrentAmount);
Assert.Equal(0m, model.Info.CurrentPendingAmount);
});
@ -227,10 +232,10 @@ namespace BTCPayServer.Tests
TestLogs.LogInformation("Because UseAllStoreInvoices is true, let's make sure the invoice is tagged");
var invoiceEntity = tester.PayTester.InvoiceRepository.GetInvoice(invoice.Id).GetAwaiter().GetResult();
Assert.True(invoiceEntity.Version >= InvoiceEntity.InternalTagSupport_Version);
Assert.Contains(AppService.GetAppInternalTag(appId), invoiceEntity.InternalTags);
Assert.Contains(AppService.GetAppInternalTag(app.Id), invoiceEntity.InternalTags);
crowdfundViewModel.UseAllStoreInvoices = false;
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(appId, crowdfundViewModel, "save").Result);
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(app.Id, crowdfundViewModel, "save").Result);
TestLogs.LogInformation("Because UseAllStoreInvoices is false, let's make sure the invoice is not tagged");
invoice = await user.BitPay.CreateInvoiceAsync(new Invoice
@ -244,12 +249,12 @@ namespace BTCPayServer.Tests
FullNotifications = true
}, Facade.Merchant);
invoiceEntity = tester.PayTester.InvoiceRepository.GetInvoice(invoice.Id).GetAwaiter().GetResult();
Assert.DoesNotContain(AppService.GetAppInternalTag(appId), invoiceEntity.InternalTags);
Assert.DoesNotContain(AppService.GetAppInternalTag(app.Id), invoiceEntity.InternalTags);
TestLogs.LogInformation("After turning setting a softcap, let's check that only actual payments are counted");
crowdfundViewModel.EnforceTargetAmount = false;
crowdfundViewModel.UseAllStoreInvoices = true;
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(appId, crowdfundViewModel, "save").Result);
Assert.IsType<RedirectToActionResult>(apps.UpdateCrowdfund(app.Id, crowdfundViewModel, "save").Result);
invoice = await user.BitPay.CreateInvoiceAsync(new Invoice
{
Buyer = new Buyer { email = "test@fwf.com" },
@ -267,7 +272,7 @@ namespace BTCPayServer.Tests
TestUtils.Eventually(() =>
{
model = Assert.IsType<ViewCrowdfundViewModel>(Assert
.IsType<ViewResult>(publicApps.ViewCrowdfund(appId, string.Empty).Result).Model);
.IsType<ViewResult>(publicApps.ViewCrowdfund(app.Id, string.Empty).Result).Model);
Assert.Equal(0.7m, model.Info.CurrentPendingAmount);
});
}

View File

@ -1,5 +1,6 @@
using System.Threading.Tasks;
using BTCPayServer.Controllers;
using BTCPayServer.Data;
using BTCPayServer.Models.AppViewModels;
using BTCPayServer.Services.Apps;
using BTCPayServer.Tests.Logging;
@ -32,10 +33,11 @@ namespace BTCPayServer.Tests
vm.AppName = "test";
vm.SelectedAppType = AppType.PointOfSale.ToString();
Assert.IsType<RedirectToActionResult>(apps.CreateApp(user.StoreId, vm).Result);
var appId = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model)
.Apps[0].Id;
var appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
var app = appList.Apps[0];
apps.HttpContext.SetAppData(new AppData { Id = app.Id, StoreDataId = app.StoreId, Name = app.AppName });
var vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
.IsType<ViewResult>(apps.UpdatePointOfSale(app.Id)).Model);
vmpos.Template = @"
apple:
price: 5.0
@ -47,13 +49,13 @@ donation:
price: 1.02
custom: true
";
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result);
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(app.Id, vmpos).Result);
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
.IsType<ViewResult>(apps.UpdatePointOfSale(app.Id)).Model);
var publicApps = user.GetController<AppsPublicController>();
var vmview =
Assert.IsType<ViewPointOfSaleViewModel>(Assert
.IsType<ViewResult>(publicApps.ViewPointOfSale(appId, PosViewType.Cart).Result).Model);
.IsType<ViewResult>(publicApps.ViewPointOfSale(app.Id, PosViewType.Cart).Result).Model);
// apple shouldn't be available since we it's set to "disabled: true" above
Assert.Equal(2, vmview.Items.Length);
@ -61,10 +63,10 @@ donation:
Assert.Equal("donation", vmview.Items[1].Title);
// orange is available
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(appId, PosViewType.Cart, 0, null, null, null, null, "orange").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, null, null, null, null, "orange").Result);
// apple is not found
Assert.IsType<NotFoundResult>(publicApps
.ViewPointOfSale(appId, PosViewType.Cart, 0, null, null, null, null, "apple").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, null, null, null, null, "apple").Result);
}
}
}

View File

@ -2,6 +2,7 @@ using System;
using System.Linq;
using System.Threading.Tasks;
using BTCPayServer.Controllers;
using BTCPayServer.Data;
using BTCPayServer.Models.PaymentRequestViewModels;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.PaymentRequests;
@ -49,9 +50,11 @@ namespace BTCPayServer.Tests
.IsType<RedirectToActionResult>(await paymentRequestController.EditPaymentRequest(null, request))
.RouteValues.Values.Last().ToString();
paymentRequestController.HttpContext.SetPaymentRequestData(new PaymentRequestData { Id = id, StoreDataId = request.StoreId });
// Permission guard for guests editing
Assert
.IsType<NotFoundResult>(await guestpaymentRequestController.EditPaymentRequest(user.StoreId, id));
.IsType<NotFoundResult>(guestpaymentRequestController.EditPaymentRequest(user.StoreId, id));
request.Title = "update";
Assert.IsType<RedirectToActionResult>(await paymentRequestController.EditPaymentRequest(id, request));

View File

@ -2040,14 +2040,16 @@ namespace BTCPayServer.Tests
var appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
var appList2 =
Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps2.ListApps(user2.StoreId).Result).Model);
var app = appList.Apps[0];
apps.HttpContext.SetAppData(new AppData { Id = app.Id, StoreDataId = app.StoreId, Name = app.AppName });
Assert.Single(appList.Apps);
Assert.Empty(appList2.Apps);
Assert.Equal("test", appList.Apps[0].AppName);
Assert.Equal(apps.CreatedAppId, appList.Apps[0].Id);
Assert.True(appList.Apps[0].IsOwner);
Assert.True(app.IsOwner);
Assert.Equal(user.StoreId, appList.Apps[0].StoreId);
Assert.IsType<NotFoundResult>(apps2.DeleteApp(appList.Apps[0].Id).Result);
Assert.IsType<ViewResult>(apps.DeleteApp(appList.Apps[0].Id).Result);
Assert.IsType<NotFoundResult>(apps2.DeleteApp(appList.Apps[0].Id));
Assert.IsType<ViewResult>(apps.DeleteApp(appList.Apps[0].Id));
redirectToAction = Assert.IsType<RedirectToActionResult>(apps.DeleteAppPost(appList.Apps[0].Id).Result);
Assert.Equal(nameof(apps.ListApps), redirectToAction.ActionName);
appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);

View File

@ -25,18 +25,18 @@ namespace BTCPayServer.Controllers
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[HttpGet("{appId}/settings/crowdfund")]
public async Task<IActionResult> UpdateCrowdfund(string appId)
public IActionResult UpdateCrowdfund(string appId)
{
var app = await GetOwnedApp(appId, AppType.Crowdfund);
if (app == null)
if (CurrentApp == null)
return NotFound();
var settings = app.GetSettings<CrowdfundSettings>();
var settings = CurrentApp.GetSettings<CrowdfundSettings>();
var vm = new UpdateCrowdfundViewModel
{
Title = settings.Title,
StoreId = app.StoreDataId,
StoreName = app.StoreData?.StoreName,
AppName = app.Name,
StoreId = CurrentApp.StoreDataId,
StoreName = CurrentApp.StoreData?.StoreName,
AppName = CurrentApp.Name,
Enabled = settings.Enabled,
EnforceTargetAmount = settings.EnforceTargetAmount,
StartDate = settings.StartDate,
@ -56,9 +56,9 @@ namespace BTCPayServer.Controllers
AnimationsEnabled = settings.AnimationsEnabled,
ResetEveryAmount = settings.ResetEveryAmount,
ResetEvery = Enum.GetName(typeof(CrowdfundResetEvery), settings.ResetEvery),
UseAllStoreInvoices = app.TagAllInvoices,
UseAllStoreInvoices = CurrentApp.TagAllInvoices,
AppId = appId,
SearchTerm = app.TagAllInvoices ? $"storeid:{app.StoreDataId}" : $"orderid:{AppService.GetCrowdfundOrderId(appId)}",
SearchTerm = CurrentApp.TagAllInvoices ? $"storeid:{CurrentApp.StoreDataId}" : $"orderid:{AppService.GetCrowdfundOrderId(appId)}",
DisplayPerksRanking = settings.DisplayPerksRanking,
DisplayPerksValue = settings.DisplayPerksValue,
SortPerksByPopularity = settings.SortPerksByPopularity,
@ -71,10 +71,10 @@ namespace BTCPayServer.Controllers
[HttpPost("{appId}/settings/crowdfund")]
public async Task<IActionResult> UpdateCrowdfund(string appId, UpdateCrowdfundViewModel vm, string command)
{
var app = await GetOwnedApp(appId, AppType.Crowdfund);
if (app == null)
if (CurrentApp == null)
return NotFound();
vm.TargetCurrency = await GetStoreDefaultCurrentIfEmpty(app.StoreDataId, vm.TargetCurrency);
vm.TargetCurrency = await GetStoreDefaultCurrentIfEmpty(CurrentApp.StoreDataId, vm.TargetCurrency);
if (_currencies.GetCurrencyData(vm.TargetCurrency, false) == null)
ModelState.AddModelError(nameof(vm.TargetCurrency), "Invalid currency");
@ -125,8 +125,8 @@ namespace BTCPayServer.Controllers
return View(vm);
}
app.Name = vm.AppName;
var newSettings = new CrowdfundSettings()
CurrentApp.Name = vm.AppName;
var newSettings = new CrowdfundSettings
{
Title = vm.Title,
Enabled = vm.Enabled,
@ -155,15 +155,15 @@ namespace BTCPayServer.Controllers
AnimationColors = parsedAnimationColors
};
app.TagAllInvoices = vm.UseAllStoreInvoices;
app.SetSettings(newSettings);
CurrentApp.TagAllInvoices = vm.UseAllStoreInvoices;
CurrentApp.SetSettings(newSettings);
await _appService.UpdateOrCreateApp(app);
await _appService.UpdateOrCreateApp(CurrentApp);
_eventAggregator.Publish(new AppUpdated()
{
AppId = appId,
StoreId = app.StoreDataId,
StoreId = CurrentApp.StoreDataId,
Settings = newSettings
});
TempData[WellKnownTempData.SuccessMessage] = "App updated";

View File

@ -75,8 +75,7 @@ namespace BTCPayServer.Controllers
public string CustomTipText { get; set; } = CUSTOM_TIP_TEXT_DEF;
public static readonly int[] CUSTOM_TIP_PERCENTAGES_DEF = new int[] { 15, 18, 20 };
public int[] CustomTipPercentages { get; set; } = CUSTOM_TIP_PERCENTAGES_DEF;
public string CustomCSSLink { get; set; }
public string EmbeddedCSS { get; set; }
@ -88,21 +87,20 @@ namespace BTCPayServer.Controllers
}
[HttpGet("{appId}/settings/pos")]
public async Task<IActionResult> UpdatePointOfSale(string appId)
public IActionResult UpdatePointOfSale(string appId)
{
var app = await GetOwnedApp(appId, AppType.PointOfSale);
if (app == null)
if (CurrentApp == null)
return NotFound();
var settings = app.GetSettings<PointOfSaleSettings>();
var settings = CurrentApp.GetSettings<PointOfSaleSettings>();
settings.DefaultView = settings.EnableShoppingCart ? PosViewType.Cart : settings.DefaultView;
settings.EnableShoppingCart = false;
var vm = new UpdatePointOfSaleViewModel
{
Id = appId,
StoreId = app.StoreDataId,
StoreName = app.StoreData?.StoreName,
AppName = app.Name,
StoreId = CurrentApp.StoreDataId,
StoreName = CurrentApp.StoreData?.StoreName,
AppName = CurrentApp.Name,
Title = settings.Title,
DefaultView = settings.DefaultView,
ShowCustomAmount = settings.ShowCustomAmount,
@ -119,7 +117,7 @@ namespace BTCPayServer.Controllers
Description = settings.Description,
NotificationUrl = settings.NotificationUrl,
RedirectUrl = settings.RedirectUrl,
SearchTerm = $"storeid:{app.StoreDataId}",
SearchTerm = $"storeid:{CurrentApp.StoreDataId}",
RedirectAutomatically = settings.RedirectAutomatically.HasValue ? settings.RedirectAutomatically.Value ? "true" : "false" : "",
RequiresRefundEmail = settings.RequiresRefundEmail
};
@ -164,14 +162,13 @@ namespace BTCPayServer.Controllers
[HttpPost("{appId}/settings/pos")]
public async Task<IActionResult> UpdatePointOfSale(string appId, UpdatePointOfSaleViewModel vm)
{
var app = await GetOwnedApp(appId, AppType.PointOfSale);
if (app == null)
if (CurrentApp == null)
return NotFound();
if (!ModelState.IsValid)
{
return View(vm);
}
vm.Currency = await GetStoreDefaultCurrentIfEmpty(app.StoreDataId, vm.Currency);
vm.Currency = await GetStoreDefaultCurrentIfEmpty(CurrentApp.StoreDataId, vm.Currency);
if (_currencies.GetCurrencyData(vm.Currency, false) == null)
ModelState.AddModelError(nameof(vm.Currency), "Invalid currency");
try
@ -187,8 +184,8 @@ namespace BTCPayServer.Controllers
return View(vm);
}
app.Name = vm.AppName;
app.SetSettings(new PointOfSaleSettings
CurrentApp.Name = vm.AppName;
CurrentApp.SetSettings(new PointOfSaleSettings
{
Title = vm.Title,
DefaultView = vm.DefaultView,
@ -209,7 +206,7 @@ namespace BTCPayServer.Controllers
RedirectAutomatically = string.IsNullOrEmpty(vm.RedirectAutomatically) ? (bool?)null : bool.Parse(vm.RedirectAutomatically),
RequiresRefundEmail = vm.RequiresRefundEmail,
});
await _appService.UpdateOrCreateApp(app);
await _appService.UpdateOrCreateApp(CurrentApp);
TempData[WellKnownTempData.SuccessMessage] = "App updated";
return RedirectToAction(nameof(UpdatePointOfSale), new { appId });
}
@ -220,14 +217,12 @@ namespace BTCPayServer.Controllers
{
return Array.Empty<int>();
}
else
{
// Remove all characters except numeric and comma
Regex charsToDestroy = new Regex(@"[^\d|\" + separator + "]");
list = charsToDestroy.Replace(list, "");
// Remove all characters except numeric and comma
Regex charsToDestroy = new Regex(@"[^\d|\" + separator + "]");
list = charsToDestroy.Replace(list, "");
return list.Split(separator, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
}
return list.Split(separator, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
}
}
}

View File

@ -144,23 +144,24 @@ namespace BTCPayServer.Controllers
}
[HttpGet("{appId}/delete")]
public async Task<IActionResult> DeleteApp(string appId)
public IActionResult DeleteApp(string appId)
{
var appData = await GetOwnedApp(appId);
if (appData == null)
if (CurrentApp == null)
return NotFound();
return View("Confirm", new ConfirmModel("Delete app", $"The app <strong>{appData.Name}</strong> and its settings will be permanently deleted. Are you sure?", "Delete"));
return View("Confirm", new ConfirmModel("Delete app", $"The app <strong>{CurrentApp.Name}</strong> and its settings will be permanently deleted. Are you sure?", "Delete"));
}
[HttpPost("{appId}/delete")]
public async Task<IActionResult> DeleteAppPost(string appId)
{
var appData = await GetOwnedApp(appId);
if (appData == null)
if (CurrentApp == null)
return NotFound();
if (await _appService.DeleteApp(appData))
if (await _appService.DeleteApp(CurrentApp))
TempData[WellKnownTempData.SuccessMessage] = "App deleted successfully.";
return RedirectToAction(nameof(ListApps), new { storeId = appData.StoreDataId });
return RedirectToAction(nameof(ListApps), new { storeId = CurrentApp.StoreDataId });
}
async Task<string> GetStoreDefaultCurrentIfEmpty(string storeId, string currency)
@ -172,11 +173,6 @@ namespace BTCPayServer.Controllers
return currency.Trim().ToUpperInvariant();
}
private Task<AppData> GetOwnedApp(string appId, AppType? type = null)
{
return _appService.GetAppDataIfOwner(GetUserId(), appId, type);
}
private string GetUserId()
{
return _userManager.GetUserId(User);
@ -186,5 +182,10 @@ namespace BTCPayServer.Controllers
{
get => HttpContext.GetStoreData();
}
private AppData CurrentApp
{
get => HttpContext.GetAppData();
}
}
}

View File

@ -41,7 +41,7 @@ namespace BTCPayServer.Controllers
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
public async Task<IActionResult> WebhookDelivery(string invoiceId, string deliveryId)
{
var invoice = (await _InvoiceRepository.GetInvoices(new InvoiceQuery()
var invoice = (await _InvoiceRepository.GetInvoices(new InvoiceQuery
{
InvoiceId = new[] { invoiceId },
UserId = GetUserId()
@ -223,19 +223,15 @@ namespace BTCPayServer.Controllers
public async Task<IActionResult> Refund(string invoiceId, RefundModel model, CancellationToken cancellationToken)
{
using var ctx = _dbContextFactory.CreateContext();
var invoice = await _InvoiceRepository.GetInvoice(invoiceId);
if (invoice is null)
return NotFound();
var store = await _StoreRepository.FindStore(invoice.StoreId, GetUserId());
if (store is null)
if (CurrentInvoice == null)
return NotFound();
if (!CanRefund(invoice.GetInvoiceState()))
if (!CanRefund(CurrentInvoice.GetInvoiceState()))
return NotFound();
var paymentMethodId = PaymentMethodId.Parse(model.SelectedPaymentMethod);
var cdCurrency = _CurrencyNameTable.GetCurrencyData(invoice.Currency, true);
var cdCurrency = _CurrencyNameTable.GetCurrencyData(CurrentInvoice.Currency, true);
var paymentMethodDivisibility = _CurrencyNameTable.GetCurrencyData(paymentMethodId.CryptoCode, false)?.Divisibility ?? 8;
RateRules rules;
RateResult rateResult;
@ -245,7 +241,7 @@ namespace BTCPayServer.Controllers
case RefundSteps.SelectPaymentMethod:
model.RefundStep = RefundSteps.SelectRate;
model.Title = "What to refund?";
var pms = invoice.GetPaymentMethods();
var pms = CurrentInvoice.GetPaymentMethods();
var paymentMethod = pms.SingleOrDefault(method => method.GetId() == paymentMethodId);
//TODO: Make this clean
@ -257,15 +253,13 @@ namespace BTCPayServer.Controllers
if (paymentMethod != null)
{
var cryptoPaid = paymentMethod.Calculate().Paid.ToDecimal(MoneyUnit.BTC);
var paidCurrency =
Math.Round(cryptoPaid * paymentMethod.Rate,
cdCurrency.Divisibility);
var paidCurrency = Math.Round(cryptoPaid * paymentMethod.Rate, cdCurrency.Divisibility);
model.CryptoAmountThen = cryptoPaid.RoundToSignificant(paymentMethodDivisibility);
model.RateThenText =
_CurrencyNameTable.DisplayFormatCurrency(model.CryptoAmountThen, paymentMethodId.CryptoCode);
rules = store.GetStoreBlob().GetRateRules(_NetworkProvider);
rules = CurrentStore.GetStoreBlob().GetRateRules(_NetworkProvider);
rateResult = await _RateProvider.FetchRate(
new Rating.CurrencyPair(paymentMethodId.CryptoCode, invoice.Currency), rules,
new CurrencyPair(paymentMethodId.CryptoCode, CurrentInvoice.Currency), rules,
cancellationToken);
//TODO: What if fetching rate failed?
if (rateResult.BidAsk is null)
@ -281,14 +275,15 @@ namespace BTCPayServer.Controllers
model.FiatAmount = paidCurrency;
}
model.FiatText = _CurrencyNameTable.DisplayFormatCurrency(model.FiatAmount, invoice.Currency);
model.FiatText = _CurrencyNameTable.DisplayFormatCurrency(model.FiatAmount, CurrentInvoice.Currency);
return View(model);
case RefundSteps.SelectRate:
createPullPayment = new HostedServices.CreatePullPayment();
createPullPayment.Name = $"Refund {invoice.Id}";
createPullPayment.PaymentMethodIds = new[] { paymentMethodId };
createPullPayment.StoreId = invoice.StoreId;
switch (model.SelectedRefundOption)
createPullPayment = new CreatePullPayment
{
Name = $"Refund {CurrentInvoice.Id}", PaymentMethodIds = new[] { paymentMethodId },
StoreId = CurrentInvoice.StoreId
};
switch (model.SelectedRefundOption)
{
case "RateThen":
createPullPayment.Currency = paymentMethodId.CryptoCode;
@ -299,12 +294,12 @@ namespace BTCPayServer.Controllers
createPullPayment.Amount = model.CryptoAmountNow;
break;
case "Fiat":
createPullPayment.Currency = invoice.Currency;
createPullPayment.Currency = CurrentInvoice.Currency;
createPullPayment.Amount = model.FiatAmount;
break;
case "Custom":
model.Title = "How much to refund?";
model.CustomCurrency = invoice.Currency;
model.CustomCurrency = CurrentInvoice.Currency;
model.CustomAmount = model.FiatAmount;
model.RefundStep = RefundSteps.SelectCustomAmount;
return View(model);
@ -330,7 +325,7 @@ namespace BTCPayServer.Controllers
{
return View(model);
}
rules = store.GetStoreBlob().GetRateRules(_NetworkProvider);
rules = CurrentStore.GetStoreBlob().GetRateRules(_NetworkProvider);
rateResult = await _RateProvider.FetchRate(
new CurrencyPair(paymentMethodId.CryptoCode, model.CustomCurrency), rules,
cancellationToken);
@ -342,12 +337,13 @@ namespace BTCPayServer.Controllers
return View(model);
}
createPullPayment = new CreatePullPayment();
createPullPayment.Name = $"Refund {invoice.Id}";
createPullPayment.PaymentMethodIds = new[] { paymentMethodId };
createPullPayment.StoreId = invoice.StoreId;
createPullPayment.Currency = model.CustomCurrency;
createPullPayment.Amount = model.CustomAmount;
createPullPayment = new CreatePullPayment
{
Name = $"Refund {CurrentInvoice.Id}", PaymentMethodIds = new[] { paymentMethodId },
StoreId = CurrentInvoice.StoreId,
Currency = model.CustomCurrency,
Amount = model.CustomAmount
};
break;
default:
throw new ArgumentOutOfRangeException();
@ -359,10 +355,10 @@ namespace BTCPayServer.Controllers
Html = "Refund successfully created!<br />Share the link to this page with a customer.<br />The customer needs to enter their address and claim the refund.<br />Once a customer claims the refund, you will get a notification and would need to approve and initiate it from your Store > Payouts.",
Severity = StatusMessageModel.StatusSeverity.Success
});
(await ctx.Invoices.FindAsync(new[] { invoice.Id }, cancellationToken)).CurrentRefundId = ppId;
(await ctx.Invoices.FindAsync(new[] { CurrentInvoice.Id }, cancellationToken)).CurrentRefundId = ppId;
ctx.Refunds.Add(new RefundData()
{
InvoiceDataId = invoice.Id,
InvoiceDataId = CurrentInvoice.Id,
PullPaymentDataId = ppId
});
await ctx.SaveChangesAsync(cancellationToken);
@ -407,7 +403,7 @@ namespace BTCPayServer.Controllers
[BitpayAPIConstraint(false)]
public async Task<IActionResult> ToggleArchive(string invoiceId)
{
var invoice = (await _InvoiceRepository.GetInvoices(new InvoiceQuery()
var invoice = (await _InvoiceRepository.GetInvoices(new InvoiceQuery
{
InvoiceId = new[] { invoiceId },
UserId = GetUserId(),
@ -949,7 +945,7 @@ namespace BTCPayServer.Controllers
[BitpayAPIConstraint(false)]
public async Task<IActionResult> ChangeInvoiceState(string invoiceId, string newState)
{
var invoice = (await _InvoiceRepository.GetInvoices(new InvoiceQuery()
var invoice = (await _InvoiceRepository.GetInvoices(new InvoiceQuery
{
InvoiceId = new[] { invoiceId },
UserId = GetUserId()
@ -980,6 +976,16 @@ namespace BTCPayServer.Controllers
public string? StatusString { get; set; }
}
private StoreData CurrentStore
{
get => HttpContext.GetStoreData();
}
private InvoiceEntity CurrentInvoice
{
get => HttpContext.GetInvoiceData();
}
private string GetUserId()
{
return _UserManager.GetUserId(User);

View File

@ -29,7 +29,6 @@ namespace BTCPayServer.Controllers
{
private readonly InvoiceController _InvoiceController;
private readonly UserManager<ApplicationUser> _UserManager;
private readonly StoreRepository _StoreRepository;
private readonly PaymentRequestRepository _PaymentRequestRepository;
private readonly PaymentRequestService _PaymentRequestService;
private readonly EventAggregator _EventAggregator;
@ -40,7 +39,6 @@ namespace BTCPayServer.Controllers
public PaymentRequestController(
InvoiceController invoiceController,
UserManager<ApplicationUser> userManager,
StoreRepository storeRepository,
PaymentRequestRepository paymentRequestRepository,
PaymentRequestService paymentRequestService,
EventAggregator eventAggregator,
@ -50,7 +48,6 @@ namespace BTCPayServer.Controllers
{
_InvoiceController = invoiceController;
_UserManager = userManager;
_StoreRepository = storeRepository;
_PaymentRequestRepository = paymentRequestRepository;
_PaymentRequestService = paymentRequestService;
_EventAggregator = eventAggregator;
@ -81,15 +78,14 @@ namespace BTCPayServer.Controllers
}
[HttpGet("/stores/{storeId}/payment-requests/edit/{payReqId?}")]
public async Task<IActionResult> EditPaymentRequest(string storeId, string payReqId)
public IActionResult EditPaymentRequest(string storeId, string payReqId)
{
var data = await _PaymentRequestRepository.FindPaymentRequest(payReqId, GetUserId());
if (data == null && !string.IsNullOrEmpty(payReqId))
if (CurrentPaymentRequest == null && !string.IsNullOrEmpty(payReqId))
{
return NotFound();
}
return View(nameof(EditPaymentRequest), new UpdatePaymentRequestViewModel(data)
return View(nameof(EditPaymentRequest), new UpdatePaymentRequestViewModel(CurrentPaymentRequest)
{
StoreId = CurrentStore.Id
});
@ -102,13 +98,12 @@ namespace BTCPayServer.Controllers
_Currencies.GetCurrencyData(viewModel.Currency, false) == null)
ModelState.AddModelError(nameof(viewModel.Currency), "Invalid currency");
var data = await _PaymentRequestRepository.FindPaymentRequest(payReqId, GetUserId());
if (data == null && !string.IsNullOrEmpty(payReqId))
if (CurrentPaymentRequest == null && !string.IsNullOrEmpty(payReqId))
{
return NotFound();
}
if (data?.Archived is true && viewModel.Archived is true)
if (CurrentPaymentRequest?.Archived is true && viewModel.Archived)
{
ModelState.AddModelError(string.Empty, "You cannot edit an archived payment request.");
}
@ -118,15 +113,11 @@ namespace BTCPayServer.Controllers
return View(nameof(EditPaymentRequest), viewModel);
}
if (data == null)
{
data = new PaymentRequestData();
}
var data = CurrentPaymentRequest ?? new PaymentRequestData();
data.StoreDataId = viewModel.StoreId;
data.Archived = viewModel.Archived;
var blob = data.GetBlob();
blob.Title = viewModel.Title;
blob.Email = viewModel.Email;
blob.Description = viewModel.Description;
@ -310,9 +301,9 @@ namespace BTCPayServer.Controllers
}
[HttpGet("{payReqId}/clone")]
public async Task<IActionResult> ClonePaymentRequest(string payReqId)
public IActionResult ClonePaymentRequest(string payReqId)
{
var result = await EditPaymentRequest(CurrentStore.Id, payReqId);
var result = EditPaymentRequest(CurrentStore.Id, payReqId);
if (result is ViewResult viewResult)
{
var model = (UpdatePaymentRequestViewModel)viewResult.Model;
@ -329,7 +320,7 @@ namespace BTCPayServer.Controllers
[HttpGet("{payReqId}/archive")]
public async Task<IActionResult> TogglePaymentRequestArchival(string payReqId)
{
var result = await EditPaymentRequest(CurrentStore.Id, payReqId);
var result = EditPaymentRequest(CurrentStore.Id, payReqId);
if (result is ViewResult viewResult)
{
var model = (UpdatePaymentRequestViewModel)viewResult.Model;
@ -353,5 +344,10 @@ namespace BTCPayServer.Controllers
{
get => HttpContext.GetStoreData();
}
private PaymentRequestData CurrentPaymentRequest
{
get => HttpContext.GetPaymentRequestData();
}
}
}

View File

@ -415,6 +415,7 @@ namespace BTCPayServer
{
return ctx.Items.TryGet("BTCPAY.STOREDATA") as StoreData;
}
public static void SetStoreData(this HttpContext ctx, StoreData storeData)
{
ctx.Items["BTCPAY.STOREDATA"] = storeData;
@ -429,9 +430,39 @@ namespace BTCPayServer
ctx.Items["BTCPAY.STORESDATA"] = storeData;
}
public static InvoiceEntity GetInvoiceData(this HttpContext ctx)
{
return ctx.Items.TryGet("BTCPAY.INVOICEDATA") as InvoiceEntity;
}
public static void SetInvoiceData(this HttpContext ctx, InvoiceEntity invoiceEntity)
{
ctx.Items["BTCPAY.INVOICEDATA"] = invoiceEntity;
}
public static PaymentRequestData GetPaymentRequestData(this HttpContext ctx)
{
return ctx.Items.TryGet("BTCPAY.PAYMENTREQUESTDATA") as PaymentRequestData;
}
public static void SetPaymentRequestData(this HttpContext ctx, PaymentRequestData paymentRequestData)
{
ctx.Items["BTCPAY.PAYMENTREQUESTDATA"] = paymentRequestData;
}
public static AppData GetAppData(this HttpContext ctx)
{
return ctx.Items.TryGet("BTCPAY.APPDATA") as AppData;
}
public static void SetAppData(this HttpContext ctx, AppData appData)
{
ctx.Items["BTCPAY.APPDATA"] = appData;
}
public static IActionResult RedirectToRecoverySeedBackup(this Controller controller, RecoverySeedBackupViewModel vm)
{
var redirectVm = new PostRedirectViewModel()
var redirectVm = new PostRedirectViewModel
{
AspController = "Home",
AspAction = "RecoverySeedBackup",

View File

@ -5,6 +5,7 @@ using BTCPayServer.Data;
using BTCPayServer.PaymentRequest;
using BTCPayServer.Services.Apps;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.PaymentRequests;
using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
@ -15,11 +16,11 @@ namespace BTCPayServer.Security
{
public class CookieAuthorizationHandler : AuthorizationHandler<PolicyRequirement>
{
private readonly HttpContext _HttpContext;
private readonly HttpContext _httpContext;
private readonly UserManager<ApplicationUser> _userManager;
private readonly StoreRepository _storeRepository;
private readonly AppService _appService;
private readonly PaymentRequestService _paymentRequestService;
private readonly PaymentRequestRepository _paymentRequestRepository;
private readonly InvoiceRepository _invoiceRepository;
public CookieAuthorizationHandler(IHttpContextAccessor httpContextAccessor,
@ -27,14 +28,14 @@ namespace BTCPayServer.Security
StoreRepository storeRepository,
AppService appService,
InvoiceRepository invoiceRepository,
PaymentRequestService paymentRequestService)
PaymentRequestRepository paymentRequestRepository)
{
_HttpContext = httpContextAccessor.HttpContext;
_httpContext = httpContextAccessor.HttpContext;
_userManager = userManager;
_appService = appService;
_storeRepository = storeRepository;
_invoiceRepository = invoiceRepository;
_paymentRequestService = paymentRequestService;
_paymentRequestRepository = paymentRequestRepository;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PolicyRequirement requirement)
{
@ -49,48 +50,48 @@ namespace BTCPayServer.Security
context.Succeed(requirement);
return;
}
string storeId = context.Resource is string s ? s : _HttpContext.GetImplicitStoreId();
if (storeId == null)
{
var routeData = _HttpContext.GetRouteData();
if (routeData != null)
{
// resolve from app
if (routeData.Values.TryGetValue("appId", out var vAppId))
{
string appId = vAppId as string;
var app = await _appService.GetApp(appId, null);
storeId = app?.StoreDataId;
}
// resolve from payment request
else if (routeData.Values.TryGetValue("payReqId", out var vPayReqId))
{
string payReqId = vPayReqId as string;
var paymentRequest = await _paymentRequestService.GetPaymentRequest(payReqId);
storeId = paymentRequest?.StoreId;
}
// resolve from app
if (routeData.Values.TryGetValue("invoiceId", out var vInvoiceId))
{
string invoiceId = vInvoiceId as string;
var invoice = await _invoiceRepository.GetInvoice(invoiceId);
storeId = invoice?.StoreId;
}
}
// store could not be found
if (storeId == null)
{
return;
}
}
var userid = _userManager.GetUserId(context.User);
if (string.IsNullOrEmpty(userid))
var userId = _userManager.GetUserId(context.User);
if (string.IsNullOrEmpty(userId))
return;
var store = await _storeRepository.FindStore(storeId, userid);
AppData app = null;
InvoiceEntity invoice = null;
PaymentRequestData paymentRequest = null;
string storeId = context.Resource is string s ? s : _httpContext.GetImplicitStoreId();
var routeData = _httpContext.GetRouteData();
if (routeData != null)
{
// resolve from app
if (routeData.Values.TryGetValue("appId", out var vAppId))
{
string appId = vAppId as string;
app = await _appService.GetApp(appId, null);
storeId ??= app?.StoreDataId;
}
// resolve from payment request
if (routeData.Values.TryGetValue("payReqId", out var vPayReqId))
{
string payReqId = vPayReqId as string;
paymentRequest = await _paymentRequestRepository.FindPaymentRequest(payReqId, userId);
storeId ??= paymentRequest?.StoreDataId;
}
// resolve from invoice
if (routeData.Values.TryGetValue("invoiceId", out var vInvoiceId))
{
string invoiceId = vInvoiceId as string;
invoice = await _invoiceRepository.GetInvoice(invoiceId);
storeId ??= invoice?.StoreId;
}
}
// store could not be found
if (storeId == null)
{
return;
}
var store = await _storeRepository.FindStore(storeId, userId);
bool success = false;
switch (requirement.Policy)
@ -112,8 +113,12 @@ namespace BTCPayServer.Security
if (success)
{
context.Succeed(requirement);
_HttpContext.SetStoreData(store);
return;
_httpContext.SetStoreData(store);
// cache associated entities if present
if (app != null) _httpContext.SetAppData(app);
if (invoice != null) _httpContext.SetInvoiceData(invoice);
if (paymentRequest != null) _httpContext.SetPaymentRequestData(paymentRequest);
}
}
}

View File

@ -13,17 +13,13 @@ namespace BTCPayServer.Services.PaymentRequests
{
private readonly ApplicationDbContextFactory _ContextFactory;
private readonly InvoiceRepository _InvoiceRepository;
private readonly StoreRepository _storeRepository;
public PaymentRequestRepository(ApplicationDbContextFactory contextFactory, InvoiceRepository invoiceRepository,
StoreRepository storeRepository)
public PaymentRequestRepository(ApplicationDbContextFactory contextFactory, InvoiceRepository invoiceRepository)
{
_ContextFactory = contextFactory;
_InvoiceRepository = invoiceRepository;
_storeRepository = storeRepository;
}
public async Task<PaymentRequestData> CreateOrUpdatePaymentRequest(PaymentRequestData entity)
{
using (var context = _ContextFactory.CreateContext())