From 53b6034f2ae2816d4b1c509e326f305c30aaed2f Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 9 Dec 2025 13:56:55 +0900 Subject: [PATCH 1/4] feat: add liststore annotations upfront --- dzgui/controllers/model.py | 76 ++++++++++++++++++++++++++++++++++---- dzgui/init/migrate.py | 1 + 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/dzgui/controllers/model.py b/dzgui/controllers/model.py index 8defdb1..747f701 100644 --- a/dzgui/controllers/model.py +++ b/dzgui/controllers/model.py @@ -1,25 +1,80 @@ import gi gi.require_version("Gtk", "3.0") from gi.repository.Gtk import ListStore +from gi.repository import GObject from dzgui.const.enum import FilterMode +from dataclasses import dataclass, fields + +@dataclass +@dataclass(slots=True, frozen=True) +class ServerColumns: + name: str + _map: str + perspective: str + gametime: str + players: int + _max: int + queue: int + ip: str + qport: int + ping: int + provider: str + modded: bool + + +@dataclass(slots=True, frozen=True) +class ModCols: + name: str + symlink: str + directory: str + size: float + color: str + + +@dataclass(slots=True, frozen=True) +class LogCols: + timestamp: str + flag: str + traceback: str + msg: str + + +@dataclass(slots=True, frozen=True) +class ServerModCols: + name: str + uid: GObject.TYPE_INT64 + installed: str + + +@dataclass(slots=True, frozen=True) +class MenuCols: + name: str + hidden: GObject.TYPE_PYOBJECT + + class ModelManager: """ Manages access to cached ListStore resources and performs filtering on behalf of TreeViews. - Not thread-safe. + Methods are not thread-safe in themselves. """ def __init__(self): - # NOTE: packed ListStores self.filter_cache = {} self.ping_cache = {} - self.mod_store = ListStore(str, str, str, float, str) + self.map_store = ListStore(str) + self.row_store = self.new_model_from_class(MenuCols) + self.help_store = self.new_model_from_class(MenuCols) - # NOTE: stringwise (list) representation of the model + self.mod_store = self.new_model_from_class(ModCols) + self.log_store = self.new_model_from_class(LogCols) + self.modlist_store = self.new_model_from_class(ServerModCols) + + #self.mod_store = ListStore(str, str, str, float, str) self.control_model = None self.filtered = None self.success = True @@ -29,6 +84,10 @@ class ModelManager: cls.instance = super(ModelManager, cls).__new__(cls) return cls.instance + def new_model_from_class(self, cls: type) -> ListStore: + store = ListStore(*[ftype for field, ftype in cls.__annotations__.items()]) + return store + def get_mod_store(self) -> ListStore: return self.mod_store @@ -200,9 +259,12 @@ class ModelManager: self.filter_cache[filters] = (model, rows) def new_model(self) -> ListStore: - return ListStore( - str, str, str, str, int, int, int, str, int, int, str, bool - ) + store = ListStore(*[ftype for field, ftype in ServerColumns.__annotations__.items()]) + return store + #return = ListStore(*f) + #return ListStore( + # str, str, str, str, int, int, int, str, int, int, str, bool + #) def resync_model(self, addr: str, qport: int) -> None: """ diff --git a/dzgui/init/migrate.py b/dzgui/init/migrate.py index 08a7c8b..3fb2e84 100644 --- a/dzgui/init/migrate.py +++ b/dzgui/init/migrate.py @@ -11,6 +11,7 @@ def test_legacy_conf(config: Path) -> None: old_conf = Path.home() / LEGACY_CONFIG_PATH if old_conf.is_file(): j = rc2json(old_conf) + # FIXME: superfluous use of Path() Path(config).parent.mkdir(parents=True, exist_ok=True) config.write_text(j) else: From 57be68ea73d19c4610640b7d17430980ec439577 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 9 Dec 2025 13:58:37 +0900 Subject: [PATCH 2/4] chore: cleanup --- dzgui/controllers/model.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dzgui/controllers/model.py b/dzgui/controllers/model.py index 747f701..a3dae37 100644 --- a/dzgui/controllers/model.py +++ b/dzgui/controllers/model.py @@ -259,12 +259,8 @@ class ModelManager: self.filter_cache[filters] = (model, rows) def new_model(self) -> ListStore: - store = ListStore(*[ftype for field, ftype in ServerColumns.__annotations__.items()]) + store = self.new_model_from_class(ServerColumns) return store - #return = ListStore(*f) - #return ListStore( - # str, str, str, str, int, int, int, str, int, int, str, bool - #) def resync_model(self, addr: str, qport: int) -> None: """ From 5483717e0cf539d6e8d96cad1c53e0f6cddf4d26 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Sat, 13 Dec 2025 23:00:41 +0900 Subject: [PATCH 3/4] feat: redact API key in log table --- CHANGELOG.md | 1 + dzgui/controllers/mc.py | 21 +++++++++++++++++++-- dzgui/data/CHANGELOG.md | 1 + dzgui/views/pages/options.py | 3 +++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index faf81e5..2fc386a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - Documentation ships with source - Open filepicker when generating system log - Developers page (and -d flag) +- Redact API key in log table ## Changed - Reduce padding on keys button diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index f9757b4..decd220 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -1,6 +1,7 @@ import logging -import os import locale +import os +import re import shutil import threading import textwrap @@ -437,9 +438,25 @@ class Controller: with open(log, "r") as f: lines = [line.split(strings.delimiter) for line in f.read().splitlines()] for record in lines: - store.append(record) + clean = self.redact_log(record) + store.append(clean) self.open_page(NotebookPage.LOG) + def redact_log(self, record: list) -> list[str]: + """ + requests library includes Steam API key in URL params + """ + clean = [] + for item in record: + if "&key=" in item: + pat = r"(.*&key=)(\S+)(.*)" + scrubbed = re.sub(pat, r"\1REDACTED\3", item) + clean.append(scrubbed) + else: + clean.append(item) + return clean + + def select_colorized(self) -> None: model = self.model_manager.get_mod_store() sel = self.mediator.modtreeview.get_selection() diff --git a/dzgui/data/CHANGELOG.md b/dzgui/data/CHANGELOG.md index faf81e5..2fc386a 100644 --- a/dzgui/data/CHANGELOG.md +++ b/dzgui/data/CHANGELOG.md @@ -13,6 +13,7 @@ - Documentation ships with source - Open filepicker when generating system log - Developers page (and -d flag) +- Redact API key in log table ## Changed - Reduce padding on keys button diff --git a/dzgui/views/pages/options.py b/dzgui/views/pages/options.py index d9946de..4d63a51 100644 --- a/dzgui/views/pages/options.py +++ b/dzgui/views/pages/options.py @@ -487,8 +487,11 @@ class Options(Gtk.Box): active_combo = 1 if config["branch"] == BETA_REPO else 0 + + self.controller.suppress_signal(self, self.branch_combo, "_on_branch_changed", True) self.branch_combo.set_active(active_combo) self.branch_combo.set_sensitive(prefs.allow_updates) + self.controller.suppress_signal(self, self.branch_combo, "_on_branch_changed", False) if prefs.allow_updates is True: msg = strings.options.self_update From f44e1959389560b26c83ed715f9d7f7fd907e010 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Sat, 13 Dec 2025 23:05:34 +0900 Subject: [PATCH 4/4] chore: move redact_log() to util --- dzgui/controllers/mc.py | 18 ++---------------- dzgui/util/redact.py | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index decd220..9553694 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -47,6 +47,7 @@ from dzgui.util import localize, cooldown, strings from dzgui.util._json import read_json, write_json from dzgui.util.open_links import open_workshop_page from dzgui.util.format import pluralize, format_mods +from dzgui.util.redact import redact_log from dzgui.views.dialogs.filepicker import FilePicker from dzgui.views.dialogs.generic import GenericDialog @@ -438,25 +439,10 @@ class Controller: with open(log, "r") as f: lines = [line.split(strings.delimiter) for line in f.read().splitlines()] for record in lines: - clean = self.redact_log(record) + clean = redact_log(record) store.append(clean) self.open_page(NotebookPage.LOG) - def redact_log(self, record: list) -> list[str]: - """ - requests library includes Steam API key in URL params - """ - clean = [] - for item in record: - if "&key=" in item: - pat = r"(.*&key=)(\S+)(.*)" - scrubbed = re.sub(pat, r"\1REDACTED\3", item) - clean.append(scrubbed) - else: - clean.append(item) - return clean - - def select_colorized(self) -> None: model = self.model_manager.get_mod_store() sel = self.mediator.modtreeview.get_selection() diff --git a/dzgui/util/redact.py b/dzgui/util/redact.py index c99124d..94d4bfb 100644 --- a/dzgui/util/redact.py +++ b/dzgui/util/redact.py @@ -4,3 +4,17 @@ def redact(text: str) -> str: r = r"(/home/)([^/])*" cleaned = re.sub(r, r"/home/REDACTED", text) return cleaned + +def redact_log(record: list) -> list[str]: + """ + requests library includes Steam API key in URL params + """ + clean = [] + for item in record: + if "&key=" in item: + pat = r"(.*&key=)(\S+)(.*)" + scrubbed = re.sub(pat, r"\1REDACTED\3", item) + clean.append(scrubbed) + else: + clean.append(item) + return clean