donau

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

donau_api_charity_patch.c (6636B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2025 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_patch.c
     22  * @brief Implementation of the PATCH /charities/$ID call for the donau HTTP API
     23  * @author Bohdan Potuzhnyi
     24  */
     25 #include <jansson.h>
     26 #include <microhttpd.h>
     27 #include <gnunet/gnunet_curl_lib.h>
     28 #include <taler/taler_curl_lib.h>
     29 #include <taler/taler_json_lib.h>
     30 #include "donau_service.h"
     31 #include "donau_api_curl_defaults.h"
     32 #include "donau_json_lib.h"
     33 
     34 
     35 /**
     36  * Handle for a PATCH /charities/$ID request.
     37  */
     38 struct DONAU_CharityPatchHandle
     39 {
     40   /**
     41    * Fully qualified request URL.
     42    */
     43   char *url;
     44 
     45   /**
     46    * CURL job for the request.
     47    */
     48   struct GNUNET_CURL_Job *job;
     49 
     50   /**
     51    * Callback for the response.
     52    */
     53   DONAU_PatchCharityResponseCallback cb;
     54 
     55   /**
     56    * Closure for @e cb.
     57    */
     58   void *cb_cls;
     59 
     60   /**
     61    * Reference to the CURL context.
     62    */
     63   struct GNUNET_CURL_Context *ctx;
     64 
     65   /**
     66    * Helper context for POST-style uploads.
     67    */
     68   struct TALER_CURL_PostContext post_ctx;
     69 };
     70 
     71 
     72 /**
     73  * Finalizer called once the PATCH request is complete.
     74  */
     75 static void
     76 handle_charity_patch_finished (void *cls,
     77                                long response_code,
     78                                const void *resp_obj)
     79 {
     80   struct DONAU_CharityPatchHandle *cph = cls;
     81   const json_t *j = resp_obj;
     82   struct DONAU_PatchCharityResponse pcresp = {
     83     .hr.reply = j,
     84     .hr.http_status = (unsigned int) response_code
     85   };
     86 
     87   cph->job = NULL;
     88   switch (response_code)
     89   {
     90   case 0:
     91     pcresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     92     GNUNET_break (0);
     93     break;
     94   case MHD_HTTP_OK:
     95   case MHD_HTTP_NO_CONTENT:
     96     /* nothing further to parse */
     97     break;
     98   case MHD_HTTP_BAD_REQUEST:
     99   case MHD_HTTP_NOT_FOUND:
    100   case MHD_HTTP_FORBIDDEN:
    101   case MHD_HTTP_UNAUTHORIZED:
    102   case MHD_HTTP_CONFLICT:
    103   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    104     pcresp.hr.ec = TALER_JSON_get_error_code (j);
    105     pcresp.hr.hint = TALER_JSON_get_error_hint (j);
    106     break;
    107   default:
    108     pcresp.hr.ec = TALER_JSON_get_error_code (j);
    109     pcresp.hr.hint = TALER_JSON_get_error_hint (j);
    110     GNUNET_break_op (0);
    111     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    112                 "Unexpected response code %ld for PATCH %s\n",
    113                 response_code,
    114                 cph->url);
    115     break;
    116   }
    117 
    118   if (NULL != cph->cb)
    119   {
    120     cph->cb (cph->cb_cls,
    121              &pcresp);
    122     cph->cb = NULL;
    123   }
    124   DONAU_charity_patch_cancel (cph);
    125 }
    126 
    127 
    128 struct DONAU_CharityPatchHandle *
    129 DONAU_charity_patch (
    130   struct GNUNET_CURL_Context *ctx,
    131   const char *url,
    132   const uint64_t charity_id,
    133   const char *charity_name,
    134   const char *charity_url,
    135   const struct TALER_Amount *max_per_year,
    136   const struct DONAU_CharityPublicKeyP *charity_pub,
    137   const struct DONAU_BearerToken *bearer,
    138   DONAU_PatchCharityResponseCallback cb,
    139   void *cb_cls)
    140 {
    141   struct DONAU_CharityPatchHandle *cph;
    142   CURL *eh;
    143   json_t *body;
    144 
    145   if ( (NULL == charity_name) ||
    146        (NULL == charity_url) ||
    147        (NULL == max_per_year) ||
    148        (NULL == charity_pub) )
    149   {
    150     /* Caller must provide the complete CharityRequest payload. */
    151     GNUNET_break_op (0);
    152     return NULL;
    153   }
    154 
    155   body = GNUNET_JSON_PACK (
    156     GNUNET_JSON_pack_data_auto ("charity_pub",
    157                                 charity_pub),
    158     GNUNET_JSON_pack_string ("charity_url",
    159                              charity_url),
    160     GNUNET_JSON_pack_string ("charity_name",
    161                              charity_name),
    162     TALER_JSON_pack_amount ("max_per_year",
    163                             max_per_year));
    164   if (NULL == body)
    165   {
    166     GNUNET_break (0);
    167     return NULL;
    168   }
    169 
    170   cph = GNUNET_new (struct DONAU_CharityPatchHandle);
    171   cph->ctx = ctx;
    172   cph->cb = cb;
    173   cph->cb_cls = cb_cls;
    174 
    175   {
    176     char *path;
    177 
    178     GNUNET_asprintf (&path,
    179                      "charities/%llu",
    180                      (unsigned long long) charity_id);
    181     cph->url = TALER_url_join (url,
    182                                path,
    183                                NULL);
    184     GNUNET_free (path);
    185   }
    186   if (NULL == cph->url)
    187   {
    188     json_decref (body);
    189     GNUNET_free (cph);
    190     GNUNET_break (0);
    191     return NULL;
    192   }
    193 
    194   eh = DONAU_curl_easy_get_ (cph->url);
    195   if (NULL == eh)
    196   {
    197     json_decref (body);
    198     GNUNET_free (cph->url);
    199     GNUNET_free (cph);
    200     GNUNET_break (0);
    201     return NULL;
    202   }
    203   if (GNUNET_OK !=
    204       TALER_curl_easy_post (&cph->post_ctx,
    205                             eh,
    206                             body))
    207   {
    208     GNUNET_break (0);
    209     curl_easy_cleanup (eh);
    210     json_decref (body);
    211     GNUNET_free (cph->url);
    212     GNUNET_free (cph);
    213     return NULL;
    214   }
    215   json_decref (body);
    216   GNUNET_assert (CURLE_OK ==
    217                  curl_easy_setopt (eh,
    218                                    CURLOPT_CUSTOMREQUEST,
    219                                    MHD_HTTP_METHOD_PATCH));
    220   cph->job = GNUNET_CURL_job_add2 (ctx,
    221                                    eh,
    222                                    cph->post_ctx.headers,
    223                                    &handle_charity_patch_finished,
    224                                    cph);
    225   if (NULL == cph->job)
    226   {
    227     GNUNET_break (0);
    228     TALER_curl_easy_post_finished (&cph->post_ctx);
    229     curl_easy_cleanup (eh);
    230     GNUNET_free (cph->url);
    231     GNUNET_free (cph);
    232     return NULL;
    233   }
    234 
    235   if (NULL != bearer)
    236   {
    237     struct curl_slist *auth;
    238     char *hdr;
    239 
    240     GNUNET_asprintf (&hdr,
    241                      "%s: Bearer %s",
    242                      MHD_HTTP_HEADER_AUTHORIZATION,
    243                      bearer->token);
    244     auth = curl_slist_append (NULL,
    245                               hdr);
    246     GNUNET_free (hdr);
    247     GNUNET_CURL_extend_headers (cph->job,
    248                                 auth);
    249     curl_slist_free_all (auth);
    250   }
    251 
    252   return cph;
    253 }
    254 
    255 
    256 void
    257 DONAU_charity_patch_cancel (
    258   struct DONAU_CharityPatchHandle *cph)
    259 {
    260   if (NULL == cph)
    261     return;
    262   if (NULL != cph->job)
    263   {
    264     GNUNET_CURL_job_cancel (cph->job);
    265     cph->job = NULL;
    266   }
    267   TALER_curl_easy_post_finished (&cph->post_ctx);
    268   GNUNET_free (cph->url);
    269   GNUNET_free (cph);
    270 }
    271 
    272 
    273 /* end of donau_api_charity_patch.c */