mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2026-02-08 15:54:20 +01:00
Triggering webhook for pending transaction events
Adding Cancelled event as well
This commit is contained in:
@@ -1,15 +1,17 @@
|
||||
using System.Globalization;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Controllers;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using WebhookDeliveryData = BTCPayServer.Data.WebhookDeliveryData;
|
||||
|
||||
namespace BTCPayServer.HostedServices.Webhooks;
|
||||
|
||||
public class PendingTransactionDeliveryRequest(
|
||||
PendingTransaction pendingTransaction,
|
||||
PendingTransactionService.PendingTransactionEvent evt,
|
||||
string webhookId,
|
||||
WebhookEvent webhookEvent,
|
||||
WebhookDeliveryData delivery,
|
||||
@@ -19,6 +21,7 @@ public class PendingTransactionDeliveryRequest(
|
||||
public override Task<SendEmailRequest> Interpolate(SendEmailRequest req,
|
||||
UIStoresController.StoreEmailRule storeEmailRule)
|
||||
{
|
||||
var blob = evt.Data.GetBlob();
|
||||
// if (storeEmailRule.CustomerEmail &&
|
||||
// MailboxAddressValidator.TryParse(Invoice.Metadata.BuyerEmail, out var bmb))
|
||||
// {
|
||||
@@ -26,20 +29,18 @@ public class PendingTransactionDeliveryRequest(
|
||||
// req.Email += $",{bmb}";
|
||||
// }
|
||||
|
||||
req.Subject = Interpolate(req.Subject);
|
||||
req.Body = Interpolate(req.Body);
|
||||
req.Subject = Interpolate(req.Subject, blob);
|
||||
req.Body = Interpolate(req.Body, blob);
|
||||
return Task.FromResult(req);
|
||||
}
|
||||
|
||||
private string Interpolate(string str)
|
||||
private string Interpolate(string str, PendingTransactionBlob blob)
|
||||
{
|
||||
var res = str.Replace("{PendingTransaction.Id}", pendingTransaction.TransactionId);
|
||||
// .Replace("{Invoice.StoreId}", Invoice.StoreId)
|
||||
// .Replace("{Invoice.Price}", Invoice.Price.ToString(CultureInfo.InvariantCulture))
|
||||
// .Replace("{Invoice.Currency}", Invoice.Currency)
|
||||
// .Replace("{Invoice.Status}", Invoice.Status.ToString())
|
||||
// .Replace("{Invoice.AdditionalStatus}", Invoice.ExceptionStatus.ToString())
|
||||
// .Replace("{Invoice.OrderId}", Invoice.Metadata.OrderId);
|
||||
var res = str.Replace("{PendingTransaction.Id}", evt.Data.TransactionId)
|
||||
.Replace("{PendingTransaction.StoreId}", evt.Data.StoreId)
|
||||
.Replace("{PendingTransaction.SignaturesCollected}", blob.SignaturesCollected?.ToString())
|
||||
.Replace("{PendingTransaction.SignaturesNeeded}", blob.SignaturesNeeded?.ToString())
|
||||
.Replace("{PendingTransaction.SignaturesTotal}", blob.SignaturesTotal?.ToString());
|
||||
|
||||
// res = InterpolateJsonField(res, "Invoice.Metadata", Invoice.Metadata.ToJObject());
|
||||
return res;
|
||||
|
||||
@@ -23,6 +23,7 @@ public class PendingTransactionWebhookProvider : WebhookProvider<PendingTransact
|
||||
public const string PendingTransactionCreated = nameof(PendingTransactionCreated);
|
||||
public const string PendingTransactionSignatureCollected = nameof(PendingTransactionSignatureCollected);
|
||||
public const string PendingTransactionBroadcast = nameof(PendingTransactionBroadcast);
|
||||
public const string PendingTransactionCancelled = nameof(PendingTransactionCancelled);
|
||||
|
||||
public override Dictionary<string, string> GetSupportedWebhookTypes()
|
||||
{
|
||||
@@ -30,7 +31,8 @@ public class PendingTransactionWebhookProvider : WebhookProvider<PendingTransact
|
||||
{
|
||||
{PendingTransactionCreated, "Pending Transaction - Created"},
|
||||
{PendingTransactionSignatureCollected, "Pending Transaction - Signature Collected"},
|
||||
{PendingTransactionBroadcast, "Pending Transaction - Broadcast"}
|
||||
{PendingTransactionBroadcast, "Pending Transaction - Broadcast"},
|
||||
{PendingTransactionCancelled, "Pending Transaction - Cancelled"}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -50,7 +52,7 @@ public class PendingTransactionWebhookProvider : WebhookProvider<PendingTransact
|
||||
webhookEvent.OriginalDeliveryId = delivery.Id;
|
||||
webhookEvent.Timestamp = delivery.Timestamp;
|
||||
}
|
||||
return new PendingTransactionDeliveryRequest(evt.Data, webhook?.Id, webhookEvent, delivery, webhookBlob);
|
||||
return new PendingTransactionDeliveryRequest(evt, webhook?.Id, webhookEvent, delivery, webhookBlob);
|
||||
}
|
||||
|
||||
protected override WebhookPendingTransactionEvent GetWebhookEvent(PendingTransactionService.PendingTransactionEvent evt)
|
||||
@@ -63,6 +65,8 @@ public class PendingTransactionWebhookProvider : WebhookProvider<PendingTransact
|
||||
PendingTransactionSignatureCollected, evt.Data.StoreId),
|
||||
PendingTransactionService.PendingTransactionEvent.Broadcast => new WebhookPendingTransactionEvent(
|
||||
PendingTransactionBroadcast, evt.Data.StoreId),
|
||||
PendingTransactionService.PendingTransactionEvent.Cancelled => new WebhookPendingTransactionEvent(
|
||||
PendingTransactionCancelled, evt.Data.StoreId),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ public static class WebhookExtensions
|
||||
services.AddSingleton<PaymentRequestWebhookProvider>();
|
||||
services.AddSingleton<IWebhookProvider>(o => o.GetRequiredService<PaymentRequestWebhookProvider>());
|
||||
services.AddHostedService(o => o.GetRequiredService<PaymentRequestWebhookProvider>());
|
||||
|
||||
services.AddSingleton<PendingTransactionWebhookProvider>();
|
||||
services.AddSingleton<IWebhookProvider>(o => o.GetRequiredService<PendingTransactionWebhookProvider>());
|
||||
services.AddHostedService(o => o.GetRequiredService<PendingTransactionWebhookProvider>());
|
||||
|
||||
services.AddSingleton<WebhookSender>();
|
||||
services.AddSingleton<IHostedService, WebhookSender>(o => o.GetRequiredService<WebhookSender>());
|
||||
|
||||
@@ -354,8 +354,8 @@ namespace BTCPayServer.Hosting
|
||||
services.TryAddSingleton<PaymentRequestRepository>();
|
||||
services.TryAddSingleton<BTCPayWalletProvider>();
|
||||
services.AddSingleton<PendingTransactionService>();
|
||||
services.AddSingleton<IWebhookProvider>(o => o.GetRequiredService<PendingTransactionWebhookProvider>());
|
||||
services.AddScheduledTask<PendingTransactionService>(TimeSpan.FromMinutes(10));
|
||||
// PendingTransactionWebhookProvider webhooks registered in WebhookExtensions
|
||||
services.TryAddSingleton<WalletReceiveService>();
|
||||
services.AddSingleton<IHostedService>(provider => provider.GetService<WalletReceiveService>());
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
@using BTCPayServer.HostedServices.Webhooks
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@model BTCPayServer.Controllers.UIStoresController.StoreEmailRule
|
||||
@inject Microsoft.AspNetCore.Http.IHttpContextAccessor context;
|
||||
@inject WebhookSender WebhookSender
|
||||
|
||||
@{
|
||||
var storeId = Context.GetStoreData().Id;
|
||||
bool isEdit = Model.Trigger != null;
|
||||
ViewData.SetActivePage(StoreNavPages.Emails, StringLocalizer[isEdit ? "Edit Email Rule" : "Create Email Rule"], storeId);
|
||||
var expectedScheme = context.HttpContext?.Request.Scheme;
|
||||
var expectedHost = context.HttpContext?.Request.Host.ToString().ToLower();
|
||||
var hostRoot = $"{expectedScheme}://{expectedHost}";
|
||||
}
|
||||
|
||||
@section PageHeadContent {
|
||||
@@ -104,6 +108,16 @@
|
||||
<code>{Payout.Metadata}*</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th text-translate="true">Pending Transaction</th>
|
||||
<td>
|
||||
<code>{PendingTransaction.Id}</code>,
|
||||
<code>{PendingTransaction.StoreId}</code>,
|
||||
<code>{PendingTransaction.SignaturesCollected}</code>,
|
||||
<code>{PendingTransaction.SignaturesNeeded}</code>,
|
||||
<code>{PendingTransaction.SignaturesTotal}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td colspan="2">* These fields are JSON objects. You can access properties within them using <a href="https://www.newtonsoft.com/json/help/html/SelectToken.htm#SelectTokenJSONPath" rel="noreferrer noopener" target="_blank">this syntax</a>. One example is <code>{Invoice.Metadata.itemCode}</code></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -145,6 +159,25 @@
|
||||
subject: 'Invoice {Invoice.Id} payment settled',
|
||||
body: 'Invoice {Invoice.Id} (Order Id: {Invoice.OrderId}) payment settled.'
|
||||
},
|
||||
@PendingTransactionWebhookProvider.PendingTransactionCreated : {
|
||||
subject: 'Pending Transaction {PendingTransaction.Id} Created',
|
||||
body: 'Review the transaction and sign it on: @hostRoot/wallets/S-{PendingTransaction.StoreId}-BTC/transactions'
|
||||
},
|
||||
@PendingTransactionWebhookProvider.PendingTransactionSignatureCollected : {
|
||||
subject: 'Signature Collected for Pending Transaction {PendingTransaction.Id}',
|
||||
body: 'So far {PendingTransaction.SignaturesCollected} signatures collected out of {PendingTransaction.SignaturesNeeded} signatures needed. ' +
|
||||
'Review the transaction and sign it on: @hostRoot/wallets/S-{PendingTransaction.StoreId}-BTC/transactions'
|
||||
},
|
||||
@PendingTransactionWebhookProvider.PendingTransactionBroadcast : {
|
||||
subject: 'Transaction {PendingTransaction.Id} has been Broadcast',
|
||||
body: 'Transaction is visible in mempool on: https://mempool.space/tx/{PendingTransaction.Id}. ' +
|
||||
'Review the transaction: @hostRoot/wallets/S-{PendingTransaction.StoreId}-BTC/transactions'
|
||||
},
|
||||
@PendingTransactionWebhookProvider.PendingTransactionCancelled : {
|
||||
subject: 'Pending Transaction {PendingTransaction.Id} Cancelled',
|
||||
body: 'Transaction {PendingTransaction.Id} is cancelled and signatures are no longer being collected. ' +
|
||||
'Review the wallet: @hostRoot/wallets/S-{PendingTransaction.StoreId}-BTC/transactions'
|
||||
},
|
||||
};
|
||||
|
||||
const triggerSelect = document.querySelector('.email-rule-trigger');
|
||||
|
||||
Reference in New Issue
Block a user