wqer
This commit is contained in:
@@ -36,14 +36,14 @@
|
||||
@if (_connectionStatus.TryGetValue(context.Id, out var status))
|
||||
{
|
||||
<MudTooltip Text="@BuildStatusTooltip(status)">
|
||||
<MudChip Color="@(status.Success ? Color.Success : Color.Error)" Variant="Variant.Filled" Size="Size.Small">
|
||||
<MudChip T="string" Color="@(status.Success ? Color.Success : Color.Error)" Variant="Variant.Filled" Size="Size.Small">
|
||||
@(status.Success ? "OK" : "Fehler") - @status.Stage
|
||||
</MudChip>
|
||||
</MudTooltip>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudChip Color="Color.Default" Variant="Variant.Outlined" Size="Size.Small">Nicht getestet</MudChip>
|
||||
<MudChip T="string" Color="Color.Default" Variant="Variant.Outlined" Size="Size.Small">Nicht getestet</MudChip>
|
||||
}
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
@@ -71,7 +71,7 @@
|
||||
<MudTh>TSC</MudTh>
|
||||
<MudTh>Schema</MudTh>
|
||||
<MudTh>Quellsystem</MudTh>
|
||||
<MudTh>Server</MudTh>
|
||||
<MudTh>Host</MudTh>
|
||||
<MudTh>Aktiv</MudTh>
|
||||
<MudTh>Aktionen</MudTh>
|
||||
</HeaderContent>
|
||||
@@ -80,7 +80,7 @@
|
||||
<MudTd>@context.TSC</MudTd>
|
||||
<MudTd>@context.Schema</MudTd>
|
||||
<MudTd>@context.SourceSystem</MudTd>
|
||||
<MudTd>@(context.HanaServer?.Name ?? "-")</MudTd>
|
||||
<MudTd>@GetServerNode(context.HanaServer)</MudTd>
|
||||
<MudTd>
|
||||
@if (context.IsActive)
|
||||
{
|
||||
@@ -132,12 +132,6 @@
|
||||
<MudText Typo="Typo.h6">@(_editingSite.Id == 0 ? "Standort hinzufügen" : "Standort bearbeiten")</MudText>
|
||||
</TitleContent>
|
||||
<DialogContent>
|
||||
<MudSelect @bind-Value="_editingSite.HanaServerId" Label="Server" Required>
|
||||
@foreach (var s in _servers)
|
||||
{
|
||||
<MudSelectItem Value="@s.Id">@s.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudTextField @bind-Value="_editingSite.Schema" Label="Schema" Required />
|
||||
<MudTextField @bind-Value="_editingSite.TSC" Label="TSC" Required />
|
||||
<MudTextField @bind-Value="_editingSite.Land" Label="Land" Required />
|
||||
@@ -148,6 +142,25 @@
|
||||
}
|
||||
</MudSelect>
|
||||
<MudCheckBox @bind-Value="_editingSite.IsActive" Label="Aktiv" />
|
||||
|
||||
<MudDivider Class="my-4" />
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mb-2">HANA-Verbindung</MudText>
|
||||
<MudTextField @bind-Value="_editingSiteServer.Name" Label="Verbindungsname" Required
|
||||
HelperText="Interner Anzeigename für diesen Standort" />
|
||||
<MudTextField @bind-Value="_editingSiteServer.Host" Label="Host oder ServerNode" Required
|
||||
HelperText="z.B. hana01 oder hana01:30015 oder derselbe HanaServer-Wert wie in Power BI" />
|
||||
<MudNumericField @bind-Value="_editingSiteServer.Port" Label="Port"
|
||||
HelperText="Wird ignoriert, wenn im Host bereits ein Port enthalten ist" />
|
||||
<MudTextField @bind-Value="_editingSiteServer.Username" Label="Username" />
|
||||
<MudTextField @bind-Value="_editingSiteServer.Password" Label="Password" InputType="InputType.Password" />
|
||||
<MudTextField @bind-Value="_editingSiteServer.DatabaseName" Label="Database Name (MDC)"
|
||||
HelperText="Nur bei Multi-Tenant Setup angeben, sonst leer lassen" />
|
||||
<MudSwitch @bind-Value="_editingSiteServer.UseSsl" Label="SSL/TLS verwenden (encrypt=true)" Color="Color.Primary" />
|
||||
<MudSwitch @bind-Value="_editingSiteServer.ValidateCertificate" Label="SSL-Zertifikat validieren" Color="Color.Primary"
|
||||
Disabled="!_editingSiteServer.UseSsl" />
|
||||
<MudTextField @bind-Value="_editingSiteServer.AdditionalParams" Label="Zusätzliche Parameter"
|
||||
HelperText="Optional, z.B. sslCryptoProvider=openssl;communicationTimeout=0" />
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="() => _siteDialogVisible = false">Abbrechen</MudButton>
|
||||
@@ -162,6 +175,7 @@
|
||||
private List<Site> _sites = new();
|
||||
private HanaServer _editingServer = new();
|
||||
private Site _editingSite = new();
|
||||
private HanaServer _editingSiteServer = new();
|
||||
private bool _serverDialogVisible;
|
||||
private bool _siteDialogVisible;
|
||||
private readonly DialogOptions _dialogOptions = new() { MaxWidth = MaxWidth.Small, FullWidth = true };
|
||||
@@ -186,19 +200,7 @@
|
||||
|
||||
private void EditServer(HanaServer server)
|
||||
{
|
||||
_editingServer = new HanaServer
|
||||
{
|
||||
Id = server.Id,
|
||||
Name = server.Name,
|
||||
Host = server.Host,
|
||||
Port = server.Port,
|
||||
Username = server.Username,
|
||||
Password = server.Password,
|
||||
DatabaseName = server.DatabaseName,
|
||||
UseSsl = server.UseSsl,
|
||||
ValidateCertificate = server.ValidateCertificate,
|
||||
AdditionalParams = server.AdditionalParams
|
||||
};
|
||||
_editingServer = CloneServer(server);
|
||||
_serverDialogVisible = true;
|
||||
}
|
||||
|
||||
@@ -283,8 +285,9 @@
|
||||
{
|
||||
IsActive = true,
|
||||
SourceSystem = "SAP",
|
||||
HanaServerId = _servers.FirstOrDefault()?.Id ?? 0
|
||||
HanaServerId = 0
|
||||
};
|
||||
_editingSiteServer = CreateDefaultSiteServer();
|
||||
_siteDialogVisible = true;
|
||||
}
|
||||
|
||||
@@ -300,14 +303,20 @@
|
||||
SourceSystem = string.IsNullOrWhiteSpace(site.SourceSystem) ? "SAP" : site.SourceSystem,
|
||||
IsActive = site.IsActive
|
||||
};
|
||||
_editingSiteServer = site.HanaServer is null
|
||||
? CreateDefaultSiteServer(site)
|
||||
: CloneServer(site.HanaServer);
|
||||
_siteDialogVisible = true;
|
||||
}
|
||||
|
||||
private async Task SaveSite()
|
||||
{
|
||||
using var db = await DbFactory.CreateDbContextAsync();
|
||||
var serverId = await SaveOrCreateSiteServerAsync(db);
|
||||
|
||||
if (_editingSite.Id == 0)
|
||||
{
|
||||
_editingSite.HanaServerId = serverId;
|
||||
db.Sites.Add(_editingSite);
|
||||
}
|
||||
else
|
||||
@@ -315,7 +324,7 @@
|
||||
var existing = await db.Sites.FindAsync(_editingSite.Id);
|
||||
if (existing is not null)
|
||||
{
|
||||
existing.HanaServerId = _editingSite.HanaServerId;
|
||||
existing.HanaServerId = serverId;
|
||||
existing.Schema = _editingSite.Schema;
|
||||
existing.TSC = _editingSite.TSC;
|
||||
existing.Land = _editingSite.Land;
|
||||
@@ -350,4 +359,93 @@
|
||||
await LoadDataAsync();
|
||||
Snackbar.Add("Standort gelöscht", Severity.Info);
|
||||
}
|
||||
|
||||
private static string GetServerNode(HanaServer? server)
|
||||
{
|
||||
if (server is null || string.IsNullOrWhiteSpace(server.Host))
|
||||
return "-";
|
||||
|
||||
return server.Host.Contains(':', StringComparison.Ordinal) ? server.Host : $"{server.Host}:{server.Port}";
|
||||
}
|
||||
|
||||
private HanaServer CreateDefaultSiteServer(Site? site = null)
|
||||
{
|
||||
var label = !string.IsNullOrWhiteSpace(site?.Land) ? site!.Land : site?.TSC;
|
||||
if (string.IsNullOrWhiteSpace(label))
|
||||
label = "Neuer Standort";
|
||||
|
||||
return new HanaServer
|
||||
{
|
||||
Name = $"{label} HANA",
|
||||
Port = 30015
|
||||
};
|
||||
}
|
||||
|
||||
private static HanaServer CloneServer(HanaServer server)
|
||||
{
|
||||
return new HanaServer
|
||||
{
|
||||
Id = server.Id,
|
||||
Name = server.Name,
|
||||
Host = server.Host,
|
||||
Port = server.Port,
|
||||
Username = server.Username,
|
||||
Password = server.Password,
|
||||
DatabaseName = server.DatabaseName,
|
||||
UseSsl = server.UseSsl,
|
||||
ValidateCertificate = server.ValidateCertificate,
|
||||
AdditionalParams = server.AdditionalParams
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<int> SaveOrCreateSiteServerAsync(AppDbContext db)
|
||||
{
|
||||
_editingSiteServer.Name = string.IsNullOrWhiteSpace(_editingSiteServer.Name)
|
||||
? $"{_editingSite.Land} HANA".Trim()
|
||||
: _editingSiteServer.Name.Trim();
|
||||
_editingSiteServer.Host = _editingSiteServer.Host.Trim();
|
||||
_editingSiteServer.Username = _editingSiteServer.Username.Trim();
|
||||
_editingSiteServer.DatabaseName = _editingSiteServer.DatabaseName.Trim();
|
||||
_editingSiteServer.AdditionalParams = _editingSiteServer.AdditionalParams.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_editingSiteServer.Host))
|
||||
throw new InvalidOperationException("Host oder ServerNode muss gesetzt sein.");
|
||||
|
||||
if (_editingSite.HanaServerId == 0)
|
||||
{
|
||||
db.HanaServers.Add(_editingSiteServer);
|
||||
await db.SaveChangesAsync();
|
||||
return _editingSiteServer.Id;
|
||||
}
|
||||
|
||||
var sharedUseCount = await db.Sites.CountAsync(s => s.HanaServerId == _editingSite.HanaServerId && s.Id != _editingSite.Id);
|
||||
if (sharedUseCount > 0)
|
||||
{
|
||||
var dedicatedServer = CloneServer(_editingSiteServer);
|
||||
dedicatedServer.Id = 0;
|
||||
db.HanaServers.Add(dedicatedServer);
|
||||
await db.SaveChangesAsync();
|
||||
return dedicatedServer.Id;
|
||||
}
|
||||
|
||||
var existingServer = await db.HanaServers.FindAsync(_editingSite.HanaServerId);
|
||||
if (existingServer is null)
|
||||
{
|
||||
db.HanaServers.Add(_editingSiteServer);
|
||||
await db.SaveChangesAsync();
|
||||
return _editingSiteServer.Id;
|
||||
}
|
||||
|
||||
existingServer.Name = _editingSiteServer.Name;
|
||||
existingServer.Host = _editingSiteServer.Host;
|
||||
existingServer.Port = _editingSiteServer.Port;
|
||||
existingServer.Username = _editingSiteServer.Username;
|
||||
existingServer.Password = _editingSiteServer.Password;
|
||||
existingServer.DatabaseName = _editingSiteServer.DatabaseName;
|
||||
existingServer.UseSsl = _editingSiteServer.UseSsl;
|
||||
existingServer.ValidateCertificate = _editingSiteServer.ValidateCertificate;
|
||||
existingServer.AdditionalParams = _editingSiteServer.AdditionalParams;
|
||||
await db.SaveChangesAsync();
|
||||
return existingServer.Id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
</MudSelect>
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
<MudTextField Value="@context.Argument" ValueChanged="@(v => context.Argument = v)" Dense
|
||||
<MudTextField T="string" Value="@context.Argument" ValueChanged="@(v => context.Argument = v)"
|
||||
HelperText="Replace: alt=>neu" />
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Data.Common;
|
||||
|
||||
namespace TrafagSalesExporter.Models;
|
||||
|
||||
@@ -41,26 +42,23 @@ public class HanaServer
|
||||
|
||||
public string BuildConnectionString()
|
||||
{
|
||||
var parts = new List<string>
|
||||
{
|
||||
$"ServerNode={Host}:{Port}",
|
||||
$"UserName={Username}",
|
||||
$"Password={Password}"
|
||||
};
|
||||
var builder = new DbConnectionStringBuilder();
|
||||
builder["ServerNode"] = BuildServerNode();
|
||||
builder["UserName"] = Username.Trim();
|
||||
builder["Password"] = Password;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(DatabaseName))
|
||||
parts.Add($"DatabaseName={DatabaseName}");
|
||||
builder["DatabaseName"] = DatabaseName.Trim();
|
||||
|
||||
if (UseSsl)
|
||||
{
|
||||
parts.Add("encrypt=true");
|
||||
parts.Add($"sslValidateCertificate={(ValidateCertificate ? "true" : "false")}");
|
||||
builder["encrypt"] = true;
|
||||
builder["sslValidateCertificate"] = ValidateCertificate;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(AdditionalParams))
|
||||
parts.Add(AdditionalParams.Trim().Trim(';'));
|
||||
AppendAdditionalParams(builder);
|
||||
|
||||
return string.Join(";", parts);
|
||||
return builder.ConnectionString;
|
||||
}
|
||||
|
||||
public string GetConnectionStringPreview()
|
||||
@@ -80,5 +78,67 @@ public class HanaServer
|
||||
|
||||
return copy.BuildConnectionString();
|
||||
}
|
||||
|
||||
private string BuildServerNode()
|
||||
{
|
||||
var normalizedHost = NormalizeHost(Host);
|
||||
if (string.IsNullOrWhiteSpace(normalizedHost))
|
||||
throw new InvalidOperationException("HANA Host darf nicht leer sein.");
|
||||
|
||||
if (HasExplicitPort(normalizedHost))
|
||||
return normalizedHost;
|
||||
|
||||
return $"{normalizedHost}:{Port}";
|
||||
}
|
||||
|
||||
private static string NormalizeHost(string host)
|
||||
{
|
||||
var value = host.Trim();
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
return string.Empty;
|
||||
|
||||
if (Uri.TryCreate(value, UriKind.Absolute, out var uri))
|
||||
{
|
||||
return uri.IsDefaultPort ? uri.Host : $"{uri.Host}:{uri.Port}";
|
||||
}
|
||||
|
||||
var schemeIndex = value.IndexOf("://", StringComparison.Ordinal);
|
||||
if (schemeIndex >= 0)
|
||||
value = value[(schemeIndex + 3)..];
|
||||
|
||||
var slashIndex = value.IndexOf('/');
|
||||
if (slashIndex >= 0)
|
||||
value = value[..slashIndex];
|
||||
|
||||
return value.Trim();
|
||||
}
|
||||
|
||||
private static bool HasExplicitPort(string host)
|
||||
{
|
||||
if (host.StartsWith('['))
|
||||
return host.Contains("]:", StringComparison.Ordinal);
|
||||
|
||||
return host.Count(c => c == ':') == 1;
|
||||
}
|
||||
|
||||
private void AppendAdditionalParams(DbConnectionStringBuilder builder)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(AdditionalParams))
|
||||
return;
|
||||
|
||||
foreach (var rawPart in AdditionalParams.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
||||
{
|
||||
var separatorIndex = rawPart.IndexOf('=');
|
||||
if (separatorIndex <= 0 || separatorIndex == rawPart.Length - 1)
|
||||
continue;
|
||||
|
||||
var key = rawPart[..separatorIndex].Trim();
|
||||
var value = rawPart[(separatorIndex + 1)..].Trim();
|
||||
if (key.Length == 0)
|
||||
continue;
|
||||
|
||||
builder[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user