summaryrefslogtreecommitdiff
path: root/src/backend/taler-merchant-httpd_private-patch-orders-ID-forget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/taler-merchant-httpd_private-patch-orders-ID-forget.c')
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-orders-ID-forget.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/src/backend/taler-merchant-httpd_private-patch-orders-ID-forget.c b/src/backend/taler-merchant-httpd_private-patch-orders-ID-forget.c
new file mode 100644
index 00000000..314e66a5
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-patch-orders-ID-forget.c
@@ -0,0 +1,248 @@
+/*
+ This file is part of TALER
+ (C) 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 <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file backend/taler-merchant-httpd_private-patch-orders-ID-forget.c
+ * @brief implementing PATCH /orders/$ORDER_ID/forget request handling
+ * @author Jonathan Buchanan
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-patch-instances-ID.h"
+#include <taler/taler_json_lib.h>
+
+
+/**
+ * Parse a json path, using the syntax defined in the spec for this method.
+ * @param obj the root object the path applies to.
+ * @param path the path to find.
+ *
+ * @return the object pointed to by @e path if it exists, NULL otherwise.
+ */
+static int
+forget_field (json_t *obj,
+ json_t *prev,
+ const char *field)
+{
+ /* FIXME: Handle nonexistent paths */
+ /* FIXME: If prev is NULL, check that the string starts with $ */
+ char *id = GNUNET_strdup (field);
+ char *next_id = strchr (id,
+ '.');
+ json_t *next_obj = NULL;
+ int ret;
+
+ if (NULL != next_id)
+ {
+ *next_id = '\0';
+ next_id++;
+ }
+ else
+ {
+ return TALER_JSON_contract_part_forget (prev,
+ id);
+ }
+
+ // Check for bracketed indices
+ char *bracket = strchr (id,
+ '[');
+ if (NULL != bracket)
+ {
+ char *end_bracket = strchr (bracket,
+ ']');
+ if (NULL == end_bracket)
+ return GNUNET_SYSERR;
+ *end_bracket = '\0';
+
+ *bracket = '\0';
+ bracket++;
+
+ json_t *arr = json_object_get (obj,
+ id);
+ if (0 == strcmp (bracket,
+ "*"))
+ {
+ /* FIXME: Handle wildcard expansion */
+ }
+ else
+ {
+ unsigned int index;
+ if (1 != sscanf (bracket,
+ "%u",
+ &index))
+ return GNUNET_SYSERR;
+
+ next_obj = json_array_get (arr,
+ index);
+ }
+ }
+ else
+ {
+ // No brackets, so just fetch the object by name
+ next_obj = json_object_get (obj,
+ next_id);
+ }
+
+ ret = forget_field (next_obj,
+ obj,
+ next_id);
+
+ GNUNET_free (id);
+
+ return ret;
+}
+
+
+/**
+ * Forget fields of an order's contract terms.
+ *
+ * @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_patch_orders_ID_forget (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ const char *order_id = hc->infix;
+ enum GNUNET_DB_QueryStatus qs;
+ json_t *fields;
+ json_t *contract_terms;
+ uint64_t order_serial;
+
+ qs = TMH_db->lookup_contract_terms (TMH_db->cls,
+ hc->instance->settings.id,
+ order_id,
+ &contract_terms,
+ &order_serial);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_ORDERS_CLAIM_HARD_DB_ERROR,
+ "Failed to run DB transaction to lookup order");
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_ORDERS_CLAIM_SOFT_DB_ERROR,
+ "Failed to serialize DB transaction to lookup order");
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_FORGET_ORDER_NOT_FOUND,
+ "unknown order id");
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ GNUNET_assert (NULL != contract_terms);
+ break;
+ }
+
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_json ("fields",
+ &fields),
+ GNUNET_JSON_spec_end ()
+ };
+ enum GNUNET_GenericReturnValue res;
+
+ res = TALER_MHD_parse_json_data (connection,
+ hc->request_body,
+ spec);
+ if (GNUNET_OK != res)
+ return (GNUNET_NO == res)
+ ? MHD_YES
+ : MHD_NO;
+ }
+ if ( !(json_is_array (fields)))
+ {
+ json_decref (contract_terms);
+ json_decref (fields);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_PARAMETER_MALFORMED,
+ "paths");
+ }
+
+ {
+ size_t index;
+ json_t *value;
+ json_array_foreach (fields, index, value) {
+ int forget_status;
+ if ( !(json_is_string (value)))
+ {
+ json_decref (contract_terms);
+ json_decref (fields);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_FORGET_PATH_SYNTAX_INCORRECT,
+ "field isn't a string");
+ }
+ // Check that the field starts with "$."
+ forget_status = forget_field (contract_terms,
+ NULL,
+ json_string_value (value));
+ if (GNUNET_SYSERR == forget_status)
+ {
+ /* We tried to forget a field that isn't forgettable */
+ json_decref (contract_terms);
+ json_decref (fields);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_FORGET_PATH_NOT_FORGETTABLE,
+ "field isn't forgettable");
+ }
+ }
+ }
+
+ qs = TMH_db->update_contract_terms (TMH_db->cls,
+ hc->instance->settings.id,
+ order_id,
+ contract_terms);
+
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_ORDERS_CLAIM_HARD_DB_ERROR,
+ "Failed to run DB transaction to update contract terms");
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_ORDERS_CLAIM_SOFT_DB_ERROR,
+ "Failed to serialize DB transaction to update contract terms");
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_FORGET_ORDER_NOT_FOUND,
+ "unknown order id");
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+
+ json_decref (contract_terms);
+ json_decref (fields);
+
+ return TALER_MHD_reply_static (connection,
+ MHD_HTTP_OK,
+ NULL,
+ NULL,
+ 0);
+}