diff options
Diffstat (limited to 'src/backend/taler-merchant-httpd_private-post-templates.c')
-rw-r--r-- | src/backend/taler-merchant-httpd_private-post-templates.c | 231 |
1 files changed, 147 insertions, 84 deletions
diff --git a/src/backend/taler-merchant-httpd_private-post-templates.c b/src/backend/taler-merchant-httpd_private-post-templates.c index 1dd324e4..7aa72992 100644 --- a/src/backend/taler-merchant-httpd_private-post-templates.c +++ b/src/backend/taler-merchant-httpd_private-post-templates.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2022 Taler Systems SA + (C) 2022-2024 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -29,12 +29,6 @@ /** - * How often do we retry the simple INSERT database transaction? - */ -#define MAX_RETRIES 3 - - -/** * Check if the two templates are identical. * * @param t1 template to compare @@ -47,10 +41,24 @@ templates_equal (const struct TALER_MERCHANTDB_TemplateDetails *t1, { return ( (0 == strcmp (t1->template_description, t2->template_description)) && - ( ( (NULL == t1->image) && (NULL == t2->image) ) || - ( (NULL != t1->image) && (NULL != t2->image) && - (0 == strcmp (t1->image, - t2->image)) ) ) && + ( ( (NULL == t1->otp_id) && + (NULL == t2->otp_id) ) || + ( (NULL != t1->otp_id) && + (NULL != t2->otp_id) && + (0 == strcmp (t1->otp_id, + t2->otp_id))) ) && + ( ( (NULL == t1->required_currency) && + (NULL == t2->required_currency) ) || + ( (NULL != t1->required_currency) && + (NULL != t2->required_currency) && + (0 == strcmp (t1->required_currency, + t2->required_currency))) ) && + ( ( (NULL == t1->editable_defaults) && + (NULL == t2->editable_defaults) ) || + ( (NULL != t1->editable_defaults) && + (NULL != t2->editable_defaults) && + (1 == json_equal (t1->editable_defaults, + t2->editable_defaults))) ) && (1 == json_equal (t1->template_contract, t2->template_contract)) ); } @@ -71,13 +79,22 @@ TMH_private_post_templates (const struct TMH_RequestHandler *rh, GNUNET_JSON_spec_string ("template_description", (const char **) &tp.template_description), GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("image", - (const char **) &tp.image), + GNUNET_JSON_spec_string ("otp_id", + (const char **) &tp.otp_id), NULL), GNUNET_JSON_spec_json ("template_contract", &tp.template_contract), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("required_currency", + (const char **) &tp.required_currency), + NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_json ("editable_defaults", + &tp.editable_defaults), + NULL), GNUNET_JSON_spec_end () }; + uint64_t otp_serial = 0; GNUNET_assert (NULL != mi); { @@ -107,34 +124,114 @@ TMH_private_post_templates (const struct TMH_RequestHandler *rh, "template_contract"); } - if ( (NULL != tp.image) && - (! TMH_image_data_url_valid (tp.image)) ) + if ( (NULL != tp.required_currency) && + (GNUNET_OK != + TALER_check_currency (tp.required_currency)) ) { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error (connection, MHD_HTTP_BAD_REQUEST, TALER_EC_GENERIC_PARAMETER_MALFORMED, - "image"); + "required_currency"); } - - /* finally, interact with DB until no serialization error */ - for (unsigned int i = 0; i<MAX_RETRIES; i++) + if ( (NULL != tp.required_currency) && + (NULL != json_object_get (tp.template_contract, + "amount")) ) { - /* Test if a template of this id is known */ - struct TALER_MERCHANTDB_TemplateDetails etp; + GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "required_currency and contract::amount specified"); + } + if (NULL != tp.editable_defaults) + { + const char *key; + json_t *val; - if (GNUNET_OK != - TMH_db->start (TMH_db->cls, - "/post templates")) + json_object_foreach (tp.editable_defaults, key, val) { + if (NULL != + json_object_get (tp.template_contract, + key)) + { + char *msg; + MHD_RESULT ret; + + GNUNET_break_op (0); + GNUNET_asprintf (&msg, + "editable_defaults::%s conflicts with template_contract", + key); + GNUNET_JSON_parse_free (spec); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + msg); + GNUNET_free (msg); + return ret; + } + } + } + + if (NULL != tp.otp_id) + { + qs = TMH_db->select_otp_serial (TMH_db->cls, + mi->settings.id, + tp.otp_id, + &otp_serial); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: GNUNET_break (0); GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_START_FAILED, + TALER_EC_GENERIC_DB_STORE_FAILED, + "select_otp_serial"); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN, NULL); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; } + } + + qs = TMH_db->insert_template (TMH_db->cls, + mi->settings.id, + template_id, + otp_serial, + &tp); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + NULL); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + break; + } + + { + /* Test if a template of this id is known */ + struct TALER_MERCHANTDB_TemplateDetails etp; + qs = TMH_db->lookup_template (TMH_db->cls, mi->settings.id, template_id, @@ -142,79 +239,45 @@ TMH_private_post_templates (const struct TMH_RequestHandler *rh, switch (qs) { case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: /* Clean up and fail hard */ GNUNET_break (0); - TMH_db->rollback (TMH_db->cls); GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_FETCH_FAILED, NULL); - case GNUNET_DB_STATUS_SOFT_ERROR: - /* restart transaction */ - goto retry; case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* Good, we can proceed! */ - break; + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "logic error"); case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - /* idempotency check: is etp == tp? */ - { - bool eq; - - eq = templates_equal (&tp, - &etp); - TALER_MERCHANTDB_template_details_free (&etp); - TMH_db->rollback (TMH_db->cls); - GNUNET_JSON_parse_free (spec); - return eq - ? TALER_MHD_reply_static (connection, - MHD_HTTP_NO_CONTENT, - NULL, - NULL, - 0) - : TALER_MHD_reply_with_error (connection, - MHD_HTTP_CONFLICT, - TALER_EC_MERCHANT_PRIVATE_POST_TEMPLATES_CONFLICT_TEMPLATE_EXISTS, - template_id); - } - } /* end switch (qs) */ - - qs = TMH_db->insert_template (TMH_db->cls, - mi->settings.id, - template_id, - &tp); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - { - TMH_db->rollback (TMH_db->cls); break; } - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) + /* idempotency check: is etp == tp? */ { - qs = TMH_db->commit (TMH_db->cls); - if (GNUNET_DB_STATUS_SOFT_ERROR != qs) - break; + bool eq; + + eq = templates_equal (&tp, + &etp); + TALER_MERCHANTDB_template_details_free (&etp); + TMH_db->rollback (TMH_db->cls); + GNUNET_JSON_parse_free (spec); + return eq + ? TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0) + : TALER_MHD_reply_with_error (connection, + MHD_HTTP_CONFLICT, + TALER_EC_MERCHANT_PRIVATE_POST_TEMPLATES_CONFLICT_TEMPLATE_EXISTS, + template_id); } -retry: - GNUNET_assert (GNUNET_DB_STATUS_SOFT_ERROR == qs); - TMH_db->rollback (TMH_db->cls); - } /* for RETRIES loop */ - GNUNET_JSON_parse_free (spec); - if (qs < 0) - { - GNUNET_break (0); - return TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - (GNUNET_DB_STATUS_SOFT_ERROR == qs) - ? TALER_EC_GENERIC_DB_SOFT_FAILURE - : TALER_EC_GENERIC_DB_COMMIT_FAILED, - NULL); } - return TALER_MHD_reply_static (connection, - MHD_HTTP_NO_CONTENT, - NULL, - NULL, - 0); } |