diff options
author | Christian Grothoff <christian@grothoff.org> | 2024-05-26 15:21:50 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2024-05-26 15:21:50 +0200 |
commit | c4936ee74300fd2a8503530a3aa8c43cf04b455c (patch) | |
tree | 51831f4f21c597603cf13bae267e622250305e16 /src/backend/taler-merchant-httpd_private-patch-products-ID.c | |
parent | ffdfeb863a03cc2cf9a92731f7b44b0c058d6a2d (diff) |
-finish implementation of protocol v16, still undertested
Diffstat (limited to 'src/backend/taler-merchant-httpd_private-patch-products-ID.c')
-rw-r--r-- | src/backend/taler-merchant-httpd_private-patch-products-ID.c | 306 |
1 files changed, 171 insertions, 135 deletions
diff --git a/src/backend/taler-merchant-httpd_private-patch-products-ID.c b/src/backend/taler-merchant-httpd_private-patch-products-ID.c index 7bc327cd..6e50cced 100644 --- a/src/backend/taler-merchant-httpd_private-patch-products-ID.c +++ b/src/backend/taler-merchant-httpd_private-patch-products-ID.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2020 Taler Systems SA + (C) 2020-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,76 +29,6 @@ /** - * How often do we retry the simple INSERT database transaction? - */ -#define MAX_RETRIES 3 - - -/** - * Determine the cause of the PATCH failure in more detail and report. - * - * @param connection connection to report on - * @param instance_id instance we are processing - * @param product_id ID of the product to patch - * @param pd product details we failed to set - */ -static MHD_RESULT -determine_cause (struct MHD_Connection *connection, - const char *instance_id, - const char *product_id, - const struct TALER_MERCHANTDB_ProductDetails *pd) -{ - struct TALER_MERCHANTDB_ProductDetails pdx; - enum GNUNET_DB_QueryStatus qs; - - qs = TMH_db->lookup_product (TMH_db->cls, - instance_id, - product_id, - &pdx); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - 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: - GNUNET_break (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, - "unexpected serialization problem"); - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN, - product_id); - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; /* do below */ - } - - { - enum TALER_ErrorCode ec; - - ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - if (pdx.total_lost > pd->total_lost) - ec = TALER_EC_MERCHANT_PRIVATE_PATCH_PRODUCTS_TOTAL_LOST_REDUCED; - if (pdx.total_sold > pd->total_sold) - ec = TALER_EC_MERCHANT_PRIVATE_PATCH_PRODUCTS_TOTAL_SOLD_REDUCED; - if (pdx.total_stock > pd->total_stock) - ec = TALER_EC_MERCHANT_PRIVATE_PATCH_PRODUCTS_TOTAL_STOCKED_REDUCED; - TALER_MERCHANTDB_product_details_free (&pdx); - GNUNET_break (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE != ec); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_CONFLICT, - ec, - NULL); - } -} - - -/** * PATCH configuration of an existing instance, given its configuration. * * @param rh context of the handler @@ -107,13 +37,15 @@ determine_cause (struct MHD_Connection *connection, * @return MHD result code */ MHD_RESULT -TMH_private_patch_products_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) +TMH_private_patch_products_ID ( + const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) { struct TMH_MerchantInstance *mi = hc->instance; const char *product_id = hc->infix; struct TALER_MERCHANTDB_ProductDetails pd = {0}; + const json_t *categories = NULL; int64_t total_stock; enum GNUNET_DB_QueryStatus qs; struct GNUNET_JSON_Specification spec[] = { @@ -135,6 +67,10 @@ TMH_private_patch_products_ID (const struct TMH_RequestHandler *rh, GNUNET_JSON_spec_json ("taxes", &pd.taxes), NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_array_const ("categories", + &categories), + NULL), GNUNET_JSON_spec_int64 ("total_stock", &total_stock), GNUNET_JSON_spec_mark_optional ( @@ -155,6 +91,15 @@ TMH_private_patch_products_ID (const struct TMH_RequestHandler *rh, NULL), GNUNET_JSON_spec_end () }; + MHD_RESULT ret; + size_t num_cats = 0; + uint64_t *cats = NULL; + bool no_instance; + ssize_t no_cat; + bool no_product; + bool lost_reduced; + bool sold_reduced; + bool stock_reduced; pd.total_sold = 0; /* will be ignored anyway */ GNUNET_assert (NULL != mi); @@ -173,11 +118,11 @@ TMH_private_patch_products_ID (const struct TMH_RequestHandler *rh, if (total_stock < -1) { 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, - "total_stock"); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "total_stock"); + goto cleanup; } if (-1 == total_stock) pd.total_stock = INT64_MAX; @@ -189,23 +134,45 @@ TMH_private_patch_products_ID (const struct TMH_RequestHandler *rh, if (! TMH_location_object_valid (pd.address)) { 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, - "address"); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "address"); + goto cleanup; + } + num_cats = json_array_size (categories); + cats = GNUNET_new_array (num_cats, + uint64_t); + { + size_t idx; + json_t *val; + + json_array_foreach (categories, idx, val) + { + if (! json_is_integer (val)) + { + GNUNET_break_op (0); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "categories"); + goto cleanup; + } + cats[idx] = json_integer_value (val); + } } + if (NULL == pd.description_i18n) pd.description_i18n = json_object (); if (! TALER_JSON_check_i18n (pd.description_i18n)) { 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, - "description_i18n"); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "description_i18n"); + goto cleanup; } if (NULL == pd.taxes) @@ -214,74 +181,143 @@ TMH_private_patch_products_ID (const struct TMH_RequestHandler *rh, if (! TMH_taxes_array_valid (pd.taxes)) { 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, - "taxes"); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "taxes"); + goto cleanup; } + if (NULL == pd.image) pd.image = ""; if (! TMH_image_data_url_valid (pd.image)) { 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"); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "image"); + goto cleanup; } + if ( (pd.total_stock < pd.total_sold + pd.total_lost) || (pd.total_sold + pd.total_lost < pd.total_sold) /* integer overflow */) { GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return TALER_MHD_reply_with_error ( + ret = TALER_MHD_reply_with_error ( connection, MHD_HTTP_BAD_REQUEST, TALER_EC_MERCHANT_PRIVATE_PATCH_PRODUCTS_TOTAL_LOST_EXCEEDS_STOCKS, NULL); + goto cleanup; } + qs = TMH_db->update_product (TMH_db->cls, mi->settings.id, product_id, - &pd); + &pd, + num_cats, + cats, + &no_instance, + &no_cat, + &no_product, + &lost_reduced, + &sold_reduced, + &stock_reduced); + switch (qs) { - MHD_RESULT ret = MHD_NO; + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + NULL); + goto cleanup; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "unexpected serialization problem"); + goto cleanup; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "unexpected problem in stored procedure"); + goto cleanup; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_STORE_FAILED, - NULL); - break; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, - "unexpected serialization problem"); - break; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - ret = determine_cause (connection, - mi->settings.id, - product_id, - &pd); - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - ret = TALER_MHD_reply_static (connection, - MHD_HTTP_NO_CONTENT, - NULL, - NULL, - 0); - break; - } - GNUNET_JSON_parse_free (spec); - return ret; + if (no_instance) + { + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN, + mi->settings.id); + goto cleanup; + } + if (-1 != no_cat) + { + char cats[24]; + + GNUNET_snprintf (cats, + sizeof (cats), + "%llu", + (unsigned long long) no_cat); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_CATEGORY_UNKNOWN, + cats); + goto cleanup; + } + if (no_product) + { + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN, + product_id); + goto cleanup; + } + if (lost_reduced) + { + ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_CONFLICT, + TALER_EC_MERCHANT_PRIVATE_PATCH_PRODUCTS_TOTAL_LOST_REDUCED, + NULL); + goto cleanup; + } + if (sold_reduced) + { + ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_CONFLICT, + TALER_EC_MERCHANT_PRIVATE_PATCH_PRODUCTS_TOTAL_SOLD_REDUCED, + NULL); + goto cleanup; + } + if (stock_reduced) + { + ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_CONFLICT, + TALER_EC_MERCHANT_PRIVATE_PATCH_PRODUCTS_TOTAL_STOCKED_REDUCED, + NULL); + goto cleanup; } + /* success! */ + ret = TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); +cleanup: + GNUNET_free (cats); + GNUNET_JSON_parse_free (spec); + return ret; } |