120 lines
3.8 KiB
C#
120 lines
3.8 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;
|
|
}
|
|
|
|
private async Task InvalidateCacheAsync(string observationCode)
|
|
{
|
|
var cache = _redis.GetDatabase();
|
|
await cache.KeyDeleteAsync($"threshold:{observationCode}");
|
|
}
|
|
} |