commit f2b5027ba37abbbfe7ff0711aa9aff2c0e08ac6c
parent 9300bca7e76714d4562d691c93894d36809283a3
Author: bohdan-potuzhnyi <bohdan.potuzhnyi@gmail.com>
Date: Wed, 23 Jul 2025 09:30:18 +0200
fixing merge issues
Diffstat:
1 file changed, 71 insertions(+), 468 deletions(-)
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -3221,6 +3221,59 @@ phase_merge_inventory (struct OrderContext *oc)
}
+#ifdef HAVE_DONAU_DONAU_SERVICE_H
+/**
+ * Callback function that is called for each donau instance.
+ * It simply adds the provided donau_url to the json.
+ */
+/* FIXME: very-very bad */
+static void
+add_donau_url (void *cls,
+ const char *donau_url,
+ const char *charity_name,
+ const struct DONAU_CharityPublicKeyP *charity_pub_key,
+ uint64_t charity_id,
+ const struct TALER_Amount *charity_max_per_year,
+ const struct TALER_Amount *charity_receipts_to_date,
+ int64_t current_year,
+ const json_t *donau_keys_json)
+{
+ struct TALER_MERCHANT_ContractOutput *output = cls;
+
+ GNUNET_array_append (output->details.donation_receipt.donau_urls,
+ output->details.donation_receipt.donau_urls_len,
+ GNUNET_strdup (donau_url));
+}
+
+
+static void
+parse_donau_instances (struct OrderContext *oc,
+ struct TALER_MERCHANT_ContractOutput *output)
+{
+ enum GNUNET_DB_QueryStatus qs;
+
+ /* Invoke the database call, accumulating URLs in a JSON array */
+ /* FIXME: select_donau_instanceS */
+ qs = TMH_db->select_donau_instance (TMH_db->cls,
+ &add_donau_url,
+ output);
+
+ /* REVIEW: If no switch */
+ if (qs < 0)
+ {
+ GNUNET_break_op (0);
+ reply_with_error (oc,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR,
+ "donau url parsing db call");
+ return;
+ }
+}
+
+
+#endif
+
+
/* ***************** ORDER_PHASE_PARSE_CHOICES **************** */
/**
@@ -3418,8 +3471,24 @@ phase_parse_choices (struct OrderContext *oc)
GNUNET_assert (0);
break;
case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
- GNUNET_break (0); /* FIXME-#9059: not yet implemented! */
- break;
+ output.details.donation_receipt.amount = choice->amount;
+#ifdef HAVE_DONAU_DONAU_SERVICE_H
+ /* FIXME: Change to fetch and move to new phase */
+ /* filter by currency */
+ parse_donau_instances (oc,
+ &output);
+#endif
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Output details donation receipt donau urls %p\n",
+ output.details.donation_receipt.donau_urls);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Output details donation receipt donau urls len %u\n",
+ output.details.donation_receipt.donau_urls_len);
+
+ GNUNET_array_append (choice->outputs,
+ choice->outputs_len,
+ output);
+ continue;
case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
/* Ignore inputs tokens with 'count' field set to 0 */
if (0 == output.details.token.count)
@@ -3457,7 +3526,6 @@ phase_parse_choices (struct OrderContext *oc)
/* ***************** ORDER_PHASE_PARSE_ORDER **************** */
-
/**
* Parse the order field of the request. Upon success, continue
* processing with parse_choices().
@@ -3979,471 +4047,6 @@ phase_parse_order (struct OrderContext *oc)
}
-#ifdef HAVE_DONAU_DONAU_SERVICE_H
-/**
- * Callback function that is called for each donau instance.
- * It simply adds the provided donau_url to the json.
- */
-/* FIXME: very-very bad */
-static void
-add_donau_url (void *cls,
- const char *donau_url,
- const char *charity_name,
- const struct DONAU_CharityPublicKeyP *charity_pub_key,
- uint64_t charity_id,
- const struct TALER_Amount *charity_max_per_year,
- const struct TALER_Amount *charity_receipts_to_date,
- int64_t current_year,
- const json_t *donau_keys_json)
-{
- struct TALER_MERCHANT_ContractOutput *output = cls;
-
- GNUNET_array_append (output->details.donation_receipt.donau_urls,
- output->details.donation_receipt.donau_urls_len,
- GNUNET_strdup (donau_url));
-}
-
-
-static void
-parse_donau_instances (struct OrderContext *oc,
- struct TALER_MERCHANT_ContractOutput *output)
-{
- enum GNUNET_DB_QueryStatus qs;
-
- /* Invoke the database call, accumulating URLs in a JSON array */
- /* FIXME: select_donau_instanceS */
- qs = TMH_db->select_donau_instance (TMH_db->cls,
- &add_donau_url,
- output);
-
- /* REVIEW: If no switch */
- if (qs < 0)
- {
- GNUNET_break_op (0);
- reply_with_error (oc,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR,
- "donau url parsing db call");
- return;
- }
-}
-
-
-#endif
-
-
-/**
- * Parse contract choices. Upon success, continue
- * processing with merge_inventory().
- *
- * @param[in,out] oc order context
- */
-static void
-parse_choices (struct OrderContext *oc)
-{
- const json_t *jchoices;
-
- switch (oc->parse_order.version)
- {
- case TALER_MERCHANT_CONTRACT_VERSION_0:
- oc->phase++;
- return;
- case TALER_MERCHANT_CONTRACT_VERSION_1:
- /* handle below */
- break;
- default:
- GNUNET_assert (0);
- }
-
- jchoices = oc->parse_order.details.v1.choices;
-
- if (! json_is_array (jchoices))
- GNUNET_assert (0);
-
- GNUNET_array_grow (oc->parse_choices.choices,
- oc->parse_choices.choices_len,
- json_array_size (jchoices));
- for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
- {
- struct TALER_MERCHANT_ContractChoice *choice
- = &oc->parse_choices.choices[i];
- const char *error_name;
- unsigned int error_line;
- const json_t *jinputs;
- const json_t *joutputs;
- bool no_fee;
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_amount_any ("amount",
- &choice->amount),
- GNUNET_JSON_spec_mark_optional (
- TALER_JSON_spec_amount_any ("max_fee",
- &choice->max_fee),
- &no_fee),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_array_const ("inputs",
- &jinputs),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_array_const ("outputs",
- &joutputs),
- NULL),
- GNUNET_JSON_spec_end ()
- };
- enum GNUNET_GenericReturnValue ret;
-
- ret = GNUNET_JSON_parse (json_array_get (jchoices,
- i),
- spec,
- &error_name,
- &error_line);
- if (GNUNET_OK != ret)
- {
- GNUNET_break_op (0);
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Choice parsing failed: %s:%u\n",
- error_name,
- error_line);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "choice");
- return;
- }
- if ( (! no_fee) &&
- (GNUNET_OK !=
- TALER_amount_cmp_currency (&choice->amount,
- &choice->max_fee)) )
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_CURRENCY_MISMATCH,
- "different currencies used for 'max_fee' and 'amount' currency");
- return;
- }
-
- if (! TMH_test_exchange_configured_for_currency (
- choice->amount.currency))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- reply_with_error (oc,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGE_FOR_CURRENCY,
- choice->amount.currency);
- return;
- }
-
- if (NULL != jinputs)
- {
- const json_t *jinput;
- size_t idx;
- json_array_foreach ((json_t *) jinputs, idx, jinput)
- {
- struct TALER_MERCHANT_ContractInput input = {
- .details.token.count = 1
- };
-
- if (GNUNET_OK !=
- TALER_MERCHANT_parse_choice_input ((json_t *) jinput,
- &input,
- idx,
- true))
- {
- GNUNET_break_op (0);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "input");
- return;
- }
-
- switch (input.type)
- {
- case TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID:
- GNUNET_assert (0);
- break;
- case TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN:
- /* Ignore inputs tokens with 'count' field set to 0 */
- if (0 == input.details.token.count)
- continue;
-
- if (GNUNET_OK !=
- add_input_token_family (oc,
- input.details.token.token_family_slug))
-
- {
- GNUNET_break_op (0);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_SLUG_UNKNOWN,
- input.details.token.token_family_slug);
- return;
- }
-
- GNUNET_array_append (choice->inputs,
- choice->inputs_len,
- input);
- continue;
- }
- GNUNET_assert (0);
- }
- }
-
- if (NULL != joutputs)
- {
- const json_t *joutput;
- size_t idx;
- json_array_foreach ((json_t *) joutputs, idx, joutput)
- {
- struct TALER_MERCHANT_ContractOutput output = {
- .details.token.count = 1
- };
-
- if (GNUNET_OK !=
- TALER_MERCHANT_parse_choice_output ((json_t *) joutput,
- &output,
- idx,
- true))
- {
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "output");
- return;
- }
-
- switch (output.type)
- {
- case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
- GNUNET_assert (0);
- break;
- case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
- /* FIXME-#9059: not yet implemented! */
-
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Output details donation receipt amount currency %s\n",
- output.details.donation_receipt.amount.currency);
-
- /* If amount wasn't set, we need to get it from the overall amount */
- if (GNUNET_OK !=
- TALER_amount_is_valid (&output.details.donation_receipt.amount))
- {
- output.details.donation_receipt.amount = choice->amount;
- }
-
- /* If the system was complied with donau support, we can parse the donau instances */
-#ifdef HAVE_DONAU_DONAU_SERVICE_H
- /* FIXME: Change to fetch and move to new phase */
- /* filter by currency */
- parse_donau_instances (oc, &output);
-#endif
-
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Output details donation receipt donau urls %p\n",
- output.details.donation_receipt.donau_urls);
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Output details donation receipt donau urls len %u\n",
- output.details.donation_receipt.donau_urls_len);
-
- GNUNET_array_append (choice->outputs,
- choice->outputs_len,
- output);
- continue;
- case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
- /* Ignore inputs tokens with 'count' field set to 0 */
- if (0 == output.details.token.count)
- continue;
-
- if (0 == output.details.token.valid_at.abs_time.abs_value_us)
- output.details.token.valid_at
- = GNUNET_TIME_timestamp_get ();
- if (GNUNET_OK !=
- add_output_token_family (oc,
- output.details.token.token_family_slug,
- output.details.token.valid_at,
- &output.details.token.key_index))
-
- {
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_SLUG_UNKNOWN,
- output.details.token.token_family_slug);
- return;
- }
-
- GNUNET_array_append (choice->outputs,
- choice->outputs_len,
- output);
- continue;
- }
- GNUNET_assert (0);
- }
- }
- }
- oc->phase++;
-}
-
-
-/**
- * Process the @a payment_target and add the details of how the
- * order could be paid to @a order. On success, continue
- * processing with set_exchanges().
- *
- * @param[in,out] oc order context
- */
-static void
-add_payment_details (struct OrderContext *oc)
-{
- struct TMH_WireMethod *wm;
-
- wm = oc->hc->instance->wm_head;
- /* Locate wire method that has a matching payment target */
- while ( (NULL != wm) &&
- ( (! wm->active) ||
- ( (NULL != oc->parse_request.payment_target) &&
- (0 != strcasecmp (oc->parse_request.payment_target,
- wm->wire_method) ) ) ) )
- wm = wm->next;
- if (NULL == wm)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "No wire method available for instance '%s'\n",
- oc->hc->instance->settings.id);
- reply_with_error (oc,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_INSTANCE_CONFIGURATION_LACKS_WIRE,
- oc->parse_request.payment_target);
- return;
- }
- oc->add_payment_details.wm = wm;
- oc->phase++;
-}
-
-
-/**
- * Merge the inventory products into products, querying the
- * database about the details of those products. Upon success,
- * continue processing by calling add_payment_details().
- *
- * @param[in,out] oc order context to process
- */
-static void
-merge_inventory (struct OrderContext *oc)
-{
- /**
- * parse_request.inventory_products => instructions to add products to contract terms
- * parse_order.products => contains products that are not from the backend-managed inventory.
- */
- if (NULL != oc->parse_order.products)
- oc->merge_inventory.products
- = json_deep_copy (oc->parse_order.products);
- else
- oc->merge_inventory.products
- = json_array ();
- /* Populate products from inventory product array and database */
- {
- GNUNET_assert (NULL != oc->merge_inventory.products);
- for (unsigned int i = 0; i<oc->parse_request.inventory_products_length; i++)
- {
- const struct InventoryProduct *ip
- = &oc->parse_request.inventory_products[i];
- struct TALER_MERCHANTDB_ProductDetails pd;
- enum GNUNET_DB_QueryStatus qs;
- size_t num_categories = 0;
- uint64_t *categories = NULL;
-
- qs = TMH_db->lookup_product (TMH_db->cls,
- oc->hc->instance->settings.id,
- ip->product_id,
- &pd,
- &num_categories,
- &categories);
- if (qs <= 0)
- {
- enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
- unsigned int http_status = 0;
-
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- GNUNET_break (0);
- http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- ec = TALER_EC_GENERIC_DB_FETCH_FAILED;
- break;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- GNUNET_break (0);
- http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- ec = TALER_EC_GENERIC_DB_SOFT_FAILURE;
- break;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Product %s from order unknown\n",
- ip->product_id);
- http_status = MHD_HTTP_NOT_FOUND;
- ec = TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN;
- break;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- /* case listed to make compilers happy */
- GNUNET_assert (0);
- }
- reply_with_error (oc,
- http_status,
- ec,
- ip->product_id);
- return;
- }
- GNUNET_free (categories);
- oc->parse_order.minimum_age
- = GNUNET_MAX (oc->parse_order.minimum_age,
- pd.minimum_age);
- {
- json_t *p;
-
- p = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("product_name",
- pd.product_name),
- GNUNET_JSON_pack_string ("description",
- pd.description),
- GNUNET_JSON_pack_object_steal ("description_i18n",
- pd.description_i18n),
- GNUNET_JSON_pack_string ("unit",
- pd.unit),
- TALER_JSON_pack_amount ("price",
- &pd.price),
- GNUNET_JSON_pack_array_steal ("taxes",
- pd.taxes),
- GNUNET_JSON_pack_string ("image",
- pd.image),
- GNUNET_JSON_pack_uint64 (
- "quantity",
- ip->quantity));
- GNUNET_assert (NULL != p);
- GNUNET_assert (0 ==
- json_array_append_new (oc->merge_inventory.products,
- p));
- }
- GNUNET_free (pd.description);
- GNUNET_free (pd.unit);
- GNUNET_free (pd.image);
- json_decref (pd.address);
- }
- }
- /* check if final product list is well-formed */
- if (! TMH_products_array_valid (oc->merge_inventory.products))
- {
- GNUNET_break_op (0);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "order:products");
- return;
- }
- oc->phase++;
-}
-
-
/* ***************** ORDER_PHASE_PARSE_REQUEST **************** */
/**