mirror of
https://github.com/aljazceru/BTCPayServerPlugins.git
synced 2025-12-17 07:34:24 +01:00
Ticket Tailor: Require full name
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Product>TicketTailor</Product>
|
<Product>TicketTailor</Product>
|
||||||
<Description>Allows you to integrate with TicketTailor.com to sell tickets for Bitcoin</Description>
|
<Description>Allows you to integrate with TicketTailor.com to sell tickets for Bitcoin</Description>
|
||||||
<Version>1.0.8</Version>
|
<Version>1.0.9</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<!-- Plugin development properties -->
|
<!-- Plugin development properties -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ namespace BTCPayServer.Plugins.TicketTailor
|
|||||||
public async Task<IActionResult> Purchase(string storeId, TicketTailorViewModel request)
|
public async Task<IActionResult> Purchase(string storeId, TicketTailorViewModel request)
|
||||||
{
|
{
|
||||||
var config = await _ticketTailorService.GetTicketTailorForStore(storeId);
|
var config = await _ticketTailorService.GetTicketTailorForStore(storeId);
|
||||||
|
(TicketTailorClient.Hold, string error)? hold = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (config?.ApiKey is not null && config?.EventId is not null)
|
if (config?.ApiKey is not null && config?.EventId is not null)
|
||||||
@@ -109,18 +110,18 @@ namespace BTCPayServer.Plugins.TicketTailor
|
|||||||
price += ticketCost * purchaseRequestItem.Quantity;
|
price += ticketCost * purchaseRequestItem.Quantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
var hold = await client.CreateHold(new TicketTailorClient.CreateHoldRequest()
|
hold = await client.CreateHold(new TicketTailorClient.CreateHoldRequest()
|
||||||
{
|
{
|
||||||
EventId = evt.Id,
|
EventId = evt.Id,
|
||||||
Note = "Created by BTCPay Server",
|
Note = "Created by BTCPay Server",
|
||||||
TicketTypeId = request.Items.ToDictionary(item => item.TicketTypeId, item => item.Quantity)
|
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
|
TempData.SetStatusMessageModel(new StatusMessageModel
|
||||||
{
|
{
|
||||||
Severity = StatusMessageModel.StatusSeverity.Error,
|
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});
|
return RedirectToAction("View", new {storeId});
|
||||||
}
|
}
|
||||||
@@ -130,23 +131,31 @@ namespace BTCPayServer.Plugins.TicketTailor
|
|||||||
var redirectUrl = Request.GetAbsoluteUri(Url.Action("Receipt",
|
var redirectUrl = Request.GetAbsoluteUri(Url.Action("Receipt",
|
||||||
"TicketTailor", new {storeId, invoiceId = "kukkskukkskukks"}));
|
"TicketTailor", new {storeId, invoiceId = "kukkskukkskukks"}));
|
||||||
redirectUrl = redirectUrl.Replace("kukkskukkskukks", "{InvoiceId}");
|
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);
|
request.Name = nameSplit.Length switch
|
||||||
if (nameSplit.Length < 2)
|
|
||||||
{
|
{
|
||||||
request.Name = nameSplit[0] + " Lizard";
|
0 => "Satoshi Nakamoto",
|
||||||
}
|
< 2 => $"{nameSplit} Nakamoto",
|
||||||
|
_ => request.Name
|
||||||
|
};
|
||||||
var inv = await btcpayClient.CreateInvoice(storeId,
|
var inv = await btcpayClient.CreateInvoice(storeId,
|
||||||
new CreateInvoiceRequest()
|
new CreateInvoiceRequest()
|
||||||
{
|
{
|
||||||
Amount = price,
|
Amount = price,
|
||||||
Currency = evt.Currency,
|
Currency = evt.Currency,
|
||||||
Type = InvoiceType.Standard,
|
Type = InvoiceType.Standard,
|
||||||
AdditionalSearchTerms = new[] {"tickettailor", hold.Item1.Id, evt.Id},
|
AdditionalSearchTerms = new[] {"tickettailor", hold.Value.Item1.Id, evt.Id},
|
||||||
Checkout =
|
Checkout =
|
||||||
{
|
{
|
||||||
RequiresRefundEmail = true,
|
RequiresRefundEmail = true,
|
||||||
@@ -162,7 +171,7 @@ namespace BTCPayServer.Plugins.TicketTailor
|
|||||||
btcpayUrl = Request.GetAbsoluteRoot(),
|
btcpayUrl = Request.GetAbsoluteRoot(),
|
||||||
buyerName = request.Name,
|
buyerName = request.Name,
|
||||||
buyerEmail = request.Email,
|
buyerEmail = request.Email,
|
||||||
holdId = hold.Item1.Id,
|
holdId = hold.Value.Item1.Id,
|
||||||
orderId="tickettailor"
|
orderId="tickettailor"
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -173,14 +182,24 @@ namespace BTCPayServer.Plugins.TicketTailor
|
|||||||
inv = await btcpayClient.GetInvoice(inv.StoreId, inv.Id);
|
inv = await btcpayClient.GetInvoice(inv.StoreId, inv.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inv.Status == InvoiceStatus.Settled)
|
return inv.Status == InvoiceStatus.Settled
|
||||||
return RedirectToAction("Receipt", new {storeId, invoiceId = inv.Id});
|
? RedirectToAction("Receipt", new {storeId, invoiceId = inv.Id})
|
||||||
|
: RedirectToAction("Checkout", "UIInvoice", new {invoiceId = inv.Id});
|
||||||
return RedirectToAction("Checkout","UIInvoice", new {invoiceId = inv.Id});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
TempData.SetStatusMessageModel(new StatusMessageModel
|
||||||
|
{
|
||||||
|
Severity = StatusMessageModel.StatusSeverity.Error,
|
||||||
|
Html = $"Could not continue with ticket purchase.</br>{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});
|
return RedirectToAction("View", new {storeId});
|
||||||
@@ -280,6 +299,7 @@ namespace BTCPayServer.Plugins.TicketTailor
|
|||||||
vm.ShowDescription = TicketTailor.ShowDescription;
|
vm.ShowDescription = TicketTailor.ShowDescription;
|
||||||
vm.BypassAvailabilityCheck = TicketTailor.BypassAvailabilityCheck;
|
vm.BypassAvailabilityCheck = TicketTailor.BypassAvailabilityCheck;
|
||||||
vm.CustomCSS = TicketTailor.CustomCSS;
|
vm.CustomCSS = TicketTailor.CustomCSS;
|
||||||
|
vm.RequireFullName = TicketTailor.RequireFullName;
|
||||||
vm.SpecificTickets = TicketTailor.SpecificTickets;
|
vm.SpecificTickets = TicketTailor.SpecificTickets;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -374,7 +394,8 @@ namespace BTCPayServer.Plugins.TicketTailor
|
|||||||
ShowDescription = vm.ShowDescription,
|
ShowDescription = vm.ShowDescription,
|
||||||
CustomCSS = vm.CustomCSS,
|
CustomCSS = vm.CustomCSS,
|
||||||
SpecificTickets = vm.SpecificTickets,
|
SpecificTickets = vm.SpecificTickets,
|
||||||
BypassAvailabilityCheck = vm.BypassAvailabilityCheck
|
BypassAvailabilityCheck = vm.BypassAvailabilityCheck,
|
||||||
|
RequireFullName = vm.RequireFullName
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -111,14 +111,23 @@ public class TicketTailorService : EventHostedServiceBase
|
|||||||
|
|
||||||
protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken)
|
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;
|
return;
|
||||||
}
|
case InvoiceEvent invoiceEvent:
|
||||||
|
|
||||||
evt = new IssueTicket() {Invoice = invoiceEvent.Invoice};
|
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};
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evt is not IssueTicket issueTicket)
|
if (evt is not IssueTicket issueTicket)
|
||||||
|
|||||||
@@ -11,5 +11,6 @@ namespace BTCPayServer.Plugins.TicketTailor
|
|||||||
public string CustomCSS { get; set; }
|
public string CustomCSS { get; set; }
|
||||||
public List<SpecificTicket> SpecificTickets { get; set; }
|
public List<SpecificTicket> SpecificTickets { get; set; }
|
||||||
public bool BypassAvailabilityCheck { get; set; }
|
public bool BypassAvailabilityCheck { get; set; }
|
||||||
|
public bool RequireFullName { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public class UpdateTicketTailorSettingsViewModel
|
|||||||
|
|
||||||
public List<SpecificTicket> SpecificTickets { get; set; }
|
public List<SpecificTicket> SpecificTickets { get; set; }
|
||||||
public bool BypassAvailabilityCheck { get; set; }
|
public bool BypassAvailabilityCheck { get; set; }
|
||||||
|
public bool RequireFullName { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SpecificTicket
|
public class SpecificTicket
|
||||||
|
|||||||
@@ -54,6 +54,11 @@
|
|||||||
<label asp-for="BypassAvailabilityCheck" class="form-check-label">Bypass availability checks of TicketTailor (such as when in draft mode)</label>
|
<label asp-for="BypassAvailabilityCheck" class="form-check-label">Bypass availability checks of TicketTailor (such as when in draft mode)</label>
|
||||||
<span asp-validation-for="BypassAvailabilityCheck" class="text-danger"></span>
|
<span asp-validation-for="BypassAvailabilityCheck" class="text-danger"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group form-check">
|
||||||
|
<input asp-for="RequireFullName" type="checkbox" class="form-check-input"/>
|
||||||
|
<label asp-for="RequireFullName" class="form-check-label">Require full name to be provided (if unchecked and not provided, the gap will be filled in with a placeholder)</label>
|
||||||
|
<span asp-validation-for="RequireFullName" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="CustomCSS" class="form-label">Additional Custom CSS</label>
|
<label asp-for="CustomCSS" class="form-label">Additional Custom CSS</label>
|
||||||
|
|||||||
@@ -1,15 +1,9 @@
|
|||||||
@using Microsoft.AspNetCore.Routing
|
@using Microsoft.AspNetCore.Routing
|
||||||
@using BTCPayServer.Plugins.TicketTailor
|
@using BTCPayServer.Plugins.TicketTailor
|
||||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@using NBitcoin
|
|
||||||
@model BTCPayServer.Plugins.TicketTailor.TicketTailorViewModel
|
@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";
|
Layout = "_LayoutSimple";
|
||||||
var available = Model.Settings.BypassAvailabilityCheck || (Model.Event.Unavailable != "true" && Model.Event.TicketsAvailable == "true");
|
var available = Model.Settings.BypassAvailabilityCheck || (Model.Event.Unavailable != "true" && Model.Event.TicketsAvailable == "true");
|
||||||
Model.Settings.SpecificTickets ??= new List<SpecificTicket>();
|
Model.Settings.SpecificTickets ??= new List<SpecificTicket>();
|
||||||
@@ -29,7 +23,7 @@ footer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<script nonce="@nonce">
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", ()=>{
|
document.addEventListener("DOMContentLoaded", ()=>{
|
||||||
const btn = document.querySelector("button[type='submit']");
|
const btn = document.querySelector("button[type='submit']");
|
||||||
document.querySelectorAll("input").forEach(value => value.addEventListener("input", (evt)=>{
|
document.querySelectorAll("input").forEach(value => value.addEventListener("input", (evt)=>{
|
||||||
@@ -77,7 +71,8 @@ document.addEventListener("DOMContentLoaded", ()=>{
|
|||||||
<div class="row g-2 justify-content-center mb-4" id="ticket-form-container">
|
<div class="row g-2 justify-content-center mb-4" id="ticket-form-container">
|
||||||
<div class="col-sm-6 col-md-4">
|
<div class="col-sm-6 col-md-4">
|
||||||
<div class="form-floating">
|
<div class="form-floating">
|
||||||
<input type="text" minlength="3" asp-for="Name" class="form-control">
|
<input type="text" asp-for="Name" class="form-control" required="@Model.Settings.RequireFullName"
|
||||||
|
pattern="^(\w\w+)\s(\w+)$" title="Please enter your first and last name, separated with a space.">
|
||||||
<label >Name</label>
|
<label >Name</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
@using BTCPayServer.Abstractions.Services
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
|
@inject BTCPayServer.Abstractions.Services.Safe Safe
|
||||||
@inject Safe Safe
|
@addTagHelper *, BTCPayServer.Abstractions
|
||||||
|
@addTagHelper *, BTCPayServer.TagHelpers
|
||||||
|
@addTagHelper *, BTCPayServer.Views.TagHelpers
|
||||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
|
||||||
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
@addTagHelper *, BTCPayServer
|
||||||
Reference in New Issue
Block a user