Skip to content

Commit 4649c65

Browse files
committed
Fixed some issues around creating webhooks and improved webhook validation that were introduced with the .NET 8 upgrade
1 parent 41285f0 commit 4649c65

File tree

14 files changed

+169
-50
lines changed

14 files changed

+169
-50
lines changed

src/Exceptionless.Core/Models/WebHook.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,20 @@ public static class KnownVersions
2424
public const string Version1 = "v1";
2525
public const string Version2 = "v2";
2626
}
27+
28+
public static readonly string[] AllKnownEventTypes = new[]
29+
{
30+
KnownEventTypes.NewError, KnownEventTypes.CriticalError, KnownEventTypes.NewEvent,
31+
KnownEventTypes.CriticalEvent, KnownEventTypes.StackRegression, KnownEventTypes.StackPromoted
32+
};
33+
34+
public static class KnownEventTypes
35+
{
36+
public const string NewError = "NewError";
37+
public const string CriticalError = "CriticalError";
38+
public const string NewEvent = "NewEvent";
39+
public const string CriticalEvent = "CriticalEvent";
40+
public const string StackRegression = "StackRegression";
41+
public const string StackPromoted = "StackPromoted";
42+
}
2743
}

src/Exceptionless.Core/Pipeline/070_QueueNotificationAction.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,19 @@ private bool ShouldCallWebHook(WebHook hook, EventContext ctx)
8080
if (!String.IsNullOrEmpty(hook.ProjectId) && !String.Equals(ctx.Project.Id, hook.ProjectId))
8181
return false;
8282

83-
if (ctx.IsNew && ctx.Event.IsError() && hook.EventTypes.Contains(WebHookRepository.EventTypes.NewError))
83+
if (ctx.IsNew && ctx.Event.IsError() && hook.EventTypes.Contains(WebHook.KnownEventTypes.NewError))
8484
return true;
8585

86-
if (ctx.Event.IsCritical() && ctx.Event.IsError() && hook.EventTypes.Contains(WebHookRepository.EventTypes.CriticalError))
86+
if (ctx.Event.IsCritical() && ctx.Event.IsError() && hook.EventTypes.Contains(WebHook.KnownEventTypes.CriticalError))
8787
return true;
8888

89-
if (ctx.IsRegression && hook.EventTypes.Contains(WebHookRepository.EventTypes.StackRegression))
89+
if (ctx.IsRegression && hook.EventTypes.Contains(WebHook.KnownEventTypes.StackRegression))
9090
return true;
9191

92-
if (ctx.IsNew && hook.EventTypes.Contains(WebHookRepository.EventTypes.NewEvent))
92+
if (ctx.IsNew && hook.EventTypes.Contains(WebHook.KnownEventTypes.NewEvent))
9393
return true;
9494

95-
if (ctx.Event.IsCritical() && hook.EventTypes.Contains(WebHookRepository.EventTypes.CriticalEvent))
95+
if (ctx.Event.IsCritical() && hook.EventTypes.Contains(WebHook.KnownEventTypes.CriticalEvent))
9696
return true;
9797

9898
return false;

src/Exceptionless.Core/Repositories/WebHookRepository.cs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,6 @@ public async Task MarkDisabledAsync(string id)
4343
await SaveAsync(webHook, o => o.Cache()).AnyContext();
4444
}
4545

46-
public static class EventTypes
47-
{
48-
// TODO: Add support for these new web hook types.
49-
public const string NewError = "NewError";
50-
public const string CriticalError = "CriticalError";
51-
public const string NewEvent = "NewEvent";
52-
public const string CriticalEvent = "CriticalEvent";
53-
public const string StackRegression = "StackRegression";
54-
public const string StackPromoted = "StackPromoted";
55-
}
5646

5747
protected override async Task InvalidateCacheAsync(IReadOnlyCollection<ModifiedDocument<WebHook>> documents, ChangeType? changeType = null)
5848
{

src/Exceptionless.Core/Validation/WebHookValidator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public WebHookValidator()
1212
RuleFor(w => w.ProjectId).IsObjectId().When(p => String.IsNullOrEmpty(p.OrganizationId)).WithMessage("Please specify a valid project id.");
1313
RuleFor(w => w.Url).NotEmpty().WithMessage("Please specify a valid url.");
1414
RuleFor(w => w.EventTypes).NotEmpty().WithMessage("Please specify one or more event types.");
15+
RuleForEach(w => w.EventTypes).Must(et => WebHook.AllKnownEventTypes.Contains(et)).WithMessage("Please specify a valid event type.");
1516
RuleFor(w => w.Version).NotEmpty().WithMessage("Please specify a valid version.");
1617
}
1718
}

src/Exceptionless.Web/ClientApp.angular/app/project/manage/manage-controller.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
return dialogs
8585
.create("components/web-hook/add-web-hook-dialog.tpl.html", "AddWebHookDialog as vm")
8686
.result.then(function (data) {
87+
data.organization_id = vm.project.organization_id;
8788
data.project_id = vm._projectId;
8889
return createWebHook(data);
8990
})

src/Exceptionless.Web/Controllers/StackController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ public async Task<IActionResult> PromoteAsync(string id)
392392
if (!await _billingManager.HasPremiumFeaturesAsync(stack.OrganizationId))
393393
return PlanLimitReached("Promote to External is a premium feature used to promote an error stack to an external system. Please upgrade your plan to enable this feature.");
394394

395-
var promotedProjectHooks = (await _webHookRepository.GetByProjectIdAsync(stack.ProjectId)).Documents.Where(p => p.EventTypes.Contains(WebHookRepository.EventTypes.StackPromoted)).ToList();
395+
var promotedProjectHooks = (await _webHookRepository.GetByProjectIdAsync(stack.ProjectId)).Documents.Where(p => p.EventTypes.Contains(WebHook.KnownEventTypes.StackPromoted)).ToList();
396396
if (!promotedProjectHooks.Any())
397397
return NotImplemented("No promoted web hooks are configured for this project. Please add a promoted web hook to use this feature.");
398398

src/Exceptionless.Web/Controllers/WebHookController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace Exceptionless.App.Controllers.API;
1717

1818
[Route(API_PREFIX + "/webhooks")]
1919
[Authorize(Policy = AuthorizationRoles.ClientPolicy)]
20-
public class WebHookController : RepositoryApiController<IWebHookRepository, WebHook, WebHook, NewWebHook, UpdateWebHook>
20+
public class WebHookController : RepositoryApiController<IWebHookRepository, WebHook, WebHook, NewWebHook, WebHook>
2121
{
2222
private readonly IProjectRepository _projectRepository;
2323
private readonly BillingManager _billingManager;

src/Exceptionless.Web/Models/WebHook/NewWebHook.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ public record NewWebHook : IOwnedByOrganizationAndProject
1212
/// <summary>
1313
/// The schema version that should be used.
1414
/// </summary>
15-
public Version Version { get; set; } = null!;
15+
public Version? Version { get; set; }
1616
}

src/Exceptionless.Web/Models/WebHook/UpdateWebHook.cs

Lines changed: 0 additions & 6 deletions
This file was deleted.

src/Exceptionless.Web/Utility/AutoValidationActionFilter.cs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Dynamic;
12
using System.IO.Pipelines;
23
using System.Security.Claims;
34
using Exceptionless.Core.Extensions;
@@ -32,7 +33,7 @@ public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionE
3233
continue;
3334

3435
// We don't support validating JSON Types
35-
if (subject is Newtonsoft.Json.Linq.JToken)
36+
if (subject is Newtonsoft.Json.Linq.JToken or DynamicObject)
3637
continue;
3738

3839
(bool isValid, var errors) = await MiniValidator.TryValidateAsync(subject, _serviceProvider, recurse: true);
@@ -55,28 +56,28 @@ public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionE
5556

5657
if (hasErrors)
5758
{
58-
var validationProblem = controllerBase.ProblemDetailsFactory.CreateValidationProblemDetails(context.HttpContext, context.ModelState, 422);
59-
context.Result = new UnprocessableEntityObjectResult(validationProblem);
59+
var validationProblem = controllerBase.ProblemDetailsFactory.CreateValidationProblemDetails(context.HttpContext, context.ModelState, 422);
60+
context.Result = new UnprocessableEntityObjectResult(validationProblem);
6061

61-
return;
62-
}
62+
return;
6363
}
64-
65-
await next();
6664
}
6765

68-
private static bool ShouldValidate(Type type, IServiceProviderIsService? isService = null) =>
69-
!IsNonValidatedType(type, isService) && MiniValidator.RequiresValidation(type);
66+
await next();
67+
}
68+
69+
private static bool ShouldValidate(Type type, IServiceProviderIsService? isService = null) =>
70+
!IsNonValidatedType(type, isService) && MiniValidator.RequiresValidation(type);
7071

71-
private static bool IsNonValidatedType(Type type, IServiceProviderIsService? isService) =>
72-
typeof(HttpContext) == type
73-
|| typeof(HttpRequest) == type
74-
|| typeof(HttpResponse) == type
75-
|| typeof(ClaimsPrincipal) == type
76-
|| typeof(CancellationToken) == type
77-
|| typeof(IFormFileCollection) == type
78-
|| typeof(IFormFile) == type
79-
|| typeof(Stream) == type
80-
|| typeof(PipeReader) == type
81-
|| isService?.IsService(type) == true;
72+
private static bool IsNonValidatedType(Type type, IServiceProviderIsService? isService) =>
73+
typeof(HttpContext) == type
74+
|| typeof(HttpRequest) == type
75+
|| typeof(HttpResponse) == type
76+
|| typeof(ClaimsPrincipal) == type
77+
|| typeof(CancellationToken) == type
78+
|| typeof(IFormFileCollection) == type
79+
|| typeof(IFormFile) == type
80+
|| typeof(Stream) == type
81+
|| typeof(PipeReader) == type
82+
|| isService?.IsService(type) == true;
8283
}

0 commit comments

Comments
 (0)