Add verbose flag to list_entries and update archived view

This commit is contained in:
thePR0M3TH3AN
2025-07-16 15:05:11 -04:00
parent e8ade741ad
commit 073b8c4d47
3 changed files with 89 additions and 39 deletions

View File

@@ -920,6 +920,7 @@ class EntryManager:
filter_kind: str | None = None,
*,
include_archived: bool = False,
verbose: bool = True,
) -> List[Tuple[int, str, Optional[str], Optional[str], bool]]:
"""List entries in the index with optional sorting and filtering.
@@ -932,7 +933,8 @@ class EntryManager:
if not entries_data:
logger.info("No entries found.")
print(colored("No entries found.", "yellow"))
if verbose:
print(colored("No entries found.", "yellow"))
return []
def sort_key(item: Tuple[str, Dict[str, Any]]):
@@ -987,51 +989,59 @@ class EntryManager:
)
logger.debug(f"Total entries found: {len(entries)}")
for idx, entry in filtered_items:
etype = entry.get("type", entry.get("kind", EntryType.PASSWORD.value))
print(colored(f"Index: {idx}", "cyan"))
if etype == EntryType.TOTP.value:
print(colored(" Type: TOTP", "cyan"))
print(colored(f" Label: {entry.get('label', '')}", "cyan"))
print(colored(f" Derivation Index: {entry.get('index')}", "cyan"))
print(
colored(
f" Period: {entry.get('period', 30)}s Digits: {entry.get('digits', 6)}",
"cyan",
if verbose:
for idx, entry in filtered_items:
etype = entry.get(
"type", entry.get("kind", EntryType.PASSWORD.value)
)
print(colored(f"Index: {idx}", "cyan"))
if etype == EntryType.TOTP.value:
print(colored(" Type: TOTP", "cyan"))
print(colored(f" Label: {entry.get('label', '')}", "cyan"))
print(
colored(f" Derivation Index: {entry.get('index')}", "cyan")
)
)
elif etype == EntryType.PASSWORD.value:
print(
colored(
f" Label: {entry.get('label', entry.get('website', ''))}",
"cyan",
print(
colored(
f" Period: {entry.get('period', 30)}s Digits: {entry.get('digits', 6)}",
"cyan",
)
)
)
print(
colored(f" Username: {entry.get('username') or 'N/A'}", "cyan")
)
print(colored(f" URL: {entry.get('url') or 'N/A'}", "cyan"))
print(
colored(
f" Archived: {'Yes' if entry.get('archived', entry.get('blacklisted', False)) else 'No'}",
"cyan",
elif etype == EntryType.PASSWORD.value:
print(
colored(
f" Label: {entry.get('label', entry.get('website', ''))}",
"cyan",
)
)
)
else:
print(colored(f" Label: {entry.get('label', '')}", "cyan"))
print(
colored(
f" Derivation Index: {entry.get('index', idx)}",
"cyan",
print(
colored(
f" Username: {entry.get('username') or 'N/A'}", "cyan"
)
)
)
print("-" * 40)
print(colored(f" URL: {entry.get('url') or 'N/A'}", "cyan"))
print(
colored(
f" Archived: {'Yes' if entry.get('archived', entry.get('blacklisted', False)) else 'No'}",
"cyan",
)
)
else:
print(colored(f" Label: {entry.get('label', '')}", "cyan"))
print(
colored(
f" Derivation Index: {entry.get('index', idx)}",
"cyan",
)
)
print("-" * 40)
return entries
except Exception as e:
logger.error(f"Failed to list entries: {e}", exc_info=True)
print(colored(f"Error: Failed to list entries: {e}", "red"))
if verbose:
print(colored(f"Error: Failed to list entries: {e}", "red"))
return []
def search_entries(

View File

@@ -3240,7 +3240,9 @@ class PasswordManager:
def handle_view_archived_entries(self) -> None:
"""Display archived entries and optionally view or restore them."""
try:
archived = self.entry_manager.list_entries(include_archived=True)
archived = self.entry_manager.list_entries(
include_archived=True, verbose=False
)
archived = [e for e in archived if e[4]]
if not archived:
self.notify("No archived entries found.", level="WARNING")
@@ -3286,7 +3288,7 @@ class PasswordManager:
self.last_update = time.time()
pause()
archived = self.entry_manager.list_entries(
include_archived=True
include_archived=True, verbose=False
)
archived = [e for e in archived if e[4]]
if not archived:

View File

@@ -152,3 +152,41 @@ def test_view_archived_entries_removed_after_restore(monkeypatch, capsys):
note = pm.notifications.get_nowait()
assert note.level == "WARNING"
assert note.message == "No archived entries found."
def test_archived_entries_menu_hides_active(monkeypatch, capsys):
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD)
cfg_mgr = ConfigManager(vault, tmp_path)
backup_mgr = BackupManager(tmp_path, cfg_mgr)
entry_mgr = EntryManager(vault, backup_mgr)
pm = PasswordManager.__new__(PasswordManager)
pm.encryption_mode = EncryptionMode.SEED_ONLY
pm.encryption_manager = enc_mgr
pm.vault = vault
pm.entry_manager = entry_mgr
pm.backup_manager = backup_mgr
pm.parent_seed = TEST_SEED
pm.nostr_client = SimpleNamespace()
pm.fingerprint_dir = tmp_path
pm.is_dirty = False
pm.notifications = queue.Queue()
archived_idx = entry_mgr.add_entry("archived.com", 8)
active_idx = entry_mgr.add_entry("active.com", 8)
# Archive only the first entry
monkeypatch.setattr("builtins.input", lambda *_: str(archived_idx))
pm.handle_archive_entry()
assert entry_mgr.retrieve_entry(archived_idx)["archived"] is True
assert entry_mgr.retrieve_entry(active_idx)["archived"] is False
# View archived entries and immediately exit
inputs = iter([""])
monkeypatch.setattr("builtins.input", lambda *_: next(inputs))
pm.handle_view_archived_entries()
out = capsys.readouterr().out
assert "archived.com" in out
assert "active.com" not in out