diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/AppMigrate.cs b/Plugins/BTCPayServer.Plugins.TicketTailor/AppMigrate.cs new file mode 100644 index 0000000..e3e60f0 --- /dev/null +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/AppMigrate.cs @@ -0,0 +1,65 @@ +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using BTCPayServer.Abstractions.Contracts; +using BTCPayServer.Data; +using BTCPayServer.Services.Apps; +using BTCPayServer.Services.Invoices; +using BTCPayServer.Services.Stores; +using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json; + +namespace BTCPayServer.Plugins.TicketTailor; + +public class AppMigrate : IStartupTask +{ + private readonly StoreRepository _storeRepository; + private readonly AppService _appService; + private readonly ApplicationDbContextFactory _contextFactory; + private readonly BTCPayNetworkProvider _btcPayNetworkProvider; + + public AppMigrate(StoreRepository storeRepository, AppService appService, + ApplicationDbContextFactory contextFactory, BTCPayNetworkProvider btcPayNetworkProvider) + { + _storeRepository = storeRepository; + _appService = appService; + _contextFactory = contextFactory; + _btcPayNetworkProvider = btcPayNetworkProvider; + } + + public async Task ExecuteAsync(CancellationToken cancellationToken = default) + { + var existingSettings = + await _storeRepository.GetSettingsAsync("TicketTailorSettings"); + foreach (var setting in existingSettings) + { + var app = new AppData() + { + Created = DateTimeOffset.UtcNow, + Name = "Ticket Tailor", + AppType = TicketTailorApp.AppType, + StoreDataId = setting.Key, + TagAllInvoices = false, + Archived = false, + Settings = JsonConvert.SerializeObject(setting.Value) + }; + await _appService.UpdateOrCreateApp(app); + await using var ctx = _contextFactory.CreateContext(); + var invoices = await ctx.Invoices + .Include(data => data.InvoiceSearchData) + .Where(data => data.StoreDataId == setting.Key && data.OrderId == "tickettailor").ToListAsync(cancellationToken: cancellationToken); + foreach (var invoice in invoices) + { + var entity = invoice.GetBlob(_btcPayNetworkProvider); + entity.Metadata.SetAdditionalData("appId", app.Id); + entity.InternalTags.Add(AppService.GetAppInternalTag(app.Id)); + InvoiceRepository.AddToTextSearch(ctx, invoice, AppService.GetAppSearchTerm(app) ); + invoice.SetBlob(entity); + } + await ctx.SaveChangesAsync(cancellationToken); + + await _storeRepository.UpdateSetting(setting.Key, "TicketTailorSettings", null); + } + } +} \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/BTCPayServer.Plugins.TicketTailor.csproj b/Plugins/BTCPayServer.Plugins.TicketTailor/BTCPayServer.Plugins.TicketTailor.csproj index fd8c061..a02adbd 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.14 + 2.0.0 diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/README.md b/Plugins/BTCPayServer.Plugins.TicketTailor/README.md index 0ef08d3..0b85f42 100644 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/README.md +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/README.md @@ -8,7 +8,7 @@ It allows you to sell tickets for your events and accept payments in Bitcoin. 1. Install the plugin from Plugins=>Add New=> TicketTailor 2. Restart BTCPay Server 3. Go to your Ticket Tailor account and add a [new API key](https://app.tickettailor.com/box-office/api#dpop=/box-office/api-key/add) with `Admin` role and "hide personal data from responses" unchecked. -4. Go back to your BTCPay Server, choose the store to integrate with and click on Ticket Tailor in the navigation. +4. Go back to your BTCPay Server, choose the store to integrate with and click on Ticket Tailor in the navigation. This will create a ticket tailor app in your current store. 5. Enter the API Key and save. 6. Now you should be able to select your Ticket tailor events in the dropdown. One selected, click save. 7. You should now have a "ticket purchase" button on your store's page. Clicking it will take you to the btcpayserver event purchase page. diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorApp.cs b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorApp.cs new file mode 100644 index 0000000..e82cb03 --- /dev/null +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorApp.cs @@ -0,0 +1,49 @@ +using System.Threading.Tasks; +using BTCPayServer.Configuration; +using BTCPayServer.Data; +using BTCPayServer.Services.Apps; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Options; + +namespace BTCPayServer.Plugins.TicketTailor; + +public class TicketTailorApp : AppBaseType +{ + private readonly LinkGenerator _linkGenerator; + private readonly IOptions _options; + public const string AppType = "TicketTailor"; + + public TicketTailorApp( + LinkGenerator linkGenerator, + IOptions options) + { + Description = "Ticket Tailor"; + Type = AppType; + _linkGenerator = linkGenerator; + _options = options; + } + + public override Task ConfigureLink(AppData app) + { + return Task.FromResult(_linkGenerator.GetPathByAction( + nameof(TicketTailorController.UpdateTicketTailorSettings), + "TicketTailor", new {appId = app.Id}, _options.Value.RootPath)!); + } + + public override Task GetInfo(AppData appData) + { + return Task.FromResult(null); + } + + public override Task SetDefaultSettings(AppData appData, string defaultCurrency) + { + appData.SetSettings(new TicketTailorSettings()); + return Task.CompletedTask; + } + + public override Task ViewLink(AppData app) + { + return Task.FromResult(_linkGenerator.GetPathByAction(nameof(TicketTailorController.View), + "TicketTailor", new {appId = app.Id}, _options.Value.RootPath)!); + } +} \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorController.cs b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorController.cs index 8255866..bf3445b 100644 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorController.cs +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorController.cs @@ -2,33 +2,78 @@ using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; -using BTCPayServer.Abstractions.Contracts; +using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Models; using BTCPayServer.Client; using BTCPayServer.Client.Models; +using BTCPayServer.Controllers; +using BTCPayServer.Data; +using BTCPayServer.Services.Apps; +using BTCPayServer.Services.Invoices; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.EntityFrameworkCore; using Newtonsoft.Json.Linq; -using AuthenticationSchemes = BTCPayServer.Abstractions.Constants.AuthenticationSchemes; namespace BTCPayServer.Plugins.TicketTailor { [Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)] [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - [Route("plugins/{storeId}/TicketTailor")] public class TicketTailorController : Controller { - [AllowAnonymous] - [HttpGet("")] - public async Task View(string storeId) + private readonly IHttpClientFactory _httpClientFactory; + private readonly TicketTailorService _ticketTailorService; + private readonly AppService _appService; + private readonly ApplicationDbContextFactory _contextFactory; + private readonly InvoiceRepository _invoiceRepository; + private readonly UIInvoiceController _uiInvoiceController; + + public TicketTailorController(IHttpClientFactory httpClientFactory, + TicketTailorService ticketTailorService, + AppService appService, + ApplicationDbContextFactory contextFactory, + InvoiceRepository invoiceRepository, + UIInvoiceController uiInvoiceController ) { - var config = await _ticketTailorService.GetTicketTailorForStore(storeId); + _httpClientFactory = httpClientFactory; + _ticketTailorService = ticketTailorService; + _appService = appService; + _contextFactory = contextFactory; + _invoiceRepository = invoiceRepository; + _uiInvoiceController = uiInvoiceController; + } + + + [AllowAnonymous] + [HttpGet("plugins/{storeId}/TicketTailor")] + public async Task ViewLegacy(string storeId) + { + await using var ctx = _contextFactory.CreateContext(); + var app = await ctx.Apps + .Where(data => data.StoreDataId == storeId && data.AppType == TicketTailorApp.AppType) + .FirstOrDefaultAsync(); + + if (app is null) + return NotFound(); + + return RedirectToAction(nameof(View), new {storeId, appId = app.Id}); + } + + + [AllowAnonymous] + [HttpGet("plugins/TicketTailor/{appId}")] + public async Task View(string appId) + { + var app = await _appService.GetApp(appId, TicketTailorApp.AppType); + if (app is null) + return NotFound(); try { + var config = app.GetSettings(); if (config?.ApiKey is not null && config?.EventId is not null) { var client = new TicketTailorClient(_httpClientFactory, config.ApiKey); @@ -47,20 +92,25 @@ namespace BTCPayServer.Plugins.TicketTailor return NotFound(); } - + [AllowAnonymous] - [HttpPost("")] - public async Task Purchase(string storeId, TicketTailorViewModel request, bool preview = false) + [HttpPost("plugins/TicketTailor/{appId}")] + public async Task Purchase(string appId, TicketTailorViewModel request, bool preview = false) { - var config = await _ticketTailorService.GetTicketTailorForStore(storeId); + var app = await _appService.GetApp(appId, TicketTailorApp.AppType, true); + if (app is null) + return NotFound(); + (TicketTailorClient.Hold, string error)? hold = null; + var config = app.GetSettings(); try { if (config?.ApiKey is not null && config?.EventId is not null) { var client = new TicketTailorClient(_httpClientFactory, config.ApiKey); var evt = await client.GetEvent(config.EventId); - if (evt is null || (!config.BypassAvailabilityCheck && (evt.Unavailable == "true" || evt.TicketsAvailable == "false"))) + if (evt is null || (!config.BypassAvailabilityCheck && + (evt.Unavailable == "true" || evt.TicketsAvailable == "false"))) { return NotFound(); } @@ -70,7 +120,8 @@ namespace BTCPayServer.Plugins.TicketTailor if (!string.IsNullOrEmpty(request.DiscountCode) && config.AllowDiscountCodes) { discountCode = await client.GetDiscountCode(request.DiscountCode); - if (discountCode?.expires?.unix is not null && DateTimeOffset.FromUnixTimeSeconds(discountCode.expires.unix) < DateTimeOffset.Now) + if (discountCode?.expires?.unix is not null && + DateTimeOffset.FromUnixTimeSeconds(discountCode.expires.unix) < DateTimeOffset.Now) { discountCode = null; } @@ -83,39 +134,42 @@ namespace BTCPayServer.Plugins.TicketTailor { continue; } - var ticketType = evt.TicketTypes.FirstOrDefault(type => type.Id == purchaseRequestItem.TicketTypeId); - + + var ticketType = + evt.TicketTypes.FirstOrDefault(type => type.Id == purchaseRequestItem.TicketTypeId); + var specificTicket = config.SpecificTickets?.SingleOrDefault(ticket => ticketType?.Id == ticket.TicketTypeId); if ((config.SpecificTickets?.Any() is true && specificTicket is null) || ticketType is null || - (!string.IsNullOrEmpty(ticketType.AccessCode) && - !ticketType.AccessCode.Equals(request.AccessCode, StringComparison.InvariantCultureIgnoreCase)) || - !new []{"on_sale" , "locked"}.Contains(ticketType.Status.ToLowerInvariant()) - || specificTicket?.Hidden is true) + (!string.IsNullOrEmpty(ticketType.AccessCode) && + !ticketType.AccessCode.Equals(request.AccessCode, + StringComparison.InvariantCultureIgnoreCase)) || + !new[] {"on_sale", "locked"}.Contains(ticketType.Status.ToLowerInvariant()) + || specificTicket?.Hidden is true) { TempData.SetStatusMessageModel(new StatusMessageModel { Severity = StatusMessageModel.StatusSeverity.Error, Html = "The ticket was not found." }); - return RedirectToAction("View", new {storeId}); + return RedirectToAction("View", new {appId}); } if (purchaseRequestItem.Quantity > ticketType.MaxPerOrder || - purchaseRequestItem.Quantity < ticketType.MinPerOrder ) + purchaseRequestItem.Quantity < ticketType.MinPerOrder) { TempData.SetStatusMessageModel(new StatusMessageModel { Severity = StatusMessageModel.StatusSeverity.Error, Html = "The amount of tickets was not allowed." }); - return RedirectToAction("View", new {storeId}); + return RedirectToAction("View", new {appId}); } var ticketCost = ticketType.Price; if (specificTicket is not null) { - ticketCost =specificTicket.Price.GetValueOrDefault(ticketType.Price); + ticketCost = specificTicket.Price.GetValueOrDefault(ticketType.Price); } var originalTicketCost = ticketCost; @@ -129,15 +183,15 @@ namespace BTCPayServer.Plugins.TicketTailor case "percentage" when discountCode.face_value_percentage is not null: var percentageOff = (discountCode.face_value_percentage.Value / 100m); - + ticketCost -= (ticketCost * percentageOff); break; } } - + var thisTicketBatchCost = ticketCost * purchaseRequestItem.Quantity; discountedAmount += (originalTicketCost * purchaseRequestItem.Quantity) - thisTicketBatchCost; - + price += thisTicketBatchCost; } @@ -163,15 +217,14 @@ namespace BTCPayServer.Plugins.TicketTailor Severity = StatusMessageModel.StatusSeverity.Error, Html = $"Could not reserve tickets because {hold.Value.error}" }); - return RedirectToAction("View", new {storeId}); + return RedirectToAction("View", new {appId}); } - - - var btcpayClient = await CreateClient(storeId); + + var redirectUrl = Request.GetAbsoluteUri(Url.Action("Receipt", - "TicketTailor", new {storeId, invoiceId = "kukkskukkskukks"})); + "TicketTailor", new {storeId = app.StoreDataId, invoiceId = "kukkskukkskukks"})); redirectUrl = redirectUrl.Replace("kukkskukkskukks", "{InvoiceId}"); - request.Name??=string.Empty; + request.Name ??= string.Empty; var nameSplit = request.Name.Split(" ", StringSplitOptions.RemoveEmptyEntries); if (config.RequireFullName && nameSplit.Length < 2) { @@ -180,7 +233,7 @@ namespace BTCPayServer.Plugins.TicketTailor Severity = StatusMessageModel.StatusSeverity.Error, Html = "Please enter your full name." }); - return RedirectToAction("View", new {storeId}); + return RedirectToAction("View", new {appId}); } request.Name = nameSplit.Length switch @@ -189,13 +242,12 @@ namespace BTCPayServer.Plugins.TicketTailor < 2 => $"{nameSplit} Nakamoto", _ => request.Name }; - var inv = await btcpayClient.CreateInvoice(storeId, - new CreateInvoiceRequest() + var inv = await _uiInvoiceController.CreateInvoiceCoreRaw( new CreateInvoiceRequest() { Amount = price, Currency = evt.Currency, Type = InvoiceType.Standard, - AdditionalSearchTerms = new[] {"tickettailor", hold.Value.Item1.Id, evt.Id}, + AdditionalSearchTerms = new[] {"tickettailor", hold.Value.Item1.Id, evt.Id, AppService.GetAppSearchTerm(app)}, Checkout = { RequiresRefundEmail = true, @@ -209,23 +261,25 @@ namespace BTCPayServer.Plugins.TicketTailor Metadata = JObject.FromObject(new { btcpayUrl = Request.GetAbsoluteRoot(), - buyerName = request.Name, - buyerEmail = request.Email, + buyerName = request.Name, + buyerEmail = request.Email, holdId = hold.Value.Item1.Id, - orderId="tickettailor", + orderId = "tickettailor", + appId, discountCode, discountedAmount - }) - }); + }), + + }, app.StoreData, HttpContext.Request.GetAbsoluteRoot(),new List { AppService.GetAppInternalTag(appId) }, CancellationToken.None); - while (inv.Amount == 0 && inv.Status == InvoiceStatus.New) + while (inv.Price == 0 && inv.Status == InvoiceStatusLegacy.New) { - if (inv.Status == InvoiceStatus.New) - inv = await btcpayClient.GetInvoice(inv.StoreId, inv.Id); + if (inv.Status == InvoiceStatusLegacy.New) + inv = await _invoiceRepository.GetInvoice(inv.Id); } - return inv.Status == InvoiceStatus.Settled - ? RedirectToAction("Receipt", new {storeId, invoiceId = inv.Id}) + return inv.Status.ToModernStatus() == InvoiceStatus.Settled + ? RedirectToAction("Receipt", new {invoiceId = inv.Id}) : RedirectToAction("Checkout", "UIInvoice", new {invoiceId = inv.Id}); } } @@ -238,35 +292,45 @@ namespace BTCPayServer.Plugins.TicketTailor }); 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 {appId}); } [AllowAnonymous] - [HttpGet("receipt")] - public async Task Receipt(string storeId, string invoiceId) + [HttpGet("plugins/{storeId}/TicketTailor/receipt")] + [HttpGet("plugins/TicketTailor/{invoiceId}/receipt")] + public async Task Receipt(string invoiceId) { - var btcpayClient = await CreateClient(storeId); try { + var inv =await _invoiceRepository.GetInvoice(invoiceId); + if (inv is null) + { + return NotFound(); + } + + if (inv.Metadata.OrderId != "tickettailor") + { + return NotFound(); + } + + var appId = AppService.GetAppInternalTags(inv).First(); + var result = new TicketReceiptPage() {InvoiceId = invoiceId}; - var invoice = await btcpayClient.GetInvoice(storeId, invoiceId); - result.Status = invoice.Status; - if (invoice.Status == InvoiceStatus.Settled && - invoice.Metadata.TryGetValue("orderId", out var orderId) && orderId.Value() == "tickettailor" && - invoice.Metadata.TryGetValue("ticketIds", out var ticketIds)) + result.Status = inv.Status.ToModernStatus(); + if (result.Status == InvoiceStatus.Settled && + inv.Metadata.AdditionalData.TryGetValue("ticketIds", out var ticketIds)) { - await SetTicketTailorTicketResult(storeId, result, ticketIds.Values()); - - }else if (invoice.Status == InvoiceStatus.Settled) + await SetTicketTailorTicketResult(appId, result, ticketIds.Values()); + } + else if (inv.Status.ToModernStatus() == InvoiceStatus.Settled) { - await _ticketTailorService.CheckAndIssueTicket(invoice.Id); + await _ticketTailorService.CheckAndIssueTicket(inv.Id); } return View(result); @@ -277,9 +341,12 @@ namespace BTCPayServer.Plugins.TicketTailor } } - private async Task SetTicketTailorTicketResult(string storeId, TicketReceiptPage result, IEnumerable ticketIds) + private async Task SetTicketTailorTicketResult(string appId, TicketReceiptPage result, + IEnumerable ticketIds) { - var settings = await _ticketTailorService.GetTicketTailorForStore(storeId); + var app = await _appService.GetApp(appId, TicketTailorApp.AppType); + + var settings = app.GetSettings(); var client = new TicketTailorClient(_httpClientFactory, settings.ApiKey); var tickets = await Task.WhenAll(ticketIds.Select(s => client.GetTicket(s))); var evt = await client.GetEvent(settings.EventId); @@ -288,20 +355,7 @@ namespace BTCPayServer.Plugins.TicketTailor result.Settings = settings; } - private async Task CreateClient(string storeId) - { - return await _btcPayServerClientFactory.Create(null, new[] {storeId}, new DefaultHttpContext() - { - Request = - { - Scheme = "https", - Host = Request.Host, - Path = Request.Path, - PathBase = Request.PathBase - } - }); - } - + public class TicketReceiptPage { public string InvoiceId { get; set; } @@ -312,39 +366,28 @@ namespace BTCPayServer.Plugins.TicketTailor } - private readonly IHttpClientFactory _httpClientFactory; - private readonly TicketTailorService _ticketTailorService; - private readonly IBTCPayServerClientFactory _btcPayServerClientFactory; - - public TicketTailorController(IHttpClientFactory httpClientFactory, - TicketTailorService ticketTailorService, - IBTCPayServerClientFactory btcPayServerClientFactory) - { - - _httpClientFactory = httpClientFactory; - _ticketTailorService = ticketTailorService; - _btcPayServerClientFactory = btcPayServerClientFactory; - } - - [HttpGet("update")] - public async Task UpdateTicketTailorSettings(string storeId) + [HttpGet("~/plugins/TicketTailor/{appId}/update")] + public async Task UpdateTicketTailorSettings(string appId) { UpdateTicketTailorSettingsViewModel vm = new(); - TicketTailorSettings TicketTailor; + try { - TicketTailor = await _ticketTailorService.GetTicketTailorForStore(storeId); - if (TicketTailor is not null) + var app = await _appService.GetApp(appId, TicketTailorApp.AppType, false, true); + TicketTailorSettings tt = app.GetSettings(); + if (tt is not null) { - vm.ApiKey = TicketTailor.ApiKey; - vm.EventId = TicketTailor.EventId; - vm.ShowDescription = TicketTailor.ShowDescription; - vm.BypassAvailabilityCheck = TicketTailor.BypassAvailabilityCheck; - vm.CustomCSS = TicketTailor.CustomCSS; - vm.RequireFullName = TicketTailor.RequireFullName; - vm.AllowDiscountCodes = TicketTailor.AllowDiscountCodes; - vm.SpecificTickets = TicketTailor.SpecificTickets; + vm.ApiKey = tt.ApiKey; + vm.EventId = tt.EventId; + vm.ShowDescription = tt.ShowDescription; + vm.BypassAvailabilityCheck = tt.BypassAvailabilityCheck; + vm.CustomCSS = tt.CustomCSS; + vm.RequireFullName = tt.RequireFullName; + vm.AllowDiscountCodes = tt.AllowDiscountCodes; + vm.SpecificTickets = tt.SpecificTickets; } + vm.Archived = app.Archived; + vm.AppName = app.Name; } catch (Exception) { @@ -402,8 +445,8 @@ namespace BTCPayServer.Plugins.TicketTailor } - [HttpPost("update")] - public async Task UpdateTicketTailorSettings(string storeId, + [HttpPost("~/plugins/TicketTailor/{appId}/update")] + public async Task UpdateTicketTailorSettings(string appId, UpdateTicketTailorSettingsViewModel vm, string command) { @@ -429,6 +472,7 @@ namespace BTCPayServer.Plugins.TicketTailor { return View(vm); } + ModelState.Clear(); var settings = new TicketTailorSettings() { @@ -441,20 +485,21 @@ namespace BTCPayServer.Plugins.TicketTailor RequireFullName = vm.RequireFullName, AllowDiscountCodes = vm.AllowDiscountCodes }; - + switch (command?.ToLowerInvariant()) { case "save": - await _ticketTailorService.SetTicketTailorForStore(storeId, settings); + var app = await _appService.GetApp(appId, TicketTailorApp.AppType, false, true); + app.SetSettings(settings); + app.Name = vm.AppName; + await _appService.UpdateOrCreateApp(app); TempData["SuccessMessage"] = "TicketTailor settings modified"; - return RedirectToAction(nameof(UpdateTicketTailorSettings), new {storeId}); + return RedirectToAction(nameof(UpdateTicketTailorSettings), new {appId}); default: return View(vm); } } - - } -} +} \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorPlugin.cs b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorPlugin.cs index 1809dfd..19fc7a2 100644 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorPlugin.cs +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorPlugin.cs @@ -1,6 +1,8 @@ using BTCPayServer.Abstractions.Contracts; +using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Models; using BTCPayServer.Abstractions.Services; +using BTCPayServer.Services.Apps; using Microsoft.Extensions.DependencyInjection; namespace BTCPayServer.Plugins.TicketTailor @@ -9,17 +11,18 @@ namespace BTCPayServer.Plugins.TicketTailor { public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } = { - new() { Identifier = nameof(BTCPayServer), Condition = ">=1.12.0" } + new() {Identifier = nameof(BTCPayServer), Condition = ">=1.12.0"} }; + public override void Execute(IServiceCollection applicationBuilder) { + applicationBuilder.AddStartupTask(); applicationBuilder.AddSingleton(); - applicationBuilder.AddHostedService(s=>s.GetRequiredService()); - applicationBuilder.AddSingleton(new UIExtension("TicketTailor/StoreIntegrationTicketTailorOption", - "store-integrations-list")); - applicationBuilder.AddSingleton(new UIExtension("TicketTailor/TicketTailorNav", - "store-integrations-nav")); + applicationBuilder.AddHostedService(s => s.GetRequiredService()); + + applicationBuilder.AddSingleton(new UIExtension("TicketTailor/NavExtension", "header-nav")); + applicationBuilder.AddSingleton(); base.Execute(applicationBuilder); } } -} +} \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorService.cs b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorService.cs index 86f73c5..f17db6f 100644 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorService.cs +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/TicketTailorService.cs @@ -10,6 +10,7 @@ using BTCPayServer.Data; using BTCPayServer.Events; using BTCPayServer.HostedServices; using BTCPayServer.Logging; +using BTCPayServer.Services.Apps; using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Mails; using Microsoft.AspNetCore.Http; @@ -24,63 +25,33 @@ namespace BTCPayServer.Plugins.TicketTailor; public class TicketTailorService : EventHostedServiceBase { - private readonly ISettingsRepository _settingsRepository; private readonly IMemoryCache _memoryCache; private readonly IHttpClientFactory _httpClientFactory; - private readonly IStoreRepository _storeRepository; private readonly ILogger _logger; private readonly EmailSenderFactory _emailSenderFactory; private readonly LinkGenerator _linkGenerator; private readonly InvoiceRepository _invoiceRepository; + private readonly AppService _appService; - public TicketTailorService(ISettingsRepository settingsRepository, IMemoryCache memoryCache, + public TicketTailorService(IMemoryCache memoryCache, IHttpClientFactory httpClientFactory, - IStoreRepository storeRepository, ILogger logger, + ILogger logger, EmailSenderFactory emailSenderFactory , LinkGenerator linkGenerator, - EventAggregator eventAggregator, InvoiceRepository invoiceRepository) : base(eventAggregator, logger) + EventAggregator eventAggregator, InvoiceRepository invoiceRepository, + AppService appService) : base(eventAggregator, logger) { - _settingsRepository = settingsRepository; _memoryCache = memoryCache; _httpClientFactory = httpClientFactory; - _storeRepository = storeRepository; _logger = logger; _emailSenderFactory = emailSenderFactory; _linkGenerator = linkGenerator; _invoiceRepository = invoiceRepository; + _appService = appService; } - - public async Task GetTicketTailorForStore(string storeId) - { - var k = $"{nameof(TicketTailorSettings)}_{storeId}"; - return await _memoryCache.GetOrCreateAsync(k, async _ => - { - var res = await _storeRepository.GetSettingAsync(storeId, - nameof(TicketTailorSettings)); - if (res is not null) return res; - res = await _settingsRepository.GetSettingAsync(k); - - if (res is not null) - { - await SetTicketTailorForStore(storeId, res); - } - - await _settingsRepository.UpdateSetting(null, k); - return res; - }); - } - - public async Task SetTicketTailorForStore(string storeId, TicketTailorSettings TicketTailorSettings) - { - var k = $"{nameof(TicketTailorSettings)}_{storeId}"; - await _storeRepository.UpdateSetting(storeId, nameof(TicketTailorSettings), TicketTailorSettings); - _memoryCache.Set(k, TicketTailorSettings); - } - - private class IssueTicket { public InvoiceEntity Invoice { get; set; } @@ -153,7 +124,9 @@ public class TicketTailorService : EventHostedServiceBase { var invLogs = new InvoiceLogs(); - var settings = await GetTicketTailorForStore(issueTicket.Invoice.StoreId); + var appId = AppService.GetAppInternalTags(issueTicket.Invoice).First(); + var app = await _appService.GetApp(appId, TicketTailorApp.AppType); + var settings = app.GetSettings(); var invoice = issueTicket.Invoice; if (settings?.ApiKey is null) { @@ -269,7 +242,7 @@ public class TicketTailorService : EventHostedServiceBase var url = _linkGenerator.GetUriByAction("Receipt", "TicketTailor", - new {issueTicket.Invoice.StoreId, invoiceId = invoice.Id}, + new {invoiceId = invoice.Id}, uri.Scheme, new HostString(uri.Host), uri.AbsolutePath); diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/UpdateTicketTailorSettingsViewModel.cs b/Plugins/BTCPayServer.Plugins.TicketTailor/UpdateTicketTailorSettingsViewModel.cs index 44e9d2a..7d946d2 100644 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/UpdateTicketTailorSettingsViewModel.cs +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/UpdateTicketTailorSettingsViewModel.cs @@ -5,6 +5,8 @@ namespace BTCPayServer.Plugins.TicketTailor; public class UpdateTicketTailorSettingsViewModel { + public string AppName { get; set; } + public bool Archived { get; set; } public string NewSpecificTicket { get; set; } public string ApiKey { get; set; } public SelectList Events { get; set; } diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/Views/Shared/TicketTailor/NavExtension.cshtml b/Plugins/BTCPayServer.Plugins.TicketTailor/Views/Shared/TicketTailor/NavExtension.cshtml new file mode 100644 index 0000000..0dbee12 --- /dev/null +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/Views/Shared/TicketTailor/NavExtension.cshtml @@ -0,0 +1,36 @@ +@using BTCPayServer.Client +@using Microsoft.AspNetCore.Mvc.TagHelpers +@using BTCPayServer.Views.Apps +@using BTCPayServer.Services.Apps +@using BTCPayServer +@using BTCPayServer.Abstractions.Extensions +@using BTCPayServer.Plugins.TicketTailor +@inject AppService AppService; +@model BTCPayServer.Components.MainNav.MainNavViewModel +@{ + var store = Context.GetStoreData(); +} + +@if (store != null) +{ + var appType = AppService.GetAppType(TicketTailorApp.AppType)!; + + @foreach (var app in Model.Apps.Where(app => app.AppType == appType.Type)) + { + + + } +} \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/Views/Shared/TicketTailor/StoreIntegrationTicketTailorOption.cshtml b/Plugins/BTCPayServer.Plugins.TicketTailor/Views/Shared/TicketTailor/StoreIntegrationTicketTailorOption.cshtml deleted file mode 100644 index 8c426e3..0000000 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/Views/Shared/TicketTailor/StoreIntegrationTicketTailorOption.cshtml +++ /dev/null @@ -1,59 +0,0 @@ -@using BTCPayServer.Client -@using BTCPayServer.Plugins.TicketTailor -@using Microsoft.AspNetCore.Routing -@using BTCPayServer.Abstractions.Contracts -@inject IScopeProvider ScopeProvider -@inject TicketTailorService TicketTailorService -@{ - var storeId = ScopeProvider.GetCurrentStoreId(); - - TicketTailorSettings settings = null; - if (!string.IsNullOrEmpty(storeId)) - { - try - { - settings = await TicketTailorService.GetTicketTailorForStore(storeId); - } - catch (Exception) - { - } - } -} -@if (!string.IsNullOrEmpty(storeId)) -{ -
  • -
    - - - Ticket Tailor - - - Sell tickets on Ticket Tailor using BTCPay Server - - - - @if (settings?.ApiKey is not null) - { - - - Active - - | - - Modify - - } - else - { - - - Disabled - - - Setup - - } - -
    -
  • -} diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/Views/Shared/TicketTailor/TicketTailorNav.cshtml b/Plugins/BTCPayServer.Plugins.TicketTailor/Views/Shared/TicketTailor/TicketTailorNav.cshtml deleted file mode 100644 index f8e77f6..0000000 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/Views/Shared/TicketTailor/TicketTailorNav.cshtml +++ /dev/null @@ -1,17 +0,0 @@ -@using BTCPayServer.Plugins.TicketTailor -@inject IScopeProvider ScopeProvider -@using BTCPayServer.Abstractions.Contracts -@{ - var storeId = ScopeProvider.GetCurrentStoreId(); - var isActive = !string.IsNullOrEmpty(storeId) && ViewContext.RouteData.Values.TryGetValue("Controller", out var controller) && controller is not null && - nameof(TicketTailorController).StartsWith(controller?.ToString(), StringComparison.InvariantCultureIgnoreCase); -} -@if (!string.IsNullOrEmpty(storeId)) -{ - -} diff --git a/Plugins/BTCPayServer.Plugins.TicketTailor/Views/TicketTailor/Receipt.cshtml b/Plugins/BTCPayServer.Plugins.TicketTailor/Views/TicketTailor/Receipt.cshtml index 66887ff..4735def 100644 --- a/Plugins/BTCPayServer.Plugins.TicketTailor/Views/TicketTailor/Receipt.cshtml +++ b/Plugins/BTCPayServer.Plugins.TicketTailor/Views/TicketTailor/Receipt.cshtml @@ -1,12 +1,6 @@ @using BTCPayServer.Client.Models @model BTCPayServer.Plugins.TicketTailor.TicketTailorController.TicketReceiptPage -@inject ContentSecurityPolicies contentSecurityPolicies -@using BTCPayServer.Security -@using NBitcoin @{ - var nonce = RandomUtils.GetUInt256().ToString().Substring(0, 32); - contentSecurityPolicies.Add("script-src", $"'nonce-{nonce}'"); - contentSecurityPolicies.AllowUnsafeHashes(); Layout = "_LayoutSimple"; var reloadPage = false; } @@ -162,14 +156,14 @@ @if (reloadPage) { - } -