/*
This file is part of TALER
(C) 2018, 2020, 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
*/
/**
* @file taler-merchant-httpd_private-get-reserves-ID.c
* @brief implement GET /reserves/$RESERVE_PUB endpoint
* @author Christian Grothoff
*/
#include "platform.h"
#include
#include
#include
#include "taler-merchant-httpd.h"
#include "taler-merchant-httpd_mhd.h"
#include "taler-merchant-httpd_exchanges.h"
#include "taler-merchant-httpd_private-get-reserves-ID.h"
/**
* Closure for handle_reserve_details().
*/
struct GetReserveContext
{
/**
* Connection we are handling.
*/
struct MHD_Connection *connection;
/**
* Value to return from the callback.
*/
MHD_RESULT res;
/**
* Should we return details about tips?
*/
bool tips;
};
/**
* Callback with reserve details.
*
* @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 active true if the reserve is still active (we have the private key)
* @param exchange_url URL of the exchange, NULL if not active
* @param payto_uri payto:// URI to fill the reserve, NULL if not active or already paid
* @param tips_length length of the @a tips array
* @param tips information about the tips created by this reserve
*/
static void
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,
bool active,
const char *exchange_url,
const char *payto_uri,
unsigned int tips_length,
const struct TALER_MERCHANTDB_TipDetails *tips)
{
struct GetReserveContext *ctx = cls;
json_t *tips_json;
struct GNUNET_TIME_Absolute creation_time_round = creation_time;
struct GNUNET_TIME_Absolute expiration_time_round = expiration_time;
GNUNET_TIME_round_abs (&creation_time_round);
GNUNET_TIME_round_abs (&expiration_time_round);
if (NULL != tips)
{
tips_json = json_array ();
GNUNET_assert (NULL != tips_json);
for (unsigned int i = 0; ires = TALER_MHD_REPLY_JSON_PACK (
ctx->connection,
MHD_HTTP_OK,
GNUNET_JSON_pack_time_abs ("creation_time",
creation_time_round),
GNUNET_JSON_pack_time_abs ("expiration_time",
expiration_time_round),
TALER_JSON_pack_amount ("merchant_initial_amount",
merchant_initial_amount),
TALER_JSON_pack_amount ("exchange_initial_amount",
exchange_initial_amount),
TALER_JSON_pack_amount ("pickup_amount",
picked_up_amount),
TALER_JSON_pack_amount ("committed_amount",
committed_amount),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_array_steal ("tips",
tips_json)),
GNUNET_JSON_pack_bool ("active",
active),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("exchange_url",
exchange_url)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("payto_uri",
payto_uri)));
}
/**
* Manages a GET /reserves/$RESERVE_PUB 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_reserves_ID (const struct TMH_RequestHandler *rh,
struct MHD_Connection *connection,
struct TMH_HandlerContext *hc)
{
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)))
{
/* 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 *tstr;
tstr = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"tips");
tips = (NULL != tstr)
? 0 == strcasecmp (tstr, "yes")
: false;
}
{
struct GetReserveContext ctx = {
.connection = connection,
.tips = tips
};
enum GNUNET_DB_QueryStatus qs;
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)
{
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_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,
hc->infix);
}
return ctx.res;
}
}
/* end of taler-merchant-httpd_private-get-reserves-ID.c */