merchant_api_patch-management-instances-INSTANCE.c (13341B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2020-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 merchant_api_patch-management-instances-INSTANCE-new.c 21 * @brief Implementation of the PATCH /management/instances/$INSTANCE request 22 * @author Christian Grothoff 23 */ 24 #include "taler/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/taler-merchant/patch-management-instances-INSTANCE.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 /management/instances/$INSTANCE operation. 39 */ 40 struct TALER_MERCHANT_PatchManagementInstancesHandle 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 * Handle for the request. 54 */ 55 struct GNUNET_CURL_Job *job; 56 57 /** 58 * Function to call with the result. 59 */ 60 TALER_MERCHANT_PatchManagementInstancesCallback cb; 61 62 /** 63 * Closure for @a cb. 64 */ 65 TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_RESULT_CLOSURE *cb_cls; 66 67 /** 68 * Reference to the execution context. 69 */ 70 struct GNUNET_CURL_Context *ctx; 71 72 /** 73 * Minor context that holds body and headers. 74 */ 75 struct TALER_CURL_PostContext post_ctx; 76 77 /** 78 * Instance identifier. 79 */ 80 char *instance_id; 81 82 /** 83 * Human-readable name for the instance. 84 */ 85 char *name; 86 87 /** 88 * Address (JSON). 89 */ 90 json_t *address; 91 92 /** 93 * Jurisdiction (JSON). 94 */ 95 json_t *jurisdiction; 96 97 /** 98 * Whether to use STEFAN curves for fee calculations. 99 */ 100 bool use_stefan; 101 102 /** 103 * Default wire transfer delay (optional). 104 */ 105 struct GNUNET_TIME_Relative default_wire_transfer_delay; 106 107 /** 108 * Default payment deadline (optional). 109 */ 110 struct GNUNET_TIME_Relative default_pay_delay; 111 112 /** 113 * Default refund deadline (optional). 114 */ 115 struct GNUNET_TIME_Relative default_refund_delay; 116 117 /** 118 * Default wire transfer rounding interval (optional). 119 */ 120 enum GNUNET_TIME_RounderInterval default_wire_transfer_rounding_interval; 121 122 /** 123 * Email address (optional). 124 */ 125 char *email; 126 127 /** 128 * Phone number (optional). 129 */ 130 char *phone_number; 131 132 /** 133 * Website URL (optional). 134 */ 135 char *website; 136 137 /** 138 * Logo (optional). 139 */ 140 char *logo; 141 142 /** 143 * Whether default_pay_delay was set. 144 */ 145 bool have_default_pay_delay; 146 147 /** 148 * Whether default_refund_delay was set. 149 */ 150 bool have_default_refund_delay; 151 152 /** 153 * Whether default_wire_transfer_delay was set. 154 */ 155 bool have_default_wire_transfer_delay; 156 157 /** 158 * Whether default_wire_transfer_rounding_interval was set. 159 */ 160 bool have_default_wire_transfer_rounding_interval; 161 }; 162 163 164 /** 165 * Function called when we're done processing the 166 * HTTP PATCH /management/instances/$INSTANCE request. 167 * 168 * @param cls the `struct TALER_MERCHANT_PatchManagementInstancesHandle` 169 * @param response_code HTTP response code, 0 on error 170 * @param response response body, NULL if not in JSON 171 */ 172 static void 173 handle_patch_management_instances_finished (void *cls, 174 long response_code, 175 const void *response) 176 { 177 struct TALER_MERCHANT_PatchManagementInstancesHandle *pmih = cls; 178 const json_t *json = response; 179 struct TALER_MERCHANT_PatchManagementInstancesResponse pmir = { 180 .hr.http_status = (unsigned int) response_code, 181 .hr.reply = json 182 }; 183 184 pmih->job = NULL; 185 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 186 "PATCH /management/instances/$INSTANCE completed with response code %u\n", 187 (unsigned int) response_code); 188 switch (response_code) 189 { 190 case 0: 191 pmir.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 192 break; 193 case MHD_HTTP_NO_CONTENT: 194 break; 195 case MHD_HTTP_BAD_REQUEST: 196 pmir.hr.ec = TALER_JSON_get_error_code (json); 197 pmir.hr.hint = TALER_JSON_get_error_hint (json); 198 break; 199 case MHD_HTTP_UNAUTHORIZED: 200 pmir.hr.ec = TALER_JSON_get_error_code (json); 201 pmir.hr.hint = TALER_JSON_get_error_hint (json); 202 break; 203 case MHD_HTTP_FORBIDDEN: 204 pmir.hr.ec = TALER_JSON_get_error_code (json); 205 pmir.hr.hint = TALER_JSON_get_error_hint (json); 206 break; 207 case MHD_HTTP_NOT_FOUND: 208 pmir.hr.ec = TALER_JSON_get_error_code (json); 209 pmir.hr.hint = TALER_JSON_get_error_hint (json); 210 break; 211 case MHD_HTTP_CONFLICT: 212 pmir.hr.ec = TALER_JSON_get_error_code (json); 213 pmir.hr.hint = TALER_JSON_get_error_hint (json); 214 break; 215 case MHD_HTTP_INTERNAL_SERVER_ERROR: 216 pmir.hr.ec = TALER_JSON_get_error_code (json); 217 pmir.hr.hint = TALER_JSON_get_error_hint (json); 218 break; 219 default: 220 TALER_MERCHANT_parse_error_details_ (json, 221 response_code, 222 &pmir.hr); 223 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 224 "Unexpected response code %u/%d\n", 225 (unsigned int) response_code, 226 (int) pmir.hr.ec); 227 GNUNET_break_op (0); 228 break; 229 } 230 pmih->cb (pmih->cb_cls, 231 &pmir); 232 TALER_MERCHANT_patch_management_instances_cancel (pmih); 233 } 234 235 236 struct TALER_MERCHANT_PatchManagementInstancesHandle * 237 TALER_MERCHANT_patch_management_instances_create ( 238 struct GNUNET_CURL_Context *ctx, 239 const char *url, 240 const char *instance_id, 241 const char *name, 242 const json_t *address, 243 const json_t *jurisdiction, 244 bool use_stefan) 245 { 246 struct TALER_MERCHANT_PatchManagementInstancesHandle *pmih; 247 248 pmih = GNUNET_new (struct TALER_MERCHANT_PatchManagementInstancesHandle); 249 pmih->ctx = ctx; 250 pmih->base_url = GNUNET_strdup (url); 251 pmih->instance_id = GNUNET_strdup (instance_id); 252 pmih->name = GNUNET_strdup (name); 253 pmih->address = json_incref ((json_t *) address); 254 pmih->jurisdiction = json_incref ((json_t *) jurisdiction); 255 pmih->use_stefan = use_stefan; 256 return pmih; 257 } 258 259 260 enum GNUNET_GenericReturnValue 261 TALER_MERCHANT_patch_management_instances_set_options_ ( 262 struct TALER_MERCHANT_PatchManagementInstancesHandle *pmih, 263 unsigned int num_options, 264 const struct TALER_MERCHANT_PatchManagementInstancesOptionValue *options) 265 { 266 for (unsigned int i = 0; i < num_options; i++) 267 { 268 switch (options[i].option) 269 { 270 case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_END: 271 return GNUNET_OK; 272 case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_DEFAULT_PAY_DELAY: 273 pmih->default_pay_delay = options[i].details.default_pay_delay; 274 pmih->have_default_pay_delay = true; 275 break; 276 case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_DEFAULT_REFUND_DELAY: 277 pmih->default_refund_delay = options[i].details.default_refund_delay; 278 pmih->have_default_refund_delay = true; 279 break; 280 case 281 TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_DEFAULT_WIRE_TRANSFER_DELAY: 282 pmih->default_wire_transfer_delay = 283 options[i].details.default_wire_transfer_delay; 284 pmih->have_default_wire_transfer_delay = true; 285 break; 286 case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_DEFAULT_WIRE_TRANSFER_ROUNDING_INTERVAL: 287 pmih->default_wire_transfer_rounding_interval = 288 options[i].details.default_wire_transfer_rounding_interval; 289 pmih->have_default_wire_transfer_rounding_interval = true; 290 break; 291 case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_EMAIL: 292 GNUNET_free (pmih->email); 293 pmih->email = GNUNET_strdup (options[i].details.email); 294 break; 295 case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_PHONE_NUMBER: 296 GNUNET_free (pmih->phone_number); 297 pmih->phone_number = GNUNET_strdup (options[i].details.phone_number); 298 break; 299 case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_WEBSITE: 300 GNUNET_free (pmih->website); 301 pmih->website = GNUNET_strdup (options[i].details.website); 302 break; 303 case TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_OPTION_LOGO: 304 GNUNET_free (pmih->logo); 305 pmih->logo = GNUNET_strdup (options[i].details.logo); 306 break; 307 } 308 } 309 return GNUNET_OK; 310 } 311 312 313 enum TALER_ErrorCode 314 TALER_MERCHANT_patch_management_instances_start ( 315 struct TALER_MERCHANT_PatchManagementInstancesHandle *pmih, 316 TALER_MERCHANT_PatchManagementInstancesCallback cb, 317 TALER_MERCHANT_PATCH_MANAGEMENT_INSTANCES_RESULT_CLOSURE *cb_cls) 318 { 319 json_t *req_obj; 320 CURL *eh; 321 322 pmih->cb = cb; 323 pmih->cb_cls = cb_cls; 324 { 325 char *path; 326 327 GNUNET_asprintf (&path, 328 "management/instances/%s", 329 pmih->instance_id); 330 pmih->url = TALER_url_join (pmih->base_url, 331 path, 332 NULL); 333 GNUNET_free (path); 334 } 335 if (NULL == pmih->url) 336 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 337 req_obj = GNUNET_JSON_PACK ( 338 GNUNET_JSON_pack_string ("name", 339 pmih->name), 340 GNUNET_JSON_pack_object_incref ("address", 341 pmih->address), 342 GNUNET_JSON_pack_object_incref ("jurisdiction", 343 pmih->jurisdiction), 344 GNUNET_JSON_pack_bool ("use_stefan", 345 pmih->use_stefan), 346 GNUNET_JSON_pack_allow_null ( 347 pmih->have_default_wire_transfer_delay 348 ? GNUNET_JSON_pack_time_rel ("default_wire_transfer_delay", 349 pmih->default_wire_transfer_delay) 350 : GNUNET_JSON_pack_string ("default_wire_transfer_delay", 351 NULL)), 352 GNUNET_JSON_pack_allow_null ( 353 pmih->have_default_pay_delay 354 ? GNUNET_JSON_pack_time_rel ("default_pay_delay", 355 pmih->default_pay_delay) 356 : GNUNET_JSON_pack_string ("default_pay_delay", 357 NULL)), 358 GNUNET_JSON_pack_allow_null ( 359 pmih->have_default_refund_delay 360 ? GNUNET_JSON_pack_time_rel ("default_refund_delay", 361 pmih->default_refund_delay) 362 : GNUNET_JSON_pack_string ("default_refund_delay", 363 NULL)), 364 GNUNET_JSON_pack_allow_null ( 365 pmih->have_default_wire_transfer_rounding_interval 366 ? GNUNET_JSON_pack_time_rounder_interval ( 367 "default_wire_transfer_rounding_interval", 368 pmih->default_wire_transfer_rounding_interval) 369 : GNUNET_JSON_pack_string ("default_wire_transfer_rounding_interval", 370 NULL)), 371 GNUNET_JSON_pack_allow_null ( 372 GNUNET_JSON_pack_string ("email", 373 pmih->email)), 374 GNUNET_JSON_pack_allow_null ( 375 GNUNET_JSON_pack_string ("phone_number", 376 pmih->phone_number)), 377 GNUNET_JSON_pack_allow_null ( 378 GNUNET_JSON_pack_string ("website", 379 pmih->website)), 380 GNUNET_JSON_pack_allow_null ( 381 GNUNET_JSON_pack_string ("logo", 382 pmih->logo)) 383 ); 384 eh = TALER_MERCHANT_curl_easy_get_ (pmih->url); 385 if ( (NULL == eh) || 386 (GNUNET_OK != 387 TALER_curl_easy_post (&pmih->post_ctx, 388 eh, 389 req_obj)) ) 390 { 391 GNUNET_break (0); 392 json_decref (req_obj); 393 if (NULL != eh) 394 curl_easy_cleanup (eh); 395 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 396 } 397 json_decref (req_obj); 398 GNUNET_assert (CURLE_OK == 399 curl_easy_setopt (eh, 400 CURLOPT_CUSTOMREQUEST, 401 MHD_HTTP_METHOD_PATCH)); 402 pmih->job = GNUNET_CURL_job_add2 (pmih->ctx, 403 eh, 404 pmih->post_ctx.headers, 405 &handle_patch_management_instances_finished, 406 pmih); 407 if (NULL == pmih->job) 408 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 409 return TALER_EC_NONE; 410 } 411 412 413 void 414 TALER_MERCHANT_patch_management_instances_cancel ( 415 struct TALER_MERCHANT_PatchManagementInstancesHandle *pmih) 416 { 417 if (NULL != pmih->job) 418 { 419 GNUNET_CURL_job_cancel (pmih->job); 420 pmih->job = NULL; 421 } 422 TALER_curl_easy_post_finished (&pmih->post_ctx); 423 json_decref (pmih->address); 424 json_decref (pmih->jurisdiction); 425 GNUNET_free (pmih->instance_id); 426 GNUNET_free (pmih->name); 427 GNUNET_free (pmih->email); 428 GNUNET_free (pmih->phone_number); 429 GNUNET_free (pmih->website); 430 GNUNET_free (pmih->logo); 431 GNUNET_free (pmih->url); 432 GNUNET_free (pmih->base_url); 433 GNUNET_free (pmih); 434 } 435 436 437 /* end of merchant_api_patch-management-instances-INSTANCE-new.c */