feat(audit)!: ScadaBridge C3 — swap to canonical ZB.MOM.WW.Audit.AuditEvent across seams/emitters/DTO/redactor wiring; transitional 24-col storage shim (Task 2.5)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Audit;
|
||||
using ZB.MOM.WW.Audit;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
||||
using Timestamp = Google.Protobuf.WellKnownTypes.Timestamp;
|
||||
|
||||
@@ -41,38 +42,44 @@ public static class AuditEventDtoMapper
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(evt);
|
||||
|
||||
// C3 (Task 2.5): the proto contract is the UNCHANGED 24-field wire. The
|
||||
// canonical record carries the ScadaBridge domain fields inside
|
||||
// DetailsJson — decompose them so the DTO's typed domain fields are
|
||||
// populated exactly as before.
|
||||
var r = AuditRowProjection.Decompose(evt);
|
||||
|
||||
var dto = new AuditEventDto
|
||||
{
|
||||
EventId = evt.EventId.ToString(),
|
||||
OccurredAtUtc = Timestamp.FromDateTime(EnsureUtc(evt.OccurredAtUtc)),
|
||||
Channel = evt.Channel.ToString(),
|
||||
Kind = evt.Kind.ToString(),
|
||||
CorrelationId = evt.CorrelationId?.ToString() ?? string.Empty,
|
||||
ExecutionId = evt.ExecutionId?.ToString() ?? string.Empty,
|
||||
ParentExecutionId = evt.ParentExecutionId?.ToString() ?? string.Empty,
|
||||
SourceSiteId = evt.SourceSiteId ?? string.Empty,
|
||||
SourceNode = evt.SourceNode ?? string.Empty,
|
||||
SourceInstanceId = evt.SourceInstanceId ?? string.Empty,
|
||||
SourceScript = evt.SourceScript ?? string.Empty,
|
||||
Actor = evt.Actor ?? string.Empty,
|
||||
Target = evt.Target ?? string.Empty,
|
||||
Status = evt.Status.ToString(),
|
||||
ErrorMessage = evt.ErrorMessage ?? string.Empty,
|
||||
ErrorDetail = evt.ErrorDetail ?? string.Empty,
|
||||
RequestSummary = evt.RequestSummary ?? string.Empty,
|
||||
ResponseSummary = evt.ResponseSummary ?? string.Empty,
|
||||
PayloadTruncated = evt.PayloadTruncated,
|
||||
Extra = evt.Extra ?? string.Empty
|
||||
EventId = r.EventId.ToString(),
|
||||
OccurredAtUtc = Timestamp.FromDateTime(EnsureUtc(r.OccurredAtUtc)),
|
||||
Channel = r.Channel.ToString(),
|
||||
Kind = r.Kind.ToString(),
|
||||
CorrelationId = r.CorrelationId?.ToString() ?? string.Empty,
|
||||
ExecutionId = r.ExecutionId?.ToString() ?? string.Empty,
|
||||
ParentExecutionId = r.ParentExecutionId?.ToString() ?? string.Empty,
|
||||
SourceSiteId = r.SourceSiteId ?? string.Empty,
|
||||
SourceNode = r.SourceNode ?? string.Empty,
|
||||
SourceInstanceId = r.SourceInstanceId ?? string.Empty,
|
||||
SourceScript = r.SourceScript ?? string.Empty,
|
||||
Actor = r.Actor ?? string.Empty,
|
||||
Target = r.Target ?? string.Empty,
|
||||
Status = r.Status.ToString(),
|
||||
ErrorMessage = r.ErrorMessage ?? string.Empty,
|
||||
ErrorDetail = r.ErrorDetail ?? string.Empty,
|
||||
RequestSummary = r.RequestSummary ?? string.Empty,
|
||||
ResponseSummary = r.ResponseSummary ?? string.Empty,
|
||||
PayloadTruncated = r.PayloadTruncated,
|
||||
Extra = r.Extra ?? string.Empty
|
||||
};
|
||||
|
||||
if (evt.HttpStatus.HasValue)
|
||||
if (r.HttpStatus.HasValue)
|
||||
{
|
||||
dto.HttpStatus = evt.HttpStatus.Value;
|
||||
dto.HttpStatus = r.HttpStatus.Value;
|
||||
}
|
||||
|
||||
if (evt.DurationMs.HasValue)
|
||||
if (r.DurationMs.HasValue)
|
||||
{
|
||||
dto.DurationMs = evt.DurationMs.Value;
|
||||
dto.DurationMs = r.DurationMs.Value;
|
||||
}
|
||||
|
||||
return dto;
|
||||
@@ -89,33 +96,35 @@ public static class AuditEventDtoMapper
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dto);
|
||||
|
||||
return new AuditEvent
|
||||
{
|
||||
EventId = Guid.Parse(dto.EventId),
|
||||
OccurredAtUtc = DateTime.SpecifyKind(dto.OccurredAtUtc.ToDateTime(), DateTimeKind.Utc),
|
||||
IngestedAtUtc = null,
|
||||
Channel = Enum.Parse<AuditChannel>(dto.Channel),
|
||||
Kind = Enum.Parse<AuditKind>(dto.Kind),
|
||||
CorrelationId = NullIfEmpty(dto.CorrelationId) is { } cid ? Guid.Parse(cid) : null,
|
||||
ExecutionId = NullIfEmpty(dto.ExecutionId) is { } eid ? Guid.Parse(eid) : null,
|
||||
ParentExecutionId = NullIfEmpty(dto.ParentExecutionId) is { } pid ? Guid.Parse(pid) : null,
|
||||
SourceSiteId = NullIfEmpty(dto.SourceSiteId),
|
||||
SourceNode = NullIfEmpty(dto.SourceNode),
|
||||
SourceInstanceId = NullIfEmpty(dto.SourceInstanceId),
|
||||
SourceScript = NullIfEmpty(dto.SourceScript),
|
||||
Actor = NullIfEmpty(dto.Actor),
|
||||
Target = NullIfEmpty(dto.Target),
|
||||
Status = Enum.Parse<AuditStatus>(dto.Status),
|
||||
HttpStatus = dto.HttpStatus,
|
||||
DurationMs = dto.DurationMs,
|
||||
ErrorMessage = NullIfEmpty(dto.ErrorMessage),
|
||||
ErrorDetail = NullIfEmpty(dto.ErrorDetail),
|
||||
RequestSummary = NullIfEmpty(dto.RequestSummary),
|
||||
ResponseSummary = NullIfEmpty(dto.ResponseSummary),
|
||||
PayloadTruncated = dto.PayloadTruncated,
|
||||
Extra = NullIfEmpty(dto.Extra),
|
||||
ForwardState = null
|
||||
};
|
||||
// C3 (Task 2.5): recompose the canonical record from the 24-field wire
|
||||
// DTO. The domain fields are re-serialized into DetailsJson via the
|
||||
// projection helper; IngestedAtUtc is left null (central sets it at
|
||||
// ingest) and ForwardState is dropped (site-storage-only, never on the
|
||||
// wire).
|
||||
return AuditRowProjection.Recompose(new AuditRowProjection.AuditRowValues(
|
||||
EventId: Guid.Parse(dto.EventId),
|
||||
OccurredAtUtc: DateTime.SpecifyKind(dto.OccurredAtUtc.ToDateTime(), DateTimeKind.Utc),
|
||||
IngestedAtUtc: null,
|
||||
Channel: Enum.Parse<AuditChannel>(dto.Channel),
|
||||
Kind: Enum.Parse<AuditKind>(dto.Kind),
|
||||
Status: Enum.Parse<AuditStatus>(dto.Status),
|
||||
CorrelationId: NullIfEmpty(dto.CorrelationId) is { } cid ? Guid.Parse(cid) : null,
|
||||
ExecutionId: NullIfEmpty(dto.ExecutionId) is { } eid ? Guid.Parse(eid) : null,
|
||||
ParentExecutionId: NullIfEmpty(dto.ParentExecutionId) is { } pid ? Guid.Parse(pid) : null,
|
||||
SourceSiteId: NullIfEmpty(dto.SourceSiteId),
|
||||
SourceNode: NullIfEmpty(dto.SourceNode),
|
||||
SourceInstanceId: NullIfEmpty(dto.SourceInstanceId),
|
||||
SourceScript: NullIfEmpty(dto.SourceScript),
|
||||
Actor: NullIfEmpty(dto.Actor),
|
||||
Target: NullIfEmpty(dto.Target),
|
||||
HttpStatus: dto.HttpStatus,
|
||||
DurationMs: dto.DurationMs,
|
||||
ErrorMessage: NullIfEmpty(dto.ErrorMessage),
|
||||
ErrorDetail: NullIfEmpty(dto.ErrorDetail),
|
||||
RequestSummary: NullIfEmpty(dto.RequestSummary),
|
||||
ResponseSummary: NullIfEmpty(dto.ResponseSummary),
|
||||
PayloadTruncated: dto.PayloadTruncated,
|
||||
Extra: NullIfEmpty(dto.Extra)));
|
||||
}
|
||||
|
||||
private static string? NullIfEmpty(string? value) =>
|
||||
|
||||
@@ -4,7 +4,7 @@ using Akka.Actor;
|
||||
using Grpc.Core;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Audit;
|
||||
using ZB.MOM.WW.Audit;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Audit;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Observability;
|
||||
|
||||
Reference in New Issue
Block a user