merchant_api_patch-private-fountains-FOUNTAIN_ID.c (9100B)
1 /* 2 This file is part of TALER 3 Copyright (C) 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 src/lib/merchant_api_patch-private-fountains-FOUNTAIN_ID.c 21 * @brief Implementation of the PATCH /private/fountains/$FOUNTAIN_ID request 22 * @author Bohdan Potuzhnyi 23 */ 24 #include "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/merchant/patch-private-fountains-FOUNTAIN_ID.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 PATCH /private/fountains/$FOUNTAIN_ID operation. 39 */ 40 struct TALER_MERCHANT_PatchPrivateFountainHandle 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 * Fountain identifier. 54 */ 55 char *fountain_id; 56 57 /** 58 * Handle for the request. 59 */ 60 struct GNUNET_CURL_Job *job; 61 62 /** 63 * Function to call with the result. 64 */ 65 TALER_MERCHANT_PatchPrivateFountainCallback cb; 66 67 /** 68 * Closure for @a cb. 69 */ 70 TALER_MERCHANT_PATCH_PRIVATE_FOUNTAIN_RESULT_CLOSURE *cb_cls; 71 72 /** 73 * Reference to the execution context. 74 */ 75 struct GNUNET_CURL_Context *ctx; 76 77 /** 78 * Minor context that holds body and headers. 79 */ 80 struct TALER_CURL_PostContext post_ctx; 81 82 /** 83 * Request body being assembled from the options. 84 */ 85 json_t *req_obj; 86 }; 87 88 89 /** 90 * Function called when we're done processing the 91 * HTTP PATCH /private/fountains/$FOUNTAIN_ID request. 92 * 93 * @param cls the `struct TALER_MERCHANT_PatchPrivateFountainHandle` 94 * @param response_code HTTP response code, 0 on error 95 * @param response response body, NULL if not in JSON 96 */ 97 static void 98 handle_patch_fountain_finished (void *cls, 99 long response_code, 100 const void *response) 101 { 102 struct TALER_MERCHANT_PatchPrivateFountainHandle *ppfh = cls; 103 const json_t *json = response; 104 struct TALER_MERCHANT_PatchPrivateFountainResponse pfr = { 105 .hr.http_status = (unsigned int) response_code, 106 .hr.reply = json 107 }; 108 109 ppfh->job = NULL; 110 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 111 "PATCH /private/fountains/$ID completed with response code %u\n", 112 (unsigned int) response_code); 113 switch (response_code) 114 { 115 case 0: 116 pfr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 117 break; 118 case MHD_HTTP_NO_CONTENT: 119 break; 120 case MHD_HTTP_BAD_REQUEST: 121 case MHD_HTTP_UNAUTHORIZED: 122 case MHD_HTTP_FORBIDDEN: 123 case MHD_HTTP_NOT_FOUND: 124 case MHD_HTTP_INTERNAL_SERVER_ERROR: 125 pfr.hr.ec = TALER_JSON_get_error_code (json); 126 pfr.hr.hint = TALER_JSON_get_error_hint (json); 127 break; 128 default: 129 TALER_MERCHANT_parse_error_details_ (json, 130 response_code, 131 &pfr.hr); 132 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 133 "Unexpected response code %u/%d\n", 134 (unsigned int) response_code, 135 (int) pfr.hr.ec); 136 GNUNET_break_op (0); 137 break; 138 } 139 ppfh->cb (ppfh->cb_cls, 140 &pfr); 141 TALER_MERCHANT_patch_private_fountain_cancel (ppfh); 142 } 143 144 145 struct TALER_MERCHANT_PatchPrivateFountainHandle * 146 TALER_MERCHANT_patch_private_fountain_create ( 147 struct GNUNET_CURL_Context *ctx, 148 const char *url, 149 const char *fountain_id) 150 { 151 struct TALER_MERCHANT_PatchPrivateFountainHandle *ppfh; 152 153 ppfh = GNUNET_new (struct TALER_MERCHANT_PatchPrivateFountainHandle); 154 ppfh->ctx = ctx; 155 ppfh->base_url = GNUNET_strdup (url); 156 ppfh->fountain_id = GNUNET_strdup (fountain_id); 157 ppfh->req_obj = json_object (); 158 GNUNET_assert (NULL != ppfh->req_obj); 159 return ppfh; 160 } 161 162 163 enum GNUNET_GenericReturnValue 164 TALER_MERCHANT_patch_private_fountain_set_options_ ( 165 struct TALER_MERCHANT_PatchPrivateFountainHandle *ppfh, 166 unsigned int num_options, 167 const struct TALER_MERCHANT_PatchPrivateFountainOptionValue *options) 168 { 169 for (unsigned int i = 0; i < num_options; i++) 170 { 171 switch (options[i].option) 172 { 173 case TALER_MERCHANT_PATCH_PRIVATE_FOUNTAIN_OPTION_END: 174 return GNUNET_OK; 175 case TALER_MERCHANT_PATCH_PRIVATE_FOUNTAIN_OPTION_DESCRIPTION: 176 GNUNET_assert (0 == 177 json_object_set_new ( 178 ppfh->req_obj, 179 "description", 180 json_string (options[i].details.description))); 181 break; 182 case TALER_MERCHANT_PATCH_PRIVATE_FOUNTAIN_OPTION_POLL_FREQ: 183 GNUNET_assert (0 == 184 json_object_set_new ( 185 ppfh->req_obj, 186 "poll_freq", 187 GNUNET_JSON_from_time_rel ( 188 options[i].details.poll_freq))); 189 break; 190 case TALER_MERCHANT_PATCH_PRIVATE_FOUNTAIN_OPTION_GRANTS: 191 { 192 json_t *jgrants; 193 194 jgrants = json_array (); 195 GNUNET_assert (NULL != jgrants); 196 for (unsigned int j = 0; 197 j < options[i].details.grants.num_grants; 198 j++) 199 { 200 const struct TALER_MERCHANT_FountainGrant *fg 201 = &options[i].details.grants.grants[j]; 202 203 GNUNET_assert (0 == 204 json_array_append_new ( 205 jgrants, 206 GNUNET_JSON_PACK ( 207 GNUNET_JSON_pack_string ( 208 "token_family_slug", 209 fg->token_family_slug), 210 GNUNET_JSON_pack_uint64 ( 211 "tokens_per_period_limit", 212 fg->tokens_per_period_limit), 213 GNUNET_JSON_pack_uint64 ( 214 "tokens_per_period_stash", 215 fg->tokens_per_period_stash), 216 GNUNET_JSON_pack_uint64 ( 217 "key_window_size", 218 fg->key_window_size)))); 219 } 220 GNUNET_assert (0 == 221 json_object_set_new (ppfh->req_obj, 222 "grants", 223 jgrants)); 224 break; 225 } 226 default: 227 GNUNET_break (0); 228 return GNUNET_SYSERR; 229 } 230 } 231 return GNUNET_OK; 232 } 233 234 235 enum TALER_ErrorCode 236 TALER_MERCHANT_patch_private_fountain_start ( 237 struct TALER_MERCHANT_PatchPrivateFountainHandle *ppfh, 238 TALER_MERCHANT_PatchPrivateFountainCallback cb, 239 TALER_MERCHANT_PATCH_PRIVATE_FOUNTAIN_RESULT_CLOSURE *cb_cls) 240 { 241 CURL *eh; 242 243 ppfh->cb = cb; 244 ppfh->cb_cls = cb_cls; 245 { 246 char *path; 247 248 GNUNET_asprintf (&path, 249 "private/fountains/%s", 250 ppfh->fountain_id); 251 ppfh->url = TALER_url_join (ppfh->base_url, 252 path, 253 NULL); 254 GNUNET_free (path); 255 } 256 if (NULL == ppfh->url) 257 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 258 eh = TALER_MERCHANT_curl_easy_get_ (ppfh->url); 259 if ( (NULL == eh) || 260 (GNUNET_OK != 261 TALER_curl_easy_post (&ppfh->post_ctx, 262 eh, 263 ppfh->req_obj)) ) 264 { 265 GNUNET_break (0); 266 if (NULL != eh) 267 curl_easy_cleanup (eh); 268 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 269 } 270 GNUNET_assert (CURLE_OK == 271 curl_easy_setopt (eh, 272 CURLOPT_CUSTOMREQUEST, 273 MHD_HTTP_METHOD_PATCH)); 274 ppfh->job = GNUNET_CURL_job_add2 (ppfh->ctx, 275 eh, 276 ppfh->post_ctx.headers, 277 &handle_patch_fountain_finished, 278 ppfh); 279 if (NULL == ppfh->job) 280 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 281 return TALER_EC_NONE; 282 } 283 284 285 void 286 TALER_MERCHANT_patch_private_fountain_cancel ( 287 struct TALER_MERCHANT_PatchPrivateFountainHandle *ppfh) 288 { 289 if (NULL != ppfh->job) 290 { 291 GNUNET_CURL_job_cancel (ppfh->job); 292 ppfh->job = NULL; 293 } 294 TALER_curl_easy_post_finished (&ppfh->post_ctx); 295 json_decref (ppfh->req_obj); 296 GNUNET_free (ppfh->fountain_id); 297 GNUNET_free (ppfh->url); 298 GNUNET_free (ppfh->base_url); 299 GNUNET_free (ppfh); 300 } 301 302 303 /* end of merchant_api_patch-private-fountains-FOUNTAIN_ID.c */