diff options
-rw-r--r-- | src/headless/integrationtest.ts | 9 | ||||
-rw-r--r-- | src/headless/taler-wallet-cli.ts | 42 | ||||
-rw-r--r-- | src/operations/pending.ts | 2 | ||||
-rw-r--r-- | src/types/pending.ts | 12 | ||||
-rw-r--r-- | src/webex/messages.ts | 5 | ||||
-rw-r--r-- | src/webex/pages/popup.tsx | 390 | ||||
-rw-r--r-- | src/webex/wxBackend.ts | 4 |
7 files changed, 31 insertions, 433 deletions
diff --git a/src/headless/integrationtest.ts b/src/headless/integrationtest.ts index db96d57c4..51e93f30b 100644 --- a/src/headless/integrationtest.ts +++ b/src/headless/integrationtest.ts @@ -184,13 +184,6 @@ export async function runIntegrationTest( ); await myWallet.runUntilDone(); - - const history = await myWallet.getHistory({ extraDebug: true }); - - console.log( - "history after integration test:", - JSON.stringify(history, undefined, 2), - ); } export async function runIntegrationTestBasic( @@ -327,8 +320,6 @@ export async function runIntegrationTestBasic( await myWallet.runUntilDone(); - const history = await myWallet.getHistory({ extraDebug: true }); - console.log( "history after integration test:", JSON.stringify(history, undefined, 2), diff --git a/src/headless/taler-wallet-cli.ts b/src/headless/taler-wallet-cli.ts index b8ae84d72..0357a10fe 100644 --- a/src/headless/taler-wallet-cli.ts +++ b/src/headless/taler-wallet-cli.ts @@ -39,6 +39,7 @@ import { makeCodecForList, codecForString } from "../util/codec"; import { NodeHttpLib } from "./NodeHttpLib"; import * as nacl from "../crypto/primitives/nacl-fast"; import { addPaytoQueryParams } from "../util/payto"; +import { handleCoreApiRequest } from "../walletCoreApiHandler"; const logger = new Logger("taler-wallet-cli.ts"); @@ -198,33 +199,26 @@ walletCli }); walletCli - .subcommand("history", "history", { help: "Show wallet event history." }) - .flag("json", ["--json"], { - default: false, - }) - .maybeOption("from", ["--from"], clk.STRING) - .maybeOption("to", ["--to"], clk.STRING) - .maybeOption("limit", ["--limit"], clk.STRING) - .maybeOption("contEvt", ["--continue-with"], clk.STRING) - .flag("extraDebug", ["--extra-debug"]) + .subcommand("api", "balance", { help: "Call the wallet-core API directly." }) + .requiredArgument("operation", clk.STRING) + .requiredArgument("request", clk.STRING) .action(async (args) => { await withWallet(args, async (wallet) => { - const history = await wallet.getHistory({ - extraDebug: args.history.extraDebug, - }); - if (args.history.json) { - console.log(JSON.stringify(history, undefined, 2)); - } else { - for (const h of history.history) { - console.log( - `event at ${new Date(h.timestamp.t_ms).toISOString()} with type ${ - h.type - }:`, - ); - console.log(JSON.stringify(h, undefined, 2)); - console.log(); - } + let requestJson; + try { + requestJson = JSON.parse(args.api.operation); + } catch (e) { + console.error("malformed request"); + process.exit(1); + return; } + const resp = await handleCoreApiRequest( + wallet, + args.api.operation, + 1, + requestJson, + ); + console.log(JSON.stringify(resp, undefined, 2)); }); }); diff --git a/src/operations/pending.ts b/src/operations/pending.ts index e610d42ef..acad5e634 100644 --- a/src/operations/pending.ts +++ b/src/operations/pending.ts @@ -27,6 +27,7 @@ import { PendingOperationsResponse, PendingOperationType, ExchangeUpdateOperationStage, + ReserveType, } from "../types/pending"; import { Duration, @@ -38,7 +39,6 @@ import { import { TransactionHandle } from "../util/query"; import { InternalWalletState } from "./state"; import { getBalancesInsideTransaction } from "./balance"; -import { ReserveType } from "../types/history"; function updateRetryDelay( oldDelay: Duration, diff --git a/src/types/pending.ts b/src/types/pending.ts index 8a1e84362..e6c879992 100644 --- a/src/types/pending.ts +++ b/src/types/pending.ts @@ -24,7 +24,6 @@ import { OperationErrorDetails, WalletBalance } from "./walletTypes"; import { WithdrawalSource, RetryInfo, ReserveRecordStatus } from "./dbTypes"; import { Timestamp, Duration } from "../util/time"; -import { ReserveType } from "./history"; export const enum PendingOperationType { Bug = "bug", @@ -91,6 +90,17 @@ export const enum ExchangeUpdateOperationStage { FinalizeUpdate = "finalize-update", } +export const enum ReserveType { + /** + * Manually created. + */ + Manual = "manual", + /** + * Withdrawn from a bank that has "tight" Taler integration + */ + TalerBankWithdraw = "taler-bank-withdraw", +} + /** * Status of processing a reserve. * diff --git a/src/webex/messages.ts b/src/webex/messages.ts index fd9fe0347..5f63697c1 100644 --- a/src/webex/messages.ts +++ b/src/webex/messages.ts @@ -25,7 +25,6 @@ import * as dbTypes from "../types/dbTypes"; import * as walletTypes from "../types/walletTypes"; import { UpgradeResponse } from "./wxApi"; -import { HistoryEvent } from "../types/history"; /** * Message type information. @@ -61,10 +60,6 @@ export interface MessageMap { request: { baseUrl: string }; response: dbTypes.ExchangeRecord; }; - "get-history": { - request: {}; - response: HistoryEvent[]; - }; "get-coins": { request: { exchangeBaseUrl: string }; response: any; diff --git a/src/webex/pages/popup.tsx b/src/webex/pages/popup.tsx index 875bbcb5c..e4eea4d9e 100644 --- a/src/webex/pages/popup.tsx +++ b/src/webex/pages/popup.tsx @@ -35,7 +35,6 @@ import { abbrev, renderAmount, PageLink } from "../renderHtml"; import * as wxApi from "../wxApi"; import React, { Fragment, useState, useEffect } from "react"; -import { HistoryEvent } from "../../types/history"; import moment from "moment"; import { Timestamp } from "../../util/time"; @@ -315,311 +314,9 @@ function formatAndCapitalize(text: string): string { return text; } -type HistoryItemProps = { - title?: string | JSX.Element; - text?: string | JSX.Element; - small?: string | JSX.Element; - amount?: string | AmountJson; - fees?: string | AmountJson; - invalid?: string | AmountJson; - icon?: string; - timestamp: Timestamp; - negative?: boolean; -}; - -function HistoryItem({ - title, - text, - small, - amount, - fees, - invalid, - timestamp, - icon, - negative = false, -}: HistoryItemProps): JSX.Element { - function formatDate(timestamp: number | "never"): string | null { - if (timestamp !== "never") { - const itemDate = moment(timestamp); - if (itemDate.isBetween(moment().subtract(2, "days"), moment())) { - return itemDate.fromNow(); - } - return itemDate.format("lll"); - } - return null; - } - - let invalidElement, amountElement, feesElement; - - if (amount) { - amountElement = renderAmount(amount); - } - - if (fees) { - fees = typeof fees === "string" ? Amounts.parse(fees) : fees; - if (fees && Amounts.isNonZero(fees)) { - feesElement = renderAmount(fees); - } - } - - if (invalid) { - invalid = typeof invalid === "string" ? Amounts.parse(invalid) : invalid; - if (invalid && Amounts.isNonZero(invalid)) { - invalidElement = renderAmount(invalid); - } - } - - return ( - <div className="historyItem"> - {icon ? <Icon l={icon} /> : null} - <div className="historyContent"> - {title ? <div className={"historyTitle"}>{title}</div> : null} - {text ? <div className={"historyText"}>{text}</div> : null} - {small ? <div className={"historySmall"}>{small}</div> : null} - </div> - <div className={"historyLeft"}> - <div className={"historyAmount"}> - {amountElement ? ( - <div className={`${negative ? "negative" : "positive"}`}> - {amountElement} - </div> - ) : null} - {invalidElement ? ( - <div className={"secondary"}> - {i18n.str`Invalid `}{" "} - <span className={"negative"}>{invalidElement}</span> - </div> - ) : null} - {feesElement ? ( - <div className={"secondary"}> - {i18n.str`Fees `}{" "} - <span className={"negative"}>{feesElement}</span> - </div> - ) : null} - </div> - <div className="historyDate">{formatDate(timestamp.t_ms)}</div> - </div> - </div> - ); -} - -function amountDiff( - total: string | Amounts.AmountJson, - partial: string | Amounts.AmountJson, -): Amounts.AmountJson | string { - const a = typeof total === "string" ? Amounts.parse(total) : total; - const b = typeof partial === "string" ? Amounts.parse(partial) : partial; - if (a && b) { - return Amounts.sub(a, b).amount; - } else { - return total; - } -} - -function parseSummary(summary: string): { item: string; merchant: string } { - const parsed = summary.split(/: (.+)/); - return { - merchant: parsed[0], - item: parsed[1], - }; -} - -function formatHistoryItem(historyItem: HistoryEvent): JSX.Element { - switch (historyItem.type) { - case "refreshed": { - return ( - <HistoryItem - timestamp={historyItem.timestamp} - small={i18n.str`Refresh sessions has completed`} - fees={amountDiff( - historyItem.amountRefreshedRaw, - historyItem.amountRefreshedEffective, - )} - /> - ); - } - - case "order-refused": { - const { merchant, item } = parseSummary( - historyItem.orderShortInfo.summary, - ); - return ( - <HistoryItem - icon={"X"} - timestamp={historyItem.timestamp} - small={i18n.str`Order Refused`} - title={merchant} - text={abbrev(item, 30)} - /> - ); - } - - case "order-redirected": { - const { merchant, item } = parseSummary( - historyItem.newOrderShortInfo.summary, - ); - return ( - <HistoryItem - icon={"⟲"} - small={i18n.str`Order redirected`} - text={abbrev(item, 40)} - timestamp={historyItem.timestamp} - title={merchant} - /> - ); - } - - case "payment-aborted": { - const { merchant, item } = parseSummary( - historyItem.orderShortInfo.summary, - ); - return ( - <HistoryItem - amount={historyItem.orderShortInfo.amount} - fees={historyItem.amountLost} - icon={"P"} - small={i18n.str`Payment aborted`} - text={abbrev(item, 40)} - timestamp={historyItem.timestamp} - title={merchant} - /> - ); - } - - case "payment-sent": { - const url = historyItem.orderShortInfo.fulfillmentUrl; - const { merchant, item } = parseSummary( - historyItem.orderShortInfo.summary, - ); - const fees = amountDiff( - historyItem.amountPaidWithFees, - historyItem.orderShortInfo.amount, - ); - const fulfillmentLinkElem = ( - <Fragment> - <a href={url} onClick={openTab(url)}> - {item ? abbrev(item, 30) : null} - </a> - </Fragment> - ); - return ( - <HistoryItem - amount={historyItem.orderShortInfo.amount} - fees={fees} - icon={"P"} - negative={true} - small={i18n.str`Payment Sent`} - text={fulfillmentLinkElem} - timestamp={historyItem.timestamp} - title={merchant} - /> - ); - } - case "order-accepted": { - const url = historyItem.orderShortInfo.fulfillmentUrl; - const { merchant, item } = parseSummary( - historyItem.orderShortInfo.summary, - ); - const fulfillmentLinkElem = ( - <Fragment> - <a href={url} onClick={openTab(url)}> - {item ? abbrev(item, 40) : null} - </a> - </Fragment> - ); - return ( - <HistoryItem - negative={true} - amount={historyItem.orderShortInfo.amount} - icon={"P"} - small={i18n.str`Order accepted`} - text={fulfillmentLinkElem} - timestamp={historyItem.timestamp} - title={merchant} - /> - ); - } - case "reserve-balance-updated": { - return ( - <HistoryItem - timestamp={historyItem.timestamp} - small={i18n.str`Reserve balance updated`} - /> - ); - } - case "refund": { - const merchantElem = ( - <em>{abbrev(historyItem.orderShortInfo.summary, 25)}</em> - ); - return ( - <HistoryItem - icon={"R"} - timestamp={historyItem.timestamp} - small={i18n.str`Payment refund`} - text={merchantElem} - amount={historyItem.amountRefundedRaw} - invalid={historyItem.amountRefundedInvalid} - fees={amountDiff( - amountDiff( - historyItem.amountRefundedRaw, - historyItem.amountRefundedInvalid, - ), - historyItem.amountRefundedEffective, - )} - /> - ); - } - case "withdrawn": { - const exchange = new URL(historyItem.exchangeBaseUrl).host; - const fees = amountDiff( - historyItem.amountWithdrawnRaw, - historyItem.amountWithdrawnEffective, - ); - return ( - <HistoryItem - amount={historyItem.amountWithdrawnRaw} - fees={fees} - icon={"w"} - small={i18n.str`Withdrawn`} - title={exchange} - timestamp={historyItem.timestamp} - /> - ); - } - case "tip-accepted": { - return ( - <HistoryItem - icon={"T"} - negative={true} - timestamp={historyItem.timestamp} - title={<i18n.Translate wrap={Fragment}>Tip Accepted</i18n.Translate>} - amount={historyItem.tipAmountRaw} - /> - ); - } - case "tip-declined": { - return ( - <HistoryItem - icon={"T"} - timestamp={historyItem.timestamp} - title={<i18n.Translate wrap={Fragment}>Tip Declined</i18n.Translate>} - amount={historyItem.tipAmountRaw} - /> - ); - } - default: - return ( - <HistoryItem - timestamp={historyItem.timestamp} - small={i18n.str`${formatAndCapitalize(historyItem.type)}`} - /> - ); - } -} const HistoryComponent = (props: any): JSX.Element => { - const record = props.record; - return formatHistoryItem(record); + return <span>TBD</span>; }; class WalletSettings extends React.Component<any, any> { @@ -633,90 +330,6 @@ class WalletSettings extends React.Component<any, any> { } } -class WalletHistory extends React.Component<any, any> { - private myHistory: any[]; - private gotError = false; - private unmounted = false; - private hidenTypes: string[] = [ - "order-accepted", - "order-redirected", - "refreshed", - "reserve-balance-updated", - "exchange-updated", - "exchange-added", - ]; - - componentWillMount(): void { - this.update(); - this.setState({ filter: true }); - wxApi.onUpdateNotification(() => this.update()); - } - - componentWillUnmount(): void { - console.log("history component unmounted"); - this.unmounted = true; - } - - update(): void { - chrome.runtime.sendMessage({ type: "get-history" }, (resp) => { - if (this.unmounted) { - return; - } - console.log("got history response"); - if (resp.error) { - this.gotError = true; - console.error("could not retrieve history", resp); - this.setState({}); - return; - } - this.gotError = false; - console.log("got history", resp.history); - this.myHistory = resp.history; - this.setState({}); - }); - } - - render(): JSX.Element { - console.log("rendering history"); - const history: HistoryEvent[] = this.myHistory; - if (this.gotError) { - return <span>i18n.str`Error: could not retrieve event history`</span>; - } - - if (!history) { - // We're not ready yet - return <span />; - } - - const listing: any[] = []; - const messages = history.reverse().filter((hEvent) => { - if (!this.state.filter) return true; - return this.hidenTypes.indexOf(hEvent.type) === -1; - }); - - for (const record of messages) { - const item = <HistoryComponent key={record.eventId} record={record} />; - listing.push(item); - } - - if (listing.length > 0) { - return ( - <div> - <div className="container">{listing}</div> - <div className="option"> - Filtered list{" "} - <input - type="checkbox" - checked={this.state.filter} - onChange={() => this.setState({ filter: !this.state.filter })} - /> - </div> - </div> - ); - } - return <p>{i18n.str`Your wallet has no events recorded.`}</p>; - } -} function reload(): void { try { @@ -884,7 +497,6 @@ function WalletPopup(): JSX.Element { <div style={{ margin: "1em" }}> <Router> <WalletBalanceView route="/balance" default /> - <WalletHistory route="/history" /> <WalletSettings route="/settings" /> <WalletDebug route="/debug" /> </Router> diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts index d5a272160..793f4b5d3 100644 --- a/src/webex/wxBackend.ts +++ b/src/webex/wxBackend.ts @@ -117,10 +117,6 @@ async function handleMessage( } return needsWallet().updateExchangeFromUrl(detail.baseUrl); } - case "get-history": { - // TODO: limit history length - return needsWallet().getHistory(); - } case "get-exchanges": { return needsWallet().getExchangeRecords(); } |