gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] 10/277: implement POST /instances


From: gnunet
Subject: [taler-merchant] 10/277: implement POST /instances
Date: Sun, 05 Jul 2020 20:48:43 +0200

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

grothoff pushed a commit to branch master
in repository merchant.

commit 741f7127849d8e5c8e5feacc34fc16d415fc2944
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sat Apr 18 13:34:48 2020 +0200

    implement POST /instances
---
 src/backend/Makefile.am                            |   3 +-
 src/backend/taler-merchant-httpd.c                 |  41 +-
 src/backend/taler-merchant-httpd.h                 |  27 +-
 .../taler-merchant-httpd_private-get-instances.c   |   8 +-
 .../taler-merchant-httpd_private-post-instances.c  | 411 +++++++++++++++++++++
 .../taler-merchant-httpd_private-post-instances.h  |  43 +++
 src/backenddb/merchant-0001.sql                    |  10 +-
 src/backenddb/plugin_merchantdb_postgres.c         | 131 ++++++-
 src/include/taler_merchantdb_plugin.h              |  36 +-
 9 files changed, 662 insertions(+), 48 deletions(-)

diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index 1f98de3..db8969d 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -23,7 +23,8 @@ taler_merchant_httpd_SOURCES = \
   taler-merchant-httpd_config.c taler-merchant-httpd_config.h \
   taler-merchant-httpd_exchanges.c taler-merchant-httpd_exchanges.h \
   taler-merchant-httpd_mhd.c taler-merchant-httpd_mhd.h \
-  taler-merchant-httpd_private-get-instances.c 
taler-merchant-httpd_private-get-instances.h
+  taler-merchant-httpd_private-get-instances.c 
taler-merchant-httpd_private-get-instances.h \
+  taler-merchant-httpd_private-post-instances.c 
taler-merchant-httpd_private-post-instances.h
 
 DEAD = \
   taler-merchant-httpd_check-payment.c taler-merchant-httpd_check-payment.h \
diff --git a/src/backend/taler-merchant-httpd.c 
b/src/backend/taler-merchant-httpd.c
index 7ad0f85..7f5e32f 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -29,6 +29,7 @@
 #include "taler-merchant-httpd_exchanges.h"
 #include "taler-merchant-httpd_mhd.h"
 #include "taler-merchant-httpd_private-get-instances.h"
+#include "taler-merchant-httpd_private-post-instances.h"
 
 /**
  * Backlog for listen operation on unix-domain sockets.
@@ -131,7 +132,7 @@ TMH_instance_decref (struct TMH_MerchantInstance *mi)
 
   GNUNET_free (mi->settings.id);
   GNUNET_free (mi->settings.name);
-  json_decref (mi->settings.location);
+  json_decref (mi->settings.address);
   json_decref (mi->settings.jurisdiction);
   GNUNET_free (mi);
 }
@@ -269,7 +270,7 @@ TMH_long_poll_suspend (const char *order_id,
                        const struct TALER_Amount *min_refund)
 {
   compute_pay_key (order_id,
-                   &mi->pubkey,
+                   &mi->merchant_pub,
                    &sc->key);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Suspending operation on key %s\n",
@@ -358,7 +359,7 @@ TMH_long_poll_resume (const char *order_id,
   struct GNUNET_HashCode key;
 
   compute_pay_key (order_id,
-                   &mi->pubkey,
+                   &mi->merchant_pub,
                    &key);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Resuming operations suspended pending payment on key %s\n",
@@ -480,8 +481,8 @@ handle_mhd_completion_callback (void *cls,
     hc->cc (hc->ctx);
   TALER_MHD_parse_post_cleanup_callback (hc->json_parse_context);
   GNUNET_free_non_null (hc->infix);
-  if (NULL != hc->json)
-    json_decref (hc->json);
+  if (NULL != hc->request_body)
+    json_decref (hc->request_body);
   GNUNET_free (hc);
   *con_cls = NULL;
 }
@@ -600,8 +601,8 @@ prepare_daemon (void)
  * @param instance_id identifier of the instance to resolve
  * @return NULL if that instance is unknown to us
  */
-static struct TMH_MerchantInstance *
-lookup_instance (const char *instance_id)
+struct TMH_MerchantInstance *
+TMH_lookup_instance (const char *instance_id)
 {
   struct GNUNET_HashCode h_instance;
 
@@ -634,7 +635,7 @@ TMH_add_instance (struct TMH_MerchantInstance *mi)
   const char *id;
   int ret;
 
-  id = mi->id;
+  id = mi->settings.id;
   if (NULL == id)
     id = "default";
   GNUNET_CRYPTO_hash (id,
@@ -727,6 +728,12 @@ url_handler (void *cls,
       .skip_instance = true,
       .handler = &TMH_private_get_instances
     },
+    {
+      .url_prefix = "/instances",
+      .method = MHD_HTTP_METHOD_POST,
+      .skip_instance = true,
+      .handler = &TMH_private_post_instances
+    },
     {
       NULL
     }
@@ -778,7 +785,7 @@ url_handler (void *cls,
     GNUNET_assert (NULL != hc->rh);
     GNUNET_SCHEDULER_begin_async_scope (&hc->async_scope_id);
     if ( (hc->has_body) &&
-         (NULL == hc->json) )
+         (NULL == hc->request_body) )
     {
       int res;
 
@@ -786,13 +793,13 @@ url_handler (void *cls,
                                        &hc->json_parse_context,
                                        upload_data,
                                        upload_data_size,
-                                       &hc->json);
+                                       &hc->request_body);
       if (GNUNET_SYSERR == res)
         return MHD_NO;
       /* A error response was already generated */
       if ( (GNUNET_NO == res) ||
            /* or, need more data to accomplish parsing */
-           (NULL == hc->json) )
+           (NULL == hc->request_body) )
         return MHD_YES;
     }
     return hc->rh->handler (hc->rh,
@@ -857,14 +864,14 @@ url_handler (void *cls,
       }
       instance_id = GNUNET_strndup (istart,
                                     slash - istart);
-      hc->instance = lookup_instance (instance_id);
+      hc->instance = TMH_lookup_instance (instance_id);
       GNUNET_free (instance_id);
       url = slash;
     }
     else
     {
       /* use 'default' */
-      hc->instance = lookup_instance (NULL);
+      hc->instance = TMH_lookup_instance (NULL);
     }
   }
 
@@ -993,7 +1000,7 @@ url_handler (void *cls,
        and refuse if it is too big? (Note: maximum upload
        size may need to vary based on the handler.) */
 
-    GNUNET_break (NULL == hc->json); /* can't have it already */
+    GNUNET_break (NULL == hc->request_body); /* can't have it already */
     return MHD_YES; /* proceed with upload */
   }
   return hc->rh->handler (hc->rh,
@@ -1029,10 +1036,10 @@ add_instance_cb (void *cls,
   mi->settings = *is;
   mi->settings.id = GNUNET_strdup (mi->settings.id);
   mi->settings.name = GNUNET_strdup (mi->settings.name);
-  mi->settings.location = json_incref (mi->settings.location);
+  mi->settings.address = json_incref (mi->settings.address);
   mi->settings.jurisdiction = json_incref (mi->settings.jurisdiction);
-  mi->privkey = *merchant_priv;
-  mi->pubkey = *merchant_pub;
+  mi->merchant_priv = *merchant_priv;
+  mi->merchant_pub = *merchant_pub;
   for (unsigned int i = 0; i<accounts_length; i++)
   {
     const struct TALER_MERCHANTDB_AccountDetails *acc = &accounts[i];
diff --git a/src/backend/taler-merchant-httpd.h 
b/src/backend/taler-merchant-httpd.h
index 1d5715d..3a8b307 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -81,18 +81,6 @@ struct TMH_WireMethod
 struct TMH_MerchantInstance
 {
 
-  /**
-   * Instance's mnemonic identifier. This value lives as long as
-   * the configuration is kept in memory, as it's as substring of
-   * a section name
-   */
-  char *id;
-
-  /**
-   * Legal name of the merchant.
-   */
-  char *name;
-
   /**
    * Next entry in DLL.
    */
@@ -106,12 +94,12 @@ struct TMH_MerchantInstance
   /**
    * Merchant's private key.
    */
-  struct TALER_MerchantPrivateKeyP privkey;
+  struct TALER_MerchantPrivateKeyP merchant_priv;
 
   /**
    * Merchant's public key
    */
-  struct TALER_MerchantPublicKeyP pubkey;
+  struct TALER_MerchantPublicKeyP merchant_pub;
 
   /**
    * General settings for an instance.
@@ -287,7 +275,7 @@ struct TMH_HandlerContext
   /**
    * JSON body that was uploaded, NULL if @e has_body is false.
    */
-  json_t *json;
+  json_t *request_body;
 
   /**
    * Placeholder for #TALER_MHD_parse_post_json() to keep its internal state.
@@ -425,5 +413,14 @@ TMH_instance_decref (struct TMH_MerchantInstance *mi);
 int
 TMH_add_instance (struct TMH_MerchantInstance *mi);
 
+/**
+ * Lookup a merchant instance by its instance ID.
+ *
+ * @param instance_id identifier of the instance to resolve
+ * @return NULL if that instance is unknown to us
+ */
+struct TMH_MerchantInstance *
+TMH_lookup_instance (const char *instance_id);
+
 
 #endif
diff --git a/src/backend/taler-merchant-httpd_private-get-instances.c 
b/src/backend/taler-merchant-httpd_private-get-instances.c
index bd36817..74dbfef 100644
--- a/src/backend/taler-merchant-httpd_private-get-instances.c
+++ b/src/backend/taler-merchant-httpd_private-get-instances.c
@@ -74,11 +74,11 @@ add_instance (void *cls,
                    json_pack (
                      "{s:s, s:s, s:o, s:o}",
                      "name",
-                     mi->name,
-                     "instance",
-                     mi->id,
+                     mi->settings.name,
+                     "id",
+                     mi->settings.id,
                      "merchant_pub",
-                     GNUNET_JSON_from_data_auto (&mi->pubkey),
+                     GNUNET_JSON_from_data_auto (&mi->merchant_pub),
                      "payment_targets",
                      pta)));
   return GNUNET_OK;
diff --git a/src/backend/taler-merchant-httpd_private-post-instances.c 
b/src/backend/taler-merchant-httpd_private-post-instances.c
new file mode 100644
index 0000000..6bbd882
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-post-instances.c
@@ -0,0 +1,411 @@
+/*
+  This file is part of TALER
+  (C) 2020 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Affero General Public License as
+  published by the Free Software Foundation; either version 3,
+  or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public
+  License along with TALER; see the file COPYING.  If not,
+  see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file backend/taler-merchant-httpd_private-post-instances.c
+ * @brief implementing POST /instances request handling
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-post-instances.h"
+#include <taler/taler_json_lib.h>
+
+
+/**
+ * How often do we retry the simple INSERT database transaction?
+ */
+#define MAX_RETRIES 3
+
+
+/**
+ * Check if the array of @a payto_uris contains exactly the same
+ * URIs as those already in @a mi (possibly in a different order).
+ *
+ * @param mi a merchant instance with accounts
+ * @param payto_uris a JSON array with accounts (presumably)
+ * @return true if they are 'equal', false if not or of payto_uris is not an 
array
+ */
+static bool
+accounts_equal (const struct TMH_MerchantInstance *mi,
+                json_t *payto_uris)
+{
+  if (! json_is_array (payto_uris))
+    return false;
+  {
+    unsigned int len = json_array_size (payto_uris);
+    bool matches[GNUNET_NZL (len)];
+    struct TMH_WireMethod *wm;
+
+    memset (matches,
+            0,
+            sizeof (matches));
+    for (wm = mi->wm_head;
+         NULL != wm;
+         wm = wm->next)
+    {
+      const char *uri = json_string_value (json_object_get (wm->j_wire,
+                                                            "payto_uri"));
+
+      GNUNET_assert (NULL != uri);
+      for (unsigned int i = 0; i<len; i++)
+      {
+        const char *str = json_string_value (json_array_get (payto_uris,
+                                                             i));
+        if (NULL == str)
+          return false;
+        if ( (strcasecmp (uri,
+                          str)) )
+        {
+          if (matches[i])
+          {
+            GNUNET_break (0);
+            return false; /* duplicate entry!? */
+          }
+          matches[i] = true;
+          break;
+        }
+      }
+    }
+    for (unsigned int i = 0; i<len; i++)
+      if (! matches[i])
+        return false;
+  }
+  return true;
+}
+
+
+/**
+ * Free memory used by @a wm
+ *
+ * @param wm wire method to free
+ */
+static void
+free_wm (struct TMH_WireMethod *wm)
+{
+  json_decref (wm->j_wire);
+  GNUNET_free (wm->wire_method);
+  GNUNET_free (wm);
+}
+
+
+/**
+ * Free memory used by @a mi.
+ *
+ * @param mi instance to free
+ */
+static void
+free_mi (struct TMH_MerchantInstance *mi)
+{
+  struct TMH_WireMethod *wm;
+
+  while (NULL != (wm = mi->wm_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (mi->wm_head,
+                                 mi->wm_tail,
+                                 wm);
+    free_wm (wm);
+  }
+  GNUNET_free (mi->settings.id);
+  GNUNET_free (mi->settings.name);
+  GNUNET_free (mi);
+}
+
+
+/**
+ * Generate an instance, given its configuration.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_post_instances (const struct TMH_RequestHandler *rh,
+                            struct MHD_Connection *connection,
+                            struct TMH_HandlerContext *hc)
+{
+  struct TALER_MERCHANTDB_InstanceSettings is;
+  json_t *payto_uris;
+  const char *id;
+  const char *name;
+  struct TMH_WireMethod *wm_head = NULL;
+  struct TMH_WireMethod *wm_tail = NULL;
+  struct GNUNET_JSON_Specification spec[] = {
+    GNUNET_JSON_spec_json ("payto_uris",
+                           &payto_uris),
+    GNUNET_JSON_spec_string ("instance",
+                             &id),
+    GNUNET_JSON_spec_string ("name",
+                             &name),
+    GNUNET_JSON_spec_json ("address",
+                           &is.address),
+    GNUNET_JSON_spec_json ("jurisdiction",
+                           &is.jurisdiction),
+    TALER_JSON_spec_amount ("default_max_deposit_fee",
+                            &is.default_max_deposit_fee),
+    TALER_JSON_spec_amount ("default_max_wire_fee",
+                            &is.default_max_wire_fee),
+    GNUNET_JSON_spec_uint32 ("default_wire_fee_amortization",
+                             &is.default_wire_fee_amortization),
+    GNUNET_JSON_spec_relative_time ("default_wire_transfer_delay",
+                                    &is.default_wire_transfer_delay),
+    GNUNET_JSON_spec_relative_time ("default_pay_delay",
+                                    &is.default_pay_delay),
+    GNUNET_JSON_spec_end ()
+  };
+
+  {
+    enum GNUNET_GenericReturnValue res;
+
+    res = TALER_MHD_parse_json_data (connection,
+                                     hc->request_body,
+                                     spec);
+    /* json is malformed */
+    if (GNUNET_NO == res)
+    {
+      GNUNET_break_op (0);
+      return MHD_YES;
+    }
+    /* other internal errors might have occurred */
+    if (GNUNET_SYSERR == res)
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         TALER_EC_INTERNAL_INVARIANT_FAILURE,
+                                         "Impossible to parse the order");
+  }
+
+  {
+    /* Test if an instance of this id is known */
+    struct TMH_MerchantInstance *mi;
+
+    mi = TMH_lookup_instance (is.id);
+    if (NULL != mi)
+    {
+      /* Check for idempotency */
+      if ( (0 == strcmp (mi->settings.id,
+                         id)) &&
+           (0 == strcmp (mi->settings.name,
+                         name)) &&
+           (1 == json_equal (mi->settings.address,
+                             is.address)) &&
+           (1 == json_equal (mi->settings.jurisdiction,
+                             is.jurisdiction)) &&
+           (0 == TALER_amount_cmp_currency (
+              &mi->settings.default_max_deposit_fee,
+              &is.default_max_deposit_fee)) &&
+           (0 == TALER_amount_cmp (&mi->settings.default_max_deposit_fee,
+                                   &is.default_max_deposit_fee)) &&
+           (0 == TALER_amount_cmp_currency (&mi->settings.default_max_wire_fee,
+                                            &is.default_max_wire_fee)) &&
+           (0 == TALER_amount_cmp (&mi->settings.default_max_wire_fee,
+                                   &is.default_max_wire_fee)) &&
+           (mi->settings.default_wire_fee_amortization ==
+            is.default_wire_fee_amortization) &&
+           (mi->settings.default_wire_transfer_delay.rel_value_us ==
+            is.default_wire_transfer_delay.rel_value_us) &&
+           (mi->settings.default_pay_delay.rel_value_us ==
+            is.default_pay_delay.rel_value_us) &&
+           (accounts_equal (mi,
+                            payto_uris)) )
+      {
+        GNUNET_JSON_parse_free (spec);
+        return TALER_MHD_reply_static (connection,
+                                       MHD_HTTP_NO_CONTENT,
+                                       NULL,
+                                       NULL,
+                                       0);
+      }
+      else
+      {
+        GNUNET_JSON_parse_free (spec);
+        return TALER_MHD_reply_with_error (connection,
+                                           MHD_HTTP_CONFLICT,
+                                           
TALER_EC_POST_INSTANCES_ALREADY_EXISTS,
+                                           "An instance using this identifier 
already exists");
+      }
+    }
+  }
+
+  {
+    bool payto_ok = true;
+    unsigned int len;
+
+    if (! json_is_array (payto_uris))
+    {
+      payto_ok = false;
+      len = 0;
+    }
+    else
+    {
+      len = json_array_size (payto_uris);
+    }
+    for (unsigned int i = 0; i<len; i++)
+    {
+      json_t *payto_uri = json_array_get (payto_uris,
+                                          i);
+
+      if (! json_is_string (payto_uri))
+      {
+        payto_ok = false;
+        break;
+      }
+      /* Test for the same payto:// URI being given twice */
+      for (unsigned int j = 0; j<i; j++)
+      {
+        json_t *old_uri = json_array_get (payto_uris,
+                                          j);
+        if (json_equal (payto_uri,
+                        old_uri))
+        {
+          payto_ok = false;
+          break;
+        }
+      }
+      if (! payto_ok)
+        break;
+
+      {
+        struct TMH_WireMethod *wm;
+        struct GNUNET_HashCode salt;
+
+        GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+                                    &salt,
+                                    sizeof (salt));
+        wm = GNUNET_new (struct TMH_WireMethod);
+        wm->j_wire = json_pack ("{s:O, s:s}",
+                                "payto_uri", payto_uri,
+                                "salt", GNUNET_JSON_from_data_auto (&salt));
+        GNUNET_assert (NULL != wm->j_wire);
+        /* This also tests for things like the IBAN being malformed */
+        if (GNUNET_OK !=
+            TALER_JSON_merchant_wire_signature_hash (wm->j_wire,
+                                                     &wm->h_wire))
+        {
+          payto_ok = false;
+          GNUNET_free (wm);
+          break;
+        }
+        wm->wire_method
+          = TALER_payto_get_method (json_string_value (payto_uri));
+        GNUNET_assert (NULL != wm->wire_method);
+        wm->active = true;
+        GNUNET_CONTAINER_DLL_insert (wm_head,
+                                     wm_tail,
+                                     wm);
+      }
+    }
+    if (! payto_ok)
+    {
+      struct TMH_WireMethod *wm;
+
+      while (NULL != (wm = wm_head))
+      {
+        GNUNET_CONTAINER_DLL_remove (wm_head,
+                                     wm_tail,
+                                     wm);
+        free_wm (wm);
+      }
+      GNUNET_JSON_parse_free (spec);
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_BAD_REQUEST,
+                                         
TALER_EC_POST_INSTANCES_BAD_PAYTO_URIS,
+                                         "Invalid bank account information");
+    }
+  }
+
+  {
+    struct TMH_MerchantInstance *mi;
+    enum GNUNET_DB_QueryStatus qs;
+
+    mi = GNUNET_new (struct TMH_MerchantInstance);
+    mi->wm_head = wm_head;
+    mi->wm_tail = wm_tail;
+    mi->settings = is;
+    mi->settings.id = GNUNET_strdup (id);
+    mi->settings.name = GNUNET_strdup (name);
+    GNUNET_CRYPTO_eddsa_key_create (&mi->merchant_priv.eddsa_priv);
+    GNUNET_CRYPTO_eddsa_key_get_public (&mi->merchant_priv.eddsa_priv,
+                                        &mi->merchant_pub.eddsa_pub);
+
+    for (unsigned int i = 0; i<MAX_RETRIES; i++)
+    {
+      if (GNUNET_OK !=
+          TMH_db->start (TMH_db->cls,
+                         "post /instances"))
+      {
+        GNUNET_JSON_parse_free (spec);
+        free_mi (mi);
+        return TALER_MHD_reply_with_error (connection,
+                                           MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                           
TALER_EC_POST_INSTANCES_DB_START_ERROR,
+                                           "failed to start database 
transaction");
+      }
+      qs = TMH_db->insert_instance (TMH_db->cls,
+                                    &mi->merchant_pub,
+                                    &mi->merchant_priv,
+                                    &mi->settings);
+      if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+      {
+        TMH_db->rollback (TMH_db->cls);
+        continue;
+      }
+      for (struct TMH_WireMethod *wm = wm_head;
+           NULL != wm;
+           wm = wm->next)
+      {
+        struct TALER_MERCHANTDB_AccountDetails ad;
+
+        qs = TMH_db->insert_account (TMH_db->cls,
+                                     mi->settings.id,
+                                     &ad);
+        if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+          break;
+      }
+      if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+      {
+        TMH_db->rollback (TMH_db->cls);
+        continue;
+      }
+      qs = TMH_db->commit (TMH_db->cls);
+      if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+        break; /* success! */
+    }
+    if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+    {
+      GNUNET_JSON_parse_free (spec);
+      free_mi (mi);
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         
TALER_EC_POST_INSTANCES_DB_COMMIT_ERROR,
+                                         "failed to add instance to database");
+    }
+    /* Finally, also update our running process */
+    GNUNET_assert (GNUNET_OK ==
+                   TMH_add_instance (mi));
+  }
+  GNUNET_JSON_parse_free (spec);
+  return TALER_MHD_reply_static (connection,
+                                 MHD_HTTP_NO_CONTENT,
+                                 NULL,
+                                 NULL,
+                                 0);
+}
+
+
+/* end of taler-merchant-httpd_private-post-instances.c */
diff --git a/src/backend/taler-merchant-httpd_private-post-instances.h 
b/src/backend/taler-merchant-httpd_private-post-instances.h
new file mode 100644
index 0000000..b30d039
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-post-instances.h
@@ -0,0 +1,43 @@
+/*
+  This file is part of TALER
+  (C) 2020 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Affero General Public License as
+  published by the Free Software Foundation; either version 3,
+  or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public
+  License along with TALER; see the file COPYING.  If not,
+  see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file backend/taler-merchant-httpd_private-post-instances.h
+ * @brief implementing POST /instances request handling
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_POST_INSTANCES_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_POST_INSTANCES_H
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * Generate an instance, given its configuration.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_post_instances (const struct TMH_RequestHandler *rh,
+                            struct MHD_Connection *connection,
+                            struct TMH_HandlerContext *hc);
+
+#endif
diff --git a/src/backenddb/merchant-0001.sql b/src/backenddb/merchant-0001.sql
index 244d0f7..104ea47 100644
--- a/src/backenddb/merchant-0001.sql
+++ b/src/backenddb/merchant-0001.sql
@@ -63,7 +63,7 @@ CREATE TABLE IF NOT EXISTS merchant_instances
   ,merchant_pub BYTEA NOT NULL UNIQUE CHECK (LENGTH(merchant_pub)=32)
   ,merchant_id VARCHAR NOT NULL
   ,merchant_name VARCHAR NOT NULL
-  ,location BYTEA NOT NULL
+  ,address BYTEA NOT NULL
   ,jurisdiction BYTEA NOT NULL
   ,default_max_deposit_fee_val INT8 NOT NULL
   ,default_max_deposit_fee_frac INT4 NOT NULL
@@ -79,8 +79,8 @@ COMMENT ON COLUMN merchant_instances.merchant_id
   IS 'identifier of the merchant as used in the base URL (required)';
 COMMENT ON COLUMN merchant_instances.merchant_name
   IS 'legal name of the merchant as a simple string (required)';
-COMMENT ON COLUMN merchant_instances.location
-  IS 'physical location of the merchant as a Location in JSON format 
(required)';
+COMMENT ON COLUMN merchant_instances.address
+  IS 'physical address of the merchant as a Location in JSON format 
(required)';
 COMMENT ON COLUMN merchant_instances.jurisdiction
   IS 'jurisdiction of the merchant as a Location in JSON format (required)';
 
@@ -131,7 +131,7 @@ CREATE TABLE IF NOT EXISTS merchant_inventory
   ,total_stock BIGINT NOT NULL
   ,total_sold BIGINT NOT NULL
   ,total_lost BIGINT NOT NULL
-  ,location BYTEA NOT NULL
+  ,address BYTEA NOT NULL
   ,next_restock INT8 NOT NULL
   ,UNIQUE (merchant_serial, product_id)
   );
@@ -155,7 +155,7 @@ COMMENT ON COLUMN merchant_inventory.total_sold
   IS 'Number of products sold, must be below total_stock, non-negative, may 
never be lowered';
 COMMENT ON COLUMN merchant_inventory.total_lost
   IS 'Number of products that used to be in stock but were lost (spoiled, 
damaged), may never be lowered';
-COMMENT ON COLUMN merchant_inventory.location
+COMMENT ON COLUMN merchant_inventory.address
   IS 'JSON formatted Location of where the product is stocked';
 COMMENT ON COLUMN merchant_inventory.next_restock
   IS 'GNUnet absolute time indicating when the next restock is expected. 0 for 
unknown.';
diff --git a/src/backenddb/plugin_merchantdb_postgres.c 
b/src/backenddb/plugin_merchantdb_postgres.c
index c081332..f9cdcad 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -436,8 +436,8 @@ lookup_instances_cb (void *cls,
                                     &lic->is.name),
       GNUNET_PQ_result_spec_string ("id",
                                     &lic->is.id),
-      TALER_PQ_result_spec_json ("location",
-                                 &lic->is.location),
+      TALER_PQ_result_spec_json ("address",
+                                 &lic->is.address),
       TALER_PQ_result_spec_json ("jurisdiction",
                                  &lic->is.jurisdiction),
       TALER_PQ_RESULT_SPEC_AMOUNT ("default_max_deposit_fee",
@@ -524,6 +524,88 @@ postgres_lookup_instances (void *cls,
 }
 
 
+/**
+ * Insert information about an instance into our database.
+ *
+ * @param cls closure
+ * @param merchant_pub public key of the instance
+ * @param merchant_priv private key of the instance
+ * @param is details about the instance
+ * @return database result code
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_insert_instance (void *cls,
+                          const struct TALER_MerchantPublicKeyP *merchant_pub,
+                          const struct TALER_MerchantPrivateKeyP 
*merchant_priv,
+                          const struct TALER_MERCHANTDB_InstanceSettings *is)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+    GNUNET_PQ_query_param_string (is->id),
+    GNUNET_PQ_query_param_string (is->name),
+    TALER_PQ_query_param_json (is->address),
+    TALER_PQ_query_param_json (is->jurisdiction),
+    TALER_PQ_query_param_amount (&is->default_max_deposit_fee),
+    TALER_PQ_query_param_amount (&is->default_max_wire_fee),
+    GNUNET_PQ_query_param_uint32 (&is->default_wire_fee_amortization),
+    GNUNET_PQ_query_param_relative_time (
+      &is->default_wire_transfer_delay),
+    GNUNET_PQ_query_param_relative_time (&is->default_pay_delay),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_QueryParam params_priv[] = {
+    GNUNET_PQ_query_param_auto_from_type (merchant_priv),
+    GNUNET_PQ_query_param_string (is->id)
+  };
+  enum GNUNET_DB_QueryStatus qs;
+
+  check_connection (pg);
+  qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                           "insert_instance",
+                                           params);
+  if (qs <= 0)
+    return qs;
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_keys",
+                                             params_priv);
+}
+
+
+/**
+ * Insert information about an instance's account into our database.
+ *
+ * @param cls closure
+ * @param id identifier of the instance
+ * @param account_details details about the account
+ * @return database result code
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_insert_account (
+  void *cls,
+  const char *id,
+  const struct
+  TALER_MERCHANTDB_AccountDetails *account_details)
+{
+  struct PostgresClosure *pg = cls;
+  uint8_t active = account_details->active;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (id),
+    GNUNET_PQ_query_param_auto_from_type (&account_details->h_wire),
+    GNUNET_PQ_query_param_auto_from_type (&account_details->salt),
+    GNUNET_PQ_query_param_string (account_details->payto_uri),
+    GNUNET_PQ_query_param_auto_from_type (&active),
+    GNUNET_PQ_query_param_end
+  };
+
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_account",
+                                             params);
+
+}
+
+
 /* ********************* OLD API ************************** */
 
 /**
@@ -848,7 +930,7 @@ postgres_insert_session_info (void *cls,
  * 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
+ * @param[out] order_id where to store the order ID that was used when
  *             paying for the resource URL
  * @param session_id session id
  * @param fulfillment_url URL that canonically identifies the resource
@@ -3423,7 +3505,7 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
                             ",merchant_pub"
                             ",merchant_id"
                             ",merchant_name"
-                            ",location"
+                            ",address"
                             ",jurisdiction"
                             ",default_max_deposit_fee_val"
                             ",default_max_deposit_fee_frac"
@@ -3434,6 +3516,45 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
                             ",default_pay_delay"
                             " FROM merchant_instances",
                             0),
+    /* for postgres_insert_instance() */
+    GNUNET_PQ_make_prepare ("insert_instance",
+                            "INSERT INTO merchant_instances"
+                            "(merchant_pub"
+                            ",merchant_id"
+                            ",merchant_name"
+                            ",address"
+                            ",jurisdiction"
+                            ",default_max_deposit_fee_val"
+                            ",default_max_deposit_fee_frac"
+                            ",default_max_wire_fee_val"
+                            ",default_max_wire_fee_frac"
+                            ",default_wire_fee_amortization"
+                            ",default_wire_transfer_delay"
+                            ",default_pay_delay)"
+                            "VALUES"
+                            "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, 
$12)",
+                            12),
+    /* for postgres_insert_instance() */
+    GNUNET_PQ_make_prepare ("insert_keys",
+                            "INSERT INTO merchant_keys"
+                            "(merchant_priv"
+                            ",merchant_serial)"
+                            " SELECT $1, merchant_serial"
+                            " FROM merchant_instances"
+                            " WHERE merchant_id=$2",
+                            2),
+    /* for postgres_insert_account() */
+    GNUNET_PQ_make_prepare ("insert_account",
+                            "INSERT INTO merchant_accounts"
+                            "(merchant_serial"
+                            ",h_wire"
+                            ",salt"
+                            ",payto_uri"
+                            ",active)"
+                            " SELECT merchant_serial, $2, $3, $4, $5"
+                            " FROM merchant_instances"
+                            " WHERE merchant_id=$1",
+                            5),
     /* OLD API: */
 #if 0
     GNUNET_PQ_make_prepare ("insert_deposit",
@@ -3931,6 +4052,8 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
   plugin->rollback = &postgres_rollback;
   plugin->commit = &postgres_commit;
   plugin->lookup_instances = &postgres_lookup_instances;
+  plugin->insert_instance = &postgres_insert_instance;
+  plugin->insert_account = &postgres_insert_account;
 
   /* old API: */
   plugin->store_deposit = &postgres_store_deposit;
diff --git a/src/include/taler_merchantdb_plugin.h 
b/src/include/taler_merchantdb_plugin.h
index 30941eb..2d688dd 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -76,9 +76,9 @@ struct TALER_MERCHANTDB_InstanceSettings
   char *name;
 
   /**
-   * location of the business
+   * Address of the business
    */
-  json_t *location;
+  json_t *address;
 
   /**
    * jurisdiction of the business
@@ -354,6 +354,38 @@ struct TALER_MERCHANTDB_Plugin
                       void *cb_cls);
 
 
+  /**
+   * Insert information about an instance into our database.
+   *
+   * @param cls closure
+   * @param merchant_pub public key of the instance
+   * @param merchant_priv private key of the instance
+   * @param is details about the instance
+   * @return database result code
+   */
+  enum GNUNET_DB_QueryStatus
+  (*insert_instance)(void *cls,
+                     const struct TALER_MerchantPublicKeyP *merchant_pub,
+                     const struct TALER_MerchantPrivateKeyP *merchant_priv,
+                     const struct TALER_MERCHANTDB_InstanceSettings *is);
+
+  /**
+   * Insert information about an instance's account into our database.
+   *
+   * @param cls closure
+   * @param id identifier of the instance
+   * @param account_details details about the account
+   * @return database result code
+   */
+  enum GNUNET_DB_QueryStatus
+  (*insert_account)(
+    void *cls,
+    const char *id,
+    const struct TALER_MERCHANTDB_AccountDetails *account_details);
+
+
+  /* ****************** OLD API ******************** */
+
   /**
    * Insert order into db.
    *

-- 
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]