donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

donau_api_charity_post.c (6704B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2024 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it
      6   under the terms of the GNU General Public License as published
      7   by the Free Software Foundation; either version 3, or (at your
      8   option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful, but
     11   WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14 
     15   You should have received a copy of the GNU General Public
     16   License along with TALER; see the file COPYING.  If not, see
     17   <http://www.gnu.org/licenses/>
     18 */
     19 
     20 /**
     21  * @file lib/donau_api_charity_post.c
     22  * @brief Implementation of the "handle" component of the donau's HTTP API
     23  * @author Lukas Matyja
     24  */
     25 #include <gnunet/gnunet_curl_lib.h>
     26 #include <taler/taler_json_lib.h>
     27 #include <taler/taler_curl_lib.h>
     28 #include "donau_service.h"
     29 #include "donau_api_curl_defaults.h"
     30 #include "donau_json_lib.h"
     31 
     32 
     33 /**
     34  * Handle for a POST /charities request.
     35  */
     36 struct DONAU_CharityPostHandle
     37 {
     38   /**
     39    * The url for the /charities request.
     40    */
     41   char *url;
     42 
     43   /**
     44    * Minor context that holds body and headers.
     45    */
     46   struct TALER_CURL_PostContext post_ctx;
     47 
     48   /**
     49    * Entry for this request with the `struct GNUNET_CURL_Context`.
     50    */
     51   struct GNUNET_CURL_Job *job;
     52 
     53   /**
     54    * Function to call with the result.
     55    */
     56   DONAU_PostCharityResponseCallback cb;
     57 
     58   /**
     59    * Closure to pass to @e cb.
     60    */
     61   void *cb_cls;
     62 
     63   /**
     64    * Reference to the execution context.
     65    */
     66   struct GNUNET_CURL_Context *ctx;
     67 
     68 };
     69 
     70 /**
     71  * Function called when we're done processing the
     72  * HTTP POST /charities request.
     73  *
     74  * @param cls the `struct KeysRequest`
     75  * @param response_code HTTP response code, 0 on error
     76  * @param resp_obj parsed JSON result, NULL on error
     77  */
     78 static void
     79 handle_charity_post_finished (void *cls,
     80                               long response_code,
     81                               const void *resp_obj)
     82 {
     83   struct DONAU_CharityPostHandle *cph = cls;
     84   const json_t *j = resp_obj;
     85 
     86   struct DONAU_PostCharityResponse pcresp = {
     87     .hr.reply = j,
     88     .hr.http_status = (unsigned int) response_code
     89   };
     90 
     91   cph->job = NULL;
     92   switch (response_code)
     93   {
     94   case MHD_HTTP_CREATED:
     95     {
     96       struct GNUNET_JSON_Specification spec[] = {
     97         GNUNET_JSON_spec_uint64 ("charity_id",
     98                                  &pcresp.details.ok.charity_id),
     99         GNUNET_JSON_spec_end ()
    100       };
    101 
    102       if (GNUNET_OK !=
    103           GNUNET_JSON_parse (j,
    104                              spec,
    105                              NULL,
    106                              NULL))
    107       {
    108         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    109                     "Could not parse response from charity POST\n");
    110         GNUNET_break_op (0);
    111         pcresp.hr.http_status = 0;
    112         pcresp.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
    113       }
    114     }
    115     break;
    116   case MHD_HTTP_FORBIDDEN:
    117     pcresp.hr.ec = TALER_JSON_get_error_code (j);
    118     pcresp.hr.hint = TALER_JSON_get_error_hint (j);
    119     break;
    120   case MHD_HTTP_NOT_FOUND:
    121     pcresp.hr.ec = TALER_JSON_get_error_code (j);
    122     pcresp.hr.hint = TALER_JSON_get_error_hint (j);
    123     break;
    124   case MHD_HTTP_CONFLICT:
    125     pcresp.hr.ec = TALER_JSON_get_error_code (j);
    126     pcresp.hr.hint = TALER_JSON_get_error_hint (j);
    127     break;
    128   default:
    129     /* unexpected response code */
    130     GNUNET_break_op (0);
    131     pcresp.hr.ec = TALER_JSON_get_error_code (j);
    132     pcresp.hr.hint = TALER_JSON_get_error_hint (j);
    133     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    134                 "Unexpected response code %u/%d for POST %s\n",
    135                 (unsigned int) response_code,
    136                 (int) pcresp.hr.ec,
    137                 cph->url);
    138     break;
    139   }
    140   if (NULL != cph->cb)
    141   {
    142     cph->cb (cph->cb_cls,
    143              &pcresp);
    144     cph->cb = NULL;
    145   }
    146   DONAU_charity_post_cancel (cph);
    147 }
    148 
    149 
    150 struct DONAU_CharityPostHandle *
    151 DONAU_charity_post (
    152   struct GNUNET_CURL_Context *ctx,
    153   const char *url,
    154   const char *charity_name,
    155   const char *charity_url,
    156   const struct TALER_Amount *max_per_year,
    157   const struct DONAU_CharityPublicKeyP *charity_pub,
    158   const struct DONAU_BearerToken *bearer,
    159   DONAU_PostCharityResponseCallback cb,
    160   void *cb_cls)
    161 {
    162   struct DONAU_CharityPostHandle *cph;
    163   CURL *eh;
    164   json_t *body;
    165 
    166   TALER_LOG_DEBUG ("Connecting to the donau (%s)\n",
    167                    url);
    168   cph = GNUNET_new (struct DONAU_CharityPostHandle);
    169   cph->cb = cb;
    170   cph->cb_cls = cb_cls;
    171   cph->ctx = ctx;
    172   cph->url = TALER_url_join (url,
    173                              "charities",
    174                              NULL);
    175   if (NULL == cph->url)
    176   {
    177     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    178                 "Could not construct request URL.\n");
    179     GNUNET_free (cph);
    180     return NULL;
    181   }
    182   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    183               "POST a charity with URL `%s'.\n",
    184               cph->url);
    185   body = GNUNET_JSON_PACK (
    186     GNUNET_JSON_pack_data_auto ("charity_pub",
    187                                 charity_pub),
    188     GNUNET_JSON_pack_string ("charity_url",
    189                              charity_url),
    190     GNUNET_JSON_pack_string ("charity_name",
    191                              charity_name),
    192     TALER_JSON_pack_amount ("max_per_year",
    193                             max_per_year));
    194   eh = DONAU_curl_easy_get_ (cph->url);
    195   if ( (NULL == eh) ||
    196        (GNUNET_OK !=
    197         TALER_curl_easy_post (&cph->post_ctx,
    198                               eh,
    199                               body)) )
    200   {
    201     GNUNET_break (0);
    202     if (NULL != eh)
    203       curl_easy_cleanup (eh);
    204     json_decref (body);
    205     GNUNET_free (cph->url);
    206     GNUNET_free (cph);
    207     return NULL;
    208   }
    209   json_decref (body);
    210   cph->job = GNUNET_CURL_job_add2 (ctx,
    211                                    eh,
    212                                    cph->post_ctx.headers,
    213                                    &handle_charity_post_finished,
    214                                    cph);
    215   GNUNET_assert (NULL != cph->job);
    216   if (NULL != bearer)
    217   {
    218     struct curl_slist *auth;
    219     char *hdr;
    220 
    221     GNUNET_asprintf (&hdr,
    222                      "%s: Bearer %s",
    223                      MHD_HTTP_HEADER_AUTHORIZATION,
    224                      bearer->token);
    225     auth = curl_slist_append (NULL,
    226                               hdr);
    227     GNUNET_free (hdr);
    228     GNUNET_CURL_extend_headers (cph->job,
    229                                 auth);
    230     curl_slist_free_all (auth);
    231   }
    232   return cph;
    233 }
    234 
    235 
    236 void
    237 DONAU_charity_post_cancel (
    238   struct DONAU_CharityPostHandle *cph)
    239 {
    240   if (NULL != cph->job)
    241   {
    242     GNUNET_CURL_job_cancel (cph->job);
    243     cph->job = NULL;
    244   }
    245   TALER_curl_easy_post_finished (&cph->post_ctx);
    246   GNUNET_free (cph->url);
    247   GNUNET_free (cph);
    248 }