merchant_api_post-private-tokenfamilies.c (10364B)
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_post-private-tokenfamilies-new.c 21 * @brief Implementation of the POST /private/tokenfamilies 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/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 ptfh->description_i18n 253 = json_incref ((json_t *) options[i].details.description_i18n); 254 break; 255 case TALER_MERCHANT_POST_PRIVATE_TOKENFAMILIES_OPTION_EXTRA_DATA: 256 ptfh->extra_data 257 = json_incref ((json_t *) options[i].details.extra_data); 258 break; 259 default: 260 GNUNET_break (0); 261 return GNUNET_SYSERR; 262 } 263 } 264 return GNUNET_OK; 265 } 266 267 268 enum TALER_ErrorCode 269 TALER_MERCHANT_post_private_tokenfamilies_start ( 270 struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle *ptfh, 271 TALER_MERCHANT_PostPrivateTokenfamiliesCallback cb, 272 TALER_MERCHANT_POST_PRIVATE_TOKENFAMILIES_RESULT_CLOSURE *cb_cls) 273 { 274 json_t *req_obj; 275 CURL *eh; 276 277 ptfh->cb = cb; 278 ptfh->cb_cls = cb_cls; 279 ptfh->url = TALER_url_join (ptfh->base_url, 280 "private/tokenfamilies", 281 NULL); 282 if (NULL == ptfh->url) 283 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 284 req_obj = GNUNET_JSON_PACK ( 285 GNUNET_JSON_pack_string ("slug", 286 ptfh->slug), 287 GNUNET_JSON_pack_string ("name", 288 ptfh->name), 289 GNUNET_JSON_pack_string ("description", 290 ptfh->description), 291 GNUNET_JSON_pack_allow_null ( 292 GNUNET_JSON_pack_object_incref ("description_i18n", 293 ptfh->description_i18n)), 294 GNUNET_JSON_pack_allow_null ( 295 GNUNET_JSON_pack_object_incref ("extra_data", 296 ptfh->extra_data)), 297 GNUNET_JSON_pack_allow_null ( 298 GNUNET_JSON_pack_timestamp ("valid_after", 299 ptfh->valid_after)), 300 GNUNET_JSON_pack_timestamp ("valid_before", 301 ptfh->valid_before), 302 GNUNET_JSON_pack_time_rel ("duration", 303 ptfh->duration), 304 GNUNET_JSON_pack_time_rel ("validity_granularity", 305 ptfh->validity_granularity), 306 GNUNET_JSON_pack_time_rel ("start_offset", 307 ptfh->start_offset), 308 GNUNET_JSON_pack_string ("kind", 309 ptfh->kind)); 310 eh = TALER_MERCHANT_curl_easy_get_ (ptfh->url); 311 if ( (NULL == eh) || 312 (GNUNET_OK != 313 TALER_curl_easy_post (&ptfh->post_ctx, 314 eh, 315 req_obj)) ) 316 { 317 GNUNET_break (0); 318 json_decref (req_obj); 319 if (NULL != eh) 320 curl_easy_cleanup (eh); 321 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 322 } 323 json_decref (req_obj); 324 ptfh->job = GNUNET_CURL_job_add2 (ptfh->ctx, 325 eh, 326 ptfh->post_ctx.headers, 327 &handle_post_tokenfamilies_finished, 328 ptfh); 329 if (NULL == ptfh->job) 330 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 331 return TALER_EC_NONE; 332 } 333 334 335 void 336 TALER_MERCHANT_post_private_tokenfamilies_cancel ( 337 struct TALER_MERCHANT_PostPrivateTokenfamiliesHandle *ptfh) 338 { 339 if (NULL != ptfh->job) 340 { 341 GNUNET_CURL_job_cancel (ptfh->job); 342 ptfh->job = NULL; 343 } 344 TALER_curl_easy_post_finished (&ptfh->post_ctx); 345 json_decref (ptfh->description_i18n); 346 json_decref (ptfh->extra_data); 347 GNUNET_free (ptfh->slug); 348 GNUNET_free (ptfh->name); 349 GNUNET_free (ptfh->description); 350 GNUNET_free (ptfh->kind); 351 GNUNET_free (ptfh->url); 352 GNUNET_free (ptfh->base_url); 353 GNUNET_free (ptfh); 354 } 355 356 357 /* end of merchant_api_post-private-tokenfamilies-new.c */