From 0929857b12129b61320a98ac92c050a439eba018 Mon Sep 17 00:00:00 2001 From: Nicolas Dorier Date: Tue, 5 Jan 2021 12:38:12 +0900 Subject: [PATCH] Attempt to solve webhooks disappearing (#2178) --- .../GreenField/StoreWebhooksController.cs | 65 ++++++++----------- .../WebhookNotificationManager.cs | 6 +- .../Services/Stores/StoreRepository.cs | 36 ++++++++-- 3 files changed, 64 insertions(+), 43 deletions(-) diff --git a/BTCPayServer/Controllers/GreenField/StoreWebhooksController.cs b/BTCPayServer/Controllers/GreenField/StoreWebhooksController.cs index fc1b0ca26..2a0c34f65 100644 --- a/BTCPayServer/Controllers/GreenField/StoreWebhooksController.cs +++ b/BTCPayServer/Controllers/GreenField/StoreWebhooksController.cs @@ -36,36 +36,39 @@ namespace BTCPayServer.Controllers.GreenField public WebhookNotificationManager WebhookNotificationManager { get; } [HttpGet("~/api/v1/stores/{storeId}/webhooks/{webhookId?}")] - public async Task ListWebhooks(string storeId, string webhookId) + public async Task ListWebhooks(string webhookId) { if (webhookId is null) { - var store = HttpContext.GetStoreData(); - if (store == null) - return NotFound(); - return Ok((await StoreRepository.GetWebhooks(storeId)) + return Ok((await StoreRepository.GetWebhooks(CurrentStoreId)) .Select(o => FromModel(o, false)) .ToList()); } else { - var w = await StoreRepository.GetWebhook(storeId, webhookId); + var w = await StoreRepository.GetWebhook(CurrentStoreId, webhookId); if (w is null) return NotFound(); return Ok(FromModel(w, false)); } } - [HttpPost("~/api/v1/stores/{storeId}/webhooks")] - public async Task CreateWebhook(string storeId, Client.Models.CreateStoreWebhookRequest create) + + string CurrentStoreId + { + get + { + return this.HttpContext.GetStoreData()?.Id; + } + } + + [HttpPost("~/api/v1/stores/{storeId}/webhooks")] + public async Task CreateWebhook(Client.Models.CreateStoreWebhookRequest create) { - var store = HttpContext.GetStoreData(); - if (store == null) - return NotFound(); ValidateWebhookRequest(create); if (!ModelState.IsValid) return this.CreateValidationError(ModelState); - var webhookId = await StoreRepository.CreateWebhook(storeId, ToModel(create)); - var w = await StoreRepository.GetWebhook(storeId, webhookId); + var webhookId = await StoreRepository.CreateWebhook(CurrentStoreId, ToModel(create)); + var w = await StoreRepository.GetWebhook(CurrentStoreId, webhookId); if (w is null) return NotFound(); return Ok(FromModel(w, true)); @@ -83,25 +86,19 @@ namespace BTCPayServer.Controllers.GreenField ValidateWebhookRequest(update); if (!ModelState.IsValid) return this.CreateValidationError(ModelState); - var store = HttpContext.GetStoreData(); - if (store == null) - return NotFound(); - var w = await StoreRepository.GetWebhook(storeId, webhookId); + var w = await StoreRepository.GetWebhook(CurrentStoreId, webhookId); if (w is null) return NotFound(); await StoreRepository.UpdateWebhook(storeId, webhookId, ToModel(update)); - return await ListWebhooks(storeId, webhookId); + return await ListWebhooks(webhookId); } [HttpDelete("~/api/v1/stores/{storeId}/webhooks/{webhookId}")] - public async Task DeleteWebhook(string storeId, string webhookId) + public async Task DeleteWebhook(string webhookId) { - var store = HttpContext.GetStoreData(); - if (store == null) - return NotFound(); - var w = await StoreRepository.GetWebhook(storeId, webhookId); + var w = await StoreRepository.GetWebhook(CurrentStoreId, webhookId); if (w is null) return NotFound(); - await StoreRepository.DeleteWebhook(storeId, webhookId); + await StoreRepository.DeleteWebhook(CurrentStoreId, webhookId); return Ok(); } private WebhookBlob ToModel(StoreWebhookBaseData create) @@ -124,41 +121,35 @@ namespace BTCPayServer.Controllers.GreenField [HttpGet("~/api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId?}")] - public async Task ListDeliveries(string storeId, string webhookId, string deliveryId, int? count = null) + public async Task ListDeliveries(string webhookId, string deliveryId, int? count = null) { if (deliveryId is null) { - var store = HttpContext.GetStoreData(); - if (store == null) - return NotFound(); - return Ok((await StoreRepository.GetWebhookDeliveries(storeId, webhookId, count)) + return Ok((await StoreRepository.GetWebhookDeliveries(CurrentStoreId, webhookId, count)) .Select(o => FromModel(o)) .ToList()); } else { - var delivery = await StoreRepository.GetWebhookDelivery(storeId, webhookId, deliveryId); + var delivery = await StoreRepository.GetWebhookDelivery(CurrentStoreId, webhookId, deliveryId); if (delivery is null) return NotFound(); return Ok(FromModel(delivery)); } } [HttpPost("~/api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver")] - public async Task RedeliverWebhook(string storeId, string webhookId, string deliveryId) + public async Task RedeliverWebhook(string webhookId, string deliveryId) { - var delivery = await StoreRepository.GetWebhookDelivery(HttpContext.GetStoreData().Id, webhookId, deliveryId); + var delivery = await StoreRepository.GetWebhookDelivery(CurrentStoreId, webhookId, deliveryId); if (delivery is null) return NotFound(); return this.Ok(new JValue(await WebhookNotificationManager.Redeliver(deliveryId))); } [HttpGet("~/api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}/request")] - public async Task GetDeliveryRequest(string storeId, string webhookId, string deliveryId) + public async Task GetDeliveryRequest(string webhookId, string deliveryId) { - var store = HttpContext.GetStoreData(); - if (store == null) - return NotFound(); - var delivery = await StoreRepository.GetWebhookDelivery(storeId, webhookId, deliveryId); + var delivery = await StoreRepository.GetWebhookDelivery(CurrentStoreId, webhookId, deliveryId); if (delivery is null) return NotFound(); return File(delivery.GetBlob().Request, "application/json"); diff --git a/BTCPayServer/HostedServices/WebhookNotificationManager.cs b/BTCPayServer/HostedServices/WebhookNotificationManager.cs index f027e8961..3e9b698df 100644 --- a/BTCPayServer/HostedServices/WebhookNotificationManager.cs +++ b/BTCPayServer/HostedServices/WebhookNotificationManager.cs @@ -86,6 +86,8 @@ namespace BTCPayServer.HostedServices public async Task Redeliver(string deliveryId) { var deliveryRequest = await CreateRedeliveryRequest(deliveryId); + if (deliveryRequest is null) + return null; EnqueueDelivery(deliveryRequest); return deliveryRequest.Delivery.Id; } @@ -208,8 +210,8 @@ namespace BTCPayServer.HostedServices try { var ctx = originalCtx; - var wh = (await StoreRepository.GetWebhook(ctx.WebhookId)).GetBlob(); - if (!ShouldDeliver(ctx.WebhookEvent.Type, wh)) + var wh = (await StoreRepository.GetWebhook(ctx.WebhookId))?.GetBlob(); + if (wh is null || !ShouldDeliver(ctx.WebhookEvent.Type, wh)) continue; var result = await SendDelivery(ctx); if (ctx.WebhookBlob.AutomaticRedelivery && diff --git a/BTCPayServer/Services/Stores/StoreRepository.cs b/BTCPayServer/Services/Stores/StoreRepository.cs index b62d3cd27..57c165afc 100644 --- a/BTCPayServer/Services/Stores/StoreRepository.cs +++ b/BTCPayServer/Services/Stores/StoreRepository.cs @@ -206,6 +206,10 @@ namespace BTCPayServer.Services.Stores public async Task GetWebhookDelivery(string storeId, string webhookId, string deliveryId) { + if (webhookId == null) + throw new ArgumentNullException(nameof(webhookId)); + if (storeId == null) + throw new ArgumentNullException(nameof(storeId)); using var ctx = _ContextFactory.CreateContext(); return await ctx.StoreWebhooks .Where(d => d.StoreId == storeId && d.WebhookId == webhookId) @@ -232,6 +236,10 @@ namespace BTCPayServer.Services.Stores public async Task GetWebhookDeliveries(string storeId, string webhookId, int? count) { + if (webhookId == null) + throw new ArgumentNullException(nameof(webhookId)); + if (storeId == null) + throw new ArgumentNullException(nameof(storeId)); using var ctx = _ContextFactory.CreateContext(); IQueryable req = ctx.StoreWebhooks .Where(s => s.StoreId == storeId && s.WebhookId == webhookId) @@ -245,6 +253,10 @@ namespace BTCPayServer.Services.Stores public async Task CreateWebhook(string storeId, WebhookBlob blob) { + if (storeId == null) + throw new ArgumentNullException(nameof(storeId)); + if (blob == null) + throw new ArgumentNullException(nameof(blob)); using var ctx = _ContextFactory.CreateContext(); WebhookData data = new WebhookData(); data.Id = Encoders.Base58.EncodeData(RandomUtils.GetBytes(16)); @@ -262,7 +274,11 @@ namespace BTCPayServer.Services.Stores public async Task GetWebhook(string storeId, string webhookId) { - var ctx = _ContextFactory.CreateContext(); + if (webhookId == null) + throw new ArgumentNullException(nameof(webhookId)); + if (storeId == null) + throw new ArgumentNullException(nameof(storeId)); + using var ctx = _ContextFactory.CreateContext(); return await ctx.StoreWebhooks .Where(s => s.StoreId == storeId && s.WebhookId == webhookId) .Select(s => s.Webhook) @@ -270,7 +286,9 @@ namespace BTCPayServer.Services.Stores } public async Task GetWebhook(string webhookId) { - var ctx = _ContextFactory.CreateContext(); + if (webhookId == null) + throw new ArgumentNullException(nameof(webhookId)); + using var ctx = _ContextFactory.CreateContext(); return await ctx.StoreWebhooks .Where(s => s.WebhookId == webhookId) .Select(s => s.Webhook) @@ -278,7 +296,11 @@ namespace BTCPayServer.Services.Stores } public async Task DeleteWebhook(string storeId, string webhookId) { - var ctx = _ContextFactory.CreateContext(); + if (webhookId == null) + throw new ArgumentNullException(nameof(webhookId)); + if (storeId == null) + throw new ArgumentNullException(nameof(storeId)); + using var ctx = _ContextFactory.CreateContext(); var hook = await ctx.StoreWebhooks .Where(s => s.StoreId == storeId && s.WebhookId == webhookId) .Select(s => s.Webhook) @@ -291,7 +313,13 @@ namespace BTCPayServer.Services.Stores public async Task UpdateWebhook(string storeId, string webhookId, WebhookBlob webhookBlob) { - var ctx = _ContextFactory.CreateContext(); + if (webhookId == null) + throw new ArgumentNullException(nameof(webhookId)); + if (storeId == null) + throw new ArgumentNullException(nameof(storeId)); + if (webhookBlob == null) + throw new ArgumentNullException(nameof(webhookBlob)); + using var ctx = _ContextFactory.CreateContext(); var hook = await ctx.StoreWebhooks .Where(s => s.StoreId == storeId && s.WebhookId == webhookId) .Select(s => s.Webhook)