fix(uns): guard scripted-alarm name uniqueness on create/update (code-review)

This commit is contained in:
Joseph Doherty
2026-06-11 14:31:35 -04:00
parent 705ed6234f
commit 5cae3c5b96
2 changed files with 52 additions and 7 deletions
@@ -1316,6 +1316,9 @@ public sealed class UnsTreeService(IDbContextFactory<OtOpcUaConfigDbContext> dbF
if (await db.ScriptedAlarms.AnyAsync(a => a.ScriptedAlarmId == input.ScriptedAlarmId, ct))
return new UnsMutationResult(false, $"ScriptedAlarm '{input.ScriptedAlarmId}' already exists.");
if (await db.ScriptedAlarms.AnyAsync(a => a.EquipmentId == equipmentId && a.Name == input.Name, ct))
return new UnsMutationResult(false, $"A scripted alarm named '{input.Name}' already exists on this equipment.");
db.ScriptedAlarms.Add(new ScriptedAlarm
{
ScriptedAlarmId = input.ScriptedAlarmId,
@@ -1338,7 +1341,14 @@ public sealed class UnsTreeService(IDbContextFactory<OtOpcUaConfigDbContext> dbF
{
await using var db = await dbFactory.CreateDbContextAsync(ct);
var entity = await db.ScriptedAlarms.FirstOrDefaultAsync(a => a.ScriptedAlarmId == scriptedAlarmId, ct);
if (entity is null) return new UnsMutationResult(false, "Row no longer exists.");
if (entity is null)
{
return new UnsMutationResult(false, "Row no longer exists.");
}
if (await db.ScriptedAlarms.AnyAsync(a => a.EquipmentId == entity.EquipmentId && a.Name == input.Name && a.ScriptedAlarmId != scriptedAlarmId, ct))
return new UnsMutationResult(false, $"A scripted alarm named '{input.Name}' already exists on this equipment.");
db.Entry(entity).Property(e => e.RowVersion).OriginalValue = rowVersion;
entity.Name = input.Name;
entity.AlarmType = input.AlarmType;
@@ -1348,8 +1358,16 @@ public sealed class UnsTreeService(IDbContextFactory<OtOpcUaConfigDbContext> dbF
entity.HistorizeToAveva = input.HistorizeToAveva;
entity.Retain = input.Retain;
entity.Enabled = input.Enabled;
try { await db.SaveChangesAsync(ct); return new UnsMutationResult(true, null); }
catch (DbUpdateConcurrencyException) { return new UnsMutationResult(false, "Another user changed this scripted alarm while you were editing."); }
try
{
await db.SaveChangesAsync(ct);
return new UnsMutationResult(true, null);
}
catch (DbUpdateConcurrencyException)
{
return new UnsMutationResult(false, "Another user changed this scripted alarm while you were editing.");
}
}
/// <inheritdoc />
@@ -1357,11 +1375,26 @@ public sealed class UnsTreeService(IDbContextFactory<OtOpcUaConfigDbContext> dbF
{
await using var db = await dbFactory.CreateDbContextAsync(ct);
var entity = await db.ScriptedAlarms.FirstOrDefaultAsync(a => a.ScriptedAlarmId == scriptedAlarmId, ct);
if (entity is null) return new UnsMutationResult(true, null);
if (entity is null)
{
return new UnsMutationResult(true, null);
}
db.Entry(entity).Property(e => e.RowVersion).OriginalValue = rowVersion;
db.ScriptedAlarms.Remove(entity);
try { await db.SaveChangesAsync(ct); return new UnsMutationResult(true, null); }
catch (DbUpdateConcurrencyException) { return new UnsMutationResult(false, "Another user changed this alarm while you were viewing it."); }
catch (Exception ex) { return new UnsMutationResult(false, $"Delete failed: {ex.Message}."); }
try
{
await db.SaveChangesAsync(ct);
return new UnsMutationResult(true, null);
}
catch (DbUpdateConcurrencyException)
{
return new UnsMutationResult(false, "Another user changed this alarm while you were viewing it.");
}
catch (Exception ex)
{
return new UnsMutationResult(false, $"Delete failed: {ex.Message}.");
}
}
}
@@ -74,4 +74,16 @@ public sealed class UnsTreeServiceScriptedAlarmTests
(await svc.DeleteScriptedAlarmAsync("SA-1", dto!.RowVersion)).Ok.ShouldBeTrue();
(await svc.LoadAlarmsForEquipmentAsync(UnsTreeTestDb.SeededEquipmentId)).ShouldBeEmpty();
}
[Fact]
public async Task Create_rejects_duplicate_name_on_same_equipment()
{
var svc = SeededService();
(await svc.CreateScriptedAlarmAsync(UnsTreeTestDb.SeededEquipmentId, Sample("SA-1"))).Ok.ShouldBeTrue();
// Same Name ("Over-temp" from Sample), different id, same equipment → rejected.
var dup = await svc.CreateScriptedAlarmAsync(UnsTreeTestDb.SeededEquipmentId, Sample("SA-2"));
dup.Ok.ShouldBeFalse();
dup.Error.ShouldNotBeNull();
dup.Error!.ShouldContain("already exists");
}
}