Repository navigation
fix(wallet): accept the same transaction type filter on the list and trend endpoints - #195
Merged
Merged
Conversation
`GET /api/transactions/trend` answered 400 to `?type=expire` while `GET /api/transactions` accepted it. The accepted-value set for the `type` parameter was written twice — one whitelist per handler. The previous change that introduced the `expire` type updated the list arm, the list error message, the trend SQL and the `TxTrendQuery` doc comment, but not the trend validator, which kept the old five-value whitelist. The frontend sends the *same* `type` value to both endpoints and swallows a failed trend request into `trend = null`, so selecting 赠送过期 in the type filter showed a correct list next to a chart reading "trend data failed to load". Remove the duplication instead of adding `expire` to the second copy: one `TX_FILTER_TYPES` constant plus one `parse_tx_type` helper are now shared by both handlers, and the 400 message is derived from that same array, so the two endpoints cannot drift apart again. Add a parity test that drives both endpoints with every member of the set (plus `all` / empty, and a bogus value as the positive control).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
GET /api/transactions/trendanswered 400 to?type=expirewhileGET /api/transactionsaccepted it, so choosing 赠送过期 in the transactions type filter left the list correct but replaced the trend chart with "trend data failed to load".The set of accepted values for the
typequery parameter was written twice — one whitelist per handler. The change that introduced theexpiretype (#194) updated the list arm, the list error message, the trend SQL and theTxTrendQuerydoc comment, but not the trend validator, which kept the old five-value whitelist. That is user-visible: the frontend sends the sametypevalue to both endpoints (ui/js/app.js,loadTransactions) and swallows a failed trend request intotrend = null, whichrenderTxTrendrenders as "trend data failed to load".This PR removes the duplication rather than adding
expireto the second copy: oneTX_FILTER_TYPESconstant and oneparse_tx_typehelper are now shared by both handlers, and the 400 message is derived from the same array, so the two endpoints can no longer drift apart.Runtime evidence before the fix (throwaway probe, print-only, reverted afterwards — file md5 restored):
Severity — display, not settlement. The ledger rows, the list endpoint and the trend SQL all treat
expireas an expense already; what broke was one UI panel for one filter value.Related Issue
No issue exists for this (the work came from an internal recon cycle); none is fabricated.
closingIssuesReferencesis intentionally empty.Changes
src/routes/wallet.rs: addedTX_FILTER_TYPES(consume | earn | topup | gift | expire | withdraw) as the single source of truth for thetypefilter, plusparse_tx_type(raw)(""/"all"→None; a member →Some(member); anything else → 400).transactionsandtransactions_trend) now call that one helper; the 400 message is built from the same array (format!("type 必须为 {} / all", TX_FILTER_TYPES.join(" / "))). The trend endpoint therefore acceptsexpire, and its 400 message now names the full shared list instead of the stale five-value one.TX_FILTER_TYPESinstead of restating the list (a restated list is what silently disagreed with the trend validator).transactions_trend's prose still said the 口径 was "consume 为负", which stopped being true when the direction was madetype-based (#191/#194); it now says direction comes fromtype, not from the sign ofpts.IN ('earn','topup','gift')/ expenseIN ('consume','expire','withdraw')) — a different concept, deliberately written per query.withdrawstays accepted although it has no writer, because the filter set is what the UI offers, not what exists yet.ui/change, no new i18n key, no cache-bust bump, no configuration / data-structure change.Tests
cargo test全部通过 (185 passed, baseline 184 + 1 new)cargo fmt --check通过cargo clippy --all-targets -- -D warnings通过新增/更新了单元测试:
every_accepted_type_filter_value_is_accepted_by_both_transaction_endpoints— asserts the specification (every filter value the UI offers must be accepted by every endpoint that takes atype):TX_FILTER_TYPES→ 200 on both/api/transactionsand/api/transactions/trend;alland the empty default → 200 on both;refund) → 400 on both, and the message names every member of the shared list.Because the assertions iterate the single source of truth, adding a type to only one endpoint now fails the suite.
A/B: reverting only the trend handler's
parse_tx_typecall back to its old hand-written whitelist ⇒ exactly 1 red / 184 green, the red being this test failing onexpireat/api/transactions/trend:assertion left == right failed: \expire` 应被两个端点接受(/api/transactions/trend?type=expire&bucket=day): {"error":"type 必须为 consume / earn / topup / gift / withdraw / all"}`Checklist
fix/)ui/、无 i18n 键、无 schema 变更)