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