donau

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

donau_api_charity_post.c (6623B)


      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       }
    112     }
    113     break;
    114   case MHD_HTTP_FORBIDDEN:
    115     pcresp.hr.ec = TALER_JSON_get_error_code (j);
    116     pcresp.hr.hint = TALER_JSON_get_error_hint (j);
    117     break;
    118   case MHD_HTTP_NOT_FOUND:
    119     pcresp.hr.ec = TALER_JSON_get_error_code (j);
    120     pcresp.hr.hint = TALER_JSON_get_error_hint (j);
    121     break;
    122   case MHD_HTTP_CONFLICT:
    123     pcresp.hr.ec = TALER_JSON_get_error_code (j);
    124     pcresp.hr.hint = TALER_JSON_get_error_hint (j);
    125     break;
    126   default:
    127     /* unexpected response code */
    128     GNUNET_break_op (0);
    129     pcresp.hr.ec = TALER_JSON_get_error_code (j);
    130     pcresp.hr.hint = TALER_JSON_get_error_hint (j);
    131     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    132                 "Unexpected response code %u/%d for POST %s\n",
    133                 (unsigned int) response_code,
    134                 (int) pcresp.hr.ec,
    135                 cph->url);
    136     break;
    137   }
    138   if (NULL != cph->cb)
    139   {
    140     cph->cb (cph->cb_cls,
    141              &pcresp);
    142     cph->cb = NULL;
    143   }
    144   DONAU_charity_post_cancel (cph);
    145 }
    146 
    147 
    148 struct DONAU_CharityPostHandle *
    149 DONAU_charity_post (
    150   struct GNUNET_CURL_Context *ctx,
    151   const char *url,
    152   const char *charity_name,
    153   const char *charity_url,
    154   const struct TALER_Amount *max_per_year,
    155   const struct DONAU_CharityPublicKeyP *charity_pub,
    156   const struct DONAU_BearerToken *bearer,
    157   DONAU_PostCharityResponseCallback cb,
    158   void *cb_cls)
    159 {
    160   struct DONAU_CharityPostHandle *cph;
    161   CURL *eh;
    162   json_t *body;
    163 
    164   TALER_LOG_DEBUG ("Connecting to the donau (%s)\n",
    165                    url);
    166   cph = GNUNET_new (struct DONAU_CharityPostHandle);
    167   cph->url = GNUNET_strdup (url);
    168   cph->cb = cb;
    169   cph->cb_cls = cb_cls;
    170   cph->ctx = ctx;
    171   cph->url = TALER_url_join (url,
    172                              "charities",
    173                              NULL);
    174   if (NULL == cph->url)
    175   {
    176     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    177                 "Could not construct request URL.\n");
    178     GNUNET_free (cph);
    179     return NULL;
    180   }
    181   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    182               "POST a charity with URL `%s'.\n",
    183               cph->url);
    184   body = GNUNET_JSON_PACK (
    185     GNUNET_JSON_pack_data_auto ("charity_pub",
    186                                 charity_pub),
    187     GNUNET_JSON_pack_string ("charity_url",
    188                              charity_url),
    189     GNUNET_JSON_pack_string ("charity_name",
    190                              charity_name),
    191     TALER_JSON_pack_amount ("max_per_year",
    192                             max_per_year));
    193   eh = DONAU_curl_easy_get_ (cph->url);
    194   if ( (NULL == eh) ||
    195        (GNUNET_OK !=
    196         TALER_curl_easy_post (&cph->post_ctx,
    197                               eh,
    198                               body)) )
    199   {
    200     GNUNET_break (0);
    201     if (NULL != eh)
    202       curl_easy_cleanup (eh);
    203     json_decref (body);
    204     GNUNET_free (cph->url);
    205     return NULL;
    206   }
    207   json_decref (body);
    208   cph->job = GNUNET_CURL_job_add2 (ctx,
    209                                    eh,
    210                                    cph->post_ctx.headers,
    211                                    &handle_charity_post_finished,
    212                                    cph);
    213   GNUNET_assert (NULL != cph->job);
    214   if (NULL != bearer)
    215   {
    216     struct curl_slist *auth;
    217     char *hdr;
    218 
    219     GNUNET_asprintf (&hdr,
    220                      "%s: Bearer %s",
    221                      MHD_HTTP_HEADER_AUTHORIZATION,
    222                      bearer->token);
    223     auth = curl_slist_append (NULL,
    224                               hdr);
    225     GNUNET_free (hdr);
    226     GNUNET_CURL_extend_headers (cph->job,
    227                                 auth);
    228     curl_slist_free_all (auth);
    229   }
    230   return cph;
    231 }
    232 
    233 
    234 void
    235 DONAU_charity_post_cancel (
    236   struct DONAU_CharityPostHandle *cph)
    237 {
    238   if (NULL != cph->job)
    239   {
    240     GNUNET_CURL_job_cancel (cph->job);
    241     cph->job = NULL;
    242   }
    243   TALER_curl_easy_post_finished (&cph->post_ctx);
    244   GNUNET_free (cph->url);
    245   GNUNET_free (cph);
    246 }