using System.Text; using System.Text.Json; using SharepointToolbox.Web.Core.Models; namespace SharepointToolbox.Web.Infrastructure.Persistence; /// Append-only JSONL audit log. Each line is one AuditEntry JSON object. public class AuditRepository { private readonly string _filePath; private readonly SemaphoreSlim _writeLock = new(1, 1); private static readonly JsonSerializerOptions _opts = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, PropertyNameCaseInsensitive = true }; public AuditRepository(string filePath) { _filePath = filePath; } public async Task AppendAsync(AuditEntry entry) { await _writeLock.WaitAsync(); try { var dir = Path.GetDirectoryName(_filePath); if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir); var line = JsonSerializer.Serialize(entry, _opts) + "\n"; await File.AppendAllTextAsync(_filePath, line, Encoding.UTF8); } finally { _writeLock.Release(); } } public async Task> LoadAllAsync() { if (!File.Exists(_filePath)) return Array.Empty(); var lines = await File.ReadAllLinesAsync(_filePath, Encoding.UTF8); var result = new List(lines.Length); foreach (var line in lines) { if (string.IsNullOrWhiteSpace(line)) continue; try { var entry = JsonSerializer.Deserialize(line, _opts); if (entry != null) result.Add(entry); } catch { /* skip corrupt lines */ } } return result; } }