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

View File

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

View File

@@ -1,5 +1,6 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Controllers; using BTCPayServer.Controllers;
using BTCPayServer.Data;
using BTCPayServer.Models.AppViewModels; using BTCPayServer.Models.AppViewModels;
using BTCPayServer.Services.Apps; using BTCPayServer.Services.Apps;
using BTCPayServer.Tests.Logging; using BTCPayServer.Tests.Logging;
@@ -32,10 +33,11 @@ namespace BTCPayServer.Tests
vm.AppName = "test"; vm.AppName = "test";
vm.SelectedAppType = AppType.PointOfSale.ToString(); vm.SelectedAppType = AppType.PointOfSale.ToString();
Assert.IsType<RedirectToActionResult>(apps.CreateApp(user.StoreId, vm).Result); Assert.IsType<RedirectToActionResult>(apps.CreateApp(user.StoreId, vm).Result);
var appId = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model) var appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
.Apps[0].Id; 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 var vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model); .IsType<ViewResult>(apps.UpdatePointOfSale(app.Id)).Model);
vmpos.Template = @" vmpos.Template = @"
apple: apple:
price: 5.0 price: 5.0
@@ -47,13 +49,13 @@ donation:
price: 1.02 price: 1.02
custom: true custom: true
"; ";
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result); Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(app.Id, vmpos).Result);
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert 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 publicApps = user.GetController<AppsPublicController>();
var vmview = var vmview =
Assert.IsType<ViewPointOfSaleViewModel>(Assert 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 // apple shouldn't be available since we it's set to "disabled: true" above
Assert.Equal(2, vmview.Items.Length); Assert.Equal(2, vmview.Items.Length);
@@ -61,10 +63,10 @@ donation:
Assert.Equal("donation", vmview.Items[1].Title); Assert.Equal("donation", vmview.Items[1].Title);
// orange is available // orange is available
Assert.IsType<RedirectToActionResult>(publicApps 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 // apple is not found
Assert.IsType<NotFoundResult>(publicApps 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.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Controllers; using BTCPayServer.Controllers;
using BTCPayServer.Data;
using BTCPayServer.Models.PaymentRequestViewModels; using BTCPayServer.Models.PaymentRequestViewModels;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.PaymentRequests; using BTCPayServer.Services.PaymentRequests;
@@ -49,9 +50,11 @@ namespace BTCPayServer.Tests
.IsType<RedirectToActionResult>(await paymentRequestController.EditPaymentRequest(null, request)) .IsType<RedirectToActionResult>(await paymentRequestController.EditPaymentRequest(null, request))
.RouteValues.Values.Last().ToString(); .RouteValues.Values.Last().ToString();
paymentRequestController.HttpContext.SetPaymentRequestData(new PaymentRequestData { Id = id, StoreDataId = request.StoreId });
// Permission guard for guests editing // Permission guard for guests editing
Assert Assert
.IsType<NotFoundResult>(await guestpaymentRequestController.EditPaymentRequest(user.StoreId, id)); .IsType<NotFoundResult>(guestpaymentRequestController.EditPaymentRequest(user.StoreId, id));
request.Title = "update"; request.Title = "update";
Assert.IsType<RedirectToActionResult>(await paymentRequestController.EditPaymentRequest(id, request)); 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 appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
var appList2 = var appList2 =
Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps2.ListApps(user2.StoreId).Result).Model); 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.Single(appList.Apps);
Assert.Empty(appList2.Apps); Assert.Empty(appList2.Apps);
Assert.Equal("test", appList.Apps[0].AppName); Assert.Equal("test", appList.Apps[0].AppName);
Assert.Equal(apps.CreatedAppId, appList.Apps[0].Id); 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.Equal(user.StoreId, appList.Apps[0].StoreId);
Assert.IsType<NotFoundResult>(apps2.DeleteApp(appList.Apps[0].Id).Result); Assert.IsType<NotFoundResult>(apps2.DeleteApp(appList.Apps[0].Id));
Assert.IsType<ViewResult>(apps.DeleteApp(appList.Apps[0].Id).Result); Assert.IsType<ViewResult>(apps.DeleteApp(appList.Apps[0].Id));
redirectToAction = Assert.IsType<RedirectToActionResult>(apps.DeleteAppPost(appList.Apps[0].Id).Result); redirectToAction = Assert.IsType<RedirectToActionResult>(apps.DeleteAppPost(appList.Apps[0].Id).Result);
Assert.Equal(nameof(apps.ListApps), redirectToAction.ActionName); Assert.Equal(nameof(apps.ListApps), redirectToAction.ActionName);
appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model); 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)] [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[HttpGet("{appId}/settings/crowdfund")] [HttpGet("{appId}/settings/crowdfund")]
public async Task<IActionResult> UpdateCrowdfund(string appId) public IActionResult UpdateCrowdfund(string appId)
{ {
var app = await GetOwnedApp(appId, AppType.Crowdfund); if (CurrentApp == null)
if (app == null)
return NotFound(); return NotFound();
var settings = app.GetSettings<CrowdfundSettings>();
var settings = CurrentApp.GetSettings<CrowdfundSettings>();
var vm = new UpdateCrowdfundViewModel var vm = new UpdateCrowdfundViewModel
{ {
Title = settings.Title, Title = settings.Title,
StoreId = app.StoreDataId, StoreId = CurrentApp.StoreDataId,
StoreName = app.StoreData?.StoreName, StoreName = CurrentApp.StoreData?.StoreName,
AppName = app.Name, AppName = CurrentApp.Name,
Enabled = settings.Enabled, Enabled = settings.Enabled,
EnforceTargetAmount = settings.EnforceTargetAmount, EnforceTargetAmount = settings.EnforceTargetAmount,
StartDate = settings.StartDate, StartDate = settings.StartDate,
@@ -56,9 +56,9 @@ namespace BTCPayServer.Controllers
AnimationsEnabled = settings.AnimationsEnabled, AnimationsEnabled = settings.AnimationsEnabled,
ResetEveryAmount = settings.ResetEveryAmount, ResetEveryAmount = settings.ResetEveryAmount,
ResetEvery = Enum.GetName(typeof(CrowdfundResetEvery), settings.ResetEvery), ResetEvery = Enum.GetName(typeof(CrowdfundResetEvery), settings.ResetEvery),
UseAllStoreInvoices = app.TagAllInvoices, UseAllStoreInvoices = CurrentApp.TagAllInvoices,
AppId = appId, 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, DisplayPerksRanking = settings.DisplayPerksRanking,
DisplayPerksValue = settings.DisplayPerksValue, DisplayPerksValue = settings.DisplayPerksValue,
SortPerksByPopularity = settings.SortPerksByPopularity, SortPerksByPopularity = settings.SortPerksByPopularity,
@@ -71,10 +71,10 @@ namespace BTCPayServer.Controllers
[HttpPost("{appId}/settings/crowdfund")] [HttpPost("{appId}/settings/crowdfund")]
public async Task<IActionResult> UpdateCrowdfund(string appId, UpdateCrowdfundViewModel vm, string command) public async Task<IActionResult> UpdateCrowdfund(string appId, UpdateCrowdfundViewModel vm, string command)
{ {
var app = await GetOwnedApp(appId, AppType.Crowdfund); if (CurrentApp == null)
if (app == null)
return NotFound(); 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) if (_currencies.GetCurrencyData(vm.TargetCurrency, false) == null)
ModelState.AddModelError(nameof(vm.TargetCurrency), "Invalid currency"); ModelState.AddModelError(nameof(vm.TargetCurrency), "Invalid currency");
@@ -125,8 +125,8 @@ namespace BTCPayServer.Controllers
return View(vm); return View(vm);
} }
app.Name = vm.AppName; CurrentApp.Name = vm.AppName;
var newSettings = new CrowdfundSettings() var newSettings = new CrowdfundSettings
{ {
Title = vm.Title, Title = vm.Title,
Enabled = vm.Enabled, Enabled = vm.Enabled,
@@ -155,15 +155,15 @@ namespace BTCPayServer.Controllers
AnimationColors = parsedAnimationColors AnimationColors = parsedAnimationColors
}; };
app.TagAllInvoices = vm.UseAllStoreInvoices; CurrentApp.TagAllInvoices = vm.UseAllStoreInvoices;
app.SetSettings(newSettings); CurrentApp.SetSettings(newSettings);
await _appService.UpdateOrCreateApp(app); await _appService.UpdateOrCreateApp(CurrentApp);
_eventAggregator.Publish(new AppUpdated() _eventAggregator.Publish(new AppUpdated()
{ {
AppId = appId, AppId = appId,
StoreId = app.StoreDataId, StoreId = CurrentApp.StoreDataId,
Settings = newSettings Settings = newSettings
}); });
TempData[WellKnownTempData.SuccessMessage] = "App updated"; TempData[WellKnownTempData.SuccessMessage] = "App updated";

View File

@@ -76,7 +76,6 @@ namespace BTCPayServer.Controllers
public static readonly int[] CUSTOM_TIP_PERCENTAGES_DEF = new int[] { 15, 18, 20 }; public static readonly int[] CUSTOM_TIP_PERCENTAGES_DEF = new int[] { 15, 18, 20 };
public int[] CustomTipPercentages { get; set; } = CUSTOM_TIP_PERCENTAGES_DEF; public int[] CustomTipPercentages { get; set; } = CUSTOM_TIP_PERCENTAGES_DEF;
public string CustomCSSLink { get; set; } public string CustomCSSLink { get; set; }
public string EmbeddedCSS { get; set; } public string EmbeddedCSS { get; set; }
@@ -88,21 +87,20 @@ namespace BTCPayServer.Controllers
} }
[HttpGet("{appId}/settings/pos")] [HttpGet("{appId}/settings/pos")]
public async Task<IActionResult> UpdatePointOfSale(string appId) public IActionResult UpdatePointOfSale(string appId)
{ {
var app = await GetOwnedApp(appId, AppType.PointOfSale); if (CurrentApp == null)
if (app == null)
return NotFound(); return NotFound();
var settings = app.GetSettings<PointOfSaleSettings>(); var settings = CurrentApp.GetSettings<PointOfSaleSettings>();
settings.DefaultView = settings.EnableShoppingCart ? PosViewType.Cart : settings.DefaultView; settings.DefaultView = settings.EnableShoppingCart ? PosViewType.Cart : settings.DefaultView;
settings.EnableShoppingCart = false; settings.EnableShoppingCart = false;
var vm = new UpdatePointOfSaleViewModel var vm = new UpdatePointOfSaleViewModel
{ {
Id = appId, Id = appId,
StoreId = app.StoreDataId, StoreId = CurrentApp.StoreDataId,
StoreName = app.StoreData?.StoreName, StoreName = CurrentApp.StoreData?.StoreName,
AppName = app.Name, AppName = CurrentApp.Name,
Title = settings.Title, Title = settings.Title,
DefaultView = settings.DefaultView, DefaultView = settings.DefaultView,
ShowCustomAmount = settings.ShowCustomAmount, ShowCustomAmount = settings.ShowCustomAmount,
@@ -119,7 +117,7 @@ namespace BTCPayServer.Controllers
Description = settings.Description, Description = settings.Description,
NotificationUrl = settings.NotificationUrl, NotificationUrl = settings.NotificationUrl,
RedirectUrl = settings.RedirectUrl, RedirectUrl = settings.RedirectUrl,
SearchTerm = $"storeid:{app.StoreDataId}", SearchTerm = $"storeid:{CurrentApp.StoreDataId}",
RedirectAutomatically = settings.RedirectAutomatically.HasValue ? settings.RedirectAutomatically.Value ? "true" : "false" : "", RedirectAutomatically = settings.RedirectAutomatically.HasValue ? settings.RedirectAutomatically.Value ? "true" : "false" : "",
RequiresRefundEmail = settings.RequiresRefundEmail RequiresRefundEmail = settings.RequiresRefundEmail
}; };
@@ -164,14 +162,13 @@ namespace BTCPayServer.Controllers
[HttpPost("{appId}/settings/pos")] [HttpPost("{appId}/settings/pos")]
public async Task<IActionResult> UpdatePointOfSale(string appId, UpdatePointOfSaleViewModel vm) public async Task<IActionResult> UpdatePointOfSale(string appId, UpdatePointOfSaleViewModel vm)
{ {
var app = await GetOwnedApp(appId, AppType.PointOfSale); if (CurrentApp == null)
if (app == null)
return NotFound(); return NotFound();
if (!ModelState.IsValid) if (!ModelState.IsValid)
{
return View(vm); 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) if (_currencies.GetCurrencyData(vm.Currency, false) == null)
ModelState.AddModelError(nameof(vm.Currency), "Invalid currency"); ModelState.AddModelError(nameof(vm.Currency), "Invalid currency");
try try
@@ -187,8 +184,8 @@ namespace BTCPayServer.Controllers
return View(vm); return View(vm);
} }
app.Name = vm.AppName; CurrentApp.Name = vm.AppName;
app.SetSettings(new PointOfSaleSettings CurrentApp.SetSettings(new PointOfSaleSettings
{ {
Title = vm.Title, Title = vm.Title,
DefaultView = vm.DefaultView, DefaultView = vm.DefaultView,
@@ -209,7 +206,7 @@ namespace BTCPayServer.Controllers
RedirectAutomatically = string.IsNullOrEmpty(vm.RedirectAutomatically) ? (bool?)null : bool.Parse(vm.RedirectAutomatically), RedirectAutomatically = string.IsNullOrEmpty(vm.RedirectAutomatically) ? (bool?)null : bool.Parse(vm.RedirectAutomatically),
RequiresRefundEmail = vm.RequiresRefundEmail, RequiresRefundEmail = vm.RequiresRefundEmail,
}); });
await _appService.UpdateOrCreateApp(app); await _appService.UpdateOrCreateApp(CurrentApp);
TempData[WellKnownTempData.SuccessMessage] = "App updated"; TempData[WellKnownTempData.SuccessMessage] = "App updated";
return RedirectToAction(nameof(UpdatePointOfSale), new { appId }); return RedirectToAction(nameof(UpdatePointOfSale), new { appId });
} }
@@ -220,8 +217,7 @@ namespace BTCPayServer.Controllers
{ {
return Array.Empty<int>(); return Array.Empty<int>();
} }
else
{
// Remove all characters except numeric and comma // Remove all characters except numeric and comma
Regex charsToDestroy = new Regex(@"[^\d|\" + separator + "]"); Regex charsToDestroy = new Regex(@"[^\d|\" + separator + "]");
list = charsToDestroy.Replace(list, ""); list = charsToDestroy.Replace(list, "");
@@ -229,5 +225,4 @@ namespace BTCPayServer.Controllers
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")] [HttpGet("{appId}/delete")]
public async Task<IActionResult> DeleteApp(string appId) public IActionResult DeleteApp(string appId)
{ {
var appData = await GetOwnedApp(appId); if (CurrentApp == null)
if (appData == null)
return NotFound(); 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")] [HttpPost("{appId}/delete")]
public async Task<IActionResult> DeleteAppPost(string appId) public async Task<IActionResult> DeleteAppPost(string appId)
{ {
var appData = await GetOwnedApp(appId); if (CurrentApp == null)
if (appData == null)
return NotFound(); return NotFound();
if (await _appService.DeleteApp(appData))
if (await _appService.DeleteApp(CurrentApp))
TempData[WellKnownTempData.SuccessMessage] = "App deleted successfully."; 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) async Task<string> GetStoreDefaultCurrentIfEmpty(string storeId, string currency)
@@ -172,11 +173,6 @@ namespace BTCPayServer.Controllers
return currency.Trim().ToUpperInvariant(); return currency.Trim().ToUpperInvariant();
} }
private Task<AppData> GetOwnedApp(string appId, AppType? type = null)
{
return _appService.GetAppDataIfOwner(GetUserId(), appId, type);
}
private string GetUserId() private string GetUserId()
{ {
return _userManager.GetUserId(User); return _userManager.GetUserId(User);
@@ -186,5 +182,10 @@ namespace BTCPayServer.Controllers
{ {
get => HttpContext.GetStoreData(); get => HttpContext.GetStoreData();
} }
private AppData CurrentApp
{
get => HttpContext.GetAppData();
}
} }
} }

View File

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

View File

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

View File

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