merchant

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

merchant_api_post-private-tokenfamilies.c (10364B)


      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_post-private-tokenfamilies-new.c
     21  * @brief Implementation of the POST /private/tokenfamilies 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/post-private-tokenfamilies.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 POST /private/tokenfamilies operation.
     39  */
     40 struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle
     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_PostPrivateTokenfamiliesCallback cb;
     61 
     62   /**
     63    * Closure for @a cb.
     64    */
     65   TALER_MERCHANT_POST_PRIVATE_TOKENFAMILIES_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    * URL-safe slug identifier.
     79    */
     80   char *slug;
     81 
     82   /**
     83    * Human-readable name.
     84    */
     85   char *name;
     86 
     87   /**
     88    * Human-readable description.
     89    */
     90   char *description;
     91 
     92   /**
     93    * Start of validity period.
     94    */
     95   struct GNUNET_TIME_Timestamp valid_after;
     96 
     97   /**
     98    * End of validity period.
     99    */
    100   struct GNUNET_TIME_Timestamp valid_before;
    101 
    102   /**
    103    * Duration of individual token validity.
    104    */
    105   struct GNUNET_TIME_Relative duration;
    106 
    107   /**
    108    * Granularity for validity alignment.
    109    */
    110   struct GNUNET_TIME_Relative validity_granularity;
    111 
    112   /**
    113    * Offset from purchase to start of validity.
    114    */
    115   struct GNUNET_TIME_Relative start_offset;
    116 
    117   /**
    118    * Kind of token family.
    119    */
    120   char *kind;
    121 
    122   /**
    123    * Optional internationalized descriptions (JSON).
    124    */
    125   json_t *description_i18n;
    126 
    127   /**
    128    * Optional extra data (JSON).
    129    */
    130   json_t *extra_data;
    131 };
    132 
    133 
    134 /**
    135  * Function called when we're done processing the
    136  * HTTP POST /private/tokenfamilies request.
    137  *
    138  * @param cls the `struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle`
    139  * @param response_code HTTP response code, 0 on error
    140  * @param response response body, NULL if not in JSON
    141  */
    142 static void
    143 handle_post_tokenfamilies_finished (void *cls,
    144                                     long response_code,
    145                                     const void *response)
    146 {
    147   struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle *ptfh = cls;
    148   const json_t *json = response;
    149   struct TALER_MERCHANT_PostPrivateTokenfamiliesResponse tfr = {
    150     .hr.http_status = (unsigned int) response_code,
    151     .hr.reply = json
    152   };
    153 
    154   ptfh->job = NULL;
    155   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    156               "POST /private/tokenfamilies completed with response code %u\n",
    157               (unsigned int) response_code);
    158   switch (response_code)
    159   {
    160   case 0:
    161     tfr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    162     break;
    163   case MHD_HTTP_NO_CONTENT:
    164     break;
    165   case MHD_HTTP_BAD_REQUEST:
    166     GNUNET_break_op (0);
    167     tfr.hr.ec = TALER_JSON_get_error_code (json);
    168     tfr.hr.hint = TALER_JSON_get_error_hint (json);
    169     break;
    170   case MHD_HTTP_UNAUTHORIZED:
    171     tfr.hr.ec = TALER_JSON_get_error_code (json);
    172     tfr.hr.hint = TALER_JSON_get_error_hint (json);
    173     break;
    174   case MHD_HTTP_FORBIDDEN:
    175     tfr.hr.ec = TALER_JSON_get_error_code (json);
    176     tfr.hr.hint = TALER_JSON_get_error_hint (json);
    177     break;
    178   case MHD_HTTP_NOT_FOUND:
    179     tfr.hr.ec = TALER_JSON_get_error_code (json);
    180     tfr.hr.hint = TALER_JSON_get_error_hint (json);
    181     break;
    182   case MHD_HTTP_CONFLICT:
    183     tfr.hr.ec = TALER_JSON_get_error_code (json);
    184     tfr.hr.hint = TALER_JSON_get_error_hint (json);
    185     break;
    186   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    187     tfr.hr.ec = TALER_JSON_get_error_code (json);
    188     tfr.hr.hint = TALER_JSON_get_error_hint (json);
    189     break;
    190   default:
    191     TALER_MERCHANT_parse_error_details_ (json,
    192                                          response_code,
    193                                          &tfr.hr);
    194     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    195                 "Unexpected response code %u/%d\n",
    196                 (unsigned int) response_code,
    197                 (int) tfr.hr.ec);
    198     GNUNET_break_op (0);
    199     break;
    200   }
    201   ptfh->cb (ptfh->cb_cls,
    202             &tfr);
    203   TALER_MERCHANT_post_private_tokenfamilies_cancel (ptfh);
    204 }
    205 
    206 
    207 struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle *
    208 TALER_MERCHANT_post_private_tokenfamilies_create (
    209   struct GNUNET_CURL_Context *ctx,
    210   const char *url,
    211   const char *slug,
    212   const char *name,
    213   const char *description,
    214   struct GNUNET_TIME_Timestamp valid_after,
    215   struct GNUNET_TIME_Timestamp valid_before,
    216   struct GNUNET_TIME_Relative duration,
    217   struct GNUNET_TIME_Relative validity_granularity,
    218   struct GNUNET_TIME_Relative start_offset,
    219   const char *kind)
    220 {
    221   struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle *ptfh;
    222 
    223   ptfh = GNUNET_new (struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle);
    224   ptfh->ctx = ctx;
    225   ptfh->base_url = GNUNET_strdup (url);
    226   ptfh->slug = GNUNET_strdup (slug);
    227   ptfh->name = GNUNET_strdup (name);
    228   ptfh->description = GNUNET_strdup (description);
    229   ptfh->valid_after = valid_after;
    230   ptfh->valid_before = valid_before;
    231   ptfh->duration = duration;
    232   ptfh->validity_granularity = validity_granularity;
    233   ptfh->start_offset = start_offset;
    234   ptfh->kind = GNUNET_strdup (kind);
    235   return ptfh;
    236 }
    237 
    238 
    239 enum GNUNET_GenericReturnValue
    240 TALER_MERCHANT_post_private_tokenfamilies_set_options_ (
    241   struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle *ptfh,
    242   unsigned int num_options,
    243   const struct TALER_MERCHANT_PostPrivateTokenfamiliesOptionValue *options)
    244 {
    245   for (unsigned int i = 0; i < num_options; i++)
    246   {
    247     switch (options[i].option)
    248     {
    249     case TALER_MERCHANT_POST_PRIVATE_TOKENFAMILIES_OPTION_END:
    250       return GNUNET_OK;
    251     case TALER_MERCHANT_POST_PRIVATE_TOKENFAMILIES_OPTION_DESCRIPTION_I18N:
    252       ptfh->description_i18n
    253         = json_incref ((json_t *) options[i].details.description_i18n);
    254       break;
    255     case TALER_MERCHANT_POST_PRIVATE_TOKENFAMILIES_OPTION_EXTRA_DATA:
    256       ptfh->extra_data
    257         = json_incref ((json_t *) options[i].details.extra_data);
    258       break;
    259     default:
    260       GNUNET_break (0);
    261       return GNUNET_SYSERR;
    262     }
    263   }
    264   return GNUNET_OK;
    265 }
    266 
    267 
    268 enum TALER_ErrorCode
    269 TALER_MERCHANT_post_private_tokenfamilies_start (
    270   struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle *ptfh,
    271   TALER_MERCHANT_PostPrivateTokenfamiliesCallback cb,
    272   TALER_MERCHANT_POST_PRIVATE_TOKENFAMILIES_RESULT_CLOSURE *cb_cls)
    273 {
    274   json_t *req_obj;
    275   CURL *eh;
    276 
    277   ptfh->cb = cb;
    278   ptfh->cb_cls = cb_cls;
    279   ptfh->url = TALER_url_join (ptfh->base_url,
    280                               "private/tokenfamilies",
    281                               NULL);
    282   if (NULL == ptfh->url)
    283     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    284   req_obj = GNUNET_JSON_PACK (
    285     GNUNET_JSON_pack_string ("slug",
    286                              ptfh->slug),
    287     GNUNET_JSON_pack_string ("name",
    288                              ptfh->name),
    289     GNUNET_JSON_pack_string ("description",
    290                              ptfh->description),
    291     GNUNET_JSON_pack_allow_null (
    292       GNUNET_JSON_pack_object_incref ("description_i18n",
    293                                       ptfh->description_i18n)),
    294     GNUNET_JSON_pack_allow_null (
    295       GNUNET_JSON_pack_object_incref ("extra_data",
    296                                       ptfh->extra_data)),
    297     GNUNET_JSON_pack_allow_null (
    298       GNUNET_JSON_pack_timestamp ("valid_after",
    299                                   ptfh->valid_after)),
    300     GNUNET_JSON_pack_timestamp ("valid_before",
    301                                 ptfh->valid_before),
    302     GNUNET_JSON_pack_time_rel ("duration",
    303                                ptfh->duration),
    304     GNUNET_JSON_pack_time_rel ("validity_granularity",
    305                                ptfh->validity_granularity),
    306     GNUNET_JSON_pack_time_rel ("start_offset",
    307                                ptfh->start_offset),
    308     GNUNET_JSON_pack_string ("kind",
    309                              ptfh->kind));
    310   eh = TALER_MERCHANT_curl_easy_get_ (ptfh->url);
    311   if ( (NULL == eh) ||
    312        (GNUNET_OK !=
    313         TALER_curl_easy_post (&ptfh->post_ctx,
    314                               eh,
    315                               req_obj)) )
    316   {
    317     GNUNET_break (0);
    318     json_decref (req_obj);
    319     if (NULL != eh)
    320       curl_easy_cleanup (eh);
    321     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    322   }
    323   json_decref (req_obj);
    324   ptfh->job = GNUNET_CURL_job_add2 (ptfh->ctx,
    325                                     eh,
    326                                     ptfh->post_ctx.headers,
    327                                     &handle_post_tokenfamilies_finished,
    328                                     ptfh);
    329   if (NULL == ptfh->job)
    330     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    331   return TALER_EC_NONE;
    332 }
    333 
    334 
    335 void
    336 TALER_MERCHANT_post_private_tokenfamilies_cancel (
    337   struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle *ptfh)
    338 {
    339   if (NULL != ptfh->job)
    340   {
    341     GNUNET_CURL_job_cancel (ptfh->job);
    342     ptfh->job = NULL;
    343   }
    344   TALER_curl_easy_post_finished (&ptfh->post_ctx);
    345   json_decref (ptfh->description_i18n);
    346   json_decref (ptfh->extra_data);
    347   GNUNET_free (ptfh->slug);
    348   GNUNET_free (ptfh->name);
    349   GNUNET_free (ptfh->description);
    350   GNUNET_free (ptfh->kind);
    351   GNUNET_free (ptfh->url);
    352   GNUNET_free (ptfh->base_url);
    353   GNUNET_free (ptfh);
    354 }
    355 
    356 
    357 /* end of merchant_api_post-private-tokenfamilies-new.c */