diff options
| author | ivar <i@oiee.no> | 2025-12-03 21:49:20 +0100 |
|---|---|---|
| committer | ivar <i@oiee.no> | 2025-12-03 21:49:20 +0100 |
| commit | cd70f54266d708867a1eb35870bc755bc5b2df32 (patch) | |
| tree | f0a8ec571ef3f345ac74293b4cb11918878b3ed5 /api/WhatApi/Database/AppDatabase.cs | |
| parent | 5bd9ad8bd1740dcff179d66718532086304ca4c4 (diff) | |
| download | what-cd70f54266d708867a1eb35870bc755bc5b2df32.tar.xz what-cd70f54266d708867a1eb35870bc755bc5b2df32.zip | |
Refactor db
Diffstat (limited to 'api/WhatApi/Database/AppDatabase.cs')
| -rw-r--r-- | api/WhatApi/Database/AppDatabase.cs | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/api/WhatApi/Database/AppDatabase.cs b/api/WhatApi/Database/AppDatabase.cs new file mode 100644 index 0000000..64c138f --- /dev/null +++ b/api/WhatApi/Database/AppDatabase.cs @@ -0,0 +1,113 @@ +using System.Security.Claims; + +namespace WhatApi.Database; + +public class AppDatabase(DbContextOptions<AppDatabase> options, IHttpContextAccessor httpContextAccessor, IConfiguration configuration) : DbContext(options) +{ + public DbSet<Content> Content => Set<Content>(); + public DbSet<Place> Places => Set<Place>(); + public DbSet<User> Users => Set<User>(); + public DbSet<AuditTrail> AuditTrails => Set<AuditTrail>(); + + protected override void OnModelCreating(ModelBuilder b) { + b.HasPostgresExtension("postgis"); + b.ApplyConfiguration(new AuditTrailConfiguration()); + b.ApplyConfiguration(new PlaceConfiguration()); + b.ApplyConfiguration(new UserConfiguration()); + b.ApplyConfiguration(new ContentConfiguration()); + base.OnModelCreating(b); + } + + public override int SaveChanges() { + if (configuration.GetValue<bool>("DISABLE_AUDIT_TRAILS")) return base.SaveChanges(); + SetAuditableProperties(); + var auditEntries = GetActiveAuditTrails(); + if (auditEntries.Count != 0) + AuditTrails.AddRange(auditEntries); + return base.SaveChanges(); + } + + public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) { + if (configuration.GetValue<bool>("DISABLE_AUDIT_TRAILS")) return await base.SaveChangesAsync(cancellationToken); + SetAuditableProperties(); + var auditEntries = GetActiveAuditTrails(); + if (auditEntries.Count != 0) + await AuditTrails.AddRangeAsync(auditEntries, cancellationToken); + return await base.SaveChangesAsync(cancellationToken); + } + + private List<AuditTrail> GetActiveAuditTrails() { + var userId = GetUserId(); + var entries = ChangeTracker.Entries<IAuditableEntity>() + .Where(e => e.State is EntityState.Added or EntityState.Modified or EntityState.Deleted); + + var auditTrails = new List<AuditTrail>(); + + foreach (var entry in entries) { + var audit = new AuditTrail { + Id = Guid.NewGuid(), + UserId = userId, + EntityName = entry.Entity.GetType().Name, + DateUtc = DateTimeOffset.UtcNow + }; + + foreach (var prop in entry.Properties) { + if (prop.Metadata.IsPrimaryKey()) { + audit.PrimaryKey = prop.CurrentValue?.ToString(); + continue; + } + + if (prop.Metadata.PropertyInfo?.CustomAttributes.FirstOrDefault(c => c.AttributeType == typeof(AuditTrailIgnoreAttribute)) != null) + continue; + + var name = prop.Metadata.Name; + + switch (entry.State) { + case EntityState.Added: + audit.TrailType = TrailType.Create; + audit.NewValues[name] = prop.CurrentValue; + break; + case EntityState.Deleted: + audit.TrailType = TrailType.Delete; + audit.OldValues[name] = prop.OriginalValue; + break; + case EntityState.Modified: + if (!Equals(prop.OriginalValue, prop.CurrentValue)) { + audit.TrailType = TrailType.Update; + audit.ChangedColumns.Add(name); + audit.OldValues[name] = prop.OriginalValue; + audit.NewValues[name] = prop.CurrentValue; + } + break; + } + } + + if (audit.TrailType != TrailType.None) + auditTrails.Add(audit); + } + + return auditTrails; + } + + private Guid GetUserId() { + var system = new Guid("e87ab078-55bc-4655-86d9-c5b2ecad7162"); + var userIdString = httpContextAccessor.HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier); + return string.IsNullOrWhiteSpace(userIdString) ? system : new Guid(userIdString); + } + + private void SetAuditableProperties() { + var actor = GetUserId(); + foreach (var entry in ChangeTracker.Entries<IAuditableEntity>()) { + switch (entry.State) { + case EntityState.Added: + entry.Entity.CreatedAtUtc = DateTimeOffset.UtcNow; + entry.Entity.CreatedBy = actor; + break; + case EntityState.Modified: + entry.Entity.UpdatedAtUtc = DateTimeOffset.UtcNow; + entry.Entity.UpdatedBy = actor; + break; + } + } + } +}
\ No newline at end of file |
