Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2025 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU Affero General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file taler-merchant-httpd_private-post-units.c
18 : * @brief implement POST /private/units
19 : * @author Bohdan Potuzhnyi
20 : */
21 : #include "platform.h"
22 : #include "taler-merchant-httpd_private-post-units.h"
23 : #include "taler-merchant-httpd_helper.h"
24 : #include <taler/taler_json_lib.h>
25 :
26 :
27 : MHD_RESULT
28 6 : TMH_private_post_units (const struct TMH_RequestHandler *rh,
29 : struct MHD_Connection *connection,
30 : struct TMH_HandlerContext *hc)
31 : {
32 6 : struct TMH_MerchantInstance *mi = hc->instance;
33 6 : struct TALER_MERCHANTDB_UnitDetails nud = { 0 };
34 6 : bool allow_fraction_missing = true;
35 6 : bool unit_precision_missing = true;
36 6 : bool unit_active_missing = true;
37 : enum GNUNET_GenericReturnValue res;
38 : enum GNUNET_DB_QueryStatus qs;
39 : MHD_RESULT ret;
40 : struct GNUNET_JSON_Specification spec[] = {
41 6 : GNUNET_JSON_spec_string ("unit",
42 : (const char **) &nud.unit),
43 6 : GNUNET_JSON_spec_string ("unit_name_long",
44 : (const char **) &nud.unit_name_long),
45 6 : GNUNET_JSON_spec_string ("unit_name_short",
46 : (const char **) &nud.unit_name_short),
47 6 : GNUNET_JSON_spec_mark_optional (
48 : GNUNET_JSON_spec_json ("unit_name_long_i18n",
49 : &nud.unit_name_long_i18n),
50 : NULL),
51 6 : GNUNET_JSON_spec_mark_optional (
52 : GNUNET_JSON_spec_json ("unit_name_short_i18n",
53 : &nud.unit_name_short_i18n),
54 : NULL),
55 6 : GNUNET_JSON_spec_mark_optional (
56 : GNUNET_JSON_spec_bool ("unit_allow_fraction",
57 : &nud.unit_allow_fraction),
58 : &allow_fraction_missing),
59 6 : GNUNET_JSON_spec_mark_optional (
60 : GNUNET_JSON_spec_uint32 ("unit_precision_level",
61 : &nud.unit_precision_level),
62 : &unit_precision_missing),
63 6 : GNUNET_JSON_spec_mark_optional (
64 : GNUNET_JSON_spec_bool ("unit_active",
65 : &nud.unit_active),
66 : &unit_active_missing),
67 6 : GNUNET_JSON_spec_end ()
68 : };
69 :
70 :
71 6 : GNUNET_assert (NULL != mi);
72 6 : res = TALER_MHD_parse_json_data (connection,
73 6 : hc->request_body,
74 : spec);
75 : (void) rh;
76 :
77 6 : if (GNUNET_OK != res)
78 : {
79 0 : GNUNET_break_op (0);
80 : return (GNUNET_NO == res)
81 : ? MHD_YES
82 0 : : MHD_NO;
83 : }
84 :
85 6 : if (allow_fraction_missing)
86 : {
87 0 : nud.unit_allow_fraction = false;
88 0 : nud.unit_precision_level = 0;
89 : }
90 : else
91 : {
92 6 : if (! nud.unit_allow_fraction)
93 : {
94 4 : nud.unit_precision_level = 0;
95 4 : unit_precision_missing = false;
96 : }
97 2 : else if (unit_precision_missing)
98 : {
99 0 : nud.unit_precision_level = 0;
100 : }
101 : }
102 6 : if (nud.unit_precision_level > TMH_MAX_FRACTIONAL_PRECISION_LEVEL)
103 : {
104 0 : GNUNET_break_op (0);
105 0 : ret = TALER_MHD_reply_with_error (connection,
106 : MHD_HTTP_BAD_REQUEST,
107 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
108 : "unit_precision_level");
109 0 : goto cleanup;
110 : }
111 6 : if (unit_active_missing)
112 0 : nud.unit_active = true;
113 :
114 6 : if (NULL == nud.unit_name_long_i18n)
115 2 : nud.unit_name_long_i18n = json_object ();
116 6 : if (NULL == nud.unit_name_short_i18n)
117 2 : nud.unit_name_short_i18n = json_object ();
118 :
119 6 : if (! TALER_JSON_check_i18n (nud.unit_name_long_i18n))
120 : {
121 0 : GNUNET_break_op (0);
122 0 : ret = TALER_MHD_reply_with_error (connection,
123 : MHD_HTTP_BAD_REQUEST,
124 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
125 : "unit_name_long_i18n");
126 0 : goto cleanup;
127 : }
128 6 : if (! TALER_JSON_check_i18n (nud.unit_name_short_i18n))
129 : {
130 0 : GNUNET_break_op (0);
131 0 : ret = TALER_MHD_reply_with_error (connection,
132 : MHD_HTTP_BAD_REQUEST,
133 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
134 : "unit_name_short_i18n");
135 0 : goto cleanup;
136 : }
137 :
138 6 : nud.unit_builtin = false;
139 :
140 : {
141 6 : bool no_instance = false;
142 6 : bool conflict = false;
143 6 : uint64_t unit_serial = 0;
144 :
145 6 : qs = TMH_db->insert_unit (TMH_db->cls,
146 6 : mi->settings.id,
147 : &nud,
148 : &no_instance,
149 : &conflict,
150 : &unit_serial);
151 :
152 6 : switch (qs)
153 : {
154 0 : case GNUNET_DB_STATUS_HARD_ERROR:
155 0 : GNUNET_break (0);
156 0 : ret = TALER_MHD_reply_with_error (connection,
157 : MHD_HTTP_INTERNAL_SERVER_ERROR,
158 : TALER_EC_GENERIC_DB_STORE_FAILED,
159 : NULL);
160 2 : goto cleanup;
161 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
162 0 : GNUNET_break (0);
163 0 : ret = TALER_MHD_reply_with_error (connection,
164 : MHD_HTTP_INTERNAL_SERVER_ERROR,
165 : TALER_EC_GENERIC_DB_SOFT_FAILURE,
166 : NULL);
167 0 : goto cleanup;
168 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
169 0 : GNUNET_break (0);
170 0 : ret = TALER_MHD_reply_with_error (connection,
171 : MHD_HTTP_INTERNAL_SERVER_ERROR,
172 : TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
173 : "insert_unit");
174 0 : goto cleanup;
175 6 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
176 6 : break;
177 : }
178 :
179 6 : if (no_instance)
180 : {
181 0 : ret = TALER_MHD_reply_with_error (connection,
182 : MHD_HTTP_NOT_FOUND,
183 : TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN,
184 0 : mi->settings.id);
185 0 : goto cleanup;
186 : }
187 6 : if (conflict)
188 : {
189 2 : ret = TALER_MHD_reply_with_error (connection,
190 : MHD_HTTP_CONFLICT,
191 : TALER_EC_MERCHANT_GENERIC_UNIT_BUILTIN,
192 2 : nud.unit);
193 2 : goto cleanup;
194 : }
195 :
196 4 : ret = TALER_MHD_reply_static (connection,
197 : MHD_HTTP_NO_CONTENT,
198 : NULL,
199 : NULL,
200 : 0);
201 : }
202 :
203 6 : cleanup:
204 6 : if (NULL != nud.unit_name_long_i18n)
205 : {
206 6 : json_decref (nud.unit_name_long_i18n);
207 6 : nud.unit_name_long_i18n = NULL;
208 : }
209 6 : if (NULL != nud.unit_name_short_i18n)
210 : {
211 6 : json_decref (nud.unit_name_short_i18n);
212 6 : nud.unit_name_short_i18n = NULL;
213 : }
214 6 : GNUNET_JSON_parse_free (spec);
215 6 : return ret;
216 : }
217 :
218 :
219 : /* end of taler-merchant-httpd_private-post-units.c */
|