fix(expense-snapshot): validate functional class + stamp DeletedBy on soft delete
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ROLAC.API.Data;
|
||||
using ROLAC.API.DTOs.Expense;
|
||||
@@ -8,7 +10,17 @@ namespace ROLAC.API.Services;
|
||||
public class ExpenseSnapshotService : IExpenseSnapshotService
|
||||
{
|
||||
private readonly AppDbContext _db;
|
||||
public ExpenseSnapshotService(AppDbContext db) => _db = db;
|
||||
private readonly IHttpContextAccessor _http;
|
||||
public ExpenseSnapshotService(AppDbContext db, IHttpContextAccessor http)
|
||||
{ _db = db; _http = http; }
|
||||
|
||||
// The JWT carries the user id in the "sub" claim (NameClaimType="sub", MapInboundClaims=false),
|
||||
// so ClaimTypes.NameIdentifier is absent at runtime. Check NameIdentifier first (unit tests set it),
|
||||
// then fall back to "sub" (real tokens). Required for the self-ownership guard to work in production.
|
||||
private string CurrentUserId =>
|
||||
_http.HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier)
|
||||
?? _http.HttpContext?.User.FindFirstValue("sub")
|
||||
?? "system";
|
||||
|
||||
public async Task<List<ExpenseSnapshotDto>> GetAllAsync()
|
||||
{
|
||||
@@ -101,7 +113,7 @@ public class ExpenseSnapshotService : IExpenseSnapshotService
|
||||
{
|
||||
var s = await _db.ExpenseSnapshots.FirstOrDefaultAsync(x => x.Id == id)
|
||||
?? throw new KeyNotFoundException($"Snapshot {id} not found.");
|
||||
s.IsDeleted = true; s.DeletedAt = DateTimeOffset.UtcNow;
|
||||
s.IsDeleted = true; s.DeletedAt = DateTimeOffset.UtcNow; s.DeletedBy = CurrentUserId;
|
||||
await _db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -115,6 +127,8 @@ public class ExpenseSnapshotService : IExpenseSnapshotService
|
||||
throw new InvalidOperationException("Each snapshot line needs a category group and subcategory.");
|
||||
if (l.Amount <= 0)
|
||||
throw new InvalidOperationException("Each snapshot line amount must be greater than zero.");
|
||||
if (l.FunctionalClass is not null && !FunctionalClasses.All.Contains(l.FunctionalClass))
|
||||
throw new InvalidOperationException($"Invalid functional class '{l.FunctionalClass}'.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user