diff --git a/src/Exceptionless.Web/Controllers/EventController.cs b/src/Exceptionless.Web/Controllers/EventController.cs index b506b3679c..61e90da185 100644 --- a/src/Exceptionless.Web/Controllers/EventController.cs +++ b/src/Exceptionless.Web/Controllers/EventController.cs @@ -580,7 +580,7 @@ public async Task>> GetByReferenceIdAs var ti = GetTimeInfo(null, offset, organizations.GetRetentionUtcCutoff(_appOptions.MaximumRetentionDays, _timeProvider)); var sf = new AppFilter(organizations) { IsUserOrganizationsFilter = true }; - return await GetInternalAsync(sf, ti, String.Concat("reference:", referenceId), null, mode, page, limit, before, after, includeTotal: ShouldIncludeTotal(include)); + return await GetInternalAsync(sf, ti, $"(reference:{referenceId} OR ref.parent:{referenceId})", null, mode, page, limit, before, after, includeTotal: ShouldIncludeTotal(include)); } /// @@ -618,7 +618,7 @@ public async Task>> GetByReferenceIdAs var ti = GetTimeInfo(null, offset, organization.GetRetentionUtcCutoff(project, _appOptions.MaximumRetentionDays, _timeProvider)); var sf = new AppFilter(project, organization); - return await GetInternalAsync(sf, ti, String.Concat("reference:", referenceId), null, mode, page, limit, before, after, includeTotal: ShouldIncludeTotal(include)); + return await GetInternalAsync(sf, ti, $"(reference:{referenceId} OR ref.parent:{referenceId})", null, mode, page, limit, before, after, includeTotal: ShouldIncludeTotal(include)); } /// diff --git a/tests/Exceptionless.Tests/Controllers/EventControllerTests.cs b/tests/Exceptionless.Tests/Controllers/EventControllerTests.cs index dca6b4cfaa..910154054b 100644 --- a/tests/Exceptionless.Tests/Controllers/EventControllerTests.cs +++ b/tests/Exceptionless.Tests/Controllers/EventControllerTests.cs @@ -113,6 +113,33 @@ public async Task GetByReferenceIdAsync_WithExistingReference_ReturnsMatchingEve Assert.Equal(referenceId, ev.ReferenceId); } + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task GetByReferenceIdAsync_WithOnlyParentReference_ReturnsMatchingEvents(bool projectScoped) + { + // Arrange + string referenceId = Guid.NewGuid().ToString("N"); + await CreateDataAsync(d => d.Event().TestProject().Reference("parent", referenceId).Message("parent reference route")); + await RefreshDataAsync(); + + string[] paths = projectScoped + ? ["projects", SampleDataService.TEST_PROJECT_ID, "events", "by-ref", referenceId] + : ["events", "by-ref", referenceId]; + + // Act + var events = await SendRequestAsAsync>(r => r + .AsTestOrganizationUser() + .AppendPaths(paths) + .StatusCodeShouldBeOk() + ); + + // Assert + Assert.NotNull(events); + var ev = Assert.Single(events); + Assert.Equal(referenceId, ev.GetEventReference("parent")); + } + [Fact] public async Task GetCountByOrganizationAsync_WithExistingEvents_ReturnsOrganizationCount() { diff --git a/tests/http/events.http b/tests/http/events.http index 271fdcaaa6..e52d3c35c1 100644 --- a/tests/http/events.http +++ b/tests/http/events.http @@ -71,6 +71,14 @@ Content-Type: application/json "reference_id": "{{referenceId}}" } +### By ReferenceId +GET {{apiUrl}}/events/by-ref/{{referenceId}} +Authorization: Bearer {{token}} + +### By ReferenceId And Project +GET {{apiUrl}}/projects/{{projectId}}/events/by-ref/{{referenceId}} +Authorization: Bearer {{token}} + ### Post User Description POST {{apiUrl}}/events/by-ref/{{referenceId}}/user-description?access_token={{clientToken}} Content-Type: application/json