diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index 37ac22326..42ec0cb74 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -30,7 +30,6 @@ using Newtonsoft.Json.Linq; using OpenQA.Selenium; using OpenQA.Selenium.Support.Extensions; using OpenQA.Selenium.Support.UI; -using Renci.SshNet.Security.Cryptography; using Xunit; using Xunit.Abstractions; @@ -1300,6 +1299,46 @@ namespace BTCPayServer.Tests s.Driver.AssertElementNotFound(By.Id("ActionsDropdownToggle")); } + [Fact] + [Trait("Selenium", "Selenium")] + [Trait("Lightning", "Lightning")] + public async Task CanEditPullPaymentUI() + { + using var s = CreateSeleniumTester(); + s.Server.ActivateLightning(LightningConnectionType.LndREST); + await s.StartAsync(); + await s.Server.EnsureChannelsSetup(); + s.RegisterNewUser(true); + s.CreateNewStore(); + s.GenerateWallet("BTC", "", true, true); + await s.Server.ExplorerNode.GenerateAsync(1); + await s.FundStoreWallet(denomination: 50.0m); + + s.GoToStore(s.StoreId, StoreNavPages.PullPayments); + + s.Driver.FindElement(By.Id("NewPullPayment")).Click(); + s.Driver.FindElement(By.Id("Name")).SendKeys("PP1"); + s.Driver.FindElement(By.Id("Amount")).Clear(); + s.Driver.FindElement(By.Id("Amount")).SendKeys("99.0"); + s.Driver.FindElement(By.Id("Create")).Click(); + s.Driver.FindElement(By.LinkText("View")).Click(); + + s.GoToStore(s.StoreId, StoreNavPages.PullPayments); + + s.Driver.FindElement(By.LinkText("PP1")).Click(); + var name = s.Driver.FindElement(By.Id("Name")); + name.Clear(); + name.SendKeys("PP1 Edited"); + var description = s.Driver.FindElement(By.ClassName("card-block")); + description.SendKeys("Description Edit"); + s.Driver.FindElement(By.Id("SaveButton")).Click(); + + s.Driver.FindElement(By.LinkText("PP1 Edited")).Click(); + + Assert.Contains("Description Edit", s.Driver.PageSource); + Assert.Contains("PP1 Edited", s.Driver.PageSource); + } + [Fact] [Trait("Selenium", "Selenium")] [Trait("Lightning", "Lightning")] diff --git a/BTCPayServer/Controllers/UIPullPaymentController.cs b/BTCPayServer/Controllers/UIPullPaymentController.cs index 25d2b7c2d..1712030ce 100644 --- a/BTCPayServer/Controllers/UIPullPaymentController.cs +++ b/BTCPayServer/Controllers/UIPullPaymentController.cs @@ -1,14 +1,16 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Threading.Tasks; +using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Models; +using BTCPayServer.Client; using BTCPayServer.Client.Models; using BTCPayServer.Data; using BTCPayServer.HostedServices; using BTCPayServer.Models; +using BTCPayServer.Models.WalletViewModels; using BTCPayServer.Payments; using BTCPayServer.Services; using BTCPayServer.Services.Rates; @@ -19,7 +21,6 @@ using NBitcoin; namespace BTCPayServer.Controllers { - [AllowAnonymous] public class UIPullPaymentController : Controller { private readonly ApplicationDbContextFactory _dbContextFactory; @@ -41,7 +42,8 @@ namespace BTCPayServer.Controllers _payoutHandlers = payoutHandlers; } - [Route("pull-payments/{pullPaymentId}")] + [AllowAnonymous] + [HttpGet("pull-payments/{pullPaymentId}")] public async Task ViewPullPayment(string pullPaymentId) { using var ctx = _dbContextFactory.CreateContext(); @@ -92,6 +94,64 @@ namespace BTCPayServer.Controllers return View(nameof(ViewPullPayment), vm); } + [HttpGet("stores/{storeId}/pull-payments/edit/{pullPaymentId}")] + [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] + public async Task EditPullPayment(string storeId, string pullPaymentId) + { + using var ctx = _dbContextFactory.CreateContext(); + Data.PullPaymentData pp = await ctx.PullPayments.FindAsync(pullPaymentId); + if (pp == null && !string.IsNullOrEmpty(pullPaymentId)) + { + return NotFound(); + } + + var vm = new UpdatePullPaymentModel(pp); + return View(vm); + } + + [HttpPost("stores/{storeId}/pull-payments/edit/{pullPaymentId}")] + [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] + public async Task EditPullPayment(string storeId, string pullPaymentId, UpdatePullPaymentModel viewModel) + { + using var ctx = _dbContextFactory.CreateContext(); + + var pp = await ctx.PullPayments.FindAsync(pullPaymentId); + if (pp == null && !string.IsNullOrEmpty(pullPaymentId)) + { + return NotFound(); + } + + if (!ModelState.IsValid) + { + return View(viewModel); + } + + var blob = pp.GetBlob(); + blob.Description = viewModel.Description ?? string.Empty; + blob.Name = viewModel.Name ?? string.Empty; + blob.View = new PullPaymentBlob.PullPaymentView() + { + Title = viewModel.Name ?? string.Empty, + Description = viewModel.Description ?? string.Empty, + CustomCSSLink = viewModel.CustomCSSLink, + Email = null, + EmbeddedCSS = viewModel.EmbeddedCSS, + }; + + pp.SetBlob(blob); + ctx.PullPayments.Update(pp); + await ctx.SaveChangesAsync(); + + TempData.SetStatusMessageModel(new StatusMessageModel + { + Message = "Pull payment updated successfully", + Severity = StatusMessageModel.StatusSeverity.Success + }); + + return RedirectToAction(nameof(UIStorePullPaymentsController.PullPayments), "UIStorePullPayments", new { storeId, pullPaymentId }); + } + + [AllowAnonymous] [HttpPost("pull-payments/{pullPaymentId}/claim")] public async Task ClaimPullPayment(string pullPaymentId, ViewPullPaymentModel vm) { diff --git a/BTCPayServer/Models/WalletViewModels/PullPaymentsModel.cs b/BTCPayServer/Models/WalletViewModels/PullPaymentsModel.cs index a1d649588..3fe4c65f4 100644 --- a/BTCPayServer/Models/WalletViewModels/PullPaymentsModel.cs +++ b/BTCPayServer/Models/WalletViewModels/PullPaymentsModel.cs @@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Mvc.Rendering; using BTCPayServer.Payments; using BTCPayServer.Client.Models; +using BTCPayServer.Data; namespace BTCPayServer.Models.WalletViewModels { @@ -70,4 +71,37 @@ namespace BTCPayServer.Models.WalletViewModels [Display(Name = "Automatically approve claims")] public bool AutoApproveClaims { get; set; } = false; } + + public class UpdatePullPaymentModel + { + + public string Id { get; set; } + + public UpdatePullPaymentModel() + { + } + + public UpdatePullPaymentModel(Data.PullPaymentData data) + { + if (data == null) + { + return; + } + + Id = data.Id; + var blob = data.GetBlob(); + Name = blob.Name; + Description = blob.Description; + CustomCSSLink = blob.View.CustomCSSLink; + EmbeddedCSS = blob.View.EmbeddedCSS; + } + + [MaxLength(30)] + public string Name { get; set; } + public string Description { get; set; } + [Display(Name = "Custom CSS URL")] + public string CustomCSSLink { get; set; } + [Display(Name = "Custom CSS Code")] + public string EmbeddedCSS { get; set; } + } } diff --git a/BTCPayServer/Views/UIPullPayment/EditPullPayment.cshtml b/BTCPayServer/Views/UIPullPayment/EditPullPayment.cshtml new file mode 100644 index 000000000..bd44d1a44 --- /dev/null +++ b/BTCPayServer/Views/UIPullPayment/EditPullPayment.cshtml @@ -0,0 +1,92 @@ +@using BTCPayServer.Views.Stores +@using BTCPayServer.Abstractions.Extensions +@model BTCPayServer.Models.WalletViewModels.UpdatePullPaymentModel + +@{ + ViewData.SetActivePage(StoreNavPages.Create, "Edit Pull Payment", Model.Id); +} + +@section PageHeadContent { + +} + +@section PageFootContent { + + +} + +
+
+ + + + +
+
+
+
+ + + +
+
+
+ +
+
+
+ + + +
+
+
+ +
+
+

Additional Options

+
+
+
+

+ +

+
+
+
+ + + + + + +
+
+ + + +
+
+
+
+
+
+
+
+ diff --git a/BTCPayServer/Views/UIPullPayment/ViewPullPayment.cshtml b/BTCPayServer/Views/UIPullPayment/ViewPullPayment.cshtml index e2f5df00c..0bbef23bf 100644 --- a/BTCPayServer/Views/UIPullPayment/ViewPullPayment.cshtml +++ b/BTCPayServer/Views/UIPullPayment/ViewPullPayment.cshtml @@ -215,8 +215,11 @@