diff --git a/BACKEND_API.md b/BACKEND_API.md index 0157b57..47335e9 100644 --- a/BACKEND_API.md +++ b/BACKEND_API.md @@ -67,9 +67,9 @@ Content-Type: image/png Body: binäres PNG-Bild. -## 3. Drucker registrieren (Agent-Start) +## 3. Drucker registrieren (Benutzeraktion in den Agent-Einstellungen) -Der Agent ruft diesen Endpunkt beim Start für jeden konfigurierten lokalen Windows-Drucker auf. +Der Agent ruft diesen Endpunkt nicht automatisch beim Start auf. Der Benutzer registriert die freigegebenen lokalen Windows-Drucker bewusst über die Agent-Einstellungen. ```http POST /api/label-print-agent/printers/register diff --git a/README.md b/README.md index b8eaffc..5c2f2de 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,7 @@ Beispiel: Der API-Token wird lokal mit Windows DPAPI verschlüsselt gespeichert. -Beim Start registriert der Agent jeden Eintrag aus `printers` beim Backend. Das Feld `printer` bleibt als Kompatibilitätsfeld für ältere Einstellungen erhalten; neue Jobs werden anhand von `windowsPrinterName` aus der Backend-Antwort auf den passenden lokalen Windows-Drucker gedruckt. +Der Agent registriert Drucker nicht automatisch. Im Tab `Drucker` kann der Benutzer die freigegebenen Einträge aus `printers` bewusst mit `Im Backend registrieren` an das Backend melden. Das Feld `printer` bleibt als Kompatibilitätsfeld für ältere Einstellungen erhalten; neue Jobs werden anhand von `windowsPrinterName` aus der Backend-Antwort auf den passenden lokalen Windows-Drucker gedruckt. ## Dymo-Druck @@ -166,7 +166,7 @@ Wichtig: 1. Anwendung starten. 2. Tray-Symbol öffnen. 3. Im Tab `Backend` BaseUrl, AgentId und optional API-Token eintragen. -4. Im Tab `Drucker` den Dymo LabelWriter auswählen. +4. Im Tab `Drucker` die freigegebenen Drucker konfigurieren und mit `Im Backend registrieren` ans Backend melden. 5. Im Tab `Allgemein` Polling aktivieren und Intervall setzen. 6. Mit `Jetzt prüfen` kann sofort ein Poll-Lauf ausgelöst werden; dabei werden alle aktuell verfügbaren Jobs verarbeitet. diff --git a/src/LabelPrintAgent/App/Program.cs b/src/LabelPrintAgent/App/Program.cs index 270ee9e..f8bd2a8 100644 --- a/src/LabelPrintAgent/App/Program.cs +++ b/src/LabelPrintAgent/App/Program.cs @@ -28,7 +28,7 @@ internal static class Program using var backendWorker = new BackendPollingWorker(settingsStore, backendClient, printerService); backendWorker.Start(); - Application.Run(new TrayApplicationContext(settingsStore, printerService, backendWorker, updateService)); + Application.Run(new TrayApplicationContext(settingsStore, printerService, backendClient, backendWorker, updateService)); } catch (Exception ex) { diff --git a/src/LabelPrintAgent/App/SettingsForm.cs b/src/LabelPrintAgent/App/SettingsForm.cs index 08f510e..ea489b9 100644 --- a/src/LabelPrintAgent/App/SettingsForm.cs +++ b/src/LabelPrintAgent/App/SettingsForm.cs @@ -14,6 +14,7 @@ internal sealed class SettingsForm : Form private readonly SettingsStore _settingsStore; private readonly PrinterService _printerService; + private readonly BackendClient _backendClient; private readonly BackendPollingWorker _backendWorker; private readonly UpdateService _updateService; private UpdateCheckResult? _lastUpdateCheck; @@ -41,6 +42,7 @@ internal sealed class SettingsForm : Form private readonly Button _installUpdateButton; private readonly ComboBox _printer = new() { Width = 360, DropDownStyle = ComboBoxStyle.DropDownList }; + private readonly CheckedListBox _sharedPrinters = new() { Width = 360, Height = 125, CheckOnClick = true }; private readonly NumericUpDown _labelWidth = new() { Minimum = 1, Maximum = 500, DecimalPlaces = 1, Value = 57, Width = 100 }; private readonly NumericUpDown _labelHeight = new() { Minimum = 1, Maximum = 500, DecimalPlaces = 1, Value = 32, Width = 100 }; @@ -55,11 +57,13 @@ internal sealed class SettingsForm : Form public SettingsForm( SettingsStore settingsStore, PrinterService printerService, + BackendClient backendClient, BackendPollingWorker backendWorker, UpdateService updateService) { _settingsStore = settingsStore; _printerService = printerService; + _backendClient = backendClient; _backendWorker = backendWorker; _updateService = updateService; _installUpdateButton = ButtonAt("Update installieren", 340, 265, async (_, _) => await InstallUpdateFromUiAsync()); @@ -116,11 +120,19 @@ internal sealed class SettingsForm : Form private TabPage CreatePrinterTab() { var panel = CreatePaddedPanel(); - panel.Controls.Add(Row(20, Label("Drucker", 120), _printer)); - panel.Controls.Add(Row(60, Label("Breite", 120), _labelWidth, Label("mm", 40))); - panel.Controls.Add(Row(100, Label("Höhe", 120), _labelHeight, Label("mm", 40))); - panel.Controls.Add(ButtonAt("Drucker neu laden", 140, 150, (_, _) => LoadPrinters())); - panel.Controls.Add(ButtonAt("Speichern", 300, 150, (_, _) => SavePrinter(showMessage: true))); + panel.Controls.Add(Row(20, Label("Standarddrucker", 120), _printer)); + var sharedLabel = Label("Freigegeben", 120); + sharedLabel.Left = 20; + sharedLabel.Top = 60; + _sharedPrinters.Left = 145; + _sharedPrinters.Top = 60; + panel.Controls.Add(sharedLabel); + panel.Controls.Add(_sharedPrinters); + panel.Controls.Add(Row(200, Label("Breite", 120), _labelWidth, Label("mm", 40))); + panel.Controls.Add(Row(240, Label("Höhe", 120), _labelHeight, Label("mm", 40))); + panel.Controls.Add(ButtonAt("Drucker neu laden", 140, 295, (_, _) => LoadPrinters())); + panel.Controls.Add(ButtonAt("Speichern", 300, 295, (_, _) => SavePrinter(showMessage: true))); + panel.Controls.Add(ButtonAt("Im Backend registrieren", 430, 295, async (_, _) => await RegisterPrintersFromUiAsync())); return new TabPage("Drucker") { Controls = { panel } }; } @@ -181,10 +193,16 @@ internal sealed class SettingsForm : Form var settings = _settingsStore.Load(); var selected = GetPrimaryPrinter(settings)?.WindowsPrinterName ?? settings.Printer.PrinterName; _printer.Items.Clear(); + _sharedPrinters.Items.Clear(); + var sharedPrinterNames = settings.Printers + .Select(printer => printer.WindowsPrinterName) + .Where(name => !string.IsNullOrWhiteSpace(name)) + .ToHashSet(StringComparer.OrdinalIgnoreCase); var printers = _printerService.GetInstalledPrinters(); foreach (var printer in printers) { _printer.Items.Add(printer); + _sharedPrinters.Items.Add(printer, sharedPrinterNames.Contains(printer.Name)); } var configuredPrinter = printers.FirstOrDefault(printer => string.Equals(printer.Name, selected, StringComparison.OrdinalIgnoreCase)); @@ -231,26 +249,17 @@ internal sealed class SettingsForm : Form { var settings = _settingsStore.Load(); var selectedPrinterName = GetSelectedPrinterName() ?? string.Empty; + var sharedPrinterNames = GetSharedPrinterNames(); settings.Printer.PrinterName = selectedPrinterName; settings.Printer.LabelWidthMm = _labelWidth.Value; settings.Printer.LabelHeightMm = _labelHeight.Value; - if (!string.IsNullOrWhiteSpace(selectedPrinterName)) + settings.Printers = sharedPrinterNames + .Select(printerName => BuildPrinterConfig(settings, printerName)) + .ToList(); + + if (settings.Printers.Count == 0 && !string.IsNullOrWhiteSpace(selectedPrinterName)) { - var existingPrinter = settings.Printers.FirstOrDefault( - printer => string.Equals(printer.WindowsPrinterName, selectedPrinterName, StringComparison.OrdinalIgnoreCase)); - var printerConfig = existingPrinter ?? new PrinterConfig(); - printerConfig.PrinterId = string.IsNullOrWhiteSpace(printerConfig.PrinterId) - ? SettingsStore.BuildPrinterId(settings.Backend.AgentId, selectedPrinterName) - : printerConfig.PrinterId; - printerConfig.Name = string.IsNullOrWhiteSpace(printerConfig.Name) ? selectedPrinterName : printerConfig.Name; - printerConfig.WindowsPrinterName = selectedPrinterName; - printerConfig.Dpi = settings.Printer.Dpi; - printerConfig.DefaultWidthMm = Math.Max(1, (int)Math.Round(_labelWidth.Value)); - printerConfig.DefaultHeightMm = Math.Max(1, (int)Math.Round(_labelHeight.Value)); - if (existingPrinter is null) - { - settings.Printers.Add(printerConfig); - } + settings.Printers.Add(BuildPrinterConfig(settings, selectedPrinterName)); } _settingsStore.Save(settings); @@ -292,6 +301,34 @@ internal sealed class SettingsForm : Form } } + private async Task RegisterPrintersFromUiAsync() + { + try + { + SaveBackend(showMessage: false); + SavePrinter(showMessage: false); + + var settings = _settingsStore.Load(); + var printerCount = settings.Printers.Count(printer => !string.IsNullOrWhiteSpace(printer.WindowsPrinterName)); + if (printerCount == 0) + { + MessageBox.Show("Bitte zuerst mindestens einen Drucker konfigurieren.", Text, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + AppendStatus($"{printerCount} Drucker werden im Backend registriert..."); + await _backendClient.RegisterPrintersAsync(); + AppendStatus($"{printerCount} Drucker im Backend registriert."); + MessageBox.Show("Drucker wurden im Backend registriert.", Text, MessageBoxButtons.OK, MessageBoxIcon.Information); + } + catch (Exception ex) + { + Log.Error(ex, "Printer registration failed"); + AppendStatus($"Druckerregistrierung fehlgeschlagen: {ex.Message}"); + MessageBox.Show($"Druckerregistrierung fehlgeschlagen: {ex.Message}", Text, MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + private async Task CheckForUpdateFromUiAsync() { try @@ -379,6 +416,39 @@ internal sealed class SettingsForm : Form }; } + private List GetSharedPrinterNames() + { + return _sharedPrinters.CheckedItems + .Cast() + .Select(item => item switch + { + PrinterInfo printerInfo => printerInfo.Name, + string printerName => printerName, + _ => null + }) + .Where(printerName => !string.IsNullOrWhiteSpace(printerName)) + .Cast() + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + } + + private PrinterConfig BuildPrinterConfig(AppSettings settings, string printerName) + { + var existingPrinter = settings.Printers.FirstOrDefault( + printer => string.Equals(printer.WindowsPrinterName, printerName, StringComparison.OrdinalIgnoreCase)); + return new PrinterConfig + { + PrinterId = string.IsNullOrWhiteSpace(existingPrinter?.PrinterId) + ? SettingsStore.BuildPrinterId(settings.Backend.AgentId, printerName) + : existingPrinter.PrinterId, + Name = string.IsNullOrWhiteSpace(existingPrinter?.Name) ? printerName : existingPrinter.Name, + WindowsPrinterName = printerName, + Dpi = existingPrinter?.Dpi > 0 ? existingPrinter.Dpi : settings.Printer.Dpi, + DefaultWidthMm = Math.Max(1, (int)Math.Round(_labelWidth.Value)), + DefaultHeightMm = Math.Max(1, (int)Math.Round(_labelHeight.Value)) + }; + } + private static PrinterConfig? GetPrimaryPrinter(AppSettings settings) { return settings.Printers.FirstOrDefault(printer => !string.IsNullOrWhiteSpace(printer.WindowsPrinterName)); diff --git a/src/LabelPrintAgent/App/TrayApplicationContext.cs b/src/LabelPrintAgent/App/TrayApplicationContext.cs index 656be63..25d20e1 100644 --- a/src/LabelPrintAgent/App/TrayApplicationContext.cs +++ b/src/LabelPrintAgent/App/TrayApplicationContext.cs @@ -11,6 +11,7 @@ internal sealed class TrayApplicationContext : ApplicationContext private readonly NotifyIcon _notifyIcon; private readonly SettingsStore _settingsStore; private readonly PrinterService _printerService; + private readonly BackendClient _backendClient; private readonly BackendPollingWorker _backendWorker; private readonly UpdateService _updateService; private readonly Icon _healthyIcon; @@ -21,11 +22,13 @@ internal sealed class TrayApplicationContext : ApplicationContext public TrayApplicationContext( SettingsStore settingsStore, PrinterService printerService, + BackendClient backendClient, BackendPollingWorker backendWorker, UpdateService updateService) { _settingsStore = settingsStore; _printerService = printerService; + _backendClient = backendClient; _backendWorker = backendWorker; _updateService = updateService; _healthyIcon = TrayIconFactory.CreatePrinterIcon(Color.FromArgb(36, 160, 72)); @@ -62,7 +65,7 @@ internal sealed class TrayApplicationContext : ApplicationContext { if (_settingsForm is null || _settingsForm.IsDisposed) { - _settingsForm = new SettingsForm(_settingsStore, _printerService, _backendWorker, _updateService); + _settingsForm = new SettingsForm(_settingsStore, _printerService, _backendClient, _backendWorker, _updateService); } _settingsForm.Show(); diff --git a/src/LabelPrintAgent/Backend/BackendPollingWorker.cs b/src/LabelPrintAgent/Backend/BackendPollingWorker.cs index 19afaa2..be5cc29 100644 --- a/src/LabelPrintAgent/Backend/BackendPollingWorker.cs +++ b/src/LabelPrintAgent/Backend/BackendPollingWorker.cs @@ -64,8 +64,6 @@ public sealed class BackendPollingWorker : IDisposable return; } - await _backendClient.RegisterPrintersAsync(cancellationToken); - var unavailablePrinters = configuredPrinters .Where(printer => !_printerService.IsPrinterAvailable(printer.WindowsPrinterName)) .Select(printer => printer.WindowsPrinterName)