taler-merchant-httpd_patch-private-reports-REPORT_ID.c (7008B)
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 Affero General Public License for more 12 details. 13 14 You should have received a copy of the GNU Affero General Public License 15 along with TALER; see the file COPYING. If not, see 16 <http://www.gnu.org/licenses/> 17 */ 18 /** 19 * @file src/backend/taler-merchant-httpd_patch-private-reports-REPORT_ID.c 20 * @brief implementation of PATCH /private/reports/$REPORT_ID 21 * @author Christian Grothoff 22 */ 23 #include "platform.h" 24 #include "taler-merchant-httpd_patch-private-reports-REPORT_ID.h" 25 #include <taler/taler_json_lib.h> 26 #include <taler/taler_dbevents.h> 27 #include "taler/taler_merchant_util.h" 28 #include "merchant-database/update_report.h" 29 #include "merchant-database/event_notify.h" 30 31 32 enum MHD_Result 33 TMH_private_patch_report (const struct TMH_RequestHandler *rh, 34 struct MHD_Connection *connection, 35 struct TMH_HandlerContext *hc) 36 { 37 const char *report_id_str = hc->infix; 38 unsigned long long report_id; 39 const char *description; 40 const char *program_section; 41 const char *mime_type; 42 const char *data_source; 43 const char *target_address; 44 struct GNUNET_TIME_Relative frequency; 45 struct GNUNET_TIME_Relative frequency_shift 46 = GNUNET_TIME_UNIT_ZERO; 47 enum GNUNET_DB_QueryStatus qs; 48 struct GNUNET_JSON_Specification spec[] = { 49 GNUNET_JSON_spec_string ("description", 50 &description), 51 GNUNET_JSON_spec_string ("program_section", 52 &program_section), 53 GNUNET_JSON_spec_string ("mime_type", 54 &mime_type), 55 GNUNET_JSON_spec_string ("data_source", 56 &data_source), 57 GNUNET_JSON_spec_string ("target_address", 58 &target_address), 59 GNUNET_JSON_spec_relative_time ("report_frequency", 60 &frequency), 61 GNUNET_JSON_spec_mark_optional ( 62 GNUNET_JSON_spec_relative_time ("report_frequency_shift", 63 &frequency_shift), 64 NULL), 65 GNUNET_JSON_spec_end () 66 }; 67 68 (void) rh; 69 { 70 char dummy; 71 72 if (1 != sscanf (report_id_str, 73 "%llu%c", 74 &report_id, 75 &dummy)) 76 { 77 GNUNET_break_op (0); 78 return TALER_MHD_reply_with_error (connection, 79 MHD_HTTP_BAD_REQUEST, 80 TALER_EC_GENERIC_PARAMETER_MALFORMED, 81 "report_id"); 82 } 83 } 84 85 { 86 enum GNUNET_GenericReturnValue res; 87 88 res = TALER_MHD_parse_json_data (connection, 89 hc->request_body, 90 spec); 91 if (GNUNET_OK != res) 92 { 93 GNUNET_break_op (0); 94 return (GNUNET_NO == res) 95 ? MHD_YES 96 : MHD_NO; 97 } 98 } 99 { 100 char *section; 101 102 GNUNET_asprintf (§ion, 103 "report-generator-%s", 104 program_section); 105 if (GNUNET_YES != 106 GNUNET_CONFIGURATION_have_value (TMH_cfg, 107 section, 108 "BINARY")) 109 { 110 GNUNET_free (section); 111 GNUNET_break (0); 112 return TALER_MHD_reply_with_error ( 113 connection, 114 MHD_HTTP_NOT_IMPLEMENTED, 115 TALER_EC_MERCHANT_GENERIC_REPORT_GENERATOR_UNCONFIGURED, 116 program_section); 117 } 118 GNUNET_free (section); 119 } 120 if ('/' != data_source[0]) 121 { 122 GNUNET_break_op (0); 123 return TALER_MHD_reply_with_error (connection, 124 MHD_HTTP_BAD_REQUEST, 125 TALER_EC_GENERIC_PARAMETER_MALFORMED, 126 "data_source"); 127 128 } 129 130 /* The report generator passes both values to the generator binary on 131 the command line, and the mime type into an "Accept:" header of its 132 own request. A target address that begins with '-' is taken for an 133 option by the delivery tools behind the generator, and a control 134 character in either value would distort the header. */ 135 if (! TALER_MERCHANT_report_target_valid (target_address)) 136 { 137 GNUNET_break_op (0); 138 return TALER_MHD_reply_with_error (connection, 139 MHD_HTTP_BAD_REQUEST, 140 TALER_EC_GENERIC_PARAMETER_MALFORMED, 141 "target_address"); 142 } 143 if (! TALER_MERCHANT_mime_type_valid (mime_type)) 144 { 145 GNUNET_break_op (0); 146 return TALER_MHD_reply_with_error (connection, 147 MHD_HTTP_BAD_REQUEST, 148 TALER_EC_GENERIC_PARAMETER_MALFORMED, 149 "mime_type"); 150 } 151 qs = TALER_MERCHANTDB_update_report (TMH_db, 152 hc->instance->settings.id, 153 report_id, 154 program_section, 155 description, 156 mime_type, 157 data_source, 158 target_address, 159 frequency, 160 frequency_shift); 161 if (qs < 0) 162 { 163 GNUNET_break (0); 164 return TALER_MHD_reply_with_error (connection, 165 MHD_HTTP_INTERNAL_SERVER_ERROR, 166 TALER_EC_GENERIC_DB_STORE_FAILED, 167 "update_report"); 168 } 169 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) 170 { 171 return TALER_MHD_reply_with_error (connection, 172 MHD_HTTP_NOT_FOUND, 173 TALER_EC_MERCHANT_GENERIC_REPORT_UNKNOWN, 174 report_id_str); 175 } 176 177 /* FIXME-Optimization: Trigger MERCHANT_REPORT_UPDATE event inside of UPDATE transaction */ 178 { 179 struct GNUNET_DB_EventHeaderP ev = { 180 .size = htons (sizeof (ev)), 181 .type = htons (TALER_DBEVENT_MERCHANT_REPORT_UPDATE) 182 }; 183 184 TALER_MERCHANTDB_event_notify (TMH_db, 185 &ev, 186 NULL, 187 0); 188 } 189 190 return TALER_MHD_reply_static (connection, 191 MHD_HTTP_NO_CONTENT, 192 NULL, 193 NULL, 194 0); 195 }