taler-merchant-httpd_private-post-units.c (7315B)
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 TMH_private_post_units (const struct TMH_RequestHandler *rh, 29 struct MHD_Connection *connection, 30 struct TMH_HandlerContext *hc) 31 { 32 struct TMH_MerchantInstance *mi = hc->instance; 33 struct TALER_MERCHANTDB_UnitDetails nud = { 0 }; 34 bool allow_fraction_missing = true; 35 bool unit_precision_missing = true; 36 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 GNUNET_JSON_spec_string ("unit", 42 (const char **) &nud.unit), 43 GNUNET_JSON_spec_string ("unit_name_long", 44 (const char **) &nud.unit_name_long), 45 GNUNET_JSON_spec_string ("unit_name_short", 46 (const char **) &nud.unit_name_short), 47 GNUNET_JSON_spec_mark_optional ( 48 GNUNET_JSON_spec_json ("unit_name_long_i18n", 49 &nud.unit_name_long_i18n), 50 NULL), 51 GNUNET_JSON_spec_mark_optional ( 52 GNUNET_JSON_spec_json ("unit_name_short_i18n", 53 &nud.unit_name_short_i18n), 54 NULL), 55 GNUNET_JSON_spec_mark_optional ( 56 GNUNET_JSON_spec_bool ("unit_allow_fraction", 57 &nud.unit_allow_fraction), 58 &allow_fraction_missing), 59 GNUNET_JSON_spec_mark_optional ( 60 GNUNET_JSON_spec_uint32 ("unit_precision_level", 61 &nud.unit_precision_level), 62 &unit_precision_missing), 63 GNUNET_JSON_spec_mark_optional ( 64 GNUNET_JSON_spec_bool ("unit_active", 65 &nud.unit_active), 66 &unit_active_missing), 67 GNUNET_JSON_spec_end () 68 }; 69 70 71 GNUNET_assert (NULL != mi); 72 res = TALER_MHD_parse_json_data (connection, 73 hc->request_body, 74 spec); 75 (void) rh; 76 77 if (GNUNET_OK != res) 78 { 79 GNUNET_break_op (0); 80 return (GNUNET_NO == res) 81 ? MHD_YES 82 : MHD_NO; 83 } 84 85 if (allow_fraction_missing) 86 { 87 nud.unit_allow_fraction = false; 88 nud.unit_precision_level = 0; 89 } 90 else 91 { 92 if (! nud.unit_allow_fraction) 93 { 94 nud.unit_precision_level = 0; 95 unit_precision_missing = false; 96 } 97 else if (unit_precision_missing) 98 { 99 nud.unit_precision_level = 0; 100 } 101 } 102 if (nud.unit_precision_level > TMH_MAX_FRACTIONAL_PRECISION_LEVEL) 103 { 104 GNUNET_break_op (0); 105 ret = TALER_MHD_reply_with_error (connection, 106 MHD_HTTP_BAD_REQUEST, 107 TALER_EC_GENERIC_PARAMETER_MALFORMED, 108 "unit_precision_level"); 109 goto cleanup; 110 } 111 if (unit_active_missing) 112 nud.unit_active = true; 113 114 if (NULL == nud.unit_name_long_i18n) 115 nud.unit_name_long_i18n = json_object (); 116 if (NULL == nud.unit_name_short_i18n) 117 nud.unit_name_short_i18n = json_object (); 118 119 if (! TALER_JSON_check_i18n (nud.unit_name_long_i18n)) 120 { 121 GNUNET_break_op (0); 122 ret = TALER_MHD_reply_with_error (connection, 123 MHD_HTTP_BAD_REQUEST, 124 TALER_EC_GENERIC_PARAMETER_MALFORMED, 125 "unit_name_long_i18n"); 126 goto cleanup; 127 } 128 if (! TALER_JSON_check_i18n (nud.unit_name_short_i18n)) 129 { 130 GNUNET_break_op (0); 131 ret = TALER_MHD_reply_with_error (connection, 132 MHD_HTTP_BAD_REQUEST, 133 TALER_EC_GENERIC_PARAMETER_MALFORMED, 134 "unit_name_short_i18n"); 135 goto cleanup; 136 } 137 138 nud.unit_builtin = false; 139 140 { 141 bool no_instance = false; 142 bool conflict = false; 143 uint64_t unit_serial = 0; 144 145 qs = TMH_db->insert_unit (TMH_db->cls, 146 mi->settings.id, 147 &nud, 148 &no_instance, 149 &conflict, 150 &unit_serial); 151 152 switch (qs) 153 { 154 case GNUNET_DB_STATUS_HARD_ERROR: 155 GNUNET_break (0); 156 ret = TALER_MHD_reply_with_error (connection, 157 MHD_HTTP_INTERNAL_SERVER_ERROR, 158 TALER_EC_GENERIC_DB_STORE_FAILED, 159 NULL); 160 goto cleanup; 161 case GNUNET_DB_STATUS_SOFT_ERROR: 162 GNUNET_break (0); 163 ret = TALER_MHD_reply_with_error (connection, 164 MHD_HTTP_INTERNAL_SERVER_ERROR, 165 TALER_EC_GENERIC_DB_SOFT_FAILURE, 166 NULL); 167 goto cleanup; 168 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 169 GNUNET_break (0); 170 ret = TALER_MHD_reply_with_error (connection, 171 MHD_HTTP_INTERNAL_SERVER_ERROR, 172 TALER_EC_GENERIC_DB_INVARIANT_FAILURE, 173 "insert_unit"); 174 goto cleanup; 175 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 176 break; 177 } 178 179 if (no_instance) 180 { 181 ret = TALER_MHD_reply_with_error (connection, 182 MHD_HTTP_NOT_FOUND, 183 TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN, 184 mi->settings.id); 185 goto cleanup; 186 } 187 if (conflict) 188 { 189 ret = TALER_MHD_reply_with_error (connection, 190 MHD_HTTP_CONFLICT, 191 TALER_EC_MERCHANT_GENERIC_UNIT_BUILTIN, 192 nud.unit); 193 goto cleanup; 194 } 195 196 ret = TALER_MHD_reply_static (connection, 197 MHD_HTTP_NO_CONTENT, 198 NULL, 199 NULL, 200 0); 201 } 202 203 cleanup: 204 if (NULL != nud.unit_name_long_i18n) 205 { 206 json_decref (nud.unit_name_long_i18n); 207 nud.unit_name_long_i18n = NULL; 208 } 209 if (NULL != nud.unit_name_short_i18n) 210 { 211 json_decref (nud.unit_name_short_i18n); 212 nud.unit_name_short_i18n = NULL; 213 } 214 GNUNET_JSON_parse_free (spec); 215 return ret; 216 } 217 218 219 /* end of taler-merchant-httpd_private-post-units.c */