From 66f2b60141d623adcd548bedf622930d4eda338a Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Tue, 7 Jan 2025 11:18:32 +0100 Subject: [PATCH] V15: Add webhooklogs endpoint (#17838) * Add webhook logs endpoint * Add attribute routing * Add to open api json --- .../Webhook/Logs/AllWebhookLogController.cs | 34 +++++++++ .../Webhook/Logs/WebhookLogControllerBase.cs | 9 +++ .../Factories/IWebhookPresentationFactory.cs | 4 +- .../Factories/WebhookPresentationFactory.cs | 43 ++++++++++- src/Umbraco.Cms.Api.Management/OpenApi.json | 72 ++++++++++++++++++- .../Webhook/Logs/WebhookLogResponseModel.cs | 30 ++++++++ 6 files changed, 187 insertions(+), 5 deletions(-) create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/Webhook/Logs/AllWebhookLogController.cs create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/Webhook/Logs/WebhookLogControllerBase.cs create mode 100644 src/Umbraco.Cms.Api.Management/ViewModels/Webhook/Logs/WebhookLogResponseModel.cs diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Webhook/Logs/AllWebhookLogController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Webhook/Logs/AllWebhookLogController.cs new file mode 100644 index 0000000000..a40b9d4e6a --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/Webhook/Logs/AllWebhookLogController.cs @@ -0,0 +1,34 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.Factories; +using Umbraco.Cms.Api.Management.ViewModels.Webhook; +using Umbraco.Cms.Api.Management.ViewModels.Webhook.Logs; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Api.Management.Controllers.Webhook.Logs; + +[ApiVersion("1.0")] +public class AllWebhookLogController : WebhookLogControllerBase +{ + private readonly IWebhookLogService _webhookLogService; + private readonly IWebhookPresentationFactory _webhookPresentationFactory; + + public AllWebhookLogController(IWebhookLogService webhookLogService, IWebhookPresentationFactory webhookPresentationFactory) + { + _webhookLogService = webhookLogService; + _webhookPresentationFactory = webhookPresentationFactory; + } + + [HttpGet("logs")] + [MapToApiVersion("1.0")] + [ProducesResponseType(typeof(WebhookResponseModel), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] + public async Task Logs(CancellationToken cancellationToken, int skip = 0, int take = 100) + { + PagedModel logs = await _webhookLogService.Get(skip, take); + IEnumerable logResponseModels = logs.Items.Select(x => _webhookPresentationFactory.CreateResponseModel(x)); + return Ok(logResponseModels); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Webhook/Logs/WebhookLogControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Webhook/Logs/WebhookLogControllerBase.cs new file mode 100644 index 0000000000..84888184ab --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/Webhook/Logs/WebhookLogControllerBase.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.Routing; +using Umbraco.Cms.Core; + +namespace Umbraco.Cms.Api.Management.Controllers.Webhook.Logs; + +[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.Webhook}")] +[ApiExplorerSettings(GroupName = "Webhook")] +public class WebhookLogControllerBase : ManagementApiControllerBase; diff --git a/src/Umbraco.Cms.Api.Management/Factories/IWebhookPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/IWebhookPresentationFactory.cs index 421115c832..7c63abd6f7 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/IWebhookPresentationFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/IWebhookPresentationFactory.cs @@ -1,6 +1,6 @@ using Umbraco.Cms.Api.Management.ViewModels.Webhook; +using Umbraco.Cms.Api.Management.ViewModels.Webhook.Logs; using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Web.Common.Models; namespace Umbraco.Cms.Api.Management.Factories; @@ -11,4 +11,6 @@ public interface IWebhookPresentationFactory IWebhook CreateWebhook(CreateWebhookRequestModel webhookRequestModel); IWebhook CreateWebhook(UpdateWebhookRequestModel webhookRequestModel, Guid existingWebhookKey); + + WebhookLogResponseModel CreateResponseModel(WebhookLog webhookLog) => new(); } diff --git a/src/Umbraco.Cms.Api.Management/Factories/WebhookPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/WebhookPresentationFactory.cs index 49a52f53e7..491b235664 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/WebhookPresentationFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/WebhookPresentationFactory.cs @@ -1,6 +1,9 @@ using Umbraco.Cms.Api.Management.ViewModels.Webhook; +using Umbraco.Cms.Api.Management.ViewModels.Webhook.Logs; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Webhooks; namespace Umbraco.Cms.Api.Management.Factories; @@ -8,8 +11,18 @@ namespace Umbraco.Cms.Api.Management.Factories; internal class WebhookPresentationFactory : IWebhookPresentationFactory { private readonly WebhookEventCollection _webhookEventCollection; + private readonly IHostingEnvironment _hostingEnvironment; + private readonly ILocalizedTextService _localizedTextService; - public WebhookPresentationFactory(WebhookEventCollection webhookEventCollection) => _webhookEventCollection = webhookEventCollection; + public WebhookPresentationFactory( + WebhookEventCollection webhookEventCollection, + IHostingEnvironment hostingEnvironment, + ILocalizedTextService localizedTextService) + { + _webhookEventCollection = webhookEventCollection; + _hostingEnvironment = hostingEnvironment; + _localizedTextService = localizedTextService; + } public WebhookResponseModel CreateResponseModel(IWebhook webhook) { @@ -44,6 +57,34 @@ internal class WebhookPresentationFactory : IWebhookPresentationFactory return target; } + public WebhookLogResponseModel CreateResponseModel(WebhookLog webhookLog) + { + var webhookLogResponseModel = new WebhookLogResponseModel + { + Date = webhookLog.Date, EventAlias = webhookLog.EventAlias, Key = webhookLog.Key, RequestBody = webhookLog.RequestBody ?? string.Empty, + RetryCount = webhookLog.RetryCount, + Url = webhookLog.Url, + RequestHeaders = webhookLog.RequestHeaders, + WebhookKey = webhookLog.WebhookKey, + IsSuccessStatusCode = webhookLog.IsSuccessStatusCode + }; + + if (_hostingEnvironment.IsDebugMode) + { + webhookLogResponseModel.ExceptionOccured = webhookLog.ExceptionOccured; + webhookLogResponseModel.ResponseBody = webhookLog.ResponseBody; + webhookLogResponseModel.ResponseHeaders = webhookLog.ResponseHeaders; + webhookLogResponseModel.StatusCode = webhookLog.StatusCode; + } + else + { + webhookLogResponseModel.ResponseBody = _localizedTextService.Localize("webhooks", "toggleDebug", Thread.CurrentThread.CurrentUICulture); + webhookLogResponseModel.StatusCode = webhookLog.StatusCode is "OK (200)" ? webhookLog.StatusCode : _localizedTextService.Localize("webhooks", "statusNotOk", Thread.CurrentThread.CurrentUICulture); + } + + return webhookLogResponseModel; + } + private WebhookEventResponseModel Create(string alias) { IWebhookEvent? webhookEvent = _webhookEventCollection.FirstOrDefault(x => x.Alias == alias); diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index a6f3db0530..7042802f04 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -33875,6 +33875,72 @@ } ] } + }, + "/umbraco/management/api/v1/webhook/logs": { + "get": { + "tags": [ + "Webhook" + ], + "operationId": "GetWebhookLogs", + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/WebhookResponseModel" + } + ] + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/ProblemDetails" + } + ] + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } } }, "components": { @@ -38339,8 +38405,8 @@ "enum": [ "Healthy", "Unhealthy", - "Corrupt", - "Rebuilding" + "Rebuilding", + "Corrupt" ], "type": "string" }, @@ -46100,4 +46166,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Webhook/Logs/WebhookLogResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Webhook/Logs/WebhookLogResponseModel.cs new file mode 100644 index 0000000000..fab5ee4c12 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Webhook/Logs/WebhookLogResponseModel.cs @@ -0,0 +1,30 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.Webhook.Logs; + +public class WebhookLogResponseModel +{ + public Guid Key { get; set; } + + public Guid WebhookKey { get; set; } + + public string StatusCode { get; set; } = string.Empty; + + public bool IsSuccessStatusCode { get; set; } + + public DateTime Date { get; set; } + + public string EventAlias { get; set; } = string.Empty; + + public string Url { get; set; } = string.Empty; + + public int RetryCount { get; set; } + + public string RequestHeaders { get; set; } = string.Empty; + + public string RequestBody { get; set; } = string.Empty; + + public string ResponseHeaders { get; set; } = string.Empty; + + public string ResponseBody { get; set; } = string.Empty; + + public bool ExceptionOccured { get; set; } +}