merchant_api_post-private-templates.c (8729B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2022-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-templates-new.c 21 * @brief Implementation of the POST /private/templates 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-templates.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/templates operation. 39 */ 40 struct TALER_MERCHANT_PostPrivateTemplatesHandle 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_PostPrivateTemplatesCallback cb; 61 62 /** 63 * Closure for @a cb. 64 */ 65 TALER_MERCHANT_POST_PRIVATE_TEMPLATES_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 * Template identifier. 79 */ 80 char *template_id; 81 82 /** 83 * Human-readable description. 84 */ 85 char *template_description; 86 87 /** 88 * Template contract (JSON). 89 */ 90 json_t *template_contract; 91 92 /** 93 * Optional OTP device ID. 94 */ 95 char *otp_id; 96 97 /** 98 * Optional editable defaults (JSON object). 99 */ 100 json_t *editable_defaults; 101 }; 102 103 104 /** 105 * Function called when we're done processing the 106 * HTTP POST /private/templates request. 107 * 108 * @param cls the `struct TALER_MERCHANT_PostPrivateTemplatesHandle` 109 * @param response_code HTTP response code, 0 on error 110 * @param response response body, NULL if not in JSON 111 */ 112 static void 113 handle_post_templates_finished (void *cls, 114 long response_code, 115 const void *response) 116 { 117 struct TALER_MERCHANT_PostPrivateTemplatesHandle *ppth = cls; 118 const json_t *json = response; 119 struct TALER_MERCHANT_PostPrivateTemplatesResponse ptr = { 120 .hr.http_status = (unsigned int) response_code, 121 .hr.reply = json 122 }; 123 124 ppth->job = NULL; 125 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 126 "POST /private/templates completed with response code %u\n", 127 (unsigned int) response_code); 128 switch (response_code) 129 { 130 case 0: 131 ptr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 132 break; 133 case MHD_HTTP_NO_CONTENT: 134 break; 135 case MHD_HTTP_BAD_REQUEST: 136 GNUNET_break_op (0); 137 ptr.hr.ec = TALER_JSON_get_error_code (json); 138 ptr.hr.hint = TALER_JSON_get_error_hint (json); 139 break; 140 case MHD_HTTP_UNAUTHORIZED: 141 ptr.hr.ec = TALER_JSON_get_error_code (json); 142 ptr.hr.hint = TALER_JSON_get_error_hint (json); 143 break; 144 case MHD_HTTP_FORBIDDEN: 145 ptr.hr.ec = TALER_JSON_get_error_code (json); 146 ptr.hr.hint = TALER_JSON_get_error_hint (json); 147 break; 148 case MHD_HTTP_NOT_FOUND: 149 ptr.hr.ec = TALER_JSON_get_error_code (json); 150 ptr.hr.hint = TALER_JSON_get_error_hint (json); 151 break; 152 case MHD_HTTP_CONFLICT: 153 ptr.hr.ec = TALER_JSON_get_error_code (json); 154 ptr.hr.hint = TALER_JSON_get_error_hint (json); 155 break; 156 case MHD_HTTP_INTERNAL_SERVER_ERROR: 157 ptr.hr.ec = TALER_JSON_get_error_code (json); 158 ptr.hr.hint = TALER_JSON_get_error_hint (json); 159 break; 160 default: 161 TALER_MERCHANT_parse_error_details_ (json, 162 response_code, 163 &ptr.hr); 164 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 165 "Unexpected response code %u/%d\n", 166 (unsigned int) response_code, 167 (int) ptr.hr.ec); 168 GNUNET_break_op (0); 169 break; 170 } 171 ppth->cb (ppth->cb_cls, 172 &ptr); 173 TALER_MERCHANT_post_private_templates_cancel (ppth); 174 } 175 176 177 struct TALER_MERCHANT_PostPrivateTemplatesHandle * 178 TALER_MERCHANT_post_private_templates_create ( 179 struct GNUNET_CURL_Context *ctx, 180 const char *url, 181 const char *template_id, 182 const char *template_description, 183 const json_t *template_contract) 184 { 185 struct TALER_MERCHANT_PostPrivateTemplatesHandle *ppth; 186 187 ppth = GNUNET_new (struct TALER_MERCHANT_PostPrivateTemplatesHandle); 188 ppth->ctx = ctx; 189 ppth->base_url = GNUNET_strdup (url); 190 ppth->template_id = GNUNET_strdup (template_id); 191 ppth->template_description = GNUNET_strdup (template_description); 192 ppth->template_contract = json_incref ((json_t *) template_contract); 193 return ppth; 194 } 195 196 197 enum GNUNET_GenericReturnValue 198 TALER_MERCHANT_post_private_templates_set_options_ ( 199 struct TALER_MERCHANT_PostPrivateTemplatesHandle *ppth, 200 unsigned int num_options, 201 const struct TALER_MERCHANT_PostPrivateTemplatesOptionValue *options) 202 { 203 for (unsigned int i = 0; i < num_options; i++) 204 { 205 switch (options[i].option) 206 { 207 case TALER_MERCHANT_POST_PRIVATE_TEMPLATES_OPTION_END: 208 return GNUNET_OK; 209 case TALER_MERCHANT_POST_PRIVATE_TEMPLATES_OPTION_OTP_ID: 210 ppth->otp_id = GNUNET_strdup (options[i].details.otp_id); 211 break; 212 case TALER_MERCHANT_POST_PRIVATE_TEMPLATES_OPTION_EDITABLE_DEFAULTS: 213 ppth->editable_defaults 214 = json_incref ((json_t *) options[i].details.editable_defaults); 215 break; 216 default: 217 GNUNET_break (0); 218 return GNUNET_SYSERR; 219 } 220 } 221 return GNUNET_OK; 222 } 223 224 225 enum TALER_ErrorCode 226 TALER_MERCHANT_post_private_templates_start ( 227 struct TALER_MERCHANT_PostPrivateTemplatesHandle *ppth, 228 TALER_MERCHANT_PostPrivateTemplatesCallback cb, 229 TALER_MERCHANT_POST_PRIVATE_TEMPLATES_RESULT_CLOSURE *cb_cls) 230 { 231 json_t *req_obj; 232 CURL *eh; 233 234 ppth->cb = cb; 235 ppth->cb_cls = cb_cls; 236 ppth->url = TALER_url_join (ppth->base_url, 237 "private/templates", 238 NULL); 239 if (NULL == ppth->url) 240 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 241 req_obj = GNUNET_JSON_PACK ( 242 GNUNET_JSON_pack_string ("template_id", 243 ppth->template_id), 244 GNUNET_JSON_pack_string ("template_description", 245 ppth->template_description), 246 GNUNET_JSON_pack_allow_null ( 247 GNUNET_JSON_pack_string ("otp_id", 248 ppth->otp_id)), 249 GNUNET_JSON_pack_object_incref ("template_contract", 250 ppth->template_contract), 251 GNUNET_JSON_pack_allow_null ( 252 GNUNET_JSON_pack_object_incref ("editable_defaults", 253 ppth->editable_defaults))); 254 eh = TALER_MERCHANT_curl_easy_get_ (ppth->url); 255 if ( (NULL == eh) || 256 (GNUNET_OK != 257 TALER_curl_easy_post (&ppth->post_ctx, 258 eh, 259 req_obj)) ) 260 { 261 GNUNET_break (0); 262 json_decref (req_obj); 263 if (NULL != eh) 264 curl_easy_cleanup (eh); 265 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 266 } 267 json_decref (req_obj); 268 ppth->job = GNUNET_CURL_job_add2 (ppth->ctx, 269 eh, 270 ppth->post_ctx.headers, 271 &handle_post_templates_finished, 272 ppth); 273 if (NULL == ppth->job) 274 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 275 return TALER_EC_NONE; 276 } 277 278 279 void 280 TALER_MERCHANT_post_private_templates_cancel ( 281 struct TALER_MERCHANT_PostPrivateTemplatesHandle *ppth) 282 { 283 if (NULL != ppth->job) 284 { 285 GNUNET_CURL_job_cancel (ppth->job); 286 ppth->job = NULL; 287 } 288 TALER_curl_easy_post_finished (&ppth->post_ctx); 289 json_decref (ppth->template_contract); 290 GNUNET_free (ppth->template_id); 291 GNUNET_free (ppth->template_description); 292 GNUNET_free (ppth->otp_id); 293 json_decref (ppth->editable_defaults); 294 GNUNET_free (ppth->url); 295 GNUNET_free (ppth->base_url); 296 GNUNET_free (ppth); 297 } 298 299 300 /* end of merchant_api_post-private-templates-new.c */