Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2022, 2024 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 src/backend/taler-merchant-httpd_patch-private-templates-TEMPLATE_ID.c
22 : * @brief implementing PATCH /templates/$ID request handling
23 : * @author Priscilla HUANG
24 : */
25 : #include "platform.h"
26 : #include "taler-merchant-httpd_patch-private-templates-TEMPLATE_ID.h"
27 : #include "taler-merchant-httpd_helper.h"
28 : #include <taler/taler_json_lib.h>
29 : #include "merchant-database/get_otp_device_serial.h"
30 : #include "merchant-database/update_template.h"
31 :
32 :
33 : /**
34 : * PATCH configuration of an existing instance, given its configuration.
35 : *
36 : * @param rh context of the handler
37 : * @param connection the MHD connection to handle
38 : * @param[in,out] hc context with further information about the request
39 : * @return MHD result code
40 : */
41 : enum MHD_Result
42 10 : TMH_private_patch_templates_ID (const struct TMH_RequestHandler *rh,
43 : struct MHD_Connection *connection,
44 : struct TMH_HandlerContext *hc)
45 : {
46 10 : struct TMH_MerchantInstance *mi = hc->instance;
47 10 : const char *template_id = hc->infix;
48 10 : struct TALER_MERCHANTDB_TemplateDetails tp = {0};
49 : enum GNUNET_DB_QueryStatus qs;
50 : struct GNUNET_JSON_Specification spec[] = {
51 10 : GNUNET_JSON_spec_string ("template_description",
52 : (const char **) &tp.template_description),
53 10 : GNUNET_JSON_spec_mark_optional (
54 : TALER_JSON_spec_slug ("otp_id",
55 : (const char **) &tp.otp_id),
56 : NULL),
57 10 : GNUNET_JSON_spec_json ("template_contract",
58 : &tp.template_contract),
59 10 : GNUNET_JSON_spec_mark_optional (
60 : GNUNET_JSON_spec_json ("editable_defaults",
61 : &tp.editable_defaults),
62 : NULL),
63 10 : GNUNET_JSON_spec_end ()
64 : };
65 :
66 10 : GNUNET_assert (NULL != mi);
67 10 : GNUNET_assert (NULL != template_id);
68 : {
69 : enum GNUNET_GenericReturnValue res;
70 :
71 10 : res = TALER_MHD_parse_json_data (connection,
72 10 : hc->request_body,
73 : spec);
74 10 : if (GNUNET_OK != res)
75 : return (GNUNET_NO == res)
76 : ? MHD_YES
77 0 : : MHD_NO;
78 : }
79 :
80 10 : if (! TALER_MERCHANT_template_contract_valid (tp.template_contract))
81 : {
82 2 : GNUNET_break_op (0);
83 2 : GNUNET_JSON_parse_free (spec);
84 2 : return TALER_MHD_reply_with_error (connection,
85 : MHD_HTTP_BAD_REQUEST,
86 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
87 : "template_contract");
88 : }
89 8 : if (NULL != tp.editable_defaults)
90 : {
91 : const char *key;
92 : json_t *val;
93 :
94 0 : json_object_foreach (tp.editable_defaults, key, val)
95 : {
96 0 : if (NULL !=
97 0 : json_object_get (tp.template_contract,
98 : key))
99 : {
100 : char *msg;
101 : enum MHD_Result ret;
102 :
103 0 : GNUNET_break_op (0);
104 0 : GNUNET_asprintf (&msg,
105 : "editable_defaults::%s conflicts with template_contract",
106 : key);
107 0 : GNUNET_JSON_parse_free (spec);
108 0 : ret = TALER_MHD_reply_with_error (
109 : connection,
110 : MHD_HTTP_BAD_REQUEST,
111 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
112 : msg);
113 0 : GNUNET_free (msg);
114 0 : return ret;
115 : }
116 : }
117 : }
118 :
119 8 : if (NULL != tp.otp_id)
120 : {
121 : uint64_t otp_serial;
122 :
123 : /* Note: without this pre-check, an unknown @e otp_id would
124 : simply resolve to NULL in the UPDATE and thus *silently*
125 : remove the OTP device binding of the template. */
126 6 : qs = TALER_MERCHANTDB_get_otp_device_serial (TMH_db,
127 6 : mi->settings.id,
128 6 : tp.otp_id,
129 : &otp_serial);
130 6 : switch (qs)
131 : {
132 0 : case GNUNET_DB_STATUS_HARD_ERROR:
133 : case GNUNET_DB_STATUS_SOFT_ERROR:
134 0 : GNUNET_break (0);
135 0 : GNUNET_JSON_parse_free (spec);
136 2 : return TALER_MHD_reply_with_error (connection,
137 : MHD_HTTP_INTERNAL_SERVER_ERROR,
138 : TALER_EC_GENERIC_DB_FETCH_FAILED,
139 : "get_otp_device_serial");
140 2 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
141 2 : GNUNET_JSON_parse_free (spec);
142 2 : return TALER_MHD_reply_with_error (connection,
143 : MHD_HTTP_NOT_FOUND,
144 : TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN,
145 2 : tp.otp_id);
146 4 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
147 4 : break;
148 : }
149 : }
150 :
151 6 : qs = TALER_MERCHANTDB_update_template (TMH_db,
152 6 : mi->settings.id,
153 : template_id,
154 : &tp);
155 : {
156 6 : enum MHD_Result ret = MHD_NO;
157 :
158 6 : switch (qs)
159 : {
160 0 : case GNUNET_DB_STATUS_HARD_ERROR:
161 0 : GNUNET_break (0);
162 0 : ret = TALER_MHD_reply_with_error (
163 : connection,
164 : MHD_HTTP_INTERNAL_SERVER_ERROR,
165 : TALER_EC_GENERIC_DB_STORE_FAILED,
166 : NULL);
167 0 : break;
168 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
169 0 : GNUNET_break (0);
170 0 : ret = TALER_MHD_reply_with_error (
171 : connection,
172 : MHD_HTTP_INTERNAL_SERVER_ERROR,
173 : TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
174 : "unexpected serialization problem");
175 0 : break;
176 2 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
177 2 : ret = TALER_MHD_reply_with_error (
178 : connection,
179 : MHD_HTTP_NOT_FOUND,
180 : TALER_EC_MERCHANT_GENERIC_TEMPLATE_UNKNOWN,
181 : template_id);
182 2 : break;
183 4 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
184 4 : ret = TALER_MHD_reply_static (connection,
185 : MHD_HTTP_NO_CONTENT,
186 : NULL,
187 : NULL,
188 : 0);
189 4 : break;
190 : }
191 6 : GNUNET_JSON_parse_free (spec);
192 6 : return ret;
193 : }
194 : }
195 :
196 :
197 : /* end of taler-merchant-httpd_patch-private-templates-TEMPLATE_ID.c */
|