diff --git a/src/Exceptionless.Web/Controllers/Base/ExceptionlessApiController.cs b/src/Exceptionless.Web/Controllers/Base/ExceptionlessApiController.cs index 662defc7a3..813f4312d2 100644 --- a/src/Exceptionless.Web/Controllers/Base/ExceptionlessApiController.cs +++ b/src/Exceptionless.Web/Controllers/Base/ExceptionlessApiController.cs @@ -229,6 +229,11 @@ protected ObjectResult PlanLimitReached(string message) return Problem(statusCode: StatusCodes.Status426UpgradeRequired, title: message); } + protected bool IsPremiumFeatureQueryBlocked(AppFilter filter) + { + return filter.UsesPremiumFeatures && filter.Organizations.Any(o => !o.HasPremiumFeatures); + } + protected ObjectResult TooManyRequests(string message) { return Problem(statusCode: StatusCodes.Status429TooManyRequests, title: message); diff --git a/src/Exceptionless.Web/Controllers/EventController.cs b/src/Exceptionless.Web/Controllers/EventController.cs index 7470abb854..3d232ecc5a 100644 --- a/src/Exceptionless.Web/Controllers/EventController.cs +++ b/src/Exceptionless.Web/Controllers/EventController.cs @@ -241,6 +241,8 @@ private async Task> CountInternalAsync(AppFilter sf, T return BadRequest(far.Message); sf.UsesPremiumFeatures = pr.UsesPremiumFeatures || far.UsesPremiumFeatures; + if (IsPremiumFeatureQueryBlocked(sf)) + return PlanLimitReached("Please upgrade your plan to use premium search features."); if (mode == "stack_new") filter = AddFirstOccurrenceFilter(ti.Range, filter); @@ -297,6 +299,8 @@ private async Task>> GetInternalAsync( return BadRequest(pr.Message); sf.UsesPremiumFeatures = pr.UsesPremiumFeatures || usesPremiumFeatures; + if (IsPremiumFeatureQueryBlocked(sf)) + return PlanLimitReached("Please upgrade your plan to use premium search features."); try { diff --git a/src/Exceptionless.Web/Controllers/StackController.cs b/src/Exceptionless.Web/Controllers/StackController.cs index 9b9b5630c4..ae41cce6ac 100644 --- a/src/Exceptionless.Web/Controllers/StackController.cs +++ b/src/Exceptionless.Web/Controllers/StackController.cs @@ -489,6 +489,8 @@ private async Task>> GetInternalAsync(Ap return BadRequest(pr.Message); sf.UsesPremiumFeatures = pr.UsesPremiumFeatures; + if (IsPremiumFeatureQueryBlocked(sf)) + return PlanLimitReached("Please upgrade your plan to use premium search features."); try { diff --git a/tests/Exceptionless.Tests/Controllers/EventControllerTests.cs b/tests/Exceptionless.Tests/Controllers/EventControllerTests.cs index 066c3d7d6c..4fc055b19a 100644 --- a/tests/Exceptionless.Tests/Controllers/EventControllerTests.cs +++ b/tests/Exceptionless.Tests/Controllers/EventControllerTests.cs @@ -519,6 +519,36 @@ public async Task CanGetFreeProjectLevelMostFrequentStackMode() Assert.Equal(2, results.Count); } + [Fact] + public async Task GetCountByProjectAsync_WithPremiumFilterOnFreeOrganization_ReturnsUpgradeRequired() + { + // Arrange + await CreateDataAsync(d => d.Event().FreeProject().Tag("premium-tag")); + + // Act & Assert + await SendRequestAsync(r => r + .AsFreeOrganizationUser() + .AppendPaths("projects", SampleDataService.FREE_PROJECT_ID, "events", "count") + .QueryString("filter", "tags:premium-tag") + .StatusCodeShouldBeUpgradeRequired() + ); + } + + [Fact] + public async Task GetByProjectAsync_WithPremiumFilterOnFreeOrganization_ReturnsUpgradeRequired() + { + // Arrange + await CreateDataAsync(d => d.Event().FreeProject().Tag("premium-tag")); + + // Act & Assert + await SendRequestAsync(r => r + .AsFreeOrganizationUser() + .AppendPaths("projects", SampleDataService.FREE_PROJECT_ID, "events") + .QueryString("filter", "tags:premium-tag") + .StatusCodeShouldBeUpgradeRequired() + ); + } + [Fact] public async Task CanGetNewStackMode() { diff --git a/tests/Exceptionless.Tests/Controllers/StackControllerTests.cs b/tests/Exceptionless.Tests/Controllers/StackControllerTests.cs index 02017715de..79b1c7ba9e 100644 --- a/tests/Exceptionless.Tests/Controllers/StackControllerTests.cs +++ b/tests/Exceptionless.Tests/Controllers/StackControllerTests.cs @@ -61,6 +61,21 @@ public async Task CanSearchByNonPremiumFields() Assert.Single(result); } + [Fact] + public async Task GetByProjectAsync_WithPremiumFilterOnFreeOrganization_ReturnsUpgradeRequired() + { + // Arrange + await CreateDataAsync(d => d.Event().FreeProject().Message("Premium restricted stack")); + + // Act & Assert + await SendRequestAsync(r => r + .AsFreeOrganizationUser() + .AppendPaths("projects", SampleDataService.FREE_PROJECT_ID, "stacks") + .QueryString("filter", "title:\"Premium restricted stack\"") + .StatusCodeShouldBeUpgradeRequired() + ); + } + [Theory] [InlineData(null)] [InlineData("1.0.0")]