feat(management): handlers for native alarm source CRUD
This commit is contained in:
@@ -183,6 +183,7 @@ public class ManagementActor : ReceiveActor
|
|||||||
or DeleteDataConnectionCommand
|
or DeleteDataConnectionCommand
|
||||||
or AddTemplateAttributeCommand or UpdateTemplateAttributeCommand or DeleteTemplateAttributeCommand
|
or AddTemplateAttributeCommand or UpdateTemplateAttributeCommand or DeleteTemplateAttributeCommand
|
||||||
or AddTemplateAlarmCommand or UpdateTemplateAlarmCommand or DeleteTemplateAlarmCommand
|
or AddTemplateAlarmCommand or UpdateTemplateAlarmCommand or DeleteTemplateAlarmCommand
|
||||||
|
or AddTemplateNativeAlarmSourceCommand or UpdateTemplateNativeAlarmSourceCommand or DeleteTemplateNativeAlarmSourceCommand
|
||||||
or AddTemplateScriptCommand or UpdateTemplateScriptCommand or DeleteTemplateScriptCommand
|
or AddTemplateScriptCommand or UpdateTemplateScriptCommand or DeleteTemplateScriptCommand
|
||||||
or AddTemplateCompositionCommand or DeleteTemplateCompositionCommand
|
or AddTemplateCompositionCommand or DeleteTemplateCompositionCommand
|
||||||
or CreateSharedScriptCommand or UpdateSharedScriptCommand or DeleteSharedScriptCommand
|
or CreateSharedScriptCommand or UpdateSharedScriptCommand or DeleteSharedScriptCommand
|
||||||
@@ -204,6 +205,7 @@ public class ManagementActor : ReceiveActor
|
|||||||
or MgmtDisableInstanceCommand or MgmtDeleteInstanceCommand
|
or MgmtDisableInstanceCommand or MgmtDeleteInstanceCommand
|
||||||
or SetConnectionBindingsCommand or SetInstanceOverridesCommand or SetInstanceAreaCommand
|
or SetConnectionBindingsCommand or SetInstanceOverridesCommand or SetInstanceAreaCommand
|
||||||
or SetInstanceAlarmOverrideCommand or DeleteInstanceAlarmOverrideCommand
|
or SetInstanceAlarmOverrideCommand or DeleteInstanceAlarmOverrideCommand
|
||||||
|
or SetInstanceNativeAlarmSourceOverrideCommand or DeleteInstanceNativeAlarmSourceOverrideCommand
|
||||||
or GetDeploymentDiffCommand
|
or GetDeploymentDiffCommand
|
||||||
or MgmtDeployArtifactsCommand
|
or MgmtDeployArtifactsCommand
|
||||||
or QueryDeploymentsCommand
|
or QueryDeploymentsCommand
|
||||||
@@ -233,6 +235,10 @@ public class ManagementActor : ReceiveActor
|
|||||||
AddTemplateAlarmCommand cmd => await HandleAddAlarm(sp, cmd, user.Username),
|
AddTemplateAlarmCommand cmd => await HandleAddAlarm(sp, cmd, user.Username),
|
||||||
UpdateTemplateAlarmCommand cmd => await HandleUpdateAlarm(sp, cmd, user.Username),
|
UpdateTemplateAlarmCommand cmd => await HandleUpdateAlarm(sp, cmd, user.Username),
|
||||||
DeleteTemplateAlarmCommand cmd => await HandleDeleteAlarm(sp, cmd, user.Username),
|
DeleteTemplateAlarmCommand cmd => await HandleDeleteAlarm(sp, cmd, user.Username),
|
||||||
|
AddTemplateNativeAlarmSourceCommand cmd => await HandleAddNativeAlarmSource(sp, cmd),
|
||||||
|
UpdateTemplateNativeAlarmSourceCommand cmd => await HandleUpdateNativeAlarmSource(sp, cmd),
|
||||||
|
DeleteTemplateNativeAlarmSourceCommand cmd => await HandleDeleteNativeAlarmSource(sp, cmd),
|
||||||
|
ListTemplateNativeAlarmSourcesCommand cmd => await HandleListNativeAlarmSources(sp, cmd),
|
||||||
AddTemplateScriptCommand cmd => await HandleAddScript(sp, cmd, user.Username),
|
AddTemplateScriptCommand cmd => await HandleAddScript(sp, cmd, user.Username),
|
||||||
UpdateTemplateScriptCommand cmd => await HandleUpdateScript(sp, cmd, user.Username),
|
UpdateTemplateScriptCommand cmd => await HandleUpdateScript(sp, cmd, user.Username),
|
||||||
DeleteTemplateScriptCommand cmd => await HandleDeleteScript(sp, cmd, user.Username),
|
DeleteTemplateScriptCommand cmd => await HandleDeleteScript(sp, cmd, user.Username),
|
||||||
@@ -261,6 +267,9 @@ public class ManagementActor : ReceiveActor
|
|||||||
SetInstanceAlarmOverrideCommand cmd => await HandleSetInstanceAlarmOverride(sp, cmd, user),
|
SetInstanceAlarmOverrideCommand cmd => await HandleSetInstanceAlarmOverride(sp, cmd, user),
|
||||||
DeleteInstanceAlarmOverrideCommand cmd => await HandleDeleteInstanceAlarmOverride(sp, cmd, user),
|
DeleteInstanceAlarmOverrideCommand cmd => await HandleDeleteInstanceAlarmOverride(sp, cmd, user),
|
||||||
ListInstanceAlarmOverridesCommand cmd => await HandleListInstanceAlarmOverrides(sp, cmd, user),
|
ListInstanceAlarmOverridesCommand cmd => await HandleListInstanceAlarmOverrides(sp, cmd, user),
|
||||||
|
SetInstanceNativeAlarmSourceOverrideCommand cmd => await HandleSetInstanceNativeAlarmSourceOverride(sp, cmd, user),
|
||||||
|
DeleteInstanceNativeAlarmSourceOverrideCommand cmd => await HandleDeleteInstanceNativeAlarmSourceOverride(sp, cmd, user),
|
||||||
|
ListInstanceNativeAlarmSourceOverridesCommand cmd => await HandleListInstanceNativeAlarmSourceOverrides(sp, cmd, user),
|
||||||
|
|
||||||
// Sites
|
// Sites
|
||||||
ListSitesCommand => await HandleListSites(sp, user),
|
ListSitesCommand => await HandleListSites(sp, user),
|
||||||
@@ -765,6 +774,58 @@ public class ManagementActor : ReceiveActor
|
|||||||
return await repo.GetAlarmOverridesByInstanceIdAsync(cmd.InstanceId);
|
return await repo.GetAlarmOverridesByInstanceIdAsync(cmd.InstanceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task<object?> HandleSetInstanceNativeAlarmSourceOverride(
|
||||||
|
IServiceProvider sp, SetInstanceNativeAlarmSourceOverrideCommand cmd, AuthenticatedUser user)
|
||||||
|
{
|
||||||
|
await EnforceSiteScopeForInstance(sp, user, cmd.InstanceId);
|
||||||
|
var repo = sp.GetRequiredService<ITemplateEngineRepository>();
|
||||||
|
|
||||||
|
var existing = await repo.GetNativeAlarmSourceOverrideAsync(cmd.InstanceId, cmd.SourceCanonicalName);
|
||||||
|
if (existing == null)
|
||||||
|
{
|
||||||
|
var ovr = new InstanceNativeAlarmSourceOverride(cmd.SourceCanonicalName)
|
||||||
|
{
|
||||||
|
InstanceId = cmd.InstanceId,
|
||||||
|
ConnectionNameOverride = cmd.ConnectionNameOverride,
|
||||||
|
SourceReferenceOverride = cmd.SourceReferenceOverride,
|
||||||
|
ConditionFilterOverride = cmd.ConditionFilterOverride
|
||||||
|
};
|
||||||
|
await repo.AddInstanceNativeAlarmSourceOverrideAsync(ovr);
|
||||||
|
await repo.SaveChangesAsync();
|
||||||
|
return ovr;
|
||||||
|
}
|
||||||
|
|
||||||
|
existing.ConnectionNameOverride = cmd.ConnectionNameOverride;
|
||||||
|
existing.SourceReferenceOverride = cmd.SourceReferenceOverride;
|
||||||
|
existing.ConditionFilterOverride = cmd.ConditionFilterOverride;
|
||||||
|
await repo.UpdateInstanceNativeAlarmSourceOverrideAsync(existing);
|
||||||
|
await repo.SaveChangesAsync();
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<object?> HandleDeleteInstanceNativeAlarmSourceOverride(
|
||||||
|
IServiceProvider sp, DeleteInstanceNativeAlarmSourceOverrideCommand cmd, AuthenticatedUser user)
|
||||||
|
{
|
||||||
|
await EnforceSiteScopeForInstance(sp, user, cmd.InstanceId);
|
||||||
|
var repo = sp.GetRequiredService<ITemplateEngineRepository>();
|
||||||
|
|
||||||
|
var existing = await repo.GetNativeAlarmSourceOverrideAsync(cmd.InstanceId, cmd.SourceCanonicalName);
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
await repo.DeleteInstanceNativeAlarmSourceOverrideAsync(existing.Id);
|
||||||
|
await repo.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
return cmd.SourceCanonicalName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<object?> HandleListInstanceNativeAlarmSourceOverrides(
|
||||||
|
IServiceProvider sp, ListInstanceNativeAlarmSourceOverridesCommand cmd, AuthenticatedUser user)
|
||||||
|
{
|
||||||
|
await EnforceSiteScopeForInstance(sp, user, cmd.InstanceId);
|
||||||
|
var repo = sp.GetRequiredService<ITemplateEngineRepository>();
|
||||||
|
return await repo.GetNativeAlarmSourceOverridesByInstanceIdAsync(cmd.InstanceId);
|
||||||
|
}
|
||||||
|
|
||||||
private static async Task<object?> HandleGetDeploymentDiff(IServiceProvider sp, GetDeploymentDiffCommand cmd, AuthenticatedUser user)
|
private static async Task<object?> HandleGetDeploymentDiff(IServiceProvider sp, GetDeploymentDiffCommand cmd, AuthenticatedUser user)
|
||||||
{
|
{
|
||||||
await EnforceSiteScopeForInstance(sp, user, cmd.InstanceId);
|
await EnforceSiteScopeForInstance(sp, user, cmd.InstanceId);
|
||||||
@@ -1449,6 +1510,55 @@ public class ManagementActor : ReceiveActor
|
|||||||
return result.IsSuccess ? result.Value : throw new ManagementCommandException(result.Error);
|
return result.IsSuccess ? result.Value : throw new ManagementCommandException(result.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Native alarm source bindings (read-only mirror; repository-direct CRUD) ──
|
||||||
|
|
||||||
|
private static async Task<object?> HandleAddNativeAlarmSource(IServiceProvider sp, AddTemplateNativeAlarmSourceCommand cmd)
|
||||||
|
{
|
||||||
|
var repo = sp.GetRequiredService<ITemplateEngineRepository>();
|
||||||
|
var source = new TemplateNativeAlarmSource(cmd.Name)
|
||||||
|
{
|
||||||
|
TemplateId = cmd.TemplateId,
|
||||||
|
ConnectionName = cmd.ConnectionName,
|
||||||
|
SourceReference = cmd.SourceReference,
|
||||||
|
ConditionFilter = cmd.ConditionFilter,
|
||||||
|
Description = cmd.Description,
|
||||||
|
IsLocked = cmd.IsLocked
|
||||||
|
};
|
||||||
|
await repo.AddTemplateNativeAlarmSourceAsync(source);
|
||||||
|
await repo.SaveChangesAsync();
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<object?> HandleUpdateNativeAlarmSource(IServiceProvider sp, UpdateTemplateNativeAlarmSourceCommand cmd)
|
||||||
|
{
|
||||||
|
var repo = sp.GetRequiredService<ITemplateEngineRepository>();
|
||||||
|
var source = await repo.GetTemplateNativeAlarmSourceByIdAsync(cmd.NativeAlarmSourceId)
|
||||||
|
?? throw new ManagementCommandException($"Native alarm source {cmd.NativeAlarmSourceId} not found.");
|
||||||
|
source.Name = cmd.Name;
|
||||||
|
source.ConnectionName = cmd.ConnectionName;
|
||||||
|
source.SourceReference = cmd.SourceReference;
|
||||||
|
source.ConditionFilter = cmd.ConditionFilter;
|
||||||
|
source.Description = cmd.Description;
|
||||||
|
source.IsLocked = cmd.IsLocked;
|
||||||
|
await repo.UpdateTemplateNativeAlarmSourceAsync(source);
|
||||||
|
await repo.SaveChangesAsync();
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<object?> HandleDeleteNativeAlarmSource(IServiceProvider sp, DeleteTemplateNativeAlarmSourceCommand cmd)
|
||||||
|
{
|
||||||
|
var repo = sp.GetRequiredService<ITemplateEngineRepository>();
|
||||||
|
await repo.DeleteTemplateNativeAlarmSourceAsync(cmd.NativeAlarmSourceId);
|
||||||
|
await repo.SaveChangesAsync();
|
||||||
|
return cmd.NativeAlarmSourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<object?> HandleListNativeAlarmSources(IServiceProvider sp, ListTemplateNativeAlarmSourcesCommand cmd)
|
||||||
|
{
|
||||||
|
var repo = sp.GetRequiredService<ITemplateEngineRepository>();
|
||||||
|
return await repo.GetNativeAlarmSourcesByTemplateIdAsync(cmd.TemplateId);
|
||||||
|
}
|
||||||
|
|
||||||
private static async Task<object?> HandleAddScript(IServiceProvider sp, AddTemplateScriptCommand cmd, string user)
|
private static async Task<object?> HandleAddScript(IServiceProvider sp, AddTemplateScriptCommand cmd, string user)
|
||||||
{
|
{
|
||||||
var svc = sp.GetRequiredService<TemplateService>();
|
var svc = sp.GetRequiredService<TemplateService>();
|
||||||
|
|||||||
@@ -1416,4 +1416,85 @@ public class ManagementActorTests : TestKit, IDisposable
|
|||||||
// earlier Modified row's Overwrite action.
|
// earlier Modified row's Overwrite action.
|
||||||
Assert.Equal(Commons.Types.Transport.ResolutionAction.Skip, dupResolutions[0].Action);
|
Assert.Equal(Commons.Types.Transport.ResolutionAction.Skip, dupResolutions[0].Action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Native alarm source CRUD (Task 21)
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddTemplateNativeAlarmSource_WithDesignRole_ReturnsSuccess()
|
||||||
|
{
|
||||||
|
var actor = CreateActor();
|
||||||
|
var envelope = Envelope(
|
||||||
|
new AddTemplateNativeAlarmSourceCommand(1, "Pressure", "Opc", "ns=2;s=T01", null, "desc", false),
|
||||||
|
"Design");
|
||||||
|
|
||||||
|
actor.Tell(envelope);
|
||||||
|
|
||||||
|
ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
|
||||||
|
_templateRepo.ReceivedWithAnyArgs(1).AddTemplateNativeAlarmSourceAsync(default!, default);
|
||||||
|
_templateRepo.ReceivedWithAnyArgs(1).SaveChangesAsync(default);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddTemplateNativeAlarmSource_WithDeploymentRole_ReturnsUnauthorized()
|
||||||
|
{
|
||||||
|
var actor = CreateActor();
|
||||||
|
var envelope = Envelope(
|
||||||
|
new AddTemplateNativeAlarmSourceCommand(1, "Pressure", "Opc", "ns=2;s=T01", null, null, false),
|
||||||
|
"Deployment");
|
||||||
|
|
||||||
|
actor.Tell(envelope);
|
||||||
|
|
||||||
|
var response = ExpectMsg<ManagementUnauthorized>(TimeSpan.FromSeconds(5));
|
||||||
|
Assert.Contains("Design", response.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ListTemplateNativeAlarmSources_ReturnsData()
|
||||||
|
{
|
||||||
|
_templateRepo.GetNativeAlarmSourcesByTemplateIdAsync(1, Arg.Any<CancellationToken>())
|
||||||
|
.Returns(new List<TemplateNativeAlarmSource>
|
||||||
|
{
|
||||||
|
new("Pressure") { Id = 1, TemplateId = 1, ConnectionName = "Opc", SourceReference = "ns=2;s=T01" }
|
||||||
|
});
|
||||||
|
|
||||||
|
var actor = CreateActor();
|
||||||
|
var envelope = Envelope(new ListTemplateNativeAlarmSourcesCommand(1));
|
||||||
|
|
||||||
|
actor.Tell(envelope);
|
||||||
|
|
||||||
|
var response = ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
|
||||||
|
Assert.Contains("Pressure", response.JsonData);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SetInstanceNativeAlarmSourceOverride_WithDeploymentRole_ReturnsSuccess()
|
||||||
|
{
|
||||||
|
// No prior override → Add path.
|
||||||
|
var actor = CreateActor();
|
||||||
|
var envelope = Envelope(
|
||||||
|
new SetInstanceNativeAlarmSourceOverrideCommand(1, "Pressure", "Opc2", "ns=2;s=NEW", null),
|
||||||
|
"Deployment");
|
||||||
|
|
||||||
|
actor.Tell(envelope);
|
||||||
|
|
||||||
|
ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
|
||||||
|
_templateRepo.ReceivedWithAnyArgs(1).AddInstanceNativeAlarmSourceOverrideAsync(default!, default);
|
||||||
|
_templateRepo.ReceivedWithAnyArgs(1).SaveChangesAsync(default);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SetInstanceNativeAlarmSourceOverride_WithDesignRole_ReturnsUnauthorized()
|
||||||
|
{
|
||||||
|
var actor = CreateActor();
|
||||||
|
var envelope = Envelope(
|
||||||
|
new SetInstanceNativeAlarmSourceOverrideCommand(1, "Pressure", "Opc2", "ns=2;s=NEW", null),
|
||||||
|
"Design");
|
||||||
|
|
||||||
|
actor.Tell(envelope);
|
||||||
|
|
||||||
|
var response = ExpectMsg<ManagementUnauthorized>(TimeSpan.FromSeconds(5));
|
||||||
|
Assert.Contains("Deployment", response.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user