taler-merchant-httpd_private-post-categories.c (5717B)
1 /* 2 This file is part of TALER 3 (C) 2024 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify 6 it under the terms of the GNU Affero General Public License as 7 published by the Free Software Foundation; either version 3, 8 or (at your option) any later version. 9 10 TALER is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public 16 License along with TALER; see the file COPYING. If not, 17 see <http://www.gnu.org/licenses/> 18 */ 19 /** 20 * @file taler-merchant-httpd_private-post-categories.c 21 * @brief implementing POST /private/categories request handling 22 * @author Christian Grothoff 23 */ 24 #include "platform.h" 25 #include "taler-merchant-httpd_private-post-categories.h" 26 #include "taler-merchant-httpd_helper.h" 27 #include <taler/taler_json_lib.h> 28 29 30 /** 31 * How often do we retry the simple INSERT database transaction? 32 */ 33 #define MAX_RETRIES 3 34 35 36 MHD_RESULT 37 TMH_private_post_categories (const struct TMH_RequestHandler *rh, 38 struct MHD_Connection *connection, 39 struct TMH_HandlerContext *hc) 40 { 41 struct TMH_MerchantInstance *mi = hc->instance; 42 const char *category_name; 43 const json_t *category_name_i18n; 44 uint64_t category_id; 45 struct GNUNET_JSON_Specification spec[] = { 46 GNUNET_JSON_spec_string ("name", 47 &category_name), 48 GNUNET_JSON_spec_object_const ("name_i18n", 49 &category_name_i18n), 50 GNUNET_JSON_spec_end () 51 }; 52 enum GNUNET_DB_QueryStatus qs; 53 54 GNUNET_assert (NULL != mi); 55 { 56 enum GNUNET_GenericReturnValue res; 57 58 res = TALER_MHD_parse_json_data (connection, 59 hc->request_body, 60 spec); 61 if (GNUNET_OK != res) 62 { 63 GNUNET_break_op (0); 64 return (GNUNET_NO == res) 65 ? MHD_YES 66 : MHD_NO; 67 } 68 } 69 70 /* finally, interact with DB until no serialization error */ 71 for (unsigned int i = 0; i<MAX_RETRIES; i++) 72 { 73 json_t *xcategory_name_i18n; 74 75 if (GNUNET_OK != 76 TMH_db->start (TMH_db->cls, 77 "POST /categories")) 78 { 79 GNUNET_break (0); 80 GNUNET_JSON_parse_free (spec); 81 return TALER_MHD_reply_with_error (connection, 82 MHD_HTTP_INTERNAL_SERVER_ERROR, 83 TALER_EC_GENERIC_DB_START_FAILED, 84 NULL); 85 } 86 qs = TMH_db->select_category_by_name (TMH_db->cls, 87 mi->settings.id, 88 category_name, 89 &xcategory_name_i18n, 90 &category_id); 91 switch (qs) 92 { 93 case GNUNET_DB_STATUS_HARD_ERROR: 94 /* Clean up and fail hard */ 95 GNUNET_break (0); 96 TMH_db->rollback (TMH_db->cls); 97 GNUNET_JSON_parse_free (spec); 98 return TALER_MHD_reply_with_error (connection, 99 MHD_HTTP_INTERNAL_SERVER_ERROR, 100 TALER_EC_GENERIC_DB_FETCH_FAILED, 101 NULL); 102 case GNUNET_DB_STATUS_SOFT_ERROR: 103 /* restart transaction */ 104 goto retry; 105 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 106 /* Good, we can proceed! */ 107 break; 108 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 109 /* idempotency check: is etp == tp? */ 110 { 111 bool eq; 112 113 eq = (1 == json_equal (xcategory_name_i18n, 114 category_name_i18n)); 115 json_decref (xcategory_name_i18n); 116 TMH_db->rollback (TMH_db->cls); 117 GNUNET_JSON_parse_free (spec); 118 return eq 119 ? TALER_MHD_REPLY_JSON_PACK (connection, 120 MHD_HTTP_OK, 121 GNUNET_JSON_pack_uint64 ("category_id", 122 category_id)) 123 : TALER_MHD_reply_with_error (connection, 124 MHD_HTTP_CONFLICT, 125 TALER_EC_MERCHANT_PRIVATE_POST_CATEGORIES_CONFLICT_CATEGORY_EXISTS, 126 category_name); 127 } 128 } /* end switch (qs) */ 129 130 qs = TMH_db->insert_category (TMH_db->cls, 131 mi->settings.id, 132 category_name, 133 category_name_i18n, 134 &category_id); 135 if (GNUNET_DB_STATUS_HARD_ERROR == qs) 136 { 137 TMH_db->rollback (TMH_db->cls); 138 break; 139 } 140 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) 141 { 142 qs = TMH_db->commit (TMH_db->cls); 143 if (GNUNET_DB_STATUS_SOFT_ERROR != qs) 144 break; 145 } 146 retry: 147 GNUNET_assert (GNUNET_DB_STATUS_SOFT_ERROR == qs); 148 TMH_db->rollback (TMH_db->cls); 149 } /* for RETRIES loop */ 150 GNUNET_JSON_parse_free (spec); 151 if (qs < 0) 152 { 153 GNUNET_break (0); 154 return TALER_MHD_reply_with_error ( 155 connection, 156 MHD_HTTP_INTERNAL_SERVER_ERROR, 157 (GNUNET_DB_STATUS_SOFT_ERROR == qs) 158 ? TALER_EC_GENERIC_DB_SOFT_FAILURE 159 : TALER_EC_GENERIC_DB_COMMIT_FAILED, 160 NULL); 161 } 162 return TALER_MHD_REPLY_JSON_PACK ( 163 connection, 164 MHD_HTTP_OK, 165 GNUNET_JSON_pack_uint64 ("category_id", 166 category_id)); 167 } 168 169 170 /* end of taler-merchant-httpd_private-post-categories.c */