fix(uns): guard scripted-alarm name uniqueness on create/update (code-review)
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user