From d5a57b88a7ccbfdfe49378410417d170eff2f14f Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 1 May 2020 16:12:51 +0200 Subject: DB API for /abort --- .../taler-merchant-httpd_post-orders-ID-abort.c | 259 ++++++++++----------- 1 file changed, 117 insertions(+), 142 deletions(-) (limited to 'src/backend/taler-merchant-httpd_post-orders-ID-abort.c') diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-abort.c b/src/backend/taler-merchant-httpd_post-orders-ID-abort.c index 27a83812..e6e8e406 100644 --- a/src/backend/taler-merchant-httpd_post-orders-ID-abort.c +++ b/src/backend/taler-merchant-httpd_post-orders-ID-abort.c @@ -704,36 +704,66 @@ begin_transaction (struct AbortContext *ac) return; } - /* check payment was indeed incomplete */ - qs = TMH_db->lookup_paid_order (TMH_db->cls, - ac->hc->instance->settings.id, - &ac->h_contract_terms, - NULL); - if (0 < qs) + /* check payment was indeed incomplete + (now that we are in the transaction scope!) */ { - /* Payment is complete, refuse to abort. */ - TMH_db->rollback (TMH_db->cls); - resume_abort_with_error (ac, - MHD_HTTP_FORBIDDEN, - TALER_EC_ABORT_ABORT_REFUND_REFUSED_ABORTMENT_COMPLETE, - "Payment was complete, refusing to abort"); - return; - } - if (0 > qs) - { - TMH_db->rollback (TMH_db->cls); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + struct GNUNET_HashCode h_contract_terms; + bool paid; + + qs = TMH_db->lookup_order_status (TMH_db->cls, + ac->hc->instance->settings.id, + ac->hc->infix, + &h_contract_terms, + &paid); + switch (qs) { - begin_transaction (ac); + case GNUNET_DB_STATUS_SOFT_ERROR: + case GNUNET_DB_STATUS_HARD_ERROR: + /* Always report on hard error to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); + TMH_db->rollback (TMH_db->cls); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + { + begin_transaction (ac); + return; + } + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); + resume_abort_with_error (ac, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_ABORT_DB_FETCH_TRANSACTION_ERROR, + "Merchant database error"); + return; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + TMH_db->rollback (TMH_db->cls); + resume_abort_with_error (ac, + MHD_HTTP_NOT_FOUND, + TALER_EC_ABORT_CONTRACT_NOT_FOUND, + "Could not find contract"); + return; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + if (paid) + { + /* Payment is complete, refuse to abort. */ + TMH_db->rollback (TMH_db->cls); + resume_abort_with_error (ac, + MHD_HTTP_FORBIDDEN, + TALER_EC_ABORT_REFUND_REFUSED_PAYMENT_COMPLETE, + "Payment was complete, refusing to abort"); + return; + } + } + if (0 != + GNUNET_memcmp (&ac->h_contract_terms, + &h_contract_terms)) + { + GNUNET_break_op (0); + resume_abort_with_error (ac, + MHD_HTTP_BAD_REQUEST, + TALER_EC_ABORT_CONTRACT_HASH_MISSMATCH, + "Provided hash does not match order on file"); return; } - /* Always report on hard error as well to enable diagnostics */ - GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); - resume_abort_with_error (ac, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_ABORT_DB_STORE_ABORT_ERROR, - "Merchant database error"); - return; } /* Mark all deposits we have in our database for the order as refunded. */ @@ -802,132 +832,77 @@ parse_abort (struct MHD_Connection *connection, struct TMH_HandlerContext *hc, struct AbortContext *ac) { + json_t *coins; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_json ("coins", + &coins), + GNUNET_JSON_spec_fixed_auto ("h_contract", + &ac->h_contract_terms), + + GNUNET_JSON_spec_end () + }; + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (connection, + hc->request_body, + spec); + if (GNUNET_YES != res) + { + GNUNET_break_op (0); + return res; + } + ac->coins_cnt = json_array_size (coins); + if (0 == ac->coins_cnt) { - json_t *coins; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_json ("coins", - &coins), - GNUNET_JSON_spec_fixed_auto ("h_contract", - &ac->h_contract_terms), - - GNUNET_JSON_spec_end () - }; - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (connection, - hc->request_body, - spec); - if (GNUNET_YES != res) - { - GNUNET_break_op (0); - return res; - } - ac->coins_cnt = json_array_size (coins); - if (0 == ac->coins_cnt) - { - GNUNET_JSON_parse_free (spec); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_ABORT_COINS_ARRAY_EMPTY, - "coins"); - } - /* note: 1 coin = 1 deposit confirmation expected */ - ac->pending = ac->coins_cnt; - ac->rd = GNUNET_new_array (ac->coins_cnt, - struct RefundDetails); - /* This loop populates the array 'rd' in 'ac' */ - { - unsigned int coins_index; - json_t *coin; - json_array_foreach (coins, coins_index, coin) - { - struct RefundDetails *rd = &ac->rd[coins_index]; - const char *exchange_url; - struct GNUNET_JSON_Specification ispec[] = { - TALER_JSON_spec_amount ("contribution", - &rd->amount_with_fee), - TALER_JSON_spec_amount ("refund_fee", - &rd->refund_fee), - GNUNET_JSON_spec_string ("exchange_url", - &exchange_url), - GNUNET_JSON_spec_fixed_auto ("coin_pub", - &rd->coin_pub), - GNUNET_JSON_spec_end () - }; - - res = TALER_MHD_parse_json_data (connection, - coin, - ispec); - if (GNUNET_YES != res) - { - GNUNET_JSON_parse_free (spec); - GNUNET_break_op (0); - return res; - } - rd->exchange_url = GNUNET_strdup (exchange_url); - rd->index = coins_index; - rd->ac = ac; - } - } GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_ABORT_COINS_ARRAY_EMPTY, + "coins"); } - - /* Check request against contract on file */ + /* note: 1 coin = 1 deposit confirmation expected */ + ac->pending = ac->coins_cnt; + ac->rd = GNUNET_new_array (ac->coins_cnt, + struct RefundDetails); + /* This loop populates the array 'rd' in 'ac' */ { - enum GNUNET_DB_QueryStatus qs; - struct GNUNET_HashCode h_contract_terms; - - qs = TMH_db->lookup_contract_terms_hash (TMH_db->cls, - hc->instance->settings.id, - hc->infix, - &h_contract_terms); - if (0 > qs) - { - /* single, read-only SQL statements should never cause - serialization problems */ - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); - /* Always report on hard error to enable diagnostics */ - GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); - return (MHD_YES == - TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_ABORT_DB_FETCH_ABORT_ERROR, - "Failed to obtain contract terms from DB")) - ? GNUNET_NO - : GNUNET_SYSERR; - } - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) - { - return (MHD_YES == - TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_ABORT_PROPOSAL_NOT_FOUND, - "Order not found")) - ? GNUNET_NO - : GNUNET_SYSERR; - } - - /* check client provided the right hash and is thus authorized to request aborting */ + unsigned int coins_index; + json_t *coin; + json_array_foreach (coins, coins_index, coin) { - if (0 != - GNUNET_memcmp (&ac->h_contract_terms, - &h_contract_terms)) + struct RefundDetails *rd = &ac->rd[coins_index]; + const char *exchange_url; + struct GNUNET_JSON_Specification ispec[] = { + TALER_JSON_spec_amount ("contribution", + &rd->amount_with_fee), + TALER_JSON_spec_amount ("refund_fee", + &rd->refund_fee), + GNUNET_JSON_spec_string ("exchange_url", + &exchange_url), + GNUNET_JSON_spec_fixed_auto ("coin_pub", + &rd->coin_pub), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_data (connection, + coin, + ispec); + if (GNUNET_YES != res) { + GNUNET_JSON_parse_free (spec); GNUNET_break_op (0); - return (MHD_YES == - TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_ABORT_CONTRACT_HASH_MISSMATCH, - "Provided hash does not match order on file")) - ? GNUNET_NO - : GNUNET_SYSERR; + return res; } + rd->exchange_url = GNUNET_strdup (exchange_url); + rd->index = coins_index; + rd->ac = ac; } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Handling /abort for order `%s' with contract hash `%s'\n", - ac->hc->infix, - GNUNET_h2s (&ac->h_contract_terms)); } + GNUNET_JSON_parse_free (spec); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Handling /abort for order `%s' with contract hash `%s'\n", + ac->hc->infix, + GNUNET_h2s (&ac->h_contract_terms)); return GNUNET_OK; } -- cgit v1.2.3