gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-merchant] branch master updated: implement re-pointi


From: gnunet
Subject: [GNUnet-SVN] [taler-merchant] branch master updated: implement re-pointing to an already paid order
Date: Sun, 25 Aug 2019 23:58:26 +0200

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

dold pushed a commit to branch master
in repository merchant.

The following commit(s) were added to refs/heads/master by this push:
     new deac442  implement re-pointing to an already paid order
deac442 is described below

commit deac44203154413eb11af52aa5fab6743a9f5724
Author: Florian Dold <address@hidden>
AuthorDate: Sun Aug 25 23:57:39 2019 +0200

    implement re-pointing to an already paid order
    
    This is mostly useful if a resource should be displayed on
    one device, but the payment happens on another device.
---
 src/backend/taler-merchant-httpd_check-payment.c |  56 +++++++++---
 src/backend/taler-merchant-httpd_pay.c           |  45 +++++++++-
 src/backenddb/plugin_merchantdb_postgres.c       | 108 +++++++++++++++++++++++
 src/include/taler_merchantdb_plugin.h            |  37 ++++++++
 4 files changed, 233 insertions(+), 13 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_check-payment.c 
b/src/backend/taler-merchant-httpd_check-payment.c
index 2e6cea9..9ca445b 100644
--- a/src/backend/taler-merchant-httpd_check-payment.c
+++ b/src/backend/taler-merchant-httpd_check-payment.c
@@ -73,6 +73,7 @@ process_refunds_cb (void *cls,
  * @param session_id session of the client
  * @param resource_url where the resource will be (?), can be NULL!
  * @param h_contract_terms_str hash of the contract terms, stringified
+ * @param mi merchant instance
  * @return #MHD_YES on success
  */
 static int
@@ -80,26 +81,55 @@ send_pay_request (struct MHD_Connection *connection,
                   const char *final_contract_url,
                   const char *session_id,
                   const char *resource_url,
-                  const char *h_contract_terms_str)
+                  const char *h_contract_terms_str,
+                  const struct MerchantInstance *mi)
 {
   int ret;
-  char *url = TALER_url_absolute_mhd (connection,
-                                      "public/trigger-pay",
-                                      "contract_url", final_contract_url,
-                                      "session_id", session_id,
-                                      "resource_url", resource_url,
-                                      "h_contract_terms", h_contract_terms_str,
-                                      NULL);
+  int qs;
+  char *url;
+  char *already_paid_order_id = NULL;
+
+  if ( (NULL != session_id) && (NULL != resource_url) )
+  {
+    qs = db->find_session_info (db->cls,
+                                &already_paid_order_id,
+                                session_id,
+                                resource_url,
+                                &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 TMH_RESPONSE_reply_internal_error (connection,
+                                                
TALER_EC_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR,
+                                                "db error fetching pay session 
info");
+    }
+  }
+
+  url = TALER_url_absolute_mhd (connection,
+                                "public/trigger-pay",
+                                "contract_url", final_contract_url,
+                                "session_id", session_id,
+                                "resource_url", resource_url,
+                                "h_contract_terms", h_contract_terms_str,
+                                NULL);
   GNUNET_assert (NULL != url);
   ret = TMH_RESPONSE_reply_json_pack (connection,
                                       MHD_HTTP_OK,
-                                      "{s:s, s:s, s:b}",
+                                      "{s:s, s:s, s:b, s:s?}",
                                       "payment_redirect_url",
                                       url,
                                       "contract_url",
                                       final_contract_url,
                                       "paid",
-                                      0);
+                                      0,
+                                      "already_paid_order_id",
+                                      already_paid_order_id
+                                      );
+  GNUNET_free_non_null (already_paid_order_id);
   GNUNET_free (url);
   return ret;
 }
@@ -169,7 +199,8 @@ check_order_and_request_payment (struct MHD_Connection 
*connection,
                           final_contract_url,
                           session_id,
                           resource_url,
-                          h_contract_terms_str);
+                          h_contract_terms_str,
+                          mi);
   GNUNET_free_non_null (h_contract_terms_str);
   json_decref (contract_terms);
   return ret;
@@ -370,7 +401,8 @@ MH_handler_check_payment (struct TMH_RequestHandler *rh,
                               final_contract_url,
                               session_id,
                               resource_url,
-                              h_contract_terms_str);
+                              h_contract_terms_str,
+                              mi);
       GNUNET_free_non_null (h_contract_terms_str);
       GNUNET_free (final_contract_url);
       json_decref (contract_terms);
diff --git a/src/backend/taler-merchant-httpd_pay.c 
b/src/backend/taler-merchant-httpd_pay.c
index bf15106..bf9b544 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -371,6 +371,12 @@ struct PayContext
    * Transaction ID given in @e root.
    */
   char *order_id;
+
+  /**
+   * Fulfillment URL from @e contract_terms.
+   */
+  char *fulfillment_url;
+
 };
 
 
@@ -610,6 +616,7 @@ pay_context_cleanup (struct TM_HandlerContext *hc)
   }
   GNUNET_free_non_null (pc->order_id);
   GNUNET_free_non_null (pc->session_id);
+  GNUNET_free_non_null (pc->fulfillment_url);
   GNUNET_CONTAINER_DLL_remove (pc_head,
                                pc_tail,
                                pc);
@@ -1504,6 +1511,7 @@ parse_pay (struct MHD_Connection *connection,
               pc->mi->id);
 
   {
+    const char *fulfillment_url;
     struct GNUNET_JSON_Specification espec[] = {
       GNUNET_JSON_spec_absolute_time ("refund_deadline",
                                       &pc->refund_deadline),
@@ -1515,6 +1523,8 @@ parse_pay (struct MHD_Connection *connection,
                               &pc->max_fee),
       TALER_JSON_spec_amount ("amount",
                               &pc->amount),
+      GNUNET_JSON_spec_string ("fulfillment_url",
+                               &fulfillment_url),
       GNUNET_JSON_spec_fixed_auto ("H_wire",
                                    &pc->h_wire),
       GNUNET_JSON_spec_end()
@@ -1530,6 +1540,8 @@ parse_pay (struct MHD_Connection *connection,
       return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
     }
 
+    pc->fulfillment_url = GNUNET_strdup (fulfillment_url);
+
     /* Use the value from config as default.  */
     used_wire_transfer_delay = wire_transfer_delay;
 
@@ -2021,11 +2033,40 @@ begin_transaction (struct PayContext *pc)
                                ec);
       return;
     }
-    /* Payment succeeded, commit! */
+    /* Payment succeeded, save in database */
     qs = db->mark_proposal_paid (db->cls,
                                  &pc->h_contract_terms,
                                  &pc->mi->pubkey,
                                  pc->session_id);
+
+    if (qs < 0)
+    {
+      db->rollback (db->cls);
+      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+      {
+        begin_transaction (pc);
+        return;
+      }
+      resume_pay_with_error
+        (pc,
+         MHD_HTTP_INTERNAL_SERVER_ERROR,
+         TALER_EC_PAY_DB_STORE_PAYMENTS_ERROR,
+         "Merchant database error: could not "
+         "mark proposal as 'paid'");
+      return;
+    }
+
+    if ( (NULL != pc->session_id) && (NULL != pc->fulfillment_url) )
+    {
+      qs = db->insert_session_info (db->cls,
+                                    pc->session_id,
+                                    pc->fulfillment_url,
+                                    pc->order_id,
+                                    &pc->mi->pubkey);
+    }
+
+    /* Now commit! */
+
     if (0 <= qs)
       qs = db->commit (db->cls);
     else
@@ -2045,6 +2086,8 @@ begin_transaction (struct PayContext *pc)
          "mark proposal as 'paid'");
       return;
     }
+
+
     resume_pay_with_response (pc,
                               MHD_HTTP_OK,
                               sign_success_response (pc));
diff --git a/src/backenddb/plugin_merchantdb_postgres.c 
b/src/backenddb/plugin_merchantdb_postgres.c
index 0d0f337..1b4828e 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -114,6 +114,7 @@ postgres_drop_tables (void *cls)
     GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS 
merchant_tip_reserve_credits CASCADE;"),
     GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS merchant_tip_reserves 
CASCADE;"),
     GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS merchant_orders 
CASCADE;"),
+    GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS merchant_session_info 
CASCADE;"),
     GNUNET_PQ_EXECUTE_STATEMENT_END
   };
 
@@ -257,6 +258,16 @@ postgres_initialize (void *cls)
                             ",amount_frac INT4 NOT NULL"
                             ",PRIMARY KEY (pickup_id)"
                             ");"),
+    /* sessions and their order_id/resource_url mapping */
+    GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_session_info 
("
+                            " session_id VARCHAR NOT NULL"
+                            ",resource_url VARCHAR NOT NULL"
+                            ",order_id VARCHAR NOT NULL"
+                            ",merchant_pub BYTEA NOT NULL CHECK 
(LENGTH(merchant_pub)=32)"
+                            ",timestamp INT8 NOT NULL"
+                            ",PRIMARY KEY (session_id, resource_url, 
merchant_pub)"
+                            ",UNIQUE (session_id, resource_url, order_id, 
merchant_pub)"
+                            ");"),
     GNUNET_PQ_EXECUTE_STATEMENT_END
   };
   struct GNUNET_PQ_PreparedStatement ps[] = {
@@ -326,6 +337,16 @@ postgres_initialize (void *cls)
                             " VALUES "
                             "($1, $2, $3, $4)",
                             4),
+    GNUNET_PQ_make_prepare ("insert_session_info",
+                            "INSERT INTO merchant_session_info"
+                            "(session_id"
+                            ",resource_url"
+                            ",order_id"
+                            ",merchant_pub"
+                            ",timestamp)"
+                            " VALUES "
+                            "($1, $2, $3, $4, $5)",
+                            4),
     GNUNET_PQ_make_prepare ("mark_proposal_paid",
                             "UPDATE merchant_contract_terms SET"
                             " paid=TRUE, last_session_id=$3"
@@ -413,6 +434,15 @@ postgres_initialize (void *cls)
                             " order_id=$1"
                             " AND merchant_pub=$2",
                             2),
+    GNUNET_PQ_make_prepare ("find_session_info",
+                            "SELECT"
+                            " order_id"
+                            " FROM merchant_session_info"
+                            " WHERE"
+                            " resource_url=$1"
+                            " AND session_id=$2"
+                            " AND merchant_pub=$3",
+                            2),
     GNUNET_PQ_make_prepare ("find_contract_terms_by_date",
                             "SELECT"
                             " contract_terms"
@@ -1111,6 +1141,82 @@ postgres_mark_proposal_paid (void *cls,
 
 
 /**
+ * Store the order ID that was used to pay for a resource within a session.
+ *
+ * @param cls closure
+ * @param session_id session id
+ * @param resource_url URL that canonically identifies the resource
+ *        being paid for
+ * @param order_id the order ID that was used when paying for the resource URL
+ * @param merchant_pub public key of the merchant, identifying the instance
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+postgres_insert_session_info (void *cls,
+                              const char *session_id,
+                              const char *resource_url,
+                              const char *order_id,
+                              const struct TALER_MerchantPublicKeyP 
*merchant_pub)
+{
+  struct PostgresClosure *pg = cls;
+
+  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (session_id),
+    GNUNET_PQ_query_param_auto_from_type (resource_url),
+    GNUNET_PQ_query_param_auto_from_type (order_id),
+    GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+    GNUNET_PQ_query_param_absolute_time (&now),
+    GNUNET_PQ_query_param_end
+  };
+
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_session_info",
+                                             params);
+}
+
+/**
+ * Retrieve the order ID that was used to pay for a resource within a session.
+ *
+ * @param cls closure
+ * @param[out] order_id location to store the order ID that was used when
+ *             paying for the resource URL
+ * @param session_id session id
+ * @param resource_url URL that canonically identifies the resource
+ *        being paid for
+ * @param merchant_pub public key of the merchant, identifying the instance
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+postgres_find_session_info (void *cls,
+                            char **order_id,
+                            const char *session_id,
+                            const char *resource_url,
+                            const struct TALER_MerchantPublicKeyP 
*merchant_pub)
+{
+  struct PostgresClosure *pg = cls;
+
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (session_id),
+    GNUNET_PQ_query_param_auto_from_type (resource_url),
+    GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_string ("order_id",
+                                  order_id),
+    GNUNET_PQ_result_spec_end
+  }; 
+  // We don't clean up the result spec since we want
+  // to keep around the memory for order_id.
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   
"find_contract_terms_history",
+                                                   params,
+                                                   rs);
+}
+
+
+/**
  * Insert payment confirmation from the exchange into the database.
  *
  * @param cls closure
@@ -3559,6 +3665,8 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
   plugin->lookup_wire_fee = &postgres_lookup_wire_fee;
   plugin->increase_refund_for_contract_NT = 
&postgres_increase_refund_for_contract_NT;
   plugin->mark_proposal_paid = &postgres_mark_proposal_paid;
+  plugin->insert_session_info = &postgres_insert_session_info;
+  plugin->find_session_info = &postgres_find_session_info;
   plugin->enable_tip_reserve_TR = &postgres_enable_tip_reserve_TR;
   plugin->authorize_tip_TR = &postgres_authorize_tip_TR;
   plugin->lookup_tip_by_id = &postgres_lookup_tip_by_id;
diff --git a/src/include/taler_merchantdb_plugin.h 
b/src/include/taler_merchantdb_plugin.h
index f2dad94..7d4948e 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -250,6 +250,43 @@ struct TALER_MERCHANTDB_Plugin
                          const char *last_session_id);
 
   /**
+   * Store the order ID that was used to pay for a resource within a session.
+   *
+   * @param cls closure
+   * @param session_id session id
+   * @param resource_url URL that canonically identifies the resource
+   *        being paid for
+   * @param order_id the order ID that was used when paying for the resource 
URL
+   * @param merchant_pub public key of the merchant, identifying the instance
+   * @return transaction status
+   */
+  enum GNUNET_DB_QueryStatus
+  (*insert_session_info) (void *cls,
+                          const char *session_id,
+                          const char *resource_url,
+                          const char *order_id,
+                          const struct TALER_MerchantPublicKeyP *merchant_pub);
+
+  /**
+   * Retrieve the order ID that was used to pay for a resource within a 
session.
+   *
+   * @param cls closure
+   * @param[out] order_id location to store the order ID that was used when
+   *             paying for the resource URL
+   * @param session_id session id
+   * @param resource_url URL that canonically identifies the resource
+   *        being paid for
+   * @param merchant_pub public key of the merchant, identifying the instance
+   * @return transaction status
+   */
+  enum GNUNET_DB_QueryStatus
+  (*find_session_info) (void *cls,
+                        char **order_id,
+                        const char *session_id,
+                        const char *resource_url,
+                        const struct TALER_MerchantPublicKeyP *merchant_pub);
+
+  /**
    * Retrieve proposal data given its order ID.
    *
    * @param cls closure

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

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