feat(audit): multi-value filters across ManagementService, CLI and Central UI
This commit is contained in:
@@ -74,34 +74,21 @@ public static class AuditExportEndpoints
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the query-string into an <see cref="AuditLogQueryFilter"/>.
|
||||
/// Unknown enum names / un-parseable Guids / dates are silently dropped
|
||||
/// (same contract as <c>AuditLogPage.ApplyQueryStringFilters</c>).
|
||||
/// Parses the query-string into an <see cref="AuditLogQueryFilter"/>. The
|
||||
/// <c>channel</c>/<c>kind</c>/<c>status</c>/<c>site</c> dimensions are
|
||||
/// multi-value: a repeated query param yields a multi-element filter list, a
|
||||
/// single param a one-element list. Unknown enum names / un-parseable Guids /
|
||||
/// dates are silently dropped (same lax contract as
|
||||
/// <c>AuditLogPage.ApplyQueryStringFilters</c>) — an unparseable value within
|
||||
/// a repeated set is dropped, not the whole set.
|
||||
/// </summary>
|
||||
internal static AuditLogQueryFilter ParseFilter(IQueryCollection query)
|
||||
{
|
||||
AuditChannel? channel = null;
|
||||
if (query.TryGetValue("channel", out var channelValues)
|
||||
&& Enum.TryParse<AuditChannel>(channelValues.ToString(), ignoreCase: true, out var parsedChannel))
|
||||
{
|
||||
channel = parsedChannel;
|
||||
}
|
||||
var channels = ParseEnumList<AuditChannel>(query, "channel");
|
||||
var kinds = ParseEnumList<AuditKind>(query, "kind");
|
||||
var statuses = ParseEnumList<AuditStatus>(query, "status");
|
||||
var sites = ParseStringList(query, "site");
|
||||
|
||||
AuditKind? kind = null;
|
||||
if (query.TryGetValue("kind", out var kindValues)
|
||||
&& Enum.TryParse<AuditKind>(kindValues.ToString(), ignoreCase: true, out var parsedKind))
|
||||
{
|
||||
kind = parsedKind;
|
||||
}
|
||||
|
||||
AuditStatus? status = null;
|
||||
if (query.TryGetValue("status", out var statusValues)
|
||||
&& Enum.TryParse<AuditStatus>(statusValues.ToString(), ignoreCase: true, out var parsedStatus))
|
||||
{
|
||||
status = parsedStatus;
|
||||
}
|
||||
|
||||
string? site = TrimToNullable(query, "site");
|
||||
string? target = TrimToNullable(query, "target");
|
||||
string? actor = TrimToNullable(query, "actor");
|
||||
|
||||
@@ -116,10 +103,10 @@ public static class AuditExportEndpoints
|
||||
DateTime? toUtc = ParseUtcDate(query, "to");
|
||||
|
||||
return new AuditLogQueryFilter(
|
||||
Channels: channel is { } c ? new[] { c } : null,
|
||||
Kinds: kind is { } k ? new[] { k } : null,
|
||||
Statuses: status is { } s ? new[] { s } : null,
|
||||
SourceSiteIds: site is { } siteId ? new[] { siteId } : null,
|
||||
Channels: channels,
|
||||
Kinds: kinds,
|
||||
Statuses: statuses,
|
||||
SourceSiteIds: sites,
|
||||
Target: target,
|
||||
Actor: actor,
|
||||
CorrelationId: correlationId,
|
||||
@@ -127,6 +114,53 @@ public static class AuditExportEndpoints
|
||||
ToUtc: toUtc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads EVERY value of a (possibly repeated) query param and parses each as
|
||||
/// <typeparamref name="TEnum"/>, dropping unparseable values silently. Returns
|
||||
/// <c>null</c> when the param is absent or no value parsed.
|
||||
/// </summary>
|
||||
private static IReadOnlyList<TEnum>? ParseEnumList<TEnum>(IQueryCollection query, string key)
|
||||
where TEnum : struct, Enum
|
||||
{
|
||||
if (!query.TryGetValue(key, out var values))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var parsed = new List<TEnum>();
|
||||
foreach (var raw in values)
|
||||
{
|
||||
if (Enum.TryParse<TEnum>(raw, ignoreCase: true, out var value))
|
||||
{
|
||||
parsed.Add(value);
|
||||
}
|
||||
}
|
||||
return parsed.Count > 0 ? parsed : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads EVERY value of a (possibly repeated) query param, trims each, and
|
||||
/// drops blank entries. Returns <c>null</c> when the param is absent or every
|
||||
/// value was blank.
|
||||
/// </summary>
|
||||
private static IReadOnlyList<string>? ParseStringList(IQueryCollection query, string key)
|
||||
{
|
||||
if (!query.TryGetValue(key, out var values))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var parsed = new List<string>();
|
||||
foreach (var raw in values)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(raw))
|
||||
{
|
||||
parsed.Add(raw.Trim());
|
||||
}
|
||||
}
|
||||
return parsed.Count > 0 ? parsed : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optional <c>maxRows=</c> query-string override. Falls back to
|
||||
/// <see cref="DefaultMaxRows"/> on a missing / non-positive / unparseable
|
||||
|
||||
Reference in New Issue
Block a user