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 */