/* This file is part of TALER (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 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 backend/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 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, 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, "{s:o, s:o, s:o, s:o, s:o, s:o, s:o?, s:b}", "creation_time", GNUNET_JSON_from_time_abs (creation_time_round), "expiration_time", GNUNET_JSON_from_time_abs (expiration_time_round), "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, "active", active); } /** * 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_PARAMETER_MALFORMED, "reserve_pub malformed"); } { 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_TIP_PICKUP_TIP_ID_UNKNOWN; response_code = MHD_HTTP_NOT_FOUND; break; 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, response_code, ec, "Could not determine exchange URL for the given tip id"); } return ctx.res; } } /* end of taler-merchant-httpd_private-get-reserves-ID.c */