summaryrefslogtreecommitdiff
path: root/src/backend/taler-merchant-httpd_private-get-reserves-ID.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2020-05-31 20:34:39 +0200
committerChristian Grothoff <christian@grothoff.org>2020-05-31 20:34:39 +0200
commit915480618b84f281aaa9bac3f711cf6e5fd555c1 (patch)
treec04efcf79ffcaf3fbda4b8f81a56fc3361d4316f /src/backend/taler-merchant-httpd_private-get-reserves-ID.c
parent990f4d4d5192506aa4a5f6510449e0aa79a2e61f (diff)
downloadmerchant-915480618b84f281aaa9bac3f711cf6e5fd555c1.tar.gz
merchant-915480618b84f281aaa9bac3f711cf6e5fd555c1.tar.bz2
merchant-915480618b84f281aaa9bac3f711cf6e5fd555c1.zip
implement GET /reserves/RPUB
Diffstat (limited to 'src/backend/taler-merchant-httpd_private-get-reserves-ID.c')
-rw-r--r--src/backend/taler-merchant-httpd_private-get-reserves-ID.c305
1 files changed, 133 insertions, 172 deletions
diff --git a/src/backend/taler-merchant-httpd_private-get-reserves-ID.c b/src/backend/taler-merchant-httpd_private-get-reserves-ID.c
index f7aa0ab0..d77a7bf9 100644
--- a/src/backend/taler-merchant-httpd_private-get-reserves-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-reserves-ID.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2018 Taler Systems SA
+ (C) 2018, 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
@@ -14,10 +14,9 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file backend/taler-merchant-httpd_tip-query.c
- * @brief implement API for authorizing tips to be paid to visitors
+ * @file backend/taler-merchant-httpd_private-get-reserves-ID.c
+ * @brief implement GET /reserves/$RESERVE_PUB endpoint
* @author Christian Grothoff
- * @author Florian Dold
*/
#include "platform.h"
#include <jansson.h>
@@ -26,223 +25,185 @@
#include "taler-merchant-httpd.h"
#include "taler-merchant-httpd_mhd.h"
#include "taler-merchant-httpd_exchanges.h"
-#include "taler-merchant-httpd_tip-query.h"
-#include "taler-merchant-httpd_tip-reserve-helper.h"
+#include "taler-merchant-httpd_private-get-reserves-ID.h"
/**
- * Maximum number of retries for database operations.
+ * Closure for handle_reserve_details().
*/
-#define MAX_RETRIES 5
-
-
-/**
- * Internal per-request state for processing tip queries.
- */
-struct TipQueryContext
+struct GetReserveContext
{
/**
- * This field MUST be first for handle_mhd_completion_callback() to work
- * when it treats this struct as a `struct TM_HandlerContext`.
- */
- struct TM_HandlerContext hc;
-
- /**
- * Merchant instance to use.
+ * Connection we are handling.
*/
- const char *instance;
+ struct MHD_Connection *connection;
/**
- * Context for checking the tipping reserve's status.
+ * Value to return from the callback.
*/
- struct TMH_CheckTipReserve ctr;
+ MHD_RESULT res;
/**
- * #GNUNET_YES if the tip query has already been processed
- * and we can queue the response.
+ * Should we return details about tips?
*/
- int processed;
-
+ bool tips;
};
/**
- * Custom cleanup routine for a `struct TipQueryContext`.
+ * Callback with reserve details.
*
- * @param hc the `struct TMH_JsonParseContext` to clean up.
+ * @param cls closure with a `struct GetReserveContext`
+ * @param creation_time time when the reserve was setup
+ * @param expiration_time time when the reserve will be closed by the exchange
+ * @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
+ * picked up yet
+ * @param tips_length length of the @a tips array
+ * @param tips information about the tips created by this reserve
*/
static void
-cleanup_tqc (struct TM_HandlerContext *hc)
+handle_reserve_details (void *cls,
+ struct GNUNET_TIME_Absolute creation_time,
+ struct GNUNET_TIME_Absolute expiration_time,
+ const struct TALER_Amount *merchant_initial_amount,
+ const struct TALER_Amount *exchange_initial_amount,
+ const struct TALER_Amount *picked_up_amount,
+ const struct TALER_Amount *committed_amount,
+ unsigned int tips_length,
+ const struct TALER_MERCHANTDB_TipDetails *tips)
{
- struct TipQueryContext *tqc = (struct TipQueryContext *) hc;
-
- TMH_check_tip_reserve_cleanup (&tqc->ctr);
- GNUNET_free (tqc);
-}
-
+ struct GetReserveContext *ctx = cls;
+ json_t *tips_json;
-/**
- * We've been resumed after processing the reserve data from the
- * exchange without error. Generate the final response.
- *
- * @param tqc context for which to generate the response.
- */
-static int
-generate_final_response (struct TipQueryContext *tqc)
-{
- struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
- struct TALER_Amount amount_available;
-
- GNUNET_CRYPTO_eddsa_key_get_public (&tqc->ctr.reserve_priv.eddsa_priv,
- &reserve_pub);
- if (0 >
- TALER_amount_subtract (&amount_available,
- &tqc->ctr.amount_deposited,
- &tqc->ctr.amount_withdrawn))
+ if (tips)
{
- char *a1;
- char *a2;
+ tips_json = json_array ();
+ GNUNET_assert (NULL != tips_json);
- GNUNET_break_op (0);
- a1 = TALER_amount_to_string (&tqc->ctr.amount_deposited);
- a2 = TALER_amount_to_string (&tqc->ctr.amount_withdrawn);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "amount overflow, deposited %s but withdrawn %s\n",
- a1,
- a2);
- GNUNET_free (a2);
- GNUNET_free (a1);
- return TALER_MHD_reply_with_error (
- tqc->ctr.connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_TIP_QUERY_RESERVE_HISTORY_ARITHMETIC_ISSUE_INCONSISTENT,
- "Exchange returned invalid reserve history (amount overflow)");
+ for (unsigned int i = 0; i<tips_length; i++)
+ {
+ GNUNET_assert (0 ==
+ json_array_append_new (
+ tips_json,
+ json_pack ("{s:o,s:o,s:I}",
+ "tip_id",
+ GNUNET_JSON_from_data_auto (
+ &tips[i].tip_id),
+ "total_amount",
+ TALER_JSON_from_amount (
+ &tips[i].total_amount),
+ "reason",
+ tips[i].reason)));
+ }
}
- return TALER_MHD_reply_json_pack (
- tqc->ctr.connection,
+ else
+ {
+ tips_json = NULL;
+ }
+ ctx->res = TALER_MHD_reply_json_pack (
+ ctx->connection,
MHD_HTTP_OK,
- "{s:o, s:o, s:o, s:o, s:o}",
- "reserve_pub",
- GNUNET_JSON_from_data_auto (&reserve_pub),
- "reserve_expiration",
- GNUNET_JSON_from_time_abs (tqc->ctr.reserve_expiration),
- "amount_authorized",
- TALER_JSON_from_amount (&tqc->ctr.amount_authorized),
- "amount_picked_up",
- TALER_JSON_from_amount (&tqc->ctr.amount_withdrawn),
- "amount_available",
- TALER_JSON_from_amount (&amount_available));
+ "{s:o, s:o, s:o, s:o, s:o, s:o, s:o?}",
+ "creation_time", GNUNET_JSON_from_time_abs (creation_time),
+ "expiration_time", GNUNET_JSON_from_time_abs (expiration_time),
+ "merchant_initial_amount", TALER_JSON_from_amount (merchant_initial_amount),
+ "exchange_initial_amount", TALER_JSON_from_amount (exchange_initial_amount),
+ "pickup_amount", TALER_JSON_from_amount (picked_up_amount),
+ "committed_amount", TALER_JSON_from_amount (committed_amount),
+ "tips", tips_json);
}
/**
- * Handle a "/tip-query" request.
+ * Manages a GET /reserves/$RESERVE_PUB call.
*
* @param rh context of the handler
* @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @param mi merchant backend instance, never NULL
+ * @param[in,out] hc context with further information about the request
* @return MHD result code
*/
MHD_RESULT
-MH_handler_tip_query (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size,
- struct MerchantInstance *mi)
+TMH_private_get_reserves_ID (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
{
- struct TipQueryContext *tqc;
-
- if (NULL == *connection_cls)
+ struct TALER_ReservePublicKeyP reserve_pub;
+ bool tips;
+
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (hc->infix,
+ strlen (hc->infix),
+ &reserve_pub,
+ sizeof (reserve_pub)))
{
- tqc = GNUNET_new (struct TipQueryContext);
- tqc->hc.cc = &cleanup_tqc;
- tqc->ctr.connection = connection;
- *connection_cls = tqc;
- }
- else
- {
- tqc = *connection_cls;
- }
-
- if (0 != tqc->ctr.response_code)
- {
- MHD_RESULT res;
-
- /* We are *done* processing the request, just queue the response (!) */
- if (UINT_MAX == tqc->ctr.response_code)
- {
- GNUNET_break (0);
- return MHD_NO; /* hard error */
- }
- res = MHD_queue_response (connection,
- tqc->ctr.response_code,
- tqc->ctr.response);
- MHD_destroy_response (tqc->ctr.response);
- tqc->ctr.response = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Queueing response (%u) for /tip-query (%s).\n",
- (unsigned int) tqc->ctr.response_code,
- res ? "OK" : "FAILED");
- return res;
- }
-
- if (GNUNET_YES == tqc->processed)
- {
- /* We've been here before, so TMH_check_tip_reserve() must have
- finished and left the result for us. Finish processing. */
- return generate_final_response (tqc);
+ /* tip_id has wrong encoding */
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_PARAMETER_MALFORMED,
+ "reserve_pub malformed");
}
-
- if (NULL == mi->tip_exchange)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Instance `%s' not configured for tipping\n",
- mi->id);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_PRECONDITION_FAILED,
- TALER_EC_TIP_QUERY_INSTANCE_DOES_NOT_TIP,
- "exchange for tipping not configured for the instance");
+ const char *tstr;
+
+ tstr = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "tips");
+ tips = (NULL != tstr)
+ ? 0 == strcasecmp (tstr, "yes")
+ : false;
}
- tqc->ctr.reserve_priv = mi->tip_reserve;
-
{
+ struct GetReserveContext ctx = {
+ .connection = connection,
+ .tips = tips
+ };
enum GNUNET_DB_QueryStatus qs;
- for (unsigned int i = 0; i<MAX_RETRIES; i++)
+ TMH_db->preflight (TMH_db->cls);
+ qs = TMH_db->lookup_reserve (TMH_db->cls,
+ hc->instance->settings.id,
+ &reserve_pub,
+ tips,
+ &handle_reserve_details,
+ &ctx);
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
{
- db->preflight (db->cls);
- qs = db->get_authorized_tip_amount (db->cls,
- &tqc->ctr.reserve_priv,
- &tqc->ctr.amount_authorized);
- if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
+ unsigned int response_code;
+ enum TALER_ErrorCode ec;
+
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ ec = TALER_EC_TIP_PICKUP_TIP_ID_UNKNOWN;
+ response_code = MHD_HTTP_NOT_FOUND;
break;
- }
- if (0 > qs)
- {
- GNUNET_break (0);
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ ec = TALER_EC_TIP_PICKUP_DB_ERROR_SOFT;
+ response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ break;
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ ec = TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
+ response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ break;
+ default:
+ GNUNET_break (0);
+ ec = TALER_EC_INTERNAL_LOGIC_ERROR;
+ response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ break;
+ }
return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_TIP_QUERY_DB_ERROR,
- "Merchant database error");
- }
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- {
- /* we'll set amount_authorized to zero later once
- we know the currency */
- tqc->ctr.none_authorized = GNUNET_YES;
+ response_code,
+ ec,
+ "Could not determine exchange URL for the given tip id");
}
+ return ctx.res;
}
-
- tqc->processed = GNUNET_YES;
- TMH_check_tip_reserve (&tqc->ctr,
- mi->tip_exchange);
- return MHD_YES;
}
-/* end of taler-merchant-httpd_tip-query.c */
+/* end of taler-merchant-httpd_private-get-reserves-ID.c */