taler-merchant-httpd_post-private-reports.c (6321B)
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_post-private-reports.c 20 * @brief implementation of POST /private/reports 21 * @author Christian Grothoff 22 */ 23 #include "platform.h" 24 #include "taler-merchant-httpd_post-private-reports.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/insert_report.h" 29 #include "merchant-database/event_notify.h" 30 31 32 enum MHD_Result 33 TMH_private_post_reports (const struct TMH_RequestHandler *rh, 34 struct MHD_Connection *connection, 35 struct TMH_HandlerContext *hc) 36 { 37 const char *description; 38 const char *program_section; 39 const char *mime_type; 40 const char *data_source; 41 const char *target_address; 42 struct GNUNET_TIME_Relative frequency; 43 struct GNUNET_TIME_Relative frequency_shift 44 = GNUNET_TIME_UNIT_ZERO; 45 enum GNUNET_DB_QueryStatus qs; 46 struct GNUNET_JSON_Specification spec[] = { 47 GNUNET_JSON_spec_string ("description", 48 &description), 49 GNUNET_JSON_spec_string ("program_section", 50 &program_section), 51 GNUNET_JSON_spec_string ("mime_type", 52 &mime_type), 53 GNUNET_JSON_spec_string ("data_source", 54 &data_source), 55 GNUNET_JSON_spec_string ("target_address", 56 &target_address), 57 GNUNET_JSON_spec_relative_time ("report_frequency", 58 &frequency), 59 GNUNET_JSON_spec_mark_optional ( 60 GNUNET_JSON_spec_relative_time ("report_frequency_shift", 61 &frequency_shift), 62 NULL), 63 GNUNET_JSON_spec_end () 64 }; 65 uint64_t report_id = 0; 66 67 (void) rh; 68 69 { 70 enum GNUNET_GenericReturnValue res; 71 72 res = TALER_MHD_parse_json_data (connection, 73 hc->request_body, 74 spec); 75 if (GNUNET_OK != res) 76 { 77 GNUNET_break_op (0); 78 return (GNUNET_NO == res) 79 ? MHD_YES 80 : MHD_NO; 81 } 82 } 83 { 84 char *section; 85 86 /* Check program_section exists in config! */ 87 GNUNET_asprintf (§ion, 88 "report-generator-%s", 89 program_section); 90 if (GNUNET_YES != 91 GNUNET_CONFIGURATION_have_value (TMH_cfg, 92 section, 93 "BINARY")) 94 { 95 GNUNET_free (section); 96 GNUNET_break (0); 97 return TALER_MHD_reply_with_error ( 98 connection, 99 MHD_HTTP_NOT_IMPLEMENTED, 100 TALER_EC_MERCHANT_GENERIC_REPORT_GENERATOR_UNCONFIGURED, 101 program_section); 102 } 103 GNUNET_free (section); 104 } 105 if ('/' != data_source[0]) 106 { 107 GNUNET_break_op (0); 108 return TALER_MHD_reply_with_error (connection, 109 MHD_HTTP_BAD_REQUEST, 110 TALER_EC_GENERIC_PARAMETER_MALFORMED, 111 "data_source"); 112 113 } 114 /* The report generator passes both values to the generator binary on 115 the command line, and the mime type into an "Accept:" header of its 116 own request. A target address that begins with '-' is taken for an 117 option by the delivery tools behind the generator, and a control 118 character in either value would distort the header. */ 119 if (! TALER_MERCHANT_report_target_valid (target_address)) 120 { 121 GNUNET_break_op (0); 122 return TALER_MHD_reply_with_error (connection, 123 MHD_HTTP_BAD_REQUEST, 124 TALER_EC_GENERIC_PARAMETER_MALFORMED, 125 "target_address"); 126 } 127 if (! TALER_MERCHANT_mime_type_valid (mime_type)) 128 { 129 GNUNET_break_op (0); 130 return TALER_MHD_reply_with_error (connection, 131 MHD_HTTP_BAD_REQUEST, 132 TALER_EC_GENERIC_PARAMETER_MALFORMED, 133 "mime_type"); 134 } 135 qs = TALER_MERCHANTDB_insert_report (TMH_db, 136 hc->instance->settings.id, 137 program_section, 138 description, 139 mime_type, 140 data_source, 141 target_address, 142 frequency, 143 frequency_shift, 144 &report_id); 145 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) 146 { 147 /* The INSERT either stores the row and returns its serial, or it 148 fails; anything else would leave @e report_id unset. */ 149 GNUNET_break (0); 150 return TALER_MHD_reply_with_error (connection, 151 MHD_HTTP_INTERNAL_SERVER_ERROR, 152 TALER_EC_GENERIC_DB_STORE_FAILED, 153 "insert_report"); 154 } 155 156 /* FIXME-Optimization: do trigger inside of transaction above... */ 157 { 158 struct GNUNET_DB_EventHeaderP ev = { 159 .size = htons (sizeof (ev)), 160 .type = htons (TALER_DBEVENT_MERCHANT_REPORT_UPDATE) 161 }; 162 163 TALER_MERCHANTDB_event_notify (TMH_db, 164 &ev, 165 NULL, 166 0); 167 } 168 169 return TALER_MHD_REPLY_JSON_PACK ( 170 connection, 171 MHD_HTTP_OK, 172 GNUNET_JSON_pack_uint64 ("report_serial_id", 173 report_id)); 174 }