diff options
author | Florian Dold <florian.dold@gmail.com> | 2018-01-22 01:12:08 +0100 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2018-01-22 01:12:08 +0100 |
commit | ae177549a5818e2698253ef17a11b1effbd66fdb (patch) | |
tree | 7ac7765d2af595b1d22367740d88a397b6b9868a /src | |
parent | 1671d9a508b803af31762bcd9508e70eb40e7b48 (diff) |
implement flicker-free refunds
Diffstat (limited to 'src')
-rw-r--r-- | src/wallet.ts | 8 | ||||
-rw-r--r-- | src/webex/messages.ts | 4 | ||||
-rw-r--r-- | src/webex/pages/refund.tsx | 33 | ||||
-rw-r--r-- | src/webex/wxApi.ts | 7 | ||||
-rw-r--r-- | src/webex/wxBackend.ts | 22 |
5 files changed, 63 insertions, 11 deletions
diff --git a/src/wallet.ts b/src/wallet.ts index 9498fe820..01db8c612 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -2532,6 +2532,10 @@ export class Wallet { } } + /** + * Accept a refund, return the contract hash for the contract + * that was involved in the refund. + */ async acceptRefund(refundUrl: string): Promise<string> { console.log("processing refund"); let resp; @@ -2598,7 +2602,8 @@ export class Wallet { return refundPermissions[0].h_contract_terms; } - async submitRefunds(contractTermsHash: string): Promise<void> { + + private async submitRefunds(contractTermsHash: string): Promise<void> { const purchase = await this.q().get(Stores.purchases, contractTermsHash); if (!purchase) { console.error("not submitting refunds, contract terms not found:", contractTermsHash); @@ -2644,7 +2649,6 @@ export class Wallet { return c; }; - await this.q() .mutate(Stores.purchases, contractTermsHash, transformPurchase) .mutate(Stores.coins, perm.coin_pub, transformCoin) diff --git a/src/webex/messages.ts b/src/webex/messages.ts index e1bd6f12c..2219cdf1d 100644 --- a/src/webex/messages.ts +++ b/src/webex/messages.ts @@ -195,6 +195,10 @@ export interface MessageMap { request: { contractTermsHash: string, sessionId: string | undefined }; response: void; }; + "accept-refund": { + request: { refundUrl: string } + response: string; + }; } /** diff --git a/src/webex/pages/refund.tsx b/src/webex/pages/refund.tsx index 3e82f3667..8164eb664 100644 --- a/src/webex/pages/refund.tsx +++ b/src/webex/pages/refund.tsx @@ -35,10 +35,12 @@ import { AmountDisplay } from "../renderHtml"; import * as wxApi from "../wxApi"; interface RefundStatusViewProps { - contractTermsHash: string; + contractTermsHash?: string; + refundUrl?: string; } interface RefundStatusViewState { + contractTermsHash?: string; purchase?: dbTypes.PurchaseRecord; refundFees?: AmountJson; gotResult: boolean; @@ -102,13 +104,22 @@ class RefundStatusView extends React.Component<RefundStatusViewProps, RefundStat } render(): JSX.Element { + if (!this.props.contractTermsHash && !this.props.refundUrl) { + return ( + <div id="main"> + <span>Error: Neither contract terms hash nor refund url given.</span> + </div> + ); + } const purchase = this.state.purchase; if (!purchase) { + let message; if (this.state.gotResult) { - return <span>No purchase with contract terms hash {this.props.contractTermsHash} found</span>; + message = <span>No purchase with contract terms hash {this.props.contractTermsHash} found</span>; } else { - return <span>...</span>; + message = <span>...</span>; } + return <div id="main">{message}</div>; } const merchantName = purchase.contractTerms.merchant.name || "(unknown)"; const summary = purchase.contractTerms.summary || purchase.contractTerms.order_id; @@ -128,7 +139,16 @@ class RefundStatusView extends React.Component<RefundStatusViewProps, RefundStat } async update() { - const purchase = await wxApi.getPurchase(this.props.contractTermsHash); + let contractTermsHash = this.state.contractTermsHash; + if (!contractTermsHash) { + const refundUrl = this.props.refundUrl; + if (!refundUrl) { + console.error("neither contractTermsHash nor refundUrl is given"); + return; + } + contractTermsHash = await wxApi.acceptRefund(refundUrl); + } + const purchase = await wxApi.getPurchase(contractTermsHash); console.log("got purchase", purchase); const refundsDone = Object.keys(purchase.refundsDone).map((x) => purchase.refundsDone[x]); const refundFees = await wxApi.getFullRefundFees( {refundPermissions: refundsDone }); @@ -147,8 +167,9 @@ async function main() { return; } - const contractTermsHash = query.contractTermsHash || "(none)"; - ReactDOM.render(<RefundStatusView contractTermsHash={contractTermsHash} />, container); + const contractTermsHash = query.contractTermsHash; + const refundUrl = query.refundUrl; + ReactDOM.render(<RefundStatusView contractTermsHash={contractTermsHash} refundUrl={refundUrl} />, container); } document.addEventListener("DOMContentLoaded", () => main()); diff --git a/src/webex/wxApi.ts b/src/webex/wxApi.ts index 566f45265..8a7bf8250 100644 --- a/src/webex/wxApi.ts +++ b/src/webex/wxApi.ts @@ -363,3 +363,10 @@ export function talerPay(msg: any): Promise<void> { export function downloadProposal(url: string): Promise<number> { return callBackend("download-proposal", { url }); } + +/** + * Download a refund and accept it. + */ +export function acceptRefund(refundUrl: string): Promise<string> { + return callBackend("accept-refund", { refundUrl }); +} diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts index 26b8ff2cf..98b543d28 100644 --- a/src/webex/wxBackend.ts +++ b/src/webex/wxBackend.ts @@ -292,6 +292,8 @@ function handleMessage(sender: MessageSender, } case "get-full-refund-fees": return needsWallet().getFullRefundFees(detail.refundPermissions); + case "accept-refund": + return needsWallet().acceptRefund(detail.refundUrl); case "get-tip-status": { const tipToken = TipToken.checked(detail.tipToken); return needsWallet().getTipStatus(tipToken); @@ -430,8 +432,8 @@ async function talerPay(fields: any, url: string, tabId: number): Promise<string } if (fields.refund_url) { console.log("processing refund"); - const hc = await w.acceptRefund(fields.refund_url); - return chrome.extension.getURL(`/src/webex/pages/refund.html?contractTermsHash=${hc}`); + const uri = new URI(chrome.extension.getURL("/src/webex/pages/refund.html")); + return uri.query({ refundUrl: fields.refund_url }).href(); } if (fields.tip) { const uri = new URI(chrome.extension.getURL("/src/webex/pages/tip.html")); @@ -507,10 +509,24 @@ function handleHttpPayment(headerList: chrome.webRequest.HttpHeader[], url: stri return { redirectUrl: uri.href() }; } + // Synchronous fast path for refund + if (fields.refund_url) { + console.log("processing refund"); + const uri = new URI(chrome.extension.getURL("/src/webex/pages/refund.html")); + uri.query({ refundUrl: fields.refund_url }); + return { redirectUrl: uri.href }; + } + // We need to do some asynchronous operation, we can't directly redirect talerPay(fields, url, tabId).then((nextUrl) => { if (nextUrl) { - chrome.tabs.update(tabId, { url: nextUrl }); + // We use chrome.tabs.executeScript instead of chrome.tabs.update + // because the latter is buggy when it does not execute in the same + // (micro-?)task as the header callback. + chrome.tabs.executeScript({ + code: `document.location.href = decodeURIComponent("${encodeURI(nextUrl)}");`, + runAt: "document_start", + }); } }); |