Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 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 : * @file taler-merchant-httpd_private-post-categories.c
21 : * @brief implementing POST /private/categories request handling
22 : * @author Christian Grothoff
23 : */
24 : #include "platform.h"
25 : #include "taler-merchant-httpd_private-post-categories.h"
26 : #include "taler-merchant-httpd_helper.h"
27 : #include <taler/taler_json_lib.h>
28 :
29 :
30 : /**
31 : * How often do we retry the simple INSERT database transaction?
32 : */
33 : #define MAX_RETRIES 3
34 :
35 :
36 : MHD_RESULT
37 0 : TMH_private_post_categories (const struct TMH_RequestHandler *rh,
38 : struct MHD_Connection *connection,
39 : struct TMH_HandlerContext *hc)
40 : {
41 0 : struct TMH_MerchantInstance *mi = hc->instance;
42 : const char *category_name;
43 : const json_t *category_name_i18n;
44 : uint64_t category_id;
45 : struct GNUNET_JSON_Specification spec[] = {
46 0 : GNUNET_JSON_spec_string ("name",
47 : &category_name),
48 0 : GNUNET_JSON_spec_object_const ("name_i18n",
49 : &category_name_i18n),
50 0 : GNUNET_JSON_spec_end ()
51 : };
52 : enum GNUNET_DB_QueryStatus qs;
53 :
54 0 : GNUNET_assert (NULL != mi);
55 : {
56 : enum GNUNET_GenericReturnValue res;
57 :
58 0 : res = TALER_MHD_parse_json_data (connection,
59 0 : hc->request_body,
60 : spec);
61 0 : if (GNUNET_OK != res)
62 : {
63 0 : GNUNET_break_op (0);
64 : return (GNUNET_NO == res)
65 : ? MHD_YES
66 0 : : MHD_NO;
67 : }
68 : }
69 :
70 : /* finally, interact with DB until no serialization error */
71 0 : for (unsigned int i = 0; i<MAX_RETRIES; i++)
72 : {
73 : json_t *xcategory_name_i18n;
74 :
75 0 : if (GNUNET_OK !=
76 0 : TMH_db->start (TMH_db->cls,
77 : "POST /categories"))
78 : {
79 0 : GNUNET_break (0);
80 0 : GNUNET_JSON_parse_free (spec);
81 0 : return TALER_MHD_reply_with_error (connection,
82 : MHD_HTTP_INTERNAL_SERVER_ERROR,
83 : TALER_EC_GENERIC_DB_START_FAILED,
84 : NULL);
85 : }
86 0 : qs = TMH_db->select_category_by_name (TMH_db->cls,
87 0 : mi->settings.id,
88 : category_name,
89 : &xcategory_name_i18n,
90 : &category_id);
91 0 : switch (qs)
92 : {
93 0 : case GNUNET_DB_STATUS_HARD_ERROR:
94 : /* Clean up and fail hard */
95 0 : GNUNET_break (0);
96 0 : TMH_db->rollback (TMH_db->cls);
97 0 : GNUNET_JSON_parse_free (spec);
98 0 : return TALER_MHD_reply_with_error (connection,
99 : MHD_HTTP_INTERNAL_SERVER_ERROR,
100 : TALER_EC_GENERIC_DB_FETCH_FAILED,
101 : NULL);
102 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
103 : /* restart transaction */
104 0 : goto retry;
105 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
106 : /* Good, we can proceed! */
107 0 : break;
108 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
109 : /* idempotency check: is etp == tp? */
110 : {
111 : bool eq;
112 :
113 0 : eq = (1 == json_equal (xcategory_name_i18n,
114 : category_name_i18n));
115 0 : json_decref (xcategory_name_i18n);
116 0 : TMH_db->rollback (TMH_db->cls);
117 0 : GNUNET_JSON_parse_free (spec);
118 : return eq
119 0 : ? TALER_MHD_REPLY_JSON_PACK (connection,
120 : MHD_HTTP_OK,
121 : GNUNET_JSON_pack_uint64 ("category_id",
122 : category_id))
123 0 : : TALER_MHD_reply_with_error (connection,
124 : MHD_HTTP_CONFLICT,
125 : TALER_EC_MERCHANT_PRIVATE_POST_CATEGORIES_CONFLICT_CATEGORY_EXISTS,
126 : category_name);
127 : }
128 : } /* end switch (qs) */
129 :
130 0 : qs = TMH_db->insert_category (TMH_db->cls,
131 0 : mi->settings.id,
132 : category_name,
133 : category_name_i18n,
134 : &category_id);
135 0 : if (GNUNET_DB_STATUS_HARD_ERROR == qs)
136 : {
137 0 : TMH_db->rollback (TMH_db->cls);
138 0 : break;
139 : }
140 0 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
141 : {
142 0 : qs = TMH_db->commit (TMH_db->cls);
143 0 : if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
144 0 : break;
145 : }
146 0 : retry:
147 0 : GNUNET_assert (GNUNET_DB_STATUS_SOFT_ERROR == qs);
148 0 : TMH_db->rollback (TMH_db->cls);
149 : } /* for RETRIES loop */
150 0 : GNUNET_JSON_parse_free (spec);
151 0 : if (qs < 0)
152 : {
153 0 : GNUNET_break (0);
154 0 : return TALER_MHD_reply_with_error (
155 : connection,
156 : MHD_HTTP_INTERNAL_SERVER_ERROR,
157 : (GNUNET_DB_STATUS_SOFT_ERROR == qs)
158 : ? TALER_EC_GENERIC_DB_SOFT_FAILURE
159 : : TALER_EC_GENERIC_DB_COMMIT_FAILED,
160 : NULL);
161 : }
162 0 : return TALER_MHD_REPLY_JSON_PACK (
163 : connection,
164 : MHD_HTTP_OK,
165 : GNUNET_JSON_pack_uint64 ("category_id",
166 : category_id));
167 : }
168 :
169 :
170 : /* end of taler-merchant-httpd_private-post-categories.c */
|