# Copyright (C) 2026 Danilo M. GPL-2.0-only from firefly_cli.errors import ResolutionError class Resolver: def __init__(self, client): self.client = client def _list(self, path): resp = self.client.request("GET", path, params={"limit": 1000}) out = [] for item in resp.get("data", []): attrs = item.get("attributes", {}) out.append({"id": item.get("id"), **attrs}) return out def _match(self, kind, items, name): hits = [i for i in items if str(i.get("name", "")).lower() == name.lower()] if len(hits) == 1: return hits[0] names = ", ".join(f'{i.get("name")}(id={i.get("id")})' for i in items) if not hits: raise ResolutionError( f'No {kind} named "{name}". Available: {names or "(none)"}') raise ResolutionError( f'Ambiguous {kind} "{name}" matches ids ' + ", ".join(i["id"] for i in hits)) def account(self, name): return self._match("account", self._list("/api/v1/accounts"), name) def account_by_id(self, acc_id): # Escape hatch for same-name accounts (ISSUES.md #2): GET the account # directly; a bad id errors and client.request surfaces a FireflyError. # ponytail: Firefly returns 401 (not 404) for an unknown account id, so # the message reads "Unauthenticated"; the write is still blocked, which # is what matters. Remap to "account not found" only if it confuses users. item = self.client.request("GET", f"/api/v1/accounts/{acc_id}")["data"] return {"id": item["id"], **item.get("attributes", {})} def tag(self, name): return self._match("tag", self._list("/api/v1/tags"), name) def category(self, name): return self._match("category", self._list("/api/v1/categories"), name)