Przeglądaj źródła

Support package keeps a printer name that is a model name (#3442)

- A printer named after its model (e.g. "H3C") turned every mention
  of that model in the support package into [PRINTER]; a name that is
  only a known model name or code, or the printer's own model, is now
  left alone, other names are still replaced
maziggy 3 dni temu
rodzic
commit
92ef6c16a0

+ 1 - 0
CHANGELOG.md

@@ -11,6 +11,7 @@ All notable changes to Bambuddy will be documented in this file.
 - **"Any model" jobs go to the printer with the fewest print hours (#3480, sponsor vote Q4 2026)** — When several printers of a model can take a job, the queue used to pick the first one in its list, so on a farm the same printer got most of the work. It now picks the one with the fewest print hours (the Maintenance counter, including baseline hours entered there), so jobs and wear spread across the farm. Preferred colours still come first, and the queue powers on the least used printer too when it has to switch one on with an Auto Power On plug.
 
 ### Fixed
+- **A printer named after its model no longer hides the model in the support package (#3442, reported by @daltonclift)** — The support package replaces printer names with [PRINTER]. A printer named "H3C" turned every "H3C" in the package into [PRINTER], including the model itself. A name that is only a model name or model code is not private, so it now stays; any other name is still replaced.
 - **Auto-drying no longer waits on a drying timer the printer never started (#3478, reported by @superflyer11)** — An AMS HT can accept a drying command while it feeds a print and never heat: its timer stays at the full time (12h 0m) and its status reads Off, for days. Since 1.3.1b1 the printer card shows such a timer as not running, but auto-drying still took it for a running cycle and never dried that unit again, while the humidity alarms kept firing. A timer that has not moved for a few minutes with the status Off now counts as not drying, so auto-drying tries again after its usual 30-minute pause. If that happens twice in a row, auto-drying stops on that unit and sends the **Auto-Drying Suspended** notification, saying the timer stood still (new template **Auto-Drying Not Heating**). It resumes once the humidity is back at or below the threshold. Wiki updated.
 - **The log says which auto-archive switch skipped a print (#3477, reported by @Fuzzylog2x)** — Since 1.3.0 the global **Auto-archive prints** switch (Settings > General > Archive Settings) takes effect for prints started outside Bambuddy. Before, it was saved and never read, so an install upgraded with it off stopped archiving, and the statistics stopped updating. The log only said "auto_archive: False", the same as for a printer's own switch. It now names the global switch or the printer, whichever turned archiving off. The switch's description now says what off means: those prints are missing from the archive, the print history and the statistics, while spool inventory still counts their filament. The wiki explains how to keep statistics without keeping every 3MF (auto-purge removes the files and keeps the statistics), and no longer says auto-purge removes prints from the statistics.
 - **A camera window no longer opens a dozen streams to the printer at once (#3431, reported by @buffdriver)** — When the floating camera window was open while the page loaded (after a refresh, for example), Bambuddy opened about twenty camera streams for it. Only one was shown. The browser kept the rest open until the tab was closed, and they filled its six connections to the server. The page started each stream while still preparing to draw the window. It prepared the window several times before showing it, and every attempt left a stream behind. Streams now start only once the window is on the page. The camera page, the camera wall and the stream overlay start their streams the same way.

+ 29 - 3
backend/app/services/log_reader.py

@@ -25,6 +25,7 @@ from backend.app.core.logging_filters import (
 from backend.app.models.printer import Printer
 from backend.app.models.settings import Settings
 from backend.app.models.user import User
+from backend.app.utils.printer_models import PRINTER_MODEL_ID_MAP, PRINTER_MODEL_MAP
 
 logger = logging.getLogger(__name__)
 
@@ -239,6 +240,29 @@ def sanitize_log_content(content: str, sensitive_strings: dict[str, str] | None
     return content
 
 
+def _model_key(value: str) -> str:
+    return value.upper().replace(" ", "").replace("-", "")
+
+
+# Every model name and code Bambuddy knows. A printer named after its model
+# keeps nothing private in that name, and redacting it would wipe the model
+# from the whole support package (#3442).
+_MODEL_NAME_KEYS = frozenset(
+    _model_key(v)
+    for v in (*PRINTER_MODEL_MAP, *PRINTER_MODEL_MAP.values(), *PRINTER_MODEL_ID_MAP, *PRINTER_MODEL_ID_MAP.values())
+)
+
+
+def _is_model_name(name: str, model: str | None) -> bool:
+    """True when the printer name is just a model name, so not worth redacting.
+
+    The printer's own model counts too, which covers a model Bambuddy does not
+    list yet.
+    """
+    key = _model_key(name.strip())
+    return key in _MODEL_NAME_KEYS or (bool(model) and key == _model_key(model.strip()))
+
+
 async def collect_sensitive_strings(db: AsyncSession) -> dict[str, str]:
     """Collect known sensitive values from the database for log redaction.
 
@@ -249,9 +273,11 @@ async def collect_sensitive_strings(db: AsyncSession) -> dict[str, str]:
     sensitive_strings: dict[str, str] = {}
 
     # Printer names, serial numbers, IP addresses, and access codes
-    result = await db.execute(select(Printer.name, Printer.serial_number, Printer.ip_address, Printer.access_code))
-    for name, serial, ip_address, access_code in result.all():
-        if name:
+    result = await db.execute(
+        select(Printer.name, Printer.serial_number, Printer.ip_address, Printer.access_code, Printer.model)
+    )
+    for name, serial, ip_address, access_code, model in result.all():
+        if name and not _is_model_name(name, model):
             sensitive_strings[name] = "[PRINTER]"
         if serial:
             sensitive_strings[serial] = "[SERIAL]"

+ 36 - 0
backend/tests/unit/test_support_model_name_redaction_3442.py

@@ -0,0 +1,36 @@
+"""A printer named after its model keeps the model in the support package (#3442).
+
+The support package redacts printer names everywhere. A printer named "H3C"
+turned every "H3C" into [PRINTER], so the package no longer said which model
+it came from. A name that is only a model name is not private and stays.
+"""
+
+import pytest
+
+from backend.app.services.log_reader import collect_sensitive_strings, sanitize_log_content
+
+
+@pytest.mark.asyncio
+@pytest.mark.parametrize(
+    ("name", "model"),
+    [
+        ("H3C", "H3C"),  # a model Bambuddy does not list yet: the row's own model decides
+        ("x1c", "P1S"),  # a listed display name, any case
+        ("A1mini", "A1"),  # spaces do not matter
+        ("BL-P001", "X1C"),  # an internal code
+        ("Bambu Lab H2D", "H2D"),  # the 3MF name
+    ],
+)
+async def test_a_model_name_is_not_redacted(db_session, printer_factory, name, model):
+    await printer_factory(name=name, model=model)
+    sensitive = await collect_sensitive_strings(db_session)
+    assert name not in sensitive
+
+
+@pytest.mark.asyncio
+async def test_a_real_name_is_still_redacted(db_session, printer_factory):
+    await printer_factory(name="Workshop H3C", model="H3C")
+    sensitive = await collect_sensitive_strings(db_session)
+    assert sensitive["Workshop H3C"] == "[PRINTER]"
+    line = "Workshop H3C: model H3C connected"
+    assert sanitize_log_content(line, sensitive) == "[PRINTER]: model H3C connected"