| | | 1 | | using ArturRios.Data.Relational.Core.Interfaces; |
| | | 2 | | using ArturRios.Heimdall.Domain.Entities; |
| | | 3 | | using ArturRios.Heimdall.Shared.Security; |
| | | 4 | | |
| | | 5 | | namespace ArturRios.Heimdall.Command.Auditing; |
| | | 6 | | |
| | 983 | 7 | | public class AuditLogWriter(IAsyncRepository<AuditLog, long> repository, IActorAccessor actorAccessor) |
| | | 8 | | : IAuditLogWriter |
| | | 9 | | { |
| | | 10 | | /// <summary>Longest failure reason stored; matches AUDIT_LOG.failure_reason's column.</summary> |
| | | 11 | | private const int MaxFailureReasonLength = 500; |
| | | 12 | | |
| | | 13 | | public async Task WriteAsync(string action, Guid? targetId, bool succeeded, string? failureReason) |
| | | 14 | | { |
| | 985 | 15 | | var entry = new AuditLog |
| | 985 | 16 | | { |
| | 985 | 17 | | PublicId = Guid.NewGuid(), |
| | 985 | 18 | | ActorPersonId = actorAccessor.ActorPersonId, |
| | 985 | 19 | | ActorRole = actorAccessor.ActorRole, |
| | 985 | 20 | | Action = action, |
| | 985 | 21 | | TargetId = targetId, |
| | 985 | 22 | | Succeeded = succeeded, |
| | 985 | 23 | | // Truncated rather than allowed to fail the insert: a reason too long for the column |
| | 985 | 24 | | // would otherwise turn a recorded refusal into no record at all, which is the one |
| | 985 | 25 | | // outcome the trail must not have. |
| | 985 | 26 | | FailureReason = failureReason is { Length: > MaxFailureReasonLength } |
| | 985 | 27 | | ? failureReason[..MaxFailureReasonLength] |
| | 985 | 28 | | : failureReason, |
| | 985 | 29 | | CreatedAt = DateTime.UtcNow |
| | 985 | 30 | | }; |
| | | 31 | | |
| | 985 | 32 | | await repository.CreateAsync(entry); |
| | 985 | 33 | | } |
| | | 34 | | } |