taler-merchant-httpd_post-private-products-PRODUCT_ID-lock.c (7176B)
1 /* 2 This file is part of TALER 3 (C) 2020, 2021 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 /** 21 * @file src/backend/taler-merchant-httpd_post-private-products-PRODUCT_ID-lock.c 22 * @brief implementing POST /products/$ID/lock request handling 23 * @author Christian Grothoff 24 */ 25 #include "platform.h" 26 #include "taler-merchant-httpd_post-private-products-PRODUCT_ID-lock.h" 27 #include "taler-merchant-httpd_helper.h" 28 #include <taler/taler_json_lib.h> 29 #include "merchant-database/expire_locks.h" 30 #include "merchant-database/lock_product.h" 31 #include "merchant-database/lookup_product.h" 32 33 34 enum MHD_Result 35 TMH_private_post_products_ID_lock ( 36 const struct TMH_RequestHandler *rh, 37 struct MHD_Connection *connection, 38 struct TMH_HandlerContext *hc) 39 { 40 struct TMH_MerchantInstance *mi = hc->instance; 41 const char *product_id = hc->infix; 42 enum GNUNET_DB_QueryStatus qs; 43 const char *uuids; 44 struct GNUNET_Uuid uuid; 45 uint64_t quantity; 46 bool quantity_missing; 47 const char *unit_quantity = NULL; 48 bool unit_quantity_missing = true; 49 struct GNUNET_TIME_Relative duration; 50 struct GNUNET_JSON_Specification spec[] = { 51 GNUNET_JSON_spec_string ("lock_uuid", 52 &uuids), 53 GNUNET_JSON_spec_relative_time ("duration", 54 &duration), 55 GNUNET_JSON_spec_mark_optional ( 56 GNUNET_JSON_spec_uint64 ("quantity", 57 &quantity), 58 &quantity_missing), 59 GNUNET_JSON_spec_mark_optional ( 60 GNUNET_JSON_spec_string ("unit_quantity", 61 &unit_quantity), 62 &unit_quantity_missing), 63 GNUNET_JSON_spec_end () 64 }; 65 66 GNUNET_assert (NULL != mi); 67 GNUNET_assert (NULL != product_id); 68 { 69 enum GNUNET_GenericReturnValue res; 70 71 res = TALER_MHD_parse_json_data (connection, 72 hc->request_body, 73 spec); 74 if (GNUNET_OK != res) 75 return (GNUNET_NO == res) 76 ? MHD_YES 77 : MHD_NO; 78 } 79 TMH_uuid_from_string (uuids, 80 &uuid); 81 TALER_MERCHANTDB_expire_locks (TMH_db); 82 { 83 struct TALER_MERCHANTDB_ProductDetails pd = { 0 }; 84 size_t num_categories; 85 uint64_t *categories; 86 uint64_t normalized_quantity = 0; 87 uint32_t normalized_quantity_frac = 0; 88 89 if (quantity_missing && unit_quantity_missing) 90 { 91 quantity = 1; 92 quantity_missing = false; 93 } 94 else if ( (! quantity_missing) && 95 (quantity > (uint64_t) INT64_MAX) ) 96 { 97 GNUNET_break_op (0); 98 return TALER_MHD_reply_with_error (connection, 99 MHD_HTTP_BAD_REQUEST, 100 TALER_EC_GENERIC_PARAMETER_MALFORMED, 101 "quantity"); 102 } 103 104 qs = TALER_MERCHANTDB_lookup_product (TMH_db, 105 mi->settings.id, 106 product_id, 107 &pd, 108 &num_categories, 109 &categories); 110 switch (qs) 111 { 112 case GNUNET_DB_STATUS_HARD_ERROR: 113 GNUNET_break (0); 114 TALER_MERCHANTDB_product_details_free (&pd); 115 GNUNET_free (categories); 116 return TALER_MHD_reply_with_error ( 117 connection, 118 MHD_HTTP_INTERNAL_SERVER_ERROR, 119 TALER_EC_GENERIC_DB_FETCH_FAILED, 120 "lookup_product"); 121 case GNUNET_DB_STATUS_SOFT_ERROR: 122 GNUNET_break (0); 123 TALER_MERCHANTDB_product_details_free (&pd); 124 GNUNET_free (categories); 125 return TALER_MHD_reply_with_error ( 126 connection, 127 MHD_HTTP_INTERNAL_SERVER_ERROR, 128 TALER_EC_GENERIC_DB_SOFT_FAILURE, 129 "lookup_product"); 130 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 131 GNUNET_break_op (0); 132 TALER_MERCHANTDB_product_details_free (&pd); 133 GNUNET_free (categories); 134 return TALER_MHD_reply_with_error ( 135 connection, 136 MHD_HTTP_NOT_FOUND, 137 TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN, 138 product_id); 139 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 140 break; 141 } 142 GNUNET_free (categories); 143 { 144 const char *eparam; 145 if (GNUNET_OK != 146 TALER_MERCHANT_vk_process_quantity_inputs ( 147 TALER_MERCHANT_VK_QUANTITY, 148 pd.allow_fractional_quantity, 149 quantity_missing, 150 (int64_t) quantity, 151 unit_quantity_missing, 152 unit_quantity, 153 &normalized_quantity, 154 &normalized_quantity_frac, 155 &eparam)) 156 { 157 TALER_MERCHANTDB_product_details_free (&pd); 158 GNUNET_break_op (0); 159 return TALER_MHD_reply_with_error (connection, 160 MHD_HTTP_BAD_REQUEST, 161 TALER_EC_GENERIC_PARAMETER_MALFORMED, 162 eparam); 163 } 164 } 165 quantity = normalized_quantity; 166 qs = TALER_MERCHANTDB_lock_product (TMH_db, 167 mi->settings.id, 168 product_id, 169 &uuid, 170 quantity, 171 normalized_quantity_frac, 172 GNUNET_TIME_relative_to_timestamp (duration)); 173 TALER_MERCHANTDB_product_details_free (&pd); 174 } 175 switch (qs) 176 { 177 case GNUNET_DB_STATUS_HARD_ERROR: 178 GNUNET_break (0); 179 return TALER_MHD_reply_with_error ( 180 connection, 181 MHD_HTTP_INTERNAL_SERVER_ERROR, 182 TALER_EC_GENERIC_DB_STORE_FAILED, 183 NULL); 184 case GNUNET_DB_STATUS_SOFT_ERROR: 185 GNUNET_break (0); 186 return TALER_MHD_reply_with_error ( 187 connection, 188 MHD_HTTP_INTERNAL_SERVER_ERROR, 189 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 190 "Serialization error for single-statment request"); 191 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 192 GNUNET_break_op (0); 193 return TALER_MHD_reply_with_error ( 194 connection, 195 MHD_HTTP_GONE, 196 TALER_EC_MERCHANT_PRIVATE_POST_PRODUCTS_LOCK_INSUFFICIENT_STOCKS, 197 product_id); 198 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 199 return TALER_MHD_reply_static (connection, 200 MHD_HTTP_NO_CONTENT, 201 NULL, 202 NULL, 203 0); 204 } 205 GNUNET_assert (0); 206 return MHD_NO; 207 } 208 209 210 /* end of taler-merchant-httpd_post-private-products-PRODUCT_ID-lock.c */