merchant_api_post-private-tokenfamilies.c (10438B)
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 src/lib/merchant_api_post-private-tokenfamilies.c 21 * @brief Implementation of the POST /private/tokenfamilies request 22 * @author Christian Grothoff 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/post-private-tokenfamilies.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 POST /private/tokenfamilies operation. 39 */ 40 struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle 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_PostPrivateTokenfamiliesCallback cb; 61 62 /** 63 * Closure for @a cb. 64 */ 65 TALER_MERCHANT_POST_PRIVATE_TOKENFAMILIES_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 * URL-safe slug identifier. 79 */ 80 char *slug; 81 82 /** 83 * Human-readable name. 84 */ 85 char *name; 86 87 /** 88 * Human-readable description. 89 */ 90 char *description; 91 92 /** 93 * Start of validity period. 94 */ 95 struct GNUNET_TIME_Timestamp valid_after; 96 97 /** 98 * End of validity period. 99 */ 100 struct GNUNET_TIME_Timestamp valid_before; 101 102 /** 103 * Duration of individual token validity. 104 */ 105 struct GNUNET_TIME_Relative duration; 106 107 /** 108 * Granularity for validity alignment. 109 */ 110 struct GNUNET_TIME_Relative validity_granularity; 111 112 /** 113 * Offset from purchase to start of validity. 114 */ 115 struct GNUNET_TIME_Relative start_offset; 116 117 /** 118 * Kind of token family. 119 */ 120 char *kind; 121 122 /** 123 * Optional internationalized descriptions (JSON). 124 */ 125 json_t *description_i18n; 126 127 /** 128 * Optional extra data (JSON). 129 */ 130 json_t *extra_data; 131 }; 132 133 134 /** 135 * Function called when we're done processing the 136 * HTTP POST /private/tokenfamilies request. 137 * 138 * @param cls the `struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle` 139 * @param response_code HTTP response code, 0 on error 140 * @param response response body, NULL if not in JSON 141 */ 142 static void 143 handle_post_tokenfamilies_finished (void *cls, 144 long response_code, 145 const void *response) 146 { 147 struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle *ptfh = cls; 148 const json_t *json = response; 149 struct TALER_MERCHANT_PostPrivateTokenfamiliesResponse tfr = { 150 .hr.http_status = (unsigned int) response_code, 151 .hr.reply = json 152 }; 153 154 ptfh->job = NULL; 155 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 156 "POST /private/tokenfamilies completed with response code %u\n", 157 (unsigned int) response_code); 158 switch (response_code) 159 { 160 case 0: 161 tfr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 162 break; 163 case MHD_HTTP_NO_CONTENT: 164 break; 165 case MHD_HTTP_BAD_REQUEST: 166 GNUNET_break_op (0); 167 tfr.hr.ec = TALER_JSON_get_error_code (json); 168 tfr.hr.hint = TALER_JSON_get_error_hint (json); 169 break; 170 case MHD_HTTP_UNAUTHORIZED: 171 tfr.hr.ec = TALER_JSON_get_error_code (json); 172 tfr.hr.hint = TALER_JSON_get_error_hint (json); 173 break; 174 case MHD_HTTP_FORBIDDEN: 175 tfr.hr.ec = TALER_JSON_get_error_code (json); 176 tfr.hr.hint = TALER_JSON_get_error_hint (json); 177 break; 178 case MHD_HTTP_NOT_FOUND: 179 tfr.hr.ec = TALER_JSON_get_error_code (json); 180 tfr.hr.hint = TALER_JSON_get_error_hint (json); 181 break; 182 case MHD_HTTP_CONFLICT: 183 tfr.hr.ec = TALER_JSON_get_error_code (json); 184 tfr.hr.hint = TALER_JSON_get_error_hint (json); 185 break; 186 case MHD_HTTP_INTERNAL_SERVER_ERROR: 187 tfr.hr.ec = TALER_JSON_get_error_code (json); 188 tfr.hr.hint = TALER_JSON_get_error_hint (json); 189 break; 190 default: 191 TALER_MERCHANT_parse_error_details_ (json, 192 response_code, 193 &tfr.hr); 194 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 195 "Unexpected response code %u/%d\n", 196 (unsigned int) response_code, 197 (int) tfr.hr.ec); 198 GNUNET_break_op (0); 199 break; 200 } 201 ptfh->cb (ptfh->cb_cls, 202 &tfr); 203 TALER_MERCHANT_post_private_tokenfamilies_cancel (ptfh); 204 } 205 206 207 struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle * 208 TALER_MERCHANT_post_private_tokenfamilies_create ( 209 struct GNUNET_CURL_Context *ctx, 210 const char *url, 211 const char *slug, 212 const char *name, 213 const char *description, 214 struct GNUNET_TIME_Timestamp valid_after, 215 struct GNUNET_TIME_Timestamp valid_before, 216 struct GNUNET_TIME_Relative duration, 217 struct GNUNET_TIME_Relative validity_granularity, 218 struct GNUNET_TIME_Relative start_offset, 219 const char *kind) 220 { 221 struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle *ptfh; 222 223 ptfh = GNUNET_new (struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle); 224 ptfh->ctx = ctx; 225 ptfh->base_url = GNUNET_strdup (url); 226 ptfh->slug = GNUNET_strdup (slug); 227 ptfh->name = GNUNET_strdup (name); 228 ptfh->description = GNUNET_strdup (description); 229 ptfh->valid_after = valid_after; 230 ptfh->valid_before = valid_before; 231 ptfh->duration = duration; 232 ptfh->validity_granularity = validity_granularity; 233 ptfh->start_offset = start_offset; 234 ptfh->kind = GNUNET_strdup (kind); 235 return ptfh; 236 } 237 238 239 enum GNUNET_GenericReturnValue 240 TALER_MERCHANT_post_private_tokenfamilies_set_options_ ( 241 struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle *ptfh, 242 unsigned int num_options, 243 const struct TALER_MERCHANT_PostPrivateTokenfamiliesOptionValue *options) 244 { 245 for (unsigned int i = 0; i < num_options; i++) 246 { 247 switch (options[i].option) 248 { 249 case TALER_MERCHANT_POST_PRIVATE_TOKENFAMILIES_OPTION_END: 250 return GNUNET_OK; 251 case TALER_MERCHANT_POST_PRIVATE_TOKENFAMILIES_OPTION_DESCRIPTION_I18N: 252 json_decref (ptfh->description_i18n); 253 ptfh->description_i18n 254 = json_incref ((json_t *) options[i].details.description_i18n); 255 break; 256 case TALER_MERCHANT_POST_PRIVATE_TOKENFAMILIES_OPTION_EXTRA_DATA: 257 json_decref (ptfh->extra_data); 258 ptfh->extra_data 259 = json_incref ((json_t *) options[i].details.extra_data); 260 break; 261 default: 262 GNUNET_break (0); 263 return GNUNET_SYSERR; 264 } 265 } 266 return GNUNET_OK; 267 } 268 269 270 enum TALER_ErrorCode 271 TALER_MERCHANT_post_private_tokenfamilies_start ( 272 struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle *ptfh, 273 TALER_MERCHANT_PostPrivateTokenfamiliesCallback cb, 274 TALER_MERCHANT_POST_PRIVATE_TOKENFAMILIES_RESULT_CLOSURE *cb_cls) 275 { 276 json_t *req_obj; 277 CURL *eh; 278 279 ptfh->cb = cb; 280 ptfh->cb_cls = cb_cls; 281 ptfh->url = TALER_url_join (ptfh->base_url, 282 "private/tokenfamilies", 283 NULL); 284 if (NULL == ptfh->url) 285 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 286 req_obj = GNUNET_JSON_PACK ( 287 GNUNET_JSON_pack_string ("slug", 288 ptfh->slug), 289 GNUNET_JSON_pack_string ("name", 290 ptfh->name), 291 GNUNET_JSON_pack_string ("description", 292 ptfh->description), 293 GNUNET_JSON_pack_allow_null ( 294 GNUNET_JSON_pack_object_incref ("description_i18n", 295 ptfh->description_i18n)), 296 GNUNET_JSON_pack_allow_null ( 297 GNUNET_JSON_pack_object_incref ("extra_data", 298 ptfh->extra_data)), 299 GNUNET_JSON_pack_allow_null ( 300 GNUNET_JSON_pack_timestamp ("valid_after", 301 ptfh->valid_after)), 302 GNUNET_JSON_pack_timestamp ("valid_before", 303 ptfh->valid_before), 304 GNUNET_JSON_pack_time_rel ("duration", 305 ptfh->duration), 306 GNUNET_JSON_pack_time_rel ("validity_granularity", 307 ptfh->validity_granularity), 308 GNUNET_JSON_pack_time_rel ("start_offset", 309 ptfh->start_offset), 310 GNUNET_JSON_pack_string ("kind", 311 ptfh->kind)); 312 eh = TALER_MERCHANT_curl_easy_get_ (ptfh->url); 313 if ( (NULL == eh) || 314 (GNUNET_OK != 315 TALER_curl_easy_post (&ptfh->post_ctx, 316 eh, 317 req_obj)) ) 318 { 319 GNUNET_break (0); 320 json_decref (req_obj); 321 if (NULL != eh) 322 curl_easy_cleanup (eh); 323 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 324 } 325 json_decref (req_obj); 326 ptfh->job = GNUNET_CURL_job_add2 (ptfh->ctx, 327 eh, 328 ptfh->post_ctx.headers, 329 &handle_post_tokenfamilies_finished, 330 ptfh); 331 if (NULL == ptfh->job) 332 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 333 return TALER_EC_NONE; 334 } 335 336 337 void 338 TALER_MERCHANT_post_private_tokenfamilies_cancel ( 339 struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle *ptfh) 340 { 341 if (NULL != ptfh->job) 342 { 343 GNUNET_CURL_job_cancel (ptfh->job); 344 ptfh->job = NULL; 345 } 346 TALER_curl_easy_post_finished (&ptfh->post_ctx); 347 json_decref (ptfh->description_i18n); 348 json_decref (ptfh->extra_data); 349 GNUNET_free (ptfh->slug); 350 GNUNET_free (ptfh->name); 351 GNUNET_free (ptfh->description); 352 GNUNET_free (ptfh->kind); 353 GNUNET_free (ptfh->url); 354 GNUNET_free (ptfh->base_url); 355 GNUNET_free (ptfh); 356 } 357 358 359 /* end of merchant_api_post-private-tokenfamilies-new.c */