feat: implement ManagementActor with all command handlers and authorization
This commit is contained in:
692
src/ScadaLink.ManagementService/ManagementActor.cs
Normal file
692
src/ScadaLink.ManagementService/ManagementActor.cs
Normal file
@@ -0,0 +1,692 @@
|
||||
using System.Security.Cryptography;
|
||||
using Akka.Actor;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ScadaLink.Commons.Entities.ExternalSystems;
|
||||
using ScadaLink.Commons.Entities.InboundApi;
|
||||
using ScadaLink.Commons.Entities.Instances;
|
||||
using ScadaLink.Commons.Entities.Notifications;
|
||||
using ScadaLink.Commons.Entities.Security;
|
||||
using ScadaLink.Commons.Entities.Sites;
|
||||
using ScadaLink.Commons.Interfaces.Repositories;
|
||||
using ScadaLink.Commons.Messages.Management;
|
||||
using ScadaLink.DeploymentManager;
|
||||
using ScadaLink.HealthMonitoring;
|
||||
using ScadaLink.TemplateEngine;
|
||||
using ScadaLink.TemplateEngine.Services;
|
||||
|
||||
namespace ScadaLink.ManagementService;
|
||||
|
||||
/// <summary>
|
||||
/// Central actor that handles all management commands from the CLI (via ClusterClient).
|
||||
/// Receives ManagementEnvelope messages, authorizes based on roles, then delegates to
|
||||
/// the appropriate service or repository using scoped DI.
|
||||
/// </summary>
|
||||
public class ManagementActor : ReceiveActor
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<ManagementActor> _logger;
|
||||
|
||||
public ManagementActor(IServiceProvider serviceProvider, ILogger<ManagementActor> logger)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = logger;
|
||||
Receive<ManagementEnvelope>(HandleEnvelope);
|
||||
}
|
||||
|
||||
private void HandleEnvelope(ManagementEnvelope envelope)
|
||||
{
|
||||
var sender = Sender;
|
||||
var correlationId = envelope.CorrelationId;
|
||||
var user = envelope.User;
|
||||
|
||||
// Check authorization
|
||||
var requiredRole = GetRequiredRole(envelope.Command);
|
||||
if (requiredRole != null && !user.Roles.Contains(requiredRole, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
sender.Tell(new ManagementUnauthorized(correlationId,
|
||||
$"Role '{requiredRole}' required for {envelope.Command.GetType().Name}"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Process command asynchronously with scoped DI
|
||||
Task.Run(async () =>
|
||||
{
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
try
|
||||
{
|
||||
var result = await DispatchCommand(scope.ServiceProvider, envelope.Command, user.Username);
|
||||
sender.Tell(new ManagementSuccess(correlationId, result));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Management command {Command} failed (CorrelationId={CorrelationId})",
|
||||
envelope.Command.GetType().Name, correlationId);
|
||||
sender.Tell(new ManagementError(correlationId, ex.Message, "COMMAND_FAILED"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static string? GetRequiredRole(object command) => command switch
|
||||
{
|
||||
// Admin operations
|
||||
CreateSiteCommand or UpdateSiteCommand or DeleteSiteCommand
|
||||
or CreateAreaCommand or DeleteAreaCommand
|
||||
or ListRoleMappingsCommand or CreateRoleMappingCommand
|
||||
or UpdateRoleMappingCommand or DeleteRoleMappingCommand
|
||||
or ListApiKeysCommand or CreateApiKeyCommand or DeleteApiKeyCommand => "Admin",
|
||||
|
||||
// Design operations
|
||||
CreateTemplateCommand or UpdateTemplateCommand or DeleteTemplateCommand
|
||||
or ValidateTemplateCommand
|
||||
or CreateExternalSystemCommand or UpdateExternalSystemCommand
|
||||
or DeleteExternalSystemCommand
|
||||
or CreateNotificationListCommand or UpdateNotificationListCommand
|
||||
or DeleteNotificationListCommand
|
||||
or UpdateSmtpConfigCommand
|
||||
or CreateDataConnectionCommand or UpdateDataConnectionCommand
|
||||
or DeleteDataConnectionCommand
|
||||
or AssignDataConnectionToSiteCommand
|
||||
or UnassignDataConnectionFromSiteCommand => "Design",
|
||||
|
||||
// Deployment operations
|
||||
CreateInstanceCommand or MgmtDeployInstanceCommand or MgmtEnableInstanceCommand
|
||||
or MgmtDisableInstanceCommand or MgmtDeleteInstanceCommand
|
||||
or SetConnectionBindingsCommand
|
||||
or MgmtDeployArtifactsCommand => "Deployment",
|
||||
|
||||
// Read-only queries -- any authenticated user
|
||||
_ => null
|
||||
};
|
||||
|
||||
private async Task<object?> DispatchCommand(IServiceProvider sp, object command, string user)
|
||||
{
|
||||
return command switch
|
||||
{
|
||||
// Templates
|
||||
ListTemplatesCommand => await HandleListTemplates(sp),
|
||||
GetTemplateCommand cmd => await HandleGetTemplate(sp, cmd),
|
||||
CreateTemplateCommand cmd => await HandleCreateTemplate(sp, cmd, user),
|
||||
UpdateTemplateCommand cmd => await HandleUpdateTemplate(sp, cmd, user),
|
||||
DeleteTemplateCommand cmd => await HandleDeleteTemplate(sp, cmd, user),
|
||||
ValidateTemplateCommand cmd => await HandleValidateTemplate(sp, cmd),
|
||||
|
||||
// Instances
|
||||
ListInstancesCommand cmd => await HandleListInstances(sp, cmd),
|
||||
GetInstanceCommand cmd => await HandleGetInstance(sp, cmd),
|
||||
CreateInstanceCommand cmd => await HandleCreateInstance(sp, cmd, user),
|
||||
MgmtDeployInstanceCommand cmd => await HandleDeployInstance(sp, cmd, user),
|
||||
MgmtEnableInstanceCommand cmd => await HandleEnableInstance(sp, cmd, user),
|
||||
MgmtDisableInstanceCommand cmd => await HandleDisableInstance(sp, cmd, user),
|
||||
MgmtDeleteInstanceCommand cmd => await HandleDeleteInstance(sp, cmd, user),
|
||||
SetConnectionBindingsCommand cmd => await HandleSetConnectionBindings(sp, cmd, user),
|
||||
|
||||
// Sites
|
||||
ListSitesCommand => await HandleListSites(sp),
|
||||
GetSiteCommand cmd => await HandleGetSite(sp, cmd),
|
||||
CreateSiteCommand cmd => await HandleCreateSite(sp, cmd),
|
||||
UpdateSiteCommand cmd => await HandleUpdateSite(sp, cmd),
|
||||
DeleteSiteCommand cmd => await HandleDeleteSite(sp, cmd),
|
||||
ListAreasCommand cmd => await HandleListAreas(sp, cmd),
|
||||
CreateAreaCommand cmd => await HandleCreateArea(sp, cmd),
|
||||
DeleteAreaCommand cmd => await HandleDeleteArea(sp, cmd),
|
||||
|
||||
// Data Connections
|
||||
ListDataConnectionsCommand => await HandleListDataConnections(sp),
|
||||
GetDataConnectionCommand cmd => await HandleGetDataConnection(sp, cmd),
|
||||
CreateDataConnectionCommand cmd => await HandleCreateDataConnection(sp, cmd),
|
||||
UpdateDataConnectionCommand cmd => await HandleUpdateDataConnection(sp, cmd),
|
||||
DeleteDataConnectionCommand cmd => await HandleDeleteDataConnection(sp, cmd),
|
||||
AssignDataConnectionToSiteCommand cmd => await HandleAssignDataConnectionToSite(sp, cmd),
|
||||
UnassignDataConnectionFromSiteCommand cmd => await HandleUnassignDataConnectionFromSite(sp, cmd),
|
||||
|
||||
// External Systems
|
||||
ListExternalSystemsCommand => await HandleListExternalSystems(sp),
|
||||
GetExternalSystemCommand cmd => await HandleGetExternalSystem(sp, cmd),
|
||||
CreateExternalSystemCommand cmd => await HandleCreateExternalSystem(sp, cmd),
|
||||
UpdateExternalSystemCommand cmd => await HandleUpdateExternalSystem(sp, cmd),
|
||||
DeleteExternalSystemCommand cmd => await HandleDeleteExternalSystem(sp, cmd),
|
||||
|
||||
// Notification Lists
|
||||
ListNotificationListsCommand => await HandleListNotificationLists(sp),
|
||||
GetNotificationListCommand cmd => await HandleGetNotificationList(sp, cmd),
|
||||
CreateNotificationListCommand cmd => await HandleCreateNotificationList(sp, cmd),
|
||||
UpdateNotificationListCommand cmd => await HandleUpdateNotificationList(sp, cmd),
|
||||
DeleteNotificationListCommand cmd => await HandleDeleteNotificationList(sp, cmd),
|
||||
ListSmtpConfigsCommand => await HandleListSmtpConfigs(sp),
|
||||
UpdateSmtpConfigCommand cmd => await HandleUpdateSmtpConfig(sp, cmd),
|
||||
|
||||
// Security
|
||||
ListRoleMappingsCommand => await HandleListRoleMappings(sp),
|
||||
CreateRoleMappingCommand cmd => await HandleCreateRoleMapping(sp, cmd),
|
||||
UpdateRoleMappingCommand cmd => await HandleUpdateRoleMapping(sp, cmd),
|
||||
DeleteRoleMappingCommand cmd => await HandleDeleteRoleMapping(sp, cmd),
|
||||
ListApiKeysCommand => await HandleListApiKeys(sp),
|
||||
CreateApiKeyCommand cmd => await HandleCreateApiKey(sp, cmd),
|
||||
DeleteApiKeyCommand cmd => await HandleDeleteApiKey(sp, cmd),
|
||||
|
||||
// Deployments
|
||||
MgmtDeployArtifactsCommand cmd => await HandleDeployArtifacts(sp, cmd, user),
|
||||
QueryDeploymentsCommand cmd => await HandleQueryDeployments(sp, cmd),
|
||||
|
||||
// Audit Log
|
||||
QueryAuditLogCommand cmd => await HandleQueryAuditLog(sp, cmd),
|
||||
|
||||
// Health
|
||||
GetHealthSummaryCommand => HandleGetHealthSummary(sp),
|
||||
GetSiteHealthCommand cmd => HandleGetSiteHealth(sp, cmd),
|
||||
|
||||
_ => throw new NotSupportedException($"Unknown command type: {command.GetType().Name}")
|
||||
};
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Template handlers
|
||||
// ========================================================================
|
||||
|
||||
private static async Task<object?> HandleListTemplates(IServiceProvider sp)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ITemplateEngineRepository>();
|
||||
return await repo.GetAllTemplatesAsync();
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleGetTemplate(IServiceProvider sp, GetTemplateCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ITemplateEngineRepository>();
|
||||
return await repo.GetTemplateWithChildrenAsync(cmd.TemplateId);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleCreateTemplate(IServiceProvider sp, CreateTemplateCommand cmd, string user)
|
||||
{
|
||||
var svc = sp.GetRequiredService<TemplateService>();
|
||||
var result = await svc.CreateTemplateAsync(cmd.Name, cmd.Description, cmd.ParentTemplateId, user);
|
||||
return result.IsSuccess
|
||||
? result.Value
|
||||
: throw new InvalidOperationException(result.Error);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleUpdateTemplate(IServiceProvider sp, UpdateTemplateCommand cmd, string user)
|
||||
{
|
||||
var svc = sp.GetRequiredService<TemplateService>();
|
||||
var result = await svc.UpdateTemplateAsync(cmd.TemplateId, cmd.Name, cmd.Description, cmd.ParentTemplateId, user);
|
||||
return result.IsSuccess
|
||||
? result.Value
|
||||
: throw new InvalidOperationException(result.Error);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleDeleteTemplate(IServiceProvider sp, DeleteTemplateCommand cmd, string user)
|
||||
{
|
||||
var svc = sp.GetRequiredService<TemplateService>();
|
||||
var result = await svc.DeleteTemplateAsync(cmd.TemplateId, user);
|
||||
return result.IsSuccess
|
||||
? result.Value
|
||||
: throw new InvalidOperationException(result.Error);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleValidateTemplate(IServiceProvider sp, ValidateTemplateCommand cmd)
|
||||
{
|
||||
var svc = sp.GetRequiredService<TemplateService>();
|
||||
return await svc.DetectCollisionsAsync(cmd.TemplateId);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Instance handlers
|
||||
// ========================================================================
|
||||
|
||||
private static async Task<object?> HandleListInstances(IServiceProvider sp, ListInstancesCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ICentralUiRepository>();
|
||||
return await repo.GetInstancesFilteredAsync(cmd.SiteId, cmd.TemplateId, cmd.SearchTerm);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleGetInstance(IServiceProvider sp, GetInstanceCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ITemplateEngineRepository>();
|
||||
return await repo.GetInstanceByIdAsync(cmd.InstanceId);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleCreateInstance(IServiceProvider sp, CreateInstanceCommand cmd, string user)
|
||||
{
|
||||
var svc = sp.GetRequiredService<InstanceService>();
|
||||
var result = await svc.CreateInstanceAsync(cmd.UniqueName, cmd.TemplateId, cmd.SiteId, cmd.AreaId, user);
|
||||
return result.IsSuccess
|
||||
? result.Value
|
||||
: throw new InvalidOperationException(result.Error);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleDeployInstance(IServiceProvider sp, MgmtDeployInstanceCommand cmd, string user)
|
||||
{
|
||||
var svc = sp.GetRequiredService<DeploymentService>();
|
||||
var result = await svc.DeployInstanceAsync(cmd.InstanceId, user);
|
||||
return result.IsSuccess
|
||||
? result.Value
|
||||
: throw new InvalidOperationException(result.Error);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleEnableInstance(IServiceProvider sp, MgmtEnableInstanceCommand cmd, string user)
|
||||
{
|
||||
var svc = sp.GetRequiredService<DeploymentService>();
|
||||
var result = await svc.EnableInstanceAsync(cmd.InstanceId, user);
|
||||
return result.IsSuccess
|
||||
? result.Value
|
||||
: throw new InvalidOperationException(result.Error);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleDisableInstance(IServiceProvider sp, MgmtDisableInstanceCommand cmd, string user)
|
||||
{
|
||||
var svc = sp.GetRequiredService<DeploymentService>();
|
||||
var result = await svc.DisableInstanceAsync(cmd.InstanceId, user);
|
||||
return result.IsSuccess
|
||||
? result.Value
|
||||
: throw new InvalidOperationException(result.Error);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleDeleteInstance(IServiceProvider sp, MgmtDeleteInstanceCommand cmd, string user)
|
||||
{
|
||||
var svc = sp.GetRequiredService<DeploymentService>();
|
||||
var result = await svc.DeleteInstanceAsync(cmd.InstanceId, user);
|
||||
return result.IsSuccess
|
||||
? result.Value
|
||||
: throw new InvalidOperationException(result.Error);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleSetConnectionBindings(IServiceProvider sp, SetConnectionBindingsCommand cmd, string user)
|
||||
{
|
||||
var svc = sp.GetRequiredService<InstanceService>();
|
||||
var result = await svc.SetConnectionBindingsAsync(cmd.InstanceId, cmd.Bindings, user);
|
||||
return result.IsSuccess
|
||||
? result.Value
|
||||
: throw new InvalidOperationException(result.Error);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Site handlers
|
||||
// ========================================================================
|
||||
|
||||
private static async Task<object?> HandleListSites(IServiceProvider sp)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISiteRepository>();
|
||||
return await repo.GetAllSitesAsync();
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleGetSite(IServiceProvider sp, GetSiteCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISiteRepository>();
|
||||
return await repo.GetSiteByIdAsync(cmd.SiteId);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleCreateSite(IServiceProvider sp, CreateSiteCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISiteRepository>();
|
||||
var site = new Site(cmd.Name, cmd.SiteIdentifier) { Description = cmd.Description };
|
||||
await repo.AddSiteAsync(site);
|
||||
await repo.SaveChangesAsync();
|
||||
return site;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleUpdateSite(IServiceProvider sp, UpdateSiteCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISiteRepository>();
|
||||
var site = await repo.GetSiteByIdAsync(cmd.SiteId)
|
||||
?? throw new InvalidOperationException($"Site with ID {cmd.SiteId} not found.");
|
||||
site.Name = cmd.Name;
|
||||
site.Description = cmd.Description;
|
||||
await repo.UpdateSiteAsync(site);
|
||||
await repo.SaveChangesAsync();
|
||||
return site;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleDeleteSite(IServiceProvider sp, DeleteSiteCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISiteRepository>();
|
||||
// Check for instances referencing this site
|
||||
var instances = await repo.GetInstancesBySiteIdAsync(cmd.SiteId);
|
||||
if (instances.Count > 0)
|
||||
throw new InvalidOperationException(
|
||||
$"Cannot delete site {cmd.SiteId}: it has {instances.Count} instance(s).");
|
||||
await repo.DeleteSiteAsync(cmd.SiteId);
|
||||
await repo.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleListAreas(IServiceProvider sp, ListAreasCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ICentralUiRepository>();
|
||||
return await repo.GetAreaTreeBySiteIdAsync(cmd.SiteId);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleCreateArea(IServiceProvider sp, CreateAreaCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ITemplateEngineRepository>();
|
||||
var area = new Area(cmd.Name)
|
||||
{
|
||||
SiteId = cmd.SiteId,
|
||||
ParentAreaId = cmd.ParentAreaId
|
||||
};
|
||||
await repo.AddAreaAsync(area);
|
||||
await repo.SaveChangesAsync();
|
||||
return area;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleDeleteArea(IServiceProvider sp, DeleteAreaCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ITemplateEngineRepository>();
|
||||
await repo.DeleteAreaAsync(cmd.AreaId);
|
||||
await repo.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Data Connection handlers
|
||||
// ========================================================================
|
||||
|
||||
private static async Task<object?> HandleListDataConnections(IServiceProvider sp)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISiteRepository>();
|
||||
return await repo.GetAllDataConnectionsAsync();
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleGetDataConnection(IServiceProvider sp, GetDataConnectionCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISiteRepository>();
|
||||
return await repo.GetDataConnectionByIdAsync(cmd.DataConnectionId);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleCreateDataConnection(IServiceProvider sp, CreateDataConnectionCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISiteRepository>();
|
||||
var conn = new DataConnection(cmd.Name, cmd.Protocol) { Configuration = cmd.Configuration };
|
||||
await repo.AddDataConnectionAsync(conn);
|
||||
await repo.SaveChangesAsync();
|
||||
return conn;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleUpdateDataConnection(IServiceProvider sp, UpdateDataConnectionCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISiteRepository>();
|
||||
var conn = await repo.GetDataConnectionByIdAsync(cmd.DataConnectionId)
|
||||
?? throw new InvalidOperationException($"DataConnection with ID {cmd.DataConnectionId} not found.");
|
||||
conn.Name = cmd.Name;
|
||||
conn.Protocol = cmd.Protocol;
|
||||
conn.Configuration = cmd.Configuration;
|
||||
await repo.UpdateDataConnectionAsync(conn);
|
||||
await repo.SaveChangesAsync();
|
||||
return conn;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleDeleteDataConnection(IServiceProvider sp, DeleteDataConnectionCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISiteRepository>();
|
||||
await repo.DeleteDataConnectionAsync(cmd.DataConnectionId);
|
||||
await repo.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleAssignDataConnectionToSite(IServiceProvider sp, AssignDataConnectionToSiteCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISiteRepository>();
|
||||
var assignment = new SiteDataConnectionAssignment
|
||||
{
|
||||
SiteId = cmd.SiteId,
|
||||
DataConnectionId = cmd.DataConnectionId
|
||||
};
|
||||
await repo.AddSiteDataConnectionAssignmentAsync(assignment);
|
||||
await repo.SaveChangesAsync();
|
||||
return assignment;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleUnassignDataConnectionFromSite(IServiceProvider sp, UnassignDataConnectionFromSiteCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISiteRepository>();
|
||||
await repo.DeleteSiteDataConnectionAssignmentAsync(cmd.AssignmentId);
|
||||
await repo.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// External System handlers
|
||||
// ========================================================================
|
||||
|
||||
private static async Task<object?> HandleListExternalSystems(IServiceProvider sp)
|
||||
{
|
||||
var repo = sp.GetRequiredService<IExternalSystemRepository>();
|
||||
return await repo.GetAllExternalSystemsAsync();
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleGetExternalSystem(IServiceProvider sp, GetExternalSystemCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<IExternalSystemRepository>();
|
||||
return await repo.GetExternalSystemByIdAsync(cmd.ExternalSystemId);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleCreateExternalSystem(IServiceProvider sp, CreateExternalSystemCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<IExternalSystemRepository>();
|
||||
var def = new ExternalSystemDefinition(cmd.Name, cmd.EndpointUrl, cmd.AuthType)
|
||||
{
|
||||
AuthConfiguration = cmd.AuthConfiguration
|
||||
};
|
||||
await repo.AddExternalSystemAsync(def);
|
||||
await repo.SaveChangesAsync();
|
||||
return def;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleUpdateExternalSystem(IServiceProvider sp, UpdateExternalSystemCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<IExternalSystemRepository>();
|
||||
var def = await repo.GetExternalSystemByIdAsync(cmd.ExternalSystemId)
|
||||
?? throw new InvalidOperationException($"ExternalSystem with ID {cmd.ExternalSystemId} not found.");
|
||||
def.Name = cmd.Name;
|
||||
def.EndpointUrl = cmd.EndpointUrl;
|
||||
def.AuthType = cmd.AuthType;
|
||||
def.AuthConfiguration = cmd.AuthConfiguration;
|
||||
await repo.UpdateExternalSystemAsync(def);
|
||||
await repo.SaveChangesAsync();
|
||||
return def;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleDeleteExternalSystem(IServiceProvider sp, DeleteExternalSystemCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<IExternalSystemRepository>();
|
||||
await repo.DeleteExternalSystemAsync(cmd.ExternalSystemId);
|
||||
await repo.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Notification handlers
|
||||
// ========================================================================
|
||||
|
||||
private static async Task<object?> HandleListNotificationLists(IServiceProvider sp)
|
||||
{
|
||||
var repo = sp.GetRequiredService<INotificationRepository>();
|
||||
return await repo.GetAllNotificationListsAsync();
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleGetNotificationList(IServiceProvider sp, GetNotificationListCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<INotificationRepository>();
|
||||
return await repo.GetNotificationListByIdAsync(cmd.NotificationListId);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleCreateNotificationList(IServiceProvider sp, CreateNotificationListCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<INotificationRepository>();
|
||||
var list = new NotificationList(cmd.Name);
|
||||
foreach (var email in cmd.RecipientEmails)
|
||||
{
|
||||
list.Recipients.Add(new NotificationRecipient(email, email));
|
||||
}
|
||||
await repo.AddNotificationListAsync(list);
|
||||
await repo.SaveChangesAsync();
|
||||
return list;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleUpdateNotificationList(IServiceProvider sp, UpdateNotificationListCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<INotificationRepository>();
|
||||
var list = await repo.GetNotificationListByIdAsync(cmd.NotificationListId)
|
||||
?? throw new InvalidOperationException($"NotificationList with ID {cmd.NotificationListId} not found.");
|
||||
list.Name = cmd.Name;
|
||||
|
||||
// Remove existing recipients and re-add
|
||||
var existingRecipients = await repo.GetRecipientsByListIdAsync(cmd.NotificationListId);
|
||||
foreach (var r in existingRecipients)
|
||||
{
|
||||
await repo.DeleteRecipientAsync(r.Id);
|
||||
}
|
||||
|
||||
foreach (var email in cmd.RecipientEmails)
|
||||
{
|
||||
await repo.AddRecipientAsync(new NotificationRecipient(email, email)
|
||||
{
|
||||
NotificationListId = cmd.NotificationListId
|
||||
});
|
||||
}
|
||||
|
||||
await repo.UpdateNotificationListAsync(list);
|
||||
await repo.SaveChangesAsync();
|
||||
return list;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleDeleteNotificationList(IServiceProvider sp, DeleteNotificationListCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<INotificationRepository>();
|
||||
await repo.DeleteNotificationListAsync(cmd.NotificationListId);
|
||||
await repo.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleListSmtpConfigs(IServiceProvider sp)
|
||||
{
|
||||
var repo = sp.GetRequiredService<INotificationRepository>();
|
||||
return await repo.GetAllSmtpConfigurationsAsync();
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleUpdateSmtpConfig(IServiceProvider sp, UpdateSmtpConfigCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<INotificationRepository>();
|
||||
var config = await repo.GetSmtpConfigurationByIdAsync(cmd.SmtpConfigId)
|
||||
?? throw new InvalidOperationException($"SmtpConfiguration with ID {cmd.SmtpConfigId} not found.");
|
||||
config.Host = cmd.Server;
|
||||
config.Port = cmd.Port;
|
||||
config.AuthType = cmd.AuthMode;
|
||||
config.FromAddress = cmd.FromAddress;
|
||||
await repo.UpdateSmtpConfigurationAsync(config);
|
||||
await repo.SaveChangesAsync();
|
||||
return config;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Security handlers
|
||||
// ========================================================================
|
||||
|
||||
private static async Task<object?> HandleListRoleMappings(IServiceProvider sp)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISecurityRepository>();
|
||||
return await repo.GetAllMappingsAsync();
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleCreateRoleMapping(IServiceProvider sp, CreateRoleMappingCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISecurityRepository>();
|
||||
var mapping = new LdapGroupMapping(cmd.LdapGroupName, cmd.Role);
|
||||
await repo.AddMappingAsync(mapping);
|
||||
await repo.SaveChangesAsync();
|
||||
return mapping;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleUpdateRoleMapping(IServiceProvider sp, UpdateRoleMappingCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISecurityRepository>();
|
||||
var mapping = await repo.GetMappingByIdAsync(cmd.MappingId)
|
||||
?? throw new InvalidOperationException($"RoleMapping with ID {cmd.MappingId} not found.");
|
||||
mapping.LdapGroupName = cmd.LdapGroupName;
|
||||
mapping.Role = cmd.Role;
|
||||
await repo.UpdateMappingAsync(mapping);
|
||||
await repo.SaveChangesAsync();
|
||||
return mapping;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleDeleteRoleMapping(IServiceProvider sp, DeleteRoleMappingCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ISecurityRepository>();
|
||||
await repo.DeleteMappingAsync(cmd.MappingId);
|
||||
await repo.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleListApiKeys(IServiceProvider sp)
|
||||
{
|
||||
var repo = sp.GetRequiredService<IInboundApiRepository>();
|
||||
return await repo.GetAllApiKeysAsync();
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleCreateApiKey(IServiceProvider sp, CreateApiKeyCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<IInboundApiRepository>();
|
||||
var keyValue = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32));
|
||||
var apiKey = new ApiKey(cmd.Name, keyValue) { IsEnabled = true };
|
||||
await repo.AddApiKeyAsync(apiKey);
|
||||
await repo.SaveChangesAsync();
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleDeleteApiKey(IServiceProvider sp, DeleteApiKeyCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<IInboundApiRepository>();
|
||||
await repo.DeleteApiKeyAsync(cmd.ApiKeyId);
|
||||
await repo.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Deployment handlers
|
||||
// ========================================================================
|
||||
|
||||
private static async Task<object?> HandleDeployArtifacts(IServiceProvider sp, MgmtDeployArtifactsCommand cmd, string user)
|
||||
{
|
||||
var svc = sp.GetRequiredService<ArtifactDeploymentService>();
|
||||
var command = await svc.BuildDeployArtifactsCommandAsync();
|
||||
var result = await svc.DeployToAllSitesAsync(command, user);
|
||||
return result.IsSuccess
|
||||
? result.Value
|
||||
: throw new InvalidOperationException(result.Error);
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleQueryDeployments(IServiceProvider sp, QueryDeploymentsCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<IDeploymentManagerRepository>();
|
||||
if (cmd.InstanceId.HasValue)
|
||||
return await repo.GetDeploymentsByInstanceIdAsync(cmd.InstanceId.Value);
|
||||
return await repo.GetAllDeploymentRecordsAsync();
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Audit Log handler
|
||||
// ========================================================================
|
||||
|
||||
private static async Task<object?> HandleQueryAuditLog(IServiceProvider sp, QueryAuditLogCommand cmd)
|
||||
{
|
||||
var repo = sp.GetRequiredService<ICentralUiRepository>();
|
||||
return await repo.GetAuditLogEntriesAsync(
|
||||
cmd.User, cmd.EntityType, cmd.Action, cmd.From, cmd.To,
|
||||
page: cmd.Page, pageSize: cmd.PageSize);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Health handlers
|
||||
// ========================================================================
|
||||
|
||||
private static object? HandleGetHealthSummary(IServiceProvider sp)
|
||||
{
|
||||
var aggregator = sp.GetRequiredService<ICentralHealthAggregator>();
|
||||
return aggregator.GetAllSiteStates();
|
||||
}
|
||||
|
||||
private static object? HandleGetSiteHealth(IServiceProvider sp, GetSiteHealthCommand cmd)
|
||||
{
|
||||
var aggregator = sp.GetRequiredService<ICentralHealthAggregator>();
|
||||
return aggregator.GetSiteState(cmd.SiteIdentifier);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user