taler-merchant-httpd_post-private-products-PRODUCT_ID-lock.c (6920B)
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_post-private-products-PRODUCT_ID-lock.c 22 * @brief implementing POST /products/$ID/lock request handling 23 * @author Christian Grothoff 24 */ 25 #include "taler/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 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 TALER_MERCHANT_vk_process_quantity_inputs ( 144 TALER_MERCHANT_VK_QUANTITY, 145 pd.allow_fractional_quantity, 146 quantity_missing, 147 (int64_t) quantity, 148 unit_quantity_missing, 149 unit_quantity, 150 &normalized_quantity, 151 &normalized_quantity_frac, 152 &eparam)) 153 { 154 TALER_MERCHANTDB_product_details_free (&pd); 155 GNUNET_break_op (0); 156 return TALER_MHD_reply_with_error (connection, 157 MHD_HTTP_BAD_REQUEST, 158 TALER_EC_GENERIC_PARAMETER_MALFORMED, 159 eparam); 160 } 161 } 162 quantity = normalized_quantity; 163 qs = TMH_db->lock_product (TMH_db->cls, 164 mi->settings.id, 165 product_id, 166 &uuid, 167 quantity, 168 normalized_quantity_frac, 169 GNUNET_TIME_relative_to_timestamp (duration)); 170 TALER_MERCHANTDB_product_details_free (&pd); 171 } 172 switch (qs) 173 { 174 case GNUNET_DB_STATUS_HARD_ERROR: 175 GNUNET_break (0); 176 return TALER_MHD_reply_with_error ( 177 connection, 178 MHD_HTTP_INTERNAL_SERVER_ERROR, 179 TALER_EC_GENERIC_DB_STORE_FAILED, 180 NULL); 181 case GNUNET_DB_STATUS_SOFT_ERROR: 182 GNUNET_break (0); 183 return TALER_MHD_reply_with_error ( 184 connection, 185 MHD_HTTP_INTERNAL_SERVER_ERROR, 186 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 187 "Serialization error for single-statment request"); 188 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 189 GNUNET_break_op (0); 190 return TALER_MHD_reply_with_error ( 191 connection, 192 MHD_HTTP_GONE, 193 TALER_EC_MERCHANT_PRIVATE_POST_PRODUCTS_LOCK_INSUFFICIENT_STOCKS, 194 product_id); 195 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 196 return TALER_MHD_reply_static (connection, 197 MHD_HTTP_NO_CONTENT, 198 NULL, 199 NULL, 200 0); 201 } 202 GNUNET_assert (0); 203 return MHD_NO; 204 } 205 206 207 /* end of taler-merchant-httpd_post-private-products-PRODUCT_ID-lock.c */