commit ebe98bd39046e88bb6b2605670cc38e425ccfe4e
parent 3a86481b5fa7935cf01e48ae4d638e5bac630527
Author: Christian Grothoff <grothoff@gnunet.org>
Date: Mon, 12 Jan 2026 08:15:28 +0900
fix misc. minor issues, add FIXMEs:
Diffstat:
4 files changed, 86 insertions(+), 20 deletions(-)
diff --git a/src/backend/taler-merchant-httpd_get-templates-ID.c b/src/backend/taler-merchant-httpd_get-templates-ID.c
@@ -436,9 +436,10 @@ handle_get_templates_inventory (
template_contract = json_deep_copy (tp->template_contract);
GNUNET_assert (NULL != template_contract);
- json_object_set_new (template_contract,
- "inventory_payload",
- inventory_payload);
+ GNUNET_assert (0 ==
+ json_object_set_new (template_contract,
+ "inventory_payload",
+ inventory_payload));
{
MHD_RESULT ret;
diff --git a/src/backend/taler-merchant-httpd_helper.c b/src/backend/taler-merchant-httpd_helper.c
@@ -475,10 +475,14 @@ TMH_validate_unit_price_array (const struct TALER_Amount *prices,
{
for (size_t j = i + 1; j < prices_len; j++)
{
- if (GNUNET_OK ==
+ if (GNUNET_YES ==
TALER_amount_cmp_currency (&prices[i],
&prices[j]))
+ {
+ /* duplicate currency, not allowed! */
+ GNUNET_break_op (0);
return GNUNET_SYSERR;
+ }
}
}
return GNUNET_OK;
diff --git a/src/backend/taler-merchant-httpd_post-using-templates.c b/src/backend/taler-merchant-httpd_post-using-templates.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2022-2023 Taler Systems SA
+ (C) 2022-2026 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
@@ -30,6 +30,12 @@
#include "taler-merchant-httpd_exchanges.h"
#include <taler/taler_json_lib.h>
+// FIXME: introduce PHASES (like we do in other handlers)
+// and break up the gigantic (and sometimes redundant)
+// handlers into clear parts, like parsing the request,
+// fetching template, checking inventory/computing price,
+// returning errors, etc.
+
/**
* Our context.
@@ -246,6 +252,7 @@ struct InventoryTemplateContext
/**
* Amount provided by the client.
+ * FIXME: I don't see it in the spec that the client MUST provide this amount.
*/
struct TALER_Amount amount;
@@ -256,6 +263,10 @@ struct InventoryTemplateContext
/**
* Total amount for the requested currency (includes tip when present).
+ *
+ * FIXME: this makes no sense, we MAY still have multiple choices
+ * (and thus different totals!) *if* the user didn't specify a tip
+ * and there are products in multiple currencies!
*/
struct TALER_Amount total;
@@ -316,6 +327,13 @@ cleanup_inventory_template_context (void *cls)
/**
* Compute totals for all currencies shared across selected products.
*
+ * FIXME: this is wild. If the client _already_ provided an "amount"
+ * this is pointless: we know the currency the payment will be made in.
+ * (but should still check the total, alas below you just 'skip'
+ * if the currency matches the client-given amount);
+ * However, if the client did NOT give us an amount, we need to compute
+ * per-currency totals.
+ *
* @param[in,out] ctx inventory template context
* @return #GNUNET_OK on success
*/
@@ -325,7 +343,10 @@ compute_totals_per_currency (struct InventoryTemplateContext *ctx)
struct TALER_Amount line_total;
if (0 == ctx->items_len)
+ {
+ GNUNET_break (0);
return GNUNET_SYSERR;
+ }
for (size_t i = 0; i < ctx->items[0].pd.price_array_length; i++)
{
@@ -337,16 +358,15 @@ compute_totals_per_currency (struct InventoryTemplateContext *ctx)
if (! TMH_test_exchange_configured_for_currency (currency))
continue;
-
GNUNET_array_append (ctx->currencies,
ctx->currencies_len,
(struct InventoryTemplateCurrency) {
.currency = GNUNET_strdup (currency)
});
- if (GNUNET_OK !=
- TALER_amount_set_zero (currency,
- &ctx->currencies[ctx->currencies_len - 1].total))
- return GNUNET_SYSERR;
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (currency,
+ &ctx->currencies[ctx->currencies_len
+ - 1].total));
}
if (0 == ctx->currencies_len)
@@ -373,6 +393,7 @@ compute_totals_per_currency (struct InventoryTemplateContext *ctx)
}
if (NULL == unit_price)
{
+ // FIXME: some logging would be nice...
GNUNET_free (ctx->currencies[c].currency);
ctx->currencies[c] = ctx->currencies[ctx->currencies_len - 1];
ctx->currencies_len--;
@@ -394,7 +415,7 @@ compute_totals_per_currency (struct InventoryTemplateContext *ctx)
}
return (0 == ctx->currencies_len)
- ? GNUNET_SYSERR
+ ? GNUNET_SYSERR // FIXME: at least some logging would be nice...
: GNUNET_OK;
}
@@ -483,6 +504,12 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
GNUNET_JSON_spec_string ("summary",
&summary),
NULL),
+ // FIXME: spec clearly says "amount" is *optional*!
+ // The (very common!) new inventory-cart case is one
+ // where the client did NOT specify any currency yet
+ // (unless tipping, I guess), and we should still
+ // generate a v1 order with choices for different
+ // currencies.
TALER_JSON_spec_amount_any ("amount",
&itc.amount),
GNUNET_JSON_spec_mark_optional (
@@ -562,6 +589,7 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
if ( (NULL != summary) &&
(NULL != tsummary) )
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
@@ -572,6 +600,7 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
if ( (NULL == summary) &&
(NULL == tsummary) )
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
@@ -583,6 +612,7 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
if (! no_tip && ! request_tip)
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
@@ -593,6 +623,7 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
if (! TMH_test_exchange_configured_for_currency (itc.amount.currency))
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
@@ -607,6 +638,7 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
TALER_amount_cmp_currency (&itc.amount,
&itc.tip))
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
@@ -618,6 +650,7 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
if (0 == json_array_size (inventory_selection))
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
@@ -628,6 +661,7 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
if (choose_one &&
(1 != json_array_size (inventory_selection)))
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
@@ -807,6 +841,9 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
"calculation of currency totals failed");
}
+ // FIXME: itc.amount MAY not have been specified by the client here,
+ // we MAY still be in a multi-currency scenario. You cannot just
+ // use itc.amount
if (GNUNET_OK !=
compute_inventory_total (&itc,
itc.amount.currency,
@@ -825,10 +862,12 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
{
// TODO: HMMMMM... If we have tip, we can't really go for another choice...
// or we will have to indicate it somehow in the wallet, when user changes the choice...
- if (GNUNET_OK !=
+ // FIXME: yes, so if we have a tip, only generate that exact choice!
+ if (GNUNET_YES !=
TALER_amount_cmp_currency (&itc.tip,
&itc.total))
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
cleanup_inventory_template_context (&itc);
return TALER_MHD_reply_with_error (
@@ -842,12 +881,13 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
&itc.total,
&itc.tip))
{
+ GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
cleanup_inventory_template_context (&itc);
return TALER_MHD_reply_with_error (
connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_FAILED_COMPUTE_AMOUNT,
"tip");
}
tip_products = json_array ();
@@ -866,6 +906,7 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
if (0 != TALER_amount_cmp (&itc.amount,
&itc.total))
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
json_decref (tip_products);
cleanup_inventory_template_context (&itc);
@@ -902,7 +943,8 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
json_array_append_new (choices,
GNUNET_JSON_PACK (
TALER_JSON_pack_amount ("amount",
- &itc.total))));
+ &itc.total))
+ ));
for (size_t i = 0; i < itc.currencies_len; i++)
{
@@ -1063,6 +1105,7 @@ handle_using_templates_fixed (struct MHD_Connection *connection,
if ( (! no_amount) &&
(! no_tamount) )
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
@@ -1076,6 +1119,7 @@ handle_using_templates_fixed (struct MHD_Connection *connection,
(0 != strcmp (tcurrency,
amount.currency)) )
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
@@ -1086,6 +1130,7 @@ handle_using_templates_fixed (struct MHD_Connection *connection,
if (no_amount && no_tamount)
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
@@ -1099,9 +1144,11 @@ handle_using_templates_fixed (struct MHD_Connection *connection,
const struct TALER_Amount *total_amount;
total_amount = no_amount ? &tamount : &amount;
- if (GNUNET_OK != TALER_amount_cmp_currency (&tip,
- total_amount))
+ if (GNUNET_YES !=
+ TALER_amount_cmp_currency (&tip,
+ total_amount))
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
json_decref (tip_products);
return TALER_MHD_reply_with_error (
@@ -1115,6 +1162,7 @@ handle_using_templates_fixed (struct MHD_Connection *connection,
if ( (NULL != summary) &&
(NULL != tsummary) )
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
@@ -1126,6 +1174,7 @@ handle_using_templates_fixed (struct MHD_Connection *connection,
if ( (NULL == summary) &&
(NULL == tsummary) )
{
+ GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
@@ -1140,6 +1189,7 @@ handle_using_templates_fixed (struct MHD_Connection *connection,
if (! no_tip)
{
tip_products = json_array ();
+ GNUNET_assert (NULL != tip_products);
GNUNET_assert (0 ==
json_array_append_new (
tip_products,
@@ -1239,6 +1289,8 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh,
{
enum GNUNET_DB_QueryStatus qs;
+ // FIXME: include template type in request, fully parse
+ // request before even going into the DB.
qs = TMH_db->lookup_template (TMH_db->cls,
mi->settings.id,
template_id,
@@ -1274,6 +1326,8 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh,
break;
} /* End of the switch */
}
+ // FIXME: share more logic between these, just skip (or run) individual
+ // phases depending on the template type!
switch (TMH_template_type_from_contract (uc->etp.template_contract))
{
case TALER_MERCHANT_TEMPLATE_TYPE_FIXED_ORDER:
@@ -1301,9 +1355,10 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh,
case TALER_MERCHANT_TEMPLATE_TYPE_INVALID:
break;
}
+ GNUNET_break (0);
return TALER_MHD_reply_with_error (
connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "template_contract");
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "template_contract has unexpected type");
}
diff --git a/src/backend/taler-merchant-httpd_private-post-products.c b/src/backend/taler-merchant-httpd_private-post-products.c
@@ -162,6 +162,7 @@ TMH_private_post_products (const struct TMH_RequestHandler *rh,
if (0 != TALER_amount_cmp (&price,
&pd.price_array[0]))
{
+ GNUNET_break_op (0);
ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
@@ -173,6 +174,7 @@ TMH_private_post_products (const struct TMH_RequestHandler *rh,
TMH_validate_unit_price_array (pd.price_array,
pd.price_array_length))
{
+ GNUNET_break_op (0);
ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
@@ -184,6 +186,7 @@ TMH_private_post_products (const struct TMH_RequestHandler *rh,
{
if (price_missing)
{
+ GNUNET_break_op (0);
ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
@@ -200,6 +203,7 @@ TMH_private_post_products (const struct TMH_RequestHandler *rh,
{
if (unit_precision_level > TMH_MAX_FRACTIONAL_PRECISION_LEVEL)
{
+ GNUNET_break_op (0);
ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
@@ -234,6 +238,7 @@ TMH_private_post_products (const struct TMH_RequestHandler *rh,
pd.fractional_precision_level = unit_precision_level;
{
const char *eparam;
+
if (GNUNET_OK !=
TALER_MERCHANT_vk_process_quantity_inputs (
TALER_MERCHANT_VK_STOCK,
@@ -246,6 +251,7 @@ TMH_private_post_products (const struct TMH_RequestHandler *rh,
&pd.total_stock_frac,
&eparam))
{
+ GNUNET_break_op (0);
ret = TALER_MHD_reply_with_error (
connection,
MHD_HTTP_BAD_REQUEST,