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 : TMH_process_quantity_inputs (TMH_VK_QUANTITY,
144 12 : 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 2 : TALER_MERCHANTDB_product_details_free (&pd);
154 2 : GNUNET_break_op (0);
155 2 : return TALER_MHD_reply_with_error (connection,
156 : MHD_HTTP_BAD_REQUEST,
157 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
158 : eparam);
159 : }
160 : }
161 10 : quantity = normalized_quantity;
162 10 : qs = TMH_db->lock_product (TMH_db->cls,
163 10 : mi->settings.id,
164 : product_id,
165 : &uuid,
166 : quantity,
167 : normalized_quantity_frac,
168 : GNUNET_TIME_relative_to_timestamp (duration));
169 10 : TALER_MERCHANTDB_product_details_free (&pd);
170 : }
171 10 : switch (qs)
172 : {
173 0 : case GNUNET_DB_STATUS_HARD_ERROR:
174 0 : GNUNET_break (0);
175 0 : return TALER_MHD_reply_with_error (
176 : connection,
177 : MHD_HTTP_INTERNAL_SERVER_ERROR,
178 : TALER_EC_GENERIC_DB_STORE_FAILED,
179 : NULL);
180 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
181 0 : GNUNET_break (0);
182 0 : 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 3 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
188 3 : GNUNET_break_op (0);
189 3 : 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 7 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
195 7 : return TALER_MHD_reply_static (connection,
196 : MHD_HTTP_NO_CONTENT,
197 : NULL,
198 : NULL,
199 : 0);
200 : }
201 0 : GNUNET_assert (0);
202 : return MHD_NO;
203 : }
204 :
205 :
206 : /* end of taler-merchant-httpd_private-patch-products-ID-lock.c */
|