Line data Source code
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 14 : TMH_private_post_products_ID_lock (
33 : const struct TMH_RequestHandler *rh,
34 : struct MHD_Connection *connection,
35 : struct TMH_HandlerContext *hc)
36 : {
37 14 : struct TMH_MerchantInstance *mi = hc->instance;
38 14 : 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 14 : const char *unit_quantity = NULL;
45 14 : bool unit_quantity_missing = true;
46 : struct GNUNET_TIME_Relative duration;
47 : struct GNUNET_JSON_Specification spec[] = {
48 14 : GNUNET_JSON_spec_string ("lock_uuid",
49 : &uuids),
50 14 : GNUNET_JSON_spec_relative_time ("duration",
51 : &duration),
52 14 : GNUNET_JSON_spec_mark_optional (
53 : GNUNET_JSON_spec_uint64 ("quantity",
54 : &quantity),
55 : &quantity_missing),
56 14 : GNUNET_JSON_spec_mark_optional (
57 : GNUNET_JSON_spec_string ("unit_quantity",
58 : &unit_quantity),
59 : &unit_quantity_missing),
60 14 : GNUNET_JSON_spec_end ()
61 : };
62 :
63 14 : GNUNET_assert (NULL != mi);
64 14 : GNUNET_assert (NULL != product_id);
65 : {
66 : enum GNUNET_GenericReturnValue res;
67 :
68 14 : res = TALER_MHD_parse_json_data (connection,
69 14 : hc->request_body,
70 : spec);
71 14 : if (GNUNET_OK != res)
72 : return (GNUNET_NO == res)
73 : ? MHD_YES
74 0 : : MHD_NO;
75 : }
76 14 : TMH_uuid_from_string (uuids,
77 : &uuid);
78 14 : TMH_db->expire_locks (TMH_db->cls);
79 : {
80 14 : struct TALER_MERCHANTDB_ProductDetails pd = { 0 };
81 : size_t num_categories;
82 : uint64_t *categories;
83 14 : uint64_t normalized_quantity = 0;
84 14 : uint32_t normalized_quantity_frac = 0;
85 :
86 14 : if (quantity_missing && unit_quantity_missing)
87 : {
88 0 : quantity = 1;
89 0 : quantity_missing = false;
90 : }
91 14 : else if ( (! quantity_missing) &&
92 0 : (quantity > (uint64_t) INT64_MAX) )
93 : {
94 0 : GNUNET_break_op (0);
95 4 : return TALER_MHD_reply_with_error (connection,
96 : MHD_HTTP_BAD_REQUEST,
97 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
98 : "quantity");
99 : }
100 :
101 14 : qs = TMH_db->lookup_product (TMH_db->cls,
102 14 : mi->settings.id,
103 : product_id,
104 : &pd,
105 : &num_categories,
106 : &categories);
107 14 : switch (qs)
108 : {
109 0 : case GNUNET_DB_STATUS_HARD_ERROR:
110 0 : GNUNET_break (0);
111 0 : TALER_MERCHANTDB_product_details_free (&pd);
112 0 : GNUNET_free (categories);
113 0 : 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 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
119 0 : GNUNET_break (0);
120 0 : TALER_MERCHANTDB_product_details_free (&pd);
121 0 : GNUNET_free (categories);
122 0 : 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 2 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
128 2 : GNUNET_break_op (0);
129 2 : TALER_MERCHANTDB_product_details_free (&pd);
130 2 : GNUNET_free (categories);
131 2 : return TALER_MHD_reply_with_error (
132 : connection,
133 : MHD_HTTP_NOT_FOUND,
134 : TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN,
135 : product_id);
136 12 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
137 12 : break;
138 : }
139 12 : GNUNET_free (categories);
140 : {
141 : const char *eparam;
142 12 : if (GNUNET_OK !=
143 12 : TALER_MERCHANT_vk_process_quantity_inputs (
144 : TALER_MERCHANT_VK_QUANTITY,
145 12 : 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 2 : TALER_MERCHANTDB_product_details_free (&pd);
155 2 : GNUNET_break_op (0);
156 2 : return TALER_MHD_reply_with_error (connection,
157 : MHD_HTTP_BAD_REQUEST,
158 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
159 : eparam);
160 : }
161 : }
162 10 : quantity = normalized_quantity;
163 10 : qs = TMH_db->lock_product (TMH_db->cls,
164 10 : mi->settings.id,
165 : product_id,
166 : &uuid,
167 : quantity,
168 : normalized_quantity_frac,
169 : GNUNET_TIME_relative_to_timestamp (duration));
170 10 : TALER_MERCHANTDB_product_details_free (&pd);
171 : }
172 10 : switch (qs)
173 : {
174 0 : case GNUNET_DB_STATUS_HARD_ERROR:
175 0 : GNUNET_break (0);
176 0 : return TALER_MHD_reply_with_error (
177 : connection,
178 : MHD_HTTP_INTERNAL_SERVER_ERROR,
179 : TALER_EC_GENERIC_DB_STORE_FAILED,
180 : NULL);
181 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
182 0 : GNUNET_break (0);
183 0 : 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 3 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
189 3 : GNUNET_break_op (0);
190 3 : 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 7 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
196 7 : return TALER_MHD_reply_static (connection,
197 : MHD_HTTP_NO_CONTENT,
198 : NULL,
199 : NULL,
200 : 0);
201 : }
202 0 : GNUNET_assert (0);
203 : return MHD_NO;
204 : }
205 :
206 :
207 : /* end of taler-merchant-httpd_private-patch-products-ID-lock.c */
|