aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/taler-merchant-httpd_private-delete-categories-ID.c92
-rw-r--r--src/backend/taler-merchant-httpd_private-delete-categories-ID.h42
-rw-r--r--src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.c2
-rw-r--r--src/backend/taler-merchant-httpd_private-get-categories-ID.c111
-rw-r--r--src/backend/taler-merchant-httpd_private-get-categories-ID.h42
-rw-r--r--src/backend/taler-merchant-httpd_private-get-categories.c80
-rw-r--r--src/backend/taler-merchant-httpd_private-get-categories.h42
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-categories-ID.c114
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-categories-ID.h45
-rw-r--r--src/backend/taler-merchant-httpd_private-post-categories.c198
-rw-r--r--src/backend/taler-merchant-httpd_private-post-categories.h45
-rw-r--r--src/backenddb/Makefile.am8
-rw-r--r--src/backenddb/merchant-0006.sql55
-rw-r--r--src/backenddb/pg_delete_category.c54
-rw-r--r--src/backenddb/pg_delete_category.h43
-rw-r--r--src/backenddb/pg_delete_otp.c4
-rw-r--r--src/backenddb/pg_insert_category.c65
-rw-r--r--src/backenddb/pg_insert_category.h46
-rw-r--r--src/backenddb/pg_lookup_categories.c148
-rw-r--r--src/backenddb/pg_lookup_categories.h43
-rw-r--r--src/backenddb/pg_select_category.c37
-rw-r--r--src/backenddb/pg_select_category.h45
-rw-r--r--src/backenddb/pg_update_category.c59
-rw-r--r--src/backenddb/pg_update_category.h47
-rw-r--r--src/backenddb/pg_update_otp.c15
-rw-r--r--src/backenddb/plugin_merchantdb_postgres.c15
-rw-r--r--src/include/taler_merchantdb_plugin.h170
27 files changed, 1640 insertions, 27 deletions
diff --git a/src/backend/taler-merchant-httpd_private-delete-categories-ID.c b/src/backend/taler-merchant-httpd_private-delete-categories-ID.c
new file mode 100644
index 00000000..47aab5a0
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-delete-categories-ID.c
@@ -0,0 +1,92 @@
+/*
+ This file is part of TALER
+ (C) 2024 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 taler-merchant-httpd_private-delete-categories-ID.c
+ * @brief implement DELETE /private/categories/$ID
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-delete-categories-ID.h"
+#include <taler/taler_json_lib.h>
+
+
+/**
+ * Handle a DELETE "/categories/$ID" request.
+ *
+ * @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_delete_categories_ID (
+ const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ struct TMH_MerchantInstance *mi = hc->instance;
+ enum GNUNET_DB_QueryStatus qs;
+ unsigned long long cnum;
+ char dummy;
+
+ (void) rh;
+ GNUNET_assert (NULL != mi);
+ GNUNET_assert (NULL != hc->infix);
+ if (1 != sscanf (hc->infix,
+ "%llu%d",
+ &cnum,
+ &dummy))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "category_id must be a number");
+ }
+ qs = TMH_db->delete_category (TMH_db->cls,
+ mi->settings.id,
+ cnum);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_STORE_FAILED,
+ "delete_category");
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "delete_category");
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_MERCHANT_GENERIC_CATEGORY_UNKNOWN,
+ hc->infix);
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ return TALER_MHD_reply_static (connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+ }
+ GNUNET_assert (0);
+ return MHD_NO;
+}
+
+
+/* end of taler-merchant-httpd_private-delete-categories-ID.c */
diff --git a/src/backend/taler-merchant-httpd_private-delete-categories-ID.h b/src/backend/taler-merchant-httpd_private-delete-categories-ID.h
new file mode 100644
index 00000000..b17eed49
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-delete-categories-ID.h
@@ -0,0 +1,42 @@
+/*
+ This file is part of TALER
+ (C) 2024 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 taler-merchant-httpd_private-delete-categories-ID.h
+ * @brief implement DELETE /private/categories/$ID/
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_DELETE_CATEGORIES_ID_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_DELETE_CATEGORIES_ID_H
+
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * Handle a DELETE "/categories/$ID" request.
+ *
+ * @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_delete_categories_ID (
+ const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+/* end of taler-merchant-httpd_private-delete-categories-ID.h */
+#endif
diff --git a/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.c b/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.c
index b147b84f..ff9ad2ef 100644
--- a/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.c
+++ b/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.c
@@ -61,7 +61,7 @@ TMH_private_delete_otp_devices_ID (const struct TMH_RequestHandler *rh,
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
- TALER_EC_MERCHANT_GENERIC_TEMPLATE_UNKNOWN,
+ TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN,
hc->infix);
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
return TALER_MHD_reply_static (connection,
diff --git a/src/backend/taler-merchant-httpd_private-get-categories-ID.c b/src/backend/taler-merchant-httpd_private-get-categories-ID.c
new file mode 100644
index 00000000..bebe087f
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-get-categories-ID.c
@@ -0,0 +1,111 @@
+/*
+ This file is part of TALER
+ (C) 2022-2024 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 taler-merchant-httpd_private-get-categories-ID.c
+ * @brief implement GET /private/categories/$ID
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-get-categories-ID.h"
+#include <taler/taler_json_lib.h>
+
+
+/**
+ * Handle a GET "/private/categories/$ID" request.
+ *
+ * @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_categories_ID (
+ const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ struct TMH_MerchantInstance *mi = hc->instance;
+ struct TALER_MERCHANTDB_OtpDeviceDetails tp = { 0 };
+ enum GNUNET_DB_QueryStatus qs;
+ uint64_t faketime_s
+ = GNUNET_TIME_timestamp_to_s (GNUNET_TIME_timestamp_get ());
+ struct GNUNET_TIME_Timestamp my_time;
+ struct TALER_Amount price;
+
+ TALER_MHD_parse_request_number (connection,
+ "faketime",
+ &faketime_s);
+ memset (&price,
+ 0,
+ sizeof (price));
+ TALER_MHD_parse_request_amount (connection,
+ "price",
+ &price);
+ my_time = GNUNET_TIME_timestamp_from_s (faketime_s);
+ GNUNET_assert (NULL != mi);
+ qs = TMH_db->select_otp (TMH_db->cls,
+ mi->settings.id,
+ hc->infix,
+ &tp);
+ if (0 > qs)
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "select_otp");
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_MERCHANT_GENERIC_CATEGORY_UNKNOWN,
+ hc->infix);
+ }
+ {
+ MHD_RESULT ret;
+ char *pos_confirmation;
+
+ pos_confirmation = (NULL == tp.otp_key)
+ ? NULL
+ : TALER_build_pos_confirmation (tp.otp_key,
+ tp.otp_algorithm,
+ &price,
+ my_time);
+ /* Note: we deliberately (by design) do not return the otp_key */
+ ret = TALER_MHD_REPLY_JSON_PACK (
+ connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_string ("device_description",
+ tp.otp_description),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("otp_code",
+ pos_confirmation)),
+ GNUNET_JSON_pack_uint64 ("otp_timestamp",
+ faketime_s),
+ GNUNET_JSON_pack_uint64 ("otp_algorithm",
+ tp.otp_algorithm),
+ GNUNET_JSON_pack_uint64 ("otp_ctr",
+ tp.otp_ctr));
+ GNUNET_free (pos_confirmation);
+ GNUNET_free (tp.otp_description);
+ GNUNET_free (tp.otp_key);
+ return ret;
+ }
+}
+
+
+/* end of taler-merchant-httpd_private-get-categories-ID.c */
diff --git a/src/backend/taler-merchant-httpd_private-get-categories-ID.h b/src/backend/taler-merchant-httpd_private-get-categories-ID.h
new file mode 100644
index 00000000..c0226659
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-get-categories-ID.h
@@ -0,0 +1,42 @@
+/*
+ This file is part of TALER
+ (C) 2024 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 taler-merchant-httpd_private-get-categories-ID.h
+ * @brief implement GET /private/categories/$ID/
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_CATEGORIES_ID_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_GET_CATEGORIES_ID_H
+
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * Handle a GET "/private/categories/$ID" request.
+ *
+ * @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_categories_ID (
+ const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+/* end of taler-merchant-httpd_private-get-categories-ID.h */
+#endif
diff --git a/src/backend/taler-merchant-httpd_private-get-categories.c b/src/backend/taler-merchant-httpd_private-get-categories.c
new file mode 100644
index 00000000..74c0d6cd
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-get-categories.c
@@ -0,0 +1,80 @@
+/*
+ This file is part of TALER
+ (C) 2024 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 taler-merchant-httpd_private-get-categories.c
+ * @brief implement GET /categories
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-get-categories.h"
+
+
+/**
+ * Add OTP device details to our JSON array.
+ *
+ * @param cls a `json_t *` JSON array to build
+ * @param otp_id ID of the OTP device
+ * @param otp_description human-readable description for the OTP device
+ */
+static void
+add_otp (void *cls,
+ const char *otp_id,
+ const char *otp_description)
+{
+ json_t *pa = cls;
+
+ GNUNET_assert (0 ==
+ json_array_append_new (
+ pa,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("otp_device_id",
+ otp_id),
+ GNUNET_JSON_pack_string ("device_description",
+ otp_description))));
+}
+
+
+MHD_RESULT
+TMH_private_get_categories (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ json_t *pa;
+ enum GNUNET_DB_QueryStatus qs;
+
+ pa = json_array ();
+ GNUNET_assert (NULL != pa);
+ qs = TMH_db->lookup_categories (TMH_db->cls,
+ hc->instance->settings.id,
+ &add_otp,
+ pa);
+ if (0 > qs)
+ {
+ GNUNET_break (0);
+ json_decref (pa);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
+ }
+ return TALER_MHD_REPLY_JSON_PACK (connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_array_steal ("categories",
+ pa));
+}
+
+
+/* end of taler-merchant-httpd_private-get-categories.c */
diff --git a/src/backend/taler-merchant-httpd_private-get-categories.h b/src/backend/taler-merchant-httpd_private-get-categories.h
new file mode 100644
index 00000000..68eed05e
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-get-categories.h
@@ -0,0 +1,42 @@
+/*
+ This file is part of TALER
+ (C) 2024 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 taler-merchant-httpd_private-get-categories.h
+ * @brief implement GET /private/categories
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_CATEGORIES_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_GET_CATEGORIES_H
+
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * Handle a GET "/private/categories" request.
+ *
+ * @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_categories (
+ const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+/* end of taler-merchant-httpd_private-get-categories.h */
+#endif
diff --git a/src/backend/taler-merchant-httpd_private-patch-categories-ID.c b/src/backend/taler-merchant-httpd_private-patch-categories-ID.c
new file mode 100644
index 00000000..596b8b09
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-patch-categories-ID.c
@@ -0,0 +1,114 @@
+/*
+ This file is part of TALER
+ (C) 2022 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 taler-merchant-httpd_private-patch-otp-devices-ID.c
+ * @brief implementing PATCH /otp-devices/$ID request handling
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-patch-otp-devices-ID.h"
+#include "taler-merchant-httpd_helper.h"
+#include <taler/taler_json_lib.h>
+
+
+MHD_RESULT
+TMH_private_patch_otp_devices_ID (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ struct TMH_MerchantInstance *mi = hc->instance;
+ const char *device_id = hc->infix;
+ struct TALER_MERCHANTDB_OtpDeviceDetails tp = {0};
+ enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("otp_device_description",
+ (const char **) &tp.otp_description),
+ TALER_JSON_spec_otp_type ("otp_algorithm",
+ &tp.otp_algorithm),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint64 ("otp_ctr",
+ &tp.otp_ctr),
+ NULL),
+ GNUNET_JSON_spec_mark_optional(
+
+ TALER_JSON_spec_otp_key ("otp_key",
+ (const char **) &tp.otp_key),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+
+ GNUNET_assert (NULL != mi);
+ GNUNET_assert (NULL != device_id);
+ {
+ 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;
+ }
+
+ qs = TMH_db->update_otp (TMH_db->cls,
+ mi->settings.id,
+ device_id,
+ &tp);
+ {
+ MHD_RESULT ret = MHD_NO;
+
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_STORE_FAILED,
+ "update_pos");
+ break;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "unexpected serialization problem");
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN,
+ device_id);
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ ret = TALER_MHD_reply_static (connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+ break;
+ }
+ GNUNET_JSON_parse_free (spec);
+ return ret;
+ }
+}
+
+
+/* end of taler-merchant-httpd_private-patch-otp-devices-ID.c */
diff --git a/src/backend/taler-merchant-httpd_private-patch-categories-ID.h b/src/backend/taler-merchant-httpd_private-patch-categories-ID.h
new file mode 100644
index 00000000..c88290a8
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-patch-categories-ID.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of TALER
+ (C) 2024 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 taler-merchant-httpd_private-patch-categories-ID.h
+ * @brief implementing PATCH /private/categories/$ID request handling
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_PATCH_CATEGORIES_ID_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_PATCH_CATEGORIES_ID_H
+
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * PATCH descriptions of an existing product category.
+ *
+ * @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_categories_ID (
+ const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+#endif
diff --git a/src/backend/taler-merchant-httpd_private-post-categories.c b/src/backend/taler-merchant-httpd_private-post-categories.c
new file mode 100644
index 00000000..255fd2c4
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-post-categories.c
@@ -0,0 +1,198 @@
+/*
+ This file is part of TALER
+ (C) 2024 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 taler-merchant-httpd_private-post-categories.c
+ * @brief implementing POST /private/categories request handling
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-post-categories.h"
+#include "taler-merchant-httpd_helper.h"
+#include <taler/taler_json_lib.h>
+
+
+/**
+ * How often do we retry the simple INSERT database transaction?
+ */
+#define MAX_RETRIES 3
+
+
+/**
+ * Check if the two categories are identical.
+ *
+ * @param t1 device to compare
+ * @param t2 other device to compare
+ * @return true if they are 'equal', false if not or of payto_uris is not an array
+ */
+static bool
+categories_equal (const struct TALER_MERCHANTDB_OtpDeviceDetails *t1,
+ const struct TALER_MERCHANTDB_OtpDeviceDetails *t2)
+{
+ return ( (0 == strcmp (t1->otp_description,
+ t2->otp_description)) &&
+ (0 == strcmp (t1->otp_key,
+ t2->otp_key) ) &&
+ (t1->otp_ctr == t2->otp_ctr) &&
+ (t1->otp_algorithm == t2->otp_algorithm) );
+}
+
+
+MHD_RESULT
+TMH_private_post_categories (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ struct TMH_MerchantInstance *mi = hc->instance;
+ struct TALER_MERCHANTDB_OtpDeviceDetails tp = { 0 };
+ const char *device_id;
+ enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("otp_device_id",
+ &device_id),
+ GNUNET_JSON_spec_string ("otp_device_description",
+ (const char **) &tp.otp_description),
+ TALER_JSON_spec_otp_type ("otp_algorithm",
+ &tp.otp_algorithm),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint64 ("otp_ctr",
+ &tp.otp_ctr),
+ NULL),
+ TALER_JSON_spec_otp_key ("otp_key",
+ (const char **) &tp.otp_key),
+ GNUNET_JSON_spec_end ()
+ };
+
+ GNUNET_assert (NULL != mi);
+ {
+ enum GNUNET_GenericReturnValue res;
+
+ res = TALER_MHD_parse_json_data (connection,
+ hc->request_body,
+ spec);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ return (GNUNET_NO == res)
+ ? MHD_YES
+ : MHD_NO;
+ }
+ }
+
+ /* finally, interact with DB until no serialization error */
+ for (unsigned int i = 0; i<MAX_RETRIES; i++)
+ {
+ /* Test if a OTP device of this id is known */
+ struct TALER_MERCHANTDB_OtpDeviceDetails etp;
+
+ if (GNUNET_OK !=
+ TMH_db->start (TMH_db->cls,
+ "/post categories"))
+ {
+ GNUNET_break (0);
+ GNUNET_JSON_parse_free (spec);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_START_FAILED,
+ NULL);
+ }
+ qs = TMH_db->select_otp (TMH_db->cls,
+ mi->settings.id,
+ device_id,
+ &etp);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ /* Clean up and fail hard */
+ GNUNET_break (0);
+ TMH_db->rollback (TMH_db->cls);
+ GNUNET_JSON_parse_free (spec);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ /* restart transaction */
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ /* Good, we can proceed! */
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ /* idempotency check: is etp == tp? */
+ {
+ bool eq;
+
+ eq = categories_equal (&tp,
+ &etp);
+ GNUNET_free (etp.otp_description);
+ GNUNET_free (etp.otp_key);
+ TMH_db->rollback (TMH_db->cls);
+ GNUNET_JSON_parse_free (spec);
+ return eq
+ ? TALER_MHD_reply_static (connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0)
+ : TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_PRIVATE_POST_CATEGORIES_CONFLICT_CATEGORY_EXISTS,
+ device_id);
+ }
+ } /* end switch (qs) */
+
+ qs = TMH_db->insert_otp (TMH_db->cls,
+ mi->settings.id,
+ device_id,
+ &tp);
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ {
+ TMH_db->rollback (TMH_db->cls);
+ break;
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ {
+ qs = TMH_db->commit (TMH_db->cls);
+ if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
+ break;
+ }
+retry:
+ GNUNET_assert (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ TMH_db->rollback (TMH_db->cls);
+ } /* for RETRIES loop */
+ GNUNET_JSON_parse_free (spec);
+ if (qs < 0)
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ ? TALER_EC_GENERIC_DB_SOFT_FAILURE
+ : TALER_EC_GENERIC_DB_COMMIT_FAILED,
+ NULL);
+ }
+ return TALER_MHD_reply_static (connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+}
+
+
+/* end of taler-merchant-httpd_private-post-categories.c */
diff --git a/src/backend/taler-merchant-httpd_private-post-categories.h b/src/backend/taler-merchant-httpd_private-post-categories.h
new file mode 100644
index 00000000..a8431059
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-post-categories.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of TALER
+ (C) 2024 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 taler-merchant-httpd_private-post-categories.h
+ * @brief implementing POST /categories request handling
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_POST_CATEGORIES_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_POST_CATEGORIES_H
+
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * Generate a product category.
+ *
+ * @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_post_categories (
+ const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+#endif
diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
index 89be9a4f..8d1c582c 100644
--- a/src/backenddb/Makefile.am
+++ b/src/backenddb/Makefile.am
@@ -22,6 +22,7 @@ sql_DATA = \
merchant-0003.sql \
merchant-0004.sql \
merchant-0005.sql \
+ merchant-0006.sql \
drop.sql
BUILT_SOURCES = \
@@ -62,7 +63,7 @@ libtalermerchantdb_la_LIBADD = \
libtalermerchantdb_la_LDFLAGS = \
$(POSTGRESQL_LDFLAGS) \
- -version-info 3:0:1 \
+ -version-info 3:1:1 \
-no-undefined
libtaler_plugin_merchantdb_postgres_la_SOURCES = \
@@ -76,6 +77,11 @@ libtaler_plugin_merchantdb_postgres_la_SOURCES = \
pg_insert_transfer_details.h pg_insert_transfer_details.c \
pg_store_wire_fee_by_exchange.h pg_store_wire_fee_by_exchange.c \
pg_select_open_transfers.h pg_select_open_transfers.c \
+ pg_lookup_categories.h pg_lookup_categories.c \
+ pg_select_category.h pg_select_category.c \
+ pg_update_category.h pg_update_category.c \
+ pg_insert_category.h pg_insert_category.c \
+ pg_delete_category.h pg_delete_category.c \
pg_lookup_instances.h pg_lookup_instances.c \
pg_lookup_transfers.h pg_lookup_transfers.c \
pg_update_transfer_status.h pg_update_transfer_status.c \
diff --git a/src/backenddb/merchant-0006.sql b/src/backenddb/merchant-0006.sql
new file mode 100644
index 00000000..d68927c0
--- /dev/null
+++ b/src/backenddb/merchant-0006.sql
@@ -0,0 +1,55 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2024 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/>
+--
+
+-- Everything in one big transaction
+BEGIN;
+
+-- Check patch versioning is in place.
+SELECT _v.register_patch('merchant-0006', NULL, NULL);
+
+SET search_path TO merchant;
+
+CREATE TABLE IF NOT EXISTS merchant_categories
+ (category_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
+ ,merchant_serial BIGINT NOT NULL
+ REFERENCES merchant_instances (merchant_serial) ON DELETE CASCADE
+ ,category_name TEXT NOT NULL UNIQUE
+ ,category_name_i18n BYTEA NOT NULL
+ );
+
+COMMENT ON COLUMN merchant_categories.category_name
+ IS 'name of the category';
+COMMENT ON COLUMN merchant_categories.category_name_i18n
+ IS 'JSON with translations of the category name';
+
+CREATE TABLE merchant_product_categories
+ (category_serial BIGINT NOT NULL
+ REFERENCES merchant_categories (category_serial) ON DELETE CASCADE
+ ,product_serial BIGINT NOT NULL
+ REFERENCES merchant_inventory (product_serial) ON DELETE CASCADE);
+CREATE INDEX merchant_categories_by_category
+ ON merchant_categories (category_serial);
+CREATE INDEX merchant_categories_by_product
+ ON merchant_categories (product_serial);
+
+COMMENT ON COLUMN merchant_product_categories.category_serial
+ IS 'Reference to a category the product is part of';
+COMMENT ON COLUMN merchant_product_categories.product_serial
+ IS 'Reference to a product which is in the given category';
+
+
+-- Complete transaction
+COMMIT;
diff --git a/src/backenddb/pg_delete_category.c b/src/backenddb/pg_delete_category.c
new file mode 100644
index 00000000..4a43aa37
--- /dev/null
+++ b/src/backenddb/pg_delete_category.c
@@ -0,0 +1,54 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 backenddb/pg_delete_category.c
+ * @brief Implementation of the delete_category function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_delete_category.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_category (void *cls,
+ const char *instance_id,
+ uint64_t category_id)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_uint64 (&category_id),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "delete_category",
+ "DELETE"
+ " FROM merchant_categories"
+ " WHERE merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND category_serial=$2");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "delete_category",
+ params);
+}
diff --git a/src/backenddb/pg_delete_category.h b/src/backenddb/pg_delete_category.h
new file mode 100644
index 00000000..8837a6b8
--- /dev/null
+++ b/src/backenddb/pg_delete_category.h
@@ -0,0 +1,43 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 backenddb/pg_delete_category.h
+ * @brief implementation of the delete_category function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_DELETE_CATEGORY_H
+#define PG_DELETE_CATEGORY_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Delete information about a product category.
+ *
+ * @param cls closure
+ * @param instance_id instance to delete category of
+ * @param category_id identifies the category to delete
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ * if template unknown.
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_category (void *cls,
+ const char *instance_id,
+ uint64_t category_id);
+
+
+#endif
diff --git a/src/backenddb/pg_delete_otp.c b/src/backenddb/pg_delete_otp.c
index 5f011a4b..60f20481 100644
--- a/src/backenddb/pg_delete_otp.c
+++ b/src/backenddb/pg_delete_otp.c
@@ -43,11 +43,11 @@ TMH_PG_delete_otp (void *cls,
"delete_otp",
"DELETE"
" FROM merchant_otp_devices"
- " WHERE merchant_otp_devices.merchant_serial="
+ " WHERE merchant_serial="
" (SELECT merchant_serial "
" FROM merchant_instances"
" WHERE merchant_id=$1)"
- " AND merchant_otp_devices.otp_id=$2");
+ " AND otp_id=$2");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"delete_otp",
params);
diff --git a/src/backenddb/pg_insert_category.c b/src/backenddb/pg_insert_category.c
new file mode 100644
index 00000000..f820b2c6
--- /dev/null
+++ b/src/backenddb/pg_insert_category.c
@@ -0,0 +1,65 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 backenddb/pg_insert_category.c
+ * @brief Implementation of the insert_category function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_insert_category.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_category (void *cls,
+ const char *instance_id,
+ const char *category_name,
+ const json_t *category_name_i18n,
+ uint64_t *category_id)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (category_name),
+ TALER_PQ_query_param_json (category_name_i18n),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("category_serial",
+ category_id),
+ GNUNET_PQ_result_spec_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "insert_category",
+ "INSERT INTO merchant_categories"
+ "(category_name"
+ ",category_name_i18n"
+ ")"
+ " SELECT merchant_serial,"
+ " $2, $3"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1"
+ " RETURNING category_serial");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "insert_category",
+ params,
+ rs);
+}
diff --git a/src/backenddb/pg_insert_category.h b/src/backenddb/pg_insert_category.h
new file mode 100644
index 00000000..8f4bfc99
--- /dev/null
+++ b/src/backenddb/pg_insert_category.h
@@ -0,0 +1,46 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 backenddb/pg_insert_category.h
+ * @brief implementation of the insert_category function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_INSERT_CATEGORY_H
+#define PG_INSERT_CATEGORY_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Insert new product category.
+ *
+ * @param cls closure
+ * @param instance_id instance to insert OTP device for
+ * @param category_name name of the category
+ * @param category_name_i18n translations of the category name
+ * @param[out] category_id set to the category id on success
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_category (void *cls,
+ const char *instance_id,
+ const char *category_name,
+ const json_t *category_name_i18n,
+ uint64_t *category_id);
+
+
+#endif
diff --git a/src/backenddb/pg_lookup_categories.c b/src/backenddb/pg_lookup_categories.c
new file mode 100644
index 00000000..9aea5477
--- /dev/null
+++ b/src/backenddb/pg_lookup_categories.c
@@ -0,0 +1,148 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 backenddb/pg_lookup_categories.c
+ * @brief Implementation of the lookup_categories function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_categories.h"
+#include "pg_helper.h"
+
+
+/**
+ * Context used for TMH_PG_lookup_categories().
+ */
+struct LookupCategoryContext
+{
+ /**
+ * Function to call with the results.
+ */
+ TALER_MERCHANTDB_CategoriesCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Did database result extraction fail?
+ */
+ bool extract_failed;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results about otp_device.
+ *
+ * @param[in,out] cls of type `struct LookupCategoryContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lookup_categories_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupCategoryContext *tlc = cls;
+
+ for (unsigned int i = 0; i < num_results; i++)
+ {
+ uint64_t category_id;
+ char *category_name;
+ json_t *category_name_i18n;
+ uint64_t product_count;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("category_serial",
+ &category_id),
+ GNUNET_PQ_result_spec_string ("category_name",
+ &category_name),
+ TALER_PQ_result_spec_json ("category_name_i18n",
+ &category_name_i18n),
+ GNUNET_PQ_result_spec_uint64 ("product_count",
+ &product_count),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ tlc->extract_failed = true;
+ return;
+ }
+ tlc->cb (tlc->cb_cls,
+ category_id,
+ category_name,
+ category_name_i18n,
+ product_count);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_categories (void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_CategoriesCallback cb,
+ void *cb_cls)
+{
+
+ struct PostgresClosure *pg = cls;
+ struct LookupCategoryContext tlc = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ /* Can be overwritten by the lookup_categories_cb */
+ .extract_failed = false,
+ };
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ check_connection (pg);
+ PREPARE (pg,
+ "lookup_categories",
+ "SELECT"
+ " mc.category_serial"
+ ",mc.category_name"
+ ",mc.category_name_i18n"
+ ",COALESCE(COUNT(mpc.product_serial),0)"
+ " AS product_count"
+ " FROM merchant_categories mc"
+ " JOIN merchant_product_categories mpc"
+ " JOIN merchant_instances mi"
+ " USING (merchant_serial)"
+ " WHERE mi.merchant_id=$1"
+ " GROUP BY mc.category_serial"
+ " ORDER BY mc.category_serial;");
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "lookup_categories",
+ params,
+ &lookup_categories_cb,
+ &tlc);
+ /* If there was an error inside lookup_categories_cb, return a hard error. */
+ if (tlc.extract_failed)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return qs;
+}
diff --git a/src/backenddb/pg_lookup_categories.h b/src/backenddb/pg_lookup_categories.h
new file mode 100644
index 00000000..500295c0
--- /dev/null
+++ b/src/backenddb/pg_lookup_categories.h
@@ -0,0 +1,43 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 backenddb/pg_lookup_categories.h
+ * @brief implementation of the lookup_categories function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_LOOKUP_CATEGORIES_H
+#define PG_LOOKUP_CATEGORIES_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Lookup all of the product categories the given instance has configured.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup OTP devices for
+ * @param cb function to call on all categories found
+ * @param cb_cls closure for @a cb
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_categories (void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_CategoriesCallback cb,
+ void *cb_cls);
+
+#endif
diff --git a/src/backenddb/pg_select_category.c b/src/backenddb/pg_select_category.c
new file mode 100644
index 00000000..c20d7bb7
--- /dev/null
+++ b/src/backenddb/pg_select_category.c
@@ -0,0 +1,37 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 backenddb/pg_select_category.c
+ * @brief Implementation of the select_category function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_select_category.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_select_category (void *cls,
+ const char *instance_id,
+ uint64_t category_id,
+ struct TALER_MERCHANTDB_CategoryDetails *cd)
+{
+ GNUNET_break (0); // FIXME
+ return GNUNET_DB_STATUS_HARD_ERROR;
+}
diff --git a/src/backenddb/pg_select_category.h b/src/backenddb/pg_select_category.h
new file mode 100644
index 00000000..9eeb14aa
--- /dev/null
+++ b/src/backenddb/pg_select_category.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 backenddb/pg_select_category.h
+ * @brief implementation of the select_category function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_CATEGORY_H
+#define PG_SELECT_CATEGORY_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Lookup details about product category.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup template for
+ * @param category_id category to update
+ * @param[out] cd set to the category details on success, can be NULL
+ * (in that case we only want to check if the category exists)
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_select_category (void *cls,
+ const char *instance_id,
+ uint64_t category_id,
+ struct TALER_MERCHANTDB_CategoryDetails *cd);
+
+#endif
diff --git a/src/backenddb/pg_update_category.c b/src/backenddb/pg_update_category.c
new file mode 100644
index 00000000..3b07a266
--- /dev/null
+++ b/src/backenddb/pg_update_category.c
@@ -0,0 +1,59 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 backenddb/pg_update_category.c
+ * @brief Implementation of the update_category function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_update_category.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_category (void *cls,
+ const char *instance_id,
+ uint64_t category_id,
+ const char *category_name,
+ const json_t *category_name_i18n)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_uint64 (&category_id),
+ GNUNET_PQ_query_param_string (category_name),
+ TALER_PQ_query_param_json (category_name_i18n),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "update_category",
+ "UPDATE merchant_categories SET"
+ " category_name=$3"
+ ",category_name_i18n=$4"
+ " WHERE merchant_serial="
+ " (SELECT merchant_serial"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND category_serial=$2");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "update_category",
+ params);
+}
diff --git a/src/backenddb/pg_update_category.h b/src/backenddb/pg_update_category.h
new file mode 100644
index 00000000..616a714a
--- /dev/null
+++ b/src/backenddb/pg_update_category.h
@@ -0,0 +1,47 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 backenddb/pg_update_category.h
+ * @brief implementation of the update_category function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_UPDATE_CATEGORY_H
+#define PG_UPDATE_CATEGORY_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Update descriptions of a product category.
+ *
+ * @param cls closure
+ * @param instance_id instance to update OTP device for
+ * @param category_id category to update
+ * @param category_name name of the category
+ * @param category_name_i18n translations of the category name
+ * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
+ * does not yet exist.
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_category (void *cls,
+ const char *instance_id,
+ uint64_t category_id,
+ const char *category_name,
+ const json_t *category_name_i18n);
+
+#endif
diff --git a/src/backenddb/pg_update_otp.c b/src/backenddb/pg_update_otp.c
index bdcb9624..218ae74e 100644
--- a/src/backenddb/pg_update_otp.c
+++ b/src/backenddb/pg_update_otp.c
@@ -26,17 +26,6 @@
#include "pg_helper.h"
-/**
- * Update details about a particular OTP device.
- *
- * @param cls closure
- * @param instance_id instance to update OTP device for
- * @param otp_id OTP device to update
- * @param td update to the OTP device details on success, can be NULL
- * (in that case we only want to check if the template exists)
- * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
- * does not yet exist.
- */
enum GNUNET_DB_QueryStatus
TMH_PG_update_otp (void *cls,
const char *instance_id,
@@ -52,7 +41,7 @@ TMH_PG_update_otp (void *cls,
GNUNET_PQ_query_param_uint32 (&pos32),
GNUNET_PQ_query_param_uint64 (&td->otp_ctr),
(NULL == td->otp_key)
- ? GNUNET_PQ_query_param_null()
+ ? GNUNET_PQ_query_param_null ()
: GNUNET_PQ_query_param_string (td->otp_key),
GNUNET_PQ_query_param_end
};
@@ -74,5 +63,3 @@ TMH_PG_update_otp (void *cls,
"update_otp",
params);
}
-
-
diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c
index 4a03dbfe..ede43100 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -44,6 +44,11 @@
#include "pg_lookup_instances.h"
#include "pg_lookup_transfers.h"
#include "pg_lookup_pending_deposits.h"
+#include "pg_lookup_categories.h"
+#include "pg_select_category.h"
+#include "pg_update_category.h"
+#include "pg_insert_category.h"
+#include "pg_delete_category.h"
#include "pg_update_wirewatch_progress.h"
#include "pg_select_wirewatch_accounts.h"
#include "pg_select_open_transfers.h"
@@ -564,6 +569,16 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
= &TMH_PG_insert_pending_webhook;
plugin->update_pending_webhook
= &TMH_PG_update_pending_webhook;
+ plugin->lookup_categories
+ = &TMH_PG_lookup_categories;
+ plugin->select_category
+ = &TMH_PG_select_category;
+ plugin->update_category
+ = &TMH_PG_update_category;
+ plugin->insert_category
+ = &TMH_PG_insert_category;
+ plugin->delete_category
+ = &TMH_PG_delete_category;
plugin->delete_exchange_accounts
= &TMH_PG_delete_exchange_accounts;
plugin->select_accounts_by_exchange
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
index 12b13e33..d06ab76c 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2023 Taler Systems SA
+ Copyright (C) 2014-2024 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
@@ -441,6 +441,75 @@ struct TALER_MERCHANTDB_OtpDeviceDetails
/**
+ * Typically called by `lookup_categories`.
+ *
+ * @param cls closure
+ * @param category_id ID of the category
+ * @param category_name name of the category
+ * @param category_name_i18n translations of the @a category_name
+ * @param product_count number of products in the category
+ */
+typedef void
+(*TALER_MERCHANTDB_CategoriesCallback)(
+ void *cls,
+ uint64_t category_id,
+ const char *category_name,
+ const json_t *category_name_i18n,
+ uint64_t product_count);
+
+
+/**
+ * Details about a product category.
+ */
+struct TALER_MERCHANTDB_ProductSummary
+{
+ /**
+ * ID of the product.
+ */
+ char *product_id;
+
+ /**
+ * Description for the product.
+ */
+ char *description;
+
+ /**
+ * Translation of the @e description.
+ */
+ json_t *description_i18n;
+
+};
+
+/**
+ * Details about a product category.
+ */
+struct TALER_MERCHANTDB_CategoryDetails
+{
+
+ /**
+ * Name of the category.
+ */
+ char *category_name;
+
+ /**
+ * Translations of the name of the category.
+ */
+ json_t *category_name_i18n;
+
+ /**
+ * Products in the category.
+ */
+ struct TALER_MERCHANTDB_ProductSummary *products;
+
+ /**
+ * Length of the @e products array.
+ */
+ unsigned int num_products;
+
+};
+
+
+/**
* Typically called by `lookup_webhooks`.
*
* @param cls a `json_t *` JSON array to build
@@ -2876,6 +2945,24 @@ struct TALER_MERCHANTDB_Plugin
/**
+ * Update details about a particular template.
+ *
+ * @param cls closure
+ * @param instance_id instance to update template for
+ * @param template_id template to update
+ * @param td update to the template details on success, can be NULL
+ * (in that case we only want to check if the template exists)
+ * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
+ * does not yet exist.
+ */
+ enum GNUNET_DB_QueryStatus
+ (*update_template)(void *cls,
+ const char *instance_id,
+ const char *template_id,
+ const struct TALER_MERCHANTDB_TemplateDetails *td);
+
+
+ /**
* Delete information about an OTP device.
*
* @param cls closure
@@ -2971,21 +3058,86 @@ struct TALER_MERCHANTDB_Plugin
/**
- * Update details about a particular template.
+ * Delete information about a product category.
*
* @param cls closure
- * @param instance_id instance to update template for
- * @param template_id template to update
- * @param td update to the template details on success, can be NULL
- * (in that case we only want to check if the template exists)
+ * @param instance_id instance to delete category of
+ * @param category_id identifies the category to delete
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ * if template unknown.
+ */
+ enum GNUNET_DB_QueryStatus
+ (*delete_category)(void *cls,
+ const char *instance_id,
+ uint64_t category_id);
+
+ /**
+ * Insert new product category.
+ *
+ * @param cls closure
+ * @param instance_id instance to insert OTP device for
+ * @param category_name name of the category
+ * @param category_name_i18n translations of the category name
+ * @param[out] category_id set to the category id on success
+ * @return database result code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*insert_category)(void *cls,
+ const char *instance_id,
+ const char *category_name,
+ const json_t *category_name_i18n,
+ uint64_t *category_id);
+
+
+ /**
+ * Update descriptions of a product category.
+ *
+ * @param cls closure
+ * @param instance_id instance to update OTP device for
+ * @param category_id category to update
+ * @param category_name name of the category
+ * @param category_name_i18n translations of the category name
* @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
* does not yet exist.
*/
enum GNUNET_DB_QueryStatus
- (*update_template)(void *cls,
+ (*update_category)(void *cls,
const char *instance_id,
- const char *template_id,
- const struct TALER_MERCHANTDB_TemplateDetails *td);
+ uint64_t category_id,
+ const char *category_name,
+ const json_t *category_name_i18n);
+
+ /**
+ * Lookup all of the product categories the given instance has configured.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup OTP devices for
+ * @param cb function to call on all categories found
+ * @param cb_cls closure for @a cb
+ * @return database result code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*lookup_categories)(void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_CategoriesCallback cb,
+ void *cb_cls);
+
+
+ /**
+ * Lookup details about product category.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup template for
+ * @param category_id category to update
+ * @param[out] cd set to the category details on success, can be NULL
+ * (in that case we only want to check if the category exists)
+ * @return database result code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*select_category)(void *cls,
+ const char *instance_id,
+ uint64_t category_id,
+ struct TALER_MERCHANTDB_CategoryDetails *cd);
/**