merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit 3ebb5281bc62ca6231f6131e0601471d9ef03b8b
parent c4b27ca9b9a5ef4291257e4a8b8f4bac56720b89
Author: Christian Grothoff <christian@grothoff.org>
Date:   Mon, 10 Jul 2023 10:37:25 +0200

tip -> reward

Diffstat:
Msrc/backend/Makefile.am | 20++++++++++----------
Msrc/backend/taler-merchant-httpd.c | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/backend/taler-merchant-httpd.h | 6+++---
Msrc/backend/taler-merchant-httpd_config.c | 2+-
Asrc/backend/taler-merchant-httpd_get-rewards-ID.c | 235+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/taler-merchant-httpd_get-rewards-ID.h | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/backend/taler-merchant-httpd_get-tips-ID.c | 232-------------------------------------------------------------------------------
Dsrc/backend/taler-merchant-httpd_get-tips-ID.h | 67-------------------------------------------------------------------
Asrc/backend/taler-merchant-httpd_post-rewards-ID-pickup.c | 962+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/taler-merchant-httpd_post-rewards-ID-pickup.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/backend/taler-merchant-httpd_post-tips-ID-pickup.c | 962-------------------------------------------------------------------------------
Dsrc/backend/taler-merchant-httpd_post-tips-ID-pickup.h | 49-------------------------------------------------
Msrc/backend/taler-merchant-httpd_private-get-reserves-ID.c | 56++++++++++++++++++++++++++++----------------------------
Msrc/backend/taler-merchant-httpd_private-get-reserves-ID.h | 2+-
Asrc/backend/taler-merchant-httpd_private-get-rewards-ID.c | 395+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/taler-merchant-httpd_private-get-rewards-ID.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/taler-merchant-httpd_private-get-rewards.c | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/taler-merchant-httpd_private-get-rewards.h | 41+++++++++++++++++++++++++++++++++++++++++
Dsrc/backend/taler-merchant-httpd_private-get-tips-ID.c | 395-------------------------------------------------------------------------------
Dsrc/backend/taler-merchant-httpd_private-get-tips-ID.h | 48------------------------------------------------
Dsrc/backend/taler-merchant-httpd_private-get-tips.c | 157-------------------------------------------------------------------------------
Dsrc/backend/taler-merchant-httpd_private-get-tips.h | 41-----------------------------------------
Asrc/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-reward.c | 197+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c | 196-------------------------------------------------------------------------------
Dsrc/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.h | 57---------------------------------------------------------
Msrc/backend/taler-merchant-httpd_private-post-reserves.c | 4++--
Msrc/backenddb/pg_lookup_reserves.c | 16++++++++--------
Msrc/backenddb/pg_select_open_transfers.c | 2+-
Msrc/backenddb/plugin_merchantdb_postgres.c | 528++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/backenddb/test.conf | 2+-
Msrc/backenddb/test_merchantdb.c | 468++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/include/taler_merchant_service.h | 304++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/include/taler_merchant_testing_lib.h | 132++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/include/taler_merchantdb_plugin.h | 152++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/lib/Makefile.am | 12++++++------
Msrc/lib/merchant_api_get_config.c | 2+-
Msrc/lib/merchant_api_get_reserve.c | 38+++++++++++++++++++-------------------
Asrc/lib/merchant_api_get_rewards.c | 288+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/lib/merchant_api_get_tips.c | 288-------------------------------------------------------------------------------
Asrc/lib/merchant_api_merchant_get_reward.c | 302++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/lib/merchant_api_merchant_get_tip.c | 302------------------------------------------------------------------------------
Asrc/lib/merchant_api_reward_authorize.c | 371+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/merchant_api_reward_pickup.c | 440+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/merchant_api_reward_pickup2.c | 355+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/lib/merchant_api_tip_authorize.c | 371-------------------------------------------------------------------------------
Dsrc/lib/merchant_api_tip_pickup.c | 440-------------------------------------------------------------------------------
Dsrc/lib/merchant_api_tip_pickup2.c | 355-------------------------------------------------------------------------------
Asrc/lib/merchant_api_wallet_get_reward.c | 220+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/lib/merchant_api_wallet_get_tip.c | 220-------------------------------------------------------------------------------
Msrc/testing/Makefile.am | 10+++++-----
Msrc/testing/test_kyc_api.c | 2+-
Msrc/testing/test_merchant_api.c | 272++++++++++++++++++++++++++++++++++++++++---------------------------------------
Dsrc/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_1/1687974704 | 0
Dsrc/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_5/1687974704 | 3---
Dsrc/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_1/1687974704 | 2--
Dsrc/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_10/1687974704 | 0
Msrc/testing/test_merchant_api_twisted.c | 17+----------------
Msrc/testing/testing_api_cmd_get_reserve.c | 80++++++++++++++++++++++++++++++++++++++++---------------------------------------
Asrc/testing/testing_api_cmd_get_rewards.c | 311+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/testing/testing_api_cmd_get_tips.c | 310-------------------------------------------------------------------------------
Asrc/testing/testing_api_cmd_merchant_get_reward.c | 373+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/testing/testing_api_cmd_merchant_get_tip.c | 372-------------------------------------------------------------------------------
Asrc/testing/testing_api_cmd_reward_authorize.c | 485+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/testing/testing_api_cmd_reward_pickup.c | 415+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/testing/testing_api_cmd_tip_authorize.c | 485-------------------------------------------------------------------------------
Dsrc/testing/testing_api_cmd_tip_pickup.c | 415-------------------------------------------------------------------------------
Asrc/testing/testing_api_cmd_wallet_get_reward.c | 259+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/testing/testing_api_cmd_wallet_get_tip.c | 258-------------------------------------------------------------------------------
69 files changed, 7161 insertions(+), 7112 deletions(-)

diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am @@ -27,14 +27,14 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_exchanges.c taler-merchant-httpd_exchanges.h \ taler-merchant-httpd_get-orders-ID.c \ taler-merchant-httpd_get-orders-ID.h \ - taler-merchant-httpd_get-tips-ID.c \ - taler-merchant-httpd_get-tips-ID.h \ + taler-merchant-httpd_get-rewards-ID.c \ + taler-merchant-httpd_get-rewards-ID.h \ taler-merchant-httpd_helper.c \ taler-merchant-httpd_helper.h \ - taler-merchant-httpd_private-get-tips.c \ - taler-merchant-httpd_private-get-tips.h \ - taler-merchant-httpd_private-get-tips-ID.c \ - taler-merchant-httpd_private-get-tips-ID.h \ + taler-merchant-httpd_private-get-rewards.c \ + taler-merchant-httpd_private-get-rewards.h \ + taler-merchant-httpd_private-get-rewards-ID.c \ + taler-merchant-httpd_private-get-rewards-ID.h \ taler-merchant-httpd_mhd.c taler-merchant-httpd_mhd.h \ taler-merchant-httpd_private-delete-account-ID.c \ taler-merchant-httpd_private-delete-account-ID.h \ @@ -106,8 +106,8 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-post-products-ID-lock.h \ taler-merchant-httpd_private-post-reserves.c \ taler-merchant-httpd_private-post-reserves.h \ - taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c \ - taler-merchant-httpd_private-post-reserves-ID-authorize-tip.h \ + taler-merchant-httpd_private-post-reserves-ID-authorize-reward.c \ + taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h \ taler-merchant-httpd_private-post-templates.c \ taler-merchant-httpd_private-post-templates.h \ taler-merchant-httpd_private-post-transfers.c \ @@ -124,8 +124,8 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_post-orders-ID-paid.h \ taler-merchant-httpd_post-orders-ID-refund.c \ taler-merchant-httpd_post-orders-ID-refund.h \ - taler-merchant-httpd_post-tips-ID-pickup.c \ - taler-merchant-httpd_post-tips-ID-pickup.h \ + taler-merchant-httpd_post-rewards-ID-pickup.c \ + taler-merchant-httpd_post-rewards-ID-pickup.h \ taler-merchant-httpd_post-using-templates.c \ taler-merchant-httpd_post-using-templates.h \ taler-merchant-httpd_qr.c \ diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c @@ -31,7 +31,7 @@ #include "taler-merchant-httpd_config.h" #include "taler-merchant-httpd_exchanges.h" #include "taler-merchant-httpd_get-orders-ID.h" -#include "taler-merchant-httpd_get-tips-ID.h" +#include "taler-merchant-httpd_get-rewards-ID.h" #include "taler-merchant-httpd_mhd.h" #include "taler-merchant-httpd_private-delete-account-ID.h" #include "taler-merchant-httpd_private-delete-instances-ID.h" @@ -54,8 +54,8 @@ #include "taler-merchant-httpd_private-get-orders-ID.h" #include "taler-merchant-httpd_private-get-reserves.h" #include "taler-merchant-httpd_private-get-reserves-ID.h" -#include "taler-merchant-httpd_private-get-tips-ID.h" -#include "taler-merchant-httpd_private-get-tips.h" +#include "taler-merchant-httpd_private-get-rewards-ID.h" +#include "taler-merchant-httpd_private-get-rewards.h" #include "taler-merchant-httpd_private-get-transfers.h" #include "taler-merchant-httpd_private-patch-webhooks-ID.h" #include "taler-merchant-httpd_private-patch-templates-ID.h" @@ -70,7 +70,7 @@ #include "taler-merchant-httpd_private-post-products.h" #include "taler-merchant-httpd_private-post-products-ID-lock.h" #include "taler-merchant-httpd_private-post-reserves.h" -#include "taler-merchant-httpd_private-post-reserves-ID-authorize-tip.h" +#include "taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h" #include "taler-merchant-httpd_private-post-templates.h" #include "taler-merchant-httpd_private-post-transfers.h" #include "taler-merchant-httpd_private-post-webhooks.h" @@ -80,7 +80,7 @@ #include "taler-merchant-httpd_post-orders-ID-pay.h" #include "taler-merchant-httpd_post-using-templates.h" #include "taler-merchant-httpd_post-orders-ID-refund.h" -#include "taler-merchant-httpd_post-tips-ID-pickup.h" +#include "taler-merchant-httpd_post-rewards-ID-pickup.h" #include "taler-merchant-httpd_reserves.h" #include "taler-merchant-httpd_spa.h" #include "taler-merchant-httpd_statics.h" @@ -303,13 +303,13 @@ static void do_shutdown (void *cls) { (void) cls; - TMH_force_tip_resume (); + TMH_force_reward_resume (); TMH_force_ac_resume (); TMH_force_pc_resume (); TMH_force_kyc_resume (); TMH_force_rc_resume (); TMH_force_gorc_resume (); - TMH_force_tip_pickup_resume (); + TMH_force_reward_pickup_resume (); TMH_force_wallet_get_order_resume (); TMH_force_wallet_refund_order_resume (); { @@ -927,40 +927,75 @@ url_handler (void *cls, .method = MHD_HTTP_METHOD_DELETE, .handler = &TMH_private_delete_reserves_ID }, - /* POST /reserves/$ID/authorize-tip: */ + /* POST /reserves/$ID/authorize-reward: */ + { + .url_prefix = "/reserves/", + .url_suffix = "authorize-reward", + .have_id_segment = true, + .method = MHD_HTTP_METHOD_POST, + .handler = &TMH_private_post_reserves_ID_authorize_reward, + /* the body should be pretty small, allow 1 MB of upload + to set a conservative bound for sane wallets */ + .max_upload = 1024 * 1024 + }, + // FIXME: legacy API { .url_prefix = "/reserves/", .url_suffix = "authorize-tip", .have_id_segment = true, .method = MHD_HTTP_METHOD_POST, - .handler = &TMH_private_post_reserves_ID_authorize_tip, + .handler = &TMH_private_post_reserves_ID_authorize_reward, /* the body should be pretty small, allow 1 MB of upload to set a conservative bound for sane wallets */ .max_upload = 1024 * 1024 }, - /* POST /tips: */ + /* POST /rewards: */ + { + .url_prefix = "/rewards", + .method = MHD_HTTP_METHOD_POST, + .handler = &TMH_private_post_rewards, + /* the body should be pretty small, allow 1 MB of upload + to set a conservative bound for sane wallets */ + .max_upload = 1024 * 1024 + }, + // FIXME: legacy API { .url_prefix = "/tips", .method = MHD_HTTP_METHOD_POST, - .handler = &TMH_private_post_tips, + .handler = &TMH_private_post_rewards, /* the body should be pretty small, allow 1 MB of upload to set a conservative bound for sane wallets */ .max_upload = 1024 * 1024 }, - /* GET /tips: */ + /* GET /rewards: */ + { + .url_prefix = "/rewards", + .allow_deleted_instance = true, + .method = MHD_HTTP_METHOD_GET, + .handler = &TMH_private_get_rewards + }, + // FIXME: legacy API { .url_prefix = "/tips", .allow_deleted_instance = true, .method = MHD_HTTP_METHOD_GET, - .handler = &TMH_private_get_tips + .handler = &TMH_private_get_rewards }, - /* GET /tips/$ID: */ + /* GET /rewards/$ID: */ + { + .url_prefix = "/rewards/", + .method = MHD_HTTP_METHOD_GET, + .allow_deleted_instance = true, + .have_id_segment = true, + .handler = &TMH_private_get_rewards_ID + }, + // FIXME: legacy API { .url_prefix = "/tips/", .method = MHD_HTTP_METHOD_GET, .allow_deleted_instance = true, .have_id_segment = true, - .handler = &TMH_private_get_tips_ID + .handler = &TMH_private_get_rewards_ID }, /* GET /reserves: */ { @@ -1220,22 +1255,42 @@ url_handler (void *cls, .have_id_segment = true, .handler = &TMH_get_orders_ID }, - /* GET /tips/$ID: */ + /* GET /rewards/$ID: */ + { + .url_prefix = "/rewards/", + .method = MHD_HTTP_METHOD_GET, + .allow_deleted_instance = true, + .have_id_segment = true, + .handler = &TMH_get_rewards_ID + }, + // FIXME: legacy API { .url_prefix = "/tips/", .method = MHD_HTTP_METHOD_GET, .allow_deleted_instance = true, .have_id_segment = true, - .handler = &TMH_get_tips_ID + .handler = &TMH_get_rewards_ID + }, + /* POST /rewards/$ID/pickup: */ + { + .url_prefix = "/rewards/", + .method = MHD_HTTP_METHOD_POST, + .have_id_segment = true, + .allow_deleted_instance = true, + .url_suffix = "pickup", + .handler = &TMH_post_rewards_ID_pickup, + /* wallet may give us many coins to sign, allow 1 MB of upload + to set a conservative bound for sane wallets */ + .max_upload = 1024 * 1024 }, - /* POST /tips/$ID/pickup: */ + // FIXME: legacy API { .url_prefix = "/tips/", .method = MHD_HTTP_METHOD_POST, .have_id_segment = true, .allow_deleted_instance = true, .url_suffix = "pickup", - .handler = &TMH_post_tips_ID_pickup, + .handler = &TMH_post_rewards_ID_pickup, /* wallet may give us many coins to sign, allow 1 MB of upload to set a conservative bound for sane wallets */ .max_upload = 1024 * 1024 diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h @@ -282,7 +282,7 @@ struct TMH_OrderRefundEventP /** * Event generated when a client picks up a tip. */ -struct TMH_TipPickupEventP +struct TMH_RewardPickupEventP { /** * Type is #TALER_DBEVENT_MERCHANT_TIP_PICKUP. @@ -295,9 +295,9 @@ struct TMH_TipPickupEventP uint32_t reserved GNUNET_PACKED; /** - * Tip ID. + * Reward ID. */ - struct TALER_TipIdentifierP tip_id; + struct TALER_RewardIdentifierP reward_id; /** * Hash of the instance ID. diff --git a/src/backend/taler-merchant-httpd_config.c b/src/backend/taler-merchant-httpd_config.c @@ -42,7 +42,7 @@ * #MERCHANT_PROTOCOL_CURRENT and #MERCHANT_PROTOCOL_AGE in * merchant_api_config.c! */ -#define MERCHANT_PROTOCOL_VERSION "4:0:0" +#define MERCHANT_PROTOCOL_VERSION "5:0:1" MHD_RESULT diff --git a/src/backend/taler-merchant-httpd_get-rewards-ID.c b/src/backend/taler-merchant-httpd_get-rewards-ID.c @@ -0,0 +1,235 @@ +/* + This file is part of TALER + (C) 2014-2021 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 published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_get-rewards-ID.c + * @brief implementation of GET /rewards/$ID + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include <jansson.h> +#include <taler/taler_signatures.h> +#include <taler/taler_json_lib.h> +#include <taler/taler_templating_lib.h> +#include "taler-merchant-httpd_get-rewards-ID.h" +#include "taler-merchant-httpd_helper.h" +#include "taler-merchant-httpd_mhd.h" +#include "taler-merchant-httpd_qr.h" + + +char * +TMH_make_taler_reward_uri (struct MHD_Connection *con, + const struct TALER_RewardIdentifierP *reward_id, + const char *instance_id) +{ + struct GNUNET_Buffer buf = { 0 }; + + GNUNET_assert (NULL != instance_id); + GNUNET_assert (NULL != reward_id); + if (GNUNET_OK != + TMH_taler_uri_by_connection (con, + "reward", + instance_id, + &buf)) + { + GNUNET_break (0); + return NULL; + } + /* Ensure previous part is slash-terminated */ + GNUNET_buffer_write_path (&buf, + ""); + GNUNET_buffer_write_data_encoded (&buf, + reward_id, + sizeof (*reward_id)); + return GNUNET_buffer_reap_str (&buf); +} + + +char * +TMH_make_reward_status_url (struct MHD_Connection *con, + const struct TALER_RewardIdentifierP *reward_id, + const char *instance_id) +{ + struct GNUNET_Buffer buf; + + GNUNET_assert (NULL != instance_id); + GNUNET_assert (NULL != reward_id); + if (GNUNET_OK != + TMH_base_url_by_connection (con, + instance_id, + &buf)) + { + GNUNET_break (0); + return NULL; + } + GNUNET_buffer_write_path (&buf, + "rewards/"); + GNUNET_buffer_write_data_encoded (&buf, + reward_id, + sizeof (*reward_id)); + return GNUNET_buffer_reap_str (&buf); +} + + +MHD_RESULT +TMH_get_rewards_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TALER_RewardIdentifierP reward_id; + enum GNUNET_DB_QueryStatus qs; + struct TALER_Amount total_authorized; + struct TALER_Amount total_picked_up; + struct GNUNET_TIME_Timestamp expiration; + char *exchange_url; + char *next_url; + struct TALER_ReservePrivateKeyP reserve_priv; + + (void) rh; + if (GNUNET_OK != + GNUNET_CRYPTO_hash_from_string (hc->infix, + &reward_id.hash)) + { + /* reward_id has wrong encoding */ + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + hc->infix); + } + + TMH_db->preflight (TMH_db->cls); + qs = TMH_db->lookup_reward (TMH_db->cls, + hc->instance->settings.id, + &reward_id, + &total_authorized, + &total_picked_up, + &expiration, + &exchange_url, + &next_url, + &reserve_priv); + if (0 > qs) + { + /* single, read-only SQL statements should never cause + serialization problems */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + NULL); + } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Unknown reward id given: `%s'\n", + hc->infix); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_REWARD_ID_UNKNOWN, + hc->infix); + } + + /* Build response */ + { + struct TALER_Amount remaining; + MHD_RESULT ret; + + GNUNET_break (0 <= + TALER_amount_subtract (&remaining, + &total_authorized, + &total_picked_up)); + if (TMH_MHD_test_html_desired (connection)) + { + char *qr; + char *uri; + char *reward_status_url; + + uri = TMH_make_taler_reward_uri (connection, + &reward_id, + hc->instance->settings.id); + reward_status_url = TMH_make_reward_status_url (connection, + &reward_id, + hc->instance->settings.id); + qr = TMH_create_qrcode (uri); + if (NULL == qr) + { + GNUNET_break (0); + GNUNET_free (uri); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_ALLOCATION_FAILURE, + "during QR code generation"); + } + else + { + json_t *context; + + context = GNUNET_JSON_PACK ( + TALER_JSON_pack_amount ("remaining_reward", + &remaining), + GNUNET_JSON_pack_string ("taler_reward_uri", + uri), + GNUNET_JSON_pack_string ("next_url", + next_url), + GNUNET_JSON_pack_string ("taler_reward_qrcode_svg", + qr)); + ret = TALER_TEMPLATING_reply (connection, + ( (0 == remaining.value) && + (0 == remaining.fraction) ) + ? MHD_HTTP_GONE + : MHD_HTTP_OK, + ( (0 == remaining.value) && + (0 == remaining.fraction) ) + ? "depleted_reward" + : "offer_reward", + hc->instance->settings.id, + uri, + context); + json_decref (context); + } + GNUNET_free (reward_status_url); + GNUNET_free (uri); + GNUNET_free (qr); + } + else + { + ret = TALER_MHD_REPLY_JSON_PACK ( + connection, + TALER_amount_is_zero (&remaining) + ? MHD_HTTP_GONE + : MHD_HTTP_OK, + GNUNET_JSON_pack_string ("exchange_url", + exchange_url), + GNUNET_JSON_pack_string ("next_url", + next_url), + TALER_JSON_pack_amount ("reward_amount", + &remaining), + // FIXME: tip_amount is for legacy compatibility, to be removed "later" + TALER_JSON_pack_amount ("tip_amount", + &remaining), + GNUNET_JSON_pack_timestamp ("expiration", + expiration)); + } + GNUNET_free (exchange_url); + GNUNET_free (next_url); + return ret; + } +} + + +/* end of taler-merchant-httpd_get-rewards-ID.c */ diff --git a/src/backend/taler-merchant-httpd_get-rewards-ID.h b/src/backend/taler-merchant-httpd_get-rewards-ID.h @@ -0,0 +1,67 @@ +/* + This file is part of TALER + (C) 2020 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 published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_get-rewards-ID.h + * @brief implementation of GET /rewards/$ID + * @author Marcello Stanisci + */ +#ifndef TALER_MERCHANT_HTTPD_GET_REWARDS_ID_H +#define TALER_MERCHANT_HTTPD_GET_REWARDS_ID_H +#include <microhttpd.h> +#include "taler-merchant-httpd.h" + +/** + * Create a taler://reward/ URI for the given @a con and @a reward_id + * and @a instance_id. + * + * @param con HTTP connection + * @param reward_id the reward id + * @param instance_id instance, may be "default" + * @return corresponding taler://reward/ URI, or NULL on missing "host" + */ +char * +TMH_make_taler_reward_uri (struct MHD_Connection *con, + const struct TALER_RewardIdentifierP *reward_id, + const char *instance_id); + +/** + * Create a http(s):// URL for the given @a con and @a reward_id + * and @a instance_id. + * + * @param con HTTP connection + * @param reward_id the reward id + * @param instance_id instance, may be "default" + * @return corresponding taler://reward/ URI, or NULL on missing "host" + */ +char * +TMH_make_reward_status_url (struct MHD_Connection *con, + const struct TALER_RewardIdentifierP *reward_id, + const char *instance_id); + +/** + * Handle a GET "/rewards/$ID" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_get_rewards_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +#endif diff --git a/src/backend/taler-merchant-httpd_get-tips-ID.c b/src/backend/taler-merchant-httpd_get-tips-ID.c @@ -1,232 +0,0 @@ -/* - This file is part of TALER - (C) 2014-2021 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 published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-merchant-httpd_get-tips-ID.c - * @brief implementation of GET /tips/$ID - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include <jansson.h> -#include <taler/taler_signatures.h> -#include <taler/taler_json_lib.h> -#include <taler/taler_templating_lib.h> -#include "taler-merchant-httpd_get-tips-ID.h" -#include "taler-merchant-httpd_helper.h" -#include "taler-merchant-httpd_mhd.h" -#include "taler-merchant-httpd_qr.h" - - -char * -TMH_make_taler_tip_uri (struct MHD_Connection *con, - const struct TALER_TipIdentifierP *tip_id, - const char *instance_id) -{ - struct GNUNET_Buffer buf = { 0 }; - - GNUNET_assert (NULL != instance_id); - GNUNET_assert (NULL != tip_id); - if (GNUNET_OK != - TMH_taler_uri_by_connection (con, - "tip", - instance_id, - &buf)) - { - GNUNET_break (0); - return NULL; - } - /* Ensure previous part is slash-terminated */ - GNUNET_buffer_write_path (&buf, - ""); - GNUNET_buffer_write_data_encoded (&buf, - tip_id, - sizeof (*tip_id)); - return GNUNET_buffer_reap_str (&buf); -} - - -char * -TMH_make_tip_status_url (struct MHD_Connection *con, - const struct TALER_TipIdentifierP *tip_id, - const char *instance_id) -{ - struct GNUNET_Buffer buf; - - GNUNET_assert (NULL != instance_id); - GNUNET_assert (NULL != tip_id); - if (GNUNET_OK != - TMH_base_url_by_connection (con, - instance_id, - &buf)) - { - GNUNET_break (0); - return NULL; - } - GNUNET_buffer_write_path (&buf, - "tips/"); - GNUNET_buffer_write_data_encoded (&buf, - tip_id, - sizeof (*tip_id)); - return GNUNET_buffer_reap_str (&buf); -} - - -MHD_RESULT -TMH_get_tips_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - struct TALER_TipIdentifierP tip_id; - enum GNUNET_DB_QueryStatus qs; - struct TALER_Amount total_authorized; - struct TALER_Amount total_picked_up; - struct GNUNET_TIME_Timestamp expiration; - char *exchange_url; - char *next_url; - struct TALER_ReservePrivateKeyP reserve_priv; - - (void) rh; - if (GNUNET_OK != - GNUNET_CRYPTO_hash_from_string (hc->infix, - &tip_id.hash)) - { - /* tip_id has wrong encoding */ - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - hc->infix); - } - - TMH_db->preflight (TMH_db->cls); - qs = TMH_db->lookup_tip (TMH_db->cls, - hc->instance->settings.id, - &tip_id, - &total_authorized, - &total_picked_up, - &expiration, - &exchange_url, - &next_url, - &reserve_priv); - if (0 > qs) - { - /* single, read-only SQL statements should never cause - serialization problems */ - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); - /* Always report on hard error as well to enable diagnostics */ - GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - NULL); - } - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Unknown tip id given: `%s'\n", - hc->infix); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_MERCHANT_GENERIC_TIP_ID_UNKNOWN, - hc->infix); - } - - /* Build response */ - { - struct TALER_Amount remaining; - MHD_RESULT ret; - - GNUNET_break (0 <= - TALER_amount_subtract (&remaining, - &total_authorized, - &total_picked_up)); - if (TMH_MHD_test_html_desired (connection)) - { - char *qr; - char *uri; - char *tip_status_url; - - uri = TMH_make_taler_tip_uri (connection, - &tip_id, - hc->instance->settings.id); - tip_status_url = TMH_make_tip_status_url (connection, - &tip_id, - hc->instance->settings.id); - qr = TMH_create_qrcode (uri); - if (NULL == qr) - { - GNUNET_break (0); - GNUNET_free (uri); - ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_ALLOCATION_FAILURE, - "during QR code generation"); - } - else - { - json_t *context; - - context = GNUNET_JSON_PACK ( - TALER_JSON_pack_amount ("remaining_tip", - &remaining), - GNUNET_JSON_pack_string ("taler_tip_uri", - uri), - GNUNET_JSON_pack_string ("next_url", - next_url), - GNUNET_JSON_pack_string ("taler_tip_qrcode_svg", - qr)); - ret = TALER_TEMPLATING_reply (connection, - ( (0 == remaining.value) && - (0 == remaining.fraction) ) - ? MHD_HTTP_GONE - : MHD_HTTP_OK, - ( (0 == remaining.value) && - (0 == remaining.fraction) ) - ? "depleted_tip" - : "offer_tip", - hc->instance->settings.id, - uri, - context); - json_decref (context); - } - GNUNET_free (tip_status_url); - GNUNET_free (uri); - GNUNET_free (qr); - } - else - { - ret = TALER_MHD_REPLY_JSON_PACK ( - connection, - TALER_amount_is_zero (&remaining) - ? MHD_HTTP_GONE - : MHD_HTTP_OK, - GNUNET_JSON_pack_string ("exchange_url", - exchange_url), - GNUNET_JSON_pack_string ("next_url", - next_url), - TALER_JSON_pack_amount ("tip_amount", - &remaining), - GNUNET_JSON_pack_timestamp ("expiration", - expiration)); - } - GNUNET_free (exchange_url); - GNUNET_free (next_url); - return ret; - } -} - - -/* end of taler-merchant-httpd_get-tips-ID.c */ diff --git a/src/backend/taler-merchant-httpd_get-tips-ID.h b/src/backend/taler-merchant-httpd_get-tips-ID.h @@ -1,67 +0,0 @@ -/* - This file is part of TALER - (C) 2020 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 published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-merchant-httpd_get-tips-ID.h - * @brief implementation of GET /tips/$ID - * @author Marcello Stanisci - */ -#ifndef TALER_MERCHANT_HTTPD_GET_TIPS_ID_H -#define TALER_MERCHANT_HTTPD_GET_TIPS_ID_H -#include <microhttpd.h> -#include "taler-merchant-httpd.h" - -/** - * Create a taler://tip/ URI for the given @a con and @a tip_id - * and @a instance_id. - * - * @param con HTTP connection - * @param tip_id the tip id - * @param instance_id instance, may be "default" - * @return corresponding taler://tip/ URI, or NULL on missing "host" - */ -char * -TMH_make_taler_tip_uri (struct MHD_Connection *con, - const struct TALER_TipIdentifierP *tip_id, - const char *instance_id); - -/** - * Create a http(s):// URL for the given @a con and @a tip_id - * and @a instance_id. - * - * @param con HTTP connection - * @param tip_id the tip id - * @param instance_id instance, may be "default" - * @return corresponding taler://tip/ URI, or NULL on missing "host" - */ -char * -TMH_make_tip_status_url (struct MHD_Connection *con, - const struct TALER_TipIdentifierP *tip_id, - const char *instance_id); - -/** - * Handle a GET "/tips/$ID" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_get_tips_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - -#endif diff --git a/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.c b/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.c @@ -0,0 +1,962 @@ +/* + This file is part of TALER + (C) 2017-2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_post-rewards-ID-pickup.c + * @brief implementation of a POST /rewards/ID/pickup handler + * @author Christian Grothoff + */ +#include "platform.h" +#include <microhttpd.h> +#include <jansson.h> +#include <taler/taler_json_lib.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_signatures.h> +#include "taler-merchant-httpd.h" +#include "taler-merchant-httpd_mhd.h" +#include "taler-merchant-httpd_helper.h" +#include "taler-merchant-httpd_exchanges.h" +#include "taler-merchant-httpd_post-rewards-ID-pickup.h" + + +/** + * How often do we retry on serialization errors? + */ +#define MAX_RETRIES 3 + +/** + * How long do we give the exchange operation to complete withdrawing + * all of the planchets? + */ +#define EXCHANGE_TIMEOUT GNUNET_TIME_relative_multiply ( \ + GNUNET_TIME_UNIT_SECONDS, 45) + + +/** + * Active pickup operations. + */ +struct PickupContext; + + +/** + * Handle for an individual planchet we are processing for a reward. + */ +struct PlanchetOperation +{ + /** + * Active pickup operation this planchet belongs with. + */ + struct PickupContext *pc; + + /** + * Kept in a DLL. + */ + struct PlanchetOperation *prev; + + /** + * Kept in a DLL. + */ + struct PlanchetOperation *next; + + /** + * Find operation (while active), later NULL. + */ + struct TMH_EXCHANGES_KeysOperation *fo; + + /** + * Withdraw handle (NULL while @e fo is active). + */ + struct TALER_EXCHANGE_Withdraw2Handle *w2h; + + /** + * Details about the planchet for withdrawing. + */ + struct TALER_PlanchetDetail pd; + + /** + * Offset of this planchet in the original request. + */ + unsigned int offset; +}; + + +/** + * Active pickup operations. + */ +struct PickupContext +{ + /** + * Kept in a DLL. + */ + struct PickupContext *next; + + /** + * Kept in a DLL. + */ + struct PickupContext *prev; + + /** + * The connection. + */ + struct MHD_Connection *connection; + + /** + * Request context. + */ + struct TMH_HandlerContext *hc; + + /** + * Base URL of the exchange we withdraw from. + */ + char *exchange_url; + + /** + * Timeout task. + */ + struct GNUNET_SCHEDULER_Task *tt; + + /** + * Head of DLL of exchange operations on planchets. + */ + struct PlanchetOperation *po_head; + + /** + * Tail of DLL of exchange operations on planchets. + */ + struct PlanchetOperation *po_tail; + + /** + * HTTP response to return (set on errors). + */ + struct MHD_Response *response; + + /** + * Find operation (while active), later NULL. + */ + struct TMH_EXCHANGES_KeysOperation *fo; + + /** + * Which reserve are we draining? + */ + struct TALER_ReservePrivateKeyP reserve_priv; + + /** + * Which reward is being picked up? + */ + struct TALER_RewardIdentifierP reward_id; + + /** + * What is the ID of the pickup operation? (Basically a + * hash over the key inputs). + */ + struct TALER_PickupIdentifierP pickup_id; + + /** + * Array of our planchets. + */ + struct TALER_PlanchetDetail *planchets; + + /** + * Length of the @e planchets array. + */ + unsigned int planchets_length; + + /** + * HTTP status to use (set on errors). + */ + unsigned int http_status; + + /** + * Total amount requested in the pick up operation. Computed by + * totaling up the amounts of all the @e planchets. + */ + struct TALER_Amount total_requested; + + /** + * True if @e total_requested has been initialized. + */ + bool tr_initialized; + + /** + * Should we generate a DB notification at the end for the pickup? Used to + * wake up long pollers upon reward pickup. Not done transactionally as there + * are potentially several coins individually added to the DB as + * transactions, and doing a notification per coin would be excessive. + * (And missing an event in the very rare case where our process fails + * hard between a DB operation and generating an HTTP reply is not a problem + * in this case.) However, if we in the future do group all DB transactions + * into one larger transaction, the notification should become part of it. + */ + bool do_notify; +}; + + +/** + * Head of DLL. + */ +static struct PickupContext *pc_head; + +/** + * Tail of DLL. + */ +static struct PickupContext *pc_tail; + + +/** + * Stop all ongoing operations associated with @a pc. + */ +static void +stop_operations (struct PickupContext *pc) +{ + struct PlanchetOperation *po; + + if (NULL != pc->tt) + { + GNUNET_SCHEDULER_cancel (pc->tt); + pc->tt = NULL; + } + if (NULL != pc->fo) + { + TMH_EXCHANGES_keys4exchange_cancel (pc->fo); + pc->fo = NULL; + } + while (NULL != (po = pc->po_head)) + { + if (NULL != po->fo) + { + TMH_EXCHANGES_keys4exchange_cancel (po->fo); + po->fo = NULL; + } + if (NULL != po->w2h) + { + TALER_EXCHANGE_withdraw2_cancel (po->w2h); + po->w2h = NULL; + } + GNUNET_CONTAINER_DLL_remove (pc->po_head, + pc->po_tail, + po); + GNUNET_free (po); + } +} + + +/** + * Function called to clean up. + * + * @param cls a `struct PickupContext *` to clean up + */ +static void +pick_context_cleanup (void *cls) +{ + struct PickupContext *pc = cls; + + if (pc->do_notify) + { + struct TMH_RewardPickupEventP reward_eh = { + .header.size = htons (sizeof (reward_eh)), + .header.type = htons (TALER_DBEVENT_MERCHANT_REWARD_PICKUP), + .reward_id = pc->reward_id + }; + + GNUNET_CRYPTO_hash (pc->hc->instance->settings.id, + strlen (pc->hc->instance->settings.id), + &reward_eh.h_instance); + TMH_db->event_notify (TMH_db->cls, + &reward_eh.header, + NULL, + 0); + } + stop_operations (pc); /* should not be any... */ + for (unsigned int i = 0; i<pc->planchets_length; i++) + TALER_planchet_detail_free (&pc->planchets[i]); + GNUNET_array_grow (pc->planchets, + pc->planchets_length, + 0); + GNUNET_free (pc->exchange_url); + GNUNET_free (pc); +} + + +void +TMH_force_reward_pickup_resume () +{ + struct PickupContext *nxt; + + for (struct PickupContext *pc = pc_head; + NULL != pc; + pc = nxt) + { + nxt = pc->next; + stop_operations (pc); + GNUNET_CONTAINER_DLL_remove (pc_head, + pc_tail, + pc); + MHD_resume_connection (pc->connection); + } +} + + +/** + * Callbacks of this type are used to serve the result of submitting a + * withdraw request to a exchange without the (un)blinding factor. + * We persist the result in the database and, if we were the last + * planchet operation, resume HTTP processing. + * + * @param cls closure with a `struct PlanchetOperation *` + * @param w2r response data + */ +static void +withdraw_cb (void *cls, + const struct TALER_EXCHANGE_Withdraw2Response *w2r) +{ + struct PlanchetOperation *po = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &w2r->hr; + struct PickupContext *pc = po->pc; + enum GNUNET_DB_QueryStatus qs; + + GNUNET_CONTAINER_DLL_remove (pc->po_head, + pc->po_tail, + po); + TMH_db->preflight (TMH_db->cls); + if (MHD_HTTP_OK != hr->http_status) + { + GNUNET_free (po); + stop_operations (pc); + pc->http_status = MHD_HTTP_BAD_GATEWAY; + pc->response = + TALER_MHD_MAKE_JSON_PACK ( + TALER_JSON_pack_ec (TALER_EC_MERCHANT_REWARD_PICKUP_EXCHANGE_ERROR), + TMH_pack_exchange_reply (hr)); + GNUNET_CONTAINER_DLL_remove (pc_head, + pc_tail, + pc); + MHD_resume_connection (pc->connection); + TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ + return; + } + qs = TMH_db->insert_pickup_blind_signature (TMH_db->cls, + &pc->pickup_id, + po->offset, + &w2r->details.ok.blind_sig); + GNUNET_free (po); + if (qs < 0) + { + stop_operations (pc); + pc->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; + pc->response = TALER_MHD_make_error ( + TALER_EC_GENERIC_DB_STORE_FAILED, + "blind signature"); + GNUNET_CONTAINER_DLL_remove (pc_head, + pc_tail, + pc); + MHD_resume_connection (pc->connection); + TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ + return; + } + pc->do_notify = true; + if (NULL != pc->po_head) + return; /* More pending */ + stop_operations (pc); /* stops timeout job */ + GNUNET_CONTAINER_DLL_remove (pc_head, + pc_tail, + pc); + MHD_resume_connection (pc->connection); + TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ +} + + +/** + * Function called with the result of a #TMH_EXCHANGES_find_exchange() + * operation as part of a withdraw objective. If the exchange is ready, + * withdraws the planchet from the exchange. + * + * @param cls closure, with our `struct PlanchetOperation *` + * @param keys keys for the exchange + */ +static void +do_withdraw (void *cls, + struct TALER_EXCHANGE_Keys *keys) +{ + struct PlanchetOperation *po = cls; + struct PickupContext *pc = po->pc; + + po->fo = NULL; + TMH_db->preflight (TMH_db->cls); + if (NULL == keys) + { + stop_operations (pc); + GNUNET_CONTAINER_DLL_remove (pc->po_head, + pc->po_tail, + po); + GNUNET_free (po); + pc->http_status = MHD_HTTP_GATEWAY_TIMEOUT; + pc->response = TALER_MHD_MAKE_JSON_PACK ( + TALER_JSON_pack_ec ( + TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT)); + MHD_resume_connection (pc->connection); + TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ + return; + } + po->w2h = TALER_EXCHANGE_withdraw2 (TMH_curl_ctx, + pc->exchange_url, + keys, + &po->pd, + &pc->reserve_priv, + &withdraw_cb, + po); +} + + +/** + * Withdraw @a planchet from @a exchange_url for @a pc operation at planchet + * @a offset. Sets up the respective operation and adds it @a pc's operation + * list. Once the operation is complete, the resulting blind signature is + * committed to the merchant's database. If all planchet operations are + * completed, the HTTP processing is resumed. + * + * @param[in,out] pc a pending pickup operation that includes @a planchet + * @param planchet details about the coin to pick up + * @param offset offset of @a planchet in the list, needed to process the reply + */ +static void +try_withdraw (struct PickupContext *pc, + const struct TALER_PlanchetDetail *planchet, + unsigned int offset) +{ + struct PlanchetOperation *po; + + TMH_db->preflight (TMH_db->cls); + po = GNUNET_new (struct PlanchetOperation); + po->pc = pc; + po->pd = *planchet; + po->offset = offset; + po->fo = TMH_EXCHANGES_keys4exchange (pc->exchange_url, + &do_withdraw, + po); + GNUNET_assert (NULL != po->fo); + GNUNET_CONTAINER_DLL_insert (pc->po_head, + pc->po_tail, + po); +} + + +/** + * Handle timeout for pickup. + * + * @param cls a `struct PickupContext *` + */ +static void +do_timeout (void *cls) +{ + struct PickupContext *pc = cls; + + pc->tt = NULL; + stop_operations (pc); + pc->http_status = MHD_HTTP_GATEWAY_TIMEOUT; + pc->response = TALER_MHD_make_error ( + TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT, + NULL); + GNUNET_CONTAINER_DLL_remove (pc_head, + pc_tail, + pc); + MHD_resume_connection (pc->connection); + TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ +} + + +/** + * Function called with the result of a #TMH_EXCHANGES_find_exchange() + * operation as part of a withdraw objective. Here, we initialize + * the "total_requested" amount by adding up the cost of the planchets + * provided by the client. + * + * @param cls closure, with our `struct PickupContext *` + * @param keys the keys of the exchange + */ +static void +compute_total_requested (void *cls, + struct TALER_EXCHANGE_Keys *keys) +{ + struct PickupContext *pc = cls; + + pc->fo = NULL; + stop_operations (pc); /* stops timeout job */ + if (NULL == keys) + { + pc->http_status = MHD_HTTP_GATEWAY_TIMEOUT; + pc->response = TALER_MHD_MAKE_JSON_PACK ( + TALER_JSON_pack_ec ( + TALER_EC_MERCHANT_GENERIC_EXCHANGE_KEYS_FAILURE)); + MHD_resume_connection (pc->connection); + TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ + return; + } + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (TMH_currency, + &pc->total_requested)); + for (unsigned int i = 0; i<pc->planchets_length; i++) + { + struct TALER_PlanchetDetail *pd = &pc->planchets[i]; + const struct TALER_EXCHANGE_DenomPublicKey *dpk; + + dpk = TALER_EXCHANGE_get_denomination_key_by_hash (keys, + &pd->denom_pub_hash); + if (NULL == dpk) + { + pc->http_status = MHD_HTTP_CONFLICT; + pc->response = + TALER_MHD_MAKE_JSON_PACK ( + TALER_JSON_pack_ec ( + TALER_EC_MERCHANT_REWARD_PICKUP_DENOMINATION_UNKNOWN)); + MHD_resume_connection (pc->connection); + TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ + return; + } + + if ( (GNUNET_YES != + TALER_amount_cmp_currency (&pc->total_requested, + &dpk->value)) || + (0 > + TALER_amount_add (&pc->total_requested, + &pc->total_requested, + &dpk->value)) ) + { + pc->http_status = MHD_HTTP_BAD_REQUEST; + pc->response = + TALER_MHD_make_error (TALER_EC_MERCHANT_REWARD_PICKUP_SUMMATION_FAILED, + "Could not add up values to compute pickup total"); + MHD_resume_connection (pc->connection); + TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ + return; + } + } + pc->tr_initialized = true; + MHD_resume_connection (pc->connection); + TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ +} + + +/** + * The reward lookup operation failed. Generate an error response based on the @a qs. + * + * @param connection connection to generate error for + * @param qs DB status to base error creation on + * @return MHD result code + */ +static MHD_RESULT +reply_lookup_reward_failed (struct MHD_Connection *connection, + enum GNUNET_DB_QueryStatus qs) +{ + unsigned int response_code; + enum TALER_ErrorCode ec; + + TMH_db->rollback (TMH_db->cls); + switch (qs) + { + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + ec = TALER_EC_MERCHANT_GENERIC_REWARD_ID_UNKNOWN; + response_code = MHD_HTTP_NOT_FOUND; + break; + case GNUNET_DB_STATUS_SOFT_ERROR: + ec = TALER_EC_GENERIC_DB_SOFT_FAILURE; + response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + break; + case GNUNET_DB_STATUS_HARD_ERROR: + ec = TALER_EC_GENERIC_DB_COMMIT_FAILED; + response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + break; + default: + GNUNET_break (0); + ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; + response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + break; + } + return TALER_MHD_reply_with_error (connection, + response_code, + ec, + NULL); +} + + +MHD_RESULT +TMH_post_rewards_ID_pickup (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct PickupContext *pc = hc->ctx; + char *next_url; + struct TALER_Amount total_authorized; + struct TALER_Amount total_picked_up; + struct TALER_Amount total_remaining; + struct GNUNET_TIME_Timestamp expiration; + enum GNUNET_DB_QueryStatus qs; + unsigned int num_retries; + + if (NULL == pc) + { + const json_t *planchets; + json_t *planchet; + size_t index; + + pc = GNUNET_new (struct PickupContext); + hc->ctx = pc; + hc->cc = &pick_context_cleanup; + pc->hc = hc; + GNUNET_assert (NULL != hc->infix); + if (GNUNET_OK != + GNUNET_CRYPTO_hash_from_string (hc->infix, + &pc->reward_id.hash)) + { + /* reward_id has wrong encoding */ + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + hc->infix); + } + + { + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_array_const ("planchets", + &planchets), + GNUNET_JSON_spec_end () + }; + { + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (connection, + hc->request_body, + spec); + if (GNUNET_OK != res) + return (GNUNET_NO == res) + ? MHD_YES + : MHD_NO; + } + } + GNUNET_array_grow (pc->planchets, + pc->planchets_length, + json_array_size (planchets)); + json_array_foreach (planchets, index, planchet) { + struct TALER_PlanchetDetail *pd = &pc->planchets[index]; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("denom_pub_hash", + &pd->denom_pub_hash), + TALER_JSON_spec_blinded_planchet ("coin_ev", + &pd->blinded_planchet), + GNUNET_JSON_spec_end () + }; + { + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (connection, + planchet, + spec); + if (GNUNET_OK != res) + { + return (GNUNET_NO == res) + ? MHD_YES + : MHD_NO; + } + } + } + { + struct GNUNET_HashContext *hc; + + hc = GNUNET_CRYPTO_hash_context_start (); + GNUNET_CRYPTO_hash_context_read (hc, + &pc->reward_id, + sizeof (pc->reward_id)); + for (unsigned int i = 0; i<pc->planchets_length; i++) + { + struct TALER_PlanchetDetail *pd = &pc->planchets[i]; + + GNUNET_CRYPTO_hash_context_read (hc, + &pd->denom_pub_hash, + sizeof (pd->denom_pub_hash)); + TALER_blinded_planchet_hash_ (&pd->blinded_planchet, + hc); + } + GNUNET_CRYPTO_hash_context_finish (hc, + &pc->pickup_id.hash); + } + } + + if (NULL != pc->response) + { + MHD_RESULT ret; + + ret = MHD_queue_response (connection, + pc->http_status, + pc->response); + pc->response = NULL; + return ret; + } + + if (! pc->tr_initialized) + { + char *next_url; + + qs = TMH_db->lookup_reward (TMH_db->cls, + hc->instance->settings.id, + &pc->reward_id, + &total_authorized, + &total_picked_up, + &expiration, + &pc->exchange_url, + &next_url, + &pc->reserve_priv); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) + return reply_lookup_reward_failed (connection, + qs); + GNUNET_free (next_url); + MHD_suspend_connection (connection); + pc->connection = connection; + pc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT, + &do_timeout, + pc); + pc->fo = TMH_EXCHANGES_keys4exchange (pc->exchange_url, + &compute_total_requested, + pc); + return MHD_YES; + } + + + TMH_db->preflight (TMH_db->cls); + num_retries = 0; +RETRY: + num_retries++; + if (num_retries > MAX_RETRIES) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_SOFT_FAILURE, + NULL); + } + if (GNUNET_OK != + TMH_db->start (TMH_db->cls, + "pickup reward")) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_START_FAILED, + NULL); + } + { + struct TALER_BlindedDenominationSignature sigs[ + GNUNET_NZL (pc->planchets_length)]; + + memset (sigs, + 0, + sizeof (sigs)); + GNUNET_free (pc->exchange_url); + qs = TMH_db->lookup_pickup (TMH_db->cls, + hc->instance->settings.id, + &pc->reward_id, + &pc->pickup_id, + &pc->exchange_url, + &pc->reserve_priv, + pc->planchets_length, + sigs); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Lookup pickup `%s' resulted in %d\n", + GNUNET_h2s (&pc->pickup_id.hash), + qs); + if (qs > GNUNET_DB_STATUS_SUCCESS_ONE_RESULT) + qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) + { + bool rollback = false; + + for (unsigned int i = 0; i< pc->planchets_length; i++) + { + if (TALER_DENOMINATION_INVALID != sigs[i].cipher) + continue; + if (! rollback) + { + TMH_db->rollback (TMH_db->cls); + MHD_suspend_connection (connection); + GNUNET_CONTAINER_DLL_insert (pc_head, + pc_tail, + pc); + pc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT, + &do_timeout, + pc); + rollback = true; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Lookup pickup `%s' initiated withdraw #%u\n", + GNUNET_h2s (&pc->pickup_id.hash), + i); + try_withdraw (pc, + &pc->planchets[i], + i); + } + if (rollback) + return MHD_YES; + /* we got _all_ signatures, can continue! */ + } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs) + { + unsigned int response_code; + enum TALER_ErrorCode ec; + + TMH_db->rollback (TMH_db->cls); + switch (qs) + { + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + { + json_t *blind_sigs; + + blind_sigs = json_array (); + GNUNET_assert (NULL != blind_sigs); + for (unsigned int i = 0; i<pc->planchets_length; i++) + { + GNUNET_assert (0 == + json_array_append_new ( + blind_sigs, + GNUNET_JSON_PACK ( + TALER_JSON_pack_blinded_denom_sig ("blind_sig", + &sigs[i])))); + TALER_blinded_denom_sig_free (&sigs[i]); + } + return TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_array_steal ("blind_sigs", + blind_sigs)); + } + break; + case GNUNET_DB_STATUS_SOFT_ERROR: + goto RETRY; + case GNUNET_DB_STATUS_HARD_ERROR: + ec = TALER_EC_GENERIC_DB_FETCH_FAILED; + response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + break; + default: + GNUNET_break (0); + ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; + response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + break; + } + return TALER_MHD_reply_with_error (connection, + response_code, + ec, + NULL); + } + } + GNUNET_free (pc->exchange_url); + qs = TMH_db->lookup_reward (TMH_db->cls, + hc->instance->settings.id, + &pc->reward_id, + &total_authorized, + &total_picked_up, + &expiration, + &pc->exchange_url, + &next_url, + &pc->reserve_priv); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + { + TMH_db->rollback (TMH_db->cls); + goto RETRY; + } + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) + { + TMH_db->rollback (TMH_db->cls); + return reply_lookup_reward_failed (connection, + qs); + } + GNUNET_free (next_url); + if (GNUNET_TIME_absolute_is_past (expiration.abs_time)) + { + TMH_db->rollback (TMH_db->cls); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_GONE, + TALER_EC_MERCHANT_REWARD_PICKUP_HAS_EXPIRED, + hc->infix); + } + if (0 > + TALER_amount_subtract (&total_remaining, + &total_authorized, + &total_picked_up)) + { + GNUNET_break_op (0); + TMH_db->rollback (TMH_db->cls); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "picked up amount exceeds authorized amount"); + } + + if (0 > + TALER_amount_cmp (&total_remaining, + &pc->total_requested)) + { + /* total_remaining < pc->total_requested */ + GNUNET_break_op (0); + TMH_db->rollback (TMH_db->cls); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_MERCHANT_REWARD_PICKUP_AMOUNT_EXCEEDS_REWARD_REMAINING, + hc->infix); + } + + GNUNET_assert (0 < + TALER_amount_add (&total_picked_up, + &total_picked_up, + &pc->total_requested)); + qs = TMH_db->insert_pickup (TMH_db->cls, + hc->instance->settings.id, + &pc->reward_id, + &total_picked_up, + &pc->pickup_id, + &pc->total_requested); + if (qs < 0) + { + TMH_db->rollback (TMH_db->cls); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + goto RETRY; + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + "pickup"); + } + qs = TMH_db->commit (TMH_db->cls); + if (qs < 0) + { + TMH_db->rollback (TMH_db->cls); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + goto RETRY; + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_COMMIT_FAILED, + NULL); + } + MHD_suspend_connection (connection); + GNUNET_CONTAINER_DLL_insert (pc_head, + pc_tail, + pc); + pc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT, + &do_timeout, + pc); + for (unsigned int i = 0; i<pc->planchets_length; i++) + { + try_withdraw (pc, + &pc->planchets[i], + i); + } + return MHD_YES; +} diff --git a/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.h b/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.h @@ -0,0 +1,49 @@ +/* + This file is part of TALER + (C) 2017 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_post-rewards-ID-pickup.h + * @brief headers for POST /rewards/ID/pickup handler + * @author Christian Grothoff + */ +#ifndef TALER_MERCHANT_HTTPD_POST_REWARDS_ID_PICKUP_H +#define TALER_MERCHANT_HTTPD_POST_REWARDS_ID_PICKUP_H +#include <microhttpd.h> +#include "taler-merchant-httpd.h" + + +/** + * We are shutting down, force resuming all suspended pickup operations. + */ +void +TMH_force_reward_pickup_resume (void); + + +/** + * Manages a POST /rewards/$ID/pickup call, checking that the reward is authorized, + * and if so, returning the blind signatures. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_post_rewards_ID_pickup (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + + +#endif diff --git a/src/backend/taler-merchant-httpd_post-tips-ID-pickup.c b/src/backend/taler-merchant-httpd_post-tips-ID-pickup.c @@ -1,962 +0,0 @@ -/* - This file is part of TALER - (C) 2017-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-merchant-httpd_post-tips-ID-pickup.c - * @brief implementation of a POST /tips/ID/pickup handler - * @author Christian Grothoff - */ -#include "platform.h" -#include <microhttpd.h> -#include <jansson.h> -#include <taler/taler_json_lib.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_signatures.h> -#include "taler-merchant-httpd.h" -#include "taler-merchant-httpd_mhd.h" -#include "taler-merchant-httpd_helper.h" -#include "taler-merchant-httpd_exchanges.h" -#include "taler-merchant-httpd_post-tips-ID-pickup.h" - - -/** - * How often do we retry on serialization errors? - */ -#define MAX_RETRIES 3 - -/** - * How long do we give the exchange operation to complete withdrawing - * all of the planchets? - */ -#define EXCHANGE_TIMEOUT GNUNET_TIME_relative_multiply ( \ - GNUNET_TIME_UNIT_SECONDS, 45) - - -/** - * Active pickup operations. - */ -struct PickupContext; - - -/** - * Handle for an individual planchet we are processing for a tip. - */ -struct PlanchetOperation -{ - /** - * Active pickup operation this planchet belongs with. - */ - struct PickupContext *pc; - - /** - * Kept in a DLL. - */ - struct PlanchetOperation *prev; - - /** - * Kept in a DLL. - */ - struct PlanchetOperation *next; - - /** - * Find operation (while active), later NULL. - */ - struct TMH_EXCHANGES_KeysOperation *fo; - - /** - * Withdraw handle (NULL while @e fo is active). - */ - struct TALER_EXCHANGE_Withdraw2Handle *w2h; - - /** - * Details about the planchet for withdrawing. - */ - struct TALER_PlanchetDetail pd; - - /** - * Offset of this planchet in the original request. - */ - unsigned int offset; -}; - - -/** - * Active pickup operations. - */ -struct PickupContext -{ - /** - * Kept in a DLL. - */ - struct PickupContext *next; - - /** - * Kept in a DLL. - */ - struct PickupContext *prev; - - /** - * The connection. - */ - struct MHD_Connection *connection; - - /** - * Request context. - */ - struct TMH_HandlerContext *hc; - - /** - * Base URL of the exchange we withdraw from. - */ - char *exchange_url; - - /** - * Timeout task. - */ - struct GNUNET_SCHEDULER_Task *tt; - - /** - * Head of DLL of exchange operations on planchets. - */ - struct PlanchetOperation *po_head; - - /** - * Tail of DLL of exchange operations on planchets. - */ - struct PlanchetOperation *po_tail; - - /** - * HTTP response to return (set on errors). - */ - struct MHD_Response *response; - - /** - * Find operation (while active), later NULL. - */ - struct TMH_EXCHANGES_KeysOperation *fo; - - /** - * Which reserve are we draining? - */ - struct TALER_ReservePrivateKeyP reserve_priv; - - /** - * Which tip is being picked up? - */ - struct TALER_TipIdentifierP tip_id; - - /** - * What is the ID of the pickup operation? (Basically a - * hash over the key inputs). - */ - struct TALER_PickupIdentifierP pickup_id; - - /** - * Array of our planchets. - */ - struct TALER_PlanchetDetail *planchets; - - /** - * Length of the @e planchets array. - */ - unsigned int planchets_length; - - /** - * HTTP status to use (set on errors). - */ - unsigned int http_status; - - /** - * Total amount requested in the pick up operation. Computed by - * totaling up the amounts of all the @e planchets. - */ - struct TALER_Amount total_requested; - - /** - * True if @e total_requested has been initialized. - */ - bool tr_initialized; - - /** - * Should we generate a DB notification at the end for the pickup? Used to - * wake up long pollers upon tip pickup. Not done transactionally as there - * are potentially several coins individually added to the DB as - * transactions, and doing a notification per coin would be excessive. - * (And missing an event in the very rare case where our process fails - * hard between a DB operation and generating an HTTP reply is not a problem - * in this case.) However, if we in the future do group all DB transactions - * into one larger transaction, the notification should become part of it. - */ - bool do_notify; -}; - - -/** - * Head of DLL. - */ -static struct PickupContext *pc_head; - -/** - * Tail of DLL. - */ -static struct PickupContext *pc_tail; - - -/** - * Stop all ongoing operations associated with @a pc. - */ -static void -stop_operations (struct PickupContext *pc) -{ - struct PlanchetOperation *po; - - if (NULL != pc->tt) - { - GNUNET_SCHEDULER_cancel (pc->tt); - pc->tt = NULL; - } - if (NULL != pc->fo) - { - TMH_EXCHANGES_keys4exchange_cancel (pc->fo); - pc->fo = NULL; - } - while (NULL != (po = pc->po_head)) - { - if (NULL != po->fo) - { - TMH_EXCHANGES_keys4exchange_cancel (po->fo); - po->fo = NULL; - } - if (NULL != po->w2h) - { - TALER_EXCHANGE_withdraw2_cancel (po->w2h); - po->w2h = NULL; - } - GNUNET_CONTAINER_DLL_remove (pc->po_head, - pc->po_tail, - po); - GNUNET_free (po); - } -} - - -/** - * Function called to clean up. - * - * @param cls a `struct PickupContext *` to clean up - */ -static void -pick_context_cleanup (void *cls) -{ - struct PickupContext *pc = cls; - - if (pc->do_notify) - { - struct TMH_TipPickupEventP tip_eh = { - .header.size = htons (sizeof (tip_eh)), - .header.type = htons (TALER_DBEVENT_MERCHANT_TIP_PICKUP), - .tip_id = pc->tip_id - }; - - GNUNET_CRYPTO_hash (pc->hc->instance->settings.id, - strlen (pc->hc->instance->settings.id), - &tip_eh.h_instance); - TMH_db->event_notify (TMH_db->cls, - &tip_eh.header, - NULL, - 0); - } - stop_operations (pc); /* should not be any... */ - for (unsigned int i = 0; i<pc->planchets_length; i++) - TALER_planchet_detail_free (&pc->planchets[i]); - GNUNET_array_grow (pc->planchets, - pc->planchets_length, - 0); - GNUNET_free (pc->exchange_url); - GNUNET_free (pc); -} - - -void -TMH_force_tip_pickup_resume () -{ - struct PickupContext *nxt; - - for (struct PickupContext *pc = pc_head; - NULL != pc; - pc = nxt) - { - nxt = pc->next; - stop_operations (pc); - GNUNET_CONTAINER_DLL_remove (pc_head, - pc_tail, - pc); - MHD_resume_connection (pc->connection); - } -} - - -/** - * Callbacks of this type are used to serve the result of submitting a - * withdraw request to a exchange without the (un)blinding factor. - * We persist the result in the database and, if we were the last - * planchet operation, resume HTTP processing. - * - * @param cls closure with a `struct PlanchetOperation *` - * @param w2r response data - */ -static void -withdraw_cb (void *cls, - const struct TALER_EXCHANGE_Withdraw2Response *w2r) -{ - struct PlanchetOperation *po = cls; - const struct TALER_EXCHANGE_HttpResponse *hr = &w2r->hr; - struct PickupContext *pc = po->pc; - enum GNUNET_DB_QueryStatus qs; - - GNUNET_CONTAINER_DLL_remove (pc->po_head, - pc->po_tail, - po); - TMH_db->preflight (TMH_db->cls); - if (MHD_HTTP_OK != hr->http_status) - { - GNUNET_free (po); - stop_operations (pc); - pc->http_status = MHD_HTTP_BAD_GATEWAY; - pc->response = - TALER_MHD_MAKE_JSON_PACK ( - TALER_JSON_pack_ec (TALER_EC_MERCHANT_TIP_PICKUP_EXCHANGE_ERROR), - TMH_pack_exchange_reply (hr)); - GNUNET_CONTAINER_DLL_remove (pc_head, - pc_tail, - pc); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - qs = TMH_db->insert_pickup_blind_signature (TMH_db->cls, - &pc->pickup_id, - po->offset, - &w2r->details.ok.blind_sig); - GNUNET_free (po); - if (qs < 0) - { - stop_operations (pc); - pc->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; - pc->response = TALER_MHD_make_error ( - TALER_EC_GENERIC_DB_STORE_FAILED, - "blind signature"); - GNUNET_CONTAINER_DLL_remove (pc_head, - pc_tail, - pc); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - pc->do_notify = true; - if (NULL != pc->po_head) - return; /* More pending */ - stop_operations (pc); /* stops timeout job */ - GNUNET_CONTAINER_DLL_remove (pc_head, - pc_tail, - pc); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ -} - - -/** - * Function called with the result of a #TMH_EXCHANGES_find_exchange() - * operation as part of a withdraw objective. If the exchange is ready, - * withdraws the planchet from the exchange. - * - * @param cls closure, with our `struct PlanchetOperation *` - * @param keys keys for the exchange - */ -static void -do_withdraw (void *cls, - struct TALER_EXCHANGE_Keys *keys) -{ - struct PlanchetOperation *po = cls; - struct PickupContext *pc = po->pc; - - po->fo = NULL; - TMH_db->preflight (TMH_db->cls); - if (NULL == keys) - { - stop_operations (pc); - GNUNET_CONTAINER_DLL_remove (pc->po_head, - pc->po_tail, - po); - GNUNET_free (po); - pc->http_status = MHD_HTTP_GATEWAY_TIMEOUT; - pc->response = TALER_MHD_MAKE_JSON_PACK ( - TALER_JSON_pack_ec ( - TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT)); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - po->w2h = TALER_EXCHANGE_withdraw2 (TMH_curl_ctx, - pc->exchange_url, - keys, - &po->pd, - &pc->reserve_priv, - &withdraw_cb, - po); -} - - -/** - * Withdraw @a planchet from @a exchange_url for @a pc operation at planchet - * @a offset. Sets up the respective operation and adds it @a pc's operation - * list. Once the operation is complete, the resulting blind signature is - * committed to the merchant's database. If all planchet operations are - * completed, the HTTP processing is resumed. - * - * @param[in,out] pc a pending pickup operation that includes @a planchet - * @param planchet details about the coin to pick up - * @param offset offset of @a planchet in the list, needed to process the reply - */ -static void -try_withdraw (struct PickupContext *pc, - const struct TALER_PlanchetDetail *planchet, - unsigned int offset) -{ - struct PlanchetOperation *po; - - TMH_db->preflight (TMH_db->cls); - po = GNUNET_new (struct PlanchetOperation); - po->pc = pc; - po->pd = *planchet; - po->offset = offset; - po->fo = TMH_EXCHANGES_keys4exchange (pc->exchange_url, - &do_withdraw, - po); - GNUNET_assert (NULL != po->fo); - GNUNET_CONTAINER_DLL_insert (pc->po_head, - pc->po_tail, - po); -} - - -/** - * Handle timeout for pickup. - * - * @param cls a `struct PickupContext *` - */ -static void -do_timeout (void *cls) -{ - struct PickupContext *pc = cls; - - pc->tt = NULL; - stop_operations (pc); - pc->http_status = MHD_HTTP_GATEWAY_TIMEOUT; - pc->response = TALER_MHD_make_error ( - TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT, - NULL); - GNUNET_CONTAINER_DLL_remove (pc_head, - pc_tail, - pc); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ -} - - -/** - * Function called with the result of a #TMH_EXCHANGES_find_exchange() - * operation as part of a withdraw objective. Here, we initialize - * the "total_requested" amount by adding up the cost of the planchets - * provided by the client. - * - * @param cls closure, with our `struct PickupContext *` - * @param keys the keys of the exchange - */ -static void -compute_total_requested (void *cls, - struct TALER_EXCHANGE_Keys *keys) -{ - struct PickupContext *pc = cls; - - pc->fo = NULL; - stop_operations (pc); /* stops timeout job */ - if (NULL == keys) - { - pc->http_status = MHD_HTTP_GATEWAY_TIMEOUT; - pc->response = TALER_MHD_MAKE_JSON_PACK ( - TALER_JSON_pack_ec ( - TALER_EC_MERCHANT_GENERIC_EXCHANGE_KEYS_FAILURE)); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (TMH_currency, - &pc->total_requested)); - for (unsigned int i = 0; i<pc->planchets_length; i++) - { - struct TALER_PlanchetDetail *pd = &pc->planchets[i]; - const struct TALER_EXCHANGE_DenomPublicKey *dpk; - - dpk = TALER_EXCHANGE_get_denomination_key_by_hash (keys, - &pd->denom_pub_hash); - if (NULL == dpk) - { - pc->http_status = MHD_HTTP_CONFLICT; - pc->response = - TALER_MHD_MAKE_JSON_PACK ( - TALER_JSON_pack_ec ( - TALER_EC_MERCHANT_TIP_PICKUP_DENOMINATION_UNKNOWN)); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - - if ( (GNUNET_YES != - TALER_amount_cmp_currency (&pc->total_requested, - &dpk->value)) || - (0 > - TALER_amount_add (&pc->total_requested, - &pc->total_requested, - &dpk->value)) ) - { - pc->http_status = MHD_HTTP_BAD_REQUEST; - pc->response = - TALER_MHD_make_error (TALER_EC_MERCHANT_TIP_PICKUP_SUMMATION_FAILED, - "Could not add up values to compute pickup total"); - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ - return; - } - } - pc->tr_initialized = true; - MHD_resume_connection (pc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ -} - - -/** - * The tip lookup operation failed. Generate an error response based on the @a qs. - * - * @param connection connection to generate error for - * @param qs DB status to base error creation on - * @return MHD result code - */ -static MHD_RESULT -reply_lookup_tip_failed (struct MHD_Connection *connection, - enum GNUNET_DB_QueryStatus qs) -{ - unsigned int response_code; - enum TALER_ErrorCode ec; - - TMH_db->rollback (TMH_db->cls); - switch (qs) - { - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - ec = TALER_EC_MERCHANT_GENERIC_TIP_ID_UNKNOWN; - response_code = MHD_HTTP_NOT_FOUND; - break; - case GNUNET_DB_STATUS_SOFT_ERROR: - ec = TALER_EC_GENERIC_DB_SOFT_FAILURE; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - case GNUNET_DB_STATUS_HARD_ERROR: - ec = TALER_EC_GENERIC_DB_COMMIT_FAILED; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - default: - GNUNET_break (0); - ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - } - return TALER_MHD_reply_with_error (connection, - response_code, - ec, - NULL); -} - - -MHD_RESULT -TMH_post_tips_ID_pickup (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - struct PickupContext *pc = hc->ctx; - char *next_url; - struct TALER_Amount total_authorized; - struct TALER_Amount total_picked_up; - struct TALER_Amount total_remaining; - struct GNUNET_TIME_Timestamp expiration; - enum GNUNET_DB_QueryStatus qs; - unsigned int num_retries; - - if (NULL == pc) - { - const json_t *planchets; - json_t *planchet; - size_t index; - - pc = GNUNET_new (struct PickupContext); - hc->ctx = pc; - hc->cc = &pick_context_cleanup; - pc->hc = hc; - GNUNET_assert (NULL != hc->infix); - if (GNUNET_OK != - GNUNET_CRYPTO_hash_from_string (hc->infix, - &pc->tip_id.hash)) - { - /* tip_id has wrong encoding */ - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - hc->infix); - } - - { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_array_const ("planchets", - &planchets), - GNUNET_JSON_spec_end () - }; - { - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (connection, - hc->request_body, - spec); - if (GNUNET_OK != res) - return (GNUNET_NO == res) - ? MHD_YES - : MHD_NO; - } - } - GNUNET_array_grow (pc->planchets, - pc->planchets_length, - json_array_size (planchets)); - json_array_foreach (planchets, index, planchet) { - struct TALER_PlanchetDetail *pd = &pc->planchets[index]; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("denom_pub_hash", - &pd->denom_pub_hash), - TALER_JSON_spec_blinded_planchet ("coin_ev", - &pd->blinded_planchet), - GNUNET_JSON_spec_end () - }; - { - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (connection, - planchet, - spec); - if (GNUNET_OK != res) - { - return (GNUNET_NO == res) - ? MHD_YES - : MHD_NO; - } - } - } - { - struct GNUNET_HashContext *hc; - - hc = GNUNET_CRYPTO_hash_context_start (); - GNUNET_CRYPTO_hash_context_read (hc, - &pc->tip_id, - sizeof (pc->tip_id)); - for (unsigned int i = 0; i<pc->planchets_length; i++) - { - struct TALER_PlanchetDetail *pd = &pc->planchets[i]; - - GNUNET_CRYPTO_hash_context_read (hc, - &pd->denom_pub_hash, - sizeof (pd->denom_pub_hash)); - TALER_blinded_planchet_hash_ (&pd->blinded_planchet, - hc); - } - GNUNET_CRYPTO_hash_context_finish (hc, - &pc->pickup_id.hash); - } - } - - if (NULL != pc->response) - { - MHD_RESULT ret; - - ret = MHD_queue_response (connection, - pc->http_status, - pc->response); - pc->response = NULL; - return ret; - } - - if (! pc->tr_initialized) - { - char *next_url; - - qs = TMH_db->lookup_tip (TMH_db->cls, - hc->instance->settings.id, - &pc->tip_id, - &total_authorized, - &total_picked_up, - &expiration, - &pc->exchange_url, - &next_url, - &pc->reserve_priv); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - return reply_lookup_tip_failed (connection, - qs); - GNUNET_free (next_url); - MHD_suspend_connection (connection); - pc->connection = connection; - pc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT, - &do_timeout, - pc); - pc->fo = TMH_EXCHANGES_keys4exchange (pc->exchange_url, - &compute_total_requested, - pc); - return MHD_YES; - } - - - TMH_db->preflight (TMH_db->cls); - num_retries = 0; -RETRY: - num_retries++; - if (num_retries > MAX_RETRIES) - { - GNUNET_break (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_SOFT_FAILURE, - NULL); - } - if (GNUNET_OK != - TMH_db->start (TMH_db->cls, - "pickup tip")) - { - GNUNET_break (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_START_FAILED, - NULL); - } - { - struct TALER_BlindedDenominationSignature sigs[ - GNUNET_NZL (pc->planchets_length)]; - - memset (sigs, - 0, - sizeof (sigs)); - GNUNET_free (pc->exchange_url); - qs = TMH_db->lookup_pickup (TMH_db->cls, - hc->instance->settings.id, - &pc->tip_id, - &pc->pickup_id, - &pc->exchange_url, - &pc->reserve_priv, - pc->planchets_length, - sigs); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Lookup pickup `%s' resulted in %d\n", - GNUNET_h2s (&pc->pickup_id.hash), - qs); - if (qs > GNUNET_DB_STATUS_SUCCESS_ONE_RESULT) - qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) - { - bool rollback = false; - - for (unsigned int i = 0; i< pc->planchets_length; i++) - { - if (TALER_DENOMINATION_INVALID != sigs[i].cipher) - continue; - if (! rollback) - { - TMH_db->rollback (TMH_db->cls); - MHD_suspend_connection (connection); - GNUNET_CONTAINER_DLL_insert (pc_head, - pc_tail, - pc); - pc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT, - &do_timeout, - pc); - rollback = true; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Lookup pickup `%s' initiated withdraw #%u\n", - GNUNET_h2s (&pc->pickup_id.hash), - i); - try_withdraw (pc, - &pc->planchets[i], - i); - } - if (rollback) - return MHD_YES; - /* we got _all_ signatures, can continue! */ - } - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs) - { - unsigned int response_code; - enum TALER_ErrorCode ec; - - TMH_db->rollback (TMH_db->cls); - switch (qs) - { - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - { - json_t *blind_sigs; - - blind_sigs = json_array (); - GNUNET_assert (NULL != blind_sigs); - for (unsigned int i = 0; i<pc->planchets_length; i++) - { - GNUNET_assert (0 == - json_array_append_new ( - blind_sigs, - GNUNET_JSON_PACK ( - TALER_JSON_pack_blinded_denom_sig ("blind_sig", - &sigs[i])))); - TALER_blinded_denom_sig_free (&sigs[i]); - } - return TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_array_steal ("blind_sigs", - blind_sigs)); - } - break; - case GNUNET_DB_STATUS_SOFT_ERROR: - goto RETRY; - case GNUNET_DB_STATUS_HARD_ERROR: - ec = TALER_EC_GENERIC_DB_FETCH_FAILED; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - default: - GNUNET_break (0); - ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - } - return TALER_MHD_reply_with_error (connection, - response_code, - ec, - NULL); - } - } - GNUNET_free (pc->exchange_url); - qs = TMH_db->lookup_tip (TMH_db->cls, - hc->instance->settings.id, - &pc->tip_id, - &total_authorized, - &total_picked_up, - &expiration, - &pc->exchange_url, - &next_url, - &pc->reserve_priv); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - { - TMH_db->rollback (TMH_db->cls); - goto RETRY; - } - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - TMH_db->rollback (TMH_db->cls); - return reply_lookup_tip_failed (connection, - qs); - } - GNUNET_free (next_url); - if (GNUNET_TIME_absolute_is_past (expiration.abs_time)) - { - TMH_db->rollback (TMH_db->cls); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_GONE, - TALER_EC_MERCHANT_TIP_PICKUP_HAS_EXPIRED, - hc->infix); - } - if (0 > - TALER_amount_subtract (&total_remaining, - &total_authorized, - &total_picked_up)) - { - GNUNET_break_op (0); - TMH_db->rollback (TMH_db->cls); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, - "picked up amount exceeds authorized amount"); - } - - if (0 > - TALER_amount_cmp (&total_remaining, - &pc->total_requested)) - { - /* total_remaining < pc->total_requested */ - GNUNET_break_op (0); - TMH_db->rollback (TMH_db->cls); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_MERCHANT_TIP_PICKUP_AMOUNT_EXCEEDS_TIP_REMAINING, - hc->infix); - } - - GNUNET_assert (0 < - TALER_amount_add (&total_picked_up, - &total_picked_up, - &pc->total_requested)); - qs = TMH_db->insert_pickup (TMH_db->cls, - hc->instance->settings.id, - &pc->tip_id, - &total_picked_up, - &pc->pickup_id, - &pc->total_requested); - if (qs < 0) - { - TMH_db->rollback (TMH_db->cls); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - goto RETRY; - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_STORE_FAILED, - "pickup"); - } - qs = TMH_db->commit (TMH_db->cls); - if (qs < 0) - { - TMH_db->rollback (TMH_db->cls); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - goto RETRY; - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_COMMIT_FAILED, - NULL); - } - MHD_suspend_connection (connection); - GNUNET_CONTAINER_DLL_insert (pc_head, - pc_tail, - pc); - pc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT, - &do_timeout, - pc); - for (unsigned int i = 0; i<pc->planchets_length; i++) - { - try_withdraw (pc, - &pc->planchets[i], - i); - } - return MHD_YES; -} diff --git a/src/backend/taler-merchant-httpd_post-tips-ID-pickup.h b/src/backend/taler-merchant-httpd_post-tips-ID-pickup.h @@ -1,49 +0,0 @@ -/* - This file is part of TALER - (C) 2017 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-merchant-httpd_post-tips-ID-pickup.h - * @brief headers for POST /tips/ID/pickup handler - * @author Christian Grothoff - */ -#ifndef TALER_MERCHANT_HTTPD_POST_TIPS_ID_PICKUP_H -#define TALER_MERCHANT_HTTPD_POST_TIPS_ID_PICKUP_H -#include <microhttpd.h> -#include "taler-merchant-httpd.h" - - -/** - * We are shutting down, force resuming all suspended pickup operations. - */ -void -TMH_force_tip_pickup_resume (void); - - -/** - * Manages a POST /tips/$ID/pickup call, checking that the tip is authorized, - * and if so, returning the blind signatures. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_post_tips_ID_pickup (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - - -#endif diff --git a/src/backend/taler-merchant-httpd_private-get-reserves-ID.c b/src/backend/taler-merchant-httpd_private-get-reserves-ID.c @@ -45,9 +45,9 @@ struct GetReserveContext MHD_RESULT res; /** - * Should we return details about tips? + * Should we return details about rewards? */ - bool tips; + bool rewards; }; @@ -60,14 +60,14 @@ struct GetReserveContext * @param merchant_initial_amount initial amount that the merchant claims to have filled the * reserve with * @param exchange_initial_amount initial amount that the exchange claims to have received - * @param picked_up_amount total of tips that were picked up from this reserve - * @param committed_amount total of tips that the merchant committed to, but that were not + * @param picked_up_amount total of rewards that were picked up from this reserve + * @param committed_amount total of rewards that the merchant committed to, but that were not * picked up yet * @param active true if the reserve is still active (we have the private key) * @param master_pub master public key of the exchange * @param exchange_url URL of the exchange, NULL if not active - * @param tips_length length of the @a tips array - * @param tips information about the tips created by this reserve + * @param rewards_length length of the @a rewards array + * @param rewards information about the rewards created by this reserve */ static void handle_reserve_details ( @@ -81,34 +81,34 @@ handle_reserve_details ( bool active, const struct TALER_MasterPublicKeyP *master_pub, const char *exchange_url, - unsigned int tips_length, - const struct TALER_MERCHANTDB_TipDetails *tips) + unsigned int rewards_length, + const struct TALER_MERCHANTDB_RewardDetails *rewards) { struct GetReserveContext *ctx = cls; - json_t *tips_json; + json_t *rewards_json; json_t *accounts; - if (NULL != tips) + if (NULL != rewards) { - tips_json = json_array (); - GNUNET_assert (NULL != tips_json); - for (unsigned int i = 0; i<tips_length; i++) + rewards_json = json_array (); + GNUNET_assert (NULL != rewards_json); + for (unsigned int i = 0; i<rewards_length; i++) { GNUNET_assert (0 == json_array_append_new ( - tips_json, + rewards_json, GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ("tip_id", - &tips[i].tip_id), + GNUNET_JSON_pack_data_auto ("reward_id", + &rewards[i].reward_id), TALER_JSON_pack_amount ("total_amount", - &tips[i].total_amount), + &rewards[i].total_amount), GNUNET_JSON_pack_string ("reason", - tips[i].reason)))); + rewards[i].reason)))); } } else { - tips_json = NULL; + rewards_json = NULL; } accounts = TMH_exchange_accounts_by_method (master_pub, NULL); @@ -128,8 +128,8 @@ handle_reserve_details ( TALER_JSON_pack_amount ("committed_amount", committed_amount), GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_array_steal ("tips", - tips_json)), + GNUNET_JSON_pack_array_steal ("rewards", + rewards_json)), GNUNET_JSON_pack_bool ("active", active), GNUNET_JSON_pack_allow_null ( @@ -155,7 +155,7 @@ TMH_private_get_reserves_ID (const struct TMH_RequestHandler *rh, struct TMH_HandlerContext *hc) { struct TALER_ReservePublicKeyP reserve_pub; - bool tips; + bool rewards; (void) rh; if (GNUNET_OK != @@ -164,7 +164,7 @@ TMH_private_get_reserves_ID (const struct TMH_RequestHandler *rh, &reserve_pub, sizeof (reserve_pub))) { - /* tip_id has wrong encoding */ + /* reward_id has wrong encoding */ GNUNET_break_op (0); return TALER_MHD_reply_with_error (connection, MHD_HTTP_BAD_REQUEST, @@ -176,15 +176,15 @@ TMH_private_get_reserves_ID (const struct TMH_RequestHandler *rh, tstr = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, - "tips"); - tips = (NULL != tstr) + "rewards"); + rewards = (NULL != tstr) ? 0 == strcasecmp (tstr, "yes") : false; } { struct GetReserveContext ctx = { .connection = connection, - .tips = tips + .rewards = rewards }; enum GNUNET_DB_QueryStatus qs; @@ -192,7 +192,7 @@ TMH_private_get_reserves_ID (const struct TMH_RequestHandler *rh, qs = TMH_db->lookup_reserve (TMH_db->cls, hc->instance->settings.id, &reserve_pub, - tips, + rewards, &handle_reserve_details, &ctx); if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) @@ -203,7 +203,7 @@ TMH_private_get_reserves_ID (const struct TMH_RequestHandler *rh, switch (qs) { case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - ec = TALER_EC_MERCHANT_GENERIC_TIP_ID_UNKNOWN; + ec = TALER_EC_MERCHANT_GENERIC_REWARD_ID_UNKNOWN; response_code = MHD_HTTP_NOT_FOUND; break; case GNUNET_DB_STATUS_SOFT_ERROR: diff --git a/src/backend/taler-merchant-httpd_private-get-reserves-ID.h b/src/backend/taler-merchant-httpd_private-get-reserves-ID.h @@ -15,7 +15,7 @@ */ /** * @file taler-merchant-httpd_private-get-reserves-ID.h - * @brief headers for /tip-query handler + * @brief headers for /reward-query handler * @author Florian Dold */ #ifndef TALER_MERCHANT_HTTPD_GET_RESERVES_ID_H diff --git a/src/backend/taler-merchant-httpd_private-get-rewards-ID.c b/src/backend/taler-merchant-httpd_private-get-rewards-ID.c @@ -0,0 +1,395 @@ +/* + This file is part of TALER + (C) 2017-2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_get-rewards-ID.c + * @brief implementation of a GET /rewards/ID handler + * @author Christian Grothoff + */ +#include "platform.h" +#include <microhttpd.h> +#include <jansson.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_json_lib.h> +#include <taler/taler_signatures.h> +#include "taler-merchant-httpd.h" +#include "taler-merchant-httpd_mhd.h" +#include "taler-merchant-httpd_exchanges.h" + + +/** + * Information we keep per /kyc request. + */ +struct RewardContext +{ + /** + * Stored in a DLL. + */ + struct RewardContext *next; + + /** + * Stored in a DLL. + */ + struct RewardContext *prev; + + /** + * Connection we are handling. + */ + struct MHD_Connection *connection; + + /** + * Our handler context. + */ + struct TMH_HandlerContext *hc; + + /** + * Database event we are waiting on to be resuming. + */ + struct GNUNET_DB_EventHandler *eh; + + /** + * Response to return, NULL if we don't have one yet. + */ + struct MHD_Response *response; + + /** + * When does this request time out? + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * ID of the reward being queried. + */ + struct TALER_RewardIdentifierP reward_id; + + /** + * Minimum reward amount picked up we should return to the + * client. + */ + struct TALER_Amount min_amount; + + /** + * #GNUNET_NO if the @e connection was not suspended, + * #GNUNET_YES if the @e connection was suspended, + * #GNUNET_SYSERR if @e connection was resumed to as + * part of #MH_force_pc_resume during shutdown. + */ + enum GNUNET_GenericReturnValue suspended; + + /** + * Is the "pickups" argument set to "yes"? + */ + bool fpu; + +}; + + +/** + * Head of DLL. + */ +static struct RewardContext *tc_head; + +/** + * Tail of DLL. + */ +static struct RewardContext *tc_tail; + + +void +TMH_force_reward_resume () +{ + for (struct RewardContext *tc = tc_head; + NULL != tc; + tc = tc->next) + { + if (GNUNET_YES == tc->suspended) + { + tc->suspended = GNUNET_SYSERR; + MHD_resume_connection (tc->connection); + } + } +} + + +/** + * Custom cleanup routine for a `struct RewardContext`. + * + * @param cls the `struct RewardContext` to clean up. + */ +static void +reward_context_cleanup (void *cls) +{ + struct RewardContext *tc = cls; + + if (NULL != tc->response) + { + MHD_destroy_response (tc->response); + tc->response = NULL; + } + if (NULL != tc->eh) + { + TMH_db->event_listen_cancel (tc->eh); + tc->eh = NULL; + } + GNUNET_CONTAINER_DLL_remove (tc_head, + tc_tail, + tc); + GNUNET_free (tc); +} + + +/** + * We have received a trigger from the database + * that we should (possibly) resume the request. + * + * @param cls a `struct RewardContext` to resume + * @param extra usually NULL + * @param extra_size number of bytes in @a extra + */ +static void +resume_by_event (void *cls, + const void *extra, + size_t extra_size) +{ + struct RewardContext *tc = cls; + + (void) extra; + (void) extra_size; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Resuming request %p by trigger\n", + tc); + if (GNUNET_NO == tc->suspended) + return; /* duplicate event is possible */ + tc->suspended = GNUNET_NO; + GNUNET_CONTAINER_DLL_remove (tc_head, + tc_tail, + tc); + MHD_resume_connection (tc->connection); + TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ +} + + +MHD_RESULT +TMH_private_get_rewards_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct RewardContext *tc = hc->ctx; + struct TALER_Amount total_authorized; + struct TALER_Amount total_picked_up; + char *reason; + struct GNUNET_TIME_Timestamp expiration; + struct TALER_ReservePublicKeyP reserve_pub; + unsigned int pickups_length = 0; + struct TALER_MERCHANTDB_PickupDetails *pickups = NULL; + enum GNUNET_DB_QueryStatus qs; + json_t *pickups_json = NULL; + + (void) rh; + if (NULL == tc) + { + tc = GNUNET_new (struct RewardContext); + hc->ctx = tc; + hc->cc = &reward_context_cleanup; + GNUNET_CONTAINER_DLL_insert (tc_head, + tc_tail, + tc); + tc->connection = connection; + tc->hc = hc; + GNUNET_assert (NULL != hc->infix); + if (GNUNET_OK != + GNUNET_CRYPTO_hash_from_string (hc->infix, + &tc->reward_id.hash)) + { + /* reward_id has wrong encoding */ + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + hc->infix); + } + { + const char *pstr; + + pstr = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "pickups"); + tc->fpu = (NULL != pstr) + ? 0 == strcasecmp (pstr, "yes") + : false; + } + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (TMH_currency, + &tc->min_amount)); + { + const char *min_amount; + + min_amount = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "min_amount"); + if (NULL != min_amount) + { + if (GNUNET_OK != + TALER_string_to_amount (min_amount, + &tc->min_amount)) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "min_amount"); + } + if (0 != + strcasecmp (tc->min_amount.currency, + TMH_currency)) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_CURRENCY_MISMATCH, + TMH_currency); + } + } + } + TALER_MHD_parse_request_timeout (connection, + &tc->timeout); + if (! GNUNET_TIME_absolute_is_future (tc->timeout)) + { + struct TMH_RewardPickupEventP reward_eh = { + .header.size = htons (sizeof (reward_eh)), + .header.type = htons (TALER_DBEVENT_MERCHANT_REWARD_PICKUP), + .reward_id = tc->reward_id + }; + + GNUNET_CRYPTO_hash (hc->instance->settings.id, + strlen (hc->instance->settings.id), + &reward_eh.h_instance); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Subscribing to payment triggers for %p\n", + tc); + tc->eh = TMH_db->event_listen ( + TMH_db->cls, + &reward_eh.header, + GNUNET_TIME_absolute_get_remaining (tc->timeout), + &resume_by_event, + tc); + } + } + + GNUNET_assert (GNUNET_YES != tc->suspended); + TMH_db->preflight (TMH_db->cls); + qs = TMH_db->lookup_reward_details (TMH_db->cls, + hc->instance->settings.id, + &tc->reward_id, + tc->fpu, + &total_authorized, + &total_picked_up, + &reason, + &expiration, + &reserve_pub, + &pickups_length, + &pickups); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) + { + unsigned int response_code; + enum TALER_ErrorCode ec; + + switch (qs) + { + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + ec = TALER_EC_MERCHANT_GENERIC_REWARD_ID_UNKNOWN; + response_code = MHD_HTTP_NOT_FOUND; + break; + case GNUNET_DB_STATUS_SOFT_ERROR: + ec = TALER_EC_GENERIC_DB_SOFT_FAILURE; + response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + break; + case GNUNET_DB_STATUS_HARD_ERROR: + ec = TALER_EC_GENERIC_DB_COMMIT_FAILED; + response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + break; + default: + GNUNET_break (0); + ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; + response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + break; + } + return TALER_MHD_reply_with_error (connection, + response_code, + ec, + NULL); + } + /* do not allow timeout above reward expiration */ + tc->timeout = GNUNET_TIME_absolute_min (tc->timeout, + expiration.abs_time); + if ( (NULL != tc->eh) && + (GNUNET_TIME_absolute_is_future (tc->timeout)) && + (1 == TALER_amount_cmp (&tc->min_amount, + &total_picked_up)) ) + { + MHD_suspend_connection (connection); + tc->suspended = GNUNET_YES; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Suspending REWARD request handling as pickup is below threshold requested by client\n"); + GNUNET_array_grow (pickups, + pickups_length, + 0); + GNUNET_free (reason); + return MHD_YES; + } + if (tc->fpu) + { + pickups_json = json_array (); + GNUNET_assert (NULL != pickups_json); + for (unsigned int i = 0; i<pickups_length; i++) + { + GNUNET_assert (0 == + json_array_append_new ( + pickups_json, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("pickup_id", + &pickups[i].pickup_id), + GNUNET_JSON_pack_uint64 ("num_planchets", + pickups[i].num_planchets), + TALER_JSON_pack_amount ("requested_amount", + &pickups[i].requested_amount)))); + } + } + GNUNET_array_grow (pickups, + pickups_length, + 0); + { + MHD_RESULT ret; + + ret = TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + TALER_JSON_pack_amount ("total_authorized", + &total_authorized), + TALER_JSON_pack_amount ("total_picked_up", + &total_picked_up), + GNUNET_JSON_pack_string ("reason", + reason), + GNUNET_JSON_pack_timestamp ("expiration", + expiration), + GNUNET_JSON_pack_data_auto ("reserve_pub", + &reserve_pub), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_array_steal ("pickups", + pickups_json))); + GNUNET_free (reason); + return ret; + } +} diff --git a/src/backend/taler-merchant-httpd_private-get-rewards-ID.h b/src/backend/taler-merchant-httpd_private-get-rewards-ID.h @@ -0,0 +1,48 @@ +/* + This file is part of TALER + (C) 2017, 2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_get-rewards-ID.h + * @brief headers for GET /rewards/ID handler + * @author Christian Grothoff + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_REWARDS_ID_H +#define TALER_MERCHANT_HTTPD_PRIVATE_GET_REWARDS_ID_H +#include <microhttpd.h> +#include "taler-merchant-httpd.h" + + +/** + * Force wake-up of all suspended rewardping long-pollers. + */ +void +TMH_force_reward_resume (void); + + +/** + * Manages a GET /rewards/$ID call, returning the status of the reward. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_get_rewards_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + + +#endif diff --git a/src/backend/taler-merchant-httpd_private-get-rewards.c b/src/backend/taler-merchant-httpd_private-get-rewards.c @@ -0,0 +1,157 @@ +/* + This file is part of TALER + (C) 2020-2021 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-get-rewards.c + * @brief implementation of a GET /private/rewards handler + * @author Jonathan Buchanan + */ +#include "platform.h" +#include "taler-merchant-httpd_private-get-rewards.h" +#include <taler/taler_json_lib.h> + +/** + * Add reward details to our JSON array. + * + * @param[in,out] cls a `json_t *` JSON array to build + * @param row_id row number of the reward + * @param reward_id ID of the reward + * @param amount the amount of the reward + */ +static void +add_reward (void *cls, + uint64_t row_id, + struct TALER_RewardIdentifierP reward_id, + struct TALER_Amount amount) +{ + json_t *pa = cls; + + GNUNET_assert (0 == + json_array_append_new ( + pa, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("row_id", + row_id), + GNUNET_JSON_pack_data_auto ("reward_id", + &reward_id), + TALER_JSON_pack_amount ("reward_amount", + &amount)))); +} + + +MHD_RESULT +TMH_private_get_rewards (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + json_t *pa; + enum GNUNET_DB_QueryStatus qs; + enum TALER_EXCHANGE_YesNoAll expired; + uint64_t offset; + int64_t limit; + + (void) rh; + if (! (TALER_arg_to_yna (connection, + "expired", + TALER_EXCHANGE_YNA_NO, + &expired)) ) + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "expired"); + { + const char *limit_str; + + limit_str = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "limit"); + if (NULL == limit_str) + { + limit = -20; + } + else + { + char dummy[2]; + long long ll; + + if (1 != + sscanf (limit_str, + "%lld%1s", + &ll, + dummy)) + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "limit"); + limit = (uint64_t) ll; + } + } + { + const char *offset_str; + + offset_str = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "offset"); + if (NULL == offset_str) + { + if (limit > 0) + offset = 0; + else + offset = INT64_MAX; + } + else + { + char dummy[2]; + unsigned long long ull; + + if (1 != + sscanf (offset_str, + "%llu%1s", + &ull, + dummy)) + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "offset"); + offset = (uint64_t) ull; + } + } + + pa = json_array (); + GNUNET_assert (NULL != pa); + qs = TMH_db->lookup_rewards (TMH_db->cls, + hc->instance->settings.id, + expired, + limit, + offset, + &add_reward, + pa); + + if (0 > qs) + { + GNUNET_break (0); + json_decref (pa); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "rewards"); + } + + return TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_array_steal ("rewards", + pa)); +} diff --git a/src/backend/taler-merchant-httpd_private-get-rewards.h b/src/backend/taler-merchant-httpd_private-get-rewards.h @@ -0,0 +1,41 @@ +/* + This file is part of TALER + (C) 2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-get-rewards.h + * @brief headers for GET /private/rewards handler + * @author Jonathan Buchanan + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_REWARDS_H +#define TALER_MERCHANT_HTTPD_PRIVATE_GET_REWARDS_H +#include <microhttpd.h> +#include "taler-merchant-httpd.h" + + +/** + * Manages a GET /private/rewards call. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_get_rewards (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + + +#endif diff --git a/src/backend/taler-merchant-httpd_private-get-tips-ID.c b/src/backend/taler-merchant-httpd_private-get-tips-ID.c @@ -1,395 +0,0 @@ -/* - This file is part of TALER - (C) 2017-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-merchant-httpd_get-tips-ID.c - * @brief implementation of a GET /tips/ID handler - * @author Christian Grothoff - */ -#include "platform.h" -#include <microhttpd.h> -#include <jansson.h> -#include <taler/taler_dbevents.h> -#include <taler/taler_json_lib.h> -#include <taler/taler_signatures.h> -#include "taler-merchant-httpd.h" -#include "taler-merchant-httpd_mhd.h" -#include "taler-merchant-httpd_exchanges.h" - - -/** - * Information we keep per /kyc request. - */ -struct TipContext -{ - /** - * Stored in a DLL. - */ - struct TipContext *next; - - /** - * Stored in a DLL. - */ - struct TipContext *prev; - - /** - * Connection we are handling. - */ - struct MHD_Connection *connection; - - /** - * Our handler context. - */ - struct TMH_HandlerContext *hc; - - /** - * Database event we are waiting on to be resuming. - */ - struct GNUNET_DB_EventHandler *eh; - - /** - * Response to return, NULL if we don't have one yet. - */ - struct MHD_Response *response; - - /** - * When does this request time out? - */ - struct GNUNET_TIME_Absolute timeout; - - /** - * ID of the tip being queried. - */ - struct TALER_TipIdentifierP tip_id; - - /** - * Minimum tip amount picked up we should return to the - * client. - */ - struct TALER_Amount min_amount; - - /** - * #GNUNET_NO if the @e connection was not suspended, - * #GNUNET_YES if the @e connection was suspended, - * #GNUNET_SYSERR if @e connection was resumed to as - * part of #MH_force_pc_resume during shutdown. - */ - enum GNUNET_GenericReturnValue suspended; - - /** - * Is the "pickups" argument set to "yes"? - */ - bool fpu; - -}; - - -/** - * Head of DLL. - */ -static struct TipContext *tc_head; - -/** - * Tail of DLL. - */ -static struct TipContext *tc_tail; - - -void -TMH_force_tip_resume () -{ - for (struct TipContext *tc = tc_head; - NULL != tc; - tc = tc->next) - { - if (GNUNET_YES == tc->suspended) - { - tc->suspended = GNUNET_SYSERR; - MHD_resume_connection (tc->connection); - } - } -} - - -/** - * Custom cleanup routine for a `struct TipContext`. - * - * @param cls the `struct TipContext` to clean up. - */ -static void -tip_context_cleanup (void *cls) -{ - struct TipContext *tc = cls; - - if (NULL != tc->response) - { - MHD_destroy_response (tc->response); - tc->response = NULL; - } - if (NULL != tc->eh) - { - TMH_db->event_listen_cancel (tc->eh); - tc->eh = NULL; - } - GNUNET_CONTAINER_DLL_remove (tc_head, - tc_tail, - tc); - GNUNET_free (tc); -} - - -/** - * We have received a trigger from the database - * that we should (possibly) resume the request. - * - * @param cls a `struct TipContext` to resume - * @param extra usually NULL - * @param extra_size number of bytes in @a extra - */ -static void -resume_by_event (void *cls, - const void *extra, - size_t extra_size) -{ - struct TipContext *tc = cls; - - (void) extra; - (void) extra_size; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Resuming request %p by trigger\n", - tc); - if (GNUNET_NO == tc->suspended) - return; /* duplicate event is possible */ - tc->suspended = GNUNET_NO; - GNUNET_CONTAINER_DLL_remove (tc_head, - tc_tail, - tc); - MHD_resume_connection (tc->connection); - TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ -} - - -MHD_RESULT -TMH_private_get_tips_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - struct TipContext *tc = hc->ctx; - struct TALER_Amount total_authorized; - struct TALER_Amount total_picked_up; - char *reason; - struct GNUNET_TIME_Timestamp expiration; - struct TALER_ReservePublicKeyP reserve_pub; - unsigned int pickups_length = 0; - struct TALER_MERCHANTDB_PickupDetails *pickups = NULL; - enum GNUNET_DB_QueryStatus qs; - json_t *pickups_json = NULL; - - (void) rh; - if (NULL == tc) - { - tc = GNUNET_new (struct TipContext); - hc->ctx = tc; - hc->cc = &tip_context_cleanup; - GNUNET_CONTAINER_DLL_insert (tc_head, - tc_tail, - tc); - tc->connection = connection; - tc->hc = hc; - GNUNET_assert (NULL != hc->infix); - if (GNUNET_OK != - GNUNET_CRYPTO_hash_from_string (hc->infix, - &tc->tip_id.hash)) - { - /* tip_id has wrong encoding */ - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - hc->infix); - } - { - const char *pstr; - - pstr = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "pickups"); - tc->fpu = (NULL != pstr) - ? 0 == strcasecmp (pstr, "yes") - : false; - } - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (TMH_currency, - &tc->min_amount)); - { - const char *min_amount; - - min_amount = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "min_amount"); - if (NULL != min_amount) - { - if (GNUNET_OK != - TALER_string_to_amount (min_amount, - &tc->min_amount)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "min_amount"); - } - if (0 != - strcasecmp (tc->min_amount.currency, - TMH_currency)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_CURRENCY_MISMATCH, - TMH_currency); - } - } - } - TALER_MHD_parse_request_timeout (connection, - &tc->timeout); - if (! GNUNET_TIME_absolute_is_future (tc->timeout)) - { - struct TMH_TipPickupEventP tip_eh = { - .header.size = htons (sizeof (tip_eh)), - .header.type = htons (TALER_DBEVENT_MERCHANT_TIP_PICKUP), - .tip_id = tc->tip_id - }; - - GNUNET_CRYPTO_hash (hc->instance->settings.id, - strlen (hc->instance->settings.id), - &tip_eh.h_instance); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Subscribing to payment triggers for %p\n", - tc); - tc->eh = TMH_db->event_listen ( - TMH_db->cls, - &tip_eh.header, - GNUNET_TIME_absolute_get_remaining (tc->timeout), - &resume_by_event, - tc); - } - } - - GNUNET_assert (GNUNET_YES != tc->suspended); - TMH_db->preflight (TMH_db->cls); - qs = TMH_db->lookup_tip_details (TMH_db->cls, - hc->instance->settings.id, - &tc->tip_id, - tc->fpu, - &total_authorized, - &total_picked_up, - &reason, - &expiration, - &reserve_pub, - &pickups_length, - &pickups); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - unsigned int response_code; - enum TALER_ErrorCode ec; - - switch (qs) - { - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - ec = TALER_EC_MERCHANT_GENERIC_TIP_ID_UNKNOWN; - response_code = MHD_HTTP_NOT_FOUND; - break; - case GNUNET_DB_STATUS_SOFT_ERROR: - ec = TALER_EC_GENERIC_DB_SOFT_FAILURE; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - case GNUNET_DB_STATUS_HARD_ERROR: - ec = TALER_EC_GENERIC_DB_COMMIT_FAILED; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - default: - GNUNET_break (0); - ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - } - return TALER_MHD_reply_with_error (connection, - response_code, - ec, - NULL); - } - /* do not allow timeout above tip expiration */ - tc->timeout = GNUNET_TIME_absolute_min (tc->timeout, - expiration.abs_time); - if ( (NULL != tc->eh) && - (GNUNET_TIME_absolute_is_future (tc->timeout)) && - (1 == TALER_amount_cmp (&tc->min_amount, - &total_picked_up)) ) - { - MHD_suspend_connection (connection); - tc->suspended = GNUNET_YES; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Suspending TIP request handling as pickup is below threshold requested by client\n"); - GNUNET_array_grow (pickups, - pickups_length, - 0); - GNUNET_free (reason); - return MHD_YES; - } - if (tc->fpu) - { - pickups_json = json_array (); - GNUNET_assert (NULL != pickups_json); - for (unsigned int i = 0; i<pickups_length; i++) - { - GNUNET_assert (0 == - json_array_append_new ( - pickups_json, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ("pickup_id", - &pickups[i].pickup_id), - GNUNET_JSON_pack_uint64 ("num_planchets", - pickups[i].num_planchets), - TALER_JSON_pack_amount ("requested_amount", - &pickups[i].requested_amount)))); - } - } - GNUNET_array_grow (pickups, - pickups_length, - 0); - { - MHD_RESULT ret; - - ret = TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - TALER_JSON_pack_amount ("total_authorized", - &total_authorized), - TALER_JSON_pack_amount ("total_picked_up", - &total_picked_up), - GNUNET_JSON_pack_string ("reason", - reason), - GNUNET_JSON_pack_timestamp ("expiration", - expiration), - GNUNET_JSON_pack_data_auto ("reserve_pub", - &reserve_pub), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_array_steal ("pickups", - pickups_json))); - GNUNET_free (reason); - return ret; - } -} diff --git a/src/backend/taler-merchant-httpd_private-get-tips-ID.h b/src/backend/taler-merchant-httpd_private-get-tips-ID.h @@ -1,48 +0,0 @@ -/* - This file is part of TALER - (C) 2017, 2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-merchant-httpd_get-tips-ID.h - * @brief headers for GET /tips/ID handler - * @author Christian Grothoff - */ -#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_TIPS_ID_H -#define TALER_MERCHANT_HTTPD_PRIVATE_GET_TIPS_ID_H -#include <microhttpd.h> -#include "taler-merchant-httpd.h" - - -/** - * Force wake-up of all suspended tipping long-pollers. - */ -void -TMH_force_tip_resume (void); - - -/** - * Manages a GET /tips/$ID call, returning the status of the tip. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_get_tips_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - - -#endif diff --git a/src/backend/taler-merchant-httpd_private-get-tips.c b/src/backend/taler-merchant-httpd_private-get-tips.c @@ -1,157 +0,0 @@ -/* - This file is part of TALER - (C) 2020-2021 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-merchant-httpd_private-get-tips.c - * @brief implementation of a GET /private/tips handler - * @author Jonathan Buchanan - */ -#include "platform.h" -#include "taler-merchant-httpd_private-get-tips.h" -#include <taler/taler_json_lib.h> - -/** - * Add tip details to our JSON array. - * - * @param[in,out] cls a `json_t *` JSON array to build - * @param row_id row number of the tip - * @param tip_id ID of the tip - * @param amount the amount of the tip - */ -static void -add_tip (void *cls, - uint64_t row_id, - struct TALER_TipIdentifierP tip_id, - struct TALER_Amount amount) -{ - json_t *pa = cls; - - GNUNET_assert (0 == - json_array_append_new ( - pa, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_uint64 ("row_id", - row_id), - GNUNET_JSON_pack_data_auto ("tip_id", - &tip_id), - TALER_JSON_pack_amount ("tip_amount", - &amount)))); -} - - -MHD_RESULT -TMH_private_get_tips (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - json_t *pa; - enum GNUNET_DB_QueryStatus qs; - enum TALER_EXCHANGE_YesNoAll expired; - uint64_t offset; - int64_t limit; - - (void) rh; - if (! (TALER_arg_to_yna (connection, - "expired", - TALER_EXCHANGE_YNA_NO, - &expired)) ) - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "expired"); - { - const char *limit_str; - - limit_str = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "limit"); - if (NULL == limit_str) - { - limit = -20; - } - else - { - char dummy[2]; - long long ll; - - if (1 != - sscanf (limit_str, - "%lld%1s", - &ll, - dummy)) - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "limit"); - limit = (uint64_t) ll; - } - } - { - const char *offset_str; - - offset_str = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "offset"); - if (NULL == offset_str) - { - if (limit > 0) - offset = 0; - else - offset = INT64_MAX; - } - else - { - char dummy[2]; - unsigned long long ull; - - if (1 != - sscanf (offset_str, - "%llu%1s", - &ull, - dummy)) - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "offset"); - offset = (uint64_t) ull; - } - } - - pa = json_array (); - GNUNET_assert (NULL != pa); - qs = TMH_db->lookup_tips (TMH_db->cls, - hc->instance->settings.id, - expired, - limit, - offset, - &add_tip, - pa); - - if (0 > qs) - { - GNUNET_break (0); - json_decref (pa); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "tips"); - } - - return TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_array_steal ("tips", - pa)); -} diff --git a/src/backend/taler-merchant-httpd_private-get-tips.h b/src/backend/taler-merchant-httpd_private-get-tips.h @@ -1,41 +0,0 @@ -/* - This file is part of TALER - (C) 2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-merchant-httpd_private-get-tips.h - * @brief headers for GET /private/tips handler - * @author Jonathan Buchanan - */ -#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_TIPS_H -#define TALER_MERCHANT_HTTPD_PRIVATE_GET_TIPS_H -#include <microhttpd.h> -#include "taler-merchant-httpd.h" - - -/** - * Manages a GET /private/tips call. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_get_tips (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - - -#endif diff --git a/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-reward.c b/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-reward.c @@ -0,0 +1,197 @@ +/* + This file is part of TALER + (C) 2014-2020 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 published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-post-reserves-ID-authorize-reward.c + * @brief implement API for authorizing rewards to be paid to visitors + * @author Christian Grothoff + */ +#include "platform.h" +#include <jansson.h> +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler-merchant-httpd.h" +#include "taler-merchant-httpd_mhd.h" +#include "taler-merchant-httpd_get-rewards-ID.h" +#include "taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h" + + +/** + * Handle a "reward-authorize" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @param reserve_pub reserve to use, or NULL for "any" + * @return MHD result code + */ +static MHD_RESULT +authorize_reward (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc, + const struct TALER_ReservePublicKeyP *reserve_pub) +{ + enum TALER_ErrorCode ec; + struct GNUNET_TIME_Timestamp expiration; + struct TALER_RewardIdentifierP reward_id; + const char *justification; + const char *next_url; + struct TALER_Amount amount; + { + struct GNUNET_JSON_Specification spec[] = { + TALER_JSON_spec_amount ("amount", + TMH_currency, + &amount), + GNUNET_JSON_spec_string ("justification", + &justification), + GNUNET_JSON_spec_string ("next_url", + &next_url), + GNUNET_JSON_spec_end () + }; + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (connection, + hc->request_body, + spec); + if (GNUNET_YES != res) + { + GNUNET_break_op (0); + return (GNUNET_NO == res) + ? MHD_YES + : MHD_NO; + } + } + TMH_db->preflight (TMH_db->cls); + ec = TMH_db->authorize_reward (TMH_db->cls, + hc->instance->settings.id, + reserve_pub, + &amount, + justification, + next_url, + &reward_id, + &expiration); + /* handle errors */ + if (TALER_EC_NONE != ec) + { + unsigned int http_status; + + switch (ec) + { + case TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_INSUFFICIENT_FUNDS: + http_status = MHD_HTTP_PRECONDITION_FAILED; + break; + case TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_EXPIRED: + http_status = MHD_HTTP_GONE; + break; + case TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_UNKNOWN: + http_status = MHD_HTTP_SERVICE_UNAVAILABLE; + break; + case TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_NOT_FOUND: + http_status = MHD_HTTP_NOT_FOUND; + break; + default: + http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; + break; + } + + return TALER_MHD_reply_with_error (connection, + http_status, + ec, + NULL); + } + + /* generate success response */ + { + char *taler_reward_uri; + char *reward_status_url; + struct GNUNET_CRYPTO_HashAsciiEncoded hash_enc; + MHD_RESULT res; + + GNUNET_CRYPTO_hash_to_enc (&reward_id.hash, + &hash_enc); + taler_reward_uri = TMH_make_taler_reward_uri (connection, + &reward_id, + hc->instance->settings.id); + if (NULL == taler_reward_uri) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MISSING, + "host"); + } + reward_status_url = TMH_make_reward_status_url (connection, + &reward_id, + hc->instance->settings.id); + GNUNET_assert (NULL != reward_status_url); + GNUNET_assert (! GNUNET_TIME_absolute_is_zero (expiration.abs_time)); + res = TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_string ("reward_id", + (const char *) hash_enc.encoding), + GNUNET_JSON_pack_string ("taler_reward_uri", + taler_reward_uri), + GNUNET_JSON_pack_string ("reward_status_url", + reward_status_url), + GNUNET_JSON_pack_timestamp ("reward_expiration", + expiration)); + GNUNET_free (taler_reward_uri); + GNUNET_free (reward_status_url); + return res; + } +} + + +MHD_RESULT +TMH_private_post_reserves_ID_authorize_reward (const struct + TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TALER_ReservePublicKeyP reserve_pub; + + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (hc->infix, + strlen (hc->infix), + &reserve_pub, + sizeof (reserve_pub))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_RESERVE_PUB_MALFORMED, + hc->infix); + } + return authorize_reward (rh, + connection, + hc, + &reserve_pub); +} + + +MHD_RESULT +TMH_private_post_rewards (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + return authorize_reward (rh, + connection, + hc, + NULL); +} + + +/* end of taler-merchant-httpd_private-post-reserves-ID-authorize-reward.c */ diff --git a/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h b/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h @@ -0,0 +1,58 @@ +/* + This file is part of TALER + (C) 2017, 2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h + * @brief headers for /reserves/ID/reward-authorize + * @author Christian Grothoff + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_POST_RESERVES_ID_AUTHORIZE_REWARD_H +#define TALER_MERCHANT_HTTPD_PRIVATE_POST_RESERVES_ID_AUTHORIZE_REWARD_H +#include <microhttpd.h> +#include "taler-merchant-httpd.h" + + +/** + * Handle a "/reserves/$ID/reward-authorize" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_post_reserves_ID_authorize_reward (const struct + TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + + +/** + * Handle a POST "/rewards" request. + * Here the client does not specify the reserve public key, so we + * are free to pick "any" available reserve. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_post_rewards (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + + +#endif diff --git a/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c b/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c @@ -1,196 +0,0 @@ -/* - This file is part of TALER - (C) 2014-2020 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 published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c - * @brief implement API for authorizing tips to be paid to visitors - * @author Christian Grothoff - */ -#include "platform.h" -#include <jansson.h> -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include "taler-merchant-httpd.h" -#include "taler-merchant-httpd_mhd.h" -#include "taler-merchant-httpd_get-tips-ID.h" -#include "taler-merchant-httpd_private-post-reserves-ID-authorize-tip.h" - - -/** - * Handle a "tip-authorize" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @param reserve_pub reserve to use, or NULL for "any" - * @return MHD result code - */ -static MHD_RESULT -authorize_tip (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc, - const struct TALER_ReservePublicKeyP *reserve_pub) -{ - enum TALER_ErrorCode ec; - struct GNUNET_TIME_Timestamp expiration; - struct TALER_TipIdentifierP tip_id; - const char *justification; - const char *next_url; - struct TALER_Amount amount; - { - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount ("amount", - TMH_currency, - &amount), - GNUNET_JSON_spec_string ("justification", - &justification), - GNUNET_JSON_spec_string ("next_url", - &next_url), - GNUNET_JSON_spec_end () - }; - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (connection, - hc->request_body, - spec); - if (GNUNET_YES != res) - { - GNUNET_break_op (0); - return (GNUNET_NO == res) - ? MHD_YES - : MHD_NO; - } - } - TMH_db->preflight (TMH_db->cls); - ec = TMH_db->authorize_tip (TMH_db->cls, - hc->instance->settings.id, - reserve_pub, - &amount, - justification, - next_url, - &tip_id, - &expiration); - /* handle errors */ - if (TALER_EC_NONE != ec) - { - unsigned int http_status; - - switch (ec) - { - case TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_INSUFFICIENT_FUNDS: - http_status = MHD_HTTP_PRECONDITION_FAILED; - break; - case TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_EXPIRED: - http_status = MHD_HTTP_GONE; - break; - case TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_UNKNOWN: - http_status = MHD_HTTP_SERVICE_UNAVAILABLE; - break; - case TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_NOT_FOUND: - http_status = MHD_HTTP_NOT_FOUND; - break; - default: - http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; - break; - } - - return TALER_MHD_reply_with_error (connection, - http_status, - ec, - NULL); - } - - /* generate success response */ - { - char *taler_tip_uri; - char *tip_status_url; - struct GNUNET_CRYPTO_HashAsciiEncoded hash_enc; - MHD_RESULT res; - - GNUNET_CRYPTO_hash_to_enc (&tip_id.hash, - &hash_enc); - taler_tip_uri = TMH_make_taler_tip_uri (connection, - &tip_id, - hc->instance->settings.id); - if (NULL == taler_tip_uri) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MISSING, - "host"); - } - tip_status_url = TMH_make_tip_status_url (connection, - &tip_id, - hc->instance->settings.id); - GNUNET_assert (NULL != tip_status_url); - GNUNET_assert (! GNUNET_TIME_absolute_is_zero (expiration.abs_time)); - res = TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_string ("tip_id", - (const char *) hash_enc.encoding), - GNUNET_JSON_pack_string ("taler_tip_uri", - taler_tip_uri), - GNUNET_JSON_pack_string ("tip_status_url", - tip_status_url), - GNUNET_JSON_pack_timestamp ("tip_expiration", - expiration)); - GNUNET_free (taler_tip_uri); - GNUNET_free (tip_status_url); - return res; - } -} - - -MHD_RESULT -TMH_private_post_reserves_ID_authorize_tip (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - struct TALER_ReservePublicKeyP reserve_pub; - - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (hc->infix, - strlen (hc->infix), - &reserve_pub, - sizeof (reserve_pub))) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_RESERVE_PUB_MALFORMED, - hc->infix); - } - return authorize_tip (rh, - connection, - hc, - &reserve_pub); -} - - -MHD_RESULT -TMH_private_post_tips (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - return authorize_tip (rh, - connection, - hc, - NULL); -} - - -/* end of taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c */ diff --git a/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.h b/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.h @@ -1,57 +0,0 @@ -/* - This file is part of TALER - (C) 2017, 2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-merchant-httpd_private-post-reserves-ID-authorize-tip.h - * @brief headers for /reserves/ID/tip-authorize - * @author Christian Grothoff - */ -#ifndef TALER_MERCHANT_HTTPD_PRIVATE_POST_RESERVES_ID_AUTHORIZE_TIP_H -#define TALER_MERCHANT_HTTPD_PRIVATE_POST_RESERVES_ID_AUTHORIZE_TIP_H -#include <microhttpd.h> -#include "taler-merchant-httpd.h" - - -/** - * Handle a "/reserves/$ID/tip-authorize" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_post_reserves_ID_authorize_tip (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - - -/** - * Handle a POST "/tips" request. - * Here the client does not specify the reserve public key, so we - * are free to pick "any" available reserve. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_post_tips (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc); - - -#endif diff --git a/src/backend/taler-merchant-httpd_private-post-reserves.c b/src/backend/taler-merchant-httpd_private-post-reserves.c @@ -271,9 +271,9 @@ handle_exchange (void *cls, resume_request (rc); return; } - if (! keys->tipping_allowed) + if (! keys->rewards_allowed) { - rc->ec = TALER_EC_MERCHANT_PRIVATE_POST_RESERVES_TIPPING_NOT_ALLOWED; + rc->ec = TALER_EC_MERCHANT_PRIVATE_POST_RESERVES_REWARDS_NOT_ALLOWED; rc->http_status = MHD_HTTP_CONFLICT; resume_request (rc); return; diff --git a/src/backenddb/pg_lookup_reserves.c b/src/backenddb/pg_lookup_reserves.c @@ -102,9 +102,9 @@ lookup_reserves_cb (void *cls, &merchant_initial_balance), TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_initial_balance", &exchange_initial_balance), - TALER_PQ_RESULT_SPEC_AMOUNT ("tips_committed", + TALER_PQ_RESULT_SPEC_AMOUNT ("rewards_committed", &committed_amount), - TALER_PQ_RESULT_SPEC_AMOUNT ("tips_picked_up", + TALER_PQ_RESULT_SPEC_AMOUNT ("rewards_picked_up", &pickup_amount), GNUNET_PQ_result_spec_auto_from_type ("active", &active), @@ -198,13 +198,13 @@ TMH_PG_lookup_reserves (void *cls, ",merchant_initial_balance_frac" ",exchange_initial_balance_val" ",exchange_initial_balance_frac" - ",tips_committed_val" - ",tips_committed_frac" - ",tips_picked_up_val" - ",tips_picked_up_frac" + ",rewards_committed_val" + ",rewards_committed_frac" + ",rewards_picked_up_val" + ",rewards_picked_up_frac" ",reserve_priv IS NOT NULL AS active" - " FROM merchant_tip_reserves" - " FULL OUTER JOIN merchant_tip_reserve_keys USING (reserve_serial)" + " FROM merchant_reward_reserves" + " FULL OUTER JOIN merchant_reward_reserve_keys USING (reserve_serial)" " WHERE creation_time > $2" " AND merchant_serial =" " (SELECT merchant_serial" diff --git a/src/backenddb/pg_select_open_transfers.c b/src/backenddb/pg_select_open_transfers.c @@ -55,7 +55,7 @@ struct SelectOpenTransfersContext /** * Function to be called with the results of a SELECT statement - * that has returned @a num_results results about tips. + * that has returned @a num_results results about rewards. * * @param[in,out] cls of type `struct SelectOpenTransfersContext *` * @param result the postgres result diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c @@ -152,7 +152,7 @@ postgres_create_tables (void *cls) * @param es specification of the event to listen for * @param timeout how long to wait for the event * @param cb function to call when the event happens, possibly - * multiple times (until cancel is invoked) + * mulrewardle times (until cancel is invoked) * @param cb_cls closure for @a cb * @return handle useful to cancel the listener */ @@ -1053,7 +1053,7 @@ process_deposits_for_refund_cb (void *cls, * Function called when some backoffice staff decides to award or * increase the refund on an existing contract. This function * MUST be called from within a transaction scope setup by the - * caller as it executes multiple SQL statements. + * caller as it executes mulrewardle SQL statements. * * @param cls closure * @param instance_id instance identifier @@ -2295,10 +2295,10 @@ postgres_store_wire_fee_by_exchange ( /** - * Add @a credit to a reserve to be used for tipping. Note that + * Add @a credit to a reserve to be used for rewardping. Note that * this function does not actually perform any wire transfers to * credit the reserve, it merely tells the merchant backend that - * a reserve now exists. This has to happen before tips can be + * a reserve now exists. This has to happen before rewards can be * authorized. * * @param cls closure, typically a connection to the db @@ -2396,7 +2396,7 @@ RETRY: /** * Confirms @a credit as the amount the exchange claims to have received and - * thus really 'activates' the reserve. This has to happen before tips can + * thus really 'activates' the reserve. This has to happen before rewards can * be authorized. * * @param cls closure, typically a connection to the db @@ -2545,9 +2545,9 @@ postgres_lookup_pending_reserves (void *cls, /** - * Closure for #lookup_reserve_tips_cb(). + * Closure for #lookup_reserve_rewards_cb(). */ -struct LookupTipsContext +struct LookupRewardsContext { /** * Postgres context. @@ -2555,14 +2555,14 @@ struct LookupTipsContext struct PostgresClosure *pg; /** - * Array with information about tips generated from this reserve. + * Array with information about rewards generated from this reserve. */ - struct TALER_MERCHANTDB_TipDetails *tips; + struct TALER_MERCHANTDB_RewardDetails *rewards; /** - * Length of the @e tips array. + * Length of the @e rewards array. */ - unsigned int tips_length; + unsigned int rewards_length; /** * Set in case of errors. @@ -2575,29 +2575,29 @@ struct LookupTipsContext * Function to be called with the results of a SELECT statement * that has returned @a num_results results about accounts. * - * @param[in,out] cls of type `struct LookupTipsContext *` + * @param[in,out] cls of type `struct LookupRewardsContext *` * @param result the postgres result * @param num_results the number of results in @a result */ static void -lookup_reserve_tips_cb (void *cls, +lookup_reserve_rewards_cb (void *cls, PGresult *result, unsigned int num_results) { - struct LookupTipsContext *ltc = cls; + struct LookupRewardsContext *ltc = cls; struct PostgresClosure *pg = ltc->pg; - GNUNET_array_grow (ltc->tips, - ltc->tips_length, + GNUNET_array_grow (ltc->rewards, + ltc->rewards_length, num_results); for (unsigned int i = 0; i < num_results; i++) { - struct TALER_MERCHANTDB_TipDetails *td = &ltc->tips[i]; + struct TALER_MERCHANTDB_RewardDetails *td = &ltc->rewards[i]; struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_string ("justification", &td->reason), - GNUNET_PQ_result_spec_auto_from_type ("tip_id", - &td->tip_id), + GNUNET_PQ_result_spec_auto_from_type ("reward_id", + &td->reward_id), TALER_PQ_RESULT_SPEC_AMOUNT ("amount", &td->total_amount), GNUNET_PQ_result_spec_end @@ -2622,7 +2622,7 @@ lookup_reserve_tips_cb (void *cls, * @param cls closure * @param instance_id instance to lookup payments for * @param reserve_pub public key of the reserve to inspect - * @param fetch_tips if true, also return information about tips + * @param fetch_rewards if true, also return information about rewards * @param cb function to call with reserve summary data * @param cb_cls closure for @a cb * @return transaction status @@ -2631,12 +2631,12 @@ static enum GNUNET_DB_QueryStatus postgres_lookup_reserve (void *cls, const char *instance_id, const struct TALER_ReservePublicKeyP *reserve_pub, - bool fetch_tips, + bool fetch_rewards, TALER_MERCHANTDB_ReserveDetailsCallback cb, void *cb_cls) { struct PostgresClosure *pg = cls; - struct LookupTipsContext ltc = { + struct LookupRewardsContext ltc = { .pg = pg, .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT }; @@ -2663,9 +2663,9 @@ postgres_lookup_reserve (void *cls, &merchant_initial_balance), TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_initial_balance", &exchange_initial_balance), - TALER_PQ_RESULT_SPEC_AMOUNT ("tips_picked_up", + TALER_PQ_RESULT_SPEC_AMOUNT ("rewards_picked_up", &pickup_amount), - TALER_PQ_RESULT_SPEC_AMOUNT ("tips_committed", + TALER_PQ_RESULT_SPEC_AMOUNT ("rewards_committed", &committed_amount), GNUNET_PQ_result_spec_auto_from_type ("master_pub", &master_pub), @@ -2686,7 +2686,7 @@ postgres_lookup_reserve (void *cls, rs); if (qs < 0) return qs; - if (! fetch_tips) + if (! fetch_rewards) { cb (cb_cls, creation_time, @@ -2705,9 +2705,9 @@ postgres_lookup_reserve (void *cls, } qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "lookup_reserve_tips", + "lookup_reserve_rewards", params, - &lookup_reserve_tips_cb, + &lookup_reserve_rewards_cb, &ltc); if (qs < 0) return qs; @@ -2723,13 +2723,13 @@ postgres_lookup_reserve (void *cls, active, &master_pub, exchange_url, - ltc.tips_length, - ltc.tips); + ltc.rewards_length, + ltc.rewards); } - for (unsigned int i = 0; i<ltc.tips_length; i++) - GNUNET_free (ltc.tips[i].reason); - GNUNET_array_grow (ltc.tips, - ltc.tips_length, + for (unsigned int i = 0; i<ltc.rewards_length; i++) + GNUNET_free (ltc.rewards[i].reason); + GNUNET_array_grow (ltc.rewards, + ltc.rewards_length, 0); GNUNET_PQ_cleanup_result (rs); return ltc.qs; @@ -2765,7 +2765,7 @@ postgres_delete_reserve (void *cls, /** - * Purge all of the information about a reserve, including tips. + * Purge all of the information about a reserve, including rewards. * * @param cls closure, typically a connection to the db * @param instance_id which instance is the reserve tied to @@ -2793,9 +2793,9 @@ postgres_purge_reserve (void *cls, /** - * Closure for #lookup_reserve_for_tip_cb(). + * Closure for #lookup_reserve_for_reward_cb(). */ -struct LookupReserveForTipContext +struct LookupReserveForRewardContext { /** * Postgres context. @@ -2832,7 +2832,7 @@ struct LookupReserveForTipContext /** * How long must a reserve be at least still valid before we use - * it for a tip? + * it for a reward? */ #define MIN_EXPIRATION GNUNET_TIME_UNIT_HOURS @@ -2841,16 +2841,16 @@ struct LookupReserveForTipContext * Function to be called with the results of a SELECT statement * that has returned @a num_results results about accounts. * - * @param[in,out] cls of type `struct LookupReserveForTipContext *` + * @param[in,out] cls of type `struct LookupReserveForRewardContext *` * @param result the postgres result * @param num_results the number of results in @a result */ static void -lookup_reserve_for_tip_cb (void *cls, +lookup_reserve_for_reward_cb (void *cls, PGresult *result, unsigned int num_results) { - struct LookupReserveForTipContext *lac = cls; + struct LookupReserveForRewardContext *lac = cls; struct PostgresClosure *pg = lac->pg; for (unsigned int i = 0; i < num_results; i++) @@ -2865,7 +2865,7 @@ lookup_reserve_for_tip_cb (void *cls, &reserve_pub), TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_initial_balance", &initial_balance), - TALER_PQ_RESULT_SPEC_AMOUNT ("tips_committed", + TALER_PQ_RESULT_SPEC_AMOUNT ("rewards_committed", &committed_amount), GNUNET_PQ_result_spec_timestamp ("expiration", &expiration), @@ -2896,7 +2896,7 @@ lookup_reserve_for_tip_cb (void *cls, /* insufficient balance */ if (lac->ok) continue; /* got another reserve */ - lac->ec = TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_INSUFFICIENT_FUNDS; + lac->ec = TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_INSUFFICIENT_FUNDS; continue; } if ( (! GNUNET_TIME_absolute_is_never (lac->expiration.abs_time)) && @@ -2911,7 +2911,7 @@ lookup_reserve_for_tip_cb (void *cls, /* reserve expired */ if (lac->ok) continue; /* got another reserve */ - lac->ec = TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_EXPIRED; + lac->ec = TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_EXPIRED; continue; } lac->ok = true; @@ -2923,22 +2923,22 @@ lookup_reserve_for_tip_cb (void *cls, /** - * Authorize a tip over @a amount from reserve @a reserve_pub. Remember - * the authorization under @a tip_id for later, together with the + * Authorize a reward over @a amount from reserve @a reserve_pub. Remember + * the authorization under @a reward_id for later, together with the * @a justification. * * @param cls closure, typically a connection to the db - * @param instance_id which instance should generate the tip + * @param instance_id which instance should generate the reward * @param reserve_pub which reserve is debited, NULL to pick one in the DB - * @param amount how high is the tip (with fees) - * @param justification why was the tip approved - * @param next_url where to send the URL post tip pickup - * @param[out] tip_id set to the unique ID for the tip - * @param[out] expiration set to when the tip expires + * @param amount how high is the reward (with fees) + * @param justification why was the reward approved + * @param next_url where to send the URL post reward pickup + * @param[out] reward_id set to the unique ID for the reward + * @param[out] expiration set to when the reward expires * @return transaction status, - * #TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_EXPIRED if the reserve is known but has expired - * #TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_NOT_FOUND if the reserve is not known - * #TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_INSUFFICIENT_FUNDS if the reserve has insufficient funds left + * #TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_EXPIRED if the reserve is known but has expired + * #TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_NOT_FOUND if the reserve is not known + * #TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_INSUFFICIENT_FUNDS if the reserve has insufficient funds left * #TALER_EC_GENERIC_DB_START_FAILED on hard DB errors * #TALER_EC_GENERIC_DB_FETCH_FAILED on hard DB errors * #TALER_EC_GENERIC_DB_STORE_FAILED on hard DB errors @@ -2947,22 +2947,22 @@ lookup_reserve_for_tip_cb (void *cls, * #TALER_EC_NONE upon success */ static enum TALER_ErrorCode -postgres_authorize_tip (void *cls, +postgres_authorize_reward (void *cls, const char *instance_id, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_Amount *amount, const char *justification, const char *next_url, - struct TALER_TipIdentifierP *tip_id, + struct TALER_RewardIdentifierP *reward_id, struct GNUNET_TIME_Timestamp *expiration) { struct PostgresClosure *pg = cls; unsigned int retries = 0; enum GNUNET_DB_QueryStatus qs; - struct TALER_Amount tips_committed; + struct TALER_Amount rewards_committed; struct TALER_Amount exchange_initial_balance; const struct TALER_ReservePublicKeyP *reserve_pubp; - struct LookupReserveForTipContext lac = { + struct LookupReserveForRewardContext lac = { .pg = pg, .required_amount = *amount, .expiration = GNUNET_TIME_UNIT_FOREVER_TS @@ -2979,7 +2979,7 @@ RETRY: } if (GNUNET_OK != postgres_start (pg, - "authorize tip")) + "authorize reward")) { GNUNET_break (0); return TALER_EC_GENERIC_DB_START_FAILED; @@ -2992,9 +2992,9 @@ RETRY: }; qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "lookup_reserve_for_tip", + "lookup_reserve_for_reward", params, - &lookup_reserve_for_tip_cb, + &lookup_reserve_for_reward_cb, &lac); switch (qs) { @@ -3007,7 +3007,7 @@ RETRY: return TALER_EC_GENERIC_DB_FETCH_FAILED; case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: postgres_rollback (pg); - return TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_NOT_FOUND; + return TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_NOT_FOUND; case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: default: break; @@ -3015,7 +3015,7 @@ RETRY: if (TALER_EC_NONE != lac.ec) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Enabling tip reserved failed with status %d\n", + "Enabling reward reserved failed with status %d\n", lac.ec); postgres_rollback (pg); return lac.ec; @@ -3033,8 +3033,8 @@ RETRY: struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_timestamp ("expiration", expiration), - TALER_PQ_RESULT_SPEC_AMOUNT ("tips_committed", - &tips_committed), + TALER_PQ_RESULT_SPEC_AMOUNT ("rewards_committed", + &rewards_committed), TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_initial_balance", &exchange_initial_balance), GNUNET_PQ_result_spec_end @@ -3058,7 +3058,7 @@ RETRY: if (0 == qs) { postgres_rollback (pg); - return TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_NOT_FOUND; + return TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_NOT_FOUND; } } { @@ -3067,7 +3067,7 @@ RETRY: if (0 > TALER_amount_subtract (&remaining, &exchange_initial_balance, - &tips_committed)) + &rewards_committed)) { GNUNET_break (0); postgres_rollback (pg); @@ -3078,23 +3078,23 @@ RETRY: amount)) { postgres_rollback (pg); - return TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_INSUFFICIENT_FUNDS; + return TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_INSUFFICIENT_FUNDS; } } GNUNET_assert (0 <= - TALER_amount_add (&tips_committed, - &tips_committed, + TALER_amount_add (&rewards_committed, + &rewards_committed, amount)); { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (instance_id), GNUNET_PQ_query_param_auto_from_type (reserve_pubp), - TALER_PQ_query_param_amount (&tips_committed), + TALER_PQ_query_param_amount (&rewards_committed), GNUNET_PQ_query_param_end }; qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "update_reserve_tips_committed", + "update_reserve_rewards_committed", params); if (GNUNET_DB_STATUS_SOFT_ERROR == qs) { @@ -3109,13 +3109,13 @@ RETRY: } } GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, - tip_id, - sizeof (*tip_id)); + reward_id, + sizeof (*reward_id)); { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (instance_id), GNUNET_PQ_query_param_auto_from_type (reserve_pubp), - GNUNET_PQ_query_param_auto_from_type (tip_id), + GNUNET_PQ_query_param_auto_from_type (reward_id), GNUNET_PQ_query_param_string (justification), GNUNET_PQ_query_param_string (next_url), GNUNET_PQ_query_param_timestamp (expiration), @@ -3124,7 +3124,7 @@ RETRY: }; qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "insert_tip", + "insert_reward", params); if (GNUNET_DB_STATUS_SOFT_ERROR == qs) { @@ -3221,11 +3221,11 @@ lookup_signatures_cb (void *cls, * Lookup pickup details for pickup @a pickup_id. * * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup tip details for - * @param tip_id which tip should we lookup details on + * @param instance_id which instance should we lookup reward details for + * @param reward_id which reward should we lookup details on * @param pickup_id which pickup should we lookup details on - * @param[out] exchange_url which exchange is the tip withdrawn from - * @param[out] reserve_priv private key the tip is withdrawn from (set if still available!) + * @param[out] exchange_url which exchange is the reward withdrawn from + * @param[out] reserve_priv private key the reward is withdrawn from (set if still available!) * @param sigs_length length of the @a sigs array * @param[out] sigs set to the (blind) signatures we have for this @a pickup_id, * those that are unavailable are left at NULL @@ -3234,7 +3234,7 @@ lookup_signatures_cb (void *cls, static enum GNUNET_DB_QueryStatus postgres_lookup_pickup (void *cls, const char *instance_id, - const struct TALER_TipIdentifierP *tip_id, + const struct TALER_RewardIdentifierP *reward_id, const struct TALER_PickupIdentifierP *pickup_id, char **exchange_url, struct TALER_ReservePrivateKeyP *reserve_priv, @@ -3247,7 +3247,7 @@ postgres_lookup_pickup (void *cls, { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (tip_id), + GNUNET_PQ_query_param_auto_from_type (reward_id), GNUNET_PQ_query_param_auto_from_type (pickup_id), GNUNET_PQ_query_param_end }; @@ -3289,23 +3289,23 @@ postgres_lookup_pickup (void *cls, /** - * Lookup tip details for tip @a tip_id. + * Lookup reward details for reward @a reward_id. * * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup tip details for - * @param tip_id which tip should we lookup details on - * @param[out] total_authorized amount how high is the tip (with fees) - * @param[out] total_picked_up how much of the tip was so far picked up (with fees) - * @param[out] expiration set to when the tip expires + * @param instance_id which instance should we lookup reward details for + * @param reward_id which reward should we lookup details on + * @param[out] total_authorized amount how high is the reward (with fees) + * @param[out] total_picked_up how much of the reward was so far picked up (with fees) + * @param[out] expiration set to when the reward expires * @param[out] exchange_url set to the exchange URL where the reserve is - * @param[out] next_url set to the URL where the wallet should navigate after getting the tip + * @param[out] next_url set to the URL where the wallet should navigate after getting the reward * @param[out] reserve_priv set to private key of reserve to be debited * @return transaction status */ static enum GNUNET_DB_QueryStatus -postgres_lookup_tip (void *cls, +postgres_lookup_reward (void *cls, const char *instance_id, - const struct TALER_TipIdentifierP *tip_id, + const struct TALER_RewardIdentifierP *reward_id, struct TALER_Amount *total_authorized, struct TALER_Amount *total_picked_up, struct GNUNET_TIME_Timestamp *expiration, @@ -3316,7 +3316,7 @@ postgres_lookup_tip (void *cls, struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (tip_id), + GNUNET_PQ_query_param_auto_from_type (reward_id), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { @@ -3336,16 +3336,16 @@ postgres_lookup_tip (void *cls, }; return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "lookup_tip", + "lookup_reward", params, rs); } /** - * Context used for postgres_lookup_tips(). + * Context used for postgres_lookup_rewards(). */ -struct LookupMerchantTipsContext +struct LookupMerchantRewardsContext { /** * Postgres context. @@ -3355,7 +3355,7 @@ struct LookupMerchantTipsContext /** * Function to call with the results. */ - TALER_MERCHANTDB_TipsCallback cb; + TALER_MERCHANTDB_RewardsCallback cb; /** * Closure for @a cb. @@ -3371,32 +3371,32 @@ struct LookupMerchantTipsContext /** * Function to be called with the results of a SELECT statement - * that has returned @a num_results results about tips. + * that has returned @a num_results results about rewards. * - * @param[in,out] cls of type `struct LookupTipsContext *` + * @param[in,out] cls of type `struct LookupRewardsContext *` * @param result the postgres result * @param num_results the number of results in @a result */ static void -lookup_tips_cb (void *cls, +lookup_rewards_cb (void *cls, PGresult *result, unsigned int num_results) { - struct LookupMerchantTipsContext *plc = cls; + struct LookupMerchantRewardsContext *plc = cls; struct PostgresClosure *pg = plc->pg; for (unsigned int i = 0; i < num_results; i++) { uint64_t row_id; - struct TALER_TipIdentifierP tip_id; - struct TALER_Amount tip_amount; + struct TALER_RewardIdentifierP reward_id; + struct TALER_Amount reward_amount; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint64 ("tip_serial", + GNUNET_PQ_result_spec_uint64 ("reward_serial", &row_id), - GNUNET_PQ_result_spec_auto_from_type ("tip_id", - &tip_id), + GNUNET_PQ_result_spec_auto_from_type ("reward_id", + &reward_id), TALER_PQ_RESULT_SPEC_AMOUNT ("amount", - &tip_amount), + &reward_amount), GNUNET_PQ_result_spec_end }; @@ -3411,37 +3411,37 @@ lookup_tips_cb (void *cls, } plc->cb (plc->cb_cls, row_id, - tip_id, - tip_amount); + reward_id, + reward_amount); GNUNET_PQ_cleanup_result (rs); } } /** - * Lookup tips + * Lookup rewards * * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup tips for - * @param expired should we include expired tips? + * @param instance_id which instance should we lookup rewards for + * @param expired should we include expired rewards? * @param limit maximum number of results to return, positive for * ascending row id, negative for descending * @param offset row id to start returning results from - * @param cb function to call with tip data + * @param cb function to call with reward data * @param cb_cls closure for @a cb * @return transaction status */ static enum GNUNET_DB_QueryStatus -postgres_lookup_tips (void *cls, +postgres_lookup_rewards (void *cls, const char *instance_id, enum TALER_EXCHANGE_YesNoAll expired, int64_t limit, uint64_t offset, - TALER_MERCHANTDB_TipsCallback cb, + TALER_MERCHANTDB_RewardsCallback cb, void *cb_cls) { struct PostgresClosure *pg = cls; - struct LookupMerchantTipsContext plc = { + struct LookupMerchantRewardsContext plc = { .pg = pg, .cb = cb, .cb_cls = cb_cls @@ -3463,13 +3463,13 @@ postgres_lookup_tips (void *cls, bexpired = (TALER_EXCHANGE_YNA_YES == expired); GNUNET_snprintf (stmt, sizeof (stmt), - "lookup_tips_%s%s", + "lookup_rewards_%s%s", (limit > 0) ? "inc" : "dec", (TALER_EXCHANGE_YNA_ALL == expired) ? "" : "_expired"); qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, stmt, params, - &lookup_tips_cb, + &lookup_rewards_cb, &plc); if (0 != plc.qs) return plc.qs; @@ -3480,7 +3480,7 @@ postgres_lookup_tips (void *cls, /** * Closure for #lookup_pickup_details_cb(). */ -struct LookupTipDetailsContext +struct LookupRewardDetailsContext { /** * Length of the @e sigs array @@ -3509,7 +3509,7 @@ struct LookupTipDetailsContext * Function to be called with the results of a SELECT statement * that has returned @a num_results results about pickups. * - * @param[in,out] cls of type `struct LookupTipDetailsContext *` + * @param[in,out] cls of type `struct LookupRewardDetailsContext *` * @param result the postgres result * @param num_results the number of results in @a result */ @@ -3518,7 +3518,7 @@ lookup_pickup_details_cb (void *cls, PGresult *result, unsigned int num_results) { - struct LookupTipDetailsContext *ltdc = cls; + struct LookupRewardDetailsContext *ltdc = cls; struct PostgresClosure *pg = ltdc->pg; *ltdc->pickups_length = num_results; @@ -3557,25 +3557,25 @@ lookup_pickup_details_cb (void *cls, /** - * Lookup tip details for tip @a tip_id. + * Lookup reward details for reward @a reward_id. * * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup tip details for - * @param tip_id which tip should we lookup details on + * @param instance_id which instance should we lookup reward details for + * @param reward_id which reward should we lookup details on * @param fpu should we fetch details about individual pickups - * @param[out] total_authorized amount how high is the tip (with fees) - * @param[out] total_picked_up how much of the tip was so far picked up (with fees) - * @param[out] justification why was the tip approved - * @param[out] expiration set to when the tip expires + * @param[out] total_authorized amount how high is the reward (with fees) + * @param[out] total_picked_up how much of the reward was so far picked up (with fees) + * @param[out] justification why was the reward approved + * @param[out] expiration set to when the reward expires * @param[out] reserve_pub set to which reserve is debited * @param[out] pickups_length set to the length of @e pickups * @param[out] pickups if @a fpu is true, set to details about the pickup operations * @return transaction status, */ static enum GNUNET_DB_QueryStatus -postgres_lookup_tip_details (void *cls, +postgres_lookup_reward_details (void *cls, const char *instance_id, - const struct TALER_TipIdentifierP *tip_id, + const struct TALER_RewardIdentifierP *reward_id, bool fpu, struct TALER_Amount *total_authorized, struct TALER_Amount *total_picked_up, @@ -3586,17 +3586,17 @@ postgres_lookup_tip_details (void *cls, struct TALER_MERCHANTDB_PickupDetails **pickups) { struct PostgresClosure *pg = cls; - uint64_t tip_serial; + uint64_t reward_serial; enum GNUNET_DB_QueryStatus qs; { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (tip_id), + GNUNET_PQ_query_param_auto_from_type (reward_id), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint64 ("tip_serial", - &tip_serial), + GNUNET_PQ_result_spec_uint64 ("reward_serial", + &reward_serial), TALER_PQ_RESULT_SPEC_AMOUNT ("amount", total_authorized), TALER_PQ_RESULT_SPEC_AMOUNT ("picked_up", @@ -3612,7 +3612,7 @@ postgres_lookup_tip_details (void *cls, check_connection (pg); qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "lookup_tip_details", + "lookup_reward_details", params, rs); if (qs <= 0) @@ -3626,11 +3626,11 @@ postgres_lookup_tip_details (void *cls, } { struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_uint64 (&tip_serial), + GNUNET_PQ_query_param_uint64 (&reward_serial), GNUNET_PQ_query_param_end }; - struct LookupTipDetailsContext ltdc = { + struct LookupRewardDetailsContext ltdc = { .pickups_length = pickups_length, .pickups = pickups, .pg = pg, @@ -3650,16 +3650,16 @@ postgres_lookup_tip_details (void *cls, /** - * Insert details about a tip pickup operation. The @a total_picked_up - * UPDATES the total amount under the @a tip_id, while the @a + * Insert details about a reward pickup operation. The @a total_picked_up + * UPDATES the total amount under the @a reward_id, while the @a * total_requested is the amount to be associated with this @a pickup_id. * While there is usually only one pickup event that picks up the entire * amount, our schema allows for wallets to pick up the amount incrementally - * over multiple pick up operations. + * over mulrewardle pick up operations. * * @param cls closure, typically a connection to the db - * @param instance_id which instance gave the tip - * @param tip_id the unique ID for the tip + * @param instance_id which instance gave the reward + * @param reward_id the unique ID for the reward * @param total_picked_up how much was picked up overall at this * point (includes @a total_requested) * @param pickup_id unique ID for the operation @@ -3671,7 +3671,7 @@ postgres_lookup_tip_details (void *cls, static enum GNUNET_DB_QueryStatus postgres_insert_pickup (void *cls, const char *instance_id, - const struct TALER_TipIdentifierP *tip_id, + const struct TALER_RewardIdentifierP *reward_id, const struct TALER_Amount *total_picked_up, const struct TALER_PickupIdentifierP *pickup_id, const struct TALER_Amount *total_requested) @@ -3682,7 +3682,7 @@ postgres_insert_pickup (void *cls, { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (tip_id), + GNUNET_PQ_query_param_auto_from_type (reward_id), GNUNET_PQ_query_param_auto_from_type (pickup_id), TALER_PQ_query_param_amount (total_requested), GNUNET_PQ_query_param_end @@ -3697,13 +3697,13 @@ postgres_insert_pickup (void *cls, { struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (tip_id), + GNUNET_PQ_query_param_auto_from_type (reward_id), TALER_PQ_query_param_amount (total_picked_up), GNUNET_PQ_query_param_end }; qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "update_picked_up_tip", + "update_picked_up_reward", params); if (0 > qs) return qs; @@ -3714,13 +3714,13 @@ postgres_insert_pickup (void *cls, { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (tip_id), + GNUNET_PQ_query_param_auto_from_type (reward_id), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_uint64 ("reserve_serial", &reserve_serial), - TALER_PQ_RESULT_SPEC_AMOUNT ("tips_picked_up", + TALER_PQ_RESULT_SPEC_AMOUNT ("rewards_picked_up", &reserve_picked_up), GNUNET_PQ_result_spec_end @@ -3762,7 +3762,7 @@ postgres_insert_pickup (void *cls, /** * Insert blind signature obtained from the exchange during a - * tip pickup operation. + * reward pickup operation. * * @param cls closure, typically a connection to the db * @param pickup_id unique ID for the operation @@ -5180,7 +5180,7 @@ postgres_connect (void *cls) "($1, $2, $3, $4, $5, $6, $7, $8, $9)"), /* For postgres_insert_reserve() */ GNUNET_PQ_make_prepare ("insert_reserve", - "INSERT INTO merchant_tip_reserves" + "INSERT INTO merchant_reward_reserves" "(reserve_pub" ",merchant_serial" ",creation_time" @@ -5193,7 +5193,7 @@ postgres_connect (void *cls) " WHERE merchant_id=$1"), /* For postgres_activate_reserve() */ GNUNET_PQ_make_prepare ("activate_reserve", - "UPDATE merchant_tip_reserves SET" + "UPDATE merchant_reward_reserves SET" " exchange_initial_balance_val=$3" ",exchange_initial_balance_frac=$4" " WHERE reserve_pub=$2" @@ -5203,14 +5203,14 @@ postgres_connect (void *cls) " WHERE merchant_id=$1)"), /* For postgres_insert_reserve() */ GNUNET_PQ_make_prepare ("insert_reserve_key", - "INSERT INTO merchant_tip_reserve_keys" + "INSERT INTO merchant_reward_reserve_keys" "(reserve_serial" ",reserve_priv" ",exchange_url" ",master_pub" ")" "SELECT reserve_serial, $3, $4, $5" - " FROM merchant_tip_reserves" + " FROM merchant_reward_reserves" " WHERE reserve_pub=$2" " AND merchant_serial=" " (SELECT merchant_serial" @@ -5224,9 +5224,9 @@ postgres_connect (void *cls) ",exchange_url" ",merchant_initial_balance_val" ",merchant_initial_balance_frac" - " FROM merchant_tip_reserves" + " FROM merchant_reward_reserves" " JOIN merchant_instances USING (merchant_serial)" - " JOIN merchant_tip_reserve_keys USING (reserve_serial)" + " JOIN merchant_reward_reserve_keys USING (reserve_serial)" " WHERE exchange_initial_balance_val=0" " AND exchange_initial_balance_frac=0"), /* For postgres_lookup_reserve() */ @@ -5238,31 +5238,31 @@ postgres_connect (void *cls) ",merchant_initial_balance_frac" ",exchange_initial_balance_val" ",exchange_initial_balance_frac" - ",tips_committed_val" - ",tips_committed_frac" - ",tips_picked_up_val" - ",tips_picked_up_frac" + ",rewards_committed_val" + ",rewards_committed_frac" + ",rewards_picked_up_val" + ",rewards_picked_up_frac" ",reserve_priv IS NOT NULL AS active" ",exchange_url" ",master_pub" - " FROM merchant_tip_reserves" - " FULL OUTER JOIN merchant_tip_reserve_keys USING (reserve_serial)" + " FROM merchant_reward_reserves" + " FULL OUTER JOIN merchant_reward_reserve_keys USING (reserve_serial)" " WHERE reserve_pub = $2" " AND merchant_serial =" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)"), /* For postgres_lookup_reserve() */ - GNUNET_PQ_make_prepare ("lookup_reserve_tips", + GNUNET_PQ_make_prepare ("lookup_reserve_rewards", "SELECT" " justification" - ",tip_id" + ",reward_id" ",amount_val" ",amount_frac" - " FROM merchant_tips" + " FROM merchant_rewards" " WHERE reserve_serial =" " (SELECT reserve_serial" - " FROM merchant_tip_reserves" + " FROM merchant_reward_reserves" " WHERE reserve_pub=$2" " AND merchant_serial =" " (SELECT merchant_serial" @@ -5271,10 +5271,10 @@ postgres_connect (void *cls) /* for postgres_delete_reserve() */ GNUNET_PQ_make_prepare ("delete_reserve", "DELETE" - " FROM merchant_tip_reserve_keys" + " FROM merchant_reward_reserve_keys" " WHERE reserve_serial=" " (SELECT reserve_serial" - " FROM merchant_tip_reserves" + " FROM merchant_reward_reserves" " WHERE reserve_pub=$2" " AND merchant_serial=" " (SELECT merchant_serial" @@ -5283,57 +5283,57 @@ postgres_connect (void *cls) /* for postgres_purge_reserve() */ GNUNET_PQ_make_prepare ("purge_reserve", "DELETE" - " FROM merchant_tip_reserves" + " FROM merchant_reward_reserves" " WHERE reserve_pub=$2" " AND merchant_serial=" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)"), - /* For postgres_authorize_tip() */ - GNUNET_PQ_make_prepare ("lookup_reserve_for_tip", + /* For postgres_authorize_reward() */ + GNUNET_PQ_make_prepare ("lookup_reserve_for_reward", "SELECT" " reserve_pub" ",expiration" ",exchange_initial_balance_val" ",exchange_initial_balance_frac" - ",tips_committed_val" - ",tips_committed_frac" - " FROM merchant_tip_reserves" + ",rewards_committed_val" + ",rewards_committed_frac" + " FROM merchant_reward_reserves" " WHERE" " merchant_serial =" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)"), - /* For postgres_authorize_tip() */ + /* For postgres_authorize_reward() */ GNUNET_PQ_make_prepare ("lookup_reserve_status", "SELECT" " expiration" ",exchange_initial_balance_val" ",exchange_initial_balance_frac" - ",tips_committed_val" - ",tips_committed_frac" - " FROM merchant_tip_reserves" + ",rewards_committed_val" + ",rewards_committed_frac" + " FROM merchant_reward_reserves" " WHERE reserve_pub = $2" " AND merchant_serial =" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)"), - /* For postgres_authorize_tip() */ - GNUNET_PQ_make_prepare ("update_reserve_tips_committed", - "UPDATE merchant_tip_reserves SET" - " tips_committed_val=$3" - ",tips_committed_frac=$4" + /* For postgres_authorize_reward() */ + GNUNET_PQ_make_prepare ("update_reserve_rewards_committed", + "UPDATE merchant_reward_reserves SET" + " rewards_committed_val=$3" + ",rewards_committed_frac=$4" " WHERE reserve_pub = $2" " AND merchant_serial =" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)"), - /* For postgres_authorize_tip() */ - GNUNET_PQ_make_prepare ("insert_tip", - "INSERT INTO merchant_tips" + /* For postgres_authorize_reward() */ + GNUNET_PQ_make_prepare ("insert_reward", + "INSERT INTO merchant_rewards" "(reserve_serial" - ",tip_id" + ",reward_id" ",justification" ",next_url" ",expiration" @@ -5342,7 +5342,7 @@ postgres_connect (void *cls) ") " "SELECT" " reserve_serial, $3, $4, $5, $6, $7, $8" - " FROM merchant_tip_reserves" + " FROM merchant_reward_reserves" " WHERE reserve_pub=$2" " AND merchant_serial = " " (SELECT merchant_serial" @@ -5354,12 +5354,12 @@ postgres_connect (void *cls) " exchange_url" ",reserve_priv" ",pickup_serial" - " FROM merchant_tip_pickups" - " JOIN merchant_tips USING (tip_serial)" - " JOIN merchant_tip_reserves USING (reserve_serial)" - " JOIN merchant_tip_reserve_keys USING (reserve_serial)" + " FROM merchant_reward_pickups" + " JOIN merchant_rewards USING (reward_serial)" + " JOIN merchant_reward_reserves USING (reserve_serial)" + " JOIN merchant_reward_reserve_keys USING (reserve_serial)" " WHERE pickup_id = $3" - " AND tip_id = $2" + " AND reward_id = $2" " AND merchant_serial =" " (SELECT merchant_serial" " FROM merchant_instances" @@ -5369,183 +5369,183 @@ postgres_connect (void *cls) "SELECT" " coin_offset" ",blind_sig" - " FROM merchant_tip_pickup_signatures" + " FROM merchant_reward_pickup_signatures" " WHERE pickup_serial = $1"), - /* For postgres_lookup_tip() */ - GNUNET_PQ_make_prepare ("lookup_tip", + /* For postgres_lookup_reward() */ + GNUNET_PQ_make_prepare ("lookup_reward", "SELECT" " amount_val" ",amount_frac" ",picked_up_val" ",picked_up_frac" - ",merchant_tips.expiration" + ",merchant_rewards.expiration" ",exchange_url" ",next_url" ",reserve_priv" - " FROM merchant_tips" - " JOIN merchant_tip_reserves USING (reserve_serial)" - " JOIN merchant_tip_reserve_keys USING (reserve_serial)" - " WHERE tip_id = $2" + " FROM merchant_rewards" + " JOIN merchant_reward_reserves USING (reserve_serial)" + " JOIN merchant_reward_reserve_keys USING (reserve_serial)" + " WHERE reward_id = $2" " AND merchant_serial =" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)"), - /* For postgres_lookup_tip() */ - GNUNET_PQ_make_prepare ("lookup_tips_inc", + /* For postgres_lookup_reward() */ + GNUNET_PQ_make_prepare ("lookup_rewards_inc", "SELECT" - " tip_serial" - ",tip_id" + " reward_serial" + ",reward_id" ",amount_val" ",amount_frac" ",CAST($4 as BIGINT)" /* otherwise $4 is unused and Postgres unhappy */ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - " FROM merchant_tips" - " JOIN merchant_tip_reserves USING (reserve_serial)" + " FROM merchant_rewards" + " JOIN merchant_reward_reserves USING (reserve_serial)" " WHERE merchant_serial =" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)" " AND" - " tip_serial > $3" - " ORDER BY tip_serial ASC" + " reward_serial > $3" + " ORDER BY reward_serial ASC" " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_tips_dec", + GNUNET_PQ_make_prepare ("lookup_rewards_dec", "SELECT" - " tip_serial" - ",tip_id" + " reward_serial" + ",reward_id" ",amount_val" ",amount_frac" ",CAST($4 as BIGINT)" /* otherwise $4 is unused and Postgres unhappy */ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - " FROM merchant_tips" - " JOIN merchant_tip_reserves USING (reserve_serial)" + " FROM merchant_rewards" + " JOIN merchant_reward_reserves USING (reserve_serial)" " WHERE merchant_serial =" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)" " AND" - " tip_serial < $3" - " ORDER BY tip_serial DESC" + " reward_serial < $3" + " ORDER BY reward_serial DESC" " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_tips_inc_expired", + GNUNET_PQ_make_prepare ("lookup_rewards_inc_expired", "SELECT" - " tip_serial" - ",tip_id" + " reward_serial" + ",reward_id" ",amount_val" ",amount_frac" - " FROM merchant_tips" - " JOIN merchant_tip_reserves USING (reserve_serial)" + " FROM merchant_rewards" + " JOIN merchant_reward_reserves USING (reserve_serial)" " WHERE merchant_serial =" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)" " AND" - " tip_serial > $3" + " reward_serial > $3" " AND" - " CAST($5 as BOOL) = (merchant_tips.expiration < $4)" - " ORDER BY tip_serial ASC" + " CAST($5 as BOOL) = (merchant_rewards.expiration < $4)" + " ORDER BY reward_serial ASC" " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_tips_dec_expired", + GNUNET_PQ_make_prepare ("lookup_rewards_dec_expired", "SELECT" - " tip_serial" - ",tip_id" + " reward_serial" + ",reward_id" ",amount_val" ",amount_frac" - " FROM merchant_tips" - " JOIN merchant_tip_reserves USING (reserve_serial)" + " FROM merchant_rewards" + " JOIN merchant_reward_reserves USING (reserve_serial)" " WHERE merchant_serial =" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)" " AND" - " tip_serial < $3" + " reward_serial < $3" " AND" - " CAST($5 as BOOL) = (merchant_tips.expiration < $4)" - " ORDER BY tip_serial DESC" + " CAST($5 as BOOL) = (merchant_rewards.expiration < $4)" + " ORDER BY reward_serial DESC" " LIMIT $2"), - /* for postgres_lookup_tip_details() */ - GNUNET_PQ_make_prepare ("lookup_tip_details", + /* for postgres_lookup_reward_details() */ + GNUNET_PQ_make_prepare ("lookup_reward_details", "SELECT" - " tip_serial" + " reward_serial" ",amount_val" ",amount_frac" ",picked_up_val" ",picked_up_frac" ",justification" - ",merchant_tips.expiration" + ",merchant_rewards.expiration" ",reserve_pub" - " FROM merchant_tips" - " JOIN merchant_tip_reserves USING (reserve_serial)" - " WHERE tip_id = $2" + " FROM merchant_rewards" + " JOIN merchant_reward_reserves USING (reserve_serial)" + " WHERE reward_id = $2" " AND merchant_serial =" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)"), - /* for postgres_lookup_tip_details() */ + /* for postgres_lookup_reward_details() */ GNUNET_PQ_make_prepare ("lookup_pickup_details", "SELECT" " pickup_id" ",amount_val" ",amount_frac" ",COUNT(blind_sig) AS num_planchets" - " FROM merchant_tip_pickups" - " JOIN merchant_tip_pickup_signatures USING (pickup_serial)" - " WHERE tip_serial = $1" + " FROM merchant_reward_pickups" + " JOIN merchant_reward_pickup_signatures USING (pickup_serial)" + " WHERE reward_serial = $1" " GROUP BY pickup_serial"), /* for postgres_insert_pickup() */ GNUNET_PQ_make_prepare ("insert_pickup", - "INSERT INTO merchant_tip_pickups" - "(tip_serial" + "INSERT INTO merchant_reward_pickups" + "(reward_serial" ",pickup_id" ",amount_val" ",amount_frac" ") " "SELECT" - " tip_serial, $3, $4, $5" - " FROM merchant_tips" - " JOIN merchant_tip_reserves USING (reserve_serial)" - " WHERE tip_id=$2" + " reward_serial, $3, $4, $5" + " FROM merchant_rewards" + " JOIN merchant_reward_reserves USING (reserve_serial)" + " WHERE reward_id=$2" " AND merchant_serial = " " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)"), /* for postgres_insert_pickup() */ - GNUNET_PQ_make_prepare ("update_picked_up_tip", - "UPDATE merchant_tips SET" + GNUNET_PQ_make_prepare ("update_picked_up_reward", + "UPDATE merchant_rewards SET" " picked_up_val=$2" ",picked_up_frac=$3" ",was_picked_up = ($2 = amount_val AND $3 = amount_frac)" - " WHERE tip_id = $1"), + " WHERE reward_id = $1"), /* for postgres_insert_pickup() */ GNUNET_PQ_make_prepare ("lookup_picked_up_reserve", "SELECT" " reserve_serial" - ",tips_picked_up_val" - ",tips_picked_up_frac" - " FROM merchant_tip_reserves" - " JOIN merchant_tips USING (reserve_serial)" - " WHERE tip_id=$2" + ",rewards_picked_up_val" + ",rewards_picked_up_frac" + " FROM merchant_reward_reserves" + " JOIN merchant_rewards USING (reserve_serial)" + " WHERE reward_id=$2" " AND merchant_serial =" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)"), /* for postgres_insert_pickup() */ GNUNET_PQ_make_prepare ("update_picked_up_reserve", - "UPDATE merchant_tip_reserves SET" - " tips_picked_up_val=$2" - ",tips_picked_up_frac=$3" + "UPDATE merchant_reward_reserves SET" + " rewards_picked_up_val=$2" + ",rewards_picked_up_frac=$3" " WHERE reserve_serial = $1"), /* for postgres_insert_pickup_blind_signature() */ GNUNET_PQ_make_prepare ("insert_pickup_blind_signature", - "INSERT INTO merchant_tip_pickup_signatures" + "INSERT INTO merchant_reward_pickup_signatures" "(pickup_serial" ",coin_offset" ",blind_sig" ") " "SELECT" " pickup_serial, $2, $3" - " FROM merchant_tip_pickups" + " FROM merchant_reward_pickups" " WHERE pickup_id=$1"), /* for postgres_lookup_templates() */ GNUNET_PQ_make_prepare ("lookup_templates", @@ -5936,11 +5936,11 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) plugin->lookup_reserve = &postgres_lookup_reserve; plugin->delete_reserve = &postgres_delete_reserve; plugin->purge_reserve = &postgres_purge_reserve; - plugin->authorize_tip = &postgres_authorize_tip; + plugin->authorize_reward = &postgres_authorize_reward; plugin->lookup_pickup = &postgres_lookup_pickup; - plugin->lookup_tip = &postgres_lookup_tip; - plugin->lookup_tips = &postgres_lookup_tips; - plugin->lookup_tip_details = &postgres_lookup_tip_details; + plugin->lookup_reward = &postgres_lookup_reward; + plugin->lookup_rewards = &postgres_lookup_rewards; + plugin->lookup_reward_details = &postgres_lookup_reward_details; plugin->insert_pickup = &postgres_insert_pickup; plugin->insert_pickup_blind_signature = &postgres_insert_pickup_blind_signature; diff --git a/src/backenddb/test.conf b/src/backenddb/test.conf @@ -26,7 +26,7 @@ LOOKAHEAD_SIGN = 24 days [taler-helper-crypto-eddsa] # Reduce from 1 year to speed up test LOOKAHEAD_SIGN = 24 days -# Reduce from 12 weeks to ensure we have multiple +# Reduce from 12 weeks to ensure we have mulrewardle DURATION = 14 days [bank] diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c @@ -2046,7 +2046,7 @@ run_test_orders (struct TestOrders_Closure *cls) return 1; } } - /* Test lookups on multiple orders */ + /* Test lookups on mulrewardle orders */ TEST_RET_ON_FAIL (test_insert_order (&cls->instance, &cls->orders[1], GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); @@ -3193,7 +3193,7 @@ run_test_deposits (struct TestDeposits_Closure *cls) &cls->deposits[0].coin_pub, 1, cls->deposits)); - /* Test multiple deposits */ + /* Test mulrewardle deposits */ TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance, &cls->signkey, &cls->deposits[1], @@ -4407,7 +4407,7 @@ test_transfers (void) } -/* Reserves and tips */ +/* Reserves and rewards */ struct ReserveData @@ -4482,14 +4482,14 @@ struct TestLookupReserve_Closure const struct ReserveData *reserve_to_cmp; /** - * The length of @e tips. + * The length of @e rewards. */ - unsigned int tips_length; + unsigned int rewards_length; /** - * The tips that have been authorized from the reserve. + * The rewards that have been authorized from the reserve. */ - const struct TALER_MERCHANTDB_TipDetails *tips; + const struct TALER_MERCHANTDB_RewardDetails *rewards; /** * 1 if the result matches, 0 otherwise. @@ -4506,14 +4506,14 @@ struct TestLookupReserve_Closure * @param merchant_initial_amount initial amount that the merchant claims to have filled the * reserve with * @param exchange_initial_amount initial amount that the exchange claims to have received - * @param picked_up_amount total of tips that were picked up from this reserve - * @param committed_amount total of tips that the merchant committed to, but that were not + * @param picked_up_amount total of rewards that were picked up from this reserve + * @param committed_amount total of rewards that the merchant committed to, but that were not * picked up yet * @param active true if the reserve is still active (we have the private key) * @param exchange_url base URL of the exchange hosting the reserve, NULL if not @a active * @param payto_uri URI to use to fund the reserve, NULL if not @a active - * @param tips_length length of the @a tips array - * @param tips information about the tips created by this reserve + * @param rewards_length length of the @a rewards array + * @param rewards information about the rewards created by this reserve * * @return 0 on success, 1 otherwise. */ @@ -4528,11 +4528,11 @@ lookup_reserve_cb (void *cls, bool active, const struct TALER_MasterPublicKeyP *master_pub, const char *exchange_url, - unsigned int tips_length, - const struct TALER_MERCHANTDB_TipDetails *tips) + unsigned int rewards_length, + const struct TALER_MERCHANTDB_RewardDetails *rewards) { struct TestLookupReserve_Closure *cmp = cls; - unsigned int tip_cmp_results[GNUNET_NZL (tips_length)]; + unsigned int reward_cmp_results[GNUNET_NZL (rewards_length)]; if (NULL == cmp) return; @@ -4545,7 +4545,7 @@ lookup_reserve_cb (void *cls, merchant_initial_amount)) || (0 != TALER_amount_cmp (&cmp->reserve_to_cmp->initial_amount, merchant_initial_amount)) || - (cmp->tips_length != tips_length)) + (cmp->rewards_length != rewards_length)) { cmp->result_matches = 1; return; @@ -4564,27 +4564,27 @@ lookup_reserve_cb (void *cls, cmp->result_matches = 0; return; } - memset (tip_cmp_results, + memset (reward_cmp_results, 0, - sizeof (tip_cmp_results)); - for (unsigned int i = 0; tips_length > i; ++i) + sizeof (reward_cmp_results)); + for (unsigned int i = 0; rewards_length > i; ++i) { - for (unsigned int j = 0; tips_length > j; ++j) + for (unsigned int j = 0; rewards_length > j; ++j) { - if ((GNUNET_OK == TALER_amount_cmp_currency (&cmp->tips[i].total_amount, - &tips[j].total_amount)) && - (0 == TALER_amount_cmp (&cmp->tips[i].total_amount, - &tips[j].total_amount)) && - (0 == strcmp (cmp->tips[i].reason, - tips[j].reason))) + if ((GNUNET_OK == TALER_amount_cmp_currency (&cmp->rewards[i].total_amount, + &rewards[j].total_amount)) && + (0 == TALER_amount_cmp (&cmp->rewards[i].total_amount, + &rewards[j].total_amount)) && + (0 == strcmp (cmp->rewards[i].reason, + rewards[j].reason))) { - tip_cmp_results[i] += 1; + reward_cmp_results[i] += 1; } } } - for (unsigned int i = 0; tips_length > i; ++i) + for (unsigned int i = 0; rewards_length > i; ++i) { - if (1 != tip_cmp_results[i]) + if (1 != reward_cmp_results[i]) { cmp->result_matches = 1; return; @@ -4609,8 +4609,8 @@ test_lookup_reserve (const struct InstanceData *instance, { struct TestLookupReserve_Closure cmp = { .reserve_to_cmp = reserve, - .tips_length = 0, - .tips = NULL, + .rewards_length = 0, + .rewards = NULL, .result_matches = 0 }; if (1 != plugin->lookup_reserve (plugin->cls, @@ -4635,7 +4635,7 @@ test_lookup_reserve (const struct InstanceData *instance, /** - * Container for looking up multiple reserves. + * Container for looking up mulrewardle reserves. */ struct TestLookupReserves_Closure { @@ -4670,8 +4670,8 @@ struct TestLookupReserves_Closure * @param merchant_initial_amount initial amount that the merchant claims to have filled the * reserve with * @param exchange_initial_amount initial amount that the exchange claims to have received - * @param pickup_amount total of tips that were picked up from this reserve - * @param committed_amount total of tips that the merchant committed to, but that were not + * @param pickup_amount total of rewards that were picked up from this reserve + * @param committed_amount total of rewards that the merchant committed to, but that were not * picked up yet * @param active true if the reserve is still active (we have the private key) */ @@ -4847,14 +4847,14 @@ test_lookup_pending_reserves (unsigned int reserves_length, /** - * Container for all tip data relevant to the database. + * Container for all reward data relevant to the database. */ -struct TipData +struct RewardData { /** - * The details of the tip. + * The details of the reward. */ - struct TALER_MERCHANTDB_TipDetails details; + struct TALER_MERCHANTDB_RewardDetails details; /** * Where the user should be redirected. @@ -4862,68 +4862,68 @@ struct TipData const char *next_url; /** - * When the tip expires. + * When the reward expires. */ struct GNUNET_TIME_Timestamp expiration; }; /** - * Creates a tip for testing. - * @param tip the tip to fill with data. + * Creates a reward for testing. + * @param reward the reward to fill with data. */ static void -make_tip (struct TipData *tip) +make_reward (struct RewardData *reward) { GNUNET_assert (GNUNET_OK == TALER_string_to_amount ("EUR:0.99", - &tip->details.total_amount)); - tip->details.reason = "because"; - tip->next_url = "https://taler.net"; + &reward->details.total_amount)); + reward->details.reason = "because"; + reward->next_url = "https://taler.net"; } /** - * Tests authorizing a tip. - * @param instance the instance authorizing the tip. - * @param reserve where the tip is coming from. - * @param tip the tip to authorize. + * Tests authorizing a reward. + * @param instance the instance authorizing the reward. + * @param reserve where the reward is coming from. + * @param reward the reward to authorize. * * @return 0 on success, 1 otherwise. */ static int -test_authorize_tip (const struct InstanceData *instance, +test_authorize_reward (const struct InstanceData *instance, const struct ReserveData *reserve, - struct TipData *tip) + struct RewardData *reward) { TEST_COND_RET_ON_FAIL (TALER_EC_NONE == - plugin->authorize_tip (plugin->cls, + plugin->authorize_reward (plugin->cls, instance->instance.id, &reserve->reserve_pub, - &tip->details.total_amount, - tip->details.reason, - tip->next_url, - &tip->details.tip_id, - &tip->expiration), - "Authorize tip failed\n"); + &reward->details.total_amount, + reward->details.reason, + reward->next_url, + &reward->details.reward_id, + &reward->expiration), + "Authorize reward failed\n"); return 0; } /** - * Tests looking up a tip from the database. - * @param instance the instance to look up tips from. - * @param reserve the reserve to look up tips from. - * @param tip the tip we expect to find (uses @e tip_id to perform lookup). - * @param expected_total_picked_up how much of the tip should have been + * Tests looking up a reward from the database. + * @param instance the instance to look up rewards from. + * @param reserve the reserve to look up rewards from. + * @param reward the reward we expect to find (uses @e reward_id to perform lookup). + * @param expected_total_picked_up how much of the reward should have been * picked up. * * @return 0 on success, 1 otherwise. */ static int -test_lookup_tip (const struct InstanceData *instance, +test_lookup_reward (const struct InstanceData *instance, const struct ReserveData *reserve, - const struct TipData *tip, + const struct RewardData *reward, const struct TALER_Amount *expected_total_picked_up) { struct TALER_Amount total_authorized; @@ -4933,9 +4933,9 @@ test_lookup_tip (const struct InstanceData *instance, char *next_url = NULL; struct TALER_ReservePrivateKeyP reserve_priv; - if (1 != plugin->lookup_tip (plugin->cls, + if (1 != plugin->lookup_reward (plugin->cls, instance->instance.id, - &tip->details.tip_id, + &reward->details.reward_id, &total_authorized, &total_picked_up, &expiration, @@ -4944,21 +4944,21 @@ test_lookup_tip (const struct InstanceData *instance, &reserve_priv)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup tip failed\n"); + "Lookup reward failed\n"); GNUNET_free (exchange_url); return 1; } if ((GNUNET_OK != - TALER_amount_cmp_currency (&tip->details.total_amount, + TALER_amount_cmp_currency (&reward->details.total_amount, &total_authorized)) || - (0 != TALER_amount_cmp (&tip->details.total_amount, + (0 != TALER_amount_cmp (&reward->details.total_amount, &total_authorized)) || (GNUNET_OK != TALER_amount_cmp_currency (expected_total_picked_up, &total_picked_up)) || (0 != TALER_amount_cmp (expected_total_picked_up, &total_picked_up)) || - (GNUNET_TIME_timestamp_cmp (tip->expiration, + (GNUNET_TIME_timestamp_cmp (reward->expiration, !=, expiration)) || (0 != strcmp (reserve->exchange_url, @@ -4967,7 +4967,7 @@ test_lookup_tip (const struct InstanceData *instance, &reserve_priv))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup tip failed: mismatched data\n"); + "Lookup reward failed: mismatched data\n"); GNUNET_free (exchange_url); GNUNET_free (next_url); return 1; @@ -4979,23 +4979,23 @@ test_lookup_tip (const struct InstanceData *instance, /** - * Tests looking up the details of a tip from the database. + * Tests looking up the details of a reward from the database. * - * @param instance the instance the tip is in. - * @param reserve the reserve the tip was authorized from. - * @param tip the tip we expect to find (uses @e tip_id to perform lookup). - * @param expected_total_picked_up how much of the tip should have been + * @param instance the instance the reward is in. + * @param reserve the reserve the reward was authorized from. + * @param reward the reward we expect to find (uses @e reward_id to perform lookup). + * @param expected_total_picked_up how much of the reward should have been * picked up. * @param expected_pickups_length the length of @e expected_pickups. * @param expected_pickups the pickups that we expect to be associated with - * the tip. + * the reward. * @return 0 on success, 1 otherwise. */ static int -test_lookup_tip_details ( +test_lookup_reward_details ( const struct InstanceData *instance, const struct ReserveData *reserve, - const struct TipData *tip, + const struct RewardData *reward, const struct TALER_Amount *expected_total_picked_up, unsigned int expected_pickups_length, const struct TALER_MERCHANTDB_PickupDetails *expected_pickups) @@ -5010,9 +5010,9 @@ test_lookup_tip_details ( unsigned int results_matching[GNUNET_NZL (expected_pickups_length)]; if (0 > - plugin->lookup_tip_details (plugin->cls, + plugin->lookup_reward_details (plugin->cls, instance->instance.id, - &tip->details.tip_id, + &reward->details.reward_id, true, &total_authorized, &total_picked_up, @@ -5023,24 +5023,24 @@ test_lookup_tip_details ( &pickups)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup tip details failed\n"); + "Lookup reward details failed\n"); GNUNET_free (justification); GNUNET_free (pickups); return 1; } if ( (GNUNET_OK != - TALER_amount_cmp_currency (&tip->details.total_amount, + TALER_amount_cmp_currency (&reward->details.total_amount, &total_authorized)) || - (0 != TALER_amount_cmp (&tip->details.total_amount, + (0 != TALER_amount_cmp (&reward->details.total_amount, &total_authorized)) || (GNUNET_OK != TALER_amount_cmp_currency (expected_total_picked_up, &total_picked_up)) || (0 != TALER_amount_cmp (expected_total_picked_up, &total_picked_up)) || - (0 != strcmp (tip->details.reason, + (0 != strcmp (reward->details.reason, justification)) || - (GNUNET_TIME_timestamp_cmp (tip->expiration, + (GNUNET_TIME_timestamp_cmp (reward->expiration, !=, expiration)) || (0 != GNUNET_memcmp (&reserve->reserve_pub, @@ -5048,7 +5048,7 @@ test_lookup_tip_details ( (expected_pickups_length != pickups_length) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup tip details failed: mismatched data\n"); + "Lookup reward details failed: mismatched data\n"); GNUNET_free (justification); GNUNET_free (pickups); return 1; @@ -5079,7 +5079,7 @@ test_lookup_tip_details ( if (1 != results_matching[i]) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup tip details failed: mismatched data\n"); + "Lookup reward details failed: mismatched data\n"); GNUNET_free (justification); GNUNET_free (pickups); return 1; @@ -5104,9 +5104,9 @@ free_signature_array (unsigned int sigs_length, /** - * Tests looking up a tip pickup. + * Tests looking up a reward pickup. * @param instance the instance to look up from. - * @param tip the tip the pickup was made for. + * @param reward the reward the pickup was made for. * @param pickup_id id of the pickup to look up. * @param expected_exchange_url exchange url for the pickup. * @param expected_reserve_priv reserve private key for the pickup. @@ -5118,7 +5118,7 @@ free_signature_array (unsigned int sigs_length, static int test_lookup_pickup ( const struct InstanceData *instance, - const struct TipData *tip, + const struct RewardData *reward, const struct TALER_PickupIdentifierP *pickup_id, const char *expected_exchange_url, const struct TALER_ReservePrivateKeyP *expected_reserve_priv, @@ -5136,7 +5136,7 @@ test_lookup_pickup ( sizeof (sigs)); if (0 > plugin->lookup_pickup (plugin->cls, instance->instance.id, - &tip->details.tip_id, + &reward->details.reward_id, pickup_id, &exchange_url, &reserve_priv, @@ -5195,19 +5195,19 @@ test_lookup_pickup ( /** - * Closure for testing lookup_tips. + * Closure for testing lookup_rewards. */ -struct TestLookupTips_Closure +struct TestLookupRewards_Closure { /** - * The length of @e tips_to_cmp. + * The length of @e rewards_to_cmp. */ - unsigned int tips_to_cmp_length; + unsigned int rewards_to_cmp_length; /** - * The tips that we are expecting to find. + * The rewards that we are expecting to find. */ - const struct TipData *tips_to_cmp; + const struct RewardData *rewards_to_cmp; /** * The number of results found from the lookup. @@ -5215,38 +5215,38 @@ struct TestLookupTips_Closure unsigned int results_length; /** - * Whether each result matches with the corresponding tip in @tips_to_cmp. + * Whether each result matches with the corresponding reward in @rewards_to_cmp. */ bool *results_match; }; /** - * Called after test_lookup_tips. - * @param cls pointer to a TestLookupTips_Closure. - * @param row_id the row id of the tip. - * @param tip_id the id of the tip. - * @param amount the amount of the tip. + * Called after test_lookup_rewards. + * @param cls pointer to a TestLookupRewards_Closure. + * @param row_id the row id of the reward. + * @param reward_id the id of the reward. + * @param amount the amount of the reward. */ static void -lookup_tips_cb (void *cls, +lookup_rewards_cb (void *cls, uint64_t row_id, - struct TALER_TipIdentifierP tip_id, + struct TALER_RewardIdentifierP reward_id, struct TALER_Amount amount) { - struct TestLookupTips_Closure *cmp = cls; + struct TestLookupRewards_Closure *cmp = cls; if (NULL == cmp) return; unsigned int i = cmp->results_length; cmp->results_length += 1; - if (cmp->tips_to_cmp_length > i) + if (cmp->rewards_to_cmp_length > i) { - if ((0 == GNUNET_memcmp (&cmp->tips_to_cmp[i].details.tip_id, - &tip_id)) && + if ((0 == GNUNET_memcmp (&cmp->rewards_to_cmp[i].details.reward_id, + &reward_id)) && (GNUNET_OK == TALER_amount_cmp_currency ( - &cmp->tips_to_cmp[i].details.total_amount, + &cmp->rewards_to_cmp[i].details.total_amount, &amount)) && - (0 == TALER_amount_cmp (&cmp->tips_to_cmp[i].details.total_amount, + (0 == TALER_amount_cmp (&cmp->rewards_to_cmp[i].details.total_amount, &amount))) cmp->results_match[i] = true; else @@ -5256,59 +5256,59 @@ lookup_tips_cb (void *cls, /** - * Tests looking up the tips from the database. - * @param instance the instance to look up tips from. - * @param expired how to filter expired tips. - * @param offset where to start retrieving tips. - * @param tips_length length of @e tips. - * @param tips the tips that we expect to find. + * Tests looking up the rewards from the database. + * @param instance the instance to look up rewards from. + * @param expired how to filter expired rewards. + * @param offset where to start retrieving rewards. + * @param rewards_length length of @e rewards. + * @param rewards the rewards that we expect to find. * * @return 0 on success, 1 otherwise. */ static int -test_lookup_tips (const struct InstanceData *instance, +test_lookup_rewards (const struct InstanceData *instance, enum TALER_EXCHANGE_YesNoAll expired, int64_t limit, uint64_t offset, - unsigned int tips_length, - const struct TipData *tips) + unsigned int rewards_length, + const struct RewardData *rewards) { - bool results_match[tips_length]; - struct TestLookupTips_Closure cmp = { - .tips_to_cmp_length = tips_length, - .tips_to_cmp = tips, + bool results_match[rewards_length]; + struct TestLookupRewards_Closure cmp = { + .rewards_to_cmp_length = rewards_length, + .rewards_to_cmp = rewards, .results_length = 0, .results_match = results_match }; memset (results_match, 0, - sizeof (bool) * tips_length); - if (0 > plugin->lookup_tips (plugin->cls, + sizeof (bool) * rewards_length); + if (0 > plugin->lookup_rewards (plugin->cls, instance->instance.id, expired, limit, offset, - &lookup_tips_cb, + &lookup_rewards_cb, &cmp)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup tips failed\n"); + "Lookup rewards failed\n"); return 1; } - if (tips_length != cmp.results_length) + if (rewards_length != cmp.results_length) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup tips failed: incorrect number of results (%d)\n", + "Lookup rewards failed: incorrect number of results (%d)\n", cmp.results_length); return 1; } - for (unsigned int i = 0; i < tips_length; ++i) + for (unsigned int i = 0; i < rewards_length; ++i) { if (true != cmp.results_match[i]) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup tips failed: mismatched data\n"); + "Lookup rewards failed: mismatched data\n"); return 1; } } @@ -5317,26 +5317,26 @@ test_lookup_tips (const struct InstanceData *instance, /** - * Convenience function for testing lookup tips with filters - * @param tips_length length of @e tips. - * @param tips the array of tips to reverse. + * Convenience function for testing lookup rewards with filters + * @param rewards_length length of @e rewards. + * @param rewards the array of rewards to reverse. */ static void -reverse_tip_data_array (unsigned int tips_length, - struct TipData *tips) +reverse_reward_data_array (unsigned int rewards_length, + struct RewardData *rewards) { - struct TipData tmp[tips_length]; - for (unsigned int i = 0; i < tips_length; ++i) - tmp[i] = tips[tips_length - 1 - i]; - for (unsigned int i = 0; i < tips_length; ++i) - tips[i] = tmp[i]; + struct RewardData tmp[rewards_length]; + for (unsigned int i = 0; i < rewards_length; ++i) + tmp[i] = rewards[rewards_length - 1 - i]; + for (unsigned int i = 0; i < rewards_length; ++i) + rewards[i] = tmp[i]; } /** - * Container for data for testing tips. + * Container for data for testing rewards. */ -struct TestTips_Closure +struct TestRewards_Closure { /** * The instance. @@ -5344,7 +5344,7 @@ struct TestTips_Closure struct InstanceData instance; /** - * The tip reserve data. + * The reward reserve data. */ struct ReserveData reserve; @@ -5354,19 +5354,19 @@ struct TestTips_Closure struct ReserveData expired_reserve; /** - * A normal tip. + * A normal reward. */ - struct TipData tip; + struct RewardData reward; /** - * A tip that is too large to authorize. + * A reward that is too large to authorize. */ - struct TipData bigtip; + struct RewardData bigreward; /** - * Array of tips for testing lookups. + * Array of rewards for testing lookups. */ - struct TipData tips[5]; + struct RewardData rewards[5]; /** * Id of a pickup. @@ -5386,14 +5386,14 @@ struct TestTips_Closure /** - * Prepares for testing tips functionality. + * Prepares for testing rewards functionality. * @param cls the data to prepare. */ static void -pre_test_tips (struct TestTips_Closure *cls) +pre_test_rewards (struct TestRewards_Closure *cls) { /* Instance */ - make_instance ("test_inst_tips", + make_instance ("test_inst_rewards", &cls->instance); /* Reserve */ @@ -5425,23 +5425,23 @@ pre_test_tips (struct TestTips_Closure *cls) sizeof (cls->expired_reserve.master_pub)); cls->expired_reserve.expiration = GNUNET_TIME_UNIT_ZERO_TS; - /* Tip/pickup */ - make_tip (&cls->tip); - make_tip (&cls->bigtip); + /* Reward/pickup */ + make_reward (&cls->reward); + make_reward (&cls->bigreward); GNUNET_assert (GNUNET_OK == TALER_string_to_amount ("EUR:99.90", - &cls->bigtip.details.total_amount)); + &cls->bigreward.details.total_amount)); for (unsigned int i = 0; i < 5; ++i) { char amount[16]; - make_tip (&cls->tips[i]); + make_reward (&cls->rewards[i]); GNUNET_snprintf (amount, 16, "EUR:0.%u0", i + 1); GNUNET_assert (GNUNET_OK == TALER_string_to_amount (amount, - &cls->tips[i].details.total_amount)); + &cls->rewards[i].details.total_amount)); } cls->pickup_priv = GNUNET_CRYPTO_rsa_private_key_create (2048); @@ -5453,11 +5453,11 @@ pre_test_tips (struct TestTips_Closure *cls) /** - * Cleans up after testing tips. + * Cleans up after testing rewards. * @param cls the data to clean up. */ static void -post_test_tips (struct TestTips_Closure *cls) +post_test_rewards (struct TestRewards_Closure *cls) { free_instance_data (&cls->instance); GNUNET_CRYPTO_rsa_private_key_free (cls->pickup_priv); @@ -5466,13 +5466,13 @@ post_test_tips (struct TestTips_Closure *cls) /** - * Runs tests for tips. + * Runs tests for rewards. * @param cls container of test data. * * @return 0 on success, 1 on failure. */ static int -run_test_tips (struct TestTips_Closure *cls) +run_test_rewards (struct TestRewards_Closure *cls) { struct TALER_Amount zero; @@ -5501,19 +5501,19 @@ run_test_tips (struct TestTips_Closure *cls) "Activate reserve failed\n"); TEST_RET_ON_FAIL (test_lookup_pending_reserves (0, NULL)); - /* Test inserting a tip */ - TEST_RET_ON_FAIL (test_authorize_tip (&cls->instance, + /* Test inserting a reward */ + TEST_RET_ON_FAIL (test_authorize_reward (&cls->instance, &cls->reserve, - &cls->tip)); - /* Test lookup tip */ - TEST_RET_ON_FAIL (test_lookup_tip (&cls->instance, + &cls->reward)); + /* Test lookup reward */ + TEST_RET_ON_FAIL (test_lookup_reward (&cls->instance, &cls->reserve, - &cls->tip, + &cls->reward, &zero)); - /* Test lookup tip details */ - TEST_RET_ON_FAIL (test_lookup_tip_details (&cls->instance, + /* Test lookup reward details */ + TEST_RET_ON_FAIL (test_lookup_reward_details (&cls->instance, &cls->reserve, - &cls->tip, + &cls->reward, &zero, 0, NULL)); @@ -5521,14 +5521,14 @@ run_test_tips (struct TestTips_Closure *cls) TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == plugin->insert_pickup (plugin->cls, cls->instance.instance.id, - &cls->tip.details.tip_id, - &cls->tip.details.total_amount, + &cls->reward.details.reward_id, + &cls->reward.details.total_amount, &cls->pickup_id, - &cls->tip.details.total_amount), + &cls->reward.details.total_amount), "Insert pickup failed\n"); /* Test lookup pickup */ TEST_RET_ON_FAIL (test_lookup_pickup (&cls->instance, - &cls->tip, + &cls->reward, &cls->pickup_id, cls->reserve.exchange_url, &cls->reserve.reserve_priv, @@ -5543,31 +5543,31 @@ run_test_tips (struct TestTips_Closure *cls) "Insert pickup blind signature failed\n"); /* Test that overdrawing the reserve fails */ TEST_COND_RET_ON_FAIL (TALER_EC_NONE != - plugin->authorize_tip (plugin->cls, + plugin->authorize_reward (plugin->cls, cls->instance.instance.id, &cls->reserve.reserve_pub, - &cls->bigtip.details. + &cls->bigreward.details. total_amount, - cls->bigtip.details.reason, - cls->bigtip.next_url, - &cls->bigtip.details.tip_id, + cls->bigreward.details.reason, + cls->bigreward.next_url, + &cls->bigreward.details.reward_id, &cls->reserve.expiration), - "Authorize tip failed\n"); - /* Test lookup tips */ - TEST_RET_ON_FAIL (test_lookup_tips (&cls->instance, + "Authorize reward failed\n"); + /* Test lookup rewards */ + TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, TALER_EXCHANGE_YNA_ALL, 1, 0, 1, - &cls->tip)); + &cls->reward)); /* Test lookup reserves */ TEST_RET_ON_FAIL (test_lookup_reserves (&cls->instance, 1, &cls->reserve)); { - /* Test lookup tips & friends */ - struct TipData expected_tips[6]; - expected_tips[0] = cls->tip; + /* Test lookup rewards & friends */ + struct RewardData expected_rewards[6]; + expected_rewards[0] = cls->reward; TEST_RET_ON_FAIL (test_insert_reserve (&cls->instance, &cls->expired_reserve, TALER_EC_NONE)); @@ -5583,74 +5583,74 @@ run_test_tips (struct TestTips_Closure *cls) { if (i % 2 == 0) { - TEST_RET_ON_FAIL (test_authorize_tip (&cls->instance, + TEST_RET_ON_FAIL (test_authorize_reward (&cls->instance, &cls->expired_reserve, - &cls->tips[i])); + &cls->rewards[i])); } else { - TEST_RET_ON_FAIL (test_authorize_tip (&cls->instance, + TEST_RET_ON_FAIL (test_authorize_reward (&cls->instance, &cls->reserve, - &cls->tips[i])); + &cls->rewards[i])); } } - GNUNET_memcpy (&expected_tips[1], - cls->tips, - sizeof (struct TipData) * 5); - /* Test lookup tips inc */ - TEST_RET_ON_FAIL (test_lookup_tips (&cls->instance, + GNUNET_memcpy (&expected_rewards[1], + cls->rewards, + sizeof (struct RewardData) * 5); + /* Test lookup rewards inc */ + TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, TALER_EXCHANGE_YNA_ALL, 6, 0, 6, - expected_tips)); - reverse_tip_data_array (6, - expected_tips); - /* Test lookup tips dec */ - TEST_RET_ON_FAIL (test_lookup_tips (&cls->instance, + expected_rewards)); + reverse_reward_data_array (6, + expected_rewards); + /* Test lookup rewards dec */ + TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, TALER_EXCHANGE_YNA_ALL, -6, 10, 6, - expected_tips)); - /* Test lookup tips expired inc */ - expected_tips[0] = cls->tips[0]; - expected_tips[1] = cls->tips[2]; - expected_tips[2] = cls->tips[4]; - TEST_RET_ON_FAIL (test_lookup_tips (&cls->instance, + expected_rewards)); + /* Test lookup rewards expired inc */ + expected_rewards[0] = cls->rewards[0]; + expected_rewards[1] = cls->rewards[2]; + expected_rewards[2] = cls->rewards[4]; + TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, TALER_EXCHANGE_YNA_YES, 6, 0, 3, - expected_tips)); - /* Test lookup tips expired dec */ - reverse_tip_data_array (3, - expected_tips); - TEST_RET_ON_FAIL (test_lookup_tips (&cls->instance, + expected_rewards)); + /* Test lookup rewards expired dec */ + reverse_reward_data_array (3, + expected_rewards); + TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, TALER_EXCHANGE_YNA_YES, -6, 10, 3, - expected_tips)); - /* Test lookup tips unexpired inc */ - expected_tips[0] = cls->tip; - expected_tips[1] = cls->tips[1]; - expected_tips[2] = cls->tips[3]; - TEST_RET_ON_FAIL (test_lookup_tips (&cls->instance, + expected_rewards)); + /* Test lookup rewards unexpired inc */ + expected_rewards[0] = cls->reward; + expected_rewards[1] = cls->rewards[1]; + expected_rewards[2] = cls->rewards[3]; + TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, TALER_EXCHANGE_YNA_NO, 6, 0, 3, - expected_tips)); - /* Test lookup tips unexpired dec */ - reverse_tip_data_array (3, - expected_tips); - TEST_RET_ON_FAIL (test_lookup_tips (&cls->instance, + expected_rewards)); + /* Test lookup rewards unexpired dec */ + reverse_reward_data_array (3, + expected_rewards); + TEST_RET_ON_FAIL (test_lookup_rewards (&cls->instance, TALER_EXCHANGE_YNA_NO, -6, 10, 3, - expected_tips)); + expected_rewards)); } /* Test delete reserve private key */ TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == @@ -5680,17 +5680,17 @@ run_test_tips (struct TestTips_Closure *cls) /** - * Handles all logic for testing tips in the database. + * Handles all logic for testing rewards in the database. * * @return 0 on success, 1 on failure. */ static int -test_tips (void) +test_rewards (void) { - struct TestTips_Closure test_cls; - pre_test_tips (&test_cls); - int test_result = run_test_tips (&test_cls); - post_test_tips (&test_cls); + struct TestRewards_Closure test_cls; + pre_test_rewards (&test_cls); + int test_result = run_test_rewards (&test_cls); + post_test_rewards (&test_cls); return test_result; } @@ -8385,7 +8385,7 @@ run_tests (void) TEST_RET_ON_FAIL (test_orders ()); TEST_RET_ON_FAIL (test_deposits ()); TEST_RET_ON_FAIL (test_transfers ()); - TEST_RET_ON_FAIL (test_tips ()); + TEST_RET_ON_FAIL (test_rewards ()); TEST_RET_ON_FAIL (test_refunds ()); TEST_RET_ON_FAIL (test_lookup_orders_all_filters ()); TEST_RET_ON_FAIL (test_kyc ()); diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h @@ -3765,7 +3765,7 @@ struct TALER_MERCHANT_ReserveSummary struct TALER_Amount pickup_amount; /** - * Amount approved for tips that exceeds the pickup_amount. + * Amount approved for rewards that exceeds the pickup_amount. */ struct TALER_Amount committed_amount; @@ -3861,28 +3861,28 @@ TALER_MERCHANT_reserves_get_cancel ( /** * Handle for a request to obtain details on a specific - * (tipping) reserve. + * (rewardping) reserve. */ struct TALER_MERCHANT_ReserveGetHandle; /** - * Details about a tip granted by the merchant. + * Details about a reward granted by the merchant. */ -struct TALER_MERCHANT_TipDetails +struct TALER_MERCHANT_RewardDetails { /** - * Identifier for the tip. + * Identifier for the reward. */ - struct TALER_TipIdentifierP tip_id; + struct TALER_RewardIdentifierP reward_id; /** - * Total value of the tip (including fees). + * Total value of the reward (including fees). */ struct TALER_Amount amount; /** - * Human-readable reason for why the tip was granted. + * Human-readable reason for why the reward was granted. */ const char *reason; @@ -3934,14 +3934,14 @@ struct TALER_MERCHANT_ReserveGetResponse unsigned int accounts_len; /** - * Array with details about the tips granted. + * Array with details about the rewards granted. */ - const struct TALER_MERCHANT_TipDetails *tips; + const struct TALER_MERCHANT_RewardDetails *rewards; /** - * Length of the @e tips array + * Length of the @e rewards array */ - unsigned int tips_length; + unsigned int rewards_length; /** * Is this reserve active (false if it was deleted but not purged) @@ -3974,7 +3974,7 @@ typedef void * @param ctx execution context * @param backend_url base URL of the merchant backend * @param reserve_pub which reserve should be queried - * @param fetch_tips should we return details about the tips issued from the reserve + * @param fetch_rewards should we return details about the rewards issued from the reserve * @param cb function to call with the result(s) * @param cb_cls closure for @a cb * @return handle for this operation, NULL upon errors @@ -3983,7 +3983,7 @@ struct TALER_MERCHANT_ReserveGetHandle * TALER_MERCHANT_reserve_get (struct GNUNET_CURL_Context *ctx, const char *backend_url, const struct TALER_ReservePublicKeyP *reserve_pub, - bool fetch_tips, + bool fetch_rewards, TALER_MERCHANT_ReserveGetCallback cb, void *cb_cls); @@ -3999,15 +3999,15 @@ TALER_MERCHANT_reserve_get_cancel ( /** - * Handle for a /tip-authorize operation. + * Handle for a /reward-authorize operation. */ -struct TALER_MERCHANT_TipAuthorizeHandle; +struct TALER_MERCHANT_RewardAuthorizeHandle; /** - * Response to a /tip-authorize request. + * Response to a /reward-authorize request. */ -struct TALER_MERCHANT_TipAuthorizeResponse +struct TALER_MERCHANT_RewardAuthorizeResponse { /** * HTTP response details @@ -4027,19 +4027,19 @@ struct TALER_MERCHANT_TipAuthorizeResponse { /** - * which tip ID should be used to pickup the tip + * which reward ID should be used to pickup the reward */ - struct TALER_TipIdentifierP tip_id; + struct TALER_RewardIdentifierP reward_id; /** - * URI for the tip + * URI for the reward */ - const char *tip_uri; + const char *reward_uri; /** - * when does the tip expire + * when does the reward expire */ - struct GNUNET_TIME_Timestamp tip_expiration; + struct GNUNET_TIME_Timestamp reward_expiration; } ok; @@ -4049,77 +4049,77 @@ struct TALER_MERCHANT_TipAuthorizeResponse /** - * Callback for a /reserves/$RESERVE_PUB/tip-authorize request. Returns the + * Callback for a /reserves/$RESERVE_PUB/reward-authorize request. Returns the * result of the operation. * * @param cls closure * @param tar response */ typedef void -(*TALER_MERCHANT_TipAuthorizeCallback) ( +(*TALER_MERCHANT_RewardAuthorizeCallback) ( void *cls, - const struct TALER_MERCHANT_TipAuthorizeResponse *tar); + const struct TALER_MERCHANT_RewardAuthorizeResponse *tar); /** - * Issue a /tip-authorize request to the backend. Informs the backend - * that a tip should be created. + * Issue a /reward-authorize request to the backend. Informs the backend + * that a reward should be created. * * @param ctx execution context * @param backend_url base URL of the merchant backend * @param reserve_pub public key of the reserve - * @param next_url where the browser should proceed after picking up the tip - * @param amount amount to be handed out as a tip - * @param justification which justification should be stored (human-readable reason for the tip) + * @param next_url where the browser should proceed after picking up the reward + * @param amount amount to be handed out as a reward + * @param justification which justification should be stored (human-readable reason for the reward) * @param authorize_cb callback which will work the response gotten from the backend * @param authorize_cb_cls closure to pass to @a authorize_cb * @return handle for this operation, NULL upon errors */ -struct TALER_MERCHANT_TipAuthorizeHandle * -TALER_MERCHANT_tip_authorize2 ( +struct TALER_MERCHANT_RewardAuthorizeHandle * +TALER_MERCHANT_reward_authorize2 ( struct GNUNET_CURL_Context *ctx, const char *backend_url, const struct TALER_ReservePublicKeyP *reserve_pub, const char *next_url, const struct TALER_Amount *amount, const char *justification, - TALER_MERCHANT_TipAuthorizeCallback authorize_cb, + TALER_MERCHANT_RewardAuthorizeCallback authorize_cb, void *authorize_cb_cls); /** - * Issue a POST /tips request to the backend. Informs the backend that a tip - * should be created. In contrast to #TALER_MERCHANT_tip_authorize2(), the + * Issue a POST /rewards request to the backend. Informs the backend that a reward + * should be created. In contrast to #TALER_MERCHANT_reward_authorize2(), the * backend gets to pick the reserve with this API. * * @param ctx execution context * @param backend_url base URL of the merchant backend - * @param next_url where the browser should proceed after picking up the tip - * @param amount amount to be handed out as a tip - * @param justification which justification should be stored (human-readable reason for the tip) + * @param next_url where the browser should proceed after picking up the reward + * @param amount amount to be handed out as a reward + * @param justification which justification should be stored (human-readable reason for the reward) * @param authorize_cb callback which will work the response gotten from the backend * @param authorize_cb_cls closure to pass to @a authorize_cb * @return handle for this operation, NULL upon errors */ -struct TALER_MERCHANT_TipAuthorizeHandle * -TALER_MERCHANT_tip_authorize ( +struct TALER_MERCHANT_RewardAuthorizeHandle * +TALER_MERCHANT_reward_authorize ( struct GNUNET_CURL_Context *ctx, const char *backend_url, const char *next_url, const struct TALER_Amount *amount, const char *justification, - TALER_MERCHANT_TipAuthorizeCallback authorize_cb, + TALER_MERCHANT_RewardAuthorizeCallback authorize_cb, void *authorize_cb_cls); /** - * Cancel a pending /tip-authorize request + * Cancel a pending /reward-authorize request * * @param ta handle from the operation to cancel */ void -TALER_MERCHANT_tip_authorize_cancel ( - struct TALER_MERCHANT_TipAuthorizeHandle *ta); +TALER_MERCHANT_reward_authorize_cancel ( + struct TALER_MERCHANT_RewardAuthorizeHandle *ta); /** @@ -4142,7 +4142,7 @@ typedef void /** * Issue a DELETE /reserve/$RESERVE_ID request to the backend. Only - * deletes the private key of the reserve, preserves tipping data. + * deletes the private key of the reserve, preserves rewardping data. * * @param ctx execution context * @param backend_url base URL of the merchant backend @@ -4190,18 +4190,18 @@ TALER_MERCHANT_reserve_delete_cancel ( struct TALER_MERCHANT_ReserveDeleteHandle *rdh); -/* ********************* /tips ************************** */ +/* ********************* /rewards ************************** */ /** - * Handle for a GET /tips/$TIP_ID (public variant) operation. + * Handle for a GET /rewards/$REWARD_ID (public variant) operation. */ -struct TALER_MERCHANT_TipWalletGetHandle; +struct TALER_MERCHANT_RewardWalletGetHandle; /** - * Response to a wallet's GET /tips/$TIP_ID request. + * Response to a wallet's GET /rewards/$REWARD_ID request. */ -struct TALER_MERCHANT_TipWalletGetResponse +struct TALER_MERCHANT_RewardWalletGetResponse { /** * HTTP response details @@ -4221,7 +4221,7 @@ struct TALER_MERCHANT_TipWalletGetResponse { /** - * when the tip will expire + * when the reward will expire */ struct GNUNET_TIME_Timestamp expiration; @@ -4231,12 +4231,12 @@ struct TALER_MERCHANT_TipWalletGetResponse const char *exchange_url; /** - * URL where the wallet should navigate after withdrawing the tip. + * URL where the wallet should navigate after withdrawing the reward. */ const char *next_url; /** - * total amount still available for the tip + * total amount still available for the reward */ struct TALER_Amount amount_remaining; } ok; @@ -4246,55 +4246,55 @@ struct TALER_MERCHANT_TipWalletGetResponse /** - * Callback to process a GET /tips/$TIP_ID request + * Callback to process a GET /rewards/$REWARD_ID request * * @param cls closure * @param wgr response details */ typedef void -(*TALER_MERCHANT_TipWalletGetCallback) ( +(*TALER_MERCHANT_RewardWalletGetCallback) ( void *cls, - const struct TALER_MERCHANT_TipWalletGetResponse *wgr); + const struct TALER_MERCHANT_RewardWalletGetResponse *wgr); /** - * Issue a GET /tips/$TIP_ID (public variant) request to the backend. Returns - * information needed to pick up a tip. + * Issue a GET /rewards/$REWARD_ID (public variant) request to the backend. Returns + * information needed to pick up a reward. * * @param ctx execution context * @param backend_url base URL of the merchant backend - * @param tip_id which tip should we query + * @param reward_id which reward should we query * @param cb function to call with the result * @param cb_cls closure for @a cb * @return handle for this operation, NULL upon errors */ -struct TALER_MERCHANT_TipWalletGetHandle * -TALER_MERCHANT_wallet_tip_get ( +struct TALER_MERCHANT_RewardWalletGetHandle * +TALER_MERCHANT_wallet_reward_get ( struct GNUNET_CURL_Context *ctx, const char *backend_url, - const struct TALER_TipIdentifierP *tip_id, - TALER_MERCHANT_TipWalletGetCallback cb, + const struct TALER_RewardIdentifierP *reward_id, + TALER_MERCHANT_RewardWalletGetCallback cb, void *cb_cls); /** - * Cancel a GET /tips/$TIP_ID request. + * Cancel a GET /rewards/$REWARD_ID request. * * @param[in] tgh handle to the request to be canceled */ void -TALER_MERCHANT_wallet_tip_get_cancel ( - struct TALER_MERCHANT_TipWalletGetHandle *tgh); +TALER_MERCHANT_wallet_reward_get_cancel ( + struct TALER_MERCHANT_RewardWalletGetHandle *tgh); /** - * Handle for a GET /private/tips/$TIP_ID (private variant) operation. + * Handle for a GET /private/rewards/$REWARD_ID (private variant) operation. */ -struct TALER_MERCHANT_TipMerchantGetHandle; +struct TALER_MERCHANT_RewardMerchantGetHandle; /** - * Summary information for a tip pickup. + * Summary information for a reward pickup. */ struct TALER_MERCHANT_PickupDetail { @@ -4316,9 +4316,9 @@ struct TALER_MERCHANT_PickupDetail /** - * Details returned about a tip by the merchant. + * Details returned about a reward by the merchant. */ -struct TALER_MERCHANT_TipStatusResponse +struct TALER_MERCHANT_RewardStatusResponse { /** * HTTP status of the response. @@ -4338,7 +4338,7 @@ struct TALER_MERCHANT_TipStatusResponse { /** - * Amount that was authorized under this tip + * Amount that was authorized under this reward */ struct TALER_Amount total_authorized; @@ -4348,17 +4348,17 @@ struct TALER_MERCHANT_TipStatusResponse struct TALER_Amount total_picked_up; /** - * The reason given for the tip + * The reason given for the reward */ const char *reason; /** - * Time when the tip will expire + * Time when the reward will expire */ struct GNUNET_TIME_Timestamp expiration; /** - * reserve which is funding this tip + * reserve which is funding this reward */ struct TALER_ReservePublicKeyP reserve_pub; @@ -4368,7 +4368,7 @@ struct TALER_MERCHANT_TipStatusResponse unsigned int pickups_length; /** - * array of pickup operations performed for this tip + * array of pickup operations performed for this reward */ struct TALER_MERCHANT_PickupDetail *pickups; } ok; @@ -4379,24 +4379,24 @@ struct TALER_MERCHANT_TipStatusResponse /** - * Callback to process a GET /private/tips/$TIP_ID request + * Callback to process a GET /private/rewards/$REWARD_ID request * * @param cls closure * @param tsr response details */ typedef void -(*TALER_MERCHANT_TipMerchantGetCallback) ( +(*TALER_MERCHANT_RewardMerchantGetCallback) ( void *cls, - const struct TALER_MERCHANT_TipStatusResponse *tsr); + const struct TALER_MERCHANT_RewardStatusResponse *tsr); /** - * Issue a GET /private/tips/$TIP_ID (private variant) request to the backend. - * Returns information needed to pick up a tip. + * Issue a GET /private/rewards/$REWARD_ID (private variant) request to the backend. + * Returns information needed to pick up a reward. * * @param ctx execution context * @param backend_url base URL of the merchant backend - * @param tip_id which tip should we query + * @param reward_id which reward should we query * @param min_pick_up minimum amount picked up to notify about * @param lp_timeout how long to wait for @a min_pick_up to be exceeded * @param pickups whether to fetch associated pickups @@ -4404,61 +4404,61 @@ typedef void * @param cb_cls closure for @a cb * @return handle for this operation, NULL upon errors */ -struct TALER_MERCHANT_TipMerchantGetHandle * -TALER_MERCHANT_merchant_tip_get ( +struct TALER_MERCHANT_RewardMerchantGetHandle * +TALER_MERCHANT_merchant_reward_get ( struct GNUNET_CURL_Context *ctx, const char *backend_url, - const struct TALER_TipIdentifierP *tip_id, + const struct TALER_RewardIdentifierP *reward_id, const struct TALER_Amount *min_pick_up, struct GNUNET_TIME_Relative lp_timeout, bool pickups, - TALER_MERCHANT_TipMerchantGetCallback cb, + TALER_MERCHANT_RewardMerchantGetCallback cb, void *cb_cls); /** - * Cancel a GET /private/tips/$TIP_ID request. + * Cancel a GET /private/rewards/$REWARD_ID request. * * @param[in] tgh handle to the request to be canceled */ void -TALER_MERCHANT_merchant_tip_get_cancel ( - struct TALER_MERCHANT_TipMerchantGetHandle *tgh); +TALER_MERCHANT_merchant_reward_get_cancel ( + struct TALER_MERCHANT_RewardMerchantGetHandle *tgh); /** - * Handle for a GET /private/tips request. + * Handle for a GET /private/rewards request. */ -struct TALER_MERCHANT_TipsGetHandle; +struct TALER_MERCHANT_RewardsGetHandle; /** - * Database entry information of a tip. + * Database entry information of a reward. */ -struct TALER_MERCHANT_TipEntry +struct TALER_MERCHANT_RewardEntry { /** - * Row number of the tip in the database. + * Row number of the reward in the database. */ uint64_t row_id; /** - * Identifier for the tip. + * Identifier for the reward. */ - struct TALER_TipIdentifierP tip_id; + struct TALER_RewardIdentifierP reward_id; /** - * Total value of the tip (including fees). + * Total value of the reward (including fees). */ - struct TALER_Amount tip_amount; + struct TALER_Amount reward_amount; }; /** - * Response to a GET /private/tips request. + * Response to a GET /private/rewards request. */ -struct TALER_MERCHANT_TipsGetResponse +struct TALER_MERCHANT_RewardsGetResponse { /** * HTTP response details @@ -4477,14 +4477,14 @@ struct TALER_MERCHANT_TipsGetResponse struct { /** - * length of the @e tips array + * length of the @e rewards array */ - unsigned int tips_length; + unsigned int rewards_length; /** - * the array of tips + * the array of rewards */ - const struct TALER_MERCHANT_TipEntry *tips; + const struct TALER_MERCHANT_RewardEntry *rewards; } ok; @@ -4493,19 +4493,19 @@ struct TALER_MERCHANT_TipsGetResponse /** - * Callback to process a GET /private/tips request. + * Callback to process a GET /private/rewards request. * * @param cls closure * @param tgr response details */ typedef void -(*TALER_MERCHANT_TipsGetCallback) ( +(*TALER_MERCHANT_RewardsGetCallback) ( void *cls, - const struct TALER_MERCHANT_TipsGetResponse *tgr); + const struct TALER_MERCHANT_RewardsGetResponse *tgr); /** - * Issue a GET /private/tips request to the backend. + * Issue a GET /private/rewards request to the backend. * * @param ctx execution context * @param backend_url base URL of the merchant backend @@ -4513,50 +4513,50 @@ typedef void * @param cb_cls closure for @a cb * @return handle for this operation, NULL upon errors */ -struct TALER_MERCHANT_TipsGetHandle * -TALER_MERCHANT_tips_get ( +struct TALER_MERCHANT_RewardsGetHandle * +TALER_MERCHANT_rewards_get ( struct GNUNET_CURL_Context *ctx, const char *backend_url, - TALER_MERCHANT_TipsGetCallback cb, + TALER_MERCHANT_RewardsGetCallback cb, void *cb_cls); /** - * Issue a GET /private/tips request with filters to the backend. + * Issue a GET /private/rewards request with filters to the backend. * * @param ctx execution context * @param backend_url base URL of the merchant backend - * @param expired yes for expired tips, no for unexpired tips, all for all tips + * @param expired yes for expired rewards, no for unexpired rewards, all for all rewards * @param limit number of results to return, negative for descending row id, positive for ascending * @param offset row id to start returning results from * @param cb function to call with the result * @param cb_cls closure for @a cb * @return handle for this operation, NULL upon errors */ -struct TALER_MERCHANT_TipsGetHandle * -TALER_MERCHANT_tips_get2 ( +struct TALER_MERCHANT_RewardsGetHandle * +TALER_MERCHANT_rewards_get2 ( struct GNUNET_CURL_Context *ctx, const char *backend_url, enum TALER_EXCHANGE_YesNoAll expired, int64_t limit, uint64_t offset, - TALER_MERCHANT_TipsGetCallback cb, + TALER_MERCHANT_RewardsGetCallback cb, void *cb_cls); /** - * Cancel a GET /private/tips request. + * Cancel a GET /private/rewards request. * * @param tgh the operation to cancel */ void -TALER_MERCHANT_tips_get_cancel (struct TALER_MERCHANT_TipsGetHandle *tgh); +TALER_MERCHANT_rewards_get_cancel (struct TALER_MERCHANT_RewardsGetHandle *tgh); /** - * Handle for a POST /tips/$TIP_ID/pickup operation. + * Handle for a POST /rewards/$REWARD_ID/pickup operation. */ -struct TALER_MERCHANT_TipPickupHandle; +struct TALER_MERCHANT_RewardPickupHandle; /** @@ -4598,14 +4598,14 @@ struct TALER_MERCHANT_PickupDetails /** - * Callback for a POST /tips/$TIP_ID/pickup request. Returns the result of + * Callback for a POST /rewards/$REWARD_ID/pickup request. Returns the result of * the operation. * * @param cls closure * @param pd HTTP response details */ typedef void -(*TALER_MERCHANT_TipPickupCallback) ( +(*TALER_MERCHANT_RewardPickupCallback) ( void *cls, const struct TALER_MERCHANT_PickupDetails *pd); @@ -4628,50 +4628,50 @@ struct TALER_MERCHANT_PlanchetData }; /** - * Issue a POST /tips/$TIP_ID/pickup request to the backend. Informs the - * backend that a customer wants to pick up a tip. + * Issue a POST /rewards/$REWARD_ID/pickup request to the backend. Informs the + * backend that a customer wants to pick up a reward. * * @param ctx execution context * @param exchange_url base URL of the exchange * @param backend_url base URL of the merchant backend - * @param tip_id unique identifier for the tip + * @param reward_id unique identifier for the reward * @param num_planchets number of planchets provided in @a pds - * @param planchets array of planchet secrets to be signed into existence for the tip + * @param planchets array of planchet secrets to be signed into existence for the reward * @param pickup_cb callback which will work the response gotten from the backend * @param pickup_cb_cls closure to pass to @a pickup_cb * @return handle for this operation, NULL upon errors */ -struct TALER_MERCHANT_TipPickupHandle * -TALER_MERCHANT_tip_pickup ( +struct TALER_MERCHANT_RewardPickupHandle * +TALER_MERCHANT_reward_pickup ( struct GNUNET_CURL_Context *ctx, const char *exchange_url, const char *backend_url, - const struct TALER_TipIdentifierP *tip_id, + const struct TALER_RewardIdentifierP *reward_id, unsigned int num_planchets, const struct TALER_MERCHANT_PlanchetData planchets[static num_planchets], - TALER_MERCHANT_TipPickupCallback pickup_cb, + TALER_MERCHANT_RewardPickupCallback pickup_cb, void *pickup_cb_cls); /** - * Cancel a pending /tips/$TIP_ID/pickup request + * Cancel a pending /rewards/$REWARD_ID/pickup request * * @param tph handle from the operation to cancel */ void -TALER_MERCHANT_tip_pickup_cancel (struct TALER_MERCHANT_TipPickupHandle *tph); +TALER_MERCHANT_reward_pickup_cancel (struct TALER_MERCHANT_RewardPickupHandle *tph); /** - * Handle for a low-level /tip-pickup operation (without unblinding). + * Handle for a low-level /reward-pickup operation (without unblinding). */ -struct TALER_MERCHANT_TipPickup2Handle; +struct TALER_MERCHANT_RewardPickup2Handle; /** - * Response for a POST /tips/$TIP_ID/pickup request. + * Response for a POST /rewards/$REWARD_ID/pickup request. */ -struct TALER_MERCHANT_TipPickup2Response +struct TALER_MERCHANT_RewardPickup2Response { /** * HTTP response details @@ -4707,50 +4707,50 @@ struct TALER_MERCHANT_TipPickup2Response /** - * Callback for a POST /tips/$TIP_ID/pickup request. Returns the result of + * Callback for a POST /rewards/$REWARD_ID/pickup request. Returns the result of * the operation. Note that the client MUST still do the unblinding. * * @param cls closure * @param tpr response details */ typedef void -(*TALER_MERCHANT_TipPickup2Callback) ( +(*TALER_MERCHANT_RewardPickup2Callback) ( void *cls, - const struct TALER_MERCHANT_TipPickup2Response *tpr); + const struct TALER_MERCHANT_RewardPickup2Response *tpr); /** - * Issue a POST /tips/$TIP_ID/pickup request to the backend. Informs the - * backend that a customer wants to pick up a tip. + * Issue a POST /rewards/$REWARD_ID/pickup request to the backend. Informs the + * backend that a customer wants to pick up a reward. * * @param ctx execution context * @param backend_url base URL of the merchant backend - * @param tip_id unique identifier for the tip + * @param reward_id unique identifier for the reward * @param num_planchets number of planchets provided in @a planchets - * @param planchets array of planchets to be signed into existence for the tip + * @param planchets array of planchets to be signed into existence for the reward * @param pickup_cb callback which will work the response gotten from the backend * @param pickup_cb_cls closure to pass to @a pickup_cb * @return handle for this operation, NULL upon errors */ -struct TALER_MERCHANT_TipPickup2Handle * -TALER_MERCHANT_tip_pickup2 ( +struct TALER_MERCHANT_RewardPickup2Handle * +TALER_MERCHANT_reward_pickup2 ( struct GNUNET_CURL_Context *ctx, const char *backend_url, - const struct TALER_TipIdentifierP *tip_id, + const struct TALER_RewardIdentifierP *reward_id, unsigned int num_planchets, const struct TALER_PlanchetDetail planchets[static num_planchets], - TALER_MERCHANT_TipPickup2Callback pickup_cb, + TALER_MERCHANT_RewardPickup2Callback pickup_cb, void *pickup_cb_cls); /** - * Cancel a pending /tip-pickup request. + * Cancel a pending /reward-pickup request. * * @param[in] tp handle from the operation to cancel */ void -TALER_MERCHANT_tip_pickup2_cancel ( - struct TALER_MERCHANT_TipPickup2Handle *tp); +TALER_MERCHANT_reward_pickup2_cancel ( + struct TALER_MERCHANT_RewardPickup2Handle *tp); /* ********************* /kyc ************************** */ diff --git a/src/include/taler_merchant_testing_lib.h b/src/include/taler_merchant_testing_lib.h @@ -1160,12 +1160,12 @@ TALER_TESTING_cmd_merchant_get_reserve (const char *label, * @param reserve_reference reference to a "POST /reserves" that provides the * information we are expecting. * @param ... NULL-terminated list of labels (const char *) of - * tip (commands) we expect to be returned in the list + * reward (commands) we expect to be returned in the list * (assuming @a http_code is #MHD_HTTP_OK) * @return the command. */ struct TALER_TESTING_Command -TALER_TESTING_cmd_merchant_get_reserve_with_tips (const char *label, +TALER_TESTING_cmd_merchant_get_reserve_with_rewards (const char *label, const char *merchant_url, unsigned int http_status, const char *reserve_reference, @@ -1224,40 +1224,40 @@ TALER_TESTING_cmd_merchant_purge_reserve (const char *label, /** - * Define a get tips CMD. + * Define a get rewards CMD. * * @param label the command label * @param merchant_url base URL of the merchant which will - * server the /tip-query request. + * server the /reward-query request. * @param http_status expected HTTP response code for the - * /tip-query request. + * /reward-query request. * @param ... NULL-terminated list of labels (const char *) of - * tip (commands) we expect to be returned in the list + * reward (commands) we expect to be returned in the list * (assuming @a http_code is #MHD_HTTP_OK) */ struct TALER_TESTING_Command -TALER_TESTING_cmd_get_tips (const char *label, +TALER_TESTING_cmd_get_rewards (const char *label, const char *merchant_url, unsigned int http_status, ...); /** - * Define a get tips CMD. + * Define a get rewards CMD. * * @param label the command label * @param merchant_url base URL of the merchant which will - * server the /tip-query request. + * server the /reward-query request. * @param http_status expected HTTP response code for the - * /tip-query request. + * /reward-query request. * @param offset row to start querying the database from. * @param limit how many rows to return (with direction). * @param ... NULL-terminated list of labels (const char *) of - * tip (commands) we expect to be returned in the list + * reward (commands) we expect to be returned in the list * (assuming @a http_code is #MHD_HTTP_OK) */ struct TALER_TESTING_Command -TALER_TESTING_cmd_get_tips2 (const char *label, +TALER_TESTING_cmd_get_rewards2 (const char *label, const char *merchant_url, uint64_t offset, int64_t limit, @@ -1266,90 +1266,90 @@ TALER_TESTING_cmd_get_tips2 (const char *label, /** - * Define a GET /private/tips/$TIP_ID CMD. + * Define a GET /private/rewards/$REWARD_ID CMD. * * @param label the command label * @param merchant_url base URL of the merchant which will * serve the request. - * @param tip_reference reference to a command that created a tip. + * @param reward_reference reference to a command that created a reward. * @param http_status expected HTTP response code for the request. */ struct TALER_TESTING_Command -TALER_TESTING_cmd_merchant_get_tip (const char *label, +TALER_TESTING_cmd_merchant_get_reward (const char *label, const char *merchant_url, - const char *tip_reference, + const char *reward_reference, unsigned int http_status); /** - * Define a GET /private/tips/$TIP_ID CMD. + * Define a GET /private/rewards/$REWARD_ID CMD. * * @param label the command label * @param merchant_url base URL of the merchant which will * serve the request. - * @param tip_reference reference to a command that created a tip. + * @param reward_reference reference to a command that created a reward. * @param http_status expected HTTP response code for the request. * @param ... NULL-terminated list of labels (const char *) of * pickup (commands) we expect to be returned in the list * (assuming @a http_code is #MHD_HTTP_OK) */ struct TALER_TESTING_Command -TALER_TESTING_cmd_merchant_get_tip_with_pickups (const char *label, +TALER_TESTING_cmd_merchant_get_reward_with_pickups (const char *label, const char *merchant_url, - const char *tip_reference, + const char *reward_reference, unsigned int http_status, ...); /** - * Define a GET /tips/$TIP_ID CMD. + * Define a GET /rewards/$REWARD_ID CMD. * * @param label the command label * @param merchant_url base URL of the merchant which will * serve the request. - * @param tip_reference reference to a command that created a tip. + * @param reward_reference reference to a command that created a reward. * @param http_status expected HTTP response code for the request. */ struct TALER_TESTING_Command -TALER_TESTING_cmd_wallet_get_tip (const char *label, +TALER_TESTING_cmd_wallet_get_reward (const char *label, const char *merchant_url, - const char *tip_reference, + const char *reward_reference, unsigned int http_status); /** - * Define a GET /tips/$TIP_ID CMD. + * Define a GET /rewards/$REWARD_ID CMD. * * @param label the command label * @param merchant_url base URL of the merchant which will * serve the request. - * @param tip_reference reference to a command that created a tip. + * @param reward_reference reference to a command that created a reward. * @param amount_remaining the balance remaining after pickups. * @param http_status expected HTTP response code for the request. */ struct TALER_TESTING_Command -TALER_TESTING_cmd_wallet_get_tip2 (const char *label, +TALER_TESTING_cmd_wallet_get_reward2 (const char *label, const char *merchant_url, - const char *tip_reference, + const char *reward_reference, const char *amount_remaining, unsigned int http_status); /** - * Create a /tip-authorize CMD. + * Create a /reward-authorize CMD. * * @param label this command label * @param merchant_url the base URL of the merchant that will - * serve the /tip-authorize request. + * serve the /reward-authorize request. * @param exchange_url the base URL of the exchange that owns - * the reserve from which the tip is going to be gotten. + * the reserve from which the reward is going to be gotten. * @param http_status the HTTP response code which is expected * for this operation. * @param justification human-readable justification for this - * tip authorization. - * @param amount the amount to authorize for tipping. + * reward authorization. + * @param amount the amount to authorize for rewardping. */ struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_authorize (const char *label, +TALER_TESTING_cmd_reward_authorize (const char *label, const char *merchant_url, const char *exchange_url, unsigned int http_status, @@ -1358,23 +1358,23 @@ TALER_TESTING_cmd_tip_authorize (const char *label, /** - * Create a /tip-authorize CMD. + * Create a /reward-authorize CMD. * * @param label this command label * @param merchant_url the base URL of the merchant that will - * serve the /tip-authorize request. + * serve the /reward-authorize request. * @param exchange_url the base URL of the exchange that owns - * the reserve from which the tip is going to be gotten. + * the reserve from which the reward is going to be gotten. * @param reserve_reference reference to a command that created * a reserve. * @param http_status the HTTP response code which is expected * for this operation. * @param justification human-readable justification for this - * tip authorization. - * @param amount the amount to authorize for tipping. + * reward authorization. + * @param amount the amount to authorize for rewardping. */ struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_authorize_from_reserve (const char *label, +TALER_TESTING_cmd_reward_authorize_from_reserve (const char *label, const char *merchant_url, const char *exchange_url, const char *reserve_reference, @@ -1384,23 +1384,23 @@ TALER_TESTING_cmd_tip_authorize_from_reserve (const char *label, /** - * Create a /tip-authorize CMD, specifying the Taler error code + * Create a /reward-authorize CMD, specifying the Taler error code * that is expected to be returned by the backend. * * @param label this command label * @param merchant_url the base URL of the merchant that will - * serve the /tip-authorize request. + * serve the /reward-authorize request. * @param exchange_url the base URL of the exchange that owns - * the reserve from which the tip is going to be gotten. + * the reserve from which the reward is going to be gotten. * @param http_status the HTTP response code which is expected * for this operation. * @param justification human-readable justification for this - * tip authorization. - * @param amount the amount to authorize for tipping. + * reward authorization. + * @param amount the amount to authorize for rewardping. * @param ec expected Taler-defined error code. */ struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_authorize_with_ec (const char *label, +TALER_TESTING_cmd_reward_authorize_with_ec (const char *label, const char *merchant_url, const char *exchange_url, unsigned int http_status, @@ -1410,25 +1410,25 @@ TALER_TESTING_cmd_tip_authorize_with_ec (const char *label, /** - * Create a /tip-authorize CMD, specifying the Taler error code + * Create a /reward-authorize CMD, specifying the Taler error code * that is expected to be returned by the backend. * * @param label this command label * @param merchant_url the base URL of the merchant that will - * serve the /tip-authorize request. + * serve the /reward-authorize request. * @param exchange_url the base URL of the exchange that owns - * the reserve from which the tip is going to be gotten. + * the reserve from which the reward is going to be gotten. * @param reserve_reference reference to a command that created * a reserve. * @param http_status the HTTP response code which is expected * for this operation. * @param justification human-readable justification for this - * tip authorization. - * @param amount the amount to authorize for tipping. + * reward authorization. + * @param amount the amount to authorize for rewardping. * @param ec expected Taler-defined error code. */ struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_authorize_from_reserve_with_ec ( +TALER_TESTING_cmd_reward_authorize_from_reserve_with_ec ( const char *label, const char *merchant_url, const char *exchange_url, @@ -1449,26 +1449,26 @@ TALER_TESTING_cmd_tip_authorize_from_reserve_with_ec ( * @return the command. */ struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_authorize_fake (const char *label); +TALER_TESTING_cmd_reward_authorize_fake (const char *label); /** - * Define a /tip-pickup CMD, equipped with the expected error + * Define a /reward-pickup CMD, equipped with the expected error * code. * * @param label the command label * @param merchant_url base URL of the backend which will serve - * the /tip-pickup request. + * the /reward-pickup request. * @param http_status expected HTTP response code. - * @param authorize_reference reference to a /tip-autorize CMD - * that offers a tip id to pick up. + * @param authorize_reference reference to a /reward-autorize CMD + * that offers a reward id to pick up. * @param amounts array of string-defined amounts that specifies - * which denominations will be accepted for tipping. + * which denominations will be accepted for rewardping. * @param ec expected Taler error code. * @return the command */ struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_pickup_with_ec (const char *label, +TALER_TESTING_cmd_reward_pickup_with_ec (const char *label, const char *merchant_url, unsigned int http_status, const char *authorize_reference, @@ -1476,20 +1476,20 @@ TALER_TESTING_cmd_tip_pickup_with_ec (const char *label, enum TALER_ErrorCode ec); /** - * Define a /tip-pickup CMD. + * Define a /reward-pickup CMD. * * @param label the command label * @param merchant_url base URL of the backend which will serve - * the /tip-pickup request. + * the /reward-pickup request. * @param http_status expected HTTP response code. - * @param authorize_reference reference to a /tip-autorize CMD - * that offers a tip id to pick up. + * @param authorize_reference reference to a /reward-autorize CMD + * that offers a reward id to pick up. * @param amounts array of string-defined amounts that specifies - * which denominations will be accepted for tipping. + * which denominations will be accepted for rewardping. * @return the command */ struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_pickup (const char *label, +TALER_TESTING_cmd_reward_pickup (const char *label, const char *merchant_url, unsigned int http_status, const char *authorize_reference, @@ -1889,7 +1889,7 @@ TALER_TESTING_cmd_checkserver2 (const char *label, // FIXME: rename: refund_entry->refund_detail #define TALER_MERCHANT_TESTING_SIMPLE_TRAITS(op) \ op (claim_nonce, const struct GNUNET_CRYPTO_EddsaPublicKey) \ - op (tip_id, const struct TALER_TipIdentifierP) \ + op (reward_id, const struct TALER_RewardIdentifierP) \ op (pickup_id, const struct TALER_PickupIdentifierP) \ op (instance_name, const char) \ op (instance_id, const char) \ diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h @@ -832,8 +832,8 @@ typedef void * @param merchant_initial_amount initial amount that the merchant claims to have filled the * reserve with * @param exchange_initial_amount initial amount that the exchange claims to have received - * @param pickup_amount total of tips that were picked up from this reserve - * @param committed_amount total of tips that the merchant committed to, but that were not + * @param pickup_amount total of rewards that were picked up from this reserve + * @param committed_amount total of rewards that the merchant committed to, but that were not * picked up yet * @param active true if the reserve is still active (we have the private key) */ @@ -869,22 +869,22 @@ typedef void /** - * Details about a tip. + * Details about a reward. */ -struct TALER_MERCHANTDB_TipDetails +struct TALER_MERCHANTDB_RewardDetails { /** - * ID of the tip. + * ID of the reward. */ - struct TALER_TipIdentifierP tip_id; + struct TALER_RewardIdentifierP reward_id; /** - * Total amount of the tip. + * Total amount of the reward. */ struct TALER_Amount total_amount; /** - * Reason given for granting the tip. + * Reason given for granting the reward. */ char *reason; }; @@ -921,14 +921,14 @@ typedef void * @param merchant_initial_amount initial amount that the merchant claims to have filled the * reserve with * @param exchange_initial_amount initial amount that the exchange claims to have received - * @param picked_up_amount total of tips that were picked up from this reserve - * @param committed_amount total of tips that the merchant committed to, but that were not + * @param picked_up_amount total of rewards that were picked up from this reserve + * @param committed_amount total of rewards that the merchant committed to, but that were not * picked up yet * @param active true if the reserve is still active (we have the private key) * @param master_pub master public key of the exchange * @param exchange_url base URL of the exchange hosting the reserve, NULL if not @a active - * @param tips_length length of the @a tips array - * @param tips information about the tips created by this reserve + * @param rewards_length length of the @a rewards array + * @param rewards information about the rewards created by this reserve */ typedef void (*TALER_MERCHANTDB_ReserveDetailsCallback)( @@ -942,22 +942,22 @@ typedef void bool active, const struct TALER_MasterPublicKeyP *master_pub, const char *exchange_url, - unsigned int tips_length, - const struct TALER_MERCHANTDB_TipDetails *tips); + unsigned int rewards_length, + const struct TALER_MERCHANTDB_RewardDetails *rewards); /** - * Typically called by `lookup_tips`. + * Typically called by `lookup_rewards`. * * @param cls closure - * @param row_id row of the tip in the database - * @param tip_id id of the tip - * @param amount amount of the tip + * @param row_id row of the reward in the database + * @param reward_id id of the reward + * @param amount amount of the reward */ typedef void -(*TALER_MERCHANTDB_TipsCallback)(void *cls, +(*TALER_MERCHANTDB_RewardsCallback)(void *cls, uint64_t row_id, - struct TALER_TipIdentifierP tip_id, + struct TALER_RewardIdentifierP reward_id, struct TALER_Amount amount); @@ -1070,7 +1070,7 @@ struct TALER_MERCHANTDB_Plugin * @param es specification of the event to listen for * @param timeout how long to wait for the event * @param cb function to call when the event happens, possibly - * multiple times (until cancel is invoked) + * mulrewardle times (until cancel is invoked) * @param cb_cls closure for @a cb * @return handle useful to cancel the listener */ @@ -2043,7 +2043,7 @@ struct TALER_MERCHANTDB_Plugin * Function called when some backoffice staff decides to award or * increase the refund on an existing contract. This function * MUST be called from within a transaction scope setup by the - * caller as it executes multiple SQL statements. + * caller as it executes mulrewardle SQL statements. * * @param cls closure * @param instance_id instance identifier @@ -2509,10 +2509,10 @@ struct TALER_MERCHANTDB_Plugin /** - * Add @a credit to a reserve to be used for tipping. Note that + * Add @a credit to a reserve to be used for rewardping. Note that * this function does not actually perform any wire transfers to * credit the reserve, it merely tells the merchant backend that - * a reserve now exists. This has to happen before tips can be + * a reserve now exists. This has to happen before rewards can be * authorized. * * @param cls closure, typically a connection to the db @@ -2539,7 +2539,7 @@ struct TALER_MERCHANTDB_Plugin /** * Confirms @a credit as the amount the exchange claims to have received and - * thus really 'activates' the reserve. This has to happen before tips can + * thus really 'activates' the reserve. This has to happen before rewards can * be authorized. * * @param cls closure, typically a connection to the db @@ -2599,7 +2599,7 @@ struct TALER_MERCHANTDB_Plugin * @param cls closure * @param instance_id instance to lookup payments for * @param reserve_pub public key of the reserve to inspect - * @param fetch_tips if true, also return information about tips + * @param fetch_rewards if true, also return information about rewards * @param cb function to call with reserve summary data * @param cb_cls closure for @a cb * @return transaction status @@ -2608,7 +2608,7 @@ struct TALER_MERCHANTDB_Plugin (*lookup_reserve)(void *cls, const char *instance_id, const struct TALER_ReservePublicKeyP *reserve_pub, - bool fetch_tips, + bool fetch_rewards, TALER_MERCHANTDB_ReserveDetailsCallback cb, void *cb_cls); @@ -2627,7 +2627,7 @@ struct TALER_MERCHANTDB_Plugin const struct TALER_ReservePublicKeyP *reserve_pub); /** - * Purge all information about a reserve (including tips from it). + * Purge all information about a reserve (including rewards from it). * * @param cls closure * @param instance_id instance to lookup payments for @@ -2641,22 +2641,22 @@ struct TALER_MERCHANTDB_Plugin /** - * Authorize a tip over @a amount from reserve @a reserve_pub. Remember - * the authorization under @a tip_id for later, together with the + * Authorize a reward over @a amount from reserve @a reserve_pub. Remember + * the authorization under @a reward_id for later, together with the * @a justification. * * @param cls closure, typically a connection to the db - * @param instance_id which instance should generate the tip + * @param instance_id which instance should generate the reward * @param reserve_pub which reserve is debited, NULL to pick one in the DB - * @param amount how high is the tip (with fees) - * @param justification why was the tip approved - * @param next_url where to send the URL post tip pickup - * @param[out] tip_id set to the unique ID for the tip - * @param[out] expiration set to when the tip expires + * @param amount how high is the reward (with fees) + * @param justification why was the reward approved + * @param next_url where to send the URL post reward pickup + * @param[out] reward_id set to the unique ID for the reward + * @param[out] expiration set to when the reward expires * @return transaction status, - * #TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_EXPIRED if the reserve is known but has expired - * #TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_NOT_FOUND if the reserve is not known - * #TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_INSUFFICIENT_FUNDS if the reserve has insufficient funds left + * #TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_EXPIRED if the reserve is known but has expired + * #TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_NOT_FOUND if the reserve is not known + * #TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_INSUFFICIENT_FUNDS if the reserve has insufficient funds left * #TALER_EC_GENERIC_DB_START_FAILED on hard DB errors * #TALER_EC_GENERIC_DB_FETCH_FAILED on hard DB errors * #TALER_EC_GENERIC_DB_STORE_FAILED on hard DB errors @@ -2665,13 +2665,13 @@ struct TALER_MERCHANTDB_Plugin * #TALER_EC_NONE upon success */ enum TALER_ErrorCode - (*authorize_tip)(void *cls, + (*authorize_reward)(void *cls, const char *instance_id, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_Amount *amount, const char *justification, const char *next_url, - struct TALER_TipIdentifierP *tip_id, + struct TALER_RewardIdentifierP *reward_id, struct GNUNET_TIME_Timestamp *expiration); @@ -2679,11 +2679,11 @@ struct TALER_MERCHANTDB_Plugin * Lookup pickup details for pickup @a pickup_id. * * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup tip details for - * @param tip_id which tip should we lookup details on + * @param instance_id which instance should we lookup reward details for + * @param reward_id which reward should we lookup details on * @param pickup_id which pickup should we lookup details on - * @param[out] exchange_url which exchange is the tip withdrawn from - * @param[out] reserve_priv private key the tip is withdrawn from (set if still available!) + * @param[out] exchange_url which exchange is the reward withdrawn from + * @param[out] reserve_priv private key the reward is withdrawn from (set if still available!) * @param sigs_length length of the @a sigs array * @param[out] sigs set to the (blind) signatures we have for this @a pickup_id, * those that are unavailable are left at NULL @@ -2692,7 +2692,7 @@ struct TALER_MERCHANTDB_Plugin enum GNUNET_DB_QueryStatus (*lookup_pickup)(void *cls, const char *instance_id, - const struct TALER_TipIdentifierP *tip_id, + const struct TALER_RewardIdentifierP *reward_id, const struct TALER_PickupIdentifierP *pickup_id, char **exchange_url, struct TALER_ReservePrivateKeyP *reserve_priv, @@ -2701,23 +2701,23 @@ struct TALER_MERCHANTDB_Plugin /** - * Lookup tip details for tip @a tip_id. + * Lookup reward details for reward @a reward_id. * * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup tip details for - * @param tip_id which tip should we lookup details on - * @param[out] total_authorized amount how high is the tip (with fees) - * @param[out] total_picked_up how much of the tip was so far picked up (with fees) - * @param[out] expiration set to when the tip expires + * @param instance_id which instance should we lookup reward details for + * @param reward_id which reward should we lookup details on + * @param[out] total_authorized amount how high is the reward (with fees) + * @param[out] total_picked_up how much of the reward was so far picked up (with fees) + * @param[out] expiration set to when the reward expires * @param[out] exchange_url set to the exchange URL where the reserve is - * @param[out] next_url set to the URL where the wallet should navigate to after getting the tip + * @param[out] next_url set to the URL where the wallet should navigate to after getting the reward * @param[out] reserve_priv set to private key of reserve to be debited * @return transaction status */ enum GNUNET_DB_QueryStatus - (*lookup_tip)(void *cls, + (*lookup_reward)(void *cls, const char *instance_id, - const struct TALER_TipIdentifierP *tip_id, + const struct TALER_RewardIdentifierP *reward_id, struct TALER_Amount *total_authorized, struct TALER_Amount *total_picked_up, struct GNUNET_TIME_Timestamp *expiration, @@ -2727,48 +2727,48 @@ struct TALER_MERCHANTDB_Plugin /** - * Lookup tips + * Lookup rewards * * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup tips for - * @param expired should we include expired tips? + * @param instance_id which instance should we lookup rewards for + * @param expired should we include expired rewards? * @param limit maximum number of results to return, positive for * ascending row id, negative for descending * @param offset row id to start returning results from - * @param cb function to call with tip data + * @param cb function to call with reward data * @param cb_cls closure for @a cb * @return transaction status */ enum GNUNET_DB_QueryStatus - (*lookup_tips)(void *cls, + (*lookup_rewards)(void *cls, const char *instance_id, enum TALER_EXCHANGE_YesNoAll expired, int64_t limit, uint64_t offset, - TALER_MERCHANTDB_TipsCallback cb, + TALER_MERCHANTDB_RewardsCallback cb, void *cb_cls); /** - * Lookup tip details for tip @a tip_id. + * Lookup reward details for reward @a reward_id. * * @param cls closure, typically a connection to the db - * @param instance_id which instance should we lookup tip details for - * @param tip_id which tip should we lookup details on + * @param instance_id which instance should we lookup reward details for + * @param reward_id which reward should we lookup details on * @param fpu should we fetch details about individual pickups - * @param[out] total_authorized amount how high is the tip (with fees) - * @param[out] total_picked_up how much of the tip was so far picked up (with fees) - * @param[out] justification why was the tip approved - * @param[out] expiration set to when the tip expires + * @param[out] total_authorized amount how high is the reward (with fees) + * @param[out] total_picked_up how much of the reward was so far picked up (with fees) + * @param[out] justification why was the reward approved + * @param[out] expiration set to when the reward expires * @param[out] reserve_pub set to which reserve is debited * @param[out] pickups_length set to the length of @e pickups * @param[out] pickups if @a fpu is true, set to details about the pickup operations * @return transaction status */ enum GNUNET_DB_QueryStatus - (*lookup_tip_details)(void *cls, + (*lookup_reward_details)(void *cls, const char *instance_id, - const struct TALER_TipIdentifierP *tip_id, + const struct TALER_RewardIdentifierP *reward_id, bool fpu, struct TALER_Amount *total_authorized, struct TALER_Amount *total_picked_up, @@ -2780,15 +2780,15 @@ struct TALER_MERCHANTDB_Plugin /** - * Insert details about a tip pickup operation. The @a total_picked_up - * UPDATES the total amount under the @a tip_id, while the @a total_requested + * Insert details about a reward pickup operation. The @a total_picked_up + * UPDATES the total amount under the @a reward_id, while the @a total_requested * is the amount to be associated with this @a pickup_id. * While there is usually only one pickup event that picks up the entire * amount, our schema allows for wallets to pick up the amount incrementally - * over multiple pick up operations. + * over mulrewardle pick up operations. * * @param cls closure, typically a connection to the db - * @param tip_id the unique ID for the tip + * @param reward_id the unique ID for the reward * @param total_picked_up how much was picked up overall at this * point (includes @a total_requested) * @param pickup_id unique ID for the operation @@ -2800,7 +2800,7 @@ struct TALER_MERCHANTDB_Plugin enum GNUNET_DB_QueryStatus (*insert_pickup)(void *cls, const char *instance_id, - const struct TALER_TipIdentifierP *tip_id, + const struct TALER_RewardIdentifierP *reward_id, const struct TALER_Amount *total_picked_up, const struct TALER_PickupIdentifierP *pickup_id, const struct TALER_Amount *total_requested); @@ -2808,7 +2808,7 @@ struct TALER_MERCHANTDB_Plugin /** * Insert blind signature obtained from the exchange during a - * tip pickup operation. + * reward pickup operation. * * @param cls closure, typically a connection to the db * @param pickup_id unique ID for the operation diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am @@ -33,7 +33,7 @@ libtalermerchant_la_SOURCES = \ merchant_api_get_products.c \ merchant_api_get_reserve.c \ merchant_api_get_reserves.c \ - merchant_api_get_tips.c \ + merchant_api_get_rewards.c \ merchant_api_get_transfers.c \ merchant_api_get_template.c \ merchant_api_get_templates.c \ @@ -41,7 +41,7 @@ libtalermerchant_la_SOURCES = \ merchant_api_get_webhooks.c \ merchant_api_lock_product.c \ merchant_api_merchant_get_order.c \ - merchant_api_merchant_get_tip.c \ + merchant_api_merchant_get_reward.c \ merchant_api_patch_instance.c \ merchant_api_patch_order_forget.c \ merchant_api_patch_product.c \ @@ -62,10 +62,10 @@ libtalermerchant_la_SOURCES = \ merchant_api_post_templates.c \ merchant_api_post_using_templates.c \ merchant_api_post_webhooks.c \ - merchant_api_tip_authorize.c \ - merchant_api_tip_pickup.c \ - merchant_api_tip_pickup2.c \ - merchant_api_wallet_get_tip.c \ + merchant_api_reward_authorize.c \ + merchant_api_reward_pickup.c \ + merchant_api_reward_pickup2.c \ + merchant_api_wallet_get_reward.c \ merchant_api_wallet_get_order.c \ merchant_api_wallet_post_order_refund.c diff --git a/src/lib/merchant_api_get_config.c b/src/lib/merchant_api_get_config.c @@ -34,7 +34,7 @@ * Which version of the Taler protocol is implemented * by this library? Used to determine compatibility. */ -#define MERCHANT_PROTOCOL_CURRENT 4 +#define MERCHANT_PROTOCOL_CURRENT 5 /** * How many configs are we backwards compatible with? diff --git a/src/lib/merchant_api_get_reserve.c b/src/lib/merchant_api_get_reserve.c @@ -96,7 +96,7 @@ handle_reserve_get_finished (void *cls, { struct TALER_MERCHANT_ReserveSummary *rs = &rgr.details.ok.rs; - const json_t *tips = NULL; + const json_t *rewards = NULL; const json_t *accounts = NULL; unsigned int accounts_len; struct GNUNET_JSON_Specification spec[] = { @@ -107,8 +107,8 @@ handle_reserve_get_finished (void *cls, GNUNET_JSON_spec_bool ("active", &rgr.details.ok.active), GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_array_const ("tips", - &tips), + GNUNET_JSON_spec_array_const ("rewards", + &rewards), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_array_const ("accounts", @@ -134,7 +134,7 @@ handle_reserve_get_finished (void *cls, GNUNET_JSON_spec_end () }; struct TALER_EXCHANGE_WireAccount *was = NULL; - struct TALER_MERCHANT_TipDetails *tds = NULL; + struct TALER_MERCHANT_RewardDetails *tds = NULL; if (GNUNET_OK != GNUNET_JSON_parse (json, @@ -169,20 +169,20 @@ handle_reserve_get_finished (void *cls, } } /* end 'have accounts' */ - if (NULL != tips) + if (NULL != rewards) { - size_t tds_length = json_array_size (tips); + size_t tds_length = json_array_size (rewards); bool ok = true; - json_t *tip; + json_t *reward; unsigned int i; tds = GNUNET_new_array (tds_length, - struct TALER_MERCHANT_TipDetails); - json_array_foreach (tips, i, tip) { - struct TALER_MERCHANT_TipDetails *td = &tds[i]; + struct TALER_MERCHANT_RewardDetails); + json_array_foreach (rewards, i, reward) { + struct TALER_MERCHANT_RewardDetails *td = &tds[i]; struct GNUNET_JSON_Specification ispec[] = { - GNUNET_JSON_spec_fixed_auto ("tip_id", - &td->tip_id), + GNUNET_JSON_spec_fixed_auto ("reward_id", + &td->reward_id), TALER_JSON_spec_amount_any ("total_amount", &td->amount), GNUNET_JSON_spec_string ("reason", @@ -191,7 +191,7 @@ handle_reserve_get_finished (void *cls, }; if (GNUNET_OK != - GNUNET_JSON_parse (tip, + GNUNET_JSON_parse (reward, ispec, NULL, NULL)) { @@ -208,10 +208,10 @@ handle_reserve_get_finished (void *cls, } else { - rgr.details.ok.tips = tds; - rgr.details.ok.tips_length = tds_length; + rgr.details.ok.rewards = tds; + rgr.details.ok.rewards_length = tds_length; } - } /* end 'have tips' */ + } /* end 'have rewards' */ rgh->cb (rgh->cb_cls, &rgr); @@ -258,7 +258,7 @@ struct TALER_MERCHANT_ReserveGetHandle * TALER_MERCHANT_reserve_get (struct GNUNET_CURL_Context *ctx, const char *backend_url, const struct TALER_ReservePublicKeyP *reserve_pub, - bool fetch_tips, + bool fetch_rewards, TALER_MERCHANT_ReserveGetCallback cb, void *cb_cls) { @@ -285,8 +285,8 @@ TALER_MERCHANT_reserve_get (struct GNUNET_CURL_Context *ctx, res_str); rgh->url = TALER_url_join (backend_url, arg_str, - "tips", - fetch_tips ? "yes" : "no", + "rewards", + fetch_rewards ? "yes" : "no", NULL); } if (NULL == rgh->url) diff --git a/src/lib/merchant_api_get_rewards.c b/src/lib/merchant_api_get_rewards.c @@ -0,0 +1,288 @@ +/* + This file is part of TALER + Copyright (C) 2020-2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING.LGPL. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file merchant_api_get_rewards.c + * @brief Implementation of the GET /private/rewards request of the merchant's HTTP API + * @author Jonathan Buchanan + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_curl_lib.h> +#include "taler_merchant_service.h" +#include "merchant_api_curl_defaults.h" +#include <taler/taler_json_lib.h> +#include <taler/taler_signatures.h> + + +/** + * Handle for a GET /private/rewards operation. + */ +struct TALER_MERCHANT_RewardsGetHandle +{ + /** + * The url for this request. + */ + char *url; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Function to call with the result. + */ + TALER_MERCHANT_RewardsGetCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Reference to the execution context. + */ + struct GNUNET_CURL_Context *ctx; + +}; + + +/** + * Parse reward information from @a ia. + * + * @param ia JSON array (or NULL!) reward order data + * @param[in] tgr response to complete + * @param tgh operation handle + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +parse_rewards (const json_t *ia, + struct TALER_MERCHANT_RewardsGetResponse *tgr, + struct TALER_MERCHANT_RewardsGetHandle *tgh) +{ + unsigned int tes_len = json_array_size (ia); + struct TALER_MERCHANT_RewardEntry tes[GNUNET_NZL (tes_len)]; + size_t index; + json_t *value; + + json_array_foreach (ia, index, value) { + struct TALER_MERCHANT_RewardEntry *ie = &tes[index]; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_uint64 ("row_id", + &ie->row_id), + GNUNET_JSON_spec_fixed_auto ("reward_id", + &ie->reward_id), + TALER_JSON_spec_amount_any ("reward_amount", + &ie->reward_amount), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (value, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + } + tgr->details.ok.rewards_length = tes_len; + tgr->details.ok.rewards = tes; + tgh->cb (tgh->cb_cls, + tgr); + tgh->cb = NULL; /* just to be sure */ + return GNUNET_OK; +} + + +/** + * Function called when we're done processing the + * HTTP GET /private/rewards request. + * + * @param cls the `struct TALER_MERCHANT_RewardsGetHandle` + * @param response_code HTTP response code, 0 on error + * @param response response body, NULL if not in JSON + */ +static void +handle_get_rewards_finished (void *cls, + long response_code, + const void *response) +{ + struct TALER_MERCHANT_RewardsGetHandle *tgh = cls; + const json_t *json = response; + struct TALER_MERCHANT_RewardsGetResponse tgr = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json + }; + + tgh->job = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got /private/rewards response with status code %u\n", + (unsigned int) response_code); + switch (response_code) + { + case MHD_HTTP_OK: + { + const json_t *rewards; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_array_const ("rewards", + &rewards), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json, + spec, + NULL, NULL)) + { + tgr.hr.http_status = 0; + tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + } + if (GNUNET_OK == + parse_rewards (rewards, + &tgr, + tgh)) + { + TALER_MERCHANT_rewards_get_cancel (tgh); + return; + } + tgr.hr.http_status = 0; + tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + } + case MHD_HTTP_UNAUTHORIZED: + tgr.hr.ec = TALER_JSON_get_error_code (json); + tgr.hr.hint = TALER_JSON_get_error_hint (json); + /* Nothing really to verify, merchant says we need to authenticate. */ + break; + default: + /* unexpected response code */ + tgr.hr.ec = TALER_JSON_get_error_code (json); + tgr.hr.hint = TALER_JSON_get_error_hint (json); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d\n", + (unsigned int) response_code, + (int) tgr.hr.ec); + break; + } + tgh->cb (tgh->cb_cls, + &tgr); + TALER_MERCHANT_rewards_get_cancel (tgh); +} + + +struct TALER_MERCHANT_RewardsGetHandle * +TALER_MERCHANT_rewards_get ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + TALER_MERCHANT_RewardsGetCallback cb, + void *cb_cls) +{ + return TALER_MERCHANT_rewards_get2 (ctx, + backend_url, + TALER_EXCHANGE_YNA_NO, + -20, + UINT64_MAX, + cb, + cb_cls); +} + + +struct TALER_MERCHANT_RewardsGetHandle * +TALER_MERCHANT_rewards_get2 (struct GNUNET_CURL_Context *ctx, + const char *backend_url, + enum TALER_EXCHANGE_YesNoAll expired, + int64_t limit, + uint64_t offset, + TALER_MERCHANT_RewardsGetCallback cb, + void *cb_cls) +{ + struct TALER_MERCHANT_RewardsGetHandle *tgh; + CURL *eh; + + GNUNET_assert (NULL != backend_url); + if (0 == limit) + { + GNUNET_break (0); + return NULL; + } + tgh = GNUNET_new (struct TALER_MERCHANT_RewardsGetHandle); + tgh->ctx = ctx; + tgh->cb = cb; + tgh->cb_cls = cb_cls; + + /* build tgh->url with the various optional arguments */ + { + char cbuf[30]; + char lbuf[30]; + bool have_offset; + + GNUNET_snprintf (lbuf, + sizeof (lbuf), + "%lld", + (long long) limit); + + if (limit > 0) + have_offset = (0 != offset); + else + have_offset = (UINT64_MAX != offset); + GNUNET_snprintf (cbuf, + sizeof (cbuf), + "%llu", + (unsigned long long) offset); + tgh->url = TALER_url_join (backend_url, + "private/rewards", + "expired", + (TALER_EXCHANGE_YNA_ALL != expired) + ? TALER_yna_to_string (expired) + : NULL, + "offset", (have_offset) ? cbuf : NULL, + "limit", (-20 != limit) ? lbuf : NULL, + NULL); + } + if (NULL == tgh->url) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not construct request URL.\n"); + GNUNET_free (tgh); + return NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requesting URL '%s'\n", + tgh->url); + eh = TALER_MERCHANT_curl_easy_get_ (tgh->url); + tgh->job = GNUNET_CURL_job_add (ctx, + eh, + &handle_get_rewards_finished, + tgh); + return tgh; +} + + +void +TALER_MERCHANT_rewards_get_cancel ( + struct TALER_MERCHANT_RewardsGetHandle *tgh) +{ + if (NULL != tgh->job) + GNUNET_CURL_job_cancel (tgh->job); + GNUNET_free (tgh->url); + GNUNET_free (tgh); +} diff --git a/src/lib/merchant_api_get_tips.c b/src/lib/merchant_api_get_tips.c @@ -1,288 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2020-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software - Foundation; either version 2.1, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License along with - TALER; see the file COPYING.LGPL. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file merchant_api_get_tips.c - * @brief Implementation of the GET /private/tips request of the merchant's HTTP API - * @author Jonathan Buchanan - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_merchant_service.h" -#include "merchant_api_curl_defaults.h" -#include <taler/taler_json_lib.h> -#include <taler/taler_signatures.h> - - -/** - * Handle for a GET /private/tips operation. - */ -struct TALER_MERCHANT_TipsGetHandle -{ - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Function to call with the result. - */ - TALER_MERCHANT_TipsGetCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Reference to the execution context. - */ - struct GNUNET_CURL_Context *ctx; - -}; - - -/** - * Parse tip information from @a ia. - * - * @param ia JSON array (or NULL!) tip order data - * @param[in] tgr response to complete - * @param tgh operation handle - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -parse_tips (const json_t *ia, - struct TALER_MERCHANT_TipsGetResponse *tgr, - struct TALER_MERCHANT_TipsGetHandle *tgh) -{ - unsigned int tes_len = json_array_size (ia); - struct TALER_MERCHANT_TipEntry tes[GNUNET_NZL (tes_len)]; - size_t index; - json_t *value; - - json_array_foreach (ia, index, value) { - struct TALER_MERCHANT_TipEntry *ie = &tes[index]; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_uint64 ("row_id", - &ie->row_id), - GNUNET_JSON_spec_fixed_auto ("tip_id", - &ie->tip_id), - TALER_JSON_spec_amount_any ("tip_amount", - &ie->tip_amount), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (value, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - } - tgr->details.ok.tips_length = tes_len; - tgr->details.ok.tips = tes; - tgh->cb (tgh->cb_cls, - tgr); - tgh->cb = NULL; /* just to be sure */ - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP GET /private/tips request. - * - * @param cls the `struct TALER_MERCHANT_TipsGetHandle` - * @param response_code HTTP response code, 0 on error - * @param response response body, NULL if not in JSON - */ -static void -handle_get_tips_finished (void *cls, - long response_code, - const void *response) -{ - struct TALER_MERCHANT_TipsGetHandle *tgh = cls; - const json_t *json = response; - struct TALER_MERCHANT_TipsGetResponse tgr = { - .hr.http_status = (unsigned int) response_code, - .hr.reply = json - }; - - tgh->job = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got /private/tips response with status code %u\n", - (unsigned int) response_code); - switch (response_code) - { - case MHD_HTTP_OK: - { - const json_t *tips; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_array_const ("tips", - &tips), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - tgr.hr.http_status = 0; - tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - } - if (GNUNET_OK == - parse_tips (tips, - &tgr, - tgh)) - { - TALER_MERCHANT_tips_get_cancel (tgh); - return; - } - tgr.hr.http_status = 0; - tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - } - case MHD_HTTP_UNAUTHORIZED: - tgr.hr.ec = TALER_JSON_get_error_code (json); - tgr.hr.hint = TALER_JSON_get_error_hint (json); - /* Nothing really to verify, merchant says we need to authenticate. */ - break; - default: - /* unexpected response code */ - tgr.hr.ec = TALER_JSON_get_error_code (json); - tgr.hr.hint = TALER_JSON_get_error_hint (json); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d\n", - (unsigned int) response_code, - (int) tgr.hr.ec); - break; - } - tgh->cb (tgh->cb_cls, - &tgr); - TALER_MERCHANT_tips_get_cancel (tgh); -} - - -struct TALER_MERCHANT_TipsGetHandle * -TALER_MERCHANT_tips_get ( - struct GNUNET_CURL_Context *ctx, - const char *backend_url, - TALER_MERCHANT_TipsGetCallback cb, - void *cb_cls) -{ - return TALER_MERCHANT_tips_get2 (ctx, - backend_url, - TALER_EXCHANGE_YNA_NO, - -20, - UINT64_MAX, - cb, - cb_cls); -} - - -struct TALER_MERCHANT_TipsGetHandle * -TALER_MERCHANT_tips_get2 (struct GNUNET_CURL_Context *ctx, - const char *backend_url, - enum TALER_EXCHANGE_YesNoAll expired, - int64_t limit, - uint64_t offset, - TALER_MERCHANT_TipsGetCallback cb, - void *cb_cls) -{ - struct TALER_MERCHANT_TipsGetHandle *tgh; - CURL *eh; - - GNUNET_assert (NULL != backend_url); - if (0 == limit) - { - GNUNET_break (0); - return NULL; - } - tgh = GNUNET_new (struct TALER_MERCHANT_TipsGetHandle); - tgh->ctx = ctx; - tgh->cb = cb; - tgh->cb_cls = cb_cls; - - /* build tgh->url with the various optional arguments */ - { - char cbuf[30]; - char lbuf[30]; - bool have_offset; - - GNUNET_snprintf (lbuf, - sizeof (lbuf), - "%lld", - (long long) limit); - - if (limit > 0) - have_offset = (0 != offset); - else - have_offset = (UINT64_MAX != offset); - GNUNET_snprintf (cbuf, - sizeof (cbuf), - "%llu", - (unsigned long long) offset); - tgh->url = TALER_url_join (backend_url, - "private/tips", - "expired", - (TALER_EXCHANGE_YNA_ALL != expired) - ? TALER_yna_to_string (expired) - : NULL, - "offset", (have_offset) ? cbuf : NULL, - "limit", (-20 != limit) ? lbuf : NULL, - NULL); - } - if (NULL == tgh->url) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not construct request URL.\n"); - GNUNET_free (tgh); - return NULL; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Requesting URL '%s'\n", - tgh->url); - eh = TALER_MERCHANT_curl_easy_get_ (tgh->url); - tgh->job = GNUNET_CURL_job_add (ctx, - eh, - &handle_get_tips_finished, - tgh); - return tgh; -} - - -void -TALER_MERCHANT_tips_get_cancel ( - struct TALER_MERCHANT_TipsGetHandle *tgh) -{ - if (NULL != tgh->job) - GNUNET_CURL_job_cancel (tgh->job); - GNUNET_free (tgh->url); - GNUNET_free (tgh); -} diff --git a/src/lib/merchant_api_merchant_get_reward.c b/src/lib/merchant_api_merchant_get_reward.c @@ -0,0 +1,302 @@ +/* + This file is part of TALER + Copyright (C) 2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING.LGPL. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file merchant_api_merchant_get_reward.c + * @brief Implementation of the GET /private/rewards/$REWARD_ID request of the merchant's HTTP API + * @author Jonathan Buchanan + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_curl_lib.h> +#include "taler_merchant_service.h" +#include "merchant_api_common.h" +#include "merchant_api_curl_defaults.h" +#include <taler/taler_json_lib.h> +#include <taler/taler_signatures.h> + + +struct TALER_MERCHANT_RewardMerchantGetHandle +{ + /** + * The url for this request. + */ + char *url; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Function to call with the result. + */ + TALER_MERCHANT_RewardMerchantGetCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Reference to the execution context. + */ + struct GNUNET_CURL_Context *ctx; +}; + + +static enum GNUNET_GenericReturnValue +parse_pickups (const json_t *pa, + struct TALER_MERCHANT_RewardStatusResponse *tsr, + struct TALER_MERCHANT_RewardMerchantGetHandle *tgh) +{ + unsigned int pa_len = json_array_size (pa); + struct TALER_MERCHANT_PickupDetail pickups[pa_len]; + size_t index; + json_t *value; + + json_array_foreach (pa, index, value) + { + struct TALER_MERCHANT_PickupDetail *pickup = &pickups[index]; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("pickup_id", + &pickup->pickup_id), + GNUNET_JSON_spec_uint64 ("num_planchets", + &pickup->num_planchets), + TALER_JSON_spec_amount_any ("requested_amount", + &pickup->requested_amount), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (value, + spec, + NULL, + NULL)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + } + tsr->details.ok.pickups_length = pa_len; + tsr->details.ok.pickups = pickups; + tgh->cb (tgh->cb_cls, + tsr); + return GNUNET_OK; +} + + +/** + * Function called when we're done processing the + * GET /private/rewards/$REWARD_ID request. + * + * @param cls the `struct TALER_MERCHANT_RewardMerchantGetHandle` + * @param response_code HTTP response code, 0 on error + * @param response response body, NULL if not in JSON + */ +static void +handle_merchant_reward_get_finished (void *cls, + long response_code, + const void *response) +{ + struct TALER_MERCHANT_RewardMerchantGetHandle *tgh = cls; + const json_t *json = response; + struct TALER_MERCHANT_RewardStatusResponse tsr = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json + }; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got /private/rewards/$REWARD_ID response with status code %u\n", + (unsigned int) response_code); + tgh->job = NULL; + switch (response_code) + { + case MHD_HTTP_OK: + { + struct GNUNET_JSON_Specification spec[] = { + TALER_JSON_spec_amount_any ("total_authorized", + &tsr.details.ok.total_authorized), + TALER_JSON_spec_amount_any ("total_picked_up", + &tsr.details.ok.total_picked_up), + GNUNET_JSON_spec_string ("reason", + &tsr.details.ok.reason), + GNUNET_JSON_spec_timestamp ("expiration", + &tsr.details.ok.expiration), + GNUNET_JSON_spec_fixed_auto ("reserve_pub", + &tsr.details.ok.reserve_pub), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json, + spec, + NULL, NULL)) + { + tsr.hr.http_status = 0; + tsr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + } + else + { + json_t *pickups = json_object_get (json, + "pickups"); + if (! json_is_array (pickups)) + { + tgh->cb (tgh->cb_cls, + &tsr); + TALER_MERCHANT_merchant_reward_get_cancel (tgh); + return; + } + if (GNUNET_OK == + parse_pickups (pickups, + &tsr, + tgh)) + { + GNUNET_JSON_parse_free (spec); + TALER_MERCHANT_merchant_reward_get_cancel (tgh); + return; + } + tsr.hr.http_status = 0; + tsr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + } + GNUNET_JSON_parse_free (spec); + break; + } + case MHD_HTTP_UNAUTHORIZED: + tsr.hr.ec = TALER_JSON_get_error_code (json); + tsr.hr.hint = TALER_JSON_get_error_hint (json); + /* Nothing really to verify, merchant says we need to authenticate. */ + break; + case MHD_HTTP_NOT_FOUND: + /* legal, can happen if instance or reward reserve is unknown */ + tsr.hr.ec = TALER_JSON_get_error_code (json); + tsr.hr.hint = TALER_JSON_get_error_hint (json); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + tsr.hr.ec = TALER_JSON_get_error_code (json); + tsr.hr.hint = TALER_JSON_get_error_hint (json); + break; + default: + /* unexpected response code */ + GNUNET_break_op (0); + TALER_MERCHANT_parse_error_details_ (json, + response_code, + &tsr.hr); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d\n", + (unsigned int) response_code, + (int) tsr.hr.ec); + break; + } + tgh->cb (tgh->cb_cls, + &tsr); + TALER_MERCHANT_merchant_reward_get_cancel (tgh); +} + + +struct TALER_MERCHANT_RewardMerchantGetHandle * +TALER_MERCHANT_merchant_reward_get (struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct TALER_RewardIdentifierP *reward_id, + const struct TALER_Amount *min_pick_up, + struct GNUNET_TIME_Relative lp_timeout, + bool pickups, + TALER_MERCHANT_RewardMerchantGetCallback cb, + void *cb_cls) +{ + struct TALER_MERCHANT_RewardMerchantGetHandle *tgh; + CURL *eh; + + GNUNET_assert (NULL != backend_url); + tgh = GNUNET_new (struct TALER_MERCHANT_RewardMerchantGetHandle); + tgh->ctx = ctx; + tgh->cb = cb; + tgh->cb_cls = cb_cls; + + { + char res_str[sizeof (*reward_id) * 2]; + char arg_str[sizeof (res_str) + 48]; + char timeout_str[32]; + char *end; + + end = GNUNET_STRINGS_data_to_string (reward_id, + sizeof (*reward_id), + res_str, + sizeof (res_str)); + *end = '\0'; + GNUNET_snprintf (arg_str, + sizeof (arg_str), + "private/rewards/%s", + res_str); + GNUNET_snprintf (timeout_str, + sizeof (timeout_str), + "%llu", + ((unsigned long long) + lp_timeout.rel_value_us + / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us)); + tgh->url = TALER_url_join (backend_url, + arg_str, + "pickups", + pickups + ? "yes" + : NULL, + "min_amount", + min_pick_up + ? TALER_amount2s (min_pick_up) + : NULL, + "timeout_ms", + GNUNET_TIME_relative_is_zero (lp_timeout) + ? NULL + : timeout_str, + NULL); + } + if (NULL == tgh->url) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not construct request URL.\n"); + GNUNET_free (tgh); + return NULL; + } + + eh = TALER_MERCHANT_curl_easy_get_ (tgh->url); + tgh->job = GNUNET_CURL_job_add (ctx, + eh, + &handle_merchant_reward_get_finished, + tgh); + return tgh; +} + + +void +TALER_MERCHANT_merchant_reward_get_cancel ( + struct TALER_MERCHANT_RewardMerchantGetHandle *tgh) +{ + if (NULL != tgh->job) + { + GNUNET_CURL_job_cancel (tgh->job); + tgh->job = NULL; + } + GNUNET_free (tgh->url); + GNUNET_free (tgh); +} + + +/* end of merchant_api_merchant_get_reward.c */ diff --git a/src/lib/merchant_api_merchant_get_tip.c b/src/lib/merchant_api_merchant_get_tip.c @@ -1,302 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software - Foundation; either version 2.1, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License along with - TALER; see the file COPYING.LGPL. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file merchant_api_merchant_get_tip.c - * @brief Implementation of the GET /private/tips/$TIP_ID request of the merchant's HTTP API - * @author Jonathan Buchanan - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_merchant_service.h" -#include "merchant_api_common.h" -#include "merchant_api_curl_defaults.h" -#include <taler/taler_json_lib.h> -#include <taler/taler_signatures.h> - - -struct TALER_MERCHANT_TipMerchantGetHandle -{ - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Function to call with the result. - */ - TALER_MERCHANT_TipMerchantGetCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Reference to the execution context. - */ - struct GNUNET_CURL_Context *ctx; -}; - - -static enum GNUNET_GenericReturnValue -parse_pickups (const json_t *pa, - struct TALER_MERCHANT_TipStatusResponse *tsr, - struct TALER_MERCHANT_TipMerchantGetHandle *tgh) -{ - unsigned int pa_len = json_array_size (pa); - struct TALER_MERCHANT_PickupDetail pickups[pa_len]; - size_t index; - json_t *value; - - json_array_foreach (pa, index, value) - { - struct TALER_MERCHANT_PickupDetail *pickup = &pickups[index]; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("pickup_id", - &pickup->pickup_id), - GNUNET_JSON_spec_uint64 ("num_planchets", - &pickup->num_planchets), - TALER_JSON_spec_amount_any ("requested_amount", - &pickup->requested_amount), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (value, - spec, - NULL, - NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - } - tsr->details.ok.pickups_length = pa_len; - tsr->details.ok.pickups = pickups; - tgh->cb (tgh->cb_cls, - tsr); - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * GET /private/tips/$TIP_ID request. - * - * @param cls the `struct TALER_MERCHANT_TipMerchantGetHandle` - * @param response_code HTTP response code, 0 on error - * @param response response body, NULL if not in JSON - */ -static void -handle_merchant_tip_get_finished (void *cls, - long response_code, - const void *response) -{ - struct TALER_MERCHANT_TipMerchantGetHandle *tgh = cls; - const json_t *json = response; - struct TALER_MERCHANT_TipStatusResponse tsr = { - .hr.http_status = (unsigned int) response_code, - .hr.reply = json - }; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got /private/tips/$TIP_ID response with status code %u\n", - (unsigned int) response_code); - tgh->job = NULL; - switch (response_code) - { - case MHD_HTTP_OK: - { - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount_any ("total_authorized", - &tsr.details.ok.total_authorized), - TALER_JSON_spec_amount_any ("total_picked_up", - &tsr.details.ok.total_picked_up), - GNUNET_JSON_spec_string ("reason", - &tsr.details.ok.reason), - GNUNET_JSON_spec_timestamp ("expiration", - &tsr.details.ok.expiration), - GNUNET_JSON_spec_fixed_auto ("reserve_pub", - &tsr.details.ok.reserve_pub), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - tsr.hr.http_status = 0; - tsr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - } - else - { - json_t *pickups = json_object_get (json, - "pickups"); - if (! json_is_array (pickups)) - { - tgh->cb (tgh->cb_cls, - &tsr); - TALER_MERCHANT_merchant_tip_get_cancel (tgh); - return; - } - if (GNUNET_OK == - parse_pickups (pickups, - &tsr, - tgh)) - { - GNUNET_JSON_parse_free (spec); - TALER_MERCHANT_merchant_tip_get_cancel (tgh); - return; - } - tsr.hr.http_status = 0; - tsr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - } - GNUNET_JSON_parse_free (spec); - break; - } - case MHD_HTTP_UNAUTHORIZED: - tsr.hr.ec = TALER_JSON_get_error_code (json); - tsr.hr.hint = TALER_JSON_get_error_hint (json); - /* Nothing really to verify, merchant says we need to authenticate. */ - break; - case MHD_HTTP_NOT_FOUND: - /* legal, can happen if instance or tip reserve is unknown */ - tsr.hr.ec = TALER_JSON_get_error_code (json); - tsr.hr.hint = TALER_JSON_get_error_hint (json); - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - tsr.hr.ec = TALER_JSON_get_error_code (json); - tsr.hr.hint = TALER_JSON_get_error_hint (json); - break; - default: - /* unexpected response code */ - GNUNET_break_op (0); - TALER_MERCHANT_parse_error_details_ (json, - response_code, - &tsr.hr); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d\n", - (unsigned int) response_code, - (int) tsr.hr.ec); - break; - } - tgh->cb (tgh->cb_cls, - &tsr); - TALER_MERCHANT_merchant_tip_get_cancel (tgh); -} - - -struct TALER_MERCHANT_TipMerchantGetHandle * -TALER_MERCHANT_merchant_tip_get (struct GNUNET_CURL_Context *ctx, - const char *backend_url, - const struct TALER_TipIdentifierP *tip_id, - const struct TALER_Amount *min_pick_up, - struct GNUNET_TIME_Relative lp_timeout, - bool pickups, - TALER_MERCHANT_TipMerchantGetCallback cb, - void *cb_cls) -{ - struct TALER_MERCHANT_TipMerchantGetHandle *tgh; - CURL *eh; - - GNUNET_assert (NULL != backend_url); - tgh = GNUNET_new (struct TALER_MERCHANT_TipMerchantGetHandle); - tgh->ctx = ctx; - tgh->cb = cb; - tgh->cb_cls = cb_cls; - - { - char res_str[sizeof (*tip_id) * 2]; - char arg_str[sizeof (res_str) + 48]; - char timeout_str[32]; - char *end; - - end = GNUNET_STRINGS_data_to_string (tip_id, - sizeof (*tip_id), - res_str, - sizeof (res_str)); - *end = '\0'; - GNUNET_snprintf (arg_str, - sizeof (arg_str), - "private/tips/%s", - res_str); - GNUNET_snprintf (timeout_str, - sizeof (timeout_str), - "%llu", - ((unsigned long long) - lp_timeout.rel_value_us - / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us)); - tgh->url = TALER_url_join (backend_url, - arg_str, - "pickups", - pickups - ? "yes" - : NULL, - "min_amount", - min_pick_up - ? TALER_amount2s (min_pick_up) - : NULL, - "timeout_ms", - GNUNET_TIME_relative_is_zero (lp_timeout) - ? NULL - : timeout_str, - NULL); - } - if (NULL == tgh->url) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not construct request URL.\n"); - GNUNET_free (tgh); - return NULL; - } - - eh = TALER_MERCHANT_curl_easy_get_ (tgh->url); - tgh->job = GNUNET_CURL_job_add (ctx, - eh, - &handle_merchant_tip_get_finished, - tgh); - return tgh; -} - - -void -TALER_MERCHANT_merchant_tip_get_cancel ( - struct TALER_MERCHANT_TipMerchantGetHandle *tgh) -{ - if (NULL != tgh->job) - { - GNUNET_CURL_job_cancel (tgh->job); - tgh->job = NULL; - } - GNUNET_free (tgh->url); - GNUNET_free (tgh); -} - - -/* end of merchant_api_merchant_get_tip.c */ diff --git a/src/lib/merchant_api_reward_authorize.c b/src/lib/merchant_api_reward_authorize.c @@ -0,0 +1,371 @@ +/* + This file is part of TALER + Copyright (C) 2014-2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING.LGPL. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file merchant_api_reward_authorize.c + * @brief Implementation of the /reward-authorize request of the merchant's HTTP API + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_curl_lib.h> +#include "taler_merchant_service.h" +#include "merchant_api_curl_defaults.h" +#include "merchant_api_common.h" +#include <taler/taler_json_lib.h> +#include <taler/taler_signatures.h> +#include <taler/taler_curl_lib.h> + + +/** + * @brief A handle for reward authorizations. + */ +struct TALER_MERCHANT_RewardAuthorizeHandle +{ + + /** + * The url for this request. + */ + char *url; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Function to call with the result. + */ + TALER_MERCHANT_RewardAuthorizeCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Reference to the execution context. + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Minor context that holds body and headers. + */ + struct TALER_CURL_PostContext post_ctx; +}; + + +/** + * We got a 200 response back from the exchange (or the merchant). + * Now we need to parse the response and if it is well-formed, + * call the callback (and set it to NULL afterwards). + * + * @param tao handle of the original authorization operation + * @param json cryptographic proof returned by the exchange/merchant + * @return #GNUNET_OK if response is valid + */ +static enum GNUNET_GenericReturnValue +check_ok (struct TALER_MERCHANT_RewardAuthorizeHandle *tao, + const json_t *json) +{ + const char *reward_status_url; + struct TALER_MERCHANT_RewardAuthorizeResponse tar = { + .hr.http_status = MHD_HTTP_OK, + .hr.reply = json + }; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("reward_status_url", + &reward_status_url), + GNUNET_JSON_spec_string ("taler_reward_uri", + &tar.details.ok.reward_uri), + GNUNET_JSON_spec_timestamp ("reward_expiration", + &tar.details.ok.reward_expiration), + GNUNET_JSON_spec_fixed_auto ("reward_id", + &tar.details.ok.reward_id), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json, + spec, + NULL, NULL)) + { + char *log; + + GNUNET_break_op (0); + log = json_dumps (json, + 0); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "JSON %s\n", + log); + free (log); + return GNUNET_SYSERR; + } + tao->cb (tao->cb_cls, + &tar); + tao->cb = NULL; /* do not call twice */ + GNUNET_JSON_parse_free (spec); + return GNUNET_OK; +} + + +/** + * Function called when we're done processing the + * HTTP /reservers/$REWARD_ID/reward-authorize request. + * + * @param cls the `struct TALER_MERCHANT_RewardAuthorizeHandle` + * @param response_code HTTP response code, 0 on error + * @param response response body, NULL if not in JSON + */ +static void +handle_reward_authorize_finished (void *cls, + long response_code, + const void *response) +{ + struct TALER_MERCHANT_RewardAuthorizeHandle *tao = cls; + const json_t *json = response; + struct TALER_MERCHANT_RewardAuthorizeResponse tar = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json + }; + + tao->job = NULL; + switch (response_code) + { + case MHD_HTTP_OK: + if (GNUNET_OK == + check_ok (tao, + json)) + { + TALER_MERCHANT_reward_authorize_cancel (tao); + return; + } + GNUNET_break_op (0); + tar.hr.http_status = 0; + tar.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + case MHD_HTTP_UNAUTHORIZED: + tar.hr.ec = TALER_JSON_get_error_code (json); + tar.hr.hint = TALER_JSON_get_error_hint (json); + /* Nothing really to verify, merchant says we need to authenticate. */ + break; + case MHD_HTTP_NOT_FOUND: + /* Well-defined status code, pass on to application! */ + tar.hr.ec = TALER_JSON_get_error_code (json); + tar.hr.hint = TALER_JSON_get_error_hint (json); + break; + case MHD_HTTP_PRECONDITION_FAILED: + /* Well-defined status code, pass on to application! */ + tar.hr.ec = TALER_JSON_get_error_code (json); + tar.hr.hint = TALER_JSON_get_error_hint (json); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + tar.hr.ec = TALER_JSON_get_error_code (json); + tar.hr.hint = TALER_JSON_get_error_hint (json); + break; + case MHD_HTTP_SERVICE_UNAVAILABLE: + /* Server had an unclear (internal or external) issue; we should retry, + but this API leaves this to the application */ + TALER_MERCHANT_parse_error_details_ (json, + response_code, + &tar.hr); + break; + default: + /* unexpected response code */ + GNUNET_break_op (0); + TALER_MERCHANT_parse_error_details_ (json, + response_code, + &tar.hr); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d\n", + (unsigned int) response_code, + (int) tar.hr.ec); + break; + } + if (NULL != tao->cb) + tao->cb (tao->cb_cls, + &tar); + TALER_MERCHANT_reward_authorize_cancel (tao); +} + + +struct TALER_MERCHANT_RewardAuthorizeHandle * +TALER_MERCHANT_reward_authorize2 ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct TALER_ReservePublicKeyP *reserve_pub, + const char *next_url, + const struct TALER_Amount *amount, + const char *justification, + TALER_MERCHANT_RewardAuthorizeCallback authorize_cb, + void *authorize_cb_cls) +{ + struct TALER_MERCHANT_RewardAuthorizeHandle *tao; + CURL *eh; + json_t *te_obj; + + tao = GNUNET_new (struct TALER_MERCHANT_RewardAuthorizeHandle); + tao->ctx = ctx; + tao->cb = authorize_cb; + tao->cb_cls = authorize_cb_cls; + + { + char res_str[sizeof (*reserve_pub) * 2]; + char arg_str[sizeof (res_str) + 48]; + char *end; + + end = GNUNET_STRINGS_data_to_string (reserve_pub, + sizeof (*reserve_pub), + res_str, + sizeof (res_str)); + *end = '\0'; + GNUNET_snprintf (arg_str, + sizeof (arg_str), + "private/reserves/%s/authorize-reward", + res_str); + tao->url = TALER_url_join (backend_url, + arg_str, + NULL); + } + if (NULL == tao->url) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not construct request URL.\n"); + GNUNET_free (tao); + return NULL; + } + te_obj = GNUNET_JSON_PACK ( + TALER_JSON_pack_amount ("amount", + amount), + GNUNET_JSON_pack_string ("justification", + justification), + GNUNET_JSON_pack_string ("next_url", + next_url)); + eh = curl_easy_init (); + GNUNET_assert (NULL != eh); + if (GNUNET_OK != + TALER_curl_easy_post (&tao->post_ctx, + eh, + te_obj)) + { + GNUNET_break (0); + curl_easy_cleanup (eh); + json_decref (te_obj); + GNUNET_free (tao->url); + GNUNET_free (tao); + return NULL; + } + + json_decref (te_obj); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requesting URL '%s'\n", + tao->url); + GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, + CURLOPT_URL, + tao->url)); + + tao->job = GNUNET_CURL_job_add2 (ctx, + eh, + tao->post_ctx.headers, + &handle_reward_authorize_finished, + tao); + return tao; +} + + +struct TALER_MERCHANT_RewardAuthorizeHandle * +TALER_MERCHANT_reward_authorize (struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const char *next_url, + const struct TALER_Amount *amount, + const char *justification, + TALER_MERCHANT_RewardAuthorizeCallback authorize_cb, + void *authorize_cb_cls) +{ + struct TALER_MERCHANT_RewardAuthorizeHandle *tao; + CURL *eh; + json_t *te_obj; + + tao = GNUNET_new (struct TALER_MERCHANT_RewardAuthorizeHandle); + tao->ctx = ctx; + tao->cb = authorize_cb; + tao->cb_cls = authorize_cb_cls; + + tao->url = TALER_url_join (backend_url, + "private/rewards", + NULL); + if (NULL == tao->url) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not construct request URL.\n"); + GNUNET_free (tao); + return NULL; + } + te_obj = GNUNET_JSON_PACK ( + TALER_JSON_pack_amount ("amount", + amount), + GNUNET_JSON_pack_string ("justification", + justification), + GNUNET_JSON_pack_string ("next_url", + next_url)); + eh = TALER_MERCHANT_curl_easy_get_ (tao->url); + if (GNUNET_OK != + TALER_curl_easy_post (&tao->post_ctx, + eh, + te_obj)) + { + GNUNET_break (0); + curl_easy_cleanup (eh); + json_decref (te_obj); + GNUNET_free (tao->url); + GNUNET_free (tao); + return NULL; + } + json_decref (te_obj); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requesting URL '%s'\n", + tao->url); + tao->job = GNUNET_CURL_job_add2 (ctx, + eh, + tao->post_ctx.headers, + &handle_reward_authorize_finished, + tao); + return tao; +} + + +void +TALER_MERCHANT_reward_authorize_cancel ( + struct TALER_MERCHANT_RewardAuthorizeHandle *tao) +{ + if (NULL != tao->job) + { + GNUNET_CURL_job_cancel (tao->job); + tao->job = NULL; + } + TALER_curl_easy_post_finished (&tao->post_ctx); + GNUNET_free (tao->url); + GNUNET_free (tao); +} + + +/* end of merchant_api_reward_authorize.c */ diff --git a/src/lib/merchant_api_reward_pickup.c b/src/lib/merchant_api_reward_pickup.c @@ -0,0 +1,440 @@ +/* + This file is part of TALER + Copyright (C) 2014-2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING.LGPL. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file merchant_api_reward_pickup.c + * @brief Implementation of the /reward-pickup request of the merchant's HTTP API + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_curl_lib.h> +#include "taler_merchant_service.h" +#include <taler/taler_json_lib.h> +#include <taler/taler_signatures.h> +#include <taler/taler_curl_lib.h> + + +/** + * Data we keep per planchet. + */ +struct PlanchetData +{ + /** + * Secrets of the planchet. + */ + struct TALER_PlanchetMasterSecretP ps; + + /** + * Denomination key we are withdrawing. + */ + struct TALER_EXCHANGE_DenomPublicKey pk; + + /** + * Hash of the public key of the coin we are signing. + */ + struct TALER_CoinPubHashP c_hash; + + /** + * Nonce used for @e csr request, if any. + */ + struct TALER_CsNonce nonce; + + /** + * Handle for a /csr request we may optionally need + * to trigger. + */ + struct TALER_EXCHANGE_CsRWithdrawHandle *csr; + + /** + * Handle for the /reward-pickup operation we are part of. + */ + struct TALER_MERCHANT_RewardPickupHandle *tp; + + /** + * Offset of this entry in the array. + */ + unsigned int off; +}; + + +/** + * Handle for a /reward-pickup operation. + */ +struct TALER_MERCHANT_RewardPickupHandle +{ + + /** + * Function to call with the result. + */ + TALER_MERCHANT_RewardPickupCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Handle for the actual (internal) withdraw operation. + */ + struct TALER_MERCHANT_RewardPickup2Handle *tpo2; + + /** + * Array of length @e num_planchets. + */ + struct PlanchetData *planchets; + + /** + * Array of length @e num_planchets. + */ + struct TALER_EXCHANGE_PrivateCoinDetails *pcds; + + /** + * Context for making HTTP requests. + */ + struct GNUNET_CURL_Context *ctx; + + /** + * URL of the merchant backend. + */ + char *backend_url; + + /** + * ID of the reward we are picking up. + */ + struct TALER_RewardIdentifierP reward_id; + + /** + * Number of planchets/coins used for this operation. + */ + unsigned int num_planchets; + + /** + * Number of remaining active /csr-withdraw requests. + */ + unsigned int csr_active; +}; + + +/** + * Fail the pickup operation @a tp, returning @a ec. + * Also cancels @a tp. + * + * @param[in] tp operation to fail + * @param ec reason for the failure + */ +static void +fail_pickup (struct TALER_MERCHANT_RewardPickupHandle *tp, + enum TALER_ErrorCode ec) +{ + struct TALER_MERCHANT_PickupDetails pd = { + .hr.ec = ec + }; + + tp->cb (tp->cb_cls, + &pd); + TALER_MERCHANT_reward_pickup_cancel (tp); +} + + +/** + * Callback for a /reward-pickup request. Returns the result of the operation. + * Note that the client MUST still do the unblinding of the @a blind_sigs. + * + * @param cls closure, a `struct TALER_MERCHANT_RewardPickupHandle *` + * @param tpr response details + */ +static void +pickup_done_cb (void *cls, + const struct TALER_MERCHANT_RewardPickup2Response *tpr) +{ + struct TALER_MERCHANT_RewardPickupHandle *tp = cls; + struct TALER_MERCHANT_PickupDetails pd = { + .hr = tpr->hr + }; + + tp->tpo2 = NULL; + if (MHD_HTTP_OK != tpr->hr.http_status) + { + tp->cb (tp->cb_cls, + &pd); + TALER_MERCHANT_reward_pickup_cancel (tp); + return; + } + { + enum GNUNET_GenericReturnValue ok = GNUNET_OK; + + for (unsigned int i = 0; i<tpr->details.ok.num_blind_sigs; i++) + { + const struct TALER_BlindedDenominationSignature *blind_sig + = &tpr->details.ok.blind_sigs[i]; + struct TALER_EXCHANGE_PrivateCoinDetails *pcd + = &tp->pcds[i]; + struct TALER_FreshCoin fc; + + if (GNUNET_OK != + TALER_planchet_to_coin (&tp->planchets[i].pk.key, + blind_sig, + &pcd->bks, + &pcd->coin_priv, + NULL, + &tp->planchets[i].c_hash, + &pcd->exchange_vals, + &fc)) + { + ok = GNUNET_SYSERR; + break; + } + pcd->sig = fc.sig; + } + if (GNUNET_OK != ok) + { + pd.hr.ec = TALER_EC_MERCHANT_REWARD_PICKUP_UNBLIND_FAILURE; + } + else + { + pd.details.ok.num_sigs = tpr->details.ok.num_blind_sigs; + pd.details.ok.pcds = tp->pcds; + } + tp->cb (tp->cb_cls, + &pd); + } + TALER_MERCHANT_reward_pickup_cancel (tp); +} + + +/** + * We have obtained all of the exchange inputs. Continue the pickup. + * + * @param[in,out] tp operation to continue + */ +static void +pickup_post_csr (struct TALER_MERCHANT_RewardPickupHandle *tp) +{ + struct TALER_PlanchetDetail details[tp->num_planchets]; + + for (unsigned int i = 0; i<tp->num_planchets; i++) + { + const struct PlanchetData *pd = &tp->planchets[i]; + struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i]; + + TALER_planchet_setup_coin_priv (&pd->ps, + &pcd->exchange_vals, + &pcd->coin_priv); + TALER_planchet_blinding_secret_create (&pd->ps, + &pcd->exchange_vals, + &pcd->bks); + if (TALER_DENOMINATION_CS == pcd->exchange_vals.cipher) + { + details[i].blinded_planchet.details.cs_blinded_planchet.nonce + = pd->nonce; + } + if (GNUNET_OK != + TALER_planchet_prepare (&pd->pk.key, + &pcd->exchange_vals, + &pcd->bks, + &pcd->coin_priv, + NULL, + &tp->planchets[i].c_hash, + &details[i])) + { + GNUNET_break (0); + for (unsigned int j = 0; j<i; j++) + TALER_planchet_detail_free (&details[j]); + fail_pickup (tp, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE); + return; + } + } + tp->tpo2 = TALER_MERCHANT_reward_pickup2 (tp->ctx, + tp->backend_url, + &tp->reward_id, + tp->num_planchets, + details, + &pickup_done_cb, + tp); + for (unsigned int j = 0; j<tp->num_planchets; j++) + TALER_planchet_detail_free (&details[j]); + if (NULL == tp->tpo2) + { + GNUNET_break (0); + fail_pickup (tp, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE); + return; + } +} + + +/** + * Callbacks of this type are used to serve the result of submitting a + * CS R request to a exchange. + * + * @param cls a `struct TALER_MERCHANT_RewardPickupHandle` + * @param csrr response details + */ +static void +csr_cb (void *cls, + const struct TALER_EXCHANGE_CsRWithdrawResponse *csrr) +{ + struct PlanchetData *pd = cls; + struct TALER_MERCHANT_RewardPickupHandle *tp = pd->tp; + + pd->csr = NULL; + tp->csr_active--; + switch (csrr->hr.http_status) + { + case MHD_HTTP_OK: + { + struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[pd->off]; + + pcd->exchange_vals = csrr->details.ok.alg_values; + } + if (0 != tp->csr_active) + return; + pickup_post_csr (tp); + return; + default: + { + struct TALER_MERCHANT_PickupDetails pd = { + .hr.hint = "/csr-withdraw failed", + .hr.exchange_http_status = csrr->hr.http_status + }; + + tp->cb (tp->cb_cls, + &pd); + TALER_MERCHANT_reward_pickup_cancel (tp); + return; + } + } +} + + +struct TALER_MERCHANT_RewardPickupHandle * +TALER_MERCHANT_reward_pickup ( + struct GNUNET_CURL_Context *ctx, + const char *exchange_url, + const char *backend_url, + const struct TALER_RewardIdentifierP *reward_id, + unsigned int num_planchets, + const struct TALER_MERCHANT_PlanchetData pds[static num_planchets], + TALER_MERCHANT_RewardPickupCallback pickup_cb, + void *pickup_cb_cls) +{ + struct TALER_MERCHANT_RewardPickupHandle *tp; + + if (0 == num_planchets) + { + GNUNET_break (0); + return NULL; + } + tp = GNUNET_new (struct TALER_MERCHANT_RewardPickupHandle); + tp->cb = pickup_cb; + tp->cb_cls = pickup_cb_cls; + tp->ctx = ctx; + tp->backend_url = GNUNET_strdup (backend_url); + tp->reward_id = *reward_id; + tp->num_planchets = num_planchets; + tp->planchets = GNUNET_new_array (num_planchets, + struct PlanchetData); + tp->pcds = GNUNET_new_array (num_planchets, + struct TALER_EXCHANGE_PrivateCoinDetails); + for (unsigned int i = 0; i<num_planchets; i++) + { + const struct TALER_MERCHANT_PlanchetData *mpd = &pds[i]; + const struct TALER_EXCHANGE_DenomPublicKey *pk = mpd->pk; + struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i]; + struct PlanchetData *pd = &tp->planchets[i]; + + pd->off = i; + pd->tp = tp; + tp->planchets[i].ps = mpd->ps; + tp->planchets[i].pk = *pds[i].pk; + TALER_denom_pub_deep_copy (&tp->planchets[i].pk.key, + &pds[i].pk->key); + switch (pk->key.cipher) + { + case TALER_DENOMINATION_RSA: + pcd->exchange_vals.cipher = TALER_DENOMINATION_RSA; + break; + case TALER_DENOMINATION_CS: + { + TALER_cs_withdraw_nonce_derive (&pd->ps, + &pd->nonce); + pd->csr = TALER_EXCHANGE_csr_withdraw (ctx, + exchange_url, + &pd->pk, + &pd->nonce, + &csr_cb, + pd); + if (NULL == pd->csr) + { + GNUNET_break (0); + TALER_MERCHANT_reward_pickup_cancel (tp); + return NULL; + } + tp->csr_active++; + break; + } + default: + GNUNET_break (0); + TALER_MERCHANT_reward_pickup_cancel (tp); + return NULL; + } + } + if (0 == tp->csr_active) + { + pickup_post_csr (tp); + return tp; + } + return tp; +} + + +void +TALER_MERCHANT_reward_pickup_cancel (struct TALER_MERCHANT_RewardPickupHandle *tp) +{ + for (unsigned int i = 0; i<tp->num_planchets; i++) + { + struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i]; + struct PlanchetData *pd = &tp->planchets[i]; + + TALER_denom_sig_free (&pcd->sig); + TALER_denom_pub_free (&tp->planchets[i].pk.key); + if (NULL != pd->csr) + { + TALER_EXCHANGE_csr_withdraw_cancel (pd->csr); + pd->csr = NULL; + } + } + GNUNET_array_grow (tp->planchets, + tp->num_planchets, + 0); + if (NULL != tp->tpo2) + { + TALER_MERCHANT_reward_pickup2_cancel (tp->tpo2); + tp->tpo2 = NULL; + } + GNUNET_free (tp->backend_url); + GNUNET_free (tp->pcds); + GNUNET_free (tp); +} + + +/* end of merchant_api_reward_pickup.c */ diff --git a/src/lib/merchant_api_reward_pickup2.c b/src/lib/merchant_api_reward_pickup2.c @@ -0,0 +1,355 @@ +/* + This file is part of TALER + Copyright (C) 2014-2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING.LGPL. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file merchant_api_reward_pickup2.c + * @brief Implementation of the /reward-pickup request of the merchant's HTTP API + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_curl_lib.h> +#include "taler_merchant_service.h" +#include "merchant_api_curl_defaults.h" +#include "merchant_api_common.h" +#include <taler/taler_json_lib.h> +#include <taler/taler_signatures.h> +#include <taler/taler_curl_lib.h> + + +/** + * @brief A handle for tracking transactions. + */ +struct TALER_MERCHANT_RewardPickup2Handle +{ + + /** + * The url for this request. + */ + char *url; + + /** + * Minor context that holds body and headers. + */ + struct TALER_CURL_PostContext post_ctx; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Function to call with the result. + */ + TALER_MERCHANT_RewardPickup2Callback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Reference to the execution context. + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Expected number of planchets. + */ + unsigned int num_planchets; +}; + + +/** + * We got a 200 response back from the exchange (or the merchant). + * Now we need to parse the response and if it is well-formed, + * call the callback (and set it to NULL afterwards). + * + * @param tpo handle of the original authorization operation + * @param[in] tpr response to complete + * @param json cryptographic proof returned by the exchange/merchant + * @return #GNUNET_OK if response is valid + */ +static enum GNUNET_GenericReturnValue +check_ok (struct TALER_MERCHANT_RewardPickup2Handle *tpo, + struct TALER_MERCHANT_RewardPickup2Response *tpr, + const json_t *json) +{ + const json_t *ja; + unsigned int ja_len; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_array_const ("blind_sigs", + &ja), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + ja_len = json_array_size (ja); + if (ja_len != tpo->num_planchets) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + { + struct TALER_BlindedDenominationSignature mblind_sigs[GNUNET_NZL (ja_len)]; + + for (unsigned int i = 0; i<ja_len; i++) + { + json_t *pj = json_array_get (ja, + i); + struct GNUNET_JSON_Specification ispec[] = { + TALER_JSON_spec_blinded_denom_sig ("blind_sig", + &mblind_sigs[i]), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (pj, + ispec, + NULL, NULL)) + { + GNUNET_break_op (0); + for (unsigned int j = 0; j<i; j++) + TALER_blinded_denom_sig_free (&mblind_sigs[j]); + return GNUNET_SYSERR; + } + } + tpr->details.ok.num_blind_sigs = ja_len; + tpr->details.ok.blind_sigs = mblind_sigs; + tpo->cb (tpo->cb_cls, + tpr); + tpo->cb = NULL; /* do not call twice */ + for (unsigned int i = 0; i<ja_len; i++) + TALER_blinded_denom_sig_free (&mblind_sigs[i]); + } + return GNUNET_OK; +} + + +/** + * Function called when we're done processing the + * HTTP /track/transaction request. + * + * @param cls the `struct TALER_MERCHANT_RewardPickupHandle` + * @param response_code HTTP response code, 0 on error + * @param response response body, NULL if not in JSON + */ +static void +handle_reward_pickup_finished (void *cls, + long response_code, + const void *response) +{ + struct TALER_MERCHANT_RewardPickup2Handle *tpo = cls; + const json_t *json = response; + struct TALER_MERCHANT_RewardPickup2Response tpr = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json + }; + + tpo->job = NULL; + switch (response_code) + { + case MHD_HTTP_OK: + if (GNUNET_OK != + check_ok (tpo, + &tpr, + json)) + { + GNUNET_break_op (0); + tpr.hr.http_status = 0; + tpr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + } + break; + case MHD_HTTP_BAD_REQUEST: + /* Can happen if we pickup an amount that exceeds the reward... */ + tpr.hr.ec = TALER_JSON_get_error_code (json); + tpr.hr.hint = TALER_JSON_get_error_hint (json); + GNUNET_break (TALER_EC_MERCHANT_REWARD_PICKUP_AMOUNT_EXCEEDS_REWARD_REMAINING == + tpr.hr.ec); + break; + case MHD_HTTP_CONFLICT: + /* legal, can happen if we pickup a reward twice... */ + tpr.hr.ec = TALER_JSON_get_error_code (json); + tpr.hr.hint = TALER_JSON_get_error_hint (json); + break; + case MHD_HTTP_NOT_FOUND: + /* legal, can happen if reward ID is unknown */ + tpr.hr.ec = TALER_JSON_get_error_code (json); + tpr.hr.hint = TALER_JSON_get_error_hint (json); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + tpr.hr.ec = TALER_JSON_get_error_code (json); + tpr.hr.hint = TALER_JSON_get_error_hint (json); + break; + default: + /* unexpected response code */ + GNUNET_break_op (0); + TALER_MERCHANT_parse_error_details_ (json, + response_code, + &tpr.hr); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d\n", + (unsigned int) response_code, + (int) tpr.hr.ec); + break; + } + if (NULL != tpo->cb) + { + tpo->cb (tpo->cb_cls, + &tpr); + tpo->cb = NULL; + } + TALER_MERCHANT_reward_pickup2_cancel (tpo); +} + + +struct TALER_MERCHANT_RewardPickup2Handle * +TALER_MERCHANT_reward_pickup2 ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct TALER_RewardIdentifierP *reward_id, + unsigned int num_planchets, + const struct TALER_PlanchetDetail planchets[static num_planchets], + TALER_MERCHANT_RewardPickup2Callback pickup_cb, + void *pickup_cb_cls) +{ + struct TALER_MERCHANT_RewardPickup2Handle *tpo; + CURL *eh; + json_t *pa; + json_t *tp_obj; + + if (0 == num_planchets) + { + GNUNET_break (0); + return NULL; + } + pa = json_array (); + GNUNET_assert (NULL != pa); + for (unsigned int i = 0; i<num_planchets; i++) + { + const struct TALER_PlanchetDetail *planchet = &planchets[i]; + json_t *p; + + p = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("denom_pub_hash", + &planchet->denom_pub_hash), + TALER_JSON_pack_blinded_planchet ("coin_ev", + &planchet->blinded_planchet)); + if (0 != + json_array_append_new (pa, + p)) + { + GNUNET_break (0); + json_decref (pa); + return NULL; + } + } + tp_obj = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_array_steal ("planchets", + pa)); + tpo = GNUNET_new (struct TALER_MERCHANT_RewardPickup2Handle); + tpo->num_planchets = num_planchets; + tpo->ctx = ctx; + tpo->cb = pickup_cb; + tpo->cb_cls = pickup_cb_cls; + + { + char reward_str[sizeof (*reward_id) * 2]; + char arg_str[sizeof (reward_str) + 32]; + char *end; + + end = GNUNET_STRINGS_data_to_string (reward_id, + sizeof (*reward_id), + reward_str, + sizeof (reward_str)); + *end = '\0'; + GNUNET_snprintf (arg_str, + sizeof (arg_str), + "rewards/%s/pickup", + reward_str); + tpo->url = TALER_url_join (backend_url, + arg_str, + NULL); + } + if (NULL == tpo->url) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not construct request URL.\n"); + json_decref (tp_obj); + GNUNET_free (tpo); + return NULL; + } + eh = TALER_MERCHANT_curl_easy_get_ (tpo->url); + if (GNUNET_OK != + TALER_curl_easy_post (&tpo->post_ctx, + eh, + tp_obj)) + { + GNUNET_break (0); + json_decref (tp_obj); + curl_easy_cleanup (eh); + GNUNET_free (tpo->url); + GNUNET_free (tpo); + return NULL; + } + json_decref (tp_obj); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requesting URL '%s'\n", + tpo->url); + tpo->job = GNUNET_CURL_job_add2 (ctx, + eh, + tpo->post_ctx.headers, + &handle_reward_pickup_finished, + tpo); + if (NULL == tpo->job) + { + TALER_MERCHANT_reward_pickup2_cancel (tpo); + return NULL; + } + return tpo; +} + + +void +TALER_MERCHANT_reward_pickup2_cancel ( + struct TALER_MERCHANT_RewardPickup2Handle *tpo) +{ + if (NULL != tpo->job) + { + GNUNET_CURL_job_cancel (tpo->job); + tpo->job = NULL; + } + TALER_curl_easy_post_finished (&tpo->post_ctx); + GNUNET_free (tpo->url); + GNUNET_free (tpo); +} + + +/* end of merchant_api_reward_pickup2.c */ diff --git a/src/lib/merchant_api_tip_authorize.c b/src/lib/merchant_api_tip_authorize.c @@ -1,371 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software - Foundation; either version 2.1, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License along with - TALER; see the file COPYING.LGPL. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file merchant_api_tip_authorize.c - * @brief Implementation of the /tip-authorize request of the merchant's HTTP API - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_merchant_service.h" -#include "merchant_api_curl_defaults.h" -#include "merchant_api_common.h" -#include <taler/taler_json_lib.h> -#include <taler/taler_signatures.h> -#include <taler/taler_curl_lib.h> - - -/** - * @brief A handle for tip authorizations. - */ -struct TALER_MERCHANT_TipAuthorizeHandle -{ - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Function to call with the result. - */ - TALER_MERCHANT_TipAuthorizeCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Reference to the execution context. - */ - struct GNUNET_CURL_Context *ctx; - - /** - * Minor context that holds body and headers. - */ - struct TALER_CURL_PostContext post_ctx; -}; - - -/** - * We got a 200 response back from the exchange (or the merchant). - * Now we need to parse the response and if it is well-formed, - * call the callback (and set it to NULL afterwards). - * - * @param tao handle of the original authorization operation - * @param json cryptographic proof returned by the exchange/merchant - * @return #GNUNET_OK if response is valid - */ -static enum GNUNET_GenericReturnValue -check_ok (struct TALER_MERCHANT_TipAuthorizeHandle *tao, - const json_t *json) -{ - const char *tip_status_url; - struct TALER_MERCHANT_TipAuthorizeResponse tar = { - .hr.http_status = MHD_HTTP_OK, - .hr.reply = json - }; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_string ("tip_status_url", - &tip_status_url), - GNUNET_JSON_spec_string ("taler_tip_uri", - &tar.details.ok.tip_uri), - GNUNET_JSON_spec_timestamp ("tip_expiration", - &tar.details.ok.tip_expiration), - GNUNET_JSON_spec_fixed_auto ("tip_id", - &tar.details.ok.tip_id), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - char *log; - - GNUNET_break_op (0); - log = json_dumps (json, - 0); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "JSON %s\n", - log); - free (log); - return GNUNET_SYSERR; - } - tao->cb (tao->cb_cls, - &tar); - tao->cb = NULL; /* do not call twice */ - GNUNET_JSON_parse_free (spec); - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /reservers/$TIP_ID/tip-authorize request. - * - * @param cls the `struct TALER_MERCHANT_TipAuthorizeHandle` - * @param response_code HTTP response code, 0 on error - * @param response response body, NULL if not in JSON - */ -static void -handle_tip_authorize_finished (void *cls, - long response_code, - const void *response) -{ - struct TALER_MERCHANT_TipAuthorizeHandle *tao = cls; - const json_t *json = response; - struct TALER_MERCHANT_TipAuthorizeResponse tar = { - .hr.http_status = (unsigned int) response_code, - .hr.reply = json - }; - - tao->job = NULL; - switch (response_code) - { - case MHD_HTTP_OK: - if (GNUNET_OK == - check_ok (tao, - json)) - { - TALER_MERCHANT_tip_authorize_cancel (tao); - return; - } - GNUNET_break_op (0); - tar.hr.http_status = 0; - tar.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - case MHD_HTTP_UNAUTHORIZED: - tar.hr.ec = TALER_JSON_get_error_code (json); - tar.hr.hint = TALER_JSON_get_error_hint (json); - /* Nothing really to verify, merchant says we need to authenticate. */ - break; - case MHD_HTTP_NOT_FOUND: - /* Well-defined status code, pass on to application! */ - tar.hr.ec = TALER_JSON_get_error_code (json); - tar.hr.hint = TALER_JSON_get_error_hint (json); - break; - case MHD_HTTP_PRECONDITION_FAILED: - /* Well-defined status code, pass on to application! */ - tar.hr.ec = TALER_JSON_get_error_code (json); - tar.hr.hint = TALER_JSON_get_error_hint (json); - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - tar.hr.ec = TALER_JSON_get_error_code (json); - tar.hr.hint = TALER_JSON_get_error_hint (json); - break; - case MHD_HTTP_SERVICE_UNAVAILABLE: - /* Server had an unclear (internal or external) issue; we should retry, - but this API leaves this to the application */ - TALER_MERCHANT_parse_error_details_ (json, - response_code, - &tar.hr); - break; - default: - /* unexpected response code */ - GNUNET_break_op (0); - TALER_MERCHANT_parse_error_details_ (json, - response_code, - &tar.hr); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d\n", - (unsigned int) response_code, - (int) tar.hr.ec); - break; - } - if (NULL != tao->cb) - tao->cb (tao->cb_cls, - &tar); - TALER_MERCHANT_tip_authorize_cancel (tao); -} - - -struct TALER_MERCHANT_TipAuthorizeHandle * -TALER_MERCHANT_tip_authorize2 ( - struct GNUNET_CURL_Context *ctx, - const char *backend_url, - const struct TALER_ReservePublicKeyP *reserve_pub, - const char *next_url, - const struct TALER_Amount *amount, - const char *justification, - TALER_MERCHANT_TipAuthorizeCallback authorize_cb, - void *authorize_cb_cls) -{ - struct TALER_MERCHANT_TipAuthorizeHandle *tao; - CURL *eh; - json_t *te_obj; - - tao = GNUNET_new (struct TALER_MERCHANT_TipAuthorizeHandle); - tao->ctx = ctx; - tao->cb = authorize_cb; - tao->cb_cls = authorize_cb_cls; - - { - char res_str[sizeof (*reserve_pub) * 2]; - char arg_str[sizeof (res_str) + 48]; - char *end; - - end = GNUNET_STRINGS_data_to_string (reserve_pub, - sizeof (*reserve_pub), - res_str, - sizeof (res_str)); - *end = '\0'; - GNUNET_snprintf (arg_str, - sizeof (arg_str), - "private/reserves/%s/authorize-tip", - res_str); - tao->url = TALER_url_join (backend_url, - arg_str, - NULL); - } - if (NULL == tao->url) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not construct request URL.\n"); - GNUNET_free (tao); - return NULL; - } - te_obj = GNUNET_JSON_PACK ( - TALER_JSON_pack_amount ("amount", - amount), - GNUNET_JSON_pack_string ("justification", - justification), - GNUNET_JSON_pack_string ("next_url", - next_url)); - eh = curl_easy_init (); - GNUNET_assert (NULL != eh); - if (GNUNET_OK != - TALER_curl_easy_post (&tao->post_ctx, - eh, - te_obj)) - { - GNUNET_break (0); - curl_easy_cleanup (eh); - json_decref (te_obj); - GNUNET_free (tao->url); - GNUNET_free (tao); - return NULL; - } - - json_decref (te_obj); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Requesting URL '%s'\n", - tao->url); - GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, - CURLOPT_URL, - tao->url)); - - tao->job = GNUNET_CURL_job_add2 (ctx, - eh, - tao->post_ctx.headers, - &handle_tip_authorize_finished, - tao); - return tao; -} - - -struct TALER_MERCHANT_TipAuthorizeHandle * -TALER_MERCHANT_tip_authorize (struct GNUNET_CURL_Context *ctx, - const char *backend_url, - const char *next_url, - const struct TALER_Amount *amount, - const char *justification, - TALER_MERCHANT_TipAuthorizeCallback authorize_cb, - void *authorize_cb_cls) -{ - struct TALER_MERCHANT_TipAuthorizeHandle *tao; - CURL *eh; - json_t *te_obj; - - tao = GNUNET_new (struct TALER_MERCHANT_TipAuthorizeHandle); - tao->ctx = ctx; - tao->cb = authorize_cb; - tao->cb_cls = authorize_cb_cls; - - tao->url = TALER_url_join (backend_url, - "private/tips", - NULL); - if (NULL == tao->url) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not construct request URL.\n"); - GNUNET_free (tao); - return NULL; - } - te_obj = GNUNET_JSON_PACK ( - TALER_JSON_pack_amount ("amount", - amount), - GNUNET_JSON_pack_string ("justification", - justification), - GNUNET_JSON_pack_string ("next_url", - next_url)); - eh = TALER_MERCHANT_curl_easy_get_ (tao->url); - if (GNUNET_OK != - TALER_curl_easy_post (&tao->post_ctx, - eh, - te_obj)) - { - GNUNET_break (0); - curl_easy_cleanup (eh); - json_decref (te_obj); - GNUNET_free (tao->url); - GNUNET_free (tao); - return NULL; - } - json_decref (te_obj); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Requesting URL '%s'\n", - tao->url); - tao->job = GNUNET_CURL_job_add2 (ctx, - eh, - tao->post_ctx.headers, - &handle_tip_authorize_finished, - tao); - return tao; -} - - -void -TALER_MERCHANT_tip_authorize_cancel ( - struct TALER_MERCHANT_TipAuthorizeHandle *tao) -{ - if (NULL != tao->job) - { - GNUNET_CURL_job_cancel (tao->job); - tao->job = NULL; - } - TALER_curl_easy_post_finished (&tao->post_ctx); - GNUNET_free (tao->url); - GNUNET_free (tao); -} - - -/* end of merchant_api_tip_authorize.c */ diff --git a/src/lib/merchant_api_tip_pickup.c b/src/lib/merchant_api_tip_pickup.c @@ -1,440 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software - Foundation; either version 2.1, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License along with - TALER; see the file COPYING.LGPL. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file merchant_api_tip_pickup.c - * @brief Implementation of the /tip-pickup request of the merchant's HTTP API - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_merchant_service.h" -#include <taler/taler_json_lib.h> -#include <taler/taler_signatures.h> -#include <taler/taler_curl_lib.h> - - -/** - * Data we keep per planchet. - */ -struct PlanchetData -{ - /** - * Secrets of the planchet. - */ - struct TALER_PlanchetMasterSecretP ps; - - /** - * Denomination key we are withdrawing. - */ - struct TALER_EXCHANGE_DenomPublicKey pk; - - /** - * Hash of the public key of the coin we are signing. - */ - struct TALER_CoinPubHashP c_hash; - - /** - * Nonce used for @e csr request, if any. - */ - struct TALER_CsNonce nonce; - - /** - * Handle for a /csr request we may optionally need - * to trigger. - */ - struct TALER_EXCHANGE_CsRWithdrawHandle *csr; - - /** - * Handle for the /tip-pickup operation we are part of. - */ - struct TALER_MERCHANT_TipPickupHandle *tp; - - /** - * Offset of this entry in the array. - */ - unsigned int off; -}; - - -/** - * Handle for a /tip-pickup operation. - */ -struct TALER_MERCHANT_TipPickupHandle -{ - - /** - * Function to call with the result. - */ - TALER_MERCHANT_TipPickupCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Handle for the actual (internal) withdraw operation. - */ - struct TALER_MERCHANT_TipPickup2Handle *tpo2; - - /** - * Array of length @e num_planchets. - */ - struct PlanchetData *planchets; - - /** - * Array of length @e num_planchets. - */ - struct TALER_EXCHANGE_PrivateCoinDetails *pcds; - - /** - * Context for making HTTP requests. - */ - struct GNUNET_CURL_Context *ctx; - - /** - * URL of the merchant backend. - */ - char *backend_url; - - /** - * ID of the tip we are picking up. - */ - struct TALER_TipIdentifierP tip_id; - - /** - * Number of planchets/coins used for this operation. - */ - unsigned int num_planchets; - - /** - * Number of remaining active /csr-withdraw requests. - */ - unsigned int csr_active; -}; - - -/** - * Fail the pickup operation @a tp, returning @a ec. - * Also cancels @a tp. - * - * @param[in] tp operation to fail - * @param ec reason for the failure - */ -static void -fail_pickup (struct TALER_MERCHANT_TipPickupHandle *tp, - enum TALER_ErrorCode ec) -{ - struct TALER_MERCHANT_PickupDetails pd = { - .hr.ec = ec - }; - - tp->cb (tp->cb_cls, - &pd); - TALER_MERCHANT_tip_pickup_cancel (tp); -} - - -/** - * Callback for a /tip-pickup request. Returns the result of the operation. - * Note that the client MUST still do the unblinding of the @a blind_sigs. - * - * @param cls closure, a `struct TALER_MERCHANT_TipPickupHandle *` - * @param tpr response details - */ -static void -pickup_done_cb (void *cls, - const struct TALER_MERCHANT_TipPickup2Response *tpr) -{ - struct TALER_MERCHANT_TipPickupHandle *tp = cls; - struct TALER_MERCHANT_PickupDetails pd = { - .hr = tpr->hr - }; - - tp->tpo2 = NULL; - if (MHD_HTTP_OK != tpr->hr.http_status) - { - tp->cb (tp->cb_cls, - &pd); - TALER_MERCHANT_tip_pickup_cancel (tp); - return; - } - { - enum GNUNET_GenericReturnValue ok = GNUNET_OK; - - for (unsigned int i = 0; i<tpr->details.ok.num_blind_sigs; i++) - { - const struct TALER_BlindedDenominationSignature *blind_sig - = &tpr->details.ok.blind_sigs[i]; - struct TALER_EXCHANGE_PrivateCoinDetails *pcd - = &tp->pcds[i]; - struct TALER_FreshCoin fc; - - if (GNUNET_OK != - TALER_planchet_to_coin (&tp->planchets[i].pk.key, - blind_sig, - &pcd->bks, - &pcd->coin_priv, - NULL, - &tp->planchets[i].c_hash, - &pcd->exchange_vals, - &fc)) - { - ok = GNUNET_SYSERR; - break; - } - pcd->sig = fc.sig; - } - if (GNUNET_OK != ok) - { - pd.hr.ec = TALER_EC_MERCHANT_TIP_PICKUP_UNBLIND_FAILURE; - } - else - { - pd.details.ok.num_sigs = tpr->details.ok.num_blind_sigs; - pd.details.ok.pcds = tp->pcds; - } - tp->cb (tp->cb_cls, - &pd); - } - TALER_MERCHANT_tip_pickup_cancel (tp); -} - - -/** - * We have obtained all of the exchange inputs. Continue the pickup. - * - * @param[in,out] tp operation to continue - */ -static void -pickup_post_csr (struct TALER_MERCHANT_TipPickupHandle *tp) -{ - struct TALER_PlanchetDetail details[tp->num_planchets]; - - for (unsigned int i = 0; i<tp->num_planchets; i++) - { - const struct PlanchetData *pd = &tp->planchets[i]; - struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i]; - - TALER_planchet_setup_coin_priv (&pd->ps, - &pcd->exchange_vals, - &pcd->coin_priv); - TALER_planchet_blinding_secret_create (&pd->ps, - &pcd->exchange_vals, - &pcd->bks); - if (TALER_DENOMINATION_CS == pcd->exchange_vals.cipher) - { - details[i].blinded_planchet.details.cs_blinded_planchet.nonce - = pd->nonce; - } - if (GNUNET_OK != - TALER_planchet_prepare (&pd->pk.key, - &pcd->exchange_vals, - &pcd->bks, - &pcd->coin_priv, - NULL, - &tp->planchets[i].c_hash, - &details[i])) - { - GNUNET_break (0); - for (unsigned int j = 0; j<i; j++) - TALER_planchet_detail_free (&details[j]); - fail_pickup (tp, - TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE); - return; - } - } - tp->tpo2 = TALER_MERCHANT_tip_pickup2 (tp->ctx, - tp->backend_url, - &tp->tip_id, - tp->num_planchets, - details, - &pickup_done_cb, - tp); - for (unsigned int j = 0; j<tp->num_planchets; j++) - TALER_planchet_detail_free (&details[j]); - if (NULL == tp->tpo2) - { - GNUNET_break (0); - fail_pickup (tp, - TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE); - return; - } -} - - -/** - * Callbacks of this type are used to serve the result of submitting a - * CS R request to a exchange. - * - * @param cls a `struct TALER_MERCHANT_TipPickupHandle` - * @param csrr response details - */ -static void -csr_cb (void *cls, - const struct TALER_EXCHANGE_CsRWithdrawResponse *csrr) -{ - struct PlanchetData *pd = cls; - struct TALER_MERCHANT_TipPickupHandle *tp = pd->tp; - - pd->csr = NULL; - tp->csr_active--; - switch (csrr->hr.http_status) - { - case MHD_HTTP_OK: - { - struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[pd->off]; - - pcd->exchange_vals = csrr->details.ok.alg_values; - } - if (0 != tp->csr_active) - return; - pickup_post_csr (tp); - return; - default: - { - struct TALER_MERCHANT_PickupDetails pd = { - .hr.hint = "/csr-withdraw failed", - .hr.exchange_http_status = csrr->hr.http_status - }; - - tp->cb (tp->cb_cls, - &pd); - TALER_MERCHANT_tip_pickup_cancel (tp); - return; - } - } -} - - -struct TALER_MERCHANT_TipPickupHandle * -TALER_MERCHANT_tip_pickup ( - struct GNUNET_CURL_Context *ctx, - const char *exchange_url, - const char *backend_url, - const struct TALER_TipIdentifierP *tip_id, - unsigned int num_planchets, - const struct TALER_MERCHANT_PlanchetData pds[static num_planchets], - TALER_MERCHANT_TipPickupCallback pickup_cb, - void *pickup_cb_cls) -{ - struct TALER_MERCHANT_TipPickupHandle *tp; - - if (0 == num_planchets) - { - GNUNET_break (0); - return NULL; - } - tp = GNUNET_new (struct TALER_MERCHANT_TipPickupHandle); - tp->cb = pickup_cb; - tp->cb_cls = pickup_cb_cls; - tp->ctx = ctx; - tp->backend_url = GNUNET_strdup (backend_url); - tp->tip_id = *tip_id; - tp->num_planchets = num_planchets; - tp->planchets = GNUNET_new_array (num_planchets, - struct PlanchetData); - tp->pcds = GNUNET_new_array (num_planchets, - struct TALER_EXCHANGE_PrivateCoinDetails); - for (unsigned int i = 0; i<num_planchets; i++) - { - const struct TALER_MERCHANT_PlanchetData *mpd = &pds[i]; - const struct TALER_EXCHANGE_DenomPublicKey *pk = mpd->pk; - struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i]; - struct PlanchetData *pd = &tp->planchets[i]; - - pd->off = i; - pd->tp = tp; - tp->planchets[i].ps = mpd->ps; - tp->planchets[i].pk = *pds[i].pk; - TALER_denom_pub_deep_copy (&tp->planchets[i].pk.key, - &pds[i].pk->key); - switch (pk->key.cipher) - { - case TALER_DENOMINATION_RSA: - pcd->exchange_vals.cipher = TALER_DENOMINATION_RSA; - break; - case TALER_DENOMINATION_CS: - { - TALER_cs_withdraw_nonce_derive (&pd->ps, - &pd->nonce); - pd->csr = TALER_EXCHANGE_csr_withdraw (ctx, - exchange_url, - &pd->pk, - &pd->nonce, - &csr_cb, - pd); - if (NULL == pd->csr) - { - GNUNET_break (0); - TALER_MERCHANT_tip_pickup_cancel (tp); - return NULL; - } - tp->csr_active++; - break; - } - default: - GNUNET_break (0); - TALER_MERCHANT_tip_pickup_cancel (tp); - return NULL; - } - } - if (0 == tp->csr_active) - { - pickup_post_csr (tp); - return tp; - } - return tp; -} - - -void -TALER_MERCHANT_tip_pickup_cancel (struct TALER_MERCHANT_TipPickupHandle *tp) -{ - for (unsigned int i = 0; i<tp->num_planchets; i++) - { - struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i]; - struct PlanchetData *pd = &tp->planchets[i]; - - TALER_denom_sig_free (&pcd->sig); - TALER_denom_pub_free (&tp->planchets[i].pk.key); - if (NULL != pd->csr) - { - TALER_EXCHANGE_csr_withdraw_cancel (pd->csr); - pd->csr = NULL; - } - } - GNUNET_array_grow (tp->planchets, - tp->num_planchets, - 0); - if (NULL != tp->tpo2) - { - TALER_MERCHANT_tip_pickup2_cancel (tp->tpo2); - tp->tpo2 = NULL; - } - GNUNET_free (tp->backend_url); - GNUNET_free (tp->pcds); - GNUNET_free (tp); -} - - -/* end of merchant_api_tip_pickup.c */ diff --git a/src/lib/merchant_api_tip_pickup2.c b/src/lib/merchant_api_tip_pickup2.c @@ -1,355 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software - Foundation; either version 2.1, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License along with - TALER; see the file COPYING.LGPL. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file merchant_api_tip_pickup2.c - * @brief Implementation of the /tip-pickup request of the merchant's HTTP API - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_merchant_service.h" -#include "merchant_api_curl_defaults.h" -#include "merchant_api_common.h" -#include <taler/taler_json_lib.h> -#include <taler/taler_signatures.h> -#include <taler/taler_curl_lib.h> - - -/** - * @brief A handle for tracking transactions. - */ -struct TALER_MERCHANT_TipPickup2Handle -{ - - /** - * The url for this request. - */ - char *url; - - /** - * Minor context that holds body and headers. - */ - struct TALER_CURL_PostContext post_ctx; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Function to call with the result. - */ - TALER_MERCHANT_TipPickup2Callback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Reference to the execution context. - */ - struct GNUNET_CURL_Context *ctx; - - /** - * Expected number of planchets. - */ - unsigned int num_planchets; -}; - - -/** - * We got a 200 response back from the exchange (or the merchant). - * Now we need to parse the response and if it is well-formed, - * call the callback (and set it to NULL afterwards). - * - * @param tpo handle of the original authorization operation - * @param[in] tpr response to complete - * @param json cryptographic proof returned by the exchange/merchant - * @return #GNUNET_OK if response is valid - */ -static enum GNUNET_GenericReturnValue -check_ok (struct TALER_MERCHANT_TipPickup2Handle *tpo, - struct TALER_MERCHANT_TipPickup2Response *tpr, - const json_t *json) -{ - const json_t *ja; - unsigned int ja_len; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_array_const ("blind_sigs", - &ja), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - ja_len = json_array_size (ja); - if (ja_len != tpo->num_planchets) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - { - struct TALER_BlindedDenominationSignature mblind_sigs[GNUNET_NZL (ja_len)]; - - for (unsigned int i = 0; i<ja_len; i++) - { - json_t *pj = json_array_get (ja, - i); - struct GNUNET_JSON_Specification ispec[] = { - TALER_JSON_spec_blinded_denom_sig ("blind_sig", - &mblind_sigs[i]), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (pj, - ispec, - NULL, NULL)) - { - GNUNET_break_op (0); - for (unsigned int j = 0; j<i; j++) - TALER_blinded_denom_sig_free (&mblind_sigs[j]); - return GNUNET_SYSERR; - } - } - tpr->details.ok.num_blind_sigs = ja_len; - tpr->details.ok.blind_sigs = mblind_sigs; - tpo->cb (tpo->cb_cls, - tpr); - tpo->cb = NULL; /* do not call twice */ - for (unsigned int i = 0; i<ja_len; i++) - TALER_blinded_denom_sig_free (&mblind_sigs[i]); - } - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /track/transaction request. - * - * @param cls the `struct TALER_MERCHANT_TipPickupHandle` - * @param response_code HTTP response code, 0 on error - * @param response response body, NULL if not in JSON - */ -static void -handle_tip_pickup_finished (void *cls, - long response_code, - const void *response) -{ - struct TALER_MERCHANT_TipPickup2Handle *tpo = cls; - const json_t *json = response; - struct TALER_MERCHANT_TipPickup2Response tpr = { - .hr.http_status = (unsigned int) response_code, - .hr.reply = json - }; - - tpo->job = NULL; - switch (response_code) - { - case MHD_HTTP_OK: - if (GNUNET_OK != - check_ok (tpo, - &tpr, - json)) - { - GNUNET_break_op (0); - tpr.hr.http_status = 0; - tpr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - } - break; - case MHD_HTTP_BAD_REQUEST: - /* Can happen if we pickup an amount that exceeds the tip... */ - tpr.hr.ec = TALER_JSON_get_error_code (json); - tpr.hr.hint = TALER_JSON_get_error_hint (json); - GNUNET_break (TALER_EC_MERCHANT_TIP_PICKUP_AMOUNT_EXCEEDS_TIP_REMAINING == - tpr.hr.ec); - break; - case MHD_HTTP_CONFLICT: - /* legal, can happen if we pickup a tip twice... */ - tpr.hr.ec = TALER_JSON_get_error_code (json); - tpr.hr.hint = TALER_JSON_get_error_hint (json); - break; - case MHD_HTTP_NOT_FOUND: - /* legal, can happen if tip ID is unknown */ - tpr.hr.ec = TALER_JSON_get_error_code (json); - tpr.hr.hint = TALER_JSON_get_error_hint (json); - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - tpr.hr.ec = TALER_JSON_get_error_code (json); - tpr.hr.hint = TALER_JSON_get_error_hint (json); - break; - default: - /* unexpected response code */ - GNUNET_break_op (0); - TALER_MERCHANT_parse_error_details_ (json, - response_code, - &tpr.hr); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d\n", - (unsigned int) response_code, - (int) tpr.hr.ec); - break; - } - if (NULL != tpo->cb) - { - tpo->cb (tpo->cb_cls, - &tpr); - tpo->cb = NULL; - } - TALER_MERCHANT_tip_pickup2_cancel (tpo); -} - - -struct TALER_MERCHANT_TipPickup2Handle * -TALER_MERCHANT_tip_pickup2 ( - struct GNUNET_CURL_Context *ctx, - const char *backend_url, - const struct TALER_TipIdentifierP *tip_id, - unsigned int num_planchets, - const struct TALER_PlanchetDetail planchets[static num_planchets], - TALER_MERCHANT_TipPickup2Callback pickup_cb, - void *pickup_cb_cls) -{ - struct TALER_MERCHANT_TipPickup2Handle *tpo; - CURL *eh; - json_t *pa; - json_t *tp_obj; - - if (0 == num_planchets) - { - GNUNET_break (0); - return NULL; - } - pa = json_array (); - GNUNET_assert (NULL != pa); - for (unsigned int i = 0; i<num_planchets; i++) - { - const struct TALER_PlanchetDetail *planchet = &planchets[i]; - json_t *p; - - p = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ("denom_pub_hash", - &planchet->denom_pub_hash), - TALER_JSON_pack_blinded_planchet ("coin_ev", - &planchet->blinded_planchet)); - if (0 != - json_array_append_new (pa, - p)) - { - GNUNET_break (0); - json_decref (pa); - return NULL; - } - } - tp_obj = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_array_steal ("planchets", - pa)); - tpo = GNUNET_new (struct TALER_MERCHANT_TipPickup2Handle); - tpo->num_planchets = num_planchets; - tpo->ctx = ctx; - tpo->cb = pickup_cb; - tpo->cb_cls = pickup_cb_cls; - - { - char tip_str[sizeof (*tip_id) * 2]; - char arg_str[sizeof (tip_str) + 32]; - char *end; - - end = GNUNET_STRINGS_data_to_string (tip_id, - sizeof (*tip_id), - tip_str, - sizeof (tip_str)); - *end = '\0'; - GNUNET_snprintf (arg_str, - sizeof (arg_str), - "tips/%s/pickup", - tip_str); - tpo->url = TALER_url_join (backend_url, - arg_str, - NULL); - } - if (NULL == tpo->url) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not construct request URL.\n"); - json_decref (tp_obj); - GNUNET_free (tpo); - return NULL; - } - eh = TALER_MERCHANT_curl_easy_get_ (tpo->url); - if (GNUNET_OK != - TALER_curl_easy_post (&tpo->post_ctx, - eh, - tp_obj)) - { - GNUNET_break (0); - json_decref (tp_obj); - curl_easy_cleanup (eh); - GNUNET_free (tpo->url); - GNUNET_free (tpo); - return NULL; - } - json_decref (tp_obj); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Requesting URL '%s'\n", - tpo->url); - tpo->job = GNUNET_CURL_job_add2 (ctx, - eh, - tpo->post_ctx.headers, - &handle_tip_pickup_finished, - tpo); - if (NULL == tpo->job) - { - TALER_MERCHANT_tip_pickup2_cancel (tpo); - return NULL; - } - return tpo; -} - - -void -TALER_MERCHANT_tip_pickup2_cancel ( - struct TALER_MERCHANT_TipPickup2Handle *tpo) -{ - if (NULL != tpo->job) - { - GNUNET_CURL_job_cancel (tpo->job); - tpo->job = NULL; - } - TALER_curl_easy_post_finished (&tpo->post_ctx); - GNUNET_free (tpo->url); - GNUNET_free (tpo); -} - - -/* end of merchant_api_tip_pickup2.c */ diff --git a/src/lib/merchant_api_wallet_get_reward.c b/src/lib/merchant_api_wallet_get_reward.c @@ -0,0 +1,220 @@ +/* + This file is part of TALER + Copyright (C) 2014-2018, 2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING.LGPL. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file merchant_api_wallet_get_reward.c + * @brief Implementation of the GET /rewards/$REWARD_ID request of the merchant's HTTP API + * @author Florian Dold + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_curl_lib.h> +#include "taler_merchant_service.h" +#include "merchant_api_curl_defaults.h" +#include "merchant_api_common.h" +#include <taler/taler_json_lib.h> +#include <taler/taler_signatures.h> + + +/** + * @brief A handle for tracking /reward-get operations + */ +struct TALER_MERCHANT_RewardWalletGetHandle +{ + /** + * The url for this request. + */ + char *url; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Function to call with the result. + */ + TALER_MERCHANT_RewardWalletGetCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Reference to the execution context. + */ + struct GNUNET_CURL_Context *ctx; + +}; + + +/** + * Function called when we're done processing the + * HTTP /track/transaction request. + * + * @param cls the `struct TALER_MERCHANT_RewardGetHandle` + * @param response_code HTTP response code, 0 on error + * @param response response body, NULL if not in JSON + */ +static void +handle_wallet_reward_get_finished (void *cls, + long response_code, + const void *response) +{ + struct TALER_MERCHANT_RewardWalletGetHandle *tgh = cls; + const json_t *json = response; + struct TALER_MERCHANT_RewardWalletGetResponse wgr = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json + }; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got /reward/$REWARD_ID response with status code %u\n", + (unsigned int) response_code); + + tgh->job = NULL; + switch (response_code) + { + case MHD_HTTP_OK: + { + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_timestamp ("expiration", + &wgr.details.ok.expiration), + GNUNET_JSON_spec_string ("exchange_url", + &wgr.details.ok.exchange_url), + GNUNET_JSON_spec_string ("next_url", + &wgr.details.ok.next_url), + TALER_JSON_spec_amount_any ("reward_amount", + &wgr.details.ok.amount_remaining), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + wgr.hr.http_status = 0; + wgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + } + tgh->cb (tgh->cb_cls, + &wgr); + TALER_MERCHANT_wallet_reward_get_cancel (tgh); + return; + } + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + wgr.hr.ec = TALER_JSON_get_error_code (json); + wgr.hr.hint = TALER_JSON_get_error_hint (json); + break; + case MHD_HTTP_NOT_FOUND: + /* legal, can happen if instance or reward reserve is unknown */ + wgr.hr.ec = TALER_JSON_get_error_code (json); + wgr.hr.hint = TALER_JSON_get_error_hint (json); + break; + default: + /* unexpected response code */ + GNUNET_break_op (0); + TALER_MERCHANT_parse_error_details_ (json, + response_code, + &wgr.hr); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d\n", + (unsigned int) response_code, + (int) wgr.hr.ec); + break; + } + tgh->cb (tgh->cb_cls, + &wgr); + TALER_MERCHANT_wallet_reward_get_cancel (tgh); +} + + +struct TALER_MERCHANT_RewardWalletGetHandle * +TALER_MERCHANT_wallet_reward_get (struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct TALER_RewardIdentifierP *reward_id, + TALER_MERCHANT_RewardWalletGetCallback cb, + void *cb_cls) +{ + struct TALER_MERCHANT_RewardWalletGetHandle *tgh; + CURL *eh; + + tgh = GNUNET_new (struct TALER_MERCHANT_RewardWalletGetHandle); + tgh->ctx = ctx; + tgh->cb = cb; + tgh->cb_cls = cb_cls; + { + char res_str[sizeof (*reward_id) * 2]; + char arg_str[sizeof (res_str) + 48]; + char *end; + + end = GNUNET_STRINGS_data_to_string (reward_id, + sizeof (*reward_id), + res_str, + sizeof (res_str)); + *end = '\0'; + GNUNET_snprintf (arg_str, + sizeof (arg_str), + "rewards/%s", + res_str); + tgh->url = TALER_url_join (backend_url, + arg_str, + NULL); + } + + if (NULL == tgh->url) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not construct request URL.\n"); + GNUNET_free (tgh); + return NULL; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Requesting URL '%s'\n", + tgh->url); + eh = TALER_MERCHANT_curl_easy_get_ (tgh->url); + tgh->job = GNUNET_CURL_job_add (ctx, + eh, + &handle_wallet_reward_get_finished, + tgh); + return tgh; +} + + +void +TALER_MERCHANT_wallet_reward_get_cancel ( + struct TALER_MERCHANT_RewardWalletGetHandle *tgh) +{ + if (NULL != tgh->job) + { + GNUNET_CURL_job_cancel (tgh->job); + tgh->job = NULL; + } + GNUNET_free (tgh->url); + GNUNET_free (tgh); +} + + +/* end of merchant_api_wallet_get_reward.c */ diff --git a/src/lib/merchant_api_wallet_get_tip.c b/src/lib/merchant_api_wallet_get_tip.c @@ -1,220 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2018, 2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software - Foundation; either version 2.1, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License along with - TALER; see the file COPYING.LGPL. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file merchant_api_wallet_get_tip.c - * @brief Implementation of the GET /tips/$TIP_ID request of the merchant's HTTP API - * @author Florian Dold - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_merchant_service.h" -#include "merchant_api_curl_defaults.h" -#include "merchant_api_common.h" -#include <taler/taler_json_lib.h> -#include <taler/taler_signatures.h> - - -/** - * @brief A handle for tracking /tip-get operations - */ -struct TALER_MERCHANT_TipWalletGetHandle -{ - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Function to call with the result. - */ - TALER_MERCHANT_TipWalletGetCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Reference to the execution context. - */ - struct GNUNET_CURL_Context *ctx; - -}; - - -/** - * Function called when we're done processing the - * HTTP /track/transaction request. - * - * @param cls the `struct TALER_MERCHANT_TipGetHandle` - * @param response_code HTTP response code, 0 on error - * @param response response body, NULL if not in JSON - */ -static void -handle_wallet_tip_get_finished (void *cls, - long response_code, - const void *response) -{ - struct TALER_MERCHANT_TipWalletGetHandle *tgh = cls; - const json_t *json = response; - struct TALER_MERCHANT_TipWalletGetResponse wgr = { - .hr.http_status = (unsigned int) response_code, - .hr.reply = json - }; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got /tip/$TIP_ID response with status code %u\n", - (unsigned int) response_code); - - tgh->job = NULL; - switch (response_code) - { - case MHD_HTTP_OK: - { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_timestamp ("expiration", - &wgr.details.ok.expiration), - GNUNET_JSON_spec_string ("exchange_url", - &wgr.details.ok.exchange_url), - GNUNET_JSON_spec_string ("next_url", - &wgr.details.ok.next_url), - TALER_JSON_spec_amount_any ("tip_amount", - &wgr.details.ok.amount_remaining), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - wgr.hr.http_status = 0; - wgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - } - tgh->cb (tgh->cb_cls, - &wgr); - TALER_MERCHANT_wallet_tip_get_cancel (tgh); - return; - } - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - wgr.hr.ec = TALER_JSON_get_error_code (json); - wgr.hr.hint = TALER_JSON_get_error_hint (json); - break; - case MHD_HTTP_NOT_FOUND: - /* legal, can happen if instance or tip reserve is unknown */ - wgr.hr.ec = TALER_JSON_get_error_code (json); - wgr.hr.hint = TALER_JSON_get_error_hint (json); - break; - default: - /* unexpected response code */ - GNUNET_break_op (0); - TALER_MERCHANT_parse_error_details_ (json, - response_code, - &wgr.hr); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d\n", - (unsigned int) response_code, - (int) wgr.hr.ec); - break; - } - tgh->cb (tgh->cb_cls, - &wgr); - TALER_MERCHANT_wallet_tip_get_cancel (tgh); -} - - -struct TALER_MERCHANT_TipWalletGetHandle * -TALER_MERCHANT_wallet_tip_get (struct GNUNET_CURL_Context *ctx, - const char *backend_url, - const struct TALER_TipIdentifierP *tip_id, - TALER_MERCHANT_TipWalletGetCallback cb, - void *cb_cls) -{ - struct TALER_MERCHANT_TipWalletGetHandle *tgh; - CURL *eh; - - tgh = GNUNET_new (struct TALER_MERCHANT_TipWalletGetHandle); - tgh->ctx = ctx; - tgh->cb = cb; - tgh->cb_cls = cb_cls; - { - char res_str[sizeof (*tip_id) * 2]; - char arg_str[sizeof (res_str) + 48]; - char *end; - - end = GNUNET_STRINGS_data_to_string (tip_id, - sizeof (*tip_id), - res_str, - sizeof (res_str)); - *end = '\0'; - GNUNET_snprintf (arg_str, - sizeof (arg_str), - "tips/%s", - res_str); - tgh->url = TALER_url_join (backend_url, - arg_str, - NULL); - } - - if (NULL == tgh->url) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not construct request URL.\n"); - GNUNET_free (tgh); - return NULL; - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Requesting URL '%s'\n", - tgh->url); - eh = TALER_MERCHANT_curl_easy_get_ (tgh->url); - tgh->job = GNUNET_CURL_job_add (ctx, - eh, - &handle_wallet_tip_get_finished, - tgh); - return tgh; -} - - -void -TALER_MERCHANT_wallet_tip_get_cancel ( - struct TALER_MERCHANT_TipWalletGetHandle *tgh) -{ - if (NULL != tgh->job) - { - GNUNET_CURL_job_cancel (tgh->job); - tgh->job = NULL; - } - GNUNET_free (tgh->url); - GNUNET_free (tgh); -} - - -/* end of merchant_api_wallet_get_tip.c */ diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am @@ -41,7 +41,7 @@ libtalermerchanttesting_la_SOURCES = \ testing_api_cmd_get_products.c \ testing_api_cmd_get_reserve.c \ testing_api_cmd_get_reserves.c \ - testing_api_cmd_get_tips.c \ + testing_api_cmd_get_rewards.c \ testing_api_cmd_get_transfers.c \ testing_api_cmd_get_templates.c \ testing_api_cmd_get_template.c \ @@ -60,7 +60,7 @@ libtalermerchanttesting_la_SOURCES = \ testing_api_cmd_lock_product.c \ testing_api_cmd_instance_auth.c \ testing_api_cmd_merchant_get_order.c \ - testing_api_cmd_merchant_get_tip.c \ + testing_api_cmd_merchant_get_reward.c \ testing_api_cmd_pay_order.c \ testing_api_cmd_post_account.c \ testing_api_cmd_post_instances.c \ @@ -77,11 +77,11 @@ libtalermerchanttesting_la_SOURCES = \ testing_api_cmd_patch_template.c \ testing_api_cmd_patch_webhook.c \ testing_api_cmd_refund_order.c \ - testing_api_cmd_tip_authorize.c \ - testing_api_cmd_tip_pickup.c \ + testing_api_cmd_reward_authorize.c \ + testing_api_cmd_reward_pickup.c \ testing_api_cmd_tme.c \ testing_api_cmd_wallet_get_order.c \ - testing_api_cmd_wallet_get_tip.c \ + testing_api_cmd_wallet_get_reward.c \ testing_api_cmd_wallet_post_orders_refund.c \ testing_api_cmd_webhook.c \ testing_api_cmd_testserver.c \ diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c @@ -387,11 +387,11 @@ run (void *cls, NULL), TALER_TESTING_cmd_get_exchange ("get-exchange", cred.cfg, + NULL, true, true), TALER_TESTING_cmd_oauth ("start-oauth-service", 6666), - // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), TALER_TESTING_cmd_merchant_post_instances ("instance-create-default-setup", merchant_url, "default", diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c @@ -1022,179 +1022,183 @@ run (void *cls, TALER_TESTING_cmd_end () }; - struct TALER_TESTING_Command tip[] = { - TALER_TESTING_cmd_merchant_post_reserves ("create-reserve-tip-1", + struct TALER_TESTING_Command reward[] = { + TALER_TESTING_cmd_merchant_post_reserves ("create-reserve-reward-1", merchant_url, "EUR:20.04", EXCHANGE_URL, "x-taler-bank", MHD_HTTP_OK), - TALER_TESTING_cmd_admin_add_incoming_with_ref ("create-reserve-tip-1-exch", - "EUR:20.04", - &cred.ba, - payer_payto, - "create-reserve-tip-1", - MHD_HTTP_OK), + TALER_TESTING_cmd_admin_add_incoming_with_ref ( + "create-reserve-reward-1-exch", + "EUR:20.04", + &cred.ba, + payer_payto, + "create-reserve-reward-1", + MHD_HTTP_OK), /* We need to wait until the merchant re-tries fetching the reserve from the exchange. */ cmd_exec_wirewatch ("wirewatch-3"), - TALER_TESTING_cmd_sleep ("tip-sleep", 3), - TALER_TESTING_cmd_tip_authorize ("authorize-tip-1", - merchant_url, - EXCHANGE_URL, - MHD_HTTP_OK, - "tip 1", - "EUR:5.01"), - TALER_TESTING_cmd_tip_authorize_from_reserve ("authorize-tip-2", - merchant_url, - EXCHANGE_URL, - "create-reserve-tip-1-exch", - MHD_HTTP_OK, - "tip 2", - "EUR:5.01"), - TALER_TESTING_cmd_wallet_get_tip ("get-tip-1", - merchant_url, - "authorize-tip-1", - MHD_HTTP_OK), - TALER_TESTING_cmd_merchant_get_tip ("merchant-get-tip-1", + TALER_TESTING_cmd_sleep ("reward-sleep", 3), + TALER_TESTING_cmd_reward_authorize ("authorize-reward-1", merchant_url, - "authorize-tip-1", - MHD_HTTP_OK), - TALER_TESTING_cmd_get_tips ("get-tips-1", - merchant_url, - MHD_HTTP_OK, - "authorize-tip-2", - "authorize-tip-1", - NULL), - TALER_TESTING_cmd_get_tips2 ("get-tips-1-asc", - merchant_url, - 0, - 20, - MHD_HTTP_OK, - "authorize-tip-1", - "authorize-tip-2", - NULL), - TALER_TESTING_cmd_get_tips2 ("get-tips-1-asc-offset", - merchant_url, - 1, - 20, - MHD_HTTP_OK, - "authorize-tip-2", - NULL), + EXCHANGE_URL, + MHD_HTTP_OK, + "reward 1", + "EUR:5.01"), + TALER_TESTING_cmd_reward_authorize_from_reserve ("authorize-reward-2", + merchant_url, + EXCHANGE_URL, + "create-reserve-reward-1-exch", + MHD_HTTP_OK, + "reward 2", + "EUR:5.01"), + TALER_TESTING_cmd_wallet_get_reward ("get-reward-1", + merchant_url, + "authorize-reward-1", + MHD_HTTP_OK), + TALER_TESTING_cmd_merchant_get_reward ("merchant-get-reward-1", + merchant_url, + "authorize-reward-1", + MHD_HTTP_OK), + TALER_TESTING_cmd_get_rewards ("get-rewards-1", + merchant_url, + MHD_HTTP_OK, + "authorize-reward-2", + "authorize-reward-1", + NULL), + TALER_TESTING_cmd_get_rewards2 ("get-rewards-1-asc", + merchant_url, + 0, + 20, + MHD_HTTP_OK, + "authorize-reward-1", + "authorize-reward-2", + NULL), + TALER_TESTING_cmd_get_rewards2 ("get-rewards-1-asc-offset", + merchant_url, + 1, + 20, + MHD_HTTP_OK, + "authorize-reward-2", + NULL), TALER_TESTING_cmd_merchant_get_reserves ("get-reserves-1", merchant_url, MHD_HTTP_OK, - "create-reserve-tip-1-exch", + "create-reserve-reward-1-exch", NULL), TALER_TESTING_cmd_merchant_get_reserve ("get-reserve-1", merchant_url, MHD_HTTP_OK, - "create-reserve-tip-1-exch"), - TALER_TESTING_cmd_merchant_get_reserve_with_tips ("get-reserve-2", - merchant_url, - MHD_HTTP_OK, - "create-reserve-tip-1-exch", - "authorize-tip-1", - "authorize-tip-2", - NULL), - TALER_TESTING_cmd_tip_pickup ("pickup-tip-1", - merchant_url, - MHD_HTTP_OK, - "authorize-tip-1", - pickup_amounts_1), - TALER_TESTING_cmd_wallet_get_tip2 ("query-tip-2", - merchant_url, - "authorize-tip-1", - "EUR:0.01", - MHD_HTTP_OK), - TALER_TESTING_cmd_tip_pickup ("pickup-tip-2", - merchant_url, - MHD_HTTP_OK, - "authorize-tip-2", - pickup_amounts_1), - - TALER_TESTING_cmd_tip_pickup_with_ec ("pickup-tip-3-too-much", + "create-reserve-reward-1-exch"), + TALER_TESTING_cmd_merchant_get_reserve_with_rewards ("get-reserve-2", + merchant_url, + MHD_HTTP_OK, + "create-reserve-reward-1-exch", + "authorize-reward-1", + "authorize-reward-2", + NULL), + TALER_TESTING_cmd_reward_pickup ("pickup-reward-1", + merchant_url, + MHD_HTTP_OK, + "authorize-reward-1", + pickup_amounts_1), + TALER_TESTING_cmd_wallet_get_reward2 ("query-reward-2", merchant_url, - MHD_HTTP_BAD_REQUEST, - "authorize-tip-1", - pickup_amounts_1, - TALER_EC_MERCHANT_TIP_PICKUP_AMOUNT_EXCEEDS_TIP_REMAINING), + "authorize-reward-1", + "EUR:0.01", + MHD_HTTP_OK), + TALER_TESTING_cmd_reward_pickup ("pickup-reward-2", + merchant_url, + MHD_HTTP_OK, + "authorize-reward-2", + pickup_amounts_1), - TALER_TESTING_cmd_tip_pickup ("pickup-tip-4", - merchant_url, - MHD_HTTP_OK, - "authorize-tip-1", - pickup_amounts_2), - TALER_TESTING_cmd_merchant_get_tip_with_pickups ("merchant-get-tip-2", - merchant_url, - "authorize-tip-1", - MHD_HTTP_OK, - "pickup-tip-1", - "pickup-tip-4", - NULL), + TALER_TESTING_cmd_reward_pickup_with_ec ("pickup-reward-3-too-much", + merchant_url, + MHD_HTTP_BAD_REQUEST, + "authorize-reward-1", + pickup_amounts_1, + TALER_EC_MERCHANT_REWARD_PICKUP_AMOUNT_EXCEEDS_REWARD_REMAINING), + + TALER_TESTING_cmd_reward_pickup ("pickup-reward-4", + merchant_url, + MHD_HTTP_OK, + "authorize-reward-1", + pickup_amounts_2), + TALER_TESTING_cmd_merchant_get_reward_with_pickups ("merchant-get-reward-2", + merchant_url, + "authorize-reward-1", + MHD_HTTP_OK, + "pickup-reward-1", + "pickup-reward-4", + NULL), - /* This command tests the authorization of tip + /* This command tests the authorization of reward * against a reserve that does not exist. This is - * implemented by passing a "tip instance" that + * implemented by passing a "reward instance" that * specifies a reserve key that was never used to - * actually create a reserve. */// - TALER_TESTING_cmd_merchant_post_reserves_fake ("create-reserve-tip-2-fake"), - TALER_TESTING_cmd_tip_authorize_from_reserve_with_ec ("authorize-tip-null", - merchant_url, - EXCHANGE_URL, - "create-reserve-tip-2-fake", - MHD_HTTP_NOT_FOUND, - "tip 3", - "EUR:5.01", - TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_NOT_FOUND), + * actually create a reserve. */ + TALER_TESTING_cmd_merchant_post_reserves_fake ( + "create-reserve-reward-2-fake"), + TALER_TESTING_cmd_reward_authorize_from_reserve_with_ec ( + "authorize-reward-null", + merchant_url, + EXCHANGE_URL, + "create-reserve-reward-2-fake", + MHD_HTTP_NOT_FOUND, + "reward 3", + "EUR:5.01", + TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_RESERVE_NOT_FOUND), /* Test reserve with insufficient funds */ - TALER_TESTING_cmd_merchant_post_reserves ("create-reserve-tip-2", + TALER_TESTING_cmd_merchant_post_reserves ("create-reserve-reward-2", merchant_url, "EUR:1.04", EXCHANGE_URL, "x-taler-bank", MHD_HTTP_OK), - TALER_TESTING_cmd_admin_add_incoming_with_ref ("create-reserve-tip-2-exch", - "EUR:1.04", - &cred.ba, - payer_payto, - "create-reserve-tip-2", - MHD_HTTP_OK), + TALER_TESTING_cmd_admin_add_incoming_with_ref ( + "create-reserve-reward-2-exch", + "EUR:1.04", + &cred.ba, + payer_payto, + "create-reserve-reward-2", + MHD_HTTP_OK), cmd_exec_wirewatch ("wirewatch-4"), - TALER_TESTING_cmd_tip_authorize_from_reserve_with_ec ( - "authorize-tip-insufficient-funds", + TALER_TESTING_cmd_reward_authorize_from_reserve_with_ec ( + "authorize-reward-insufficient-funds", merchant_url, EXCHANGE_URL, - "create-reserve-tip-2", + "create-reserve-reward-2", MHD_HTTP_PRECONDITION_FAILED, - "tip 4", + "reward 4", "EUR:5.01", - TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_INSUFFICIENT_FUNDS), - TALER_TESTING_cmd_tip_authorize_fake ("fake-tip-authorization"), - TALER_TESTING_cmd_tip_pickup_with_ec ("pickup-non-existent-id", - merchant_url, - MHD_HTTP_NOT_FOUND, - "fake-tip-authorization", - pickup_amounts_1, - TALER_EC_MERCHANT_GENERIC_TIP_ID_UNKNOWN), + TALER_EC_MERCHANT_PRIVATE_POST_REWARD_AUTHORIZE_INSUFFICIENT_FUNDS), + TALER_TESTING_cmd_reward_authorize_fake ("fake-reward-authorization"), + TALER_TESTING_cmd_reward_pickup_with_ec ("pickup-non-existent-id", + merchant_url, + MHD_HTTP_NOT_FOUND, + "fake-reward-authorization", + pickup_amounts_1, + TALER_EC_MERCHANT_GENERIC_REWARD_ID_UNKNOWN), TALER_TESTING_cmd_merchant_get_reserves ("get-reserves-2", merchant_url, MHD_HTTP_OK, - "create-reserve-tip-1", - "create-reserve-tip-2", + "create-reserve-reward-1", + "create-reserve-reward-2", NULL), - TALER_TESTING_cmd_merchant_delete_reserve ("delete-reserve-tip-1", + TALER_TESTING_cmd_merchant_delete_reserve ("delete-reserve-reward-1", merchant_url, - "create-reserve-tip-1", + "create-reserve-reward-1", MHD_HTTP_NO_CONTENT), - TALER_TESTING_cmd_merchant_purge_reserve ("delete-reserve-tip-2", + TALER_TESTING_cmd_merchant_purge_reserve ("delete-reserve-reward-2", merchant_url, - "create-reserve-tip-1", + "create-reserve-reward-1", MHD_HTTP_NO_CONTENT), - TALER_TESTING_cmd_merchant_purge_reserve ("delete-reserve-tip-3", + TALER_TESTING_cmd_merchant_purge_reserve ("delete-reserve-reward-3", merchant_url, - "create-reserve-tip-1", + "create-reserve-reward-1", MHD_HTTP_NOT_FOUND), TALER_TESTING_cmd_end () }; @@ -1644,9 +1648,9 @@ run (void *cls, NULL), TALER_TESTING_cmd_get_exchange ("get-exchange", cred.cfg, + NULL, true, true), - // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), TALER_TESTING_cmd_batch ("orders-id", get_private_order_id), TALER_TESTING_cmd_config ("config", @@ -1976,8 +1980,8 @@ run (void *cls, pay_abort), TALER_TESTING_cmd_batch ("refund", refund), - TALER_TESTING_cmd_batch ("tip", - tip), + TALER_TESTING_cmd_batch ("reward", + reward), TALER_TESTING_cmd_batch ("templates", templates), TALER_TESTING_cmd_batch ("webhooks", diff --git a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_1/1687974704 b/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_1/1687974704 Binary files differ. diff --git a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_5/1687974704 b/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_5/1687974704 @@ -1,2 +0,0 @@ -¶YÎ †$]P„9cÑ Œ®H˜›ž"Â<äY× - -\ No newline at end of file diff --git a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_1/1687974704 b/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_1/1687974704 @@ -1 +0,0 @@ -Q™M&K¼Š¼1áܵ¥Ê¥ 6®DÉ«<ªióá© -\ No newline at end of file diff --git a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_10/1687974704 b/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_10/1687974704 Binary files differ. diff --git a/src/testing/test_merchant_api_twisted.c b/src/testing/test_merchant_api_twisted.c @@ -331,24 +331,9 @@ run (void *cls, NULL), TALER_TESTING_cmd_get_exchange ("get-exchange", cred.cfg, + NULL, true, true), -#if 0 - TALER_TESTING_cmd_auditor_add ("add-auditor-OK", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_wire_add ("add-wire-account", - "payto://x-taler-bank/localhost/2", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys", - config_file), - TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees", - config_file, - "EUR:0.01", - "EUR:0.01"), -#endif - // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), TALER_TESTING_cmd_merchant_post_instances ("instance-create-default", twister_merchant_url, "default", diff --git a/src/testing/testing_api_cmd_get_reserve.c b/src/testing/testing_api_cmd_get_reserve.c @@ -57,19 +57,19 @@ struct GetReserveState unsigned int http_status; /** - * Fetch tips + * Fetch rewards */ - bool fetch_tips; + bool fetch_rewards; /** - * Length of @e tips. + * Length of @e rewards. */ - unsigned int tips_length; + unsigned int rewards_length; /** - * The list of references to tips. + * The list of references to rewards. */ - const char **tips; + const char **rewards; }; @@ -119,35 +119,36 @@ get_reserve_cb (void *cls, } } { - unsigned int tips_length = rgr->details.ok.tips_length; - const struct TALER_MERCHANT_TipDetails *tips = rgr->details.ok.tips; + unsigned int rewards_length = rgr->details.ok.rewards_length; + const struct TALER_MERCHANT_RewardDetails *rewards = + rgr->details.ok.rewards; - if (tips_length != grs->tips_length) + if (rewards_length != grs->rewards_length) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Number of tips authorized does not match\n"); + "Number of rewards authorized does not match\n"); TALER_TESTING_interpreter_fail (grs->is); return; } - for (unsigned int i = 0; i < tips_length; ++i) + for (unsigned int i = 0; i < rewards_length; ++i) { - const struct TALER_TESTING_Command *tip_cmd; + const struct TALER_TESTING_Command *reward_cmd; - tip_cmd = TALER_TESTING_interpreter_lookup_command (grs->is, - grs->tips[i]); + reward_cmd = TALER_TESTING_interpreter_lookup_command (grs->is, + grs->rewards[i]); { - const struct TALER_TipIdentifierP *tip_id; + const struct TALER_RewardIdentifierP *reward_id; if (GNUNET_OK != - TALER_TESTING_get_trait_tip_id (tip_cmd, - &tip_id)) + TALER_TESTING_get_trait_reward_id (reward_cmd, + &reward_id)) TALER_TESTING_interpreter_fail (grs->is); - if (0 != GNUNET_memcmp (&tips[i].tip_id, - tip_id)) + if (0 != GNUNET_memcmp (&rewards[i].reward_id, + reward_id)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Reserve tip id does not match\n"); + "Reserve reward id does not match\n"); TALER_TESTING_interpreter_fail (grs->is); return; } @@ -156,18 +157,18 @@ get_reserve_cb (void *cls, const struct TALER_Amount *total_amount; if (GNUNET_OK != - TALER_TESTING_get_trait_amount (tip_cmd, + TALER_TESTING_get_trait_amount (reward_cmd, &total_amount)) TALER_TESTING_interpreter_fail (grs->is); if ((GNUNET_OK != - TALER_amount_cmp_currency (&tips[i].amount, + TALER_amount_cmp_currency (&rewards[i].amount, total_amount)) || - (0 != TALER_amount_cmp (&tips[i].amount, + (0 != TALER_amount_cmp (&rewards[i].amount, total_amount))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Reserve tip amount does not match\n"); + "Reserve reward amount does not match\n"); TALER_TESTING_interpreter_fail (grs->is); return; } @@ -176,15 +177,15 @@ get_reserve_cb (void *cls, const char *reason; if (GNUNET_OK != - TALER_TESTING_get_trait_reason (tip_cmd, + TALER_TESTING_get_trait_reason (reward_cmd, &reason)) TALER_TESTING_interpreter_fail (grs->is); - if (0 != strcmp (tips[i].reason, + if (0 != strcmp (rewards[i].reason, reason)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Reserve tip reason does not match\n"); + "Reserve reward reason does not match\n"); TALER_TESTING_interpreter_fail (grs->is); return; } @@ -229,7 +230,7 @@ get_reserve_run (void *cls, is), grs->merchant_url, reserve_pub, - grs->fetch_tips, + grs->fetch_rewards, &get_reserve_cb, grs); @@ -256,8 +257,8 @@ get_reserve_cleanup (void *cls, "GET /private/reserve/$RESERVE_PUB operation did not complete\n"); TALER_MERCHANT_reserve_get_cancel (grs->rgh); } - GNUNET_array_grow (grs->tips, - grs->tips_length, + GNUNET_array_grow (grs->rewards, + grs->rewards_length, 0); GNUNET_free (grs); } @@ -275,7 +276,7 @@ TALER_TESTING_cmd_merchant_get_reserve (const char *label, grs->merchant_url = merchant_url; grs->http_status = http_status; grs->reserve_reference = reserve_reference; - grs->fetch_tips = false; + grs->fetch_rewards = false; { struct TALER_TESTING_Command cmd = { .cls = grs, @@ -290,11 +291,12 @@ TALER_TESTING_cmd_merchant_get_reserve (const char *label, struct TALER_TESTING_Command -TALER_TESTING_cmd_merchant_get_reserve_with_tips (const char *label, - const char *merchant_url, - unsigned int http_status, - const char *reserve_reference, - ...) +TALER_TESTING_cmd_merchant_get_reserve_with_rewards (const char *label, + const char *merchant_url, + unsigned int http_status, + const char * + reserve_reference, + ...) { struct GetReserveState *grs; @@ -302,7 +304,7 @@ TALER_TESTING_cmd_merchant_get_reserve_with_tips (const char *label, grs->merchant_url = merchant_url; grs->http_status = http_status; grs->reserve_reference = reserve_reference; - grs->fetch_tips = true; + grs->fetch_rewards = true; { const char *clabel; va_list ap; @@ -310,8 +312,8 @@ TALER_TESTING_cmd_merchant_get_reserve_with_tips (const char *label, va_start (ap, reserve_reference); while (NULL != (clabel = va_arg (ap, const char *))) { - GNUNET_array_append (grs->tips, - grs->tips_length, + GNUNET_array_append (grs->rewards, + grs->rewards_length, clabel); } va_end (ap); diff --git a/src/testing/testing_api_cmd_get_rewards.c b/src/testing/testing_api_cmd_get_rewards.c @@ -0,0 +1,311 @@ +/* + This file is part of TALER + Copyright (C) 2020-2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file testing_api_cmd_get_rewards.c + * @brief command to test GET /private/rewards + * @author Jonathan Buchanan + */ +#include "platform.h" +#include <taler/taler_exchange_service.h> +#include <taler/taler_testing_lib.h> +#include "taler_merchant_service.h" +#include "taler_merchant_testing_lib.h" + + +/** + * State of a "GET rewards" CMD. + */ +struct GetRewardsState +{ + + /** + * Handle for a "GET rewards" request. + */ + struct TALER_MERCHANT_RewardsGetHandle *tgh; + + /** + * The interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Base URL of the merchant serving the request. + */ + const char *merchant_url; + + /** + * Row to start querying the database from. + */ + uint64_t offset; + + /** + * How many rows to return (with direction). + */ + int64_t limit; + + /** + * Expected HTTP response code. + */ + unsigned int http_status; + + /** + * Length of @e rewards. + */ + unsigned int rewards_length; + + /** + * References to rewards that we expect to be found. + */ + const char **rewards; + +}; + +/** + * Callback for a GET /private/rewards operation. + * + * @param cls closure for this function + * @param tgr response details + */ +static void +get_rewards_cb (void *cls, + const struct TALER_MERCHANT_RewardsGetResponse *tgr) +{ + struct GetRewardsState *gts = cls; + + gts->tgh = NULL; + if (gts->http_status != tgr->hr.http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u (%d) to command %s\n", + tgr->hr.http_status, + (int) tgr->hr.ec, + TALER_TESTING_interpreter_get_current_label (gts->is)); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + switch (tgr->hr.http_status) + { + case MHD_HTTP_OK: + if (tgr->details.ok.rewards_length != gts->rewards_length) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Rewards length does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + for (unsigned int i = 0; i < tgr->details.ok.rewards_length; ++i) + { + const struct TALER_MERCHANT_RewardEntry *reward + = &tgr->details.ok.rewards[i]; + const struct TALER_TESTING_Command *reward_cmd; + + reward_cmd = TALER_TESTING_interpreter_lookup_command ( + gts->is, + gts->rewards[i]); + { + const struct TALER_RewardIdentifierP *reward_id; + + if (GNUNET_OK != + TALER_TESTING_get_trait_reward_id (reward_cmd, + &reward_id)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not fetch reward id\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + if (0 != GNUNET_memcmp (reward_id, + &reward->reward_id)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Reward id does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + { + const struct TALER_Amount *reward_amount; + + if (GNUNET_OK != + TALER_TESTING_get_trait_amount (reward_cmd, + &reward_amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not fetch reward amount\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + if ( (GNUNET_OK != + TALER_amount_cmp_currency (reward_amount, + &reward->reward_amount)) || + (0 != + TALER_amount_cmp (reward_amount, + &reward->reward_amount)) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Reward amount does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + } + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Unhandled HTTP status.\n"); + } + TALER_TESTING_interpreter_next (gts->is); +} + + +/** + * Run the "GET /private/rewards" CMD. + * + * @param cls closure. + * @param cmd command being run now. + * @param is interpreter state. + */ +static void +get_rewards_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct GetRewardsState *gts = cls; + + gts->is = is; + gts->tgh = TALER_MERCHANT_rewards_get2 ( + TALER_TESTING_interpreter_get_context (is), + gts->merchant_url, + TALER_EXCHANGE_YNA_NO, + gts->limit, + gts->offset, + &get_rewards_cb, + gts); + + GNUNET_assert (NULL != gts->tgh); +} + + +/** + * Free the state of a "GET rewards" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure. + * @param cmd command being run. + */ +static void +get_rewards_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct GetRewardsState *gts = cls; + + if (NULL != gts->tgh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "GET /private/rewards operation did not complete\n"); + TALER_MERCHANT_rewards_get_cancel (gts->tgh); + } + GNUNET_array_grow (gts->rewards, + gts->rewards_length, + 0); + GNUNET_free (gts); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_get_rewards (const char *label, + const char *merchant_url, + unsigned int http_status, + ...) +{ + struct GetRewardsState *gts; + + gts = GNUNET_new (struct GetRewardsState); + gts->merchant_url = merchant_url; + gts->offset = INT64_MAX; + gts->limit = -20; + gts->http_status = http_status; + { + const char *clabel; + va_list ap; + + va_start (ap, http_status); + while (NULL != (clabel = va_arg (ap, const char *))) + { + GNUNET_array_append (gts->rewards, + gts->rewards_length, + clabel); + } + va_end (ap); + } + { + struct TALER_TESTING_Command cmd = { + .cls = gts, + .label = label, + .run = &get_rewards_run, + .cleanup = &get_rewards_cleanup + }; + + return cmd; + } +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_get_rewards2 (const char *label, + const char *merchant_url, + uint64_t offset, + int64_t limit, + unsigned int http_status, + ...) +{ + struct GetRewardsState *gts; + + gts = GNUNET_new (struct GetRewardsState); + gts->merchant_url = merchant_url; + gts->offset = offset; + gts->limit = limit; + gts->http_status = http_status; + { + const char *clabel; + va_list ap; + + va_start (ap, http_status); + while (NULL != (clabel = va_arg (ap, const char *))) + { + GNUNET_array_append (gts->rewards, + gts->rewards_length, + clabel); + } + va_end (ap); + } + { + struct TALER_TESTING_Command cmd = { + .cls = gts, + .label = label, + .run = &get_rewards_run, + .cleanup = &get_rewards_cleanup + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_get_rewards.c */ diff --git a/src/testing/testing_api_cmd_get_tips.c b/src/testing/testing_api_cmd_get_tips.c @@ -1,310 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2020-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file testing_api_cmd_get_tips.c - * @brief command to test GET /private/tips - * @author Jonathan Buchanan - */ -#include "platform.h" -#include <taler/taler_exchange_service.h> -#include <taler/taler_testing_lib.h> -#include "taler_merchant_service.h" -#include "taler_merchant_testing_lib.h" - - -/** - * State of a "GET tips" CMD. - */ -struct GetTipsState -{ - - /** - * Handle for a "GET tips" request. - */ - struct TALER_MERCHANT_TipsGetHandle *tgh; - - /** - * The interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Base URL of the merchant serving the request. - */ - const char *merchant_url; - - /** - * Row to start querying the database from. - */ - uint64_t offset; - - /** - * How many rows to return (with direction). - */ - int64_t limit; - - /** - * Expected HTTP response code. - */ - unsigned int http_status; - - /** - * Length of @e tips. - */ - unsigned int tips_length; - - /** - * References to tips that we expect to be found. - */ - const char **tips; - -}; - -/** - * Callback for a GET /private/tips operation. - * - * @param cls closure for this function - * @param tgr response details - */ -static void -get_tips_cb (void *cls, - const struct TALER_MERCHANT_TipsGetResponse *tgr) -{ - struct GetTipsState *gts = cls; - - gts->tgh = NULL; - if (gts->http_status != tgr->hr.http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u (%d) to command %s\n", - tgr->hr.http_status, - (int) tgr->hr.ec, - TALER_TESTING_interpreter_get_current_label (gts->is)); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - switch (tgr->hr.http_status) - { - case MHD_HTTP_OK: - if (tgr->details.ok.tips_length != gts->tips_length) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Tips length does not match\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - for (unsigned int i = 0; i < tgr->details.ok.tips_length; ++i) - { - const struct TALER_MERCHANT_TipEntry *tip - = &tgr->details.ok.tips[i]; - const struct TALER_TESTING_Command *tip_cmd; - - tip_cmd = TALER_TESTING_interpreter_lookup_command ( - gts->is, - gts->tips[i]); - { - const struct TALER_TipIdentifierP *tip_id; - - if (GNUNET_OK != - TALER_TESTING_get_trait_tip_id (tip_cmd, - &tip_id)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not fetch tip id\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - if (0 != GNUNET_memcmp (tip_id, - &tip->tip_id)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Tip id does not match\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - } - { - const struct TALER_Amount *tip_amount; - - if (GNUNET_OK != - TALER_TESTING_get_trait_amount (tip_cmd, - &tip_amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not fetch tip amount\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - if ( (GNUNET_OK != - TALER_amount_cmp_currency (tip_amount, - &tip->tip_amount)) || - (0 != - TALER_amount_cmp (tip_amount, - &tip->tip_amount)) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Tip amount does not match\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - } - } - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Unhandled HTTP status.\n"); - } - TALER_TESTING_interpreter_next (gts->is); -} - - -/** - * Run the "GET /private/tips" CMD. - * - * @param cls closure. - * @param cmd command being run now. - * @param is interpreter state. - */ -static void -get_tips_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct GetTipsState *gts = cls; - - gts->is = is; - gts->tgh = TALER_MERCHANT_tips_get2 (TALER_TESTING_interpreter_get_context (is), - gts->merchant_url, - TALER_EXCHANGE_YNA_NO, - gts->limit, - gts->offset, - &get_tips_cb, - gts); - - GNUNET_assert (NULL != gts->tgh); -} - - -/** - * Free the state of a "GET tips" CMD, and possibly - * cancel a pending operation thereof. - * - * @param cls closure. - * @param cmd command being run. - */ -static void -get_tips_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct GetTipsState *gts = cls; - - if (NULL != gts->tgh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "GET /private/tips operation did not complete\n"); - TALER_MERCHANT_tips_get_cancel (gts->tgh); - } - GNUNET_array_grow (gts->tips, - gts->tips_length, - 0); - GNUNET_free (gts); -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_get_tips (const char *label, - const char *merchant_url, - unsigned int http_status, - ...) -{ - struct GetTipsState *gts; - - gts = GNUNET_new (struct GetTipsState); - gts->merchant_url = merchant_url; - gts->offset = INT64_MAX; - gts->limit = -20; - gts->http_status = http_status; - { - const char *clabel; - va_list ap; - - va_start (ap, http_status); - while (NULL != (clabel = va_arg (ap, const char *))) - { - GNUNET_array_append (gts->tips, - gts->tips_length, - clabel); - } - va_end (ap); - } - { - struct TALER_TESTING_Command cmd = { - .cls = gts, - .label = label, - .run = &get_tips_run, - .cleanup = &get_tips_cleanup - }; - - return cmd; - } -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_get_tips2 (const char *label, - const char *merchant_url, - uint64_t offset, - int64_t limit, - unsigned int http_status, - ...) -{ - struct GetTipsState *gts; - - gts = GNUNET_new (struct GetTipsState); - gts->merchant_url = merchant_url; - gts->offset = offset; - gts->limit = limit; - gts->http_status = http_status; - { - const char *clabel; - va_list ap; - - va_start (ap, http_status); - while (NULL != (clabel = va_arg (ap, const char *))) - { - GNUNET_array_append (gts->tips, - gts->tips_length, - clabel); - } - va_end (ap); - } - { - struct TALER_TESTING_Command cmd = { - .cls = gts, - .label = label, - .run = &get_tips_run, - .cleanup = &get_tips_cleanup - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_get_tips.c */ diff --git a/src/testing/testing_api_cmd_merchant_get_reward.c b/src/testing/testing_api_cmd_merchant_get_reward.c @@ -0,0 +1,373 @@ +/* + This file is part of TALER + Copyright (C) 2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file testing_api_cmd_merchant_get_reward.c + * @brief command to test GET /private/rewards/$REWARD_ID. + * @author Jonathan Buchanan + */ +#include "platform.h" +#include <taler/taler_exchange_service.h> +#include <taler/taler_testing_lib.h> +#include "taler_merchant_service.h" +#include "taler_merchant_testing_lib.h" + +/** + * State for a GET /private/rewards/$REWARD_ID CMD. + */ +struct MerchantRewardGetState +{ + + /** + * The merchant base URL. + */ + const char *merchant_url; + + /** + * Expected HTTP response code for this CMD. + */ + unsigned int http_status; + + /** + * Whether to fetch and compare pickups. + */ + bool fetch_pickups; + + /** + * The length of @e pickups. + */ + unsigned int pickups_length; + + /** + * The NULL-terminated list of pickup commands associated with the reward. + */ + const char **pickups; + + /** + * The handle to the current GET /rewards/$REWARD_ID request. + */ + struct TALER_MERCHANT_RewardMerchantGetHandle *tgh; + + /** + * The interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Reference to a command that created a reward. + */ + const char *reward_reference; +}; + + +/** + * Callback for a GET /private/rewards/$REWARD_ID operation. + * + * @param cls closure for this function + * @param tsr response + */ +static void +merchant_get_reward_cb (void *cls, + const struct TALER_MERCHANT_RewardStatusResponse *tsr) +{ + struct MerchantRewardGetState *gts = cls; + const struct TALER_TESTING_Command *authorize_cmd; + struct TALER_Amount expected_total_picked_up; + + authorize_cmd = TALER_TESTING_interpreter_lookup_command (gts->is, + gts-> + reward_reference); + + gts->tgh = NULL; + if (gts->http_status != tsr->hr.http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u (%d) to command %s\n", + tsr->hr.http_status, + (int) tsr->hr.ec, + TALER_TESTING_interpreter_get_current_label (gts->is)); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + switch (tsr->hr.http_status) + { + case MHD_HTTP_OK: + { + const struct TALER_Amount *initial_amount; + + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero ( + tsr->details.ok.total_picked_up.currency, + &expected_total_picked_up)); + if (GNUNET_OK != + TALER_TESTING_get_trait_amount (authorize_cmd, + &initial_amount)) + TALER_TESTING_FAIL (gts->is); + if ((GNUNET_OK != + TALER_amount_cmp_currency (&tsr->details.ok.total_authorized, + initial_amount)) || + (0 != TALER_amount_cmp (&tsr->details.ok.total_authorized, + initial_amount))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Reward authorized amount does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + { + const char *justification; + + if (GNUNET_OK != + TALER_TESTING_get_trait_reason (authorize_cmd, + &justification)) + TALER_TESTING_FAIL (gts->is); + if (0 != strcmp (tsr->details.ok.reason, + justification)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Reward authorized reason does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + { + const struct GNUNET_TIME_Timestamp *reward_expiration; + + if (GNUNET_OK != + TALER_TESTING_get_trait_timestamp (authorize_cmd, + 0, + &reward_expiration)) + TALER_TESTING_FAIL (gts->is); + if (GNUNET_TIME_timestamp_cmp (*reward_expiration, + !=, + tsr->details.ok.expiration)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Reward authorized expiration does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + if (tsr->details.ok.pickups_length != gts->pickups_length) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Length of pickups array does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + { + for (unsigned int i = 0; i < gts->pickups_length; ++i) + { + const struct TALER_TESTING_Command *pickup_cmd; + + pickup_cmd = TALER_TESTING_interpreter_lookup_command (gts->is, + gts->pickups[i]); + { + const uint32_t *num_planchets; + + if (GNUNET_OK != + TALER_TESTING_get_trait_num_planchets (pickup_cmd, + &num_planchets)) + TALER_TESTING_FAIL (gts->is); + + if (*num_planchets != tsr->details.ok.pickups[i].num_planchets) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Pickup planchet count does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + { + const struct TALER_Amount *total; + + if (GNUNET_OK != + TALER_TESTING_get_trait_amount (pickup_cmd, + &total)) + TALER_TESTING_FAIL (gts->is); + + if ( (GNUNET_OK != + TALER_amount_cmp_currency (total, + &tsr->details.ok.pickups[i]. + requested_amount)) || + (0 != TALER_amount_cmp (total, + &tsr->details.ok.pickups[i]. + requested_amount))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Pickup planchet sum does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + GNUNET_assert (0 < TALER_amount_add (&expected_total_picked_up, + &expected_total_picked_up, + total)); + } + } + if ( (GNUNET_OK != + TALER_amount_cmp_currency (&expected_total_picked_up, + &tsr->details.ok.total_picked_up)) || + (0 != + TALER_amount_cmp (&expected_total_picked_up, + &tsr->details.ok.total_picked_up)) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Reward picked up amount does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Unhandled HTTP status.\n"); + } + TALER_TESTING_interpreter_next (gts->is); +} + + +/** + * Run the "GET reward" CMD. + * + * @param cls closure. + * @param cmd command being run now. + * @param is interpreter state. + */ +static void +merchant_get_reward_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct MerchantRewardGetState *tgs = cls; + const struct TALER_TESTING_Command *reward_cmd; + const struct TALER_RewardIdentifierP *reward_id; + + reward_cmd = TALER_TESTING_interpreter_lookup_command (is, + tgs->reward_reference); + + if (GNUNET_OK != + TALER_TESTING_get_trait_reward_id (reward_cmd, + &reward_id)) + TALER_TESTING_FAIL (is); + + tgs->is = is; + tgs->tgh = TALER_MERCHANT_merchant_reward_get ( + TALER_TESTING_interpreter_get_context (is), + tgs->merchant_url, + reward_id, + NULL, + GNUNET_TIME_UNIT_ZERO, + tgs->fetch_pickups, + &merchant_get_reward_cb, + tgs); + GNUNET_assert (NULL != tgs->tgh); +} + + +/** +* Free the state of a "GET reward" CMD, and possibly +* cancel a pending operation thereof. +* +* @param cls closure. +* @param cmd command being run. +*/ +static void +merchant_get_reward_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct MerchantRewardGetState *tgs = cls; + + if (NULL != tgs->tgh) + { + TALER_LOG_WARNING ("Get reward operation did not complete\n"); + TALER_MERCHANT_merchant_reward_get_cancel (tgs->tgh); + } + GNUNET_array_grow (tgs->pickups, + tgs->pickups_length, + 0); + GNUNET_free (tgs); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_merchant_get_reward (const char *label, + const char *merchant_url, + const char *reward_reference, + unsigned int http_status) +{ + struct MerchantRewardGetState *tgs; + + tgs = GNUNET_new (struct MerchantRewardGetState); + tgs->merchant_url = merchant_url; + tgs->reward_reference = reward_reference; + tgs->http_status = http_status; + { + struct TALER_TESTING_Command cmd = { + .cls = tgs, + .label = label, + .run = &merchant_get_reward_run, + .cleanup = &merchant_get_reward_cleanup + }; + + return cmd; + } +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_merchant_get_reward_with_pickups (const char *label, + const char *merchant_url, + const char *reward_reference, + unsigned int http_status, + ...) +{ + struct MerchantRewardGetState *tgs; + + tgs = GNUNET_new (struct MerchantRewardGetState); + tgs->merchant_url = merchant_url; + tgs->reward_reference = reward_reference; + tgs->fetch_pickups = true; + tgs->http_status = http_status; + { + const char *clabel; + va_list ap; + + va_start (ap, http_status); + while (NULL != (clabel = va_arg (ap, const char *))) + { + GNUNET_array_append (tgs->pickups, + tgs->pickups_length, + clabel); + } + va_end (ap); + } + { + struct TALER_TESTING_Command cmd = { + .cls = tgs, + .label = label, + .run = &merchant_get_reward_run, + .cleanup = &merchant_get_reward_cleanup + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_merchant_get_reward.c */ diff --git a/src/testing/testing_api_cmd_merchant_get_tip.c b/src/testing/testing_api_cmd_merchant_get_tip.c @@ -1,372 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file testing_api_cmd_merchant_get_tip.c - * @brief command to test GET /private/tips/$TIP_ID. - * @author Jonathan Buchanan - */ -#include "platform.h" -#include <taler/taler_exchange_service.h> -#include <taler/taler_testing_lib.h> -#include "taler_merchant_service.h" -#include "taler_merchant_testing_lib.h" - -/** - * State for a GET /private/tips/$TIP_ID CMD. - */ -struct MerchantTipGetState -{ - - /** - * The merchant base URL. - */ - const char *merchant_url; - - /** - * Expected HTTP response code for this CMD. - */ - unsigned int http_status; - - /** - * Whether to fetch and compare pickups. - */ - bool fetch_pickups; - - /** - * The length of @e pickups. - */ - unsigned int pickups_length; - - /** - * The NULL-terminated list of pickup commands associated with the tip. - */ - const char **pickups; - - /** - * The handle to the current GET /tips/$TIP_ID request. - */ - struct TALER_MERCHANT_TipMerchantGetHandle *tgh; - - /** - * The interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Reference to a command that created a tip. - */ - const char *tip_reference; -}; - - -/** - * Callback for a GET /private/tips/$TIP_ID operation. - * - * @param cls closure for this function - * @param tsr response - */ -static void -merchant_get_tip_cb (void *cls, - const struct TALER_MERCHANT_TipStatusResponse *tsr) -{ - struct MerchantTipGetState *gts = cls; - const struct TALER_TESTING_Command *authorize_cmd; - struct TALER_Amount expected_total_picked_up; - - authorize_cmd = TALER_TESTING_interpreter_lookup_command (gts->is, - gts->tip_reference); - - gts->tgh = NULL; - if (gts->http_status != tsr->hr.http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u (%d) to command %s\n", - tsr->hr.http_status, - (int) tsr->hr.ec, - TALER_TESTING_interpreter_get_current_label (gts->is)); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - switch (tsr->hr.http_status) - { - case MHD_HTTP_OK: - { - const struct TALER_Amount *initial_amount; - - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero ( - tsr->details.ok.total_picked_up.currency, - &expected_total_picked_up)); - if (GNUNET_OK != - TALER_TESTING_get_trait_amount (authorize_cmd, - &initial_amount)) - TALER_TESTING_FAIL (gts->is); - if ((GNUNET_OK != - TALER_amount_cmp_currency (&tsr->details.ok.total_authorized, - initial_amount)) || - (0 != TALER_amount_cmp (&tsr->details.ok.total_authorized, - initial_amount))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Tip authorized amount does not match\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - } - { - const char *justification; - - if (GNUNET_OK != - TALER_TESTING_get_trait_reason (authorize_cmd, - &justification)) - TALER_TESTING_FAIL (gts->is); - if (0 != strcmp (tsr->details.ok.reason, - justification)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Tip authorized reason does not match\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - } - { - const struct GNUNET_TIME_Timestamp *tip_expiration; - - if (GNUNET_OK != - TALER_TESTING_get_trait_timestamp (authorize_cmd, - 0, - &tip_expiration)) - TALER_TESTING_FAIL (gts->is); - if (GNUNET_TIME_timestamp_cmp (*tip_expiration, - !=, - tsr->details.ok.expiration)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Tip authorized expiration does not match\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - } - if (tsr->details.ok.pickups_length != gts->pickups_length) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Length of pickups array does not match\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - { - for (unsigned int i = 0; i < gts->pickups_length; ++i) - { - const struct TALER_TESTING_Command *pickup_cmd; - - pickup_cmd = TALER_TESTING_interpreter_lookup_command (gts->is, - gts->pickups[i]); - { - const uint32_t *num_planchets; - - if (GNUNET_OK != - TALER_TESTING_get_trait_num_planchets (pickup_cmd, - &num_planchets)) - TALER_TESTING_FAIL (gts->is); - - if (*num_planchets != tsr->details.ok.pickups[i].num_planchets) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Pickup planchet count does not match\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - } - { - const struct TALER_Amount *total; - - if (GNUNET_OK != - TALER_TESTING_get_trait_amount (pickup_cmd, - &total)) - TALER_TESTING_FAIL (gts->is); - - if ( (GNUNET_OK != - TALER_amount_cmp_currency (total, - &tsr->details.ok.pickups[i]. - requested_amount)) || - (0 != TALER_amount_cmp (total, - &tsr->details.ok.pickups[i]. - requested_amount))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Pickup planchet sum does not match\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - GNUNET_assert (0 < TALER_amount_add (&expected_total_picked_up, - &expected_total_picked_up, - total)); - } - } - if ( (GNUNET_OK != - TALER_amount_cmp_currency (&expected_total_picked_up, - &tsr->details.ok.total_picked_up)) || - (0 != - TALER_amount_cmp (&expected_total_picked_up, - &tsr->details.ok.total_picked_up)) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Tip picked up amount does not match\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - } - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Unhandled HTTP status.\n"); - } - TALER_TESTING_interpreter_next (gts->is); -} - - -/** - * Run the "GET tip" CMD. - * - * @param cls closure. - * @param cmd command being run now. - * @param is interpreter state. - */ -static void -merchant_get_tip_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct MerchantTipGetState *tgs = cls; - const struct TALER_TESTING_Command *tip_cmd; - const struct TALER_TipIdentifierP *tip_id; - - tip_cmd = TALER_TESTING_interpreter_lookup_command (is, - tgs->tip_reference); - - if (GNUNET_OK != - TALER_TESTING_get_trait_tip_id (tip_cmd, - &tip_id)) - TALER_TESTING_FAIL (is); - - tgs->is = is; - tgs->tgh = TALER_MERCHANT_merchant_tip_get ( - TALER_TESTING_interpreter_get_context (is), - tgs->merchant_url, - tip_id, - NULL, - GNUNET_TIME_UNIT_ZERO, - tgs->fetch_pickups, - &merchant_get_tip_cb, - tgs); - GNUNET_assert (NULL != tgs->tgh); -} - - -/** -* Free the state of a "GET tip" CMD, and possibly -* cancel a pending operation thereof. -* -* @param cls closure. -* @param cmd command being run. -*/ -static void -merchant_get_tip_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct MerchantTipGetState *tgs = cls; - - if (NULL != tgs->tgh) - { - TALER_LOG_WARNING ("Get tip operation did not complete\n"); - TALER_MERCHANT_merchant_tip_get_cancel (tgs->tgh); - } - GNUNET_array_grow (tgs->pickups, - tgs->pickups_length, - 0); - GNUNET_free (tgs); -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_merchant_get_tip (const char *label, - const char *merchant_url, - const char *tip_reference, - unsigned int http_status) -{ - struct MerchantTipGetState *tgs; - - tgs = GNUNET_new (struct MerchantTipGetState); - tgs->merchant_url = merchant_url; - tgs->tip_reference = tip_reference; - tgs->http_status = http_status; - { - struct TALER_TESTING_Command cmd = { - .cls = tgs, - .label = label, - .run = &merchant_get_tip_run, - .cleanup = &merchant_get_tip_cleanup - }; - - return cmd; - } -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_merchant_get_tip_with_pickups (const char *label, - const char *merchant_url, - const char *tip_reference, - unsigned int http_status, - ...) -{ - struct MerchantTipGetState *tgs; - - tgs = GNUNET_new (struct MerchantTipGetState); - tgs->merchant_url = merchant_url; - tgs->tip_reference = tip_reference; - tgs->fetch_pickups = true; - tgs->http_status = http_status; - { - const char *clabel; - va_list ap; - - va_start (ap, http_status); - while (NULL != (clabel = va_arg (ap, const char *))) - { - GNUNET_array_append (tgs->pickups, - tgs->pickups_length, - clabel); - } - va_end (ap); - } - { - struct TALER_TESTING_Command cmd = { - .cls = tgs, - .label = label, - .run = &merchant_get_tip_run, - .cleanup = &merchant_get_tip_cleanup - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_merchant_get_tip.c */ diff --git a/src/testing/testing_api_cmd_reward_authorize.c b/src/testing/testing_api_cmd_reward_authorize.c @@ -0,0 +1,485 @@ +/* + This file is part of TALER + Copyright (C) 2014-2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + <http://www.gnu.org/licenses/> +*/ + +/** + * @file testing_api_cmd_reward_authorize.c + * @brief command to test the rewardping. + * @author Marcello Stanisci + */ + +#include "platform.h" +#include <taler/taler_exchange_service.h> +#include <taler/taler_testing_lib.h> +#include "taler_merchant_service.h" +#include "taler_merchant_testing_lib.h" + + +/** + * State for a /reward-authorize CMD. + */ +struct RewardAuthorizeState +{ + + /** + * Merchant base URL. + */ + const char *merchant_url; + + /** + * Expected HTTP response code. + */ + unsigned int http_status; + + /** + * Reference to the reserv to authorize the reward + * from (if NULL, the merchant decides). + */ + const char *reserve_reference; + + /** + * Human-readable justification for the + * reward authorization carried on by this CMD. + */ + const char *justification; + + /** + * Amount that should be authorized for rewardping. + */ + struct TALER_Amount amount; + + /** + * Expected Taler error code for this CMD. + */ + enum TALER_ErrorCode expected_ec; + + /** + * Reward taler:// URI. + */ + char *reward_uri; + + /** + * The reward id; set when the CMD succeeds. + */ + struct TALER_RewardIdentifierP reward_id; + + /** + * Expiration date for this reward. + */ + struct GNUNET_TIME_Timestamp reward_expiration; + + /** + * Handle to the on-going /reward-authorize request. + */ + struct TALER_MERCHANT_RewardAuthorizeHandle *tao; + + /** + * The interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Task used for retries. + */ + struct GNUNET_SCHEDULER_Task *retry_task; + + /** + * How long do we wait between retries? + */ + struct GNUNET_TIME_Relative backoff; + + /** + * How many retries are left? + */ + unsigned int retries_left; + +}; + + +/** + * Run the main logic of talking to the merchant. + * + * @param cls a `struct RewardAuthorizeState`. + */ +static void +do_retry (void *cls); + + +/** + * Callback for a /reward-authorize request. Set into the state + * what was returned from the backend (@a reward_id and @a + * reward_expiration). + * + * @param cls closure + * @param tar response we got + */ +static void +reward_authorize_cb (void *cls, + const struct TALER_MERCHANT_RewardAuthorizeResponse *tar) +{ + struct RewardAuthorizeState *tas = cls; + + tas->tao = NULL; + if (tas->http_status != tar->hr.http_status) + { + if ( (MHD_HTTP_NOT_FOUND == tar->hr.http_status) && + (0 < tas->retries_left) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Reserve authorization failed. Reserve may not yet be ready, retrying %u more times.\n", + tas->retries_left); + tas->retries_left--; + tas->backoff = GNUNET_TIME_randomized_backoff (tas->backoff, + GNUNET_TIME_UNIT_SECONDS); + tas->retry_task = GNUNET_SCHEDULER_add_delayed (tas->backoff, + &do_retry, + tas); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u (%d) to command %s\n", + tar->hr.http_status, + tar->hr.ec, + TALER_TESTING_interpreter_get_current_label (tas->is)); + TALER_TESTING_interpreter_fail (tas->is); + return; + } + + if (tas->expected_ec != tar->hr.ec) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected error code %d (%u) to command %s\n", + (int) tar->hr.ec, + tar->hr.http_status, + TALER_TESTING_interpreter_get_current_label (tas->is)); + TALER_TESTING_interpreter_fail (tas->is); + return; + } + if ( (MHD_HTTP_OK == tar->hr.http_status) && + (TALER_EC_NONE == tar->hr.ec) ) + { + tas->reward_uri = GNUNET_strdup (tar->details.ok.reward_uri); + tas->reward_id = tar->details.ok.reward_id; + tas->reward_expiration = tar->details.ok.reward_expiration; + } + TALER_TESTING_interpreter_next (tas->is); +} + + +/** + * Offers information from the /reward-authorize CMD state to other + * commands. + * + * @param cls closure + * @param[out] ret result (could be anything) + * @param trait name of the trait + * @param index index number of the object to extract. + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +reward_authorize_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct RewardAuthorizeState *tas = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_reward_id (&tas->reward_id), + TALER_TESTING_make_trait_amount (&tas->amount), + TALER_TESTING_make_trait_reason (tas->justification), + TALER_TESTING_make_trait_timestamp (0, + &tas->reward_expiration), + TALER_TESTING_trait_end (), + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Runs the /reward-authorize CMD + * + * @param cls closure + * @param cmd the CMD representing _this_ command + * @param is interpreter state + */ +static void +reward_authorize_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct RewardAuthorizeState *tas = cls; + + tas->retries_left = 16; + tas->is = is; + tas->retry_task = GNUNET_SCHEDULER_add_now (&do_retry, + tas); +} + + +static void +do_retry (void *cls) +{ + struct RewardAuthorizeState *tas = cls; + + tas->retry_task = NULL; + if (NULL == tas->reserve_reference) + { + tas->tao = TALER_MERCHANT_reward_authorize ( + TALER_TESTING_interpreter_get_context (tas->is), + tas->merchant_url, + "http://merchant.com/pickup", + &tas->amount, + tas->justification, + &reward_authorize_cb, + tas); + } + else + { + const struct TALER_TESTING_Command *reserve_cmd; + const struct TALER_ReservePublicKeyP *reserve_pub; + + reserve_cmd = TALER_TESTING_interpreter_lookup_command ( + tas->is, + tas->reserve_reference); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_reserve_pub (reserve_cmd, + &reserve_pub)); + tas->tao = TALER_MERCHANT_reward_authorize2 ( + TALER_TESTING_interpreter_get_context (tas->is), + tas->merchant_url, + reserve_pub, + "http://merchant.com/pickup", + &tas->amount, + tas->justification, + &reward_authorize_cb, + tas); + } + GNUNET_assert (NULL != tas->tao); +} + + +/** + * Run the /reward-authorize CMD, the "fake" version of it. + * + * @param cls closure + * @param cmd the CMD representing _this_ command + * @param is interpreter state * + */ +static void +reward_authorize_fake_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct RewardAuthorizeState *tas = cls; + + /* Make up a reward id. */ + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + &tas->reward_id, + sizeof (struct TALER_RewardIdentifierP)); + TALER_TESTING_interpreter_next (is); +} + + +/** + * Free the state from a /reward-authorize CMD, and possibly + * cancel any pending operation. + * + * @param cls closure + * @param cmd the /reward-authorize CMD that is about to be freed. + */ +static void +reward_authorize_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct RewardAuthorizeState *tas = cls; + + if (NULL != tas->tao) + { + TALER_LOG_WARNING ("Reward-autorize operation" + " did not complete\n"); + TALER_MERCHANT_reward_authorize_cancel (tas->tao); + } + if (NULL != tas->retry_task) + { + GNUNET_SCHEDULER_cancel (tas->retry_task); + tas->retry_task = NULL; + } + GNUNET_free (tas->reward_uri); + GNUNET_free (tas); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_reward_authorize_with_ec (const char *label, + const char *merchant_url, + const char *exchange_url, + unsigned int http_status, + const char *justification, + const char *amount, + enum TALER_ErrorCode ec) +{ + struct RewardAuthorizeState *tas; + + tas = GNUNET_new (struct RewardAuthorizeState); + tas->merchant_url = merchant_url; + tas->justification = justification; + tas->http_status = http_status; + tas->expected_ec = ec; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (amount, + &tas->amount)); + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = tas, + .run = &reward_authorize_run, + .cleanup = &reward_authorize_cleanup, + .traits = &reward_authorize_traits + }; + + return cmd; + } +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_reward_authorize_from_reserve_with_ec ( + const char *label, + const char *merchant_url, + const char *exchange_url, + const char *reserve_reference, + unsigned int http_status, + const char *justification, + const char *amount, + enum TALER_ErrorCode ec) +{ + struct RewardAuthorizeState *tas; + + tas = GNUNET_new (struct RewardAuthorizeState); + tas->merchant_url = merchant_url; + tas->justification = justification; + tas->http_status = http_status; + tas->expected_ec = ec; + tas->reserve_reference = reserve_reference; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (amount, + &tas->amount)); + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = tas, + .run = &reward_authorize_run, + .cleanup = &reward_authorize_cleanup, + .traits = &reward_authorize_traits + }; + + return cmd; + } +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_reward_authorize (const char *label, + const char *merchant_url, + const char *exchange_url, + unsigned int http_status, + const char *justification, + const char *amount) +{ + struct RewardAuthorizeState *tas; + + tas = GNUNET_new (struct RewardAuthorizeState); + tas->merchant_url = merchant_url; + tas->justification = justification; + tas->http_status = http_status; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (amount, + &tas->amount)); + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = tas, + .run = &reward_authorize_run, + .cleanup = &reward_authorize_cleanup, + .traits = &reward_authorize_traits + }; + + return cmd; + } +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_reward_authorize_from_reserve (const char *label, + const char *merchant_url, + const char *exchange_url, + const char *reserve_reference, + unsigned int http_status, + const char *justification, + const char *amount) +{ + struct RewardAuthorizeState *tas; + + tas = GNUNET_new (struct RewardAuthorizeState); + tas->merchant_url = merchant_url; + tas->reserve_reference = reserve_reference; + tas->justification = justification; + tas->http_status = http_status; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (amount, + &tas->amount)); + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = tas, + .run = &reward_authorize_run, + .cleanup = &reward_authorize_cleanup, + .traits = &reward_authorize_traits + }; + + return cmd; + } +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_reward_authorize_fake (const char *label) +{ + struct RewardAuthorizeState *tas; + + tas = GNUNET_new (struct RewardAuthorizeState); + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = tas, + .run = &reward_authorize_fake_run, + .cleanup = &reward_authorize_cleanup, + .traits = &reward_authorize_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_reward_authorize.c */ diff --git a/src/testing/testing_api_cmd_reward_pickup.c b/src/testing/testing_api_cmd_reward_pickup.c @@ -0,0 +1,415 @@ +/* + This file is part of TALER + Copyright (C) 2014-2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + <http://www.gnu.org/licenses/> +*/ + +/** + * @file testing_api_cmd_reward_pickup.c + * @brief command to test picking up a reward. + * @author Marcello Stanisci + */ +#include "platform.h" +#include <taler/taler_exchange_service.h> +#include <taler/taler_testing_lib.h> +#include "taler_merchant_service.h" +#include "taler_merchant_testing_lib.h" + +/** + * State for a /reward-pickup CMD. + */ +struct RewardPickupState +{ + /** + * Merchant base URL. + */ + const char *merchant_url; + + /** + * Exchange base URL. + */ + const char *exchange_url; + + /** + * Expected HTTP response code. + */ + unsigned int http_status; + + /** + * Reference to a /reward/authorize CMD. This will be used to + * get the reward id to make the request with. + */ + const char *authorize_reference; + + /** + * If set to non NULL, it references another pickup CMD + * that will provide all the data which is needed to issue + * the request (like planchet secrets, denomination keys..). + */ + const char *replay_reference; + + /** + * Handle to a on-going /reward/pickup request. + */ + struct TALER_MERCHANT_RewardPickupHandle *tpo; + + /** + * The interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * An array of string-defined amounts that indicates + * which denominations are going to be used to receive + * rewards. + */ + const char **amounts; + + /** + * The object version of the above @a amounts. + */ + struct TALER_Amount *amounts_obj; + + /** + * The sum of the the amounts above. + */ + struct TALER_Amount total_amount; + + /** + * The array of denomination keys, in the same order of @a + * amounts. + */ + const struct TALER_EXCHANGE_DenomPublicKey **dks; + + /** + * The array of planchet secrets, in the same order of @a + * amounts. + */ + struct TALER_PlanchetMasterSecretP *psa; + + /** + * Set (by the interpreter) to an array of @a num_coins + * details on coins created from the (successful) reward operation. + */ + struct TALER_EXCHANGE_PrivateCoinDetails *pcds; + + /** + * How many coins are involved in the rewardping operation. + */ + uint32_t num_coins; + + /** + * Expected Taler error code (NOTE: this is NOT the HTTP + * response code). + */ + enum TALER_ErrorCode expected_ec; +}; + + +/** + * Callback for a /reward-pickup request, it mainly checks if + * values returned from the backend are as expected, and if so + * (and if the status was 200 OK) proceede with the withdrawal. + * + * @param cls closure + * @param pd details about the result of the operation + */ +static void +pickup_cb (void *cls, + const struct TALER_MERCHANT_PickupDetails *pd) +{ + struct RewardPickupState *tps = cls; + + tps->tpo = NULL; + if (pd->hr.http_status != tps->http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u (%d) to command %s\n", + pd->hr.http_status, + (int) pd->hr.ec, + TALER_TESTING_interpreter_get_current_label (tps->is)); + TALER_TESTING_FAIL (tps->is); + } + + if (pd->hr.ec != tps->expected_ec) + TALER_TESTING_FAIL (tps->is); + + /* Safe to go ahead: http status was expected. */ + if ( (MHD_HTTP_OK != pd->hr.http_status) || + (TALER_EC_NONE != pd->hr.ec) ) + { + TALER_TESTING_interpreter_next (tps->is); + return; + } + if (pd->details.ok.num_sigs != tps->num_coins) + TALER_TESTING_FAIL (tps->is); + tps->pcds = GNUNET_new_array (tps->num_coins, + struct TALER_EXCHANGE_PrivateCoinDetails); + for (unsigned int i = 0; i<tps->num_coins; i++) + { + struct TALER_EXCHANGE_PrivateCoinDetails *pcd = + &pd->details.ok.pcds[i]; + + tps->pcds[i] = *pcd; + TALER_denom_sig_deep_copy (&tps->pcds[i].sig, + &pcd->sig); + } + TALER_TESTING_interpreter_next (tps->is); +} + + +/** + * Run a /reward-pickup CMD. + * + * @param cls closure + * @param cmd the current /reward-pickup CMD. + * @param is interpreter state. + */ +static void +reward_pickup_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct RewardPickupState *tps = cls; + unsigned int num_planchets; + const struct TALER_TESTING_Command *replay_cmd; + const struct TALER_TESTING_Command *authorize_cmd; + const struct TALER_RewardIdentifierP *reward_id; + + tps->is = is; + tps->exchange_url = TALER_TESTING_get_exchange_url (is); + if (NULL == tps->replay_reference) + { + replay_cmd = NULL; + + /* Count planchets. */ + for (num_planchets = 0; + NULL != tps->amounts[num_planchets]; + num_planchets++) + ; + } + else + { + const uint32_t *np; + + if (NULL == /* looking for "parent" reward-pickup command */ + (replay_cmd + = TALER_TESTING_interpreter_lookup_command (is, + tps->replay_reference)) ) + TALER_TESTING_FAIL (is); + + if (GNUNET_OK != + TALER_TESTING_get_trait_num_planchets (replay_cmd, + &np)) + TALER_TESTING_FAIL (is); + num_planchets = *np; + } + + if (NULL == + (authorize_cmd + = TALER_TESTING_interpreter_lookup_command (is, + tps->authorize_reference)) ) + TALER_TESTING_FAIL (is); + + tps->num_coins = num_planchets; + { + struct TALER_MERCHANT_PlanchetData planchets[num_planchets]; + + tps->psa = GNUNET_new_array (num_planchets, + struct TALER_PlanchetMasterSecretP); + tps->dks = GNUNET_new_array (num_planchets, + const struct TALER_EXCHANGE_DenomPublicKey *); + tps->amounts_obj = GNUNET_new_array (num_planchets, + struct TALER_Amount); + for (unsigned int i = 0; i<num_planchets; i++) + { + if (NULL == replay_cmd) + { + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (tps->amounts[i], + &tps->amounts_obj[i])); + if (0 == i) + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (tps->amounts_obj[i].currency, + &tps->total_amount)); + + GNUNET_assert (0 < + TALER_amount_add (&tps->total_amount, + &tps->total_amount, + &tps->amounts_obj[i])); + tps->dks[i] = TALER_TESTING_find_pk ( + TALER_TESTING_get_keys (is), + &tps->amounts_obj[i], + false); + if (NULL == tps->dks[i]) + TALER_TESTING_FAIL (is); + TALER_planchet_master_setup_random (&tps->psa[i]); + } + else + { + const struct TALER_PlanchetMasterSecretP *ps; + + if (GNUNET_OK != + TALER_TESTING_get_trait_denom_pub (replay_cmd, + i, + &tps->dks[i])) + TALER_TESTING_FAIL (is); + if (GNUNET_OK != + TALER_TESTING_get_trait_planchet_secrets (replay_cmd, + i, + &ps)) + TALER_TESTING_FAIL (is); + tps->psa[i] = *ps; + } + planchets[i].pk = tps->dks[i]; + planchets[i].ps = tps->psa[i]; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_reward_id (authorize_cmd, + &reward_id)) + TALER_TESTING_FAIL (is); + tps->tpo = TALER_MERCHANT_reward_pickup ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + tps->merchant_url, + reward_id, + num_planchets, + planchets, + &pickup_cb, + tps); + GNUNET_assert (NULL != tps->tpo); + } +} + + +/** + * Free a /reward-pickup CMD state, and possibly cancel a + * pending /reward-pickup request. + * + * @param cls closure. + * @param cmd current CMD to be freed. + */ +static void +reward_pickup_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct RewardPickupState *tps = cls; + + GNUNET_free (tps->amounts_obj); + GNUNET_free (tps->dks); + GNUNET_free (tps->psa); + if (NULL != tps->pcds) + { + for (unsigned int i = 0; i<tps->num_coins; i++) + TALER_denom_sig_free (&tps->pcds[i].sig); + GNUNET_free (tps->pcds); + } + if (NULL != tps->tpo) + { + TALER_LOG_WARNING ("Reward-pickup operation did not complete\n"); + TALER_MERCHANT_reward_pickup_cancel (tps->tpo); + } + GNUNET_free (tps); +} + + +static enum GNUNET_GenericReturnValue +reward_pickup_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct RewardPickupState *tps = cls; + + if (index >= tps->num_coins) + return GNUNET_SYSERR; + { + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_planchet_secrets (index, + &tps->psa[index]), + TALER_TESTING_make_trait_coin_priv (index, + &tps->pcds[index].coin_priv), + TALER_TESTING_make_trait_denom_pub (index, + tps->dks[index]), + TALER_TESTING_make_trait_denom_sig (index, + &tps->pcds[index].sig), + TALER_TESTING_make_trait_amounts (index, + &tps->amounts_obj[index]), + TALER_TESTING_make_trait_amount (&tps->total_amount), + TALER_TESTING_make_trait_num_planchets (&tps->num_coins), + TALER_TESTING_make_trait_exchange_url (tps->exchange_url), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); + } +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_reward_pickup (const char *label, + const char *merchant_url, + unsigned int http_status, + const char *authorize_reference, + const char **amounts) +{ + struct RewardPickupState *tps; + + tps = GNUNET_new (struct RewardPickupState); + tps->merchant_url = merchant_url; + tps->authorize_reference = authorize_reference; + tps->amounts = amounts; + tps->http_status = http_status; + { + struct TALER_TESTING_Command cmd = { + .cls = tps, + .label = label, + .run = &reward_pickup_run, + .cleanup = &reward_pickup_cleanup, + .traits = &reward_pickup_traits + }; + + return cmd; + } +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_reward_pickup_with_ec (const char *label, + const char *merchant_url, + unsigned int http_status, + const char *authorize_reference, + const char **amounts, + enum TALER_ErrorCode ec) +{ + struct TALER_TESTING_Command cmd; + struct RewardPickupState *tps; + + cmd = TALER_TESTING_cmd_reward_pickup (label, + merchant_url, + http_status, + authorize_reference, + amounts); + tps = cmd.cls; + tps->expected_ec = ec; + return cmd; +} + + +/* end of testing_api_cmd_reward_pickup.c */ diff --git a/src/testing/testing_api_cmd_tip_authorize.c b/src/testing/testing_api_cmd_tip_authorize.c @@ -1,485 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ - -/** - * @file testing_api_cmd_tip_authorize.c - * @brief command to test the tipping. - * @author Marcello Stanisci - */ - -#include "platform.h" -#include <taler/taler_exchange_service.h> -#include <taler/taler_testing_lib.h> -#include "taler_merchant_service.h" -#include "taler_merchant_testing_lib.h" - - -/** - * State for a /tip-authorize CMD. - */ -struct TipAuthorizeState -{ - - /** - * Merchant base URL. - */ - const char *merchant_url; - - /** - * Expected HTTP response code. - */ - unsigned int http_status; - - /** - * Reference to the reserv to authorize the tip - * from (if NULL, the merchant decides). - */ - const char *reserve_reference; - - /** - * Human-readable justification for the - * tip authorization carried on by this CMD. - */ - const char *justification; - - /** - * Amount that should be authorized for tipping. - */ - struct TALER_Amount amount; - - /** - * Expected Taler error code for this CMD. - */ - enum TALER_ErrorCode expected_ec; - - /** - * Tip taler:// URI. - */ - char *tip_uri; - - /** - * The tip id; set when the CMD succeeds. - */ - struct TALER_TipIdentifierP tip_id; - - /** - * Expiration date for this tip. - */ - struct GNUNET_TIME_Timestamp tip_expiration; - - /** - * Handle to the on-going /tip-authorize request. - */ - struct TALER_MERCHANT_TipAuthorizeHandle *tao; - - /** - * The interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Task used for retries. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * How long do we wait between retries? - */ - struct GNUNET_TIME_Relative backoff; - - /** - * How many retries are left? - */ - unsigned int retries_left; - -}; - - -/** - * Run the main logic of talking to the merchant. - * - * @param cls a `struct TipAuthorizeState`. - */ -static void -do_retry (void *cls); - - -/** - * Callback for a /tip-authorize request. Set into the state - * what was returned from the backend (@a tip_id and @a - * tip_expiration). - * - * @param cls closure - * @param tar response we got - */ -static void -tip_authorize_cb (void *cls, - const struct TALER_MERCHANT_TipAuthorizeResponse *tar) -{ - struct TipAuthorizeState *tas = cls; - - tas->tao = NULL; - if (tas->http_status != tar->hr.http_status) - { - if ( (MHD_HTTP_NOT_FOUND == tar->hr.http_status) && - (0 < tas->retries_left) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Reserve authorization failed. Reserve may not yet be ready, retrying %u more times.\n", - tas->retries_left); - tas->retries_left--; - tas->backoff = GNUNET_TIME_randomized_backoff (tas->backoff, - GNUNET_TIME_UNIT_SECONDS); - tas->retry_task = GNUNET_SCHEDULER_add_delayed (tas->backoff, - &do_retry, - tas); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u (%d) to command %s\n", - tar->hr.http_status, - tar->hr.ec, - TALER_TESTING_interpreter_get_current_label (tas->is)); - TALER_TESTING_interpreter_fail (tas->is); - return; - } - - if (tas->expected_ec != tar->hr.ec) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected error code %d (%u) to command %s\n", - (int) tar->hr.ec, - tar->hr.http_status, - TALER_TESTING_interpreter_get_current_label (tas->is)); - TALER_TESTING_interpreter_fail (tas->is); - return; - } - if ( (MHD_HTTP_OK == tar->hr.http_status) && - (TALER_EC_NONE == tar->hr.ec) ) - { - tas->tip_uri = GNUNET_strdup (tar->details.ok.tip_uri); - tas->tip_id = tar->details.ok.tip_id; - tas->tip_expiration = tar->details.ok.tip_expiration; - } - TALER_TESTING_interpreter_next (tas->is); -} - - -/** - * Offers information from the /tip-authorize CMD state to other - * commands. - * - * @param cls closure - * @param[out] ret result (could be anything) - * @param trait name of the trait - * @param index index number of the object to extract. - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -tip_authorize_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct TipAuthorizeState *tas = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_tip_id (&tas->tip_id), - TALER_TESTING_make_trait_amount (&tas->amount), - TALER_TESTING_make_trait_reason (tas->justification), - TALER_TESTING_make_trait_timestamp (0, - &tas->tip_expiration), - TALER_TESTING_trait_end (), - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Runs the /tip-authorize CMD - * - * @param cls closure - * @param cmd the CMD representing _this_ command - * @param is interpreter state - */ -static void -tip_authorize_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct TipAuthorizeState *tas = cls; - - tas->retries_left = 16; - tas->is = is; - tas->retry_task = GNUNET_SCHEDULER_add_now (&do_retry, - tas); -} - - -static void -do_retry (void *cls) -{ - struct TipAuthorizeState *tas = cls; - - tas->retry_task = NULL; - if (NULL == tas->reserve_reference) - { - tas->tao = TALER_MERCHANT_tip_authorize ( - TALER_TESTING_interpreter_get_context (tas->is), - tas->merchant_url, - "http://merchant.com/pickup", - &tas->amount, - tas->justification, - &tip_authorize_cb, - tas); - } - else - { - const struct TALER_TESTING_Command *reserve_cmd; - const struct TALER_ReservePublicKeyP *reserve_pub; - - reserve_cmd = TALER_TESTING_interpreter_lookup_command ( - tas->is, - tas->reserve_reference); - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_reserve_pub (reserve_cmd, - &reserve_pub)); - tas->tao = TALER_MERCHANT_tip_authorize2 ( - TALER_TESTING_interpreter_get_context (tas->is), - tas->merchant_url, - reserve_pub, - "http://merchant.com/pickup", - &tas->amount, - tas->justification, - &tip_authorize_cb, - tas); - } - GNUNET_assert (NULL != tas->tao); -} - - -/** - * Run the /tip-authorize CMD, the "fake" version of it. - * - * @param cls closure - * @param cmd the CMD representing _this_ command - * @param is interpreter state * - */ -static void -tip_authorize_fake_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct TipAuthorizeState *tas = cls; - - /* Make up a tip id. */ - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, - &tas->tip_id, - sizeof (struct TALER_TipIdentifierP)); - TALER_TESTING_interpreter_next (is); -} - - -/** - * Free the state from a /tip-authorize CMD, and possibly - * cancel any pending operation. - * - * @param cls closure - * @param cmd the /tip-authorize CMD that is about to be freed. - */ -static void -tip_authorize_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct TipAuthorizeState *tas = cls; - - if (NULL != tas->tao) - { - TALER_LOG_WARNING ("Tip-autorize operation" - " did not complete\n"); - TALER_MERCHANT_tip_authorize_cancel (tas->tao); - } - if (NULL != tas->retry_task) - { - GNUNET_SCHEDULER_cancel (tas->retry_task); - tas->retry_task = NULL; - } - GNUNET_free (tas->tip_uri); - GNUNET_free (tas); -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_authorize_with_ec (const char *label, - const char *merchant_url, - const char *exchange_url, - unsigned int http_status, - const char *justification, - const char *amount, - enum TALER_ErrorCode ec) -{ - struct TipAuthorizeState *tas; - - tas = GNUNET_new (struct TipAuthorizeState); - tas->merchant_url = merchant_url; - tas->justification = justification; - tas->http_status = http_status; - tas->expected_ec = ec; - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (amount, - &tas->amount)); - { - struct TALER_TESTING_Command cmd = { - .label = label, - .cls = tas, - .run = &tip_authorize_run, - .cleanup = &tip_authorize_cleanup, - .traits = &tip_authorize_traits - }; - - return cmd; - } -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_authorize_from_reserve_with_ec ( - const char *label, - const char *merchant_url, - const char *exchange_url, - const char *reserve_reference, - unsigned int http_status, - const char *justification, - const char *amount, - enum TALER_ErrorCode ec) -{ - struct TipAuthorizeState *tas; - - tas = GNUNET_new (struct TipAuthorizeState); - tas->merchant_url = merchant_url; - tas->justification = justification; - tas->http_status = http_status; - tas->expected_ec = ec; - tas->reserve_reference = reserve_reference; - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (amount, - &tas->amount)); - { - struct TALER_TESTING_Command cmd = { - .label = label, - .cls = tas, - .run = &tip_authorize_run, - .cleanup = &tip_authorize_cleanup, - .traits = &tip_authorize_traits - }; - - return cmd; - } -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_authorize (const char *label, - const char *merchant_url, - const char *exchange_url, - unsigned int http_status, - const char *justification, - const char *amount) -{ - struct TipAuthorizeState *tas; - - tas = GNUNET_new (struct TipAuthorizeState); - tas->merchant_url = merchant_url; - tas->justification = justification; - tas->http_status = http_status; - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (amount, - &tas->amount)); - { - struct TALER_TESTING_Command cmd = { - .label = label, - .cls = tas, - .run = &tip_authorize_run, - .cleanup = &tip_authorize_cleanup, - .traits = &tip_authorize_traits - }; - - return cmd; - } -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_authorize_from_reserve (const char *label, - const char *merchant_url, - const char *exchange_url, - const char *reserve_reference, - unsigned int http_status, - const char *justification, - const char *amount) -{ - struct TipAuthorizeState *tas; - - tas = GNUNET_new (struct TipAuthorizeState); - tas->merchant_url = merchant_url; - tas->reserve_reference = reserve_reference; - tas->justification = justification; - tas->http_status = http_status; - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (amount, - &tas->amount)); - { - struct TALER_TESTING_Command cmd = { - .label = label, - .cls = tas, - .run = &tip_authorize_run, - .cleanup = &tip_authorize_cleanup, - .traits = &tip_authorize_traits - }; - - return cmd; - } -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_authorize_fake (const char *label) -{ - struct TipAuthorizeState *tas; - - tas = GNUNET_new (struct TipAuthorizeState); - { - struct TALER_TESTING_Command cmd = { - .label = label, - .cls = tas, - .run = &tip_authorize_fake_run, - .cleanup = &tip_authorize_cleanup, - .traits = &tip_authorize_traits - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_tip_authorize.c */ diff --git a/src/testing/testing_api_cmd_tip_pickup.c b/src/testing/testing_api_cmd_tip_pickup.c @@ -1,415 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ - -/** - * @file testing_api_cmd_tip_pickup.c - * @brief command to test the tipping. - * @author Marcello Stanisci - */ -#include "platform.h" -#include <taler/taler_exchange_service.h> -#include <taler/taler_testing_lib.h> -#include "taler_merchant_service.h" -#include "taler_merchant_testing_lib.h" - -/** - * State for a /tip-pickup CMD. - */ -struct TipPickupState -{ - /** - * Merchant base URL. - */ - const char *merchant_url; - - /** - * Exchange base URL. - */ - const char *exchange_url; - - /** - * Expected HTTP response code. - */ - unsigned int http_status; - - /** - * Reference to a /tip/authorize CMD. This will be used to - * get the tip id to make the request with. - */ - const char *authorize_reference; - - /** - * If set to non NULL, it references another pickup CMD - * that will provide all the data which is needed to issue - * the request (like planchet secrets, denomination keys..). - */ - const char *replay_reference; - - /** - * Handle to a on-going /tip/pickup request. - */ - struct TALER_MERCHANT_TipPickupHandle *tpo; - - /** - * The interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * An array of string-defined amounts that indicates - * which denominations are going to be used to receive - * tips. - */ - const char **amounts; - - /** - * The object version of the above @a amounts. - */ - struct TALER_Amount *amounts_obj; - - /** - * The sum of the the amounts above. - */ - struct TALER_Amount total_amount; - - /** - * The array of denomination keys, in the same order of @a - * amounts. - */ - const struct TALER_EXCHANGE_DenomPublicKey **dks; - - /** - * The array of planchet secrets, in the same order of @a - * amounts. - */ - struct TALER_PlanchetMasterSecretP *psa; - - /** - * Set (by the interpreter) to an array of @a num_coins - * details on coins created from the (successful) tip operation. - */ - struct TALER_EXCHANGE_PrivateCoinDetails *pcds; - - /** - * How many coins are involved in the tipping operation. - */ - uint32_t num_coins; - - /** - * Expected Taler error code (NOTE: this is NOT the HTTP - * response code). - */ - enum TALER_ErrorCode expected_ec; -}; - - -/** - * Callback for a /tip-pickup request, it mainly checks if - * values returned from the backend are as expected, and if so - * (and if the status was 200 OK) proceede with the withdrawal. - * - * @param cls closure - * @param pd details about the result of the operation - */ -static void -pickup_cb (void *cls, - const struct TALER_MERCHANT_PickupDetails *pd) -{ - struct TipPickupState *tps = cls; - - tps->tpo = NULL; - if (pd->hr.http_status != tps->http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u (%d) to command %s\n", - pd->hr.http_status, - (int) pd->hr.ec, - TALER_TESTING_interpreter_get_current_label (tps->is)); - TALER_TESTING_FAIL (tps->is); - } - - if (pd->hr.ec != tps->expected_ec) - TALER_TESTING_FAIL (tps->is); - - /* Safe to go ahead: http status was expected. */ - if ( (MHD_HTTP_OK != pd->hr.http_status) || - (TALER_EC_NONE != pd->hr.ec) ) - { - TALER_TESTING_interpreter_next (tps->is); - return; - } - if (pd->details.ok.num_sigs != tps->num_coins) - TALER_TESTING_FAIL (tps->is); - tps->pcds = GNUNET_new_array (tps->num_coins, - struct TALER_EXCHANGE_PrivateCoinDetails); - for (unsigned int i = 0; i<tps->num_coins; i++) - { - struct TALER_EXCHANGE_PrivateCoinDetails *pcd = - &pd->details.ok.pcds[i]; - - tps->pcds[i] = *pcd; - TALER_denom_sig_deep_copy (&tps->pcds[i].sig, - &pcd->sig); - } - TALER_TESTING_interpreter_next (tps->is); -} - - -/** - * Run a /tip-pickup CMD. - * - * @param cls closure - * @param cmd the current /tip-pickup CMD. - * @param is interpreter state. - */ -static void -tip_pickup_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct TipPickupState *tps = cls; - unsigned int num_planchets; - const struct TALER_TESTING_Command *replay_cmd; - const struct TALER_TESTING_Command *authorize_cmd; - const struct TALER_TipIdentifierP *tip_id; - - tps->is = is; - tps->exchange_url = TALER_TESTING_get_exchange_url (is); - if (NULL == tps->replay_reference) - { - replay_cmd = NULL; - - /* Count planchets. */ - for (num_planchets = 0; - NULL != tps->amounts[num_planchets]; - num_planchets++) - ; - } - else - { - const uint32_t *np; - - if (NULL == /* looking for "parent" tip-pickup command */ - (replay_cmd - = TALER_TESTING_interpreter_lookup_command (is, - tps->replay_reference)) ) - TALER_TESTING_FAIL (is); - - if (GNUNET_OK != - TALER_TESTING_get_trait_num_planchets (replay_cmd, - &np)) - TALER_TESTING_FAIL (is); - num_planchets = *np; - } - - if (NULL == - (authorize_cmd - = TALER_TESTING_interpreter_lookup_command (is, - tps->authorize_reference)) ) - TALER_TESTING_FAIL (is); - - tps->num_coins = num_planchets; - { - struct TALER_MERCHANT_PlanchetData planchets[num_planchets]; - - tps->psa = GNUNET_new_array (num_planchets, - struct TALER_PlanchetMasterSecretP); - tps->dks = GNUNET_new_array (num_planchets, - const struct TALER_EXCHANGE_DenomPublicKey *); - tps->amounts_obj = GNUNET_new_array (num_planchets, - struct TALER_Amount); - for (unsigned int i = 0; i<num_planchets; i++) - { - if (NULL == replay_cmd) - { - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (tps->amounts[i], - &tps->amounts_obj[i])); - if (0 == i) - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (tps->amounts_obj[i].currency, - &tps->total_amount)); - - GNUNET_assert (0 < - TALER_amount_add (&tps->total_amount, - &tps->total_amount, - &tps->amounts_obj[i])); - tps->dks[i] = TALER_TESTING_find_pk ( - TALER_TESTING_get_keys (is), - &tps->amounts_obj[i], - false); - if (NULL == tps->dks[i]) - TALER_TESTING_FAIL (is); - TALER_planchet_master_setup_random (&tps->psa[i]); - } - else - { - const struct TALER_PlanchetMasterSecretP *ps; - - if (GNUNET_OK != - TALER_TESTING_get_trait_denom_pub (replay_cmd, - i, - &tps->dks[i])) - TALER_TESTING_FAIL (is); - if (GNUNET_OK != - TALER_TESTING_get_trait_planchet_secrets (replay_cmd, - i, - &ps)) - TALER_TESTING_FAIL (is); - tps->psa[i] = *ps; - } - planchets[i].pk = tps->dks[i]; - planchets[i].ps = tps->psa[i]; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_tip_id (authorize_cmd, - &tip_id)) - TALER_TESTING_FAIL (is); - tps->tpo = TALER_MERCHANT_tip_pickup ( - TALER_TESTING_interpreter_get_context (is), - TALER_TESTING_get_exchange_url (is), - tps->merchant_url, - tip_id, - num_planchets, - planchets, - &pickup_cb, - tps); - GNUNET_assert (NULL != tps->tpo); - } -} - - -/** - * Free a /tip-pickup CMD state, and possibly cancel a - * pending /tip-pickup request. - * - * @param cls closure. - * @param cmd current CMD to be freed. - */ -static void -tip_pickup_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct TipPickupState *tps = cls; - - GNUNET_free (tps->amounts_obj); - GNUNET_free (tps->dks); - GNUNET_free (tps->psa); - if (NULL != tps->pcds) - { - for (unsigned int i = 0; i<tps->num_coins; i++) - TALER_denom_sig_free (&tps->pcds[i].sig); - GNUNET_free (tps->pcds); - } - if (NULL != tps->tpo) - { - TALER_LOG_WARNING ("Tip-pickup operation did not complete\n"); - TALER_MERCHANT_tip_pickup_cancel (tps->tpo); - } - GNUNET_free (tps); -} - - -static enum GNUNET_GenericReturnValue -tip_pickup_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct TipPickupState *tps = cls; - - if (index >= tps->num_coins) - return GNUNET_SYSERR; - { - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_planchet_secrets (index, - &tps->psa[index]), - TALER_TESTING_make_trait_coin_priv (index, - &tps->pcds[index].coin_priv), - TALER_TESTING_make_trait_denom_pub (index, - tps->dks[index]), - TALER_TESTING_make_trait_denom_sig (index, - &tps->pcds[index].sig), - TALER_TESTING_make_trait_amounts (index, - &tps->amounts_obj[index]), - TALER_TESTING_make_trait_amount (&tps->total_amount), - TALER_TESTING_make_trait_num_planchets (&tps->num_coins), - TALER_TESTING_make_trait_exchange_url (tps->exchange_url), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); - } -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_pickup (const char *label, - const char *merchant_url, - unsigned int http_status, - const char *authorize_reference, - const char **amounts) -{ - struct TipPickupState *tps; - - tps = GNUNET_new (struct TipPickupState); - tps->merchant_url = merchant_url; - tps->authorize_reference = authorize_reference; - tps->amounts = amounts; - tps->http_status = http_status; - { - struct TALER_TESTING_Command cmd = { - .cls = tps, - .label = label, - .run = &tip_pickup_run, - .cleanup = &tip_pickup_cleanup, - .traits = &tip_pickup_traits - }; - - return cmd; - } -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_pickup_with_ec (const char *label, - const char *merchant_url, - unsigned int http_status, - const char *authorize_reference, - const char **amounts, - enum TALER_ErrorCode ec) -{ - struct TALER_TESTING_Command cmd; - struct TipPickupState *tps; - - cmd = TALER_TESTING_cmd_tip_pickup (label, - merchant_url, - http_status, - authorize_reference, - amounts); - tps = cmd.cls; - tps->expected_ec = ec; - return cmd; -} - - -/* end of testing_api_cmd_tip_pickup.c */ diff --git a/src/testing/testing_api_cmd_wallet_get_reward.c b/src/testing/testing_api_cmd_wallet_get_reward.c @@ -0,0 +1,259 @@ +/* + This file is part of TALER + Copyright (C) 2014-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file testing_api_cmd_wallet_get_reward.c + * @brief command to test the rewardping. + * @author Marcello Stanisci + */ +#include "platform.h" +#include <taler/taler_exchange_service.h> +#include <taler/taler_testing_lib.h> +#include "taler_merchant_service.h" +#include "taler_merchant_testing_lib.h" + + +/** + * State for a GET /rewards/$REWARD_ID CMD. + */ +struct WalletRewardGetState +{ + + /** + * The merchant base URL. + */ + const char *merchant_url; + + /** + * Expected HTTP response code for this CMD. + */ + unsigned int http_status; + + /** + * Whether to compare amounts or not. + */ + bool cmp_amounts; + + /** + * The expected amount remaining. + */ + struct TALER_Amount amount_remaining; + + /** + * The handle to the current GET /rewards/$REWARD_ID request. + */ + struct TALER_MERCHANT_RewardWalletGetHandle *tgh; + + /** + * The interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Reference to a command that created a reward. + */ + const char *reward_reference; +}; + + +/** + * Callback to process a GET /rewards/$REWARD_ID request, it mainly + * checks that what the backend returned matches the command's + * expectations. + * + * @param cls closure + * @param wgr response + */ +static void +wallet_reward_get_cb (void *cls, + const struct TALER_MERCHANT_RewardWalletGetResponse *wgr) +{ + struct WalletRewardGetState *gts = cls; + const struct TALER_TESTING_Command *reward_cmd; + + reward_cmd = TALER_TESTING_interpreter_lookup_command ( + gts->is, + gts->reward_reference); + + gts->tgh = NULL; + if (gts->http_status != wgr->hr.http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u (%d) to command %s\n", + wgr->hr.http_status, + (int) wgr->hr.ec, + TALER_TESTING_interpreter_get_current_label (gts->is)); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + switch (wgr->hr.http_status) + { + case MHD_HTTP_OK: + if (gts->cmp_amounts) + { + if ((GNUNET_OK != + TALER_amount_cmp_currency (&gts->amount_remaining, + &wgr->details.ok.amount_remaining)) + || + (0 != TALER_amount_cmp (&gts->amount_remaining, + &wgr->details.ok.amount_remaining))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Amount remaining on reward does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + { + const struct GNUNET_TIME_Timestamp *expiration; + + if (GNUNET_OK != + TALER_TESTING_get_trait_timestamp (reward_cmd, + 0, + &expiration)) + TALER_TESTING_interpreter_fail (gts->is); + if (GNUNET_TIME_timestamp_cmp (*expiration, + !=, + wgr->details.ok.expiration)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Reward expiration does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Unhandled HTTP status.\n"); + } + TALER_TESTING_interpreter_next (gts->is); +} + + +/** + * Run the "GET reward" CMD. + * + * @param cls closure. + * @param cmd command being run now. + * @param is interpreter state. + */ +static void +wallet_get_reward_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct WalletRewardGetState *tgs = cls; + const struct TALER_TESTING_Command *reward_cmd; + const struct TALER_RewardIdentifierP *reward_id; + + reward_cmd = TALER_TESTING_interpreter_lookup_command (is, + tgs->reward_reference); + + if (GNUNET_OK != + TALER_TESTING_get_trait_reward_id (reward_cmd, + &reward_id)) + TALER_TESTING_FAIL (is); + + tgs->is = is; + tgs->tgh = TALER_MERCHANT_wallet_reward_get ( + TALER_TESTING_interpreter_get_context (is), + tgs->merchant_url, + reward_id, + &wallet_reward_get_cb, + tgs); +} + + +/** + * Free the state of a "GET reward" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure. + * @param cmd command being run. + */ +static void +wallet_get_reward_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct WalletRewardGetState *tgs = cls; + + if (NULL != tgs->tgh) + { + TALER_LOG_WARNING ("Get reward operation did not complete\n"); + TALER_MERCHANT_wallet_reward_get_cancel (tgs->tgh); + } + GNUNET_free (tgs); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_wallet_get_reward (const char *label, + const char *merchant_url, + const char *reward_reference, + unsigned int http_status) +{ + struct WalletRewardGetState *tgs; + + tgs = GNUNET_new (struct WalletRewardGetState); + tgs->merchant_url = merchant_url; + tgs->reward_reference = reward_reference; + tgs->http_status = http_status; + { + struct TALER_TESTING_Command cmd = { + .cls = tgs, + .label = label, + .run = &wallet_get_reward_run, + .cleanup = &wallet_get_reward_cleanup + }; + + return cmd; + } +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_wallet_get_reward2 (const char *label, + const char *merchant_url, + const char *reward_reference, + const char *amount_remaining, + unsigned int http_status) +{ + struct WalletRewardGetState *tgs; + + tgs = GNUNET_new (struct WalletRewardGetState); + tgs->merchant_url = merchant_url; + tgs->reward_reference = reward_reference; + tgs->cmp_amounts = true; + GNUNET_assert (GNUNET_OK == TALER_string_to_amount (amount_remaining, + &tgs->amount_remaining)); + tgs->http_status = http_status; + { + struct TALER_TESTING_Command cmd = { + .cls = tgs, + .label = label, + .run = &wallet_get_reward_run, + .cleanup = &wallet_get_reward_cleanup + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_wallet_get_reward.c */ diff --git a/src/testing/testing_api_cmd_wallet_get_tip.c b/src/testing/testing_api_cmd_wallet_get_tip.c @@ -1,258 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file testing_api_cmd_wallet_get_tip.c - * @brief command to test the tipping. - * @author Marcello Stanisci - */ -#include "platform.h" -#include <taler/taler_exchange_service.h> -#include <taler/taler_testing_lib.h> -#include "taler_merchant_service.h" -#include "taler_merchant_testing_lib.h" - - -/** - * State for a GET /tips/$TIP_ID CMD. - */ -struct WalletTipGetState -{ - - /** - * The merchant base URL. - */ - const char *merchant_url; - - /** - * Expected HTTP response code for this CMD. - */ - unsigned int http_status; - - /** - * Whether to compare amounts or not. - */ - bool cmp_amounts; - - /** - * The expected amount remaining. - */ - struct TALER_Amount amount_remaining; - - /** - * The handle to the current GET /tips/$TIP_ID request. - */ - struct TALER_MERCHANT_TipWalletGetHandle *tgh; - - /** - * The interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Reference to a command that created a tip. - */ - const char *tip_reference; -}; - - -/** - * Callback to process a GET /tips/$TIP_ID request, it mainly - * checks that what the backend returned matches the command's - * expectations. - * - * @param cls closure - * @param wgr response - */ -static void -wallet_tip_get_cb (void *cls, - const struct TALER_MERCHANT_TipWalletGetResponse *wgr) -{ - struct WalletTipGetState *gts = cls; - const struct TALER_TESTING_Command *tip_cmd; - - tip_cmd = TALER_TESTING_interpreter_lookup_command ( - gts->is, - gts->tip_reference); - - gts->tgh = NULL; - if (gts->http_status != wgr->hr.http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u (%d) to command %s\n", - wgr->hr.http_status, - (int) wgr->hr.ec, - TALER_TESTING_interpreter_get_current_label (gts->is)); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - switch (wgr->hr.http_status) - { - case MHD_HTTP_OK: - if (gts->cmp_amounts) - { - if ((GNUNET_OK != - TALER_amount_cmp_currency (&gts->amount_remaining, - &wgr->details.ok.amount_remaining)) - || - (0 != TALER_amount_cmp (&gts->amount_remaining, - &wgr->details.ok.amount_remaining))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Amount remaining on tip does not match\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - } - { - const struct GNUNET_TIME_Timestamp *expiration; - - if (GNUNET_OK != - TALER_TESTING_get_trait_timestamp (tip_cmd, - 0, - &expiration)) - TALER_TESTING_interpreter_fail (gts->is); - if (GNUNET_TIME_timestamp_cmp (*expiration, - !=, - wgr->details.ok.expiration)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Tip expiration does not match\n"); - TALER_TESTING_interpreter_fail (gts->is); - return; - } - } - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Unhandled HTTP status.\n"); - } - TALER_TESTING_interpreter_next (gts->is); -} - - -/** - * Run the "GET tip" CMD. - * - * @param cls closure. - * @param cmd command being run now. - * @param is interpreter state. - */ -static void -wallet_get_tip_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct WalletTipGetState *tgs = cls; - const struct TALER_TESTING_Command *tip_cmd; - const struct TALER_TipIdentifierP *tip_id; - - tip_cmd = TALER_TESTING_interpreter_lookup_command (is, - tgs->tip_reference); - - if (GNUNET_OK != - TALER_TESTING_get_trait_tip_id (tip_cmd, - &tip_id)) - TALER_TESTING_FAIL (is); - - tgs->is = is; - tgs->tgh = TALER_MERCHANT_wallet_tip_get (TALER_TESTING_interpreter_get_context (is), - tgs->merchant_url, - tip_id, - &wallet_tip_get_cb, - tgs); -} - - -/** - * Free the state of a "GET tip" CMD, and possibly - * cancel a pending operation thereof. - * - * @param cls closure. - * @param cmd command being run. - */ -static void -wallet_get_tip_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct WalletTipGetState *tgs = cls; - - if (NULL != tgs->tgh) - { - TALER_LOG_WARNING ("Get tip operation did not complete\n"); - TALER_MERCHANT_wallet_tip_get_cancel (tgs->tgh); - } - GNUNET_free (tgs); -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_wallet_get_tip (const char *label, - const char *merchant_url, - const char *tip_reference, - unsigned int http_status) -{ - struct WalletTipGetState *tgs; - - tgs = GNUNET_new (struct WalletTipGetState); - tgs->merchant_url = merchant_url; - tgs->tip_reference = tip_reference; - tgs->http_status = http_status; - { - struct TALER_TESTING_Command cmd = { - .cls = tgs, - .label = label, - .run = &wallet_get_tip_run, - .cleanup = &wallet_get_tip_cleanup - }; - - return cmd; - } -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_wallet_get_tip2 (const char *label, - const char *merchant_url, - const char *tip_reference, - const char *amount_remaining, - unsigned int http_status) -{ - struct WalletTipGetState *tgs; - - tgs = GNUNET_new (struct WalletTipGetState); - tgs->merchant_url = merchant_url; - tgs->tip_reference = tip_reference; - tgs->cmp_amounts = true; - GNUNET_assert (GNUNET_OK == TALER_string_to_amount (amount_remaining, - &tgs->amount_remaining)); - tgs->http_status = http_status; - { - struct TALER_TESTING_Command cmd = { - .cls = tgs, - .label = label, - .run = &wallet_get_tip_run, - .cleanup = &wallet_get_tip_cleanup - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_wallet_get_tip.c */