diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/BTCPayServer.Plugins.TicketTailor.csproj b/Plugins/BTCPayServer.Plugins.TicketTailor/BTCPayServer.Plugins.TicketTailor.csproj index 17d9c88..2194f8b 100644 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/BTCPayServer.Plugins.TicketTailor.csproj +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/BTCPayServer.Plugins.TicketTailor.csproj @@ -9,7 +9,7 @@ TicketTailor Allows you to integrate with TicketTailor.com to sell tickets for Bitcoin - 1.0.8 + 1.0.9 diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorController.cs b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorController.cs index a6764c3..e016c8b 100644 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorController.cs +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorController.cs @@ -53,6 +53,7 @@ namespace BTCPayServer.Plugins.TicketTailor public async Task Purchase(string storeId, TicketTailorViewModel request) { var config = await _ticketTailorService.GetTicketTailorForStore(storeId); + (TicketTailorClient.Hold, string error)? hold = null; try { if (config?.ApiKey is not null && config?.EventId is not null) @@ -109,18 +110,18 @@ namespace BTCPayServer.Plugins.TicketTailor price += ticketCost * purchaseRequestItem.Quantity; } - var hold = await client.CreateHold(new TicketTailorClient.CreateHoldRequest() + hold = await client.CreateHold(new TicketTailorClient.CreateHoldRequest() { EventId = evt.Id, Note = "Created by BTCPay Server", TicketTypeId = request.Items.ToDictionary(item => item.TicketTypeId, item => item.Quantity) }); - if (!string.IsNullOrEmpty(hold.error)) + if (!string.IsNullOrEmpty(hold.Value.error)) { TempData.SetStatusMessageModel(new StatusMessageModel { Severity = StatusMessageModel.StatusSeverity.Error, - Html = $"Could not reserve tickets because {hold.error}" + Html = $"Could not reserve tickets because {hold.Value.error}" }); return RedirectToAction("View", new {storeId}); } @@ -130,23 +131,31 @@ namespace BTCPayServer.Plugins.TicketTailor var redirectUrl = Request.GetAbsoluteUri(Url.Action("Receipt", "TicketTailor", new {storeId, invoiceId = "kukkskukkskukks"})); redirectUrl = redirectUrl.Replace("kukkskukkskukks", "{InvoiceId}"); - if(string.IsNullOrEmpty(request.Name)) + request.Name??=string.Empty; + var nameSplit = request.Name.Split(" ", StringSplitOptions.RemoveEmptyEntries); + if (config.RequireFullName && nameSplit.Length < 2) { - request.Name = "Anonymous lizard"; + TempData.SetStatusMessageModel(new StatusMessageModel + { + Severity = StatusMessageModel.StatusSeverity.Error, + Html = "Please enter your full name." + }); + return RedirectToAction("View", new {storeId}); } - var nameSplit = request.Name.Split(" ", StringSplitOptions.RemoveEmptyEntries); - if (nameSplit.Length < 2) + request.Name = nameSplit.Length switch { - request.Name = nameSplit[0] + " Lizard"; - } + 0 => "Satoshi Nakamoto", + < 2 => $"{nameSplit} Nakamoto", + _ => request.Name + }; var inv = await btcpayClient.CreateInvoice(storeId, new CreateInvoiceRequest() { Amount = price, Currency = evt.Currency, Type = InvoiceType.Standard, - AdditionalSearchTerms = new[] {"tickettailor", hold.Item1.Id, evt.Id}, + AdditionalSearchTerms = new[] {"tickettailor", hold.Value.Item1.Id, evt.Id}, Checkout = { RequiresRefundEmail = true, @@ -162,7 +171,7 @@ namespace BTCPayServer.Plugins.TicketTailor btcpayUrl = Request.GetAbsoluteRoot(), buyerName = request.Name, buyerEmail = request.Email, - holdId = hold.Item1.Id, + holdId = hold.Value.Item1.Id, orderId="tickettailor" }) }); @@ -173,14 +182,24 @@ namespace BTCPayServer.Plugins.TicketTailor inv = await btcpayClient.GetInvoice(inv.StoreId, inv.Id); } - if (inv.Status == InvoiceStatus.Settled) - return RedirectToAction("Receipt", new {storeId, invoiceId = inv.Id}); - - return RedirectToAction("Checkout","UIInvoice", new {invoiceId = inv.Id}); + return inv.Status == InvoiceStatus.Settled + ? RedirectToAction("Receipt", new {storeId, invoiceId = inv.Id}) + : RedirectToAction("Checkout", "UIInvoice", new {invoiceId = inv.Id}); } } catch (Exception e) { + TempData.SetStatusMessageModel(new StatusMessageModel + { + Severity = StatusMessageModel.StatusSeverity.Error, + Html = $"Could not continue with ticket purchase.
{e.Message}" + }); + if (hold?.Item1 is not null) + { + + var client = new TicketTailorClient(_httpClientFactory, config.ApiKey); + await client.DeleteHold(hold?.Item1.Id); + } } return RedirectToAction("View", new {storeId}); @@ -280,6 +299,7 @@ namespace BTCPayServer.Plugins.TicketTailor vm.ShowDescription = TicketTailor.ShowDescription; vm.BypassAvailabilityCheck = TicketTailor.BypassAvailabilityCheck; vm.CustomCSS = TicketTailor.CustomCSS; + vm.RequireFullName = TicketTailor.RequireFullName; vm.SpecificTickets = TicketTailor.SpecificTickets; } } @@ -374,7 +394,8 @@ namespace BTCPayServer.Plugins.TicketTailor ShowDescription = vm.ShowDescription, CustomCSS = vm.CustomCSS, SpecificTickets = vm.SpecificTickets, - BypassAvailabilityCheck = vm.BypassAvailabilityCheck + BypassAvailabilityCheck = vm.BypassAvailabilityCheck, + RequireFullName = vm.RequireFullName }; diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorService.cs b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorService.cs index a7340b5..86f73c5 100644 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorService.cs +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorService.cs @@ -111,14 +111,23 @@ public class TicketTailorService : EventHostedServiceBase protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken) { - if (evt is InvoiceEvent invoiceEvent) + switch (evt) { - if (invoiceEvent.Invoice.Metadata.OrderId != "tickettailor" || !new []{InvoiceStatus.Settled, InvoiceStatus.Expired, InvoiceStatus.Invalid}.Contains(invoiceEvent.Invoice.GetInvoiceState().Status.ToModernStatus())) - { + case InvoiceEvent invoiceEvent when invoiceEvent.Invoice.Metadata.OrderId != "tickettailor" || !new []{InvoiceStatus.Settled, InvoiceStatus.Expired, InvoiceStatus.Invalid}.Contains(invoiceEvent.Invoice.GetInvoiceState().Status.ToModernStatus()): return; - } + case InvoiceEvent invoiceEvent: + + if(_memoryCache.TryGetValue($"{nameof(TicketTailorService)}_{invoiceEvent.Invoice.Id}_issue_check_from_ui", out _))return; + + await _memoryCache.GetOrCreateAsync( + $"{nameof(TicketTailorService)}_{invoiceEvent.Invoice.Id}_issue_check_from_ui", async entry => + { + entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(2); + return true; + }); - evt = new IssueTicket() {Invoice = invoiceEvent.Invoice}; + evt = new IssueTicket() {Invoice = invoiceEvent.Invoice}; + break; } if (evt is not IssueTicket issueTicket) diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorSettings.cs b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorSettings.cs index d797ff9..31bccb1 100644 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorSettings.cs +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorSettings.cs @@ -11,5 +11,6 @@ namespace BTCPayServer.Plugins.TicketTailor public string CustomCSS { get; set; } public List SpecificTickets { get; set; } public bool BypassAvailabilityCheck { get; set; } + public bool RequireFullName { get; set; } } } diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/UpdateTicketTailorSettingsViewModel.cs b/Plugins/BTCPayServer.Plugins.TicketTailor/UpdateTicketTailorSettingsViewModel.cs index 6e20426..c3c52e1 100644 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/UpdateTicketTailorSettingsViewModel.cs +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/UpdateTicketTailorSettingsViewModel.cs @@ -15,6 +15,7 @@ public class UpdateTicketTailorSettingsViewModel public List SpecificTickets { get; set; } public bool BypassAvailabilityCheck { get; set; } + public bool RequireFullName { get; set; } } public class SpecificTicket diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/Views/TicketTailor/UpdateTicketTailorSettings.cshtml b/Plugins/BTCPayServer.Plugins.TicketTailor/Views/TicketTailor/UpdateTicketTailorSettings.cshtml index a01bfe1..d3985d1 100644 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/Views/TicketTailor/UpdateTicketTailorSettings.cshtml +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/Views/TicketTailor/UpdateTicketTailorSettings.cshtml @@ -54,6 +54,11 @@ +
+ + + +
diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/Views/TicketTailor/View.cshtml b/Plugins/BTCPayServer.Plugins.TicketTailor/Views/TicketTailor/View.cshtml index 28547c0..3bc97eb 100644 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/Views/TicketTailor/View.cshtml +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/Views/TicketTailor/View.cshtml @@ -1,15 +1,9 @@ @using Microsoft.AspNetCore.Routing @using BTCPayServer.Plugins.TicketTailor @using Microsoft.AspNetCore.Mvc.TagHelpers -@using NBitcoin @model BTCPayServer.Plugins.TicketTailor.TicketTailorViewModel - -@inject BTCPayServer.Security.ContentSecurityPolicies csp; @{ - var nonce = RandomUtils.GetUInt256().ToString().Substring(0, 32); - csp.Add("script-src", $"'nonce-{nonce}'"); - csp.AllowUnsafeHashes(); Layout = "_LayoutSimple"; var available = Model.Settings.BypassAvailabilityCheck || (Model.Event.Unavailable != "true" && Model.Event.TicketsAvailable == "true"); Model.Settings.SpecificTickets ??= new List(); @@ -29,7 +23,7 @@ footer { } -