summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-10-22 19:07:20 +0200
committerChristian Grothoff <christian@grothoff.org>2017-10-22 19:07:20 +0200
commit431db2d2beecf0487ace376cba9d5f0bbf18bb08 (patch)
tree6ef942bb10a324b824a80b86fd619c624833e586
parent019f6fd33e3c538881841dc6939b105e4601d038 (diff)
downloadmerchant-431db2d2beecf0487ace376cba9d5f0bbf18bb08.tar.gz
merchant-431db2d2beecf0487ace376cba9d5f0bbf18bb08.tar.bz2
merchant-431db2d2beecf0487ace376cba9d5f0bbf18bb08.zip
first (incomplete) skeleton for tipping API
-rw-r--r--src/backend/Makefile.am3
-rw-r--r--src/backend/taler-merchant-httpd.c21
-rw-r--r--src/backend/taler-merchant-httpd.h12
-rw-r--r--src/backend/taler-merchant-httpd_pay.c2
-rw-r--r--src/backend/taler-merchant-httpd_responses.c24
-rw-r--r--src/backend/taler-merchant-httpd_responses.h19
-rw-r--r--src/backend/taler-merchant-httpd_tip-authorize.c180
-rw-r--r--src/backend/taler-merchant-httpd_tip-authorize.h44
-rw-r--r--src/backend/taler-merchant-httpd_tip-enable.c157
-rw-r--r--src/backend/taler-merchant-httpd_tip-enable.h44
-rw-r--r--src/backend/taler-merchant-httpd_tip-pickup.c44
-rw-r--r--src/backend/taler-merchant-httpd_tip-pickup.h44
-rw-r--r--src/include/taler_merchantdb_plugin.h81
13 files changed, 668 insertions, 7 deletions
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index 63add5ac..28212db4 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -22,6 +22,9 @@ taler_merchant_httpd_SOURCES = \
taler-merchant-httpd_proposal.c taler-merchant-httpd_proposal.h \
taler-merchant-httpd_pay.c taler-merchant-httpd_pay.h \
taler-merchant-httpd_history.c taler-merchant-httpd_history.h \
+ taler-merchant-httpd_tip-authorize.c taler-merchant-httpd_tip-authorize.h \
+ taler-merchant-httpd_tip-enable.c taler-merchant-httpd_tip-enable.h \
+ taler-merchant-httpd_tip-pickup.c taler-merchant-httpd_tip-pickup.h \
taler-merchant-httpd_track-transaction.c taler-merchant-httpd_track-transaction.h \
taler-merchant-httpd_track-transfer.c taler-merchant-httpd_track-transfer.h \
taler-merchant-httpd_refund.c taler-merchant-httpd_refund.h
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index 15086cc2..9c95b8b9 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -39,6 +39,9 @@
#include "taler-merchant-httpd_pay.h"
#include "taler-merchant-httpd_track-transaction.h"
#include "taler-merchant-httpd_track-transfer.h"
+#include "taler-merchant-httpd_tip-authorize.h"
+#include "taler-merchant-httpd_tip-enable.h"
+#include "taler-merchant-httpd_tip-pickup.h"
#include "taler-merchant-httpd_history.h"
#include "taler-merchant-httpd_refund.h"
@@ -220,6 +223,24 @@ url_handler (void *cls,
{ "/refund", NULL, "application/json",
"Only POST/GET are allowed", 0,
&TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED},
+ { "/tip-authorize", MHD_HTTP_METHOD_POST, "text/plain",
+ NULL, 0,
+ &MH_handler_tip_authorize, MHD_HTTP_OK},
+ { "/tip-authorize", NULL, "application/json",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED},
+ { "/tip-pickup", MHD_HTTP_METHOD_POST, "text/plain",
+ NULL, 0,
+ &MH_handler_tip_pickup, MHD_HTTP_OK},
+ { "/tip-pickup", NULL, "application/json",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED},
+ { "/tip-enable", MHD_HTTP_METHOD_POST, "text/plain",
+ NULL, 0,
+ &MH_handler_tip_enable, MHD_HTTP_OK},
+ { "/tip-enable", NULL, "application/json",
+ "Only POST is allowed", 0,
+ &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED},
{NULL, NULL, NULL, NULL, 0, 0 }
};
static struct TMH_RequestHandler h404 =
diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h
index c67a9713..83e9c07f 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -119,6 +119,18 @@ struct MerchantInstance
*/
struct TALER_MerchantPublicKeyP pubkey;
+ /**
+ * Exchange this instance uses for tipping, NULL if tipping
+ * is not supported.
+ */
+ const char *tip_exchange;
+
+ /**
+ * What is the private key of the reserve used for signing tips by this exchange?
+ * Only valid if @e tip_exchange is non-null.
+ */
+ struct TALER_ReservePrivateKeyP tip_reserve;
+
};
diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c
index 7769ef2f..34d676ac 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -1452,7 +1452,7 @@ parse_pay (struct MHD_Connection *connection,
if (GNUNET_YES != res)
{
GNUNET_JSON_parse_free (spec);
- GNUNET_break (0);
+ GNUNET_break_op (0);
return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
}
diff --git a/src/backend/taler-merchant-httpd_responses.c b/src/backend/taler-merchant-httpd_responses.c
index f5f994e8..1417fa24 100644
--- a/src/backend/taler-merchant-httpd_responses.c
+++ b/src/backend/taler-merchant-httpd_responses.c
@@ -239,6 +239,30 @@ TMH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection)
/**
+ * Send a response indicating that we did not find the @a object
+ * needed for the reply.
+ *
+ * @param connection the MHD connection to use
+ * @param response_code response code to use
+ * @param ec error code to return
+ * @param msg human-readable diagnostic
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_rc (struct MHD_Connection *connection,
+ unsigned int response_code,
+ enum TALER_ErrorCode ec,
+ const char *msg)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ response_code,
+ "{s:I, s:s}",
+ "code", (json_int_t) ec,
+ "error", msg);
+}
+
+
+/**
* Send a response indicating that the JSON was malformed.
*
* @param connection the MHD connection to use
diff --git a/src/backend/taler-merchant-httpd_responses.h b/src/backend/taler-merchant-httpd_responses.h
index ea290c5f..a96b696d 100644
--- a/src/backend/taler-merchant-httpd_responses.h
+++ b/src/backend/taler-merchant-httpd_responses.h
@@ -101,6 +101,23 @@ TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection);
* needed for the reply.
*
* @param connection the MHD connection to use
+ * @param response_code response code to use
+ * @param ec error code to return
+ * @param msg human-readable diagnostic
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_rc (struct MHD_Connection *connection,
+ unsigned int response_code,
+ enum TALER_ErrorCode ec,
+ const char *msg);
+
+
+/**
+ * Send a response indicating that we did not find the @a object
+ * needed for the reply.
+ *
+ * @param connection the MHD connection to use
* @param ec error code to return
* @param object name of the object we did not find
* @return a MHD result code
@@ -149,7 +166,7 @@ TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
struct MHD_Response *
TMH_RESPONSE_make_internal_error (enum TALER_ErrorCode ec,
const char *hint);
-
+
/**
* Send a response indicating an external error.
diff --git a/src/backend/taler-merchant-httpd_tip-authorize.c b/src/backend/taler-merchant-httpd_tip-authorize.c
new file mode 100644
index 00000000..415352a0
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_tip-authorize.c
@@ -0,0 +1,180 @@
+/*
+ This file is part of TALER
+ (C) 2014-2017 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 backend/taler-merchant-httpd_tip-authorize.c
+ * @brief implement API for authorizing tips to be paid to visitors
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <jansson.h>
+#include <taler/taler_json_lib.h>
+#include "taler-merchant-httpd.h"
+#include "taler-merchant-httpd_mhd.h"
+#include "taler-merchant-httpd_parsing.h"
+#include "taler-merchant-httpd_exchanges.h"
+#include "taler-merchant-httpd_responses.h"
+#include "taler-merchant-httpd_tip-authorize.h"
+
+
+/**
+ * Information we keep for individual calls
+ * to requests that parse JSON, but keep no other state.
+ */
+struct TMH_JsonParseContext
+{
+
+ /**
+ * This field MUST be first.
+ * FIXME: Explain why!
+ */
+ struct TM_HandlerContext hc;
+
+ /**
+ * Placeholder for #TMH_PARSE_post_json() to keep its internal state.
+ */
+ void *json_parse_context;
+};
+
+
+/**
+ * Custom cleanup routine for a `struct TMH_JsonParseContext`.
+ *
+ * @param hc the `struct TMH_JsonParseContext` to clean up.
+ */
+static void
+json_parse_cleanup (struct TM_HandlerContext *hc)
+{
+ struct TMH_JsonParseContext *jpc = (struct TMH_JsonParseContext *) hc;
+
+ TMH_PARSE_post_cleanup_callback (jpc->json_parse_context);
+ GNUNET_free (jpc);
+}
+
+
+/**
+ * Handle a "/tip-authorize" request.
+ *
+ * @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
+ * @return MHD result code
+ */
+int
+MH_handler_tip_authorize (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ enum GNUNET_DB_QueryStatus qs;
+ struct MerchantInstance *mi;
+ int res;
+ struct TALER_Amount amount;
+ const char *instance;
+ const char *justification;
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount ("amount", &amount),
+ GNUNET_JSON_spec_string ("instance", &instance),
+ GNUNET_JSON_spec_string ("justification", &justification),
+ GNUNET_JSON_spec_end()
+ };
+ json_t *root;
+ struct GNUNET_TIME_Absolute expiration;
+ struct GNUNET_HashCode tip_id;
+ struct TMH_JsonParseContext *ctx;
+
+ if (NULL == *connection_cls)
+ {
+ ctx = GNUNET_new (struct TMH_JsonParseContext);
+ ctx->hc.cc = &json_parse_cleanup;
+ *connection_cls = ctx;
+ }
+ else
+ {
+ ctx = *connection_cls;
+ }
+ res = TMH_PARSE_post_json (connection,
+ &ctx->json_parse_context,
+ upload_data,
+ upload_data_size,
+ &root);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ /* the POST's body has to be further fetched */
+ if ( (GNUNET_NO == res) ||
+ (NULL == root) )
+ return MHD_YES;
+
+ res = TMH_PARSE_json_data (connection,
+ root,
+ spec);
+ json_decref (root);
+ if (GNUNET_YES != res)
+ {
+ GNUNET_break_op (0);
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ }
+
+ mi = TMH_lookup_instance (instance);
+ if (NULL == mi)
+ return TMH_RESPONSE_reply_not_found (connection,
+ TALER_EC_TIP_AUTHORIZE_INSTANCE_UNKNOWN,
+ "unknown instance");
+ if (NULL == mi->tip_exchange)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Instance `%s' not configured for tipping\n",
+ instance);
+ return TMH_RESPONSE_reply_not_found (connection,
+ TALER_EC_TIP_AUTHORIZE_INSTANCE_DOES_NOT_TIP,
+ "exchange for tipping not configured for the instance");
+ }
+ qs = db->authorize_tip (db->cls,
+ justification,
+ &amount,
+ &mi->tip_reserve,
+ &expiration,
+ &tip_id);
+ if (0 > qs)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_TIP_AUTHORIZE_DB_TRANSACTION_ERROR,
+ "Database error approving tip");
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Insufficient funds to authorize tip over `%s' at instance `%s'\n",
+ TALER_amount2s (&amount),
+ instance);
+ return TMH_RESPONSE_reply_rc (connection,
+ MHD_HTTP_PRECONDITION_FAILED,
+ TALER_EC_TIP_AUTHORIZE_INSUFFICIENT_FUNDS,
+ "Insufficient funds for tip");
+ }
+
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o, s:o, s:s}",
+ "tip_id", GNUNET_JSON_from_data_auto (&tip_id),
+ "tip_expiration", GNUNET_JSON_from_time_abs (expiration),
+ "exchange_uri", mi->tip_exchange);
+}
+
+/* end of taler-merchant-httpd_tip-authorize.c */
diff --git a/src/backend/taler-merchant-httpd_tip-authorize.h b/src/backend/taler-merchant-httpd_tip-authorize.h
new file mode 100644
index 00000000..b7c3b9a1
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_tip-authorize.h
@@ -0,0 +1,44 @@
+/*
+ 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 backend/taler-merchant-httpd_tip-authorize.h
+ * @brief headers for /tip-authorize handler
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_TIP_AUTHORIZE_H
+#define TALER_MERCHANT_HTTPD_TIP_AUTHORIZE_H
+#include <microhttpd.h>
+#include "taler-merchant-httpd.h"
+
+/**
+ * Manages a /tip-authorize call, creating a TIP ID and storing the
+ * authorization in our DB.
+ *
+ * @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
+ * @return MHD result code
+ */
+int
+MH_handler_tip_authorize (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+#endif
diff --git a/src/backend/taler-merchant-httpd_tip-enable.c b/src/backend/taler-merchant-httpd_tip-enable.c
new file mode 100644
index 00000000..a96613e0
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_tip-enable.c
@@ -0,0 +1,157 @@
+/*
+ This file is part of TALER
+ (C) 2014-2017 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 backend/taler-merchant-httpd_tip-enable.c
+ * @brief implement API for authorizing tips to be paid to visitors
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <jansson.h>
+#include <taler/taler_json_lib.h>
+#include "taler-merchant-httpd.h"
+#include "taler-merchant-httpd_mhd.h"
+#include "taler-merchant-httpd_parsing.h"
+#include "taler-merchant-httpd_exchanges.h"
+#include "taler-merchant-httpd_responses.h"
+#include "taler-merchant-httpd_tip-enable.h"
+
+
+/**
+ * Information we keep for individual calls
+ * to requests that parse JSON, but keep no other state.
+ */
+struct TMH_JsonParseContext
+{
+
+ /**
+ * This field MUST be first.
+ * FIXME: Explain why!
+ */
+ struct TM_HandlerContext hc;
+
+ /**
+ * Placeholder for #TMH_PARSE_post_json() to keep its internal state.
+ */
+ void *json_parse_context;
+};
+
+
+/**
+ * Custom cleanup routine for a `struct TMH_JsonParseContext`.
+ *
+ * @param hc the `struct TMH_JsonParseContext` to clean up.
+ */
+static void
+json_parse_cleanup (struct TM_HandlerContext *hc)
+{
+ struct TMH_JsonParseContext *jpc = (struct TMH_JsonParseContext *) hc;
+
+ TMH_PARSE_post_cleanup_callback (jpc->json_parse_context);
+ GNUNET_free (jpc);
+}
+
+
+/**
+ * Handle a "/tip-enable" request.
+ *
+ * @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
+ * @return MHD result code
+ */
+int
+MH_handler_tip_enable (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ enum GNUNET_DB_QueryStatus qs;
+ int res;
+ struct TALER_Amount credit;
+ struct GNUNET_TIME_Absolute expiration;
+ struct TALER_ReservePrivateKeyP reserve_priv;
+ struct GNUNET_HashCode credit_uuid;
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount ("credit", &credit),
+ GNUNET_JSON_spec_absolute_time ("expiration", &expiration),
+ GNUNET_JSON_spec_fixed_auto ("reserve_priv", &reserve_priv),
+ GNUNET_JSON_spec_fixed_auto ("credit_uuid", &credit_uuid),
+ GNUNET_JSON_spec_end()
+ };
+ struct TMH_JsonParseContext *ctx;
+ json_t *root;
+
+ if (NULL == *connection_cls)
+ {
+ ctx = GNUNET_new (struct TMH_JsonParseContext);
+ ctx->hc.cc = &json_parse_cleanup;
+ *connection_cls = ctx;
+ }
+ else
+ {
+ ctx = *connection_cls;
+ }
+ res = TMH_PARSE_post_json (connection,
+ &ctx->json_parse_context,
+ upload_data,
+ upload_data_size,
+ &root);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ /* the POST's body has to be further fetched */
+ if ( (GNUNET_NO == res) ||
+ (NULL == root) )
+ return MHD_YES;
+
+ res = TMH_PARSE_json_data (connection,
+ root,
+ spec);
+ json_decref (root);
+ if (GNUNET_YES != res)
+ {
+ GNUNET_break_op (0);
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ }
+
+ qs = db->enable_tip_reserve (db->cls,
+ &reserve_priv,
+ &credit_uuid,
+ &credit,
+ expiration);
+ if (0 > qs)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_TIP_ENABLE_DB_TRANSACTION_ERROR,
+ "Database error approving tip");
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:s}",
+ "status", "duplicate submission");
+ }
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:s}",
+ "status", "ok");
+}
+
+/* end of taler-merchant-httpd_tip-enable.c */
diff --git a/src/backend/taler-merchant-httpd_tip-enable.h b/src/backend/taler-merchant-httpd_tip-enable.h
new file mode 100644
index 00000000..2981ef4f
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_tip-enable.h
@@ -0,0 +1,44 @@
+/*
+ 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 backend/taler-merchant-httpd_tip-enable.h
+ * @brief headers for /tip-enable handler
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_TIP_ENABLE_H
+#define TALER_MERCHANT_HTTPD_TIP_ENABLE_H
+#include <microhttpd.h>
+#include "taler-merchant-httpd.h"
+
+/**
+ * Manages a /tip-enable call, storing information about the
+ * reserve.
+ *
+ * @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
+ * @return MHD result code
+ */
+int
+MH_handler_tip_enable (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+#endif
diff --git a/src/backend/taler-merchant-httpd_tip-pickup.c b/src/backend/taler-merchant-httpd_tip-pickup.c
new file mode 100644
index 00000000..982ec1f0
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_tip-pickup.c
@@ -0,0 +1,44 @@
+/*
+ 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 backend/taler-merchant-httpd_tip-pickup.c
+ * @brief implementation of /tip-pickup handler
+ * @author Christian Grothoff
+ */
+#include <microhttpd.h>
+#include "taler-merchant-httpd.h"
+
+/**
+ * Manages a /tip-pickup call, checking that the tip is authorized,
+ * and if so, returning the withdrawal permissions.
+ *
+ * @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
+ * @return MHD result code
+ */
+int
+MH_handler_tip_pickup (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ GNUNET_break (0); /* #5099: not implemented */
+ return MHD_NO;
+}
diff --git a/src/backend/taler-merchant-httpd_tip-pickup.h b/src/backend/taler-merchant-httpd_tip-pickup.h
new file mode 100644
index 00000000..da42eaa6
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_tip-pickup.h
@@ -0,0 +1,44 @@
+/*
+ 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 backend/taler-merchant-httpd_tip-pickup.h
+ * @brief headers for /tip-pickup handler
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_TIP_PICKUP_H
+#define TALER_MERCHANT_HTTPD_TIP_PICKUP_H
+#include <microhttpd.h>
+#include "taler-merchant-httpd.h"
+
+/**
+ * Manages a /tip-pickup call, checking that the tip is authorized,
+ * and if so, returning the withdrawal permissions.
+ *
+ * @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
+ * @return MHD result code
+ */
+int
+MH_handler_tip_pickup (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+#endif
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
index a5e91f5f..072a00ec 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -427,7 +427,7 @@ struct TALER_MERCHANTDB_Plugin
struct GNUNET_TIME_Absolute start_date,
struct GNUNET_TIME_Absolute end_date,
const struct TALER_MasterSignatureP *exchange_sig);
-
+
/**
* Find information about a transaction.
@@ -443,7 +443,7 @@ struct TALER_MERCHANTDB_Plugin
struct GNUNET_TIME_Absolute date,
TALER_MERCHANTDB_TransactionCallback cb,
void *cb_cls);
-
+
/**
* Find information about a transaction.
@@ -480,7 +480,7 @@ struct TALER_MERCHANTDB_Plugin
const struct TALER_MerchantPublicKeyP *merchant_pub,
TALER_MERCHANTDB_CoinDepositCallback cb,
void *cb_cls);
-
+
/**
* Lookup information about coin payments by h_contract_terms and coin.
@@ -555,7 +555,7 @@ struct TALER_MERCHANTDB_Plugin
const struct TALER_WireTransferIdentifierRawP *wtid,
TALER_MERCHANTDB_ProofCallback cb,
void *cb_cls);
-
+
/**
* Obtain information about wire fees charged by an exchange,
@@ -584,7 +584,7 @@ struct TALER_MERCHANTDB_Plugin
struct GNUNET_TIME_Absolute *end_date,
struct TALER_MasterSignatureP *exchange_sig);
-
+
/**
* Function called when some backoffice staff decides to award or
* increase the refund on an existing contract.
@@ -624,6 +624,77 @@ struct TALER_MERCHANTDB_Plugin
void *rc_cls);
/**
+ * Add @a credit to a reserve to be used for tipping. Note that
+ * this function does not actually perform any wire transfers to
+ * credit the reserve, it merely tells the merchant backend that
+ * a reserve was topped up. This has to happen before tips can be
+ * authorized.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param reserve_priv which reserve is topped up or created
+ * @param credit_uuid unique identifier for the credit operation
+ * @param credit how much money was added to the reserve
+ * @param expiration when does the reserve expire?
+ * @return transaction status, usually
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a credit_uuid already known
+ */
+ enum GNUNET_DB_QueryStatus
+ (*enable_tip_reserve)(void *cls,
+ const struct TALER_ReservePrivateKeyP *reserve_priv,
+ const struct GNUNET_HashCode *credit_uuid,
+ const struct TALER_Amount *credit,
+ struct GNUNET_TIME_Absolute expiration);
+
+
+ /**
+ * Authorize a tip over @a amount from reserve @a reserve_priv. Remember
+ * the authorization under @a tip_id for later, together with the
+ * @a justification.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param justification why was the tip approved
+ * @param amount how high is the tip (with fees)
+ * @param reserve_priv which reserve is debited
+ * @param[out] expiration set to when the tip expires
+ * @param[out] tip_id set to the unique ID for the tip
+ * @return transaction status,
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if reserve has insufficient funds,
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT upon success
+ */
+ enum GNUNET_DB_QueryStatus
+ (*authorize_tip)(void *cls,
+ const char *justification,
+ const struct TALER_Amount *amount,
+ const struct TALER_ReservePrivateKeyP *reserve_priv,
+ struct GNUNET_TIME_Absolute *expiration,
+ struct GNUNET_HashCode *tip_id);
+
+
+ /**
+ * Pickup a tip over @a amount using pickup id @a pickup_id.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param amount how high is the amount picked up (with fees)
+ * @param tip_id the unique ID from the tip authorization
+ * @param pickup_id the unique ID identifying the pick up operation
+ * (to allow replays, hash over the coin envelope and denomination key)
+ * @param[out] reserve_priv which reserve key to use to sign
+ * @return taler error code
+ * #TALER_EC_TIP_PICKUP_ID_UNKNOWN if @a tip_id is unknown
+ * #TALER_EC_TIP_PICKUP_NO_FUNDS if @a tip_id has insufficient funds left
+ * #TALER_EC_TIP_PICKUP_DB_ERROR on database errors
+ * #TALER_EC_NONE upon success (@a reserve_priv was set)
+ */
+ enum TALER_ErrorCode
+ (*pickup_tip)(void *cls,
+ const struct TALER_Amount *amount,
+ const struct GNUNET_HashCode *tip_id,
+ const struct GNUNET_HashCode *pickup_id,
+ struct TALER_ReservePrivateKeyP *reserve_priv);
+
+
+ /**
* Roll back the current transaction of a database connection.
*
* @param cls the `struct PostgresClosure` with the plugin-specific state