Expand settings UI to manage systems, containers, and certificate paths.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
|||||||
|
namespace ZA.CoreService.ESBCertificateManager.Models;
|
||||||
|
|
||||||
|
public sealed class CompanyOption
|
||||||
|
{
|
||||||
|
public int CompanyId { get; init; }
|
||||||
|
|
||||||
|
public required string CompanyCode { get; init; }
|
||||||
|
|
||||||
|
public required string CompanyName { get; init; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{CompanyCode} — {CompanyName}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ContainerOption
|
||||||
|
{
|
||||||
|
public int SonicContainerId { get; init; }
|
||||||
|
|
||||||
|
public int SonicConnectionId { get; init; }
|
||||||
|
|
||||||
|
public int CompanyId { get; init; }
|
||||||
|
|
||||||
|
public required string ContainerName { get; init; }
|
||||||
|
|
||||||
|
public string? ContainerDisplayName { get; init; }
|
||||||
|
|
||||||
|
public required string CompanyCode { get; init; }
|
||||||
|
|
||||||
|
public required string ConnectionName { get; init; }
|
||||||
|
|
||||||
|
public int RestartTimeoutSeconds { get; init; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
string display =
|
||||||
|
string.IsNullOrWhiteSpace(ContainerDisplayName)
|
||||||
|
? ContainerName
|
||||||
|
: ContainerDisplayName;
|
||||||
|
|
||||||
|
return $"{CompanyCode} / {display} ({ConnectionName})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class CertificateTargetOption
|
||||||
|
{
|
||||||
|
public int CertificateTargetId { get; init; }
|
||||||
|
|
||||||
|
public int SonicContainerId { get; init; }
|
||||||
|
|
||||||
|
public required string TargetDirectory { get; init; }
|
||||||
|
|
||||||
|
public required string TargetFileName { get; init; }
|
||||||
|
|
||||||
|
public bool BackupEnabled { get; init; }
|
||||||
|
|
||||||
|
public required string BackupDirectoryName { get; init; }
|
||||||
|
|
||||||
|
public required string ContainerName { get; init; }
|
||||||
|
|
||||||
|
public required string ConnectionName { get; init; }
|
||||||
|
|
||||||
|
public required string CompanyCode { get; init; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{CompanyCode} / {ContainerName}: {TargetDirectory}\\{TargetFileName}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -595,4 +595,730 @@ public sealed class SonicSetupRepository
|
|||||||
reader.GetOrdinal("IsActive"))
|
reader.GetOrdinal("IsActive"))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IReadOnlyList<CompanyOption>> GetCompaniesAsync(
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
const string sql = """
|
||||||
|
SELECT
|
||||||
|
[CompanyId],
|
||||||
|
[CompanyCode],
|
||||||
|
[CompanyName]
|
||||||
|
FROM [dbo].[Company]
|
||||||
|
WHERE [IsActive] = 1
|
||||||
|
ORDER BY [CompanyCode];
|
||||||
|
""";
|
||||||
|
|
||||||
|
List<CompanyOption> companies = [];
|
||||||
|
|
||||||
|
await using SqlConnection connection =
|
||||||
|
new(_connectionString);
|
||||||
|
|
||||||
|
await connection.OpenAsync(cancellationToken);
|
||||||
|
|
||||||
|
await using SqlCommand command =
|
||||||
|
new(sql, connection);
|
||||||
|
|
||||||
|
await using SqlDataReader reader =
|
||||||
|
await command.ExecuteReaderAsync(cancellationToken);
|
||||||
|
|
||||||
|
while (await reader.ReadAsync(cancellationToken))
|
||||||
|
{
|
||||||
|
companies.Add(
|
||||||
|
new CompanyOption
|
||||||
|
{
|
||||||
|
CompanyId =
|
||||||
|
reader.GetInt32(
|
||||||
|
reader.GetOrdinal("CompanyId")),
|
||||||
|
|
||||||
|
CompanyCode =
|
||||||
|
reader.GetString(
|
||||||
|
reader.GetOrdinal("CompanyCode")),
|
||||||
|
|
||||||
|
CompanyName =
|
||||||
|
reader.GetString(
|
||||||
|
reader.GetOrdinal("CompanyName"))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return companies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IReadOnlyList<ContainerOption>> GetContainersAsync(
|
||||||
|
string environmentCode,
|
||||||
|
int? sonicConnectionId = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(environmentCode))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Der EnvironmentCode fehlt.",
|
||||||
|
nameof(environmentCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
const string sql = """
|
||||||
|
SELECT
|
||||||
|
container.[SonicContainerId],
|
||||||
|
container.[SonicConnectionId],
|
||||||
|
container.[CompanyId],
|
||||||
|
container.[ContainerName],
|
||||||
|
container.[ContainerDisplayName],
|
||||||
|
container.[RestartTimeoutSeconds],
|
||||||
|
company.[CompanyCode],
|
||||||
|
connection.[ConnectionName]
|
||||||
|
FROM [dbo].[SonicContainer] AS container
|
||||||
|
INNER JOIN [dbo].[Company] AS company
|
||||||
|
ON company.[CompanyId] = container.[CompanyId]
|
||||||
|
INNER JOIN [dbo].[SonicConnection] AS connection
|
||||||
|
ON connection.[SonicConnectionId] =
|
||||||
|
container.[SonicConnectionId]
|
||||||
|
INNER JOIN [dbo].[Environment] AS environment
|
||||||
|
ON environment.[EnvironmentId] =
|
||||||
|
connection.[EnvironmentId]
|
||||||
|
WHERE container.[IsActive] = 1
|
||||||
|
AND company.[IsActive] = 1
|
||||||
|
AND connection.[IsActive] = 1
|
||||||
|
AND environment.[IsActive] = 1
|
||||||
|
AND environment.[EnvironmentCode] = @EnvironmentCode
|
||||||
|
AND
|
||||||
|
(
|
||||||
|
@SonicConnectionId IS NULL
|
||||||
|
OR container.[SonicConnectionId] = @SonicConnectionId
|
||||||
|
)
|
||||||
|
ORDER BY
|
||||||
|
company.[CompanyCode],
|
||||||
|
container.[ContainerName];
|
||||||
|
""";
|
||||||
|
|
||||||
|
List<ContainerOption> containers = [];
|
||||||
|
|
||||||
|
await using SqlConnection connection =
|
||||||
|
new(_connectionString);
|
||||||
|
|
||||||
|
await connection.OpenAsync(cancellationToken);
|
||||||
|
|
||||||
|
await using SqlCommand command =
|
||||||
|
new(sql, connection);
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@EnvironmentCode",
|
||||||
|
SqlDbType.NVarChar,
|
||||||
|
30)
|
||||||
|
{
|
||||||
|
Value = environmentCode
|
||||||
|
.Trim()
|
||||||
|
.ToUpperInvariant()
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@SonicConnectionId",
|
||||||
|
SqlDbType.Int)
|
||||||
|
{
|
||||||
|
Value = sonicConnectionId is null or <= 0
|
||||||
|
? DBNull.Value
|
||||||
|
: sonicConnectionId.Value
|
||||||
|
});
|
||||||
|
|
||||||
|
await using SqlDataReader reader =
|
||||||
|
await command.ExecuteReaderAsync(cancellationToken);
|
||||||
|
|
||||||
|
while (await reader.ReadAsync(cancellationToken))
|
||||||
|
{
|
||||||
|
int displayOrdinal =
|
||||||
|
reader.GetOrdinal("ContainerDisplayName");
|
||||||
|
|
||||||
|
containers.Add(
|
||||||
|
new ContainerOption
|
||||||
|
{
|
||||||
|
SonicContainerId =
|
||||||
|
reader.GetInt32(
|
||||||
|
reader.GetOrdinal("SonicContainerId")),
|
||||||
|
|
||||||
|
SonicConnectionId =
|
||||||
|
reader.GetInt32(
|
||||||
|
reader.GetOrdinal("SonicConnectionId")),
|
||||||
|
|
||||||
|
CompanyId =
|
||||||
|
reader.GetInt32(
|
||||||
|
reader.GetOrdinal("CompanyId")),
|
||||||
|
|
||||||
|
ContainerName =
|
||||||
|
reader.GetString(
|
||||||
|
reader.GetOrdinal("ContainerName")),
|
||||||
|
|
||||||
|
ContainerDisplayName =
|
||||||
|
reader.IsDBNull(displayOrdinal)
|
||||||
|
? null
|
||||||
|
: reader.GetString(displayOrdinal),
|
||||||
|
|
||||||
|
RestartTimeoutSeconds =
|
||||||
|
reader.GetInt32(
|
||||||
|
reader.GetOrdinal("RestartTimeoutSeconds")),
|
||||||
|
|
||||||
|
CompanyCode =
|
||||||
|
reader.GetString(
|
||||||
|
reader.GetOrdinal("CompanyCode")),
|
||||||
|
|
||||||
|
ConnectionName =
|
||||||
|
reader.GetString(
|
||||||
|
reader.GetOrdinal("ConnectionName"))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return containers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IReadOnlyList<CertificateTargetOption>>
|
||||||
|
GetCertificateTargetsAsync(
|
||||||
|
string environmentCode,
|
||||||
|
int? sonicContainerId = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(environmentCode))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Der EnvironmentCode fehlt.",
|
||||||
|
nameof(environmentCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
const string sql = """
|
||||||
|
SELECT
|
||||||
|
target.[CertificateTargetId],
|
||||||
|
target.[SonicContainerId],
|
||||||
|
target.[TargetDirectory],
|
||||||
|
target.[TargetFileName],
|
||||||
|
target.[BackupEnabled],
|
||||||
|
target.[BackupDirectoryName],
|
||||||
|
container.[ContainerName],
|
||||||
|
connection.[ConnectionName],
|
||||||
|
company.[CompanyCode]
|
||||||
|
FROM [dbo].[CertificateTarget] AS target
|
||||||
|
INNER JOIN [dbo].[SonicContainer] AS container
|
||||||
|
ON container.[SonicContainerId] =
|
||||||
|
target.[SonicContainerId]
|
||||||
|
INNER JOIN [dbo].[SonicConnection] AS connection
|
||||||
|
ON connection.[SonicConnectionId] =
|
||||||
|
container.[SonicConnectionId]
|
||||||
|
INNER JOIN [dbo].[Company] AS company
|
||||||
|
ON company.[CompanyId] = container.[CompanyId]
|
||||||
|
INNER JOIN [dbo].[Environment] AS environment
|
||||||
|
ON environment.[EnvironmentId] =
|
||||||
|
connection.[EnvironmentId]
|
||||||
|
WHERE target.[IsActive] = 1
|
||||||
|
AND container.[IsActive] = 1
|
||||||
|
AND connection.[IsActive] = 1
|
||||||
|
AND company.[IsActive] = 1
|
||||||
|
AND environment.[IsActive] = 1
|
||||||
|
AND environment.[EnvironmentCode] = @EnvironmentCode
|
||||||
|
AND
|
||||||
|
(
|
||||||
|
@SonicContainerId IS NULL
|
||||||
|
OR target.[SonicContainerId] = @SonicContainerId
|
||||||
|
)
|
||||||
|
ORDER BY
|
||||||
|
company.[CompanyCode],
|
||||||
|
container.[ContainerName],
|
||||||
|
target.[TargetDirectory],
|
||||||
|
target.[TargetFileName];
|
||||||
|
""";
|
||||||
|
|
||||||
|
List<CertificateTargetOption> targets = [];
|
||||||
|
|
||||||
|
await using SqlConnection connection =
|
||||||
|
new(_connectionString);
|
||||||
|
|
||||||
|
await connection.OpenAsync(cancellationToken);
|
||||||
|
|
||||||
|
await using SqlCommand command =
|
||||||
|
new(sql, connection);
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@EnvironmentCode",
|
||||||
|
SqlDbType.NVarChar,
|
||||||
|
30)
|
||||||
|
{
|
||||||
|
Value = environmentCode
|
||||||
|
.Trim()
|
||||||
|
.ToUpperInvariant()
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@SonicContainerId",
|
||||||
|
SqlDbType.Int)
|
||||||
|
{
|
||||||
|
Value = sonicContainerId is null or <= 0
|
||||||
|
? DBNull.Value
|
||||||
|
: sonicContainerId.Value
|
||||||
|
});
|
||||||
|
|
||||||
|
await using SqlDataReader reader =
|
||||||
|
await command.ExecuteReaderAsync(cancellationToken);
|
||||||
|
|
||||||
|
while (await reader.ReadAsync(cancellationToken))
|
||||||
|
{
|
||||||
|
targets.Add(
|
||||||
|
new CertificateTargetOption
|
||||||
|
{
|
||||||
|
CertificateTargetId =
|
||||||
|
reader.GetInt32(
|
||||||
|
reader.GetOrdinal("CertificateTargetId")),
|
||||||
|
|
||||||
|
SonicContainerId =
|
||||||
|
reader.GetInt32(
|
||||||
|
reader.GetOrdinal("SonicContainerId")),
|
||||||
|
|
||||||
|
TargetDirectory =
|
||||||
|
reader.GetString(
|
||||||
|
reader.GetOrdinal("TargetDirectory")),
|
||||||
|
|
||||||
|
TargetFileName =
|
||||||
|
reader.GetString(
|
||||||
|
reader.GetOrdinal("TargetFileName")),
|
||||||
|
|
||||||
|
BackupEnabled =
|
||||||
|
reader.GetBoolean(
|
||||||
|
reader.GetOrdinal("BackupEnabled")),
|
||||||
|
|
||||||
|
BackupDirectoryName =
|
||||||
|
reader.GetString(
|
||||||
|
reader.GetOrdinal("BackupDirectoryName")),
|
||||||
|
|
||||||
|
ContainerName =
|
||||||
|
reader.GetString(
|
||||||
|
reader.GetOrdinal("ContainerName")),
|
||||||
|
|
||||||
|
ConnectionName =
|
||||||
|
reader.GetString(
|
||||||
|
reader.GetOrdinal("ConnectionName")),
|
||||||
|
|
||||||
|
CompanyCode =
|
||||||
|
reader.GetString(
|
||||||
|
reader.GetOrdinal("CompanyCode"))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return targets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> AddSonicConnectionAsync(
|
||||||
|
string environmentCode,
|
||||||
|
string connectionName,
|
||||||
|
string managementHost,
|
||||||
|
int managementPort,
|
||||||
|
string domainName,
|
||||||
|
string connectionProtocol,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(environmentCode))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Der EnvironmentCode fehlt.",
|
||||||
|
nameof(environmentCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
string name = RequireTrimmed(
|
||||||
|
connectionName,
|
||||||
|
150,
|
||||||
|
"ConnectionName");
|
||||||
|
|
||||||
|
string host = RequireTrimmed(
|
||||||
|
managementHost,
|
||||||
|
255,
|
||||||
|
"ManagementHost");
|
||||||
|
|
||||||
|
string domain = RequireTrimmed(
|
||||||
|
domainName,
|
||||||
|
150,
|
||||||
|
"DomainName");
|
||||||
|
|
||||||
|
string protocol = string.IsNullOrWhiteSpace(connectionProtocol)
|
||||||
|
? "tcp"
|
||||||
|
: connectionProtocol.Trim().TrimEnd(':', '/');
|
||||||
|
|
||||||
|
if (managementPort is < 1 or > 65535)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(
|
||||||
|
nameof(managementPort),
|
||||||
|
"Der ManagementPort muss zwischen 1 und 65535 liegen.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const string sql = """
|
||||||
|
INSERT INTO [dbo].[SonicConnection]
|
||||||
|
(
|
||||||
|
[EnvironmentId],
|
||||||
|
[ConnectionName],
|
||||||
|
[ManagementHost],
|
||||||
|
[ManagementPort],
|
||||||
|
[DomainName],
|
||||||
|
[ConnectionProtocol],
|
||||||
|
[IsActive],
|
||||||
|
[CreationDateTime],
|
||||||
|
[CreatedBy]
|
||||||
|
)
|
||||||
|
OUTPUT INSERTED.[SonicConnectionId]
|
||||||
|
SELECT
|
||||||
|
environment.[EnvironmentId],
|
||||||
|
@ConnectionName,
|
||||||
|
@ManagementHost,
|
||||||
|
@ManagementPort,
|
||||||
|
@DomainName,
|
||||||
|
@ConnectionProtocol,
|
||||||
|
1,
|
||||||
|
SYSUTCDATETIME(),
|
||||||
|
SUSER_SNAME()
|
||||||
|
FROM [dbo].[Environment] AS environment
|
||||||
|
WHERE environment.[EnvironmentCode] = @EnvironmentCode
|
||||||
|
AND environment.[IsActive] = 1;
|
||||||
|
""";
|
||||||
|
|
||||||
|
await using SqlConnection connection =
|
||||||
|
new(_connectionString);
|
||||||
|
|
||||||
|
await connection.OpenAsync(cancellationToken);
|
||||||
|
|
||||||
|
await using SqlCommand command =
|
||||||
|
new(sql, connection);
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@EnvironmentCode",
|
||||||
|
SqlDbType.NVarChar,
|
||||||
|
30)
|
||||||
|
{
|
||||||
|
Value = environmentCode
|
||||||
|
.Trim()
|
||||||
|
.ToUpperInvariant()
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@ConnectionName",
|
||||||
|
SqlDbType.NVarChar,
|
||||||
|
150)
|
||||||
|
{
|
||||||
|
Value = name
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@ManagementHost",
|
||||||
|
SqlDbType.NVarChar,
|
||||||
|
255)
|
||||||
|
{
|
||||||
|
Value = host
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@ManagementPort",
|
||||||
|
SqlDbType.Int)
|
||||||
|
{
|
||||||
|
Value = managementPort
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@DomainName",
|
||||||
|
SqlDbType.NVarChar,
|
||||||
|
150)
|
||||||
|
{
|
||||||
|
Value = domain
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@ConnectionProtocol",
|
||||||
|
SqlDbType.NVarChar,
|
||||||
|
20)
|
||||||
|
{
|
||||||
|
Value = protocol
|
||||||
|
});
|
||||||
|
|
||||||
|
object? result =
|
||||||
|
await command.ExecuteScalarAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (result is null || result is DBNull)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Die Umgebung '{environmentCode}' wurde nicht gefunden " +
|
||||||
|
"oder die Sonic-Verbindung konnte nicht angelegt werden.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Convert.ToInt32(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> AddSonicContainerAsync(
|
||||||
|
int companyId,
|
||||||
|
int sonicConnectionId,
|
||||||
|
string containerName,
|
||||||
|
string? containerDisplayName,
|
||||||
|
int restartTimeoutSeconds,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (companyId <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(companyId));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sonicConnectionId <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(sonicConnectionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
string name = RequireTrimmed(
|
||||||
|
containerName,
|
||||||
|
250,
|
||||||
|
"ContainerName");
|
||||||
|
|
||||||
|
string? display =
|
||||||
|
string.IsNullOrWhiteSpace(containerDisplayName)
|
||||||
|
? null
|
||||||
|
: containerDisplayName.Trim();
|
||||||
|
|
||||||
|
if (display is { Length: > 250 })
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Der Anzeigename darf maximal 250 Zeichen enthalten.",
|
||||||
|
nameof(containerDisplayName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (restartTimeoutSeconds is < 10 or > 3600)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(
|
||||||
|
nameof(restartTimeoutSeconds),
|
||||||
|
"Timeout muss zwischen 10 und 3600 Sekunden liegen.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const string sql = """
|
||||||
|
INSERT INTO [dbo].[SonicContainer]
|
||||||
|
(
|
||||||
|
[CompanyId],
|
||||||
|
[SonicConnectionId],
|
||||||
|
[ContainerName],
|
||||||
|
[ContainerDisplayName],
|
||||||
|
[RestartTimeoutSeconds],
|
||||||
|
[IsActive],
|
||||||
|
[CreationDateTime],
|
||||||
|
[CreatedBy]
|
||||||
|
)
|
||||||
|
OUTPUT INSERTED.[SonicContainerId]
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
@CompanyId,
|
||||||
|
@SonicConnectionId,
|
||||||
|
@ContainerName,
|
||||||
|
@ContainerDisplayName,
|
||||||
|
@RestartTimeoutSeconds,
|
||||||
|
1,
|
||||||
|
SYSUTCDATETIME(),
|
||||||
|
SUSER_SNAME()
|
||||||
|
);
|
||||||
|
""";
|
||||||
|
|
||||||
|
await using SqlConnection connection =
|
||||||
|
new(_connectionString);
|
||||||
|
|
||||||
|
await connection.OpenAsync(cancellationToken);
|
||||||
|
|
||||||
|
await using SqlCommand command =
|
||||||
|
new(sql, connection);
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter("@CompanyId", SqlDbType.Int)
|
||||||
|
{
|
||||||
|
Value = companyId
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter("@SonicConnectionId", SqlDbType.Int)
|
||||||
|
{
|
||||||
|
Value = sonicConnectionId
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@ContainerName",
|
||||||
|
SqlDbType.NVarChar,
|
||||||
|
250)
|
||||||
|
{
|
||||||
|
Value = name
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@ContainerDisplayName",
|
||||||
|
SqlDbType.NVarChar,
|
||||||
|
250)
|
||||||
|
{
|
||||||
|
Value = display is null
|
||||||
|
? DBNull.Value
|
||||||
|
: display
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@RestartTimeoutSeconds",
|
||||||
|
SqlDbType.Int)
|
||||||
|
{
|
||||||
|
Value = restartTimeoutSeconds
|
||||||
|
});
|
||||||
|
|
||||||
|
object? result =
|
||||||
|
await command.ExecuteScalarAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (result is null || result is DBNull)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Der Container konnte nicht angelegt werden.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Convert.ToInt32(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> AddCertificateTargetAsync(
|
||||||
|
int sonicContainerId,
|
||||||
|
string targetDirectory,
|
||||||
|
string targetFileName,
|
||||||
|
bool backupEnabled,
|
||||||
|
string backupDirectoryName,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (sonicContainerId <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(
|
||||||
|
nameof(sonicContainerId));
|
||||||
|
}
|
||||||
|
|
||||||
|
string directory = RequireTrimmed(
|
||||||
|
targetDirectory,
|
||||||
|
500,
|
||||||
|
"TargetDirectory");
|
||||||
|
|
||||||
|
string fileName = RequireTrimmed(
|
||||||
|
targetFileName,
|
||||||
|
260,
|
||||||
|
"TargetFileName");
|
||||||
|
|
||||||
|
string backupName = string.IsNullOrWhiteSpace(backupDirectoryName)
|
||||||
|
? "Backup"
|
||||||
|
: backupDirectoryName.Trim();
|
||||||
|
|
||||||
|
if (backupName.Length > 100)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Der Backup-Ordnername darf maximal 100 Zeichen enthalten.",
|
||||||
|
nameof(backupDirectoryName));
|
||||||
|
}
|
||||||
|
|
||||||
|
const string sql = """
|
||||||
|
INSERT INTO [dbo].[CertificateTarget]
|
||||||
|
(
|
||||||
|
[SonicContainerId],
|
||||||
|
[TargetDirectory],
|
||||||
|
[TargetFileName],
|
||||||
|
[BackupEnabled],
|
||||||
|
[BackupDirectoryName],
|
||||||
|
[IsActive],
|
||||||
|
[CreationDateTime],
|
||||||
|
[CreatedBy]
|
||||||
|
)
|
||||||
|
OUTPUT INSERTED.[CertificateTargetId]
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
@SonicContainerId,
|
||||||
|
@TargetDirectory,
|
||||||
|
@TargetFileName,
|
||||||
|
@BackupEnabled,
|
||||||
|
@BackupDirectoryName,
|
||||||
|
1,
|
||||||
|
SYSUTCDATETIME(),
|
||||||
|
SUSER_SNAME()
|
||||||
|
);
|
||||||
|
""";
|
||||||
|
|
||||||
|
await using SqlConnection connection =
|
||||||
|
new(_connectionString);
|
||||||
|
|
||||||
|
await connection.OpenAsync(cancellationToken);
|
||||||
|
|
||||||
|
await using SqlCommand command =
|
||||||
|
new(sql, connection);
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter("@SonicContainerId", SqlDbType.Int)
|
||||||
|
{
|
||||||
|
Value = sonicContainerId
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@TargetDirectory",
|
||||||
|
SqlDbType.NVarChar,
|
||||||
|
500)
|
||||||
|
{
|
||||||
|
Value = directory
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@TargetFileName",
|
||||||
|
SqlDbType.NVarChar,
|
||||||
|
260)
|
||||||
|
{
|
||||||
|
Value = fileName
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter("@BackupEnabled", SqlDbType.Bit)
|
||||||
|
{
|
||||||
|
Value = backupEnabled
|
||||||
|
});
|
||||||
|
|
||||||
|
command.Parameters.Add(
|
||||||
|
new SqlParameter(
|
||||||
|
"@BackupDirectoryName",
|
||||||
|
SqlDbType.NVarChar,
|
||||||
|
100)
|
||||||
|
{
|
||||||
|
Value = backupName
|
||||||
|
});
|
||||||
|
|
||||||
|
object? result =
|
||||||
|
await command.ExecuteScalarAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (result is null || result is DBNull)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Das Zertifikat-Ziel konnte nicht angelegt werden.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Convert.ToInt32(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string RequireTrimmed(
|
||||||
|
string? value,
|
||||||
|
int maxLength,
|
||||||
|
string fieldName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
$"'{fieldName}' fehlt.");
|
||||||
|
}
|
||||||
|
|
||||||
|
string trimmed = value.Trim();
|
||||||
|
|
||||||
|
if (trimmed.Length > maxLength)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
$"'{fieldName}' darf maximal {maxLength} Zeichen enthalten.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return trimmed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,235 @@
|
|||||||
|
using ZA.CoreService.ESBCertificateManager.Models;
|
||||||
|
|
||||||
|
namespace ZA.CoreService.ESBCertificateManager.Setup;
|
||||||
|
|
||||||
|
public sealed class AddContainerForm : Form
|
||||||
|
{
|
||||||
|
private readonly SetupCoordinator _coordinator;
|
||||||
|
private readonly ComboBox _cmbCompany;
|
||||||
|
private readonly ComboBox _cmbSystem;
|
||||||
|
private readonly TextBox _txtName;
|
||||||
|
private readonly TextBox _txtDisplay;
|
||||||
|
private readonly TextBox _txtTimeout;
|
||||||
|
private readonly Button _btnSave;
|
||||||
|
private bool _running;
|
||||||
|
|
||||||
|
public int? CreatedSonicContainerId { get; private set; }
|
||||||
|
|
||||||
|
public AddContainerForm(
|
||||||
|
SetupCoordinator coordinator,
|
||||||
|
int? preferredSonicConnectionId = null)
|
||||||
|
{
|
||||||
|
_coordinator = coordinator;
|
||||||
|
|
||||||
|
Text = "Container hinzufügen";
|
||||||
|
StartPosition = FormStartPosition.CenterParent;
|
||||||
|
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||||
|
MaximizeBox = false;
|
||||||
|
MinimizeBox = false;
|
||||||
|
ShowInTaskbar = false;
|
||||||
|
ClientSize = new Size(540, 470);
|
||||||
|
BackColor = SettingsUi.Background;
|
||||||
|
ForeColor = SettingsUi.Text;
|
||||||
|
Font = new Font("Segoe UI", 10f);
|
||||||
|
|
||||||
|
Label title = new()
|
||||||
|
{
|
||||||
|
Text = "Neuer Container",
|
||||||
|
Location = new Point(28, 22),
|
||||||
|
AutoSize = true,
|
||||||
|
Font = new Font("Segoe UI Semibold", 18f, FontStyle.Bold),
|
||||||
|
ForeColor = SettingsUi.Text
|
||||||
|
};
|
||||||
|
|
||||||
|
Label subtitle = new()
|
||||||
|
{
|
||||||
|
Text =
|
||||||
|
"Container einer Company und einem Sonic-System zuordnen.",
|
||||||
|
Location = new Point(30, 58),
|
||||||
|
AutoSize = true,
|
||||||
|
ForeColor = SettingsUi.Muted
|
||||||
|
};
|
||||||
|
|
||||||
|
Panel card = SettingsUi.CreateCard();
|
||||||
|
card.Location = new Point(28, 95);
|
||||||
|
card.Size = new Size(484, 290);
|
||||||
|
card.Paint += SettingsUi.PaintCardBorder;
|
||||||
|
|
||||||
|
_cmbCompany = SettingsUi.CreateComboBox();
|
||||||
|
_cmbSystem = SettingsUi.CreateComboBox();
|
||||||
|
_txtName = SettingsUi.CreateTextBox();
|
||||||
|
_txtDisplay = SettingsUi.CreateTextBox();
|
||||||
|
_txtTimeout = SettingsUi.CreateTextBox();
|
||||||
|
_txtTimeout.Text = "180";
|
||||||
|
|
||||||
|
AddField(card, "Company", _cmbCompany, 18, 18, 440);
|
||||||
|
AddField(card, "Sonic-System", _cmbSystem, 18, 78, 440);
|
||||||
|
AddField(card, "Container-Name", _txtName, 18, 138, 440);
|
||||||
|
AddField(card, "Anzeigename (optional)", _txtDisplay, 18, 198, 280);
|
||||||
|
AddField(card, "Timeout (s)", _txtTimeout, 318, 198, 140);
|
||||||
|
|
||||||
|
_btnSave = SettingsUi.CreatePrimaryButton("Container anlegen");
|
||||||
|
_btnSave.Location = new Point(292, 405);
|
||||||
|
_btnSave.Size = new Size(220, 40);
|
||||||
|
_btnSave.Click += async (_, _) => await SaveAsync();
|
||||||
|
|
||||||
|
Button cancel = SettingsUi.CreateGhostButton("Abbrechen");
|
||||||
|
cancel.Location = new Point(170, 405);
|
||||||
|
cancel.Size = new Size(110, 40);
|
||||||
|
cancel.Click += (_, _) =>
|
||||||
|
{
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
Close();
|
||||||
|
};
|
||||||
|
|
||||||
|
Controls.Add(title);
|
||||||
|
Controls.Add(subtitle);
|
||||||
|
Controls.Add(card);
|
||||||
|
Controls.Add(cancel);
|
||||||
|
Controls.Add(_btnSave);
|
||||||
|
|
||||||
|
Shown += async (_, _) =>
|
||||||
|
await LoadLookupsAsync(preferredSonicConnectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadLookupsAsync(int? preferredSonicConnectionId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IReadOnlyList<CompanyOption> companies =
|
||||||
|
await _coordinator.LoadCompaniesAsync();
|
||||||
|
|
||||||
|
IReadOnlyList<SonicSystemOption> systems =
|
||||||
|
await _coordinator.LoadSystemsAsync();
|
||||||
|
|
||||||
|
_cmbCompany.Items.Clear();
|
||||||
|
foreach (CompanyOption company in companies)
|
||||||
|
{
|
||||||
|
_cmbCompany.Items.Add(company);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cmbCompany.Items.Count > 0)
|
||||||
|
{
|
||||||
|
_cmbCompany.SelectedIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmbSystem.Items.Clear();
|
||||||
|
int selected = 0;
|
||||||
|
|
||||||
|
for (int index = 0; index < systems.Count; index++)
|
||||||
|
{
|
||||||
|
_cmbSystem.Items.Add(systems[index]);
|
||||||
|
|
||||||
|
if (preferredSonicConnectionId is int id
|
||||||
|
&& systems[index].SonicConnectionId == id)
|
||||||
|
{
|
||||||
|
selected = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cmbSystem.Items.Count > 0)
|
||||||
|
{
|
||||||
|
_cmbSystem.SelectedIndex = selected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
this,
|
||||||
|
ex.Message,
|
||||||
|
"Container",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveAsync()
|
||||||
|
{
|
||||||
|
if (_running)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cmbCompany.SelectedItem is not CompanyOption company)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
this,
|
||||||
|
"Bitte eine Company wählen.",
|
||||||
|
"Container",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cmbSystem.SelectedItem is not SonicSystemOption system)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
this,
|
||||||
|
"Bitte ein Sonic-System wählen.",
|
||||||
|
"Container",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!int.TryParse(_txtTimeout.Text.Trim(), out int timeout))
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
this,
|
||||||
|
"Bitte einen gültigen Timeout eingeben.",
|
||||||
|
"Container",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_running = true;
|
||||||
|
_btnSave.Enabled = false;
|
||||||
|
Cursor = Cursors.WaitCursor;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CreatedSonicContainerId =
|
||||||
|
await _coordinator.AddSonicContainerAsync(
|
||||||
|
company.CompanyId,
|
||||||
|
system.SonicConnectionId,
|
||||||
|
_txtName.Text,
|
||||||
|
_txtDisplay.Text,
|
||||||
|
timeout);
|
||||||
|
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
this,
|
||||||
|
ex.Message,
|
||||||
|
"Container",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_running = false;
|
||||||
|
_btnSave.Enabled = true;
|
||||||
|
Cursor = Cursors.Default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddField(
|
||||||
|
Control parent,
|
||||||
|
string label,
|
||||||
|
Control input,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int width)
|
||||||
|
{
|
||||||
|
Label fieldLabel = SettingsUi.CreateFieldLabel(label);
|
||||||
|
fieldLabel.Location = new Point(x, y);
|
||||||
|
input.Location = new Point(x, y + 22);
|
||||||
|
input.Width = width;
|
||||||
|
parent.Controls.Add(fieldLabel);
|
||||||
|
parent.Controls.Add(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
namespace ZA.CoreService.ESBCertificateManager.Setup;
|
||||||
|
|
||||||
|
public sealed class AddSonicSystemForm : Form
|
||||||
|
{
|
||||||
|
private readonly SetupCoordinator _coordinator;
|
||||||
|
private readonly TextBox _txtName;
|
||||||
|
private readonly TextBox _txtHost;
|
||||||
|
private readonly TextBox _txtPort;
|
||||||
|
private readonly TextBox _txtDomain;
|
||||||
|
private readonly ComboBox _cmbProtocol;
|
||||||
|
private readonly Button _btnSave;
|
||||||
|
private bool _running;
|
||||||
|
|
||||||
|
public int? CreatedSonicConnectionId { get; private set; }
|
||||||
|
|
||||||
|
public AddSonicSystemForm(SetupCoordinator coordinator)
|
||||||
|
{
|
||||||
|
_coordinator = coordinator;
|
||||||
|
|
||||||
|
Text = "Sonic-System hinzufügen";
|
||||||
|
StartPosition = FormStartPosition.CenterParent;
|
||||||
|
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||||
|
MaximizeBox = false;
|
||||||
|
MinimizeBox = false;
|
||||||
|
ShowInTaskbar = false;
|
||||||
|
ClientSize = new Size(520, 430);
|
||||||
|
BackColor = SettingsUi.Background;
|
||||||
|
ForeColor = SettingsUi.Text;
|
||||||
|
Font = new Font("Segoe UI", 10f);
|
||||||
|
|
||||||
|
Label title = new()
|
||||||
|
{
|
||||||
|
Text = "Neues Sonic-System",
|
||||||
|
Location = new Point(28, 22),
|
||||||
|
AutoSize = true,
|
||||||
|
Font = new Font("Segoe UI Semibold", 18f, FontStyle.Bold),
|
||||||
|
ForeColor = SettingsUi.Text
|
||||||
|
};
|
||||||
|
|
||||||
|
Label subtitle = new()
|
||||||
|
{
|
||||||
|
Text =
|
||||||
|
$"Umgebung {_coordinator.Settings.EnvironmentCode} · " +
|
||||||
|
"Management-Verbindung für Container-Neustarts",
|
||||||
|
Location = new Point(30, 58),
|
||||||
|
AutoSize = true,
|
||||||
|
ForeColor = SettingsUi.Muted
|
||||||
|
};
|
||||||
|
|
||||||
|
Panel card = SettingsUi.CreateCard();
|
||||||
|
card.Location = new Point(28, 95);
|
||||||
|
card.Size = new Size(464, 250);
|
||||||
|
card.Paint += SettingsUi.PaintCardBorder;
|
||||||
|
|
||||||
|
_txtName = SettingsUi.CreateTextBox();
|
||||||
|
_txtHost = SettingsUi.CreateTextBox();
|
||||||
|
_txtPort = SettingsUi.CreateTextBox();
|
||||||
|
_txtDomain = SettingsUi.CreateTextBox();
|
||||||
|
_cmbProtocol = SettingsUi.CreateComboBox();
|
||||||
|
_cmbProtocol.Items.AddRange(["tcp", "ssl"]);
|
||||||
|
_cmbProtocol.SelectedIndex = 0;
|
||||||
|
_txtPort.Text = "13070";
|
||||||
|
|
||||||
|
AddField(card, "Verbindungsname", _txtName, 18, 18, 420);
|
||||||
|
AddField(card, "Management-Host", _txtHost, 18, 78, 280);
|
||||||
|
AddField(card, "Port", _txtPort, 316, 78, 122);
|
||||||
|
AddField(card, "Domain", _txtDomain, 18, 138, 420);
|
||||||
|
AddField(card, "Protokoll", _cmbProtocol, 18, 198, 160);
|
||||||
|
|
||||||
|
_btnSave = SettingsUi.CreatePrimaryButton("System anlegen");
|
||||||
|
_btnSave.Location = new Point(292, 365);
|
||||||
|
_btnSave.Size = new Size(200, 40);
|
||||||
|
_btnSave.Click += async (_, _) => await SaveAsync();
|
||||||
|
|
||||||
|
Button cancel = SettingsUi.CreateGhostButton("Abbrechen");
|
||||||
|
cancel.Location = new Point(170, 365);
|
||||||
|
cancel.Size = new Size(110, 40);
|
||||||
|
cancel.Click += (_, _) =>
|
||||||
|
{
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
Close();
|
||||||
|
};
|
||||||
|
|
||||||
|
Controls.Add(title);
|
||||||
|
Controls.Add(subtitle);
|
||||||
|
Controls.Add(card);
|
||||||
|
Controls.Add(cancel);
|
||||||
|
Controls.Add(_btnSave);
|
||||||
|
AcceptButton = _btnSave;
|
||||||
|
CancelButton = cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveAsync()
|
||||||
|
{
|
||||||
|
if (_running)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!int.TryParse(_txtPort.Text.Trim(), out int port))
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
this,
|
||||||
|
"Bitte einen gültigen Port eingeben.",
|
||||||
|
"Sonic-System",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_running = true;
|
||||||
|
_btnSave.Enabled = false;
|
||||||
|
Cursor = Cursors.WaitCursor;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CreatedSonicConnectionId =
|
||||||
|
await _coordinator.AddSonicConnectionAsync(
|
||||||
|
_txtName.Text,
|
||||||
|
_txtHost.Text,
|
||||||
|
port,
|
||||||
|
_txtDomain.Text,
|
||||||
|
_cmbProtocol.SelectedItem?.ToString() ?? "tcp");
|
||||||
|
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
this,
|
||||||
|
ex.Message,
|
||||||
|
"Sonic-System",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_running = false;
|
||||||
|
_btnSave.Enabled = true;
|
||||||
|
Cursor = Cursors.Default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddField(
|
||||||
|
Control parent,
|
||||||
|
string label,
|
||||||
|
Control input,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int width)
|
||||||
|
{
|
||||||
|
Label fieldLabel = SettingsUi.CreateFieldLabel(label);
|
||||||
|
fieldLabel.Location = new Point(x, y);
|
||||||
|
input.Location = new Point(x, y + 22);
|
||||||
|
input.Width = width;
|
||||||
|
parent.Controls.Add(fieldLabel);
|
||||||
|
parent.Controls.Add(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
using ZA.CoreService.ESBCertificateManager.Models;
|
||||||
|
|
||||||
|
namespace ZA.CoreService.ESBCertificateManager.Setup;
|
||||||
|
|
||||||
|
public sealed class AddTargetPathForm : Form
|
||||||
|
{
|
||||||
|
private readonly SetupCoordinator _coordinator;
|
||||||
|
private readonly ComboBox _cmbContainer;
|
||||||
|
private readonly TextBox _txtDirectory;
|
||||||
|
private readonly TextBox _txtFileName;
|
||||||
|
private readonly TextBox _txtBackupFolder;
|
||||||
|
private readonly CheckBox _chkBackup;
|
||||||
|
private readonly Button _btnSave;
|
||||||
|
private bool _running;
|
||||||
|
|
||||||
|
public int? CreatedCertificateTargetId { get; private set; }
|
||||||
|
|
||||||
|
public AddTargetPathForm(
|
||||||
|
SetupCoordinator coordinator,
|
||||||
|
int? preferredSonicContainerId = null)
|
||||||
|
{
|
||||||
|
_coordinator = coordinator;
|
||||||
|
|
||||||
|
Text = "Zertifikat-Pfad hinzufügen";
|
||||||
|
StartPosition = FormStartPosition.CenterParent;
|
||||||
|
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||||
|
MaximizeBox = false;
|
||||||
|
MinimizeBox = false;
|
||||||
|
ShowInTaskbar = false;
|
||||||
|
ClientSize = new Size(560, 450);
|
||||||
|
BackColor = SettingsUi.Background;
|
||||||
|
ForeColor = SettingsUi.Text;
|
||||||
|
Font = new Font("Segoe UI", 10f);
|
||||||
|
|
||||||
|
Label title = new()
|
||||||
|
{
|
||||||
|
Text = "Neuer Zertifikat-Pfad",
|
||||||
|
Location = new Point(28, 22),
|
||||||
|
AutoSize = true,
|
||||||
|
Font = new Font("Segoe UI Semibold", 18f, FontStyle.Bold),
|
||||||
|
ForeColor = SettingsUi.Text
|
||||||
|
};
|
||||||
|
|
||||||
|
Label subtitle = new()
|
||||||
|
{
|
||||||
|
Text =
|
||||||
|
"Zielverzeichnis und Dateiname für die Zertifikatsablage.",
|
||||||
|
Location = new Point(30, 58),
|
||||||
|
AutoSize = true,
|
||||||
|
ForeColor = SettingsUi.Muted
|
||||||
|
};
|
||||||
|
|
||||||
|
Panel card = SettingsUi.CreateCard();
|
||||||
|
card.Location = new Point(28, 95);
|
||||||
|
card.Size = new Size(504, 270);
|
||||||
|
card.Paint += SettingsUi.PaintCardBorder;
|
||||||
|
|
||||||
|
_cmbContainer = SettingsUi.CreateComboBox();
|
||||||
|
_txtDirectory = SettingsUi.CreateTextBox();
|
||||||
|
_txtFileName = SettingsUi.CreateTextBox();
|
||||||
|
_txtBackupFolder = SettingsUi.CreateTextBox();
|
||||||
|
_txtBackupFolder.Text = "Backup";
|
||||||
|
_txtFileName.Text = "server.crt";
|
||||||
|
|
||||||
|
_chkBackup = new CheckBox
|
||||||
|
{
|
||||||
|
Text = "Backup vor dem Überschreiben",
|
||||||
|
AutoSize = true,
|
||||||
|
Checked = true,
|
||||||
|
ForeColor = SettingsUi.Text,
|
||||||
|
Font = new Font("Segoe UI", 9.5f)
|
||||||
|
};
|
||||||
|
|
||||||
|
AddField(card, "Container", _cmbContainer, 18, 18, 460);
|
||||||
|
AddField(card, "Zielverzeichnis", _txtDirectory, 18, 78, 460);
|
||||||
|
AddField(card, "Dateiname", _txtFileName, 18, 138, 220);
|
||||||
|
AddField(card, "Backup-Ordner", _txtBackupFolder, 258, 138, 220);
|
||||||
|
|
||||||
|
_chkBackup.Location = new Point(18, 210);
|
||||||
|
card.Controls.Add(_chkBackup);
|
||||||
|
|
||||||
|
_btnSave = SettingsUi.CreatePrimaryButton("Pfad anlegen");
|
||||||
|
_btnSave.Location = new Point(312, 385);
|
||||||
|
_btnSave.Size = new Size(220, 40);
|
||||||
|
_btnSave.Click += async (_, _) => await SaveAsync();
|
||||||
|
|
||||||
|
Button cancel = SettingsUi.CreateGhostButton("Abbrechen");
|
||||||
|
cancel.Location = new Point(190, 385);
|
||||||
|
cancel.Size = new Size(110, 40);
|
||||||
|
cancel.Click += (_, _) =>
|
||||||
|
{
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
Close();
|
||||||
|
};
|
||||||
|
|
||||||
|
Controls.Add(title);
|
||||||
|
Controls.Add(subtitle);
|
||||||
|
Controls.Add(card);
|
||||||
|
Controls.Add(cancel);
|
||||||
|
Controls.Add(_btnSave);
|
||||||
|
|
||||||
|
Shown += async (_, _) =>
|
||||||
|
await LoadContainersAsync(preferredSonicContainerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadContainersAsync(int? preferredSonicContainerId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IReadOnlyList<ContainerOption> containers =
|
||||||
|
await _coordinator.LoadContainersAsync();
|
||||||
|
|
||||||
|
_cmbContainer.Items.Clear();
|
||||||
|
int selected = 0;
|
||||||
|
|
||||||
|
for (int index = 0; index < containers.Count; index++)
|
||||||
|
{
|
||||||
|
_cmbContainer.Items.Add(containers[index]);
|
||||||
|
|
||||||
|
if (preferredSonicContainerId is int id
|
||||||
|
&& containers[index].SonicContainerId == id)
|
||||||
|
{
|
||||||
|
selected = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cmbContainer.Items.Count > 0)
|
||||||
|
{
|
||||||
|
_cmbContainer.SelectedIndex = selected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
this,
|
||||||
|
ex.Message,
|
||||||
|
"Zertifikat-Pfad",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveAsync()
|
||||||
|
{
|
||||||
|
if (_running)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cmbContainer.SelectedItem is not ContainerOption container)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
this,
|
||||||
|
"Bitte einen Container wählen.",
|
||||||
|
"Zertifikat-Pfad",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_running = true;
|
||||||
|
_btnSave.Enabled = false;
|
||||||
|
Cursor = Cursors.WaitCursor;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CreatedCertificateTargetId =
|
||||||
|
await _coordinator.AddCertificateTargetAsync(
|
||||||
|
container.SonicContainerId,
|
||||||
|
_txtDirectory.Text,
|
||||||
|
_txtFileName.Text,
|
||||||
|
_chkBackup.Checked,
|
||||||
|
_txtBackupFolder.Text);
|
||||||
|
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
this,
|
||||||
|
ex.Message,
|
||||||
|
"Zertifikat-Pfad",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_running = false;
|
||||||
|
_btnSave.Enabled = true;
|
||||||
|
Cursor = Cursors.Default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddField(
|
||||||
|
Control parent,
|
||||||
|
string label,
|
||||||
|
Control input,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int width)
|
||||||
|
{
|
||||||
|
Label fieldLabel = SettingsUi.CreateFieldLabel(label);
|
||||||
|
fieldLabel.Location = new Point(x, y);
|
||||||
|
input.Location = new Point(x, y + 22);
|
||||||
|
input.Width = width;
|
||||||
|
parent.Controls.Add(fieldLabel);
|
||||||
|
parent.Controls.Add(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
namespace ZA.CoreService.ESBCertificateManager.Setup;
|
||||||
|
|
||||||
|
internal static class SettingsUi
|
||||||
|
{
|
||||||
|
public static readonly Color Background =
|
||||||
|
Color.FromArgb(10, 18, 34);
|
||||||
|
|
||||||
|
public static readonly Color Sidebar =
|
||||||
|
Color.FromArgb(7, 23, 45);
|
||||||
|
|
||||||
|
public static readonly Color Card =
|
||||||
|
Color.FromArgb(16, 38, 65);
|
||||||
|
|
||||||
|
public static readonly Color CardHover =
|
||||||
|
Color.FromArgb(23, 55, 94);
|
||||||
|
|
||||||
|
public static readonly Color Border =
|
||||||
|
Color.FromArgb(36, 74, 117);
|
||||||
|
|
||||||
|
public static readonly Color Text =
|
||||||
|
Color.FromArgb(241, 245, 249);
|
||||||
|
|
||||||
|
public static readonly Color Muted =
|
||||||
|
Color.FromArgb(169, 184, 200);
|
||||||
|
|
||||||
|
public static readonly Color Gold =
|
||||||
|
Color.FromArgb(208, 171, 57);
|
||||||
|
|
||||||
|
public static readonly Color Blue =
|
||||||
|
Color.FromArgb(0, 110, 182);
|
||||||
|
|
||||||
|
public static readonly Color Green =
|
||||||
|
Color.FromArgb(60, 203, 127);
|
||||||
|
|
||||||
|
public static readonly Color Red =
|
||||||
|
Color.FromArgb(239, 106, 106);
|
||||||
|
|
||||||
|
public static Button CreatePrimaryButton(string text)
|
||||||
|
{
|
||||||
|
Button button = new()
|
||||||
|
{
|
||||||
|
Text = text,
|
||||||
|
BackColor = Gold,
|
||||||
|
ForeColor = Color.FromArgb(30, 25, 10),
|
||||||
|
FlatStyle = FlatStyle.Flat,
|
||||||
|
Font = new Font("Segoe UI Semibold", 9f, FontStyle.Bold),
|
||||||
|
Cursor = Cursors.Hand,
|
||||||
|
Height = 38
|
||||||
|
};
|
||||||
|
|
||||||
|
button.FlatAppearance.BorderSize = 0;
|
||||||
|
button.FlatAppearance.MouseOverBackColor =
|
||||||
|
Color.FromArgb(226, 196, 93);
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Button CreateGhostButton(string text)
|
||||||
|
{
|
||||||
|
Button button = new()
|
||||||
|
{
|
||||||
|
Text = text,
|
||||||
|
BackColor = Card,
|
||||||
|
ForeColor = Text,
|
||||||
|
FlatStyle = FlatStyle.Flat,
|
||||||
|
Font = new Font("Segoe UI Semibold", 9f, FontStyle.Bold),
|
||||||
|
Cursor = Cursors.Hand,
|
||||||
|
Height = 38
|
||||||
|
};
|
||||||
|
|
||||||
|
button.FlatAppearance.BorderColor = Border;
|
||||||
|
button.FlatAppearance.BorderSize = 1;
|
||||||
|
button.FlatAppearance.MouseOverBackColor = CardHover;
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextBox CreateTextBox()
|
||||||
|
{
|
||||||
|
return new TextBox
|
||||||
|
{
|
||||||
|
BackColor = Color.FromArgb(12, 28, 48),
|
||||||
|
ForeColor = Text,
|
||||||
|
BorderStyle = BorderStyle.FixedSingle,
|
||||||
|
Font = new Font("Segoe UI", 10f),
|
||||||
|
Height = 30
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ComboBox CreateComboBox()
|
||||||
|
{
|
||||||
|
return new ComboBox
|
||||||
|
{
|
||||||
|
BackColor = Color.FromArgb(12, 28, 48),
|
||||||
|
ForeColor = Text,
|
||||||
|
FlatStyle = FlatStyle.Flat,
|
||||||
|
DropDownStyle = ComboBoxStyle.DropDownList,
|
||||||
|
Font = new Font("Segoe UI", 10f),
|
||||||
|
Height = 30
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Label CreateFieldLabel(string text)
|
||||||
|
{
|
||||||
|
return new Label
|
||||||
|
{
|
||||||
|
Text = text,
|
||||||
|
AutoSize = true,
|
||||||
|
ForeColor = Muted,
|
||||||
|
Font = new Font("Segoe UI Semibold", 8.5f, FontStyle.Bold)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Panel CreateCard()
|
||||||
|
{
|
||||||
|
return new Panel
|
||||||
|
{
|
||||||
|
BackColor = Card,
|
||||||
|
Padding = new Padding(18)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ListView CreateListView()
|
||||||
|
{
|
||||||
|
ListView list = new()
|
||||||
|
{
|
||||||
|
View = View.Details,
|
||||||
|
FullRowSelect = true,
|
||||||
|
MultiSelect = false,
|
||||||
|
HeaderStyle = ColumnHeaderStyle.Nonclickable,
|
||||||
|
BorderStyle = BorderStyle.FixedSingle,
|
||||||
|
BackColor = Color.FromArgb(12, 28, 48),
|
||||||
|
ForeColor = Text,
|
||||||
|
Font = new Font("Segoe UI", 9.5f),
|
||||||
|
HideSelection = false
|
||||||
|
};
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PaintCardBorder(
|
||||||
|
object? sender,
|
||||||
|
PaintEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is not Control control)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using Pen pen = new(Border, 1);
|
||||||
|
Rectangle bounds = control.ClientRectangle;
|
||||||
|
bounds.Width -= 1;
|
||||||
|
bounds.Height -= 1;
|
||||||
|
e.Graphics.DrawRectangle(pen, bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -325,6 +325,85 @@ public sealed class SetupCoordinator
|
|||||||
cancellationToken);
|
cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<IReadOnlyList<CompanyOption>> LoadCompaniesAsync(
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return _setupRepository.GetCompaniesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IReadOnlyList<ContainerOption>> LoadContainersAsync(
|
||||||
|
int? sonicConnectionId = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return _setupRepository.GetContainersAsync(
|
||||||
|
_settings.EnvironmentCode,
|
||||||
|
sonicConnectionId,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IReadOnlyList<CertificateTargetOption>>
|
||||||
|
LoadCertificateTargetsAsync(
|
||||||
|
int? sonicContainerId = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return _setupRepository.GetCertificateTargetsAsync(
|
||||||
|
_settings.EnvironmentCode,
|
||||||
|
sonicContainerId,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> AddSonicConnectionAsync(
|
||||||
|
string connectionName,
|
||||||
|
string managementHost,
|
||||||
|
int managementPort,
|
||||||
|
string domainName,
|
||||||
|
string connectionProtocol,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return _setupRepository.AddSonicConnectionAsync(
|
||||||
|
_settings.EnvironmentCode,
|
||||||
|
connectionName,
|
||||||
|
managementHost,
|
||||||
|
managementPort,
|
||||||
|
domainName,
|
||||||
|
connectionProtocol,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> AddSonicContainerAsync(
|
||||||
|
int companyId,
|
||||||
|
int sonicConnectionId,
|
||||||
|
string containerName,
|
||||||
|
string? containerDisplayName,
|
||||||
|
int restartTimeoutSeconds,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return _setupRepository.AddSonicContainerAsync(
|
||||||
|
companyId,
|
||||||
|
sonicConnectionId,
|
||||||
|
containerName,
|
||||||
|
containerDisplayName,
|
||||||
|
restartTimeoutSeconds,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> AddCertificateTargetAsync(
|
||||||
|
int sonicContainerId,
|
||||||
|
string targetDirectory,
|
||||||
|
string targetFileName,
|
||||||
|
bool backupEnabled,
|
||||||
|
string backupDirectoryName,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return _setupRepository.AddCertificateTargetAsync(
|
||||||
|
sonicContainerId,
|
||||||
|
targetDirectory,
|
||||||
|
targetFileName,
|
||||||
|
backupEnabled,
|
||||||
|
backupDirectoryName,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
public void SaveSelection(
|
public void SaveSelection(
|
||||||
SonicSystemOption system,
|
SonicSystemOption system,
|
||||||
SonicCredentialProfile profile)
|
SonicCredentialProfile profile)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user