Wire admin add-account endpoint into the UI #46
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/add-account-ui"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Surfaces the existing
POST /api/v1/admin/accountsendpoint in the Libra UI, plus a backend hardening fix in the same code path.What
require_super_user) → reloads accounts. Client-side prefix validation mirrors the server's_VALID_ACCOUNT_PREFIXES.opendirective's currency constraint is optional (verified against Beancount's grammar), and the account-creation flow doesn't need it — soadd_account'scurrenciesarg is now optional and the directive is written unconstrained when omitted.add_accountwrote free-text metadata values straight into the ledger source via/api/sourcewith no escaping. An unescaped quote or newline in an admin-supplieddescriptionwould corrupt the Beancount file or forge extra metadata lines. Now escapes backslash/quote/newline per the tokenizer'scunescaperules.Verification
fava_client.py/views_api.pycompile;index.jslints.evil"\n account: Assets:Hackcase is contained as a string value rather than breaking out into a forged metadata line).Commits
fix(fava): escape string metadata + make Open currencies optionalfeat(ui): wire admin add-account endpoint into Chart of AccountsFollow-ups
🤖 Generated with Claude Code
add_account no-ops if the Open directive is already present but returned a normal-looking dict, so the admin endpoint reported success ('created (sync pending)') for a duplicate. Return an already_existed flag and raise 409 from the endpoint. Also anchor the existence check on the Open directive with a trailing-boundary match so a prefix (Expenses:Gas) doesn't match a longer sibling (Expenses:GasStation). The flag is additive, so the idempotent user-account path keeps no-opping silently. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>The endpoint only checked the root prefix, so a direct API call (bypassing the UI) could write a malformed Open directive into the ledger source. Add _validate_account_name mirroring Beancount's core/account.py grammar (root [\p{Lu}][\p{L}\p{Nd}-]*, sub [\p{Lu}\p{Nd}][\p{L}\p{Nd}-]*, >=1 sub-account) — verified to match beancount.core.account.is_valid across 20 cases incl. Unicode, digit-start subs, hyphens. Align the client segment regex to the same rule (was ASCII-only, rejected valid names). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>The existence check matched 'open <name>' anywhere in the chart source, so a prior account's description metadata or a comment mentioning the name produced a false 409, while a real directive with an inline comment and no space ('open X;legacy') was missed → a duplicate Open was appended and bean-check then rejected the file, breaking every later /api/source write. Extract the check into a pure _open_directive_exists() anchored to '^YYYY-MM-DD open <name>' with an account-boundary negative-lookahead, and unit-test both failure directions plus prefix/child non-matches. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>_open_directive_exists hardcoded '^YYYY-MM-DD open ' (dash-only, 2-digit, single-space), but Beancount's DATE token (parser/lexer.l) is (17|18|19|20)[0-9]{2}[-/][0-9]+[-/][0-9]+ and inter-token whitespace is any [ \t\r] run. So a validly-formatted existing Open written as '2024/3/5 open X' or '2020-01-01 open X' escaped detection → duplicate Open appended → bean-check rejects the file. Anchor on Beancount's actual date pattern and [ \t]+ separators. Adds parametrized coverage for slash/single-digit/multi- space/tab variants. Found in a coherence pass over the Beancount source. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>