Files
vigilcare-clinical/VigilCareClinicalAPI/Services/AlertThresholdService.cs
T
2026-06-21 19:53:19 +08:00

152 lines
4.7 KiB
C#

using Microsoft.EntityFrameworkCore;
using StackExchange.Redis;
public class AlertThresholdService : IAlertThresholdService
{
private readonly AppDbContext _db;
private readonly IConnectionMultiplexer _redis;
private readonly IAuditService _audit;
public AlertThresholdService(
AppDbContext db,
IConnectionMultiplexer redis,
IAuditService audit)
{
_db = db;
_redis = redis;
_audit = audit;
}
public async Task<AlertThreshold> CreateAsync(AlertThresholdRequest req)
{
var exists = await _db.AlertThresholds.AnyAsync(t => t.ObservationCode == req.ObservationCode);
if (exists)
throw new ConflictException(
"A threshold for this observation code already exists.",
"THRESHOLD_CODE_CONFLICT");
var threshold = new AlertThreshold
{
Id = Guid.NewGuid(),
ObservationCode = req.ObservationCode,
DisplayName = req.DisplayName,
Unit = req.Unit,
CriticalLow = req.CriticalLow,
WarningLow = req.WarningLow,
WarningHigh = req.WarningHigh,
CriticalHigh = req.CriticalHigh,
CreatedAt = DateTimeOffset.UtcNow
};
_db.AlertThresholds.Add(threshold);
await _db.SaveChangesAsync();
await _audit.WriteAsync(
AuditAction.ThresholdCreated,
"AlertThreshold",
threshold.Id,
newValue: new
{
threshold.ObservationCode,
threshold.CriticalLow,
threshold.WarningLow,
threshold.WarningHigh,
threshold.CriticalHigh
});
await InvalidateCacheAsync(threshold.ObservationCode);
return threshold;
}
public async Task<List<AlertThreshold>> ListAsync() =>
await _db.AlertThresholds.OrderBy(t => t.ObservationCode).ToListAsync();
public async Task<AlertThreshold> GetByIdAsync(Guid id)
{
var threshold = await _db.AlertThresholds.FindAsync(id);
if (threshold is null)
throw new NotFoundException("Threshold not found.", "THRESHOLD_NOT_FOUND");
return threshold;
}
public async Task<AlertThreshold> UpdateAsync(Guid id, AlertThresholdRequest req)
{
var threshold = await _db.AlertThresholds.FindAsync(id);
if (threshold is null)
throw new NotFoundException("Threshold not found.", "THRESHOLD_NOT_FOUND");
var previous = new
{
threshold.ObservationCode,
threshold.CriticalLow,
threshold.WarningLow,
threshold.WarningHigh,
threshold.CriticalHigh,
threshold.SuppressionWindowMinutes
};
threshold.DisplayName = req.DisplayName;
threshold.Unit = req.Unit;
threshold.CriticalLow = req.CriticalLow;
threshold.WarningLow = req.WarningLow;
threshold.WarningHigh = req.WarningHigh;
threshold.CriticalHigh = req.CriticalHigh;
await _db.SaveChangesAsync();
await _audit.WriteAsync(
AuditAction.ThresholdUpdated,
"AlertThreshold",
threshold.Id,
previousValue: previous,
newValue: new
{
threshold.ObservationCode,
threshold.CriticalLow,
threshold.WarningLow,
threshold.WarningHigh,
threshold.CriticalHigh,
threshold.SuppressionWindowMinutes
});
await InvalidateCacheAsync(threshold.ObservationCode);
return threshold;
}
public async Task DeleteAsync(Guid id)
{
var threshold = await _db.AlertThresholds.FindAsync(id);
if (threshold is null)
throw new NotFoundException("Threshold not found.", "THRESHOLD_NOT_FOUND");
var previous = new
{
threshold.ObservationCode,
threshold.DisplayName,
threshold.Unit,
threshold.CriticalLow,
threshold.WarningLow,
threshold.WarningHigh,
threshold.CriticalHigh,
threshold.SuppressionWindowMinutes
};
var observationCode = threshold.ObservationCode;
_db.AlertThresholds.Remove(threshold);
await _db.SaveChangesAsync();
await _audit.WriteAsync(
AuditAction.ThresholdDeleted,
"AlertThreshold",
id,
previousValue: previous);
await InvalidateCacheAsync(observationCode);
}
private async Task InvalidateCacheAsync(string observationCode)
{
var cache = _redis.GetDatabase();
await cache.KeyDeleteAsync($"threshold:{observationCode}");
}
}