From ff1f8bb4e1b6b97d43f4d6f0b5c2677a5fcb4f0b Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Sat, 19 Jul 2025 15:50:52 -0400 Subject: [PATCH] Use background sync in entry service --- src/seedpass/core/api.py | 22 +++++++++---------- src/seedpass_gui/app.py | 27 ++++++++++++++++++++---- src/tests/test_cli_core_services.py | 5 +++-- src/tests/test_cli_doc_examples.py | 1 + src/tests/test_cli_entry_add_commands.py | 4 ++-- src/tests/test_core_services.py | 4 ++-- src/tests/test_typer_cli.py | 10 ++++----- 7 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/seedpass/core/api.py b/src/seedpass/core/api.py index d51a21e..03e8d99 100644 --- a/src/seedpass/core/api.py +++ b/src/seedpass/core/api.py @@ -282,7 +282,7 @@ class EntryService: ) -> int: with self._lock: idx = self._manager.entry_manager.add_entry(label, length, username, url) - self._manager.sync_vault() + self._manager.start_background_vault_sync() return idx def add_totp( @@ -303,7 +303,7 @@ class EntryService: period=period, digits=digits, ) - self._manager.sync_vault() + self._manager.start_background_vault_sync() return uri def add_ssh_key( @@ -320,7 +320,7 @@ class EntryService: index=index, notes=notes, ) - self._manager.sync_vault() + self._manager.start_background_vault_sync() return idx def add_pgp_key( @@ -341,7 +341,7 @@ class EntryService: user_id=user_id, notes=notes, ) - self._manager.sync_vault() + self._manager.start_background_vault_sync() return idx def add_nostr_key( @@ -357,7 +357,7 @@ class EntryService: index=index, notes=notes, ) - self._manager.sync_vault() + self._manager.start_background_vault_sync() return idx def add_seed( @@ -376,13 +376,13 @@ class EntryService: words_num=words, notes=notes, ) - self._manager.sync_vault() + self._manager.start_background_vault_sync() return idx def add_key_value(self, label: str, value: str, *, notes: str = "") -> int: with self._lock: idx = self._manager.entry_manager.add_key_value(label, value, notes=notes) - self._manager.sync_vault() + self._manager.start_background_vault_sync() return idx def add_managed_account( @@ -399,7 +399,7 @@ class EntryService: index=index, notes=notes, ) - self._manager.sync_vault() + self._manager.start_background_vault_sync() return idx def modify_entry( @@ -425,17 +425,17 @@ class EntryService: digits=digits, value=value, ) - self._manager.sync_vault() + self._manager.start_background_vault_sync() def archive_entry(self, entry_id: int) -> None: with self._lock: self._manager.entry_manager.archive_entry(entry_id) - self._manager.sync_vault() + self._manager.start_background_vault_sync() def restore_entry(self, entry_id: int) -> None: with self._lock: self._manager.entry_manager.restore_entry(entry_id) - self._manager.sync_vault() + self._manager.start_background_vault_sync() def export_totp_entries(self) -> dict: with self._lock: diff --git a/src/seedpass_gui/app.py b/src/seedpass_gui/app.py index 2620f99..dcc38ff 100644 --- a/src/seedpass_gui/app.py +++ b/src/seedpass_gui/app.py @@ -5,6 +5,7 @@ import time import toga from toga.style import Pack +from toga.sources import ListSource from toga.style.pack import COLUMN, ROW from seedpass.core.entry_types import EntryType @@ -89,8 +90,10 @@ class MainWindow(toga.Window): bus.subscribe("vault_locked", self.vault_locked) self.last_sync = None + self.entry_source = ListSource(["id", "label", "kind", "info1", "info2"]) self.table = toga.Table( headings=["ID", "Label", "Kind", "Info 1", "Info 2"], + data=self.entry_source, style=Pack(flex=1), ) @@ -118,7 +121,7 @@ class MainWindow(toga.Window): self.refresh_entries() def refresh_entries(self) -> None: - self.table.data = [] + self.entry_source.clear() for idx, label, username, url, _arch in self.entries.list_entries(): entry = self.entries.retrieve_entry(idx) kind = (entry or {}).get("kind", (entry or {}).get("type", "")) @@ -131,7 +134,15 @@ class MainWindow(toga.Window): info1 = entry.get("value", "") if entry else "" else: info1 = str(entry.get("index", "")) if entry else "" - self.table.data.append((idx, label, kind, info1, info2)) + self.entry_source.append( + { + "id": idx, + "label": label, + "kind": kind, + "info1": info1, + "info2": info2, + } + ) # --- Button handlers ------------------------------------------------- def add_entry(self, widget: toga.Widget) -> None: @@ -285,9 +296,17 @@ class SearchDialog(toga.Window): def do_search(self, widget: toga.Widget) -> None: query = self.query_input.value or "" results = self.main.entries.search_entries(query) - self.main.table.data = [] + self.main.entry_source.clear() for idx, label, username, url, _arch in results: - self.main.table.data.append((idx, label, username or "", url or "")) + self.main.entry_source.append( + { + "id": idx, + "label": label, + "kind": "", + "info1": username or "", + "info2": url or "", + } + ) self.close() diff --git a/src/tests/test_cli_core_services.py b/src/tests/test_cli_core_services.py index fd68b9a..1c79a42 100644 --- a/src/tests/test_cli_core_services.py +++ b/src/tests/test_cli_core_services.py @@ -36,7 +36,7 @@ def test_cli_entry_add_search_sync(monkeypatch): calls["search"] = (q, kinds) return [(1, "Label", None, None, False)] - def sync_vault(): + def start_background_vault_sync(): calls["sync"] = True return {"manifest_id": "m", "chunk_ids": [], "delta_ids": []} @@ -44,7 +44,8 @@ def test_cli_entry_add_search_sync(monkeypatch): entry_manager=SimpleNamespace( add_entry=add_entry, search_entries=search_entries ), - sync_vault=sync_vault, + start_background_vault_sync=start_background_vault_sync, + sync_vault=lambda: {"manifest_id": "m", "chunk_ids": [], "delta_ids": []}, select_fingerprint=lambda fp: None, ) monkeypatch.setattr(cli, "PasswordManager", lambda: pm) diff --git a/src/tests/test_cli_doc_examples.py b/src/tests/test_cli_doc_examples.py index 1518261..ac5ebb1 100644 --- a/src/tests/test_cli_doc_examples.py +++ b/src/tests/test_cli_doc_examples.py @@ -58,6 +58,7 @@ class DummyPM: "chunk_ids": ["c1"], "delta_ids": [], } + self.start_background_vault_sync = lambda *a, **k: self.sync_vault() self.config_manager = SimpleNamespace( load_config=lambda require_pin=False: {"inactivity_timeout": 30}, set_inactivity_timeout=lambda v: None, diff --git a/src/tests/test_cli_entry_add_commands.py b/src/tests/test_cli_entry_add_commands.py index 5fbeafd..dd482b3 100644 --- a/src/tests/test_cli_entry_add_commands.py +++ b/src/tests/test_cli_entry_add_commands.py @@ -115,14 +115,14 @@ def test_entry_add_commands( called["kwargs"] = kwargs return stdout - def sync_vault(): + def start_background_vault_sync(): called["sync"] = True pm = SimpleNamespace( entry_manager=SimpleNamespace(**{method: func}), parent_seed="seed", select_fingerprint=lambda fp: None, - sync_vault=sync_vault, + start_background_vault_sync=start_background_vault_sync, ) monkeypatch.setattr(cli, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", command] + cli_args) diff --git a/src/tests/test_core_services.py b/src/tests/test_core_services.py index dc419c4..ea48a8a 100644 --- a/src/tests/test_core_services.py +++ b/src/tests/test_core_services.py @@ -29,7 +29,7 @@ def test_entry_service_add_entry_and_search(): called["search"] = (q, kinds) return [(5, "Example", username, url, False)] - def sync_vault(): + def start_background_vault_sync(): called["sync"] = True username = "user" @@ -38,7 +38,7 @@ def test_entry_service_add_entry_and_search(): entry_manager=SimpleNamespace( add_entry=add_entry, search_entries=search_entries ), - sync_vault=sync_vault, + start_background_vault_sync=start_background_vault_sync, ) service = EntryService(pm) idx = service.add_entry("Example", 12, username, url) diff --git a/src/tests/test_typer_cli.py b/src/tests/test_typer_cli.py index 35b3d0d..d49803c 100644 --- a/src/tests/test_typer_cli.py +++ b/src/tests/test_typer_cli.py @@ -377,7 +377,7 @@ def test_entry_add(monkeypatch): pm = SimpleNamespace( entry_manager=SimpleNamespace(add_entry=add_entry), select_fingerprint=lambda fp: None, - sync_vault=lambda: None, + start_background_vault_sync=lambda: None, ) monkeypatch.setattr(cli, "PasswordManager", lambda: pm) result = runner.invoke( @@ -408,7 +408,7 @@ def test_entry_modify(monkeypatch): pm = SimpleNamespace( entry_manager=SimpleNamespace(modify_entry=modify_entry), select_fingerprint=lambda fp: None, - sync_vault=lambda: None, + start_background_vault_sync=lambda: None, ) monkeypatch.setattr(cli, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", "modify", "1", "--username", "alice"]) @@ -423,7 +423,7 @@ def test_entry_modify_invalid(monkeypatch): pm = SimpleNamespace( entry_manager=SimpleNamespace(modify_entry=modify_entry), select_fingerprint=lambda fp: None, - sync_vault=lambda: None, + start_background_vault_sync=lambda: None, ) monkeypatch.setattr(cli, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", "modify", "1", "--username", "alice"]) @@ -440,7 +440,7 @@ def test_entry_archive(monkeypatch): pm = SimpleNamespace( entry_manager=SimpleNamespace(archive_entry=archive_entry), select_fingerprint=lambda fp: None, - sync_vault=lambda: None, + start_background_vault_sync=lambda: None, ) monkeypatch.setattr(cli, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", "archive", "3"]) @@ -458,7 +458,7 @@ def test_entry_unarchive(monkeypatch): pm = SimpleNamespace( entry_manager=SimpleNamespace(restore_entry=restore_entry), select_fingerprint=lambda fp: None, - sync_vault=lambda: None, + start_background_vault_sync=lambda: None, ) monkeypatch.setattr(cli, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", "unarchive", "4"])