refactor(audit): consolidate query-param parsers; widen CLI export to multi-value

This commit is contained in:
Joseph Doherty
2026-05-21 05:37:06 -04:00
parent 2a76be1f94
commit f64a7aed02
9 changed files with 350 additions and 177 deletions

View File

@@ -375,12 +375,18 @@ public static class AuditEndpoints
/// (no 400) — the same lax contract the CentralUI export endpoint uses; an
/// unparseable value within a repeated set is dropped, not the whole set.
/// </summary>
/// <remarks>
/// This endpoint reads the source-site filter from the <c>sourceSiteId</c>
/// query key, whereas the CentralUI export endpoint reads it as <c>site</c>.
/// The divergence is deliberate — each endpoint matches its own CLI / UI URL
/// builder — so do NOT "fix" the two to a single key name.
/// </remarks>
public static AuditLogQueryFilter ParseFilter(IQueryCollection query)
{
var channels = ParseEnumList<AuditChannel>(query, "channel");
var kinds = ParseEnumList<AuditKind>(query, "kind");
var statuses = ParseEnumList<AuditStatus>(query, "status");
var sourceSiteIds = ParseStringList(query, "sourceSiteId");
var channels = AuditQueryParamParsers.ParseEnumList<AuditChannel>(query["channel"]);
var kinds = AuditQueryParamParsers.ParseEnumList<AuditKind>(query["kind"]);
var statuses = AuditQueryParamParsers.ParseEnumList<AuditStatus>(query["status"]);
var sourceSiteIds = AuditQueryParamParsers.ParseStringList(query["sourceSiteId"]);
Guid? correlationId = null;
if (query.TryGetValue("correlationId", out var corrValues)
@@ -401,54 +407,6 @@ public static class AuditEndpoints
ToUtc: ParseUtcDate(query, "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 — so the filter
/// dimension stays unconstrained.
/// </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>
/// Parses the keyset-paging query parameters into an
/// <see cref="AuditLogPaging"/>. <c>pageSize</c> is clamped to