merchant

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

commit 9af93eeae2a1fcd9eddf22e9ebeb7ad0aeb34505
parent 601abc17e4d63fed52de91402c15bb4d9ba3e014
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue, 19 May 2020 22:34:18 +0200

expanding DB API

Diffstat:
Msrc/backend/Makefile.am | 2++
Msrc/backend/taler-merchant-httpd.c | 7+++++++
Msrc/backenddb/plugin_merchantdb_postgres.c | 395++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/include/taler_merchantdb_plugin.h | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 550 insertions(+), 2 deletions(-)

diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am @@ -41,6 +41,8 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-get-products-ID.h \ taler-merchant-httpd_private-get-orders.c \ taler-merchant-httpd_private-get-orders.h \ + taler-merchant-httpd_private-get-reserves.c \ + taler-merchant-httpd_private-get-reserves.h \ taler-merchant-httpd_private-get-transfers.c \ taler-merchant-httpd_private-get-transfers.h \ taler-merchant-httpd_private-patch-instances-ID.c \ diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c @@ -38,6 +38,7 @@ #include "taler-merchant-httpd_private-get-products-ID.h" #include "taler-merchant-httpd_private-get-orders.h" // #include "taler-merchant-httpd_private-get-orders-ID.h" +#include "taler-merchant-httpd_private-get-reserves.h" #include "taler-merchant-httpd_private-get-transfers.h" #include "taler-merchant-httpd_private-patch-instances-ID.h" #include "taler-merchant-httpd_private-patch-products-ID.h" @@ -840,6 +841,12 @@ url_handler (void *cls, .method = MHD_HTTP_METHOD_POST, .handler = &TMH_private_post_reserves }, + /* GET /reserves: */ + { + .url_prefix = "/reserves", + .method = MHD_HTTP_METHOD_GET, + .handler = &TMH_private_get_reserves + }, /* POST /transfers: */ { .url_prefix = "/transfers", diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c @@ -3813,6 +3813,391 @@ RETRY: } +/** + * Closure for #lookup_accounts_cb. + */ +struct LookupReservesContext +{ + /** + * Postgres context. + */ + struct PostgresClosure *pg; + + /** + * Function to call with the results + */ + TALER_MERCHANTDB_ReservesCallback cb; + + /** + * Closure for @e cb + */ + void *cb_cls; + + /** + * + */ + enum TALER_MERCHANTDB_YesNoAll active; + + /** + * + */ + enum TALER_MERCHANTDB_YesNoAll failures; + + /** + * Set in case of errors. + */ + enum GNUNET_DB_QueryStatus qs; + +}; + + +/** + * 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 LookupReservesContext *` + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lookup_reserves_cb (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupReservesContext *lrc = cls; + struct PostgresClosure *pg = lrc->pg; + + for (unsigned int i = 0; i < num_results; i++) + { + struct TALER_ReservePublicKeyP reserve_pub; + struct GNUNET_TIME_Absolute creation_time; + struct GNUNET_TIME_Absolute expiration_time; + struct TALER_Amount merchant_initial_amount; + struct TALER_Amount exchange_initial_amount; + struct TALER_Amount pickup_amount; + struct TALER_Amount committed_amount; + uint8_t active; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", + &reserve_pub), + GNUNET_PQ_result_spec_absolute_time ("creation_time", + &creation_time), + GNUNET_PQ_result_spec_absolute_time ("expiration_time", + &expiration_time), + TALER_PQ_RESULT_SPEC_AMOUNT ("merchant_initial_amount", + &merchant_initial_amount), + TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_initial_amount", + &exchange_initial_amount), + TALER_PQ_RESULT_SPEC_AMOUNT ("pickup_amount", + &pickup_amount), + TALER_PQ_RESULT_SPEC_AMOUNT ("committed_amount", + &committed_amount), + GNUNET_PQ_result_spec_auto_from_type ("active", + &active), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + lrc->qs = GNUNET_DB_STATUS_HARD_ERROR; + return; + } + lrc->cb (lrc->cb_cls, + &reserve_pub, + creation_time, + expiration_time, + &merchant_initial_amount, + &exchange_initial_amount, + &pickup_amount, + &committed_amount, + (0 != active)); + } +} + + +/** + * Lookup reserves. + * + * @param cls closure + * @param instance_id instance to lookup payments for + * @param created_after filter by reserves created after this date + * @param active filter by active reserves + * @param failures filter by reserves with a disagreement on the initial balance + * @param cb function to call with reserve summary data + * @param cb_cls closure for @a cb + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +postgres_lookup_reserves (void *cls, + const char *instance_id, + struct GNUNET_TIME_Absolute created_after, + enum TALER_MERCHANTDB_YesNoAll active, + enum TALER_MERCHANTDB_YesNoAll failures, + TALER_MERCHANTDB_ReservesCallback cb, + void *cb_cls) +{ + struct PostgresClosure *pg = cls; + struct LookupReservesContext lrc = { + .pg = pg, + .active = active, + .failures = failures, + .cb = cb, + .cb_cls = cb_cls + }; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_absolute_time (&created_after), + GNUNET_PQ_query_param_end + }; + enum GNUNET_DB_QueryStatus qs; + + check_connection (pg); + qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, + "lookup_reserves", + params, + &lookup_reserves_cb, + &lrc); + if (lrc.qs < 0) + return lrc.qs; + return qs; +} + + +/** + * Closure for #lookup_reserve_tips_cb(). + */ +struct LookupTipsContext +{ + /** + * Postgres context. + */ + struct PostgresClosure *pg; + + /** + * Array with information about tips generated from this reserve. + */ + struct TALER_MERCHANTDB_TipDetails *tips; + + /** + * Length of the @e tips array. + */ + unsigned int tips_length; + + /** + * Set in case of errors. + */ + enum GNUNET_DB_QueryStatus qs; +}; + + +/** + * 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 result the postgres result + * @param num_result the number of results in @a result + */ +static void +lookup_reserve_tips_cb (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupTipsContext *ltc = cls; + struct PostgresClosure *pg = ltc->pg; + + GNUNET_array_grow (ltc->tips, + ltc->tips_length, + num_results); + for (unsigned int i = 0; i < num_results; i++) + { + struct TALER_MERCHANTDB_TipDetails *td = &ltc->tips[i]; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_string ("reason", + &td->reason), + GNUNET_PQ_result_spec_auto_from_type ("tip_id", + &td->tip_id), + TALER_PQ_RESULT_SPEC_AMOUNT ("total_amount", + &td->total_amount), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ltc->qs = GNUNET_DB_STATUS_HARD_ERROR; + return; + } + } +} + + +/** + * Lookup reserve details. + * + * @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 cb function to call with reserve summary data + * @param cb_cls closure for @a cb + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +postgres_lookup_reserve (void *cls, + const char *instance_id, + const struct TALER_ReservePublicKeyP *reserve_pub, + bool fetch_tips, + TALER_MERCHANTDB_ReserveDetailsCallback cb, + void *cb_cls) +{ + struct PostgresClosure *pg = cls; + struct LookupTipsContext ltc = { + .pg = pg + }; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + GNUNET_PQ_query_param_end + }; + struct GNUNET_TIME_Absolute creation_time; + struct GNUNET_TIME_Absolute expiration_time; + struct TALER_Amount merchant_initial_amount; + struct TALER_Amount exchange_initial_amount; + struct TALER_Amount pickup_amount; + struct TALER_Amount committed_amount; + uint8_t active; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_absolute_time ("creation_time", + &creation_time), + GNUNET_PQ_result_spec_absolute_time ("expiration_time", + &expiration_time), + TALER_PQ_RESULT_SPEC_AMOUNT ("merchant_initial_amount", + &merchant_initial_amount), + TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_initial_amount", + &exchange_initial_amount), + TALER_PQ_RESULT_SPEC_AMOUNT ("pickup_amount", + &pickup_amount), + TALER_PQ_RESULT_SPEC_AMOUNT ("committed_amount", + &committed_amount), + GNUNET_PQ_result_spec_auto_from_type ("active", + &active), + GNUNET_PQ_result_spec_end + }; + enum GNUNET_DB_QueryStatus qs; + + check_connection (pg); + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "lookup_reserve", + params, + rs); + if (qs < 0) + return qs; + if (! fetch_tips) + { + cb (cb_cls, + creation_time, + expiration_time, + &merchant_initial_amount, + &exchange_initial_amount, + &pickup_amount, + &committed_amount, + 0, + NULL); + return qs; + } + + qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, + "lookup_reserve_tips", + params, + &lookup_reserve_tips_cb, + &ltc); + if (qs < 0) + return qs; + if (ltc.qs >= 0) + { + cb (cb_cls, + creation_time, + expiration_time, + &merchant_initial_amount, + &exchange_initial_amount, + &pickup_amount, + &committed_amount, + ltc.tips_length, + ltc.tips); + } + for (unsigned int i = 0; i<ltc.tips_length; i++) + GNUNET_free_non_null (ltc.tips[i].reason); + GNUNET_array_grow (ltc.tips, + ltc.tips_length, + 0); + return ltc.qs; +} + + +/** + * Delete a reserve's private key. + * + * @param cls closure, typically a connection to the db + * @param instance_id which instance is the reserve tied to + * @param reserve_pub which reserve is to be deleted + * @return transaction status, usually + * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success + */ +static enum GNUNET_DB_QueryStatus +postgres_delete_reserve (void *cls, + const char *instance_id, + const struct TALER_ReservePublicKeyP *reserve_pub) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + GNUNET_PQ_query_param_end + }; + + check_connection (pg); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "delete_reserve", + params); +} + + +/** + * Purge all of the information about a reserve, including tips. + * + * @param cls closure, typically a connection to the db + * @param instance_id which instance is the reserve tied to + * @param reserve_pub which reserve is to be purged + * @return transaction status, usually + * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success + */ +static enum GNUNET_DB_QueryStatus +postgres_purge_reserve (void *cls, + const char *instance_id, + const struct TALER_ReservePublicKeyP *reserve_pub) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + GNUNET_PQ_query_param_end + }; + + check_connection (pg); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "purge_reserve", + params); +} + + /* ********************* OLD API ************************** */ /** @@ -6442,7 +6827,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " WHERE merchant_id=$1)", 4), /* OLD API: */ - + // DO: lookup_reserves + // DO: lookup_reserve + // DO: lookup_reserve_tips + // DO: delete_reserve / purge_reserve #if 0 GNUNET_PQ_make_prepare ("insert_contract_terms", "INSERT INTO merchant_contract_terms" @@ -6755,7 +7143,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) plugin->lookup_transfer_details = &postgres_lookup_transfer_details; plugin->lookup_transfers = &postgres_lookup_transfers; plugin->insert_reserve = &postgres_insert_reserve; - + plugin->lookup_reserves = &postgres_lookup_reserves; + plugin->lookup_reserve = &postgres_lookup_reserve; + plugin->delete_reserve = &postgres_delete_reserve; + plugin->purge_reserve = &postgres_purge_reserve; /* OLD API: */ plugin->store_coin_to_transfer = &postgres_store_coin_to_transfer; plugin->store_transfer_to_proof = &postgres_store_transfer_to_proof; diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h @@ -454,6 +454,84 @@ typedef void bool confirmed); +/** + * Callback with reserve details. + * + * @param cls closure + * @param reserve_pub public key of the reserve + * @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 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 + * picked up yet + * @param active true if the reserve is still active (we have the private key) + */ +typedef void +(*TALER_MERCHANTDB_ReservesCallback)( + void *cls, + const struct TALER_ReservePublicKeyP *reserve_pub, + 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 *pickup_amount, + const struct TALER_Amount *committed_amount, + bool active); + + +/** + * Details about a tip. + */ +struct TALER_MERCHANTDB_TipDetails +{ + /** + * ID of the tip. + */ + struct GNUNET_HashCode tip_id; + + /** + * Total amount of the tip. + */ + struct TALER_Amount total_amount; + + /** + * Reason given for granting the tip. + */ + char *reason; +}; + + +/** + * Callback with reserve details. + * + * @param cls closure + * @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 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 + * picked up yet + * @param tips_length length of the @a tips array + * @param tips information about the tips created by this reserve + */ +typedef void +(*TALER_MERCHANTDB_ReserveDetailsCallback)( + 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 *pickup_amount, + const struct TALER_Amount *committed_amount, + unsigned int tips_length, + const struct TALER_MERCHANTDB_TipDetails *tips); + + /* **************** OLD: ******************** */ /** @@ -1482,6 +1560,76 @@ struct TALER_MERCHANTDB_Plugin const struct TALER_Amount *initial_balance, struct GNUNET_TIME_Absolute expiration); + + /** + * Lookup reserves. + * + * @param cls closure + * @param instance_id instance to lookup payments for + * @param created_after filter by reserves created after this date + * @param active filter by active reserves + * @param failures filter by reserves with a disagreement on the initial balance + * @param cb function to call with reserve summary data + * @param cb_cls closure for @a cb + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*lookup_reserves)(void *cls, + const char *instance_id, + struct GNUNET_TIME_Absolute created_after, + enum TALER_MERCHANTDB_YesNoAll active, + enum TALER_MERCHANTDB_YesNoAll failures, + TALER_MERCHANTDB_ReservesCallback cb, + void *cb_cls); + + + /** + * Lookup reserve details. + * + * @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 cb function to call with reserve summary data + * @param cb_cls closure for @a cb + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*lookup_reserve)(void *cls, + const char *instance_id, + const struct TALER_ReservePublicKeyP *reserve_pub, + bool fetch_tips, + TALER_MERCHANTDB_ReserveDetailsCallback cb, + void *cb_cls); + + + /** + * Delete private key of a reserve. + * + * @param cls closure + * @param instance_id instance to lookup payments for + * @param reserve_pub public key of the reserve to delete + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*delete_reserve)(void *cls, + const char *instance_id, + const struct TALER_ReservePublicKeyP *reserve_pub); + + /** + * Purge all information about a reserve (including tips from it). + * + * @param cls closure + * @param instance_id instance to lookup payments for + * @param reserve_pub public key of the reserve to purge + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*purge_reserve)(void *cls, + const char *instance_id, + const struct TALER_ReservePublicKeyP *reserve_pub); + + /* ****************** OLD API ******************** */