merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

merchant_api_patch-management-instances-INSTANCE.c (13341B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2020-2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU Lesser General Public License as
      7   published by the Free Software Foundation; either version 2.1,
      8   or (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful,
     11   but WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU Lesser General Public License for more details.
     14 
     15   You should have received a copy of the GNU Lesser General
     16   Public License along with TALER; see the file COPYING.LGPL.
     17   If not, see <http://www.gnu.org/licenses/>
     18 */
     19 /**
     20  * @file merchant_api_patch-management-instances-INSTANCE-new.c
     21  * @brief Implementation of the PATCH /management/instances/$INSTANCE request
     22  * @author Christian Grothoff
     23  */
     24 #include "taler/platform.h"
     25 #include <curl/curl.h>
     26 #include <jansson.h>
     27 #include <microhttpd.h> /* just for HTTP status codes */
     28 #include <gnunet/gnunet_util_lib.h>
     29 #include <gnunet/gnunet_curl_lib.h>
     30 #include <taler/taler-merchant/patch-management-instances-INSTANCE.h>
     31 #include "merchant_api_curl_defaults.h"
     32 #include "merchant_api_common.h"
     33 #include <taler/taler_json_lib.h>
     34 #include <taler/taler_curl_lib.h>
     35 
     36 
     37 /**
     38  * Handle for a PATCH /management/instances/$INSTANCE operation.
     39  */
     40 struct TALER_MERCHANT_PatchManagementInstancesHandle
     41 {
     42   /**
     43    * Base URL of the merchant backend.
     44    */
     45   char *base_url;
     46 
     47   /**
     48    * The full URL for this request.
     49    */
     50   char *url;
     51 
     52   /**
     53    * Handle for the request.
     54    */
     55   struct GNUNET_CURL_Job *job;
     56 
     57   /**
     58    * Function to call with the result.
     59    */
     60   TALER_MERCHANT_PatchManagementInstancesCallback cb;
     61 
     62   /**
     63    * Closure for @a cb.
     64    */
     65   TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_RESULT_CLOSURE *cb_cls;
     66 
     67   /**
     68    * Reference to the execution context.
     69    */
     70   struct GNUNET_CURL_Context *ctx;
     71 
     72   /**
     73    * Minor context that holds body and headers.
     74    */
     75   struct TALER_CURL_PostContext post_ctx;
     76 
     77   /**
     78    * Instance identifier.
     79    */
     80   char *instance_id;
     81 
     82   /**
     83    * Human-readable name for the instance.
     84    */
     85   char *name;
     86 
     87   /**
     88    * Address (JSON).
     89    */
     90   json_t *address;
     91 
     92   /**
     93    * Jurisdiction (JSON).
     94    */
     95   json_t *jurisdiction;
     96 
     97   /**
     98    * Whether to use STEFAN curves for fee calculations.
     99    */
    100   bool use_stefan;
    101 
    102   /**
    103    * Default wire transfer delay (optional).
    104    */
    105   struct GNUNET_TIME_Relative default_wire_transfer_delay;
    106 
    107   /**
    108    * Default payment deadline (optional).
    109    */
    110   struct GNUNET_TIME_Relative default_pay_delay;
    111 
    112   /**
    113    * Default refund deadline (optional).
    114    */
    115   struct GNUNET_TIME_Relative default_refund_delay;
    116 
    117   /**
    118    * Default wire transfer rounding interval (optional).
    119    */
    120   enum GNUNET_TIME_RounderInterval default_wire_transfer_rounding_interval;
    121 
    122   /**
    123    * Email address (optional).
    124    */
    125   char *email;
    126 
    127   /**
    128    * Phone number (optional).
    129    */
    130   char *phone_number;
    131 
    132   /**
    133    * Website URL (optional).
    134    */
    135   char *website;
    136 
    137   /**
    138    * Logo (optional).
    139    */
    140   char *logo;
    141 
    142   /**
    143    * Whether default_pay_delay was set.
    144    */
    145   bool have_default_pay_delay;
    146 
    147   /**
    148    * Whether default_refund_delay was set.
    149    */
    150   bool have_default_refund_delay;
    151 
    152   /**
    153    * Whether default_wire_transfer_delay was set.
    154    */
    155   bool have_default_wire_transfer_delay;
    156 
    157   /**
    158    * Whether default_wire_transfer_rounding_interval was set.
    159    */
    160   bool have_default_wire_transfer_rounding_interval;
    161 };
    162 
    163 
    164 /**
    165  * Function called when we're done processing the
    166  * HTTP PATCH /management/instances/$INSTANCE request.
    167  *
    168  * @param cls the `struct TALER_MERCHANT_PatchManagementInstancesHandle`
    169  * @param response_code HTTP response code, 0 on error
    170  * @param response response body, NULL if not in JSON
    171  */
    172 static void
    173 handle_patch_management_instances_finished (void *cls,
    174                                             long response_code,
    175                                             const void *response)
    176 {
    177   struct TALER_MERCHANT_PatchManagementInstancesHandle *pmih = cls;
    178   const json_t *json = response;
    179   struct TALER_MERCHANT_PatchManagementInstancesResponse pmir = {
    180     .hr.http_status = (unsigned int) response_code,
    181     .hr.reply = json
    182   };
    183 
    184   pmih->job = NULL;
    185   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    186               "PATCH /management/instances/$INSTANCE completed with response code %u\n",
    187               (unsigned int) response_code);
    188   switch (response_code)
    189   {
    190   case 0:
    191     pmir.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    192     break;
    193   case MHD_HTTP_NO_CONTENT:
    194     break;
    195   case MHD_HTTP_BAD_REQUEST:
    196     pmir.hr.ec = TALER_JSON_get_error_code (json);
    197     pmir.hr.hint = TALER_JSON_get_error_hint (json);
    198     break;
    199   case MHD_HTTP_UNAUTHORIZED:
    200     pmir.hr.ec = TALER_JSON_get_error_code (json);
    201     pmir.hr.hint = TALER_JSON_get_error_hint (json);
    202     break;
    203   case MHD_HTTP_FORBIDDEN:
    204     pmir.hr.ec = TALER_JSON_get_error_code (json);
    205     pmir.hr.hint = TALER_JSON_get_error_hint (json);
    206     break;
    207   case MHD_HTTP_NOT_FOUND:
    208     pmir.hr.ec = TALER_JSON_get_error_code (json);
    209     pmir.hr.hint = TALER_JSON_get_error_hint (json);
    210     break;
    211   case MHD_HTTP_CONFLICT:
    212     pmir.hr.ec = TALER_JSON_get_error_code (json);
    213     pmir.hr.hint = TALER_JSON_get_error_hint (json);
    214     break;
    215   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    216     pmir.hr.ec = TALER_JSON_get_error_code (json);
    217     pmir.hr.hint = TALER_JSON_get_error_hint (json);
    218     break;
    219   default:
    220     TALER_MERCHANT_parse_error_details_ (json,
    221                                          response_code,
    222                                          &pmir.hr);
    223     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    224                 "Unexpected response code %u/%d\n",
    225                 (unsigned int) response_code,
    226                 (int) pmir.hr.ec);
    227     GNUNET_break_op (0);
    228     break;
    229   }
    230   pmih->cb (pmih->cb_cls,
    231             &pmir);
    232   TALER_MERCHANT_patch_management_instances_cancel (pmih);
    233 }
    234 
    235 
    236 struct TALER_MERCHANT_PatchManagementInstancesHandle *
    237 TALER_MERCHANT_patch_management_instances_create (
    238   struct GNUNET_CURL_Context *ctx,
    239   const char *url,
    240   const char *instance_id,
    241   const char *name,
    242   const json_t *address,
    243   const json_t *jurisdiction,
    244   bool use_stefan)
    245 {
    246   struct TALER_MERCHANT_PatchManagementInstancesHandle *pmih;
    247 
    248   pmih = GNUNET_new (struct TALER_MERCHANT_PatchManagementInstancesHandle);
    249   pmih->ctx = ctx;
    250   pmih->base_url = GNUNET_strdup (url);
    251   pmih->instance_id = GNUNET_strdup (instance_id);
    252   pmih->name = GNUNET_strdup (name);
    253   pmih->address = json_incref ((json_t *) address);
    254   pmih->jurisdiction = json_incref ((json_t *) jurisdiction);
    255   pmih->use_stefan = use_stefan;
    256   return pmih;
    257 }
    258 
    259 
    260 enum GNUNET_GenericReturnValue
    261 TALER_MERCHANT_patch_management_instances_set_options_ (
    262   struct TALER_MERCHANT_PatchManagementInstancesHandle *pmih,
    263   unsigned int num_options,
    264   const struct TALER_MERCHANT_PatchManagementInstancesOptionValue *options)
    265 {
    266   for (unsigned int i = 0; i < num_options; i++)
    267   {
    268     switch (options[i].option)
    269     {
    270     case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_END:
    271       return GNUNET_OK;
    272     case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_DEFAULT_PAY_DELAY:
    273       pmih->default_pay_delay = options[i].details.default_pay_delay;
    274       pmih->have_default_pay_delay = true;
    275       break;
    276     case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_DEFAULT_REFUND_DELAY:
    277       pmih->default_refund_delay = options[i].details.default_refund_delay;
    278       pmih->have_default_refund_delay = true;
    279       break;
    280     case
    281       TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_DEFAULT_WIRE_TRANSFER_DELAY:
    282       pmih->default_wire_transfer_delay =
    283         options[i].details.default_wire_transfer_delay;
    284       pmih->have_default_wire_transfer_delay = true;
    285       break;
    286     case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_DEFAULT_WIRE_TRANSFER_ROUNDING_INTERVAL:
    287       pmih->default_wire_transfer_rounding_interval =
    288         options[i].details.default_wire_transfer_rounding_interval;
    289       pmih->have_default_wire_transfer_rounding_interval = true;
    290       break;
    291     case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_EMAIL:
    292       GNUNET_free (pmih->email);
    293       pmih->email = GNUNET_strdup (options[i].details.email);
    294       break;
    295     case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_PHONE_NUMBER:
    296       GNUNET_free (pmih->phone_number);
    297       pmih->phone_number = GNUNET_strdup (options[i].details.phone_number);
    298       break;
    299     case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_WEBSITE:
    300       GNUNET_free (pmih->website);
    301       pmih->website = GNUNET_strdup (options[i].details.website);
    302       break;
    303     case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_LOGO:
    304       GNUNET_free (pmih->logo);
    305       pmih->logo = GNUNET_strdup (options[i].details.logo);
    306       break;
    307     }
    308   }
    309   return GNUNET_OK;
    310 }
    311 
    312 
    313 enum TALER_ErrorCode
    314 TALER_MERCHANT_patch_management_instances_start (
    315   struct TALER_MERCHANT_PatchManagementInstancesHandle *pmih,
    316   TALER_MERCHANT_PatchManagementInstancesCallback cb,
    317   TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_RESULT_CLOSURE *cb_cls)
    318 {
    319   json_t *req_obj;
    320   CURL *eh;
    321 
    322   pmih->cb = cb;
    323   pmih->cb_cls = cb_cls;
    324   {
    325     char *path;
    326 
    327     GNUNET_asprintf (&path,
    328                      "management/instances/%s",
    329                      pmih->instance_id);
    330     pmih->url = TALER_url_join (pmih->base_url,
    331                                 path,
    332                                 NULL);
    333     GNUNET_free (path);
    334   }
    335   if (NULL == pmih->url)
    336     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    337   req_obj = GNUNET_JSON_PACK (
    338     GNUNET_JSON_pack_string ("name",
    339                              pmih->name),
    340     GNUNET_JSON_pack_object_incref ("address",
    341                                     pmih->address),
    342     GNUNET_JSON_pack_object_incref ("jurisdiction",
    343                                     pmih->jurisdiction),
    344     GNUNET_JSON_pack_bool ("use_stefan",
    345                            pmih->use_stefan),
    346     GNUNET_JSON_pack_allow_null (
    347       pmih->have_default_wire_transfer_delay
    348       ? GNUNET_JSON_pack_time_rel ("default_wire_transfer_delay",
    349                                    pmih->default_wire_transfer_delay)
    350       : GNUNET_JSON_pack_string ("default_wire_transfer_delay",
    351                                  NULL)),
    352     GNUNET_JSON_pack_allow_null (
    353       pmih->have_default_pay_delay
    354       ? GNUNET_JSON_pack_time_rel ("default_pay_delay",
    355                                    pmih->default_pay_delay)
    356       : GNUNET_JSON_pack_string ("default_pay_delay",
    357                                  NULL)),
    358     GNUNET_JSON_pack_allow_null (
    359       pmih->have_default_refund_delay
    360       ? GNUNET_JSON_pack_time_rel ("default_refund_delay",
    361                                    pmih->default_refund_delay)
    362       : GNUNET_JSON_pack_string ("default_refund_delay",
    363                                  NULL)),
    364     GNUNET_JSON_pack_allow_null (
    365       pmih->have_default_wire_transfer_rounding_interval
    366       ? GNUNET_JSON_pack_time_rounder_interval (
    367         "default_wire_transfer_rounding_interval",
    368         pmih->default_wire_transfer_rounding_interval)
    369       : GNUNET_JSON_pack_string ("default_wire_transfer_rounding_interval",
    370                                  NULL)),
    371     GNUNET_JSON_pack_allow_null (
    372       GNUNET_JSON_pack_string ("email",
    373                                pmih->email)),
    374     GNUNET_JSON_pack_allow_null (
    375       GNUNET_JSON_pack_string ("phone_number",
    376                                pmih->phone_number)),
    377     GNUNET_JSON_pack_allow_null (
    378       GNUNET_JSON_pack_string ("website",
    379                                pmih->website)),
    380     GNUNET_JSON_pack_allow_null (
    381       GNUNET_JSON_pack_string ("logo",
    382                                pmih->logo))
    383     );
    384   eh = TALER_MERCHANT_curl_easy_get_ (pmih->url);
    385   if ( (NULL == eh) ||
    386        (GNUNET_OK !=
    387         TALER_curl_easy_post (&pmih->post_ctx,
    388                               eh,
    389                               req_obj)) )
    390   {
    391     GNUNET_break (0);
    392     json_decref (req_obj);
    393     if (NULL != eh)
    394       curl_easy_cleanup (eh);
    395     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    396   }
    397   json_decref (req_obj);
    398   GNUNET_assert (CURLE_OK ==
    399                  curl_easy_setopt (eh,
    400                                    CURLOPT_CUSTOMREQUEST,
    401                                    MHD_HTTP_METHOD_PATCH));
    402   pmih->job = GNUNET_CURL_job_add2 (pmih->ctx,
    403                                     eh,
    404                                     pmih->post_ctx.headers,
    405                                     &handle_patch_management_instances_finished,
    406                                     pmih);
    407   if (NULL == pmih->job)
    408     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    409   return TALER_EC_NONE;
    410 }
    411 
    412 
    413 void
    414 TALER_MERCHANT_patch_management_instances_cancel (
    415   struct TALER_MERCHANT_PatchManagementInstancesHandle *pmih)
    416 {
    417   if (NULL != pmih->job)
    418   {
    419     GNUNET_CURL_job_cancel (pmih->job);
    420     pmih->job = NULL;
    421   }
    422   TALER_curl_easy_post_finished (&pmih->post_ctx);
    423   json_decref (pmih->address);
    424   json_decref (pmih->jurisdiction);
    425   GNUNET_free (pmih->instance_id);
    426   GNUNET_free (pmih->name);
    427   GNUNET_free (pmih->email);
    428   GNUNET_free (pmih->phone_number);
    429   GNUNET_free (pmih->website);
    430   GNUNET_free (pmih->logo);
    431   GNUNET_free (pmih->url);
    432   GNUNET_free (pmih->base_url);
    433   GNUNET_free (pmih);
    434 }
    435 
    436 
    437 /* end of merchant_api_patch-management-instances-INSTANCE-new.c */