Skip to content

Commit 92690e3

Browse files
committed
Added EnforceEventStackFilter option and turned it on in the EventController. Allow other system usages of event repository to bypass event stack filter.
1 parent e219e2a commit 92690e3

File tree

4 files changed

+69
-32
lines changed

4 files changed

+69
-32
lines changed

build/generate-client.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
curl -X POST https://generator3.swagger.io/api/generate \
2+
-H 'content-type: application/json' \
3+
-d '{
4+
"specURL" : "https://collector.exceptionless.io/docs/v2/swagger.json",
5+
"lang" : "typescript-fetch",
6+
"type" : "CLIENT",
7+
"options" : {
8+
"additionalProperties" : {
9+
"supportsES6": true,
10+
"typescriptThreePlus": true
11+
}
12+
},
13+
"codegenVersion" : "V3"
14+
}' --output exceptionless-ts.zip

src/Exceptionless.Core/Repositories/Queries/EventStackFilterQuery.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,27 @@
1313
using Nest;
1414
using DateRange = Foundatio.Repositories.DateRange;
1515

16+
namespace Exceptionless.Core.Repositories {
17+
public static class EventStackFilterQueryExtensions {
18+
internal const string EnforceEventStackFilterKey = "@EnforceEventStackFilter";
19+
20+
public static T EnforceEventStackFilter<T>(this T query, bool shouldEnforceEventStackFilter = true) where T : IRepositoryQuery {
21+
query.Values.Set(EnforceEventStackFilterKey, shouldEnforceEventStackFilter);
22+
return query;
23+
}
24+
}
25+
}
26+
27+
namespace Exceptionless.Core.Repositories.Options {
28+
public static class ReadEventStackFilterQueryExtensions {
29+
public static bool ShouldEnforceEventStackFilter(this IRepositoryQuery query) {
30+
return query.SafeGetOption<bool>(EventStackFilterQueryExtensions.EnforceEventStackFilterKey, false);
31+
}
32+
}
33+
}
34+
1635
namespace Exceptionless.Core.Repositories.Queries {
1736
public class EventStackFilterQueryBuilder : IElasticQueryBuilder {
18-
public const string StackFieldName = "@stack";
1937
private readonly IStackRepository _stackRepository;
2038
private readonly ILogger _logger;
2139
private readonly Field _inferredEventDateField;
@@ -31,6 +49,9 @@ public EventStackFilterQueryBuilder(IStackRepository stackRepository, ILoggerFac
3149
public async Task BuildAsync<T>(QueryBuilderContext<T> ctx) where T : class, new() {
3250
string filter = ctx.Source.GetFilterExpression() ?? String.Empty;
3351

52+
if (String.IsNullOrEmpty(filter) && !ctx.Source.ShouldEnforceEventStackFilter())
53+
return;
54+
3455
// TODO: Handle search expressions as well
3556
bool altInvertRequested = false;
3657
if (filter.StartsWith("@!")) {
@@ -57,7 +78,7 @@ public EventStackFilterQueryBuilder(IStackRepository stackRepository, ILoggerFac
5778
if (isStackIdsNegated)
5879
query = invertedStackFilter.Query;
5980

60-
if (String.IsNullOrEmpty(query) && ctx.Options.GetSoftDeleteMode() != SoftDeleteQueryMode.ActiveOnly)
81+
if (String.IsNullOrEmpty(query) && (!ctx.Source.ShouldEnforceEventStackFilter() || ctx.Options.GetSoftDeleteMode() != SoftDeleteQueryMode.ActiveOnly))
6182
return;
6283

6384
if (!(ctx is IQueryVisitorContextWithValidator)) {

src/Exceptionless.Web/Controllers/Base/ReadOnlyRepositoryApiController.cs

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -39,34 +39,6 @@ protected async Task<ActionResult<TViewModel>> GetByIdImplAsync(string id) {
3939
return await OkModelAsync(model);
4040
}
4141

42-
protected async Task<ActionResult<CountResult>> GetCountImplAsync(AppFilter sf, TimeInfo ti, string filter = null, string aggregations = null) {
43-
var pr = await _validator.ValidateQueryAsync(filter);
44-
if (!pr.IsValid)
45-
return BadRequest(pr.Message);
46-
47-
var far = await _validator.ValidateAggregationsAsync(aggregations);
48-
if (!far.IsValid)
49-
return BadRequest(far.Message);
50-
51-
sf.UsesPremiumFeatures = pr.UsesPremiumFeatures || far.UsesPremiumFeatures;
52-
var query = new RepositoryQuery<TModel>()
53-
.AppFilter(ShouldApplySystemFilter(sf, filter) ? sf : null)
54-
.DateRange(ti.Range.UtcStart, ti.Range.UtcEnd, ti.Field)
55-
.Index(ti.Range.UtcStart, ti.Range.UtcEnd);
56-
57-
CountResult result;
58-
try {
59-
result = await _repository.CountAsync(q => q.SystemFilter(query).FilterExpression(filter).AggregationsExpression(aggregations));
60-
} catch (Exception ex) {
61-
using (_logger.BeginScope(new ExceptionlessState().Property("Search Filter", new { SystemFilter = sf, UserFilter = filter, Time = ti, Aggregations = aggregations }).Tag("Search").Identity(CurrentUser.EmailAddress).Property("User", CurrentUser).SetHttpContext(HttpContext)))
62-
_logger.LogError(ex, "An error has occurred. Please check your filter or aggregations.");
63-
64-
return BadRequest("An error has occurred. Please check your search filter.");
65-
}
66-
67-
return Ok(result);
68-
}
69-
7042
protected async Task<ActionResult<TViewModel>> OkModelAsync(TModel model) {
7143
return Ok(await MapAsync<TViewModel>(model, true));
7244
}

src/Exceptionless.Web/Controllers/EventController.cs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,34 @@ public async Task<ActionResult<CountResult>> GetCountByProjectAsync(string proje
154154
return await GetCountImplAsync(sf, ti, filter, aggregations);
155155
}
156156

157+
private async Task<ActionResult<CountResult>> GetCountImplAsync(AppFilter sf, TimeInfo ti, string filter = null, string aggregations = null) {
158+
var pr = await _validator.ValidateQueryAsync(filter);
159+
if (!pr.IsValid)
160+
return BadRequest(pr.Message);
161+
162+
var far = await _validator.ValidateAggregationsAsync(aggregations);
163+
if (!far.IsValid)
164+
return BadRequest(far.Message);
165+
166+
sf.UsesPremiumFeatures = pr.UsesPremiumFeatures || far.UsesPremiumFeatures;
167+
var query = new RepositoryQuery<PersistentEvent>()
168+
.AppFilter(ShouldApplySystemFilter(sf, filter) ? sf : null)
169+
.DateRange(ti.Range.UtcStart, ti.Range.UtcEnd, ti.Field)
170+
.Index(ti.Range.UtcStart, ti.Range.UtcEnd);
171+
172+
CountResult result;
173+
try {
174+
result = await _repository.CountAsync(q => q.SystemFilter(query).FilterExpression(filter).EnforceEventStackFilter().AggregationsExpression(aggregations));
175+
} catch (Exception ex) {
176+
using (_logger.BeginScope(new ExceptionlessState().Property("Search Filter", new { SystemFilter = sf, UserFilter = filter, Time = ti, Aggregations = aggregations }).Tag("Search").Identity(CurrentUser.EmailAddress).Property("User", CurrentUser).SetHttpContext(HttpContext)))
177+
_logger.LogError(ex, "An error has occurred. Please check your filter or aggregations.");
178+
179+
return BadRequest("An error has occurred. Please check your search filter.");
180+
}
181+
182+
return Ok(result);
183+
}
184+
157185
/// <summary>
158186
/// Get by id
159187
/// </summary>
@@ -251,6 +279,7 @@ private async Task<ActionResult<IReadOnlyCollection<PersistentEvent>>> GetIntern
251279

252280
var systemFilter = new RepositoryQuery<PersistentEvent>()
253281
.AppFilter(ShouldApplySystemFilter(sf, filter) ? sf : null)
282+
.EnforceEventStackFilter()
254283
.DateRange(ti.Range.UtcStart, ti.Range.UtcEnd, (PersistentEvent e) => e.Date)
255284
.Index(ti.Range.UtcStart, ti.Range.UtcEnd);
256285

@@ -265,6 +294,7 @@ private async Task<ActionResult<IReadOnlyCollection<PersistentEvent>>> GetIntern
265294
var countResponse = await _repository.CountAsync(q => q
266295
.SystemFilter(systemFilter)
267296
.FilterExpression(filter)
297+
.EnforceEventStackFilter()
268298
.AggregationsExpression($"terms:(stack_id~{GetSkip(page + 1, limit) + 1} {stackAggregations})"));
269299

270300
var stackTerms = countResponse.Aggregations.Terms<string>("terms_stack_id");
@@ -296,7 +326,7 @@ private Task<FindResults<PersistentEvent>> GetEventsInternalAsync(AppFilter sf,
296326
if (String.IsNullOrEmpty(sort))
297327
sort = "-date";
298328

299-
return _repository.FindAsync(q => q.AppFilter(ShouldApplySystemFilter(sf, filter) ? sf : null).FilterExpression(filter).SortExpression(sort).DateRange(ti.Range.UtcStart, ti.Range.UtcEnd, ti.Field),
329+
return _repository.FindAsync(q => q.AppFilter(ShouldApplySystemFilter(sf, filter) ? sf : null).FilterExpression(filter).EnforceEventStackFilter().SortExpression(sort).DateRange(ti.Range.UtcStart, ti.Range.UtcEnd, ti.Field),
300330
o => useSearchAfter
301331
? o.SearchAfterPaging().SearchAfter(after).PageLimit(limit)
302332
: o.PageNumber(page).PageLimit(limit));
@@ -1211,7 +1241,7 @@ private async Task<Dictionary<string, double>> GetUserCountByProjectIdsAsync(ICo
12111241

12121242
var systemFilter = new RepositoryQuery<PersistentEvent>().AppFilter(sf).DateRange(utcStart, utcEnd, (PersistentEvent e) => e.Date).Index(utcStart, utcEnd);
12131243
var projects = cachedTotals.Where(kvp => !kvp.Value.HasValue).Select(kvp => new Project { Id = kvp.Key, OrganizationId = stacks.FirstOrDefault(s => s.ProjectId == kvp.Key)?.OrganizationId }).ToList();
1214-
var countResult = await _repository.CountAsync(q => q.SystemFilter(systemFilter).FilterExpression(projects.BuildFilter()).AggregationsExpression("terms:(project_id cardinality:user)"));
1244+
var countResult = await _repository.CountAsync(q => q.SystemFilter(systemFilter).FilterExpression(projects.BuildFilter()).EnforceEventStackFilter().AggregationsExpression("terms:(project_id cardinality:user)"));
12151245

12161246
// Cache all projects that have more than 10 users for 5 minutes.
12171247
var projectTerms = countResult.Aggregations.Terms<string>("terms_project_id").Buckets;

0 commit comments

Comments
 (0)