gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant] 172/277: first high-level hack job at GET /orders/ID --


From: gnunet
Subject: [taler-merchant] 172/277: first high-level hack job at GET /orders/ID -- certainly FTBFS still
Date: Sun, 05 Jul 2020 20:51:25 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository merchant.

commit 5e5fa7449c0343d644505d486cda2a2b10ed0b51
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Wed Jun 3 19:15:54 2020 +0200

    first high-level hack job at GET /orders/ID -- certainly FTBFS still
---
 .../taler-merchant-httpd_private-get-orders-ID.c   | 691 ++++++++-------------
 .../taler-merchant-httpd_private-get-orders-ID.h   |  29 +-
 2 files changed, 272 insertions(+), 448 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_private-get-orders-ID.c 
b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
index bb5384d..e6d1825 100644
--- a/src/backend/taler-merchant-httpd_private-get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  (C) 2017, 2019 Taler Systems SA
+  (C) 2017, 2019, 2020 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -14,37 +14,22 @@
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
 /**
- * @file backend/taler-merchant-httpd_check-payment.c
- * @brief implementation of /check-payment handler
+ * @file backend/taler-merchant-httpd_private-get-orders-ID.c
+ * @brief implementation of GET /private/orders/ID handler
  * @author Florian Dold
  * @author Christian Grothoff
  */
 #include "platform.h"
-#include <string.h>
-#include <microhttpd.h>
-#include <jansson.h>
+#include "taler-merchant-httpd_private-get-orders-ID.h"
 #include <taler/taler_json_lib.h>
-#include <taler/taler_signatures.h>
-#include "taler-merchant-httpd.h"
 #include "taler-merchant-httpd_mhd.h"
-#include "taler-merchant-httpd_exchanges.h"
-#include "taler-merchant-httpd_check-payment.h"
-
-/**
- * Maximum number of retries for database operations.
- */
-#define MAX_RETRIES 5
 
 
 /**
  * Data structure we keep for a check payment request.
  */
-struct CheckPaymentRequestContext
+struct GetOrderRequestContext
 {
-  /**
-   * Must be first for #handle_mhd_completion_callback.
-   */
-  struct TM_HandlerContext hc;
 
   /**
    * Entry in the #resume_timeout_heap for this check payment, if we are
@@ -55,22 +40,7 @@ struct CheckPaymentRequestContext
   /**
    * Which merchant instance is this for?
    */
-  struct MerchantInstance *mi;
-
-  /**
-   * URL where the final contract can be found for this payment.
-   */
-  char *final_contract_url;
-
-  /**
-   * order ID for the payment
-   */
-  const char *order_id;
-
-  /**
-   * Where to get the contract
-   */
-  const char *contract_url;
+  struct TMH_HandlerContext *hc;
 
   /**
    * session of the client
@@ -78,8 +48,8 @@ struct CheckPaymentRequestContext
   const char *session_id;
 
   /**
-   * fulfillment URL of the contract (valid as long as
-   * @e contract_terms is valid).
+   * Fulfillment URL extracted from the contract. For repurchase detection.
+   * Only valid as long as @e contract_terms is valid!
    */
   const char *fulfillment_url;
 
@@ -90,47 +60,44 @@ struct CheckPaymentRequestContext
   json_t *contract_terms;
 
   /**
-   * Hash of @e contract_terms, set only once @e contract_terms
-   * is available.
+   * Serial ID of the order.
    */
-  struct GNUNET_HashCode h_contract_terms;
+  uint64_t order_serial;
 
   /**
    * Total refunds granted for this payment. Only initialized
-   * if @e refunded is set to #GNUNET_YES.
+   * if @e refunded is set to true.
    */
   struct TALER_Amount refund_amount;
 
   /**
-   * Set to #GNUNET_YES if this payment has been refunded and
+   * Set to true if this payment has been refunded and
    * @e refund_amount is initialized.
    */
-  int refunded;
+  bool refunded;
 
   /**
-   * Initially #GNUNET_SYSERR. If we queued a response, set to the
-   * result code (i.e. #MHD_YES or #MHD_NO).
+   * Did the client request us to fetch the wire transfer status?
+   * If false, we may still return it if it is available.
    */
-  int ret;
+  bool transfer_status_requested;
 
 };
 
 
 /**
- * Clean up the session state for a check payment request.
+ * Clean up the session state for a GET /private/order/ID request.
  *
- * @param hc must be a `struct CheckPaymentRequestContext *`
+ * @param cls closure, must be a `struct GetOrderRequestContext *`
  */
 static void
-cprc_cleanup (struct TM_HandlerContext *hc)
+gorc_cleanup (void *cls)
 {
-  struct CheckPaymentRequestContext *cprc = (struct
-                                             CheckPaymentRequestContext *) hc;
+  struct GetOrderRequestContext *gorc = cls;
 
-  if (NULL != cprc->contract_terms)
-    json_decref (cprc->contract_terms);
-  GNUNET_free_non_null (cprc->final_contract_url);
-  GNUNET_free (cprc);
+  if (NULL != gorc->contract_terms)
+    json_decref (gorc->contract_terms);
+  GNUNET_free (gorc);
 }
 
 
@@ -155,437 +122,301 @@ process_refunds_cb (void *cls,
                     const struct TALER_Amount *refund_amount,
                     const struct TALER_Amount *refund_fee)
 {
-  struct CheckPaymentRequestContext *cprc = cls;
+  struct GetOrderRequestContext *gorc = cls;
 
-  if (cprc->refunded)
+  // FIXME: probably should do more here and compute
+  // an array with the details on the refunds with the reasons;
+  // FIXME: spec does NOT mandate that yet!
+  if (gorc->refunded)
   {
     GNUNET_assert (0 <=
-                   TALER_amount_add (&cprc->refund_amount,
-                                     &cprc->refund_amount,
+                   TALER_amount_add (&gorc->refund_amount,
+                                     &gorc->refund_amount,
                                      refund_amount));
     return;
   }
-  cprc->refund_amount = *refund_amount;
-  cprc->refunded = GNUNET_YES;
+  gorc->refund_amount = *refund_amount;
+  gorc->refunded = true;
 }
 
 
 /**
- * The client did not yet pay, send it the payment request.
+ * Manages a GET /private/orders/ID call, checking the status of a payment and
+ * refunds and, if necessary, constructing the URL for a payment redirect URL.
  *
- * @param cprc check pay request context
- * @return #MHD_YES on success
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] hc context with further information about the request
+ * @return MHD result code
  */
-static int
-send_pay_request (struct CheckPaymentRequestContext *cprc)
+MHD_RESULT
+TMH_private_get_orders_ID (const struct TMH_RequestHandler *rh,
+                           struct MHD_Connection *connection,
+                           struct TMH_HandlerContext *hc)
 {
-  int ret;
-  char *already_paid_order_id = NULL;
-  char *taler_pay_uri;
-  struct GNUNET_TIME_Relative remaining;
+  struct GetOrderRequestContext *gorc = hc->ctx;
+  enum GNUNET_DB_QueryStatus qs;
 
-  remaining = GNUNET_TIME_absolute_get_remaining (cprc->sc.long_poll_timeout);
-  if (0 != remaining.rel_value_us)
+  if (NULL == gorc)
   {
-    /* long polling: do not queue a response, suspend connection instead */
-    TMH_compute_pay_key (cprc->order_id,
-                         &cprc->mi->pubkey,
-                         &cprc->sc.key);
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Suspending /check-payment on key %s\n",
-                GNUNET_h2s (&cprc->sc.key));
-    TMH_long_poll_suspend (&cprc->sc,
-                           NULL);
-    return MHD_YES;
-  }
+    /* First time here, parse request and check order is known */
+    gorc = GNUNET_new (struct GetOrderRequestContext);
+    hc->cc = &gorc_cleanup;
+    hc->ctx = gorc;
+    gorc->sc.con = connection;
+    gorc->hc = hc;
+    GNUNET_assert (NULL != hc->infix);
+    gorc->session_id = MHD_lookup_connection_value (connection,
+                                                    MHD_GET_ARGUMENT_KIND,
+                                                    "session_id");
+    {
+      const char *long_poll_timeout_s;
+
+      long_poll_timeout_s = MHD_lookup_connection_value (connection,
+                                                         MHD_GET_ARGUMENT_KIND,
+                                                         "timeout_ms");
+      if (NULL != long_poll_timeout_s)
+      {
+        unsigned long long timeout;
+
+        if (1 != sscanf (long_poll_timeout_s,
+                         "%llu",
+                         &timeout))
+        {
+          GNUNET_break_op (0);
+          return TALER_MHD_reply_with_error (connection,
+                                             MHD_HTTP_BAD_REQUEST,
+                                             TALER_EC_PARAMETER_MALFORMED,
+                                             "timeout must be non-negative 
number");
+        }
+        gorc->sc.long_poll_timeout
+          = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (
+                                                GNUNET_TIME_UNIT_MILLISECONDS,
+                                                timeout));
+      }
+      else
+      {
+        gorc->sc.long_poll_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
+      }
+    }
 
-  /* Check if resource_id has been paid for in the same session
-   * with another order_id.
-   */
-  if ( (NULL != cprc->session_id) &&
-       (NULL != cprc->fulfillment_url) )
-  {
-    enum GNUNET_DB_QueryStatus qs;
-
-    qs = db->find_session_info (db->cls,
-                                &already_paid_order_id,
-                                cprc->session_id,
-                                cprc->fulfillment_url,
-                                &cprc->mi->pubkey);
-    if (qs < 0)
+    {
+      const char *transfer_s;
+
+      transfer_s = MHD_lookup_connection_value (connection,
+                                                MHD_GET_ARGUMENT_KIND,
+                                                "transfer");
+      if ( (NULL != transfer_s) &&
+           (0 == strcasecmp (transfer_s,
+                             "yes")) )
+        gorc->transfer_status_requested = true;
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Starting GET /private/orders/%s processing with timeout %s\n",
+                hc->infix,
+                GNUNET_STRINGS_absolute_time_to_string (
+                  gorc->sc.long_poll_timeout));
+
+    db->preflight (db->cls);
+    qs = db->lookup_contract_terms (db->cls,
+                                    hc->instance.settings->id,
+                                    hc->infix,
+                                    &gorc->contract_terms,
+                                    &gorc->order_serial);
+    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 as well to enable diagnostics */
       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-      return TALER_MHD_reply_with_error (cprc->sc.con,
+      return TALER_MHD_reply_with_error (connection,
                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                         
TALER_EC_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR,
-                                         "db error fetching pay session info");
+                                         
TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
+                                         "db error fetching contract terms");
     }
-  }
-  taler_pay_uri = TMH_make_taler_pay_uri (cprc->sc.con,
-                                          cprc->order_id,
-                                          cprc->session_id,
-                                          cprc->mi->id);
-  ret = TALER_MHD_reply_json_pack (cprc->sc.con,
-                                   MHD_HTTP_OK,
-                                   "{s:s, s:s, s:b, s:s?}",
-                                   "taler_pay_uri", taler_pay_uri,
-                                   "contract_url", cprc->final_contract_url,
-                                   "paid", 0,
-                                   "already_paid_order_id",
-                                   already_paid_order_id);
-  GNUNET_free (taler_pay_uri);
-  GNUNET_free_non_null (already_paid_order_id);
-  return ret;
-}
+    // FIXME: handle qs!
+    // => mainly: if 0 return 404!
 
 
-/**
- * Parse the "contract_terms" in @a cprc and set the
- * "fulfillment_url" and the "h_contract_terms" in @a cprc
- * accordingly.
- *
- * On errors, the response is being queued and the status
- * code set in @cprc "ret".
- *
- * @param cprc[in,out] context to process
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
- */
-static int
-parse_contract_terms (struct CheckPaymentRequestContext *cprc)
-{
-  struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_string ("fulfillment_url",
-                             &cprc->fulfillment_url),
-    GNUNET_JSON_spec_end ()
-  };
-
-  if (GNUNET_OK !=
-      GNUNET_JSON_parse (cprc->contract_terms,
-                         spec,
-                         NULL, NULL))
-  {
-    GNUNET_break (0);
-    cprc->ret
-      = TALER_MHD_reply_with_error (cprc->sc.con,
-                                    MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                    
TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
-                                    "Merchant database error (contract terms 
corrupted)");
-    return GNUNET_SYSERR;
-  }
-  if (GNUNET_OK !=
-      TALER_JSON_hash (cprc->contract_terms,
-                       &cprc->h_contract_terms))
-  {
-    GNUNET_break (0);
-    cprc->ret
-      = TALER_MHD_reply_with_error (cprc->sc.con,
-                                    MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                    
TALER_EC_CHECK_PAYMENT_FAILED_COMPUTE_PROPOSAL_HASH,
-                                    "Failed to hash proposal");
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
-/**
- * Check that we are aware of @a order_id and if so request the payment,
- * otherwise generate an error response.
- *
- * @param cprc session state
- * @return status code to return to MHD for @a connection
- */
-static int
-check_order_and_request_payment (struct CheckPaymentRequestContext *cprc)
-{
-  enum GNUNET_DB_QueryStatus qs;
-
-  if (NULL != cprc->contract_terms)
-  {
-    /* This should never happen. */
-    GNUNET_break (0);
-    json_decref (cprc->contract_terms);
-    cprc->contract_terms = NULL;
-  }
-  qs = db->find_order (db->cls,
-                       &cprc->contract_terms,
-                       cprc->order_id,
-                       &cprc->mi->pubkey);
-  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 as well to enable diagnostics */
-    GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-    return TALER_MHD_reply_with_error (cprc->sc.con,
-                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                       
TALER_EC_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR,
-                                       "db error fetching order");
-  }
-  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
-  {
-    return TALER_MHD_reply_with_error (cprc->sc.con,
-                                       MHD_HTTP_NOT_FOUND,
-                                       TALER_EC_CHECK_PAYMENT_ORDER_ID_UNKNOWN,
-                                       "unknown order_id");
+    /* extract the fulfillment URL from the contract terms! */
+    {
+      struct GNUNET_JSON_Specification spec[] = {
+        GNUNET_JSON_spec_string ("fulfillment_url",
+                                 &gorc->fulfillment_url),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (gorc->contract_terms,
+                             spec,
+                             NULL, NULL))
+      {
+        GNUNET_break (0);
+        return TALER_MHD_reply_with_error (
+          connection,
+          MHD_HTTP_INTERNAL_SERVER_ERROR,
+          TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
+          "Merchant database error (contract terms corrupted)");
+      }
+    }
   }
 
-  if (GNUNET_OK !=
-      parse_contract_terms (cprc))
-    return cprc->ret;
-  /* Offer was not picked up yet, but we ensured that it exists */
-  return send_pay_request (cprc);
-}
-
+  GNUNET_assert (NULL != gorc->contract_terms);
 
-/**
- * Manages a /check-payment call, checking the status
- * of a payment and, if necessary, constructing the URL
- * for a payment redirect URL.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @param mi merchant backend instance, never NULL
- * @return MHD result code
- */
-MHD_RESULT
-MH_handler_check_payment (struct TMH_RequestHandler *rh,
-                          struct MHD_Connection *connection,
-                          void **connection_cls,
-                          const char *upload_data,
-                          size_t *upload_data_size,
-                          struct MerchantInstance *mi)
-{
-  struct CheckPaymentRequestContext *cprc = *connection_cls;
-  enum GNUNET_DB_QueryStatus qs;
-  MHD_RESULT ret;
-
-  if (NULL == cprc)
   {
-    const char *long_poll_timeout_s;
-
-    /* First time here, parse request and check order is known */
-    cprc = GNUNET_new (struct CheckPaymentRequestContext);
-    cprc->hc.cc = &cprc_cleanup;
-    cprc->ret = GNUNET_SYSERR;
-    cprc->sc.con = connection;
-    cprc->mi = mi;
-    *connection_cls = cprc;
-
-    cprc->order_id = MHD_lookup_connection_value (connection,
-                                                  MHD_GET_ARGUMENT_KIND,
-                                                  "order_id");
-    if (NULL == cprc->order_id)
+    bool paid;
+    bool wired;
+
+    db->preflight (db->cls);
+    qs = db->lookup_payment_status (db->cls,
+                                    gorc->order_serial,
+                                    gorc->session_id,
+                                    &paid,
+                                    &wired);
+    if (0 >= qs)
     {
-      /* order_id is required but missing */
-      GNUNET_break_op (0);
+      /* single, read-only SQL statements should never cause
+         serialization problems, and the entry should exist as per above */
+      GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
       return TALER_MHD_reply_with_error (connection,
-                                         MHD_HTTP_BAD_REQUEST,
-                                         TALER_EC_PARAMETER_MISSING,
-                                         "order_id required");
-    }
-    cprc->contract_url = MHD_lookup_connection_value (connection,
-                                                      MHD_GET_ARGUMENT_KIND,
-                                                      "contract_url");
-    if (NULL == cprc->contract_url)
-    {
-      cprc->final_contract_url = TALER_url_absolute_mhd (connection,
-                                                         "/public/proposal",
-                                                         "instance", mi->id,
-                                                         "order_id",
-                                                         cprc->order_id,
-                                                         NULL);
-      GNUNET_assert (NULL != cprc->final_contract_url);
-    }
-    else
-    {
-      cprc->final_contract_url = GNUNET_strdup (cprc->contract_url);
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         
TALER_EC_CHECK_PAYMENT_DB_FETCH_PAYMENT_STATUS,
+                                         "DB error fetching payment status");
     }
-    cprc->session_id = MHD_lookup_connection_value (connection,
-                                                    MHD_GET_ARGUMENT_KIND,
-                                                    "session_id");
-    long_poll_timeout_s = MHD_lookup_connection_value (connection,
-                                                       MHD_GET_ARGUMENT_KIND,
-                                                       "timeout");
-    if (NULL != long_poll_timeout_s)
+    if (! paid)
     {
-      unsigned int timeout;
-
-      if (1 != sscanf (long_poll_timeout_s,
-                       "%u",
-                       &timeout))
+      char *already_paid_order_id;
+
+      qs = db->lookup_repayment_status (db->cls,
+                                        hc->instance->settings.id,
+                                        hc->infix,
+                                        gorc->session_id,
+                                        gorc->fulfillment_url,
+                                        &already_paid_order_id);
+      if (0 > qs)
       {
-        GNUNET_break_op (0);
+        /* single, read-only SQL statements should never cause
+           serialization problems, and the entry should exist as per above */
+        GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
         return TALER_MHD_reply_with_error (connection,
-                                           MHD_HTTP_BAD_REQUEST,
-                                           TALER_EC_PARAMETER_MALFORMED,
-                                           "timeout must be non-negative 
number");
+                                           MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                           
TALER_EC_CHECK_PAYMENT_DB_FETCH_PAYMENT_STATUS,
+                                           "DB error fetching payment status");
+      }
+      if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+      {
+        /* User did pay for this order, but under a different session; ask 
wallet
+           to switch order ID */
+        char *taler_pay_uri;
+        MHD_RESULT ret;
+
+        taler_pay_uri = TMH_make_taler_pay_uri (connection,
+                                                hc->infix,
+                                                gorc->session_id,
+                                                hc->instance.settings->id);
+        ret = TALER_MHD_reply_json_pack (connection,
+                                         MHD_HTTP_OK,
+                                         "{s:s, s:b, s:s}",
+                                         "taler_pay_uri",
+                                         taler_pay_uri,
+                                         "paid",
+                                         false,
+                                         "already_paid_order_id",
+                                         already_paid_order_id);
+        GNUNET_free (taler_pay_uri);
+        GNUNET_free (already_paid_order_id);
+        return ret;
       }
-      cprc->sc.long_poll_timeout
-        = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (
-                                              GNUNET_TIME_UNIT_SECONDS,
-                                              timeout));
     }
-    else
+
+    if (paid &&
+        (! wired) &&
+        gorc->transfer_status_requested)
     {
-      cprc->sc.long_poll_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
+      // FIXME: suspend connection, go to exhange to ask for the
+      // wire transfer status, and resume once we have it!
+      // (make sure to set gorc->transfer_status_requested to FALSE
+      // while we are at it!)
+      return MHD_YES;
     }
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Starting /check-payment processing with timeout %s\n",
-                GNUNET_STRINGS_absolute_time_to_string (
-                  cprc->sc.long_poll_timeout));
-  }
-  if (NULL != cprc->contract_terms)
-  {
-    json_decref (cprc->contract_terms);
-    cprc->contract_terms = NULL;
-  }
-  db->preflight (db->cls);
-  qs = db->find_contract_terms (db->cls,
-                                &cprc->contract_terms,
-                                cprc->order_id,
-                                &mi->pubkey);
-  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 as well to enable diagnostics */
-    GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                       
TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
-                                       "db error fetching contract terms");
-  }
 
-  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
-  {
-    /* Check that we're at least aware of the order */
-    return check_order_and_request_payment (cprc);
-  }
-  GNUNET_assert (NULL != cprc->contract_terms);
-
-  if (GNUNET_OK !=
-      parse_contract_terms (cprc))
-    return cprc->ret;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Checkig payment status for order `%s' with contract %s\n",
-              cprc->order_id,
-              GNUNET_h2s (&cprc->h_contract_terms));
-  GNUNET_assert (NULL != cprc->contract_terms);
-
-  /* Check if the order has been paid for. */
-  if (NULL != cprc->session_id)
-  {
-    /* Check if paid within a session. */
-    char *already_paid_order_id = NULL;
-
-    qs = db->find_session_info (db->cls,
-                                &already_paid_order_id,
-                                cprc->session_id,
-                                cprc->fulfillment_url,
-                                &mi->pubkey);
-    if (qs < 0)
+    if ( (! paid) &&
+         (0 != gorc.sc.long_poll_timeout.abs_value_us) )
     {
-      /* single, read-only SQL statements should never cause
-         serialization problems */
-      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
-      /* Always report on hard error as well to enable diagnostics */
-      GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-      return TALER_MHD_reply_with_error (connection,
-                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                         
TALER_EC_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR,
-                                         "db error fetching pay session info");
+      // FIXME: suspend connection, wait for payment!
+      return MHD_YES;
     }
-    else if (0 == qs)
+
+    if (! paid)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "Order `%s' was not yet paid for session `%s'\n",
-                  cprc->order_id,
-                  cprc->session_id);
-      ret = send_pay_request (cprc);
-      GNUNET_free_non_null (already_paid_order_id);
+      /* User never paid for this order */
+      char *taler_pay_uri;
+      MHD_RESULT ret;
+
+      taler_pay_uri = TMH_make_taler_pay_uri (connection,
+                                              hc->infix,
+                                              gorc->session_id,
+                                              hc->instance.settings->id);
+      ret = TALER_MHD_reply_json_pack (connection,
+                                       MHD_HTTP_OK,
+                                       "{s:s, s:b}",
+                                       "taler_pay_uri",
+                                       taler_pay_uri,
+                                       "paid",
+                                       false);
+      GNUNET_free (taler_pay_uri);
       return ret;
     }
-    GNUNET_break (1 == qs);
-    GNUNET_break (0 == strcmp (cprc->order_id,
-                               already_paid_order_id));
-    GNUNET_free_non_null (already_paid_order_id);
-  }
-  else
-  {
-    /* Check if paid regardless of session. */
-    json_t *xcontract_terms = NULL;
 
-    qs = db->find_paid_contract_terms_from_hash (db->cls,
-                                                 &xcontract_terms,
-                                                 &cprc->h_contract_terms,
-                                                 &mi->pubkey);
+    /* Here we know the user DID pay, compute refunds... */
+
+    /* Accumulate refunds, if any. */
+    qs = db->select_refunds_by_order (db->cls,
+                                      gorc->order_serial,
+                                      &process_refunds_cb,
+                                      gorc);
     if (0 > qs)
     {
-      /* Always report on hard error as well to enable diagnostics */
-      GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+      GNUNET_break (0);
       return TALER_MHD_reply_with_error (connection,
                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
                                          
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
                                          "Merchant database error");
     }
-    if (0 == qs)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "Order `%s' (contract `%s') was not yet paid\n",
-                  cprc->order_id,
-                  GNUNET_h2s (&cprc->h_contract_terms));
-      return send_pay_request (cprc);
-    }
-    GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
-    GNUNET_assert (NULL != xcontract_terms);
-    json_decref (xcontract_terms);
-  }
+  } /* end of scope of 'paid/wired' */
 
-  /* Accumulate refunds, if any. */
-  for (unsigned int i = 0; i<MAX_RETRIES; i++)
+  /* Generate final reply, including wire details if we have them */
   {
-    qs = db->get_refunds_from_contract_terms_hash (db->cls,
-                                                   &mi->pubkey,
-                                                   &cprc->h_contract_terms,
-                                                   &process_refunds_cb,
-                                                   cprc);
-    if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
-      break;
-  }
-  if (0 > qs)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Database hard error on refunds_from_contract_terms_hash 
lookup: %s\n",
-                GNUNET_h2s (&cprc->h_contract_terms));
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                       TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
-                                       "Merchant database error");
-  }
-  if (cprc->refunded)
+    json_t *wire_details = NULL;
+
+    qs = db->select_wire_details_by_order (db->cls,
+                                           gorc->order_serial,
+                                           &process_wire_details,
+                                           &wire_details);
+    if (0 > qs)
+    {
+      GNUNET_break (0);
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
+                                         "Merchant database error");
+    }
     return TALER_MHD_reply_json_pack (connection,
                                       MHD_HTTP_OK,
-                                      "{s:O, s:b, s:b, s:o}",
-                                      "contract_terms", cprc->contract_terms,
-                                      "paid", 1,
-                                      "refunded", cprc->refunded,
+                                      "{s:O, s:b, s:b, s:o?, s:o?}",
+                                      "contract_terms",
+                                      gorc->contract_terms,
+                                      "paid",
+                                      true,
+                                      "refunded",
+                                      gorc->refunded,
                                       "refund_amount",
-                                      TALER_JSON_from_amount (
-                                        &cprc->refund_amount));
-  return TALER_MHD_reply_json_pack (connection,
-                                    MHD_HTTP_OK,
-                                    "{s:O, s:b, s:b }",
-                                    "contract_terms", cprc->contract_terms,
-                                    "paid", 1,
-                                    "refunded", 0);
+                                      (gorc->refunded)
+                                      ? TALER_JSON_from_amount (
+                                        &gorc->refund_amount)
+                                      : NULL,
+                                      "wire_details",
+                                      wire_details);
+  }
 }
diff --git a/src/backend/taler-merchant-httpd_private-get-orders-ID.h 
b/src/backend/taler-merchant-httpd_private-get-orders-ID.h
index e94645d..2b60310 100644
--- a/src/backend/taler-merchant-httpd_private-get-orders-ID.h
+++ b/src/backend/taler-merchant-httpd_private-get-orders-ID.h
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  (C) 2017 Taler Systems SA
+  (C) 2017, 2020 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -14,35 +14,28 @@
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
 /**
- * @file backend/taler-merchant-httpd_tip-query.h
- * @brief headers for /tip-query handler
+ * @file backend/taler-merchant-httpd_private-get-orders-ID.h
+ * @brief headers for GET /private/orders/ID handler
  * @author Christian Grothoff
  * @author Florian Dold
  */
-#ifndef TALER_MERCHANT_HTTPD_CHECK_PAYMENT_H
-#define TALER_MERCHANT_HTTPD_CHECK_PAYMENT_H
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_ORDERS_ID_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_GET_ORDERS_ID_H
 #include <microhttpd.h>
 #include "taler-merchant-httpd.h"
 
 /**
- * Manages a /check-payment call, checking the status
- * of a payment and, if necessary, constructing the URL
- * for a payment redirect URL.
+ * Manages a GET /private/orders/ID call, checking the status of a payment and
+ * refunds and, if necessary, constructing the URL for a payment redirect URL.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @param mi merchant backend instance, never NULL
+ * @param[in,out] hc context with further information about the request
  * @return MHD result code
  */
 MHD_RESULT
-MH_handler_check_payment (struct TMH_RequestHandler *rh,
-                          struct MHD_Connection *connection,
-                          void **connection_cls,
-                          const char *upload_data,
-                          size_t *upload_data_size,
-                          struct MerchantInstance *mi);
+TMH_private_get_orders_ID (const struct TMH_RequestHandler *rh,
+                           struct MHD_Connection *connection,
+                           struct TMH_HandlerContext *hc);
 
 #endif

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]