diff options
author | Christian Blättler <blatc2@bfh.ch> | 2023-11-21 08:06:00 +0100 |
---|---|---|
committer | Christian Grothoff <grothoff@gnunet.org> | 2023-12-23 00:08:57 +0800 |
commit | 094327bc906cdeced19a52c86dc0725aad773997 (patch) | |
tree | b459428305452298749cb90438c7a734a64230d1 | |
parent | 20632c6a2e293a9799114497d63180a105b37065 (diff) |
POST /tokenfamilies endpoint
23 files changed, 1332 insertions, 24 deletions
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 4a25785c..7978258d 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -53,6 +53,8 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-delete-reserves-ID.h \ taler-merchant-httpd_private-delete-templates-ID.c \ taler-merchant-httpd_private-delete-templates-ID.h \ + taler-merchant-httpd_private-delete-token-families-SLUG.c \ + taler-merchant-httpd_private-delete-token-families-SLUG.h \ taler-merchant-httpd_private-delete-transfers-ID.c \ taler-merchant-httpd_private-delete-transfers-ID.h \ taler-merchant-httpd_private-delete-webhooks-ID.c \ @@ -89,6 +91,10 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-get-templates.h \ taler-merchant-httpd_private-get-templates-ID.c \ taler-merchant-httpd_private-get-templates-ID.h \ + taler-merchant-httpd_private-get-token-families.c \ + taler-merchant-httpd_private-get-token-families.h \ + taler-merchant-httpd_private-get-token-families-SLUG.c \ + taler-merchant-httpd_private-get-token-families-SLUG.h \ taler-merchant-httpd_private-get-webhooks.c \ taler-merchant-httpd_private-get-webhooks.h \ taler-merchant-httpd_private-get-webhooks-ID.c \ @@ -105,6 +111,8 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-patch-products-ID.h \ taler-merchant-httpd_private-patch-templates-ID.c \ taler-merchant-httpd_private-patch-templates-ID.h \ + taler-merchant-httpd_private-patch-token-families-SLUG.c \ + taler-merchant-httpd_private-patch-token-families-SLUG.h \ taler-merchant-httpd_private-patch-webhooks-ID.c \ taler-merchant-httpd_private-patch-webhooks-ID.h \ taler-merchant-httpd_private-post-account.c \ @@ -131,6 +139,8 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h \ taler-merchant-httpd_private-post-templates.c \ taler-merchant-httpd_private-post-templates.h \ + taler-merchant-httpd_private-post-token-families.c \ + taler-merchant-httpd_private-post-token-families.h \ taler-merchant-httpd_private-post-transfers.c \ taler-merchant-httpd_private-post-transfers.h \ taler-merchant-httpd_private-post-webhooks.c \ diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index 3b78677a..83390887 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -41,6 +41,7 @@ #include "taler-merchant-httpd_private-delete-otp-devices-ID.h" #include "taler-merchant-httpd_private-delete-reserves-ID.h" #include "taler-merchant-httpd_private-delete-templates-ID.h" +#include "taler-merchant-httpd_private-delete-token-families-SLUG.h" #include "taler-merchant-httpd_private-delete-transfers-ID.h" #include "taler-merchant-httpd_private-delete-webhooks-ID.h" #include "taler-merchant-httpd_private-get-accounts.h" @@ -60,6 +61,8 @@ #include "taler-merchant-httpd_private-get-rewards.h" #include "taler-merchant-httpd_private-get-templates.h" #include "taler-merchant-httpd_private-get-templates-ID.h" +#include "taler-merchant-httpd_private-get-token-families.h" +#include "taler-merchant-httpd_private-get-token-families-SLUG.h" #include "taler-merchant-httpd_private-get-transfers.h" #include "taler-merchant-httpd_private-get-webhooks.h" #include "taler-merchant-httpd_private-get-webhooks-ID.h" @@ -69,6 +72,7 @@ #include "taler-merchant-httpd_private-patch-otp-devices-ID.h" #include "taler-merchant-httpd_private-patch-products-ID.h" #include "taler-merchant-httpd_private-patch-templates-ID.h" +#include "taler-merchant-httpd_private-patch-token-families-SLUG.h" #include "taler-merchant-httpd_private-patch-webhooks-ID.h" #include "taler-merchant-httpd_private-post-account.h" #include "taler-merchant-httpd_private-post-instances.h" @@ -82,6 +86,7 @@ #include "taler-merchant-httpd_private-post-reserves.h" #include "taler-merchant-httpd_private-post-reserves-ID-authorize-reward.h" #include "taler-merchant-httpd_private-post-templates.h" +#include "taler-merchant-httpd_private-post-token-families.h" #include "taler-merchant-httpd_private-post-transfers.h" #include "taler-merchant-httpd_private-post-webhooks.h" #include "taler-merchant-httpd_post-orders-ID-abort.h" @@ -1300,6 +1305,42 @@ url_handler (void *cls, .method = MHD_HTTP_METHOD_DELETE, .handler = &TMH_private_delete_instances_ID_token, }, + /* GET /tokenfamilies: */ + { + .url_prefix = "/tokenfamilies", + .method = MHD_HTTP_METHOD_GET, + .handler = &TMH_private_get_tokenfamilies + }, + /* POST /tokenfamilies: */ + { + .url_prefix = "/tokenfamilies", + .method = MHD_HTTP_METHOD_POST, + .handler = &TMH_private_post_token_families + }, + /* GET /tokenfamilies/$SLUG/: */ + { + .url_prefix = "/tokenfamilies/", + .method = MHD_HTTP_METHOD_GET, + .have_id_segment = true, + .allow_deleted_instance = true, + .handler = &TMH_private_get_tokenfamilies_SLUG + }, + /* DELETE /tokenfamilies/$SLUG/: */ + { + .url_prefix = "/tokenfamilies/", + .method = MHD_HTTP_METHOD_DELETE, + .have_id_segment = true, + .allow_deleted_instance = true, + .handler = &TMH_private_delete_token_families_SLUG + }, + /* PATCH /tokenfamilies/$SLUG/: */ + { + .url_prefix = "/tokenfamilies/", + .method = MHD_HTTP_METHOD_PATCH, + .have_id_segment = true, + .allow_deleted_instance = true, + .handler = &TMH_private_patch_token_family_SLUG, + }, { .url_prefix = NULL } diff --git a/src/backend/taler-merchant-httpd_private-delete-token-families-SLUG.c b/src/backend/taler-merchant-httpd_private-delete-token-families-SLUG.c new file mode 100644 index 00000000..3418b795 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-delete-token-families-SLUG.c @@ -0,0 +1,73 @@ +/* + This file is part of TALER + (C) 2023 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-token-families-SLUG.c + * @brief implement DELETE /tokenfamilies/$SLUG + * @author Christian Blättler + */ +#include "platform.h" +#include "taler-merchant-httpd_private-delete-token-families-SLUG.h" +#include <taler/taler_json_lib.h> + + +/** + * Handle a DELETE "/tokenfamilies/$SLUG" 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_token_families_SLUG (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TMH_MerchantInstance *mi = hc->instance; + enum GNUNET_DB_QueryStatus qs; + + (void) rh; + GNUNET_assert (NULL != mi); + GNUNET_assert (NULL != hc->infix); + qs = TMH_db->delete_token_family (TMH_db->cls, + mi->settings.id, + hc->infix); + 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_token_family"); + 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_token_family (soft)"); + 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-token-families-SLUG.c */ diff --git a/src/backend/taler-merchant-httpd_private-delete-token-families-SLUG.h b/src/backend/taler-merchant-httpd_private-delete-token-families-SLUG.h new file mode 100644 index 00000000..e8b72fc6 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-delete-token-families-SLUG.h @@ -0,0 +1,41 @@ +/* + This file is part of TALER + (C) 2023 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-token-families-SLUG.h + * @brief implement DELETE /tokenfamilies/$SLUG/ + * @author Christian Blättler + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_DELETE_TOKEN_FAMILIES_SLUG_H +#define TALER_MERCHANT_HTTPD_PRIVATE_DELETE_TOKEN_FAMILIES_SLUG_H + +#include "taler-merchant-httpd.h" + + +/** + * Handle a DELETE "/tokenfamilies/$SLUG" 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_token_families_SLUG (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +/* end of taler-merchant-httpd_private-delete-token-families-SLUG.h */ +#endif diff --git a/src/backend/taler-merchant-httpd_private-get-templates.c b/src/backend/taler-merchant-httpd_private-get-templates.c index e59e47c9..d0bec884 100644 --- a/src/backend/taler-merchant-httpd_private-get-templates.c +++ b/src/backend/taler-merchant-httpd_private-get-templates.c @@ -40,8 +40,7 @@ add_template (void *cls, json_array_append_new ( pa, GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("template_id", - template_id), + GNUNET_JSON_pack_string ("template_id", template_id), GNUNET_JSON_pack_string ("template_description", template_description)))); } diff --git a/src/backend/taler-merchant-httpd_private-get-token-families-SLUG.c b/src/backend/taler-merchant-httpd_private-get-token-families-SLUG.c new file mode 100644 index 00000000..d31884da --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-get-token-families-SLUG.c @@ -0,0 +1,104 @@ +/* + This file is part of TALER + (C) 2023 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-token-families-SLUG.c + * @brief implement GET /tokenfamilies/$SLUG/ + * @author Christian Blättler + */ +#include "platform.h" +#include "taler-merchant-httpd_private-get-token-families-SLUG.h" +#include <taler/taler_json_lib.h> + + +/** + * Handle a GET "/tokenfamilies/$SLUG" 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_tokenfamilies_SLUG (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TMH_MerchantInstance *mi = hc->instance; + struct TALER_MERCHANTDB_TokenFamilyDetails details = { 0 }; + enum GNUNET_DB_QueryStatus status; + + GNUNET_assert (NULL != mi); + status = TMH_db->lookup_token_family (TMH_db->cls, + mi->settings.id, + hc->infix, + &details); + if (0 > status) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "lookup_token_family"); + } + if (0 == status) + { + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN, + hc->infix); + } + // TODO: Why is this block here? Limiting variable lifetime? + { + char *kind = NULL; + if (TALER_MERCHANTDB_TFK_Subscription == details.kind) + { + kind = GNUNET_strdup ("subscription"); + } + else if (TALER_MERCHANTDB_TFK_Discount == details.kind) + { + kind = GNUNET_strdup ("discount"); + } + else + { + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + // TODO: What error code to use here? + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "invalid_token_family_kind"); + } + + MHD_RESULT result; + + result = TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_string ("name", details.name), + GNUNET_JSON_pack_string ("description", details.description), + GNUNET_JSON_pack_object_steal ("description_i18n", details.description_i18n), + GNUNET_JSON_pack_timestamp ("valid_after", details.valid_after), + GNUNET_JSON_pack_timestamp ("valid_before", details.valid_before), + GNUNET_JSON_pack_time_rel ("duration", details.duration), + GNUNET_JSON_pack_string ("kind", kind) + ); + + GNUNET_free (details.name); + GNUNET_free (details.description); + return result; + } +} + + +/* end of taler-merchant-httpd_private-get-products-SLUG.c */ diff --git a/src/backend/taler-merchant-httpd_private-get-token-families-SLUG.h b/src/backend/taler-merchant-httpd_private-get-token-families-SLUG.h new file mode 100644 index 00000000..a7b02d8f --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-get-token-families-SLUG.h @@ -0,0 +1,41 @@ +/* + This file is part of TALER + (C) 2023 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-token-families-SLUG.h + * @brief implement GET /tokenfamilies/$SLUG/ + * @author Christian Blättler + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_TOKENFAMILIES_SLUG_H +#define TALER_MERCHANT_HTTPD_PRIVATE_GET_TOKENFAMILIES_SLUG_H + +#include "taler-merchant-httpd.h" + + +/** + * Handle a GET "/tokenfamilies/$SLUG" 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_tokenfamilies_SLUG (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +/* end of taler-merchant-httpd_private-get-token-families-SLUG.h */ +#endif diff --git a/src/backend/taler-merchant-httpd_private-get-token-families.c b/src/backend/taler-merchant-httpd_private-get-token-families.c new file mode 100644 index 00000000..031edd90 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-get-token-families.c @@ -0,0 +1,85 @@ +/* + This file is part of TALER + (C) 2023 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-token-families.c + * @brief implement GET /tokenfamilies + * @author Christian Blättler + */ +#include "platform.h" +#include "taler-merchant-httpd_private-get-token-families.h" + + + +/** + * Add token family details to our JSON array. + * + * @param cls a `json_t *` JSON array to build + * @param slug slug of the token family + * @param name name of the token family + * @param start_time start time of the token family's validity period + * @param expiration end time of the token family's validity period + */ +static void +add_token_family (void *cls, + const char *slug, + const char *name, + struct GNUNET_TIME_Timestamp start_time, + struct GNUNET_TIME_Timestamp expiration) +{ + json_t *pa = cls; + + GNUNET_assert (0 == + json_array_append_new ( + pa, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("slug", slug), + GNUNET_JSON_pack_string ("name", name), + GNUNET_JSON_pack_timestamp ("start_time", start_time), + GNUNET_JSON_pack_timestamp ("expiration", expiration)))); +} + + +MHD_RESULT +TMH_private_get_tokenfamilies (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + json_t *families; + enum GNUNET_DB_QueryStatus qs; + + families = json_array (); + GNUNET_assert (NULL != families); + qs = TMH_db->lookup_token_families (TMH_db->cls, + hc->instance->settings.id, + &add_token_family, + families); + if (0 > qs) + { + GNUNET_break (0); + json_decref (families); + 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 ("token_families", + families)); +} + + +/* end of taler-merchant-httpd_private-get-token-families.c */ diff --git a/src/backend/taler-merchant-httpd_private-get-token-families.h b/src/backend/taler-merchant-httpd_private-get-token-families.h new file mode 100644 index 00000000..a02a42b0 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-get-token-families.h @@ -0,0 +1,41 @@ +/* + This file is part of TALER + (C) 2023 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-token-families.h + * @brief implement GET /tokenfamilies + * @author Christian Blättler + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_TOKENFAMILIES_H +#define TALER_MERCHANT_HTTPD_PRIVATE_GET_TOKENFAMILIES_H + +#include "taler-merchant-httpd.h" + + +/** + * Handle a GET "/tokenfamilies" 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_tokenfamilies (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +/* end of taler-merchant-httpd_private-get-token-families.h */ +#endif diff --git a/src/backend/taler-merchant-httpd_private-patch-products-ID.h b/src/backend/taler-merchant-httpd_private-patch-products-ID.h index e7f8fcfd..9ce0a7ae 100644 --- a/src/backend/taler-merchant-httpd_private-patch-products-ID.h +++ b/src/backend/taler-merchant-httpd_private-patch-products-ID.h @@ -19,7 +19,7 @@ /** * @file taler-merchant-httpd_private-patch-products-ID.h - * @brief implementing POST /products request handling + * @brief implementing PATCH /products/$ID request handling * @author Christian Grothoff */ #ifndef TALER_MERCHANT_HTTPD_PRIVATE_PATCH_PRODUCTS_ID_H diff --git a/src/backend/taler-merchant-httpd_private-patch-token-families-SLUG.c b/src/backend/taler-merchant-httpd_private-patch-token-families-SLUG.c new file mode 100644 index 00000000..a5fef59d --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-patch-token-families-SLUG.c @@ -0,0 +1,158 @@ +/* + This file is part of TALER + (C) 2023 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-token-families-SLUG.c + * @brief implementing PATCH /tokenfamilies/$SLUG request handling + * @author Christian Blättler + */ +#include "platform.h" +#include "taler-merchant-httpd_private-patch-token-families-SLUG.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 + +/** + * Handle a PATCH "/tokenfamilies/$slug" 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_patch_token_family_SLUG (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TMH_MerchantInstance *mi = hc->instance; + const char *slug = hc->infix; + struct TALER_MERCHANTDB_TokenFamilyDetails details = {0}; + int64_t total_stock; + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("name", + (const char **) &details.name), + GNUNET_JSON_spec_string ("description", + (const char **) &details.description), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_json ("description_i18n", + &details.description_i18n), + NULL), + GNUNET_JSON_spec_timestamp ("valid_after", + &details.valid_after), + GNUNET_JSON_spec_timestamp ("valid_before", + &details.valid_before), + GNUNET_JSON_spec_relative_time ("duration", + &details.duration), + GNUNET_JSON_spec_end () + }; + + GNUNET_assert (NULL != mi); + GNUNET_assert (NULL != slug); + { + 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; + } + + struct GNUNET_TIME_Relative validity = GNUNET_TIME_absolute_get_difference( + details.valid_after.abs_time, + details.valid_before.abs_time); + + // Check if start_time is before valid_before + if (0 == validity.rel_value_us) + { + GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "invalid_validity_duration"); + } + + if (NULL == details.description_i18n) + details.description_i18n = json_object (); + + if (! TALER_JSON_check_i18n (details.description_i18n)) + { + GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "description_i18n"); + } + + qs = TMH_db->update_token_family (TMH_db->cls, + mi->settings.id, + slug, + &details); + { + 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, + NULL); + 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: + // TODO: Add error code for token family not found + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + 0, + slug); + 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-token-families-SLUG.c */ diff --git a/src/backend/taler-merchant-httpd_private-patch-token-families-SLUG.h b/src/backend/taler-merchant-httpd_private-patch-token-families-SLUG.h new file mode 100644 index 00000000..87ad86b3 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-patch-token-families-SLUG.h @@ -0,0 +1,43 @@ +/* + This file is part of TALER + (C) 2023 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-token-families-SLUG.h + * @brief implementing PATCH /tokenfamilies/$SLUG request handling + * @author Christian Blättler + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_PATCH_TOKEN_FAMILIES_SLUG_H +#define TALER_MERCHANT_HTTPD_PRIVATE_PATCH_TOKEN_FAMILIES_SLUG_H +#include "taler-merchant-httpd.h" + + +/** + * Handle a PATCH "/tokenfamilies/$slug" 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_patch_token_family_SLUG (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +#endif diff --git a/src/backend/taler-merchant-httpd_private-post-token-families.c b/src/backend/taler-merchant-httpd_private-post-token-families.c new file mode 100644 index 00000000..6ff25942 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-post-token-families.c @@ -0,0 +1,229 @@ +/* + This file is part of TALER + (C) 2023 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-token-families.c + * @brief implementing POST /tokenfamilies request handling + * @author Christian Blättler + */ +#include "platform.h" +#include "taler-merchant-httpd_private-post-token-families.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 token families are identical. + * + * @param tf1 token family to compare + * @param tf2 other token family to compare + * @return true if they are 'equal', false if not + */ +static bool +token_families_equal (const struct TALER_MERCHANTDB_TokenFamilyDetails *tf1, + const struct TALER_MERCHANTDB_TokenFamilyDetails *tf2) +{ + return ( (0 == strcmp (tf1->slug, + tf2->slug)) && + (0 == strcmp (tf1->name, + tf2->name)) && + (0 == strcmp (tf1->description, + tf2->description)) && + (1 == json_equal (tf1->description_i18n, + tf2->description_i18n)) && + (GNUNET_TIME_timestamp_cmp (tf1->valid_after, + ==, + tf2->valid_after)) && + (GNUNET_TIME_timestamp_cmp (tf1->valid_before, + ==, + tf2->valid_before)) && + (GNUNET_TIME_relative_cmp (tf1->duration, + ==, + tf2->duration)) && + (tf1->kind == tf2->kind) ); +} + + +MHD_RESULT +TMH_private_post_token_families (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TMH_MerchantInstance *mi = hc->instance; + struct TALER_MERCHANTDB_TokenFamilyDetails details = { 0 }; + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("slug", + (const char **) &details.slug), + GNUNET_JSON_spec_string ("name", + (const char **) &details.name), + GNUNET_JSON_spec_string ("description", + (const char **) &details.description), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_json ("description_i18n", + &details.description_i18n), + NULL), + GNUNET_JSON_spec_uint32("kind", &details.kind), + GNUNET_JSON_spec_timestamp ("valid_after", + &details.valid_after), + GNUNET_JSON_spec_timestamp ("valid_before", + &details.valid_before), + GNUNET_JSON_spec_relative_time ("duration", + &details.duration), + 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; + } + } + + if (NULL == details.description_i18n) + details.description_i18n = json_object (); + + if (! TALER_JSON_check_i18n (details.description_i18n)) + { + GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "description_i18n"); + } + + + /* finally, interact with DB until no serialization error */ + for (unsigned int i = 0; i<MAX_RETRIES; i++) + { + /* Test if a token family of this id is known */ + struct TALER_MERCHANTDB_TokenFamilyDetails existing; + + if (GNUNET_OK != + TMH_db->start (TMH_db->cls, + "/post tokenfamilies")) + { + 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->lookup_token_family (TMH_db->cls, + mi->settings.id, + details.slug, + &existing); + 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 existing == details? */ + { + bool eq; + + eq = token_families_equal (&details, + &existing); + TALER_MERCHANTDB_token_family_details_free (&existing); + 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) + // TODO: Use proper error code + : TALER_MHD_reply_with_error (connection, + MHD_HTTP_CONFLICT, + 0, + details.slug); + } + } /* end switch (qs) */ + + qs = TMH_db->insert_token_family (TMH_db->cls, + mi->settings.id, + details.slug, + &details); + 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-token-families.c */ diff --git a/src/backend/taler-merchant-httpd_private-post-token-families.h b/src/backend/taler-merchant-httpd_private-post-token-families.h new file mode 100644 index 00000000..ada1c7c9 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-post-token-families.h @@ -0,0 +1,43 @@ +/* + This file is part of TALER + (C) 2023 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-token-families.h + * @brief implementing POST /tokenfamilies request handling + * @author Christian Blättler + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_POST_TOKEN_FAMILIES_H +#define TALER_MERCHANT_HTTPD_PRIVATE_POST_TOKEN_FAMILIES_H +#include "taler-merchant-httpd.h" + + +/** + * Create a new token family. + * + * @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_token_families (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 339d59af..f0e2bc9c 100644 --- a/src/backenddb/Makefile.am +++ b/src/backenddb/Makefile.am @@ -166,6 +166,8 @@ libtaler_plugin_merchantdb_postgres_la_SOURCES = \ pg_insert_pending_webhook.h pg_insert_pending_webhook.c \ pg_update_pending_webhook.h pg_update_pending_webhook.c \ pg_lookup_pending_webhooks.h pg_lookup_pending_webhooks.c \ + pg_insert_token_family.h pg_insert_token_family.c \ + pg_lookup_token_family.h pg_lookup_token_family.c \ plugin_merchantdb_postgres.c \ pg_helper.h pg_helper.c libtaler_plugin_merchantdb_postgres_la_LIBADD = \ diff --git a/src/backenddb/merchant-0002.sql b/src/backenddb/merchant-0002.sql index c2fffb43..b92a1fcf 100644 --- a/src/backenddb/merchant-0002.sql +++ b/src/backenddb/merchant-0002.sql @@ -14,6 +14,10 @@ -- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -- +-- @file merchant-0002.sql +-- @brief database schema for the merchant +-- @author Christian Blättler + -- Everything in one big transaction BEGIN; @@ -43,9 +47,12 @@ CREATE INDEX IF NOT EXISTS merchant_contract_terms_by_merchant_and_session CREATE TABLE IF NOT EXISTS merchant_token_families (token_family_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY - ,name TEXT NOT NULL UNIQUE + ,slug TEXT NOT NULL UNIQUE + ,name TEXT NOT NULL ,description TEXT ,description_i18n BYTEA NOT NULL + ,valid_after BIGINT NOT NULL + ,valid_before BIGINT NOT NULL ,duration BIGINT NOT NULL ,kind TEXT NOT NULL CHECK (kind IN ('subscription', 'discount')) ,issued BIGINT DEFAULT 0 @@ -53,14 +60,20 @@ CREATE TABLE IF NOT EXISTS merchant_token_families ); COMMENT ON TABLE merchant_token_families IS 'Token families configured by the merchant.'; +COMMENT ON COLUMN merchant_token_families.slug + IS 'Unique slug for the token family.'; COMMENT ON COLUMN merchant_token_families.name IS 'Name of the token family.'; COMMENT ON COLUMN merchant_token_families.description IS 'Human-readable description or details about the token family.'; COMMENT ON COLUMN merchant_token_families.description_i18n IS 'JSON map from IETF BCP 47 language tags to localized descriptions'; +COMMENT ON COLUMN merchant_token_families.valid_after + IS 'Start time of the token family''s validity period.'; +COMMENT ON COLUMN merchant_token_families.valid_before + IS 'End time of the token family''s validity period.'; COMMENT ON COLUMN merchant_token_families.duration - IS 'Duration of the token family.'; + IS 'Duration of the token.'; COMMENT ON COLUMN merchant_token_families.kind IS 'Kind of the token (e.g., subscription, discount).'; COMMENT ON COLUMN merchant_token_families.issued @@ -69,8 +82,8 @@ COMMENT ON COLUMN merchant_token_families.redeemed IS 'Counter for the number of tokens redeemed for this token family.'; -CREATE TABLE IF NOT EXISTS merchant_token_keys - (token_keys_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY +CREATE TABLE IF NOT EXISTS merchant_token_family_keys + (token_family_key_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY ,token_family_serial BIGINT REFERENCES merchant_token_families(token_family_serial) ON DELETE CASCADE ,valid_after BIGINT NOT NULL ,valid_before BIGINT NOT NULL @@ -81,21 +94,21 @@ CREATE TABLE IF NOT EXISTS merchant_token_keys ,UNIQUE (token_family_serial, valid_after) ); -COMMENT ON TABLE merchant_token_keys +COMMENT ON TABLE merchant_token_family_keys IS 'Keys for token families.'; -COMMENT ON COLUMN merchant_token_keys.token_family_serial +COMMENT ON COLUMN merchant_token_family_keys.token_family_serial IS 'Token family to which the key belongs.'; -COMMENT ON COLUMN merchant_token_keys.valid_after - IS 'Start date/time for the validity of the token key.'; -COMMENT ON COLUMN merchant_token_keys.valid_before - IS 'Expiration date/time for the validity of the token key.'; -COMMENT ON COLUMN merchant_token_keys.pub +COMMENT ON COLUMN merchant_token_family_keys.valid_after + IS 'Start time for the validity of the token key.'; +COMMENT ON COLUMN merchant_token_family_keys.valid_before + IS 'Expiration time for the validity of the token key.'; +COMMENT ON COLUMN merchant_token_family_keys.pub IS 'Public key of the token family.'; -COMMENT ON COLUMN merchant_token_keys.h_pub +COMMENT ON COLUMN merchant_token_family_keys.h_pub IS 'Hash of the public key for quick lookup.'; -COMMENT ON COLUMN merchant_token_keys.priv +COMMENT ON COLUMN merchant_token_family_keys.priv IS 'Private key of the token family; can be NULL if no more tokens of this familiy should be issued.'; -COMMENT ON COLUMN merchant_token_keys.cipher +COMMENT ON COLUMN merchant_token_family_keys.cipher IS 'Cipher used (rsa or cs).'; @@ -103,7 +116,7 @@ CREATE TABLE IF NOT EXISTS merchant_spent_tokens (spent_token_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY ,merchant_serial BIGINT NOT NULL REFERENCES merchant_instances (merchant_serial) ON DELETE CASCADE ,h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64) - ,token_key_serial BIGINT REFERENCES merchant_token_key(token_key_serial) ON DELETE CASCADE + ,token_family_key_serial BIGINT REFERENCES merchant_token_family_keys(token_family_key_serial) ON DELETE CASCADE ,token_pub BYTEA NOT NULL UNIQUE CHECK (LENGTH(token_pub)=32) ,token_sig BYTEA NOT NULL CHECK (LENGTH(token_sig)=64) ,blind_sig BYTEA NOT NULL @@ -114,7 +127,7 @@ COMMENT ON COLUMN merchant_spent_tokens.merchant_serial IS 'Merchant serial where the token was spent.'; COMMENT ON COLUMN merchant_spent_tokens.h_contract_terms IS 'This is no foreign key by design.'; -COMMENT ON COLUMN merchant_spent_tokens.token_key_serial +COMMENT ON COLUMN merchant_spent_tokens.token_family_key_serial IS 'Token family to which the spent token belongs.'; COMMENT ON COLUMN merchant_spent_tokens.token_pub IS 'Public key of the spent token.'; diff --git a/src/backenddb/merchantdb_helper.c b/src/backenddb/merchantdb_helper.c index 4ae75020..4ba70e4b 100644 --- a/src/backenddb/merchantdb_helper.c +++ b/src/backenddb/merchantdb_helper.c @@ -69,5 +69,15 @@ TALER_MERCHANTDB_pending_webhook_details_free ( GNUNET_free (pwb->body); } +void +TALER_MERCHANTDB_token_family_details_free ( + struct TALER_MERCHANTDB_TokenFamilyDetails *tf) +{ + GNUNET_free (tf->slug); + GNUNET_free (tf->name); + GNUNET_free (tf->description); + json_decref (tf->description_i18n); +} + /* end of merchantdb_helper.c */ diff --git a/src/backenddb/pg_insert_token_family.c b/src/backenddb/pg_insert_token_family.c new file mode 100644 index 00000000..88cd8649 --- /dev/null +++ b/src/backenddb/pg_insert_token_family.c @@ -0,0 +1,81 @@ +/* + This file is part of TALER + Copyright (C) 2023 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_token_family.c + * @brief Implementation of the insert_token_family function for Postgres + * @author Christian Blättler + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_insert_token_family.h" +#include "pg_helper.h" + +enum GNUNET_DB_QueryStatus +TMH_PG_insert_token_family (void *cls, + const char *instance_id, + const char *token_family_slug, + const struct TALER_MERCHANTDB_TokenFamilyDetails *details) +{ + struct PostgresClosure *pg = cls; + + const char *kind; + switch (details->kind) + { + case TALER_MERCHANTDB_TFK_Discount: + kind = "discount"; + break; + case TALER_MERCHANTDB_TFK_Subscription: + kind = "subscription"; + default: + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + struct GNUNET_PQ_QueryParam params[] = { + // GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (token_family_slug), + GNUNET_PQ_query_param_string (details->name), + GNUNET_PQ_query_param_string (details->description), + TALER_PQ_query_param_json (details->description_i18n), + GNUNET_PQ_query_param_timestamp (&details->valid_after), + GNUNET_PQ_query_param_timestamp (&details->valid_before), + GNUNET_PQ_query_param_relative_time (&details->duration), + GNUNET_PQ_query_param_string (kind), + GNUNET_PQ_query_param_end + }; + + check_connection (pg); + PREPARE (pg, + "insert_token_family", + "INSERT INTO merchant_token_families" + "(slug" + ",name" + ",description" + ",description_i18n" + ",valid_after" + ",valid_before" + ",duration" + ",kind)" + "VALUES" + "($1, $2, $3, $4, $5, $6, $7, $8)"); + // " FROM merchant_instances" + // " WHERE merchant_id=$1"); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "insert_token_family", + params); +} diff --git a/src/backenddb/pg_insert_token_family.h b/src/backenddb/pg_insert_token_family.h new file mode 100644 index 00000000..e05755a6 --- /dev/null +++ b/src/backenddb/pg_insert_token_family.h @@ -0,0 +1,43 @@ +/* + This file is part of TALER + Copyright (C) 2023 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_token_family.h + * @brief implementation of the insert_token_family function for Postgres + * @author Christian Blättler + */ +#ifndef PG_INSERT_TOKEN_FAMILY_H +#define PG_INSERT_TOKEN_FAMILY_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + + +/** + * @param cls closure + * @param instance_id instance to insert token family for TODO: Is this needed? + * @param token_family_slug slug of the token family to insert + * @param details the token family details to insert + * @return database result code + */ +enum GNUNET_DB_QueryStatus +TMH_PG_insert_token_family (void *cls, + const char *instance_id, + const char *token_family_slug, + const struct TALER_MERCHANTDB_TokenFamilyDetails *details); + +#endif + diff --git a/src/backenddb/pg_lookup_token_family.c b/src/backenddb/pg_lookup_token_family.c new file mode 100644 index 00000000..7a871692 --- /dev/null +++ b/src/backenddb/pg_lookup_token_family.c @@ -0,0 +1,101 @@ +/* + This file is part of TALER + Copyright (C) 2023 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_token_family.c + * @brief Implementation of the lookup_token_family 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_token_family.h" +#include "pg_helper.h" + +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_token_family (void *cls, + const char *instance_id, + const char *token_family_slug, + struct TALER_MERCHANTDB_TokenFamilyDetails *details) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + // GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (token_family_slug), + GNUNET_PQ_query_param_end + }; + + if (NULL == details) + { + struct GNUNET_PQ_ResultSpec rs_null[] = { + GNUNET_PQ_result_spec_end + }; + + check_connection (pg); + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "lookup_token_family", + params, + rs_null); + } + else + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_string ("slug", + &details->slug), + GNUNET_PQ_result_spec_string ("name", + &details->name), + GNUNET_PQ_result_spec_string ("description", + &details->description), + TALER_PQ_result_spec_json ("description_i18n", + &details->description_i18n), + GNUNET_PQ_result_spec_timestamp ("valid_after", + &details->valid_after), + GNUNET_PQ_result_spec_timestamp ("valid_before", + &details->valid_before), + GNUNET_PQ_result_spec_relative_time ("duration", + &details->duration), + // TODO: How to convert kind string into enum TALER_MERCHANTDB_TokenFamilyKind + GNUNET_PQ_result_spec_uint64 ("issued", + &details->issued), + GNUNET_PQ_result_spec_uint64 ("redeemed", + &details->redeemed), + GNUNET_PQ_result_spec_end + }; + + check_connection (pg); + PREPARE (pg, + "lookup_token_family", + "SELECT" + " slug" + ",name" + ",description" + ",description_i18n" + ",valid_after" + ",valid_before" + ",duration" + ",issued" + ",redeemed" + " FROM merchant_token_families" + // " JOIN merchant_instances" + // " USING (merchant_serial)" + // " WHERE merchant_instances.merchant_id=$1" + " WHERE merchant_token_families.slug=$1"); + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "lookup_token_family", + params, + rs); + } +} diff --git a/src/backenddb/pg_lookup_token_family.h b/src/backenddb/pg_lookup_token_family.h new file mode 100644 index 00000000..4a1b1872 --- /dev/null +++ b/src/backenddb/pg_lookup_token_family.h @@ -0,0 +1,44 @@ +/* + This file is part of TALER + Copyright (C) 2023 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_token_family.h + * @brief implementation of the lookup_token_family function for Postgres + * @author Christian Blättler + */ +#ifndef PG_LOOKUP_TOKEN_FAMILY_H +#define PG_LOOKUP_TOKEN_FAMILY_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Lookup details about a particular token family. + * + * @param cls closure + * @param instance_id instance to lookup token family for + * @param token_family_slug token family to lookup + * @param[out] details set to the token family details on success, can be NULL + * (in that case we only want to check if the token family exists) + * @return database result code + */ +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_token_family (void *cls, + const char *instance_id, + const char *token_family_slug, + struct TALER_MERCHANTDB_TokenFamilyDetails *details); + +#endif diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c index 1f1f54c6..90586561 100644 --- a/src/backenddb/plugin_merchantdb_postgres.c +++ b/src/backenddb/plugin_merchantdb_postgres.c @@ -147,6 +147,8 @@ #include "pg_activate_reserve.h" #include "pg_authorize_reward.h" #include "pg_insert_pickup.h" +#include "pg_insert_token_family.h" +#include "pg_lookup_token_family.h" /** @@ -601,6 +603,12 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) = &TMH_PG_select_accounts_by_exchange; plugin->insert_exchange_account = &TMH_PG_insert_exchange_account; + plugin->insert_token_family + = &TMH_PG_insert_token_family; + plugin->lookup_token_family + = &TMH_PG_lookup_token_family; + + return plugin; } diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h index 631cdcd5..c838a175 100644 --- a/src/include/taler_merchantdb_plugin.h +++ b/src/include/taler_merchantdb_plugin.h @@ -255,6 +255,22 @@ typedef void (*TALER_MERCHANTDB_ProductsCallback)(void *cls, const char *product_id); +/** + * Typically called by `lookup_token_families`. + * + * @param cls a `json_t *` JSON array to build + * @param slug slug of the token family + * @param name name of the token family + * @param start_time start time of the token family's validity period + * @param expiration end time of the token family's validity period + */ +typedef void +(*TALER_MERCHANTDB_TokenFamiliesCallback)(void *cls, + const char *slug, + const char *name, + struct GNUNET_TIME_Timestamp start_time, + struct GNUNET_TIME_Timestamp expiration); + /** * Details about a product. @@ -1116,6 +1132,16 @@ struct TALER_MERCHANTDB_TokenFamilyDetails json_t *description_i18n; /** + * Start time of the token family duration. + */ + struct GNUNET_TIME_Timestamp valid_after; + + /** + * End time of the token family duration. + */ + struct GNUNET_TIME_Timestamp valid_before; + + /** * Validity duration of the token family. */ struct GNUNET_TIME_Relative duration; @@ -1166,11 +1192,6 @@ struct TALER_MERCHANTDB_TokenFamilyKeyDetails * Token family private key. */ struct TALER_TokenFamilyPrivateKey priv; - - /** - * Token family key cipher. - */ - // enum TALER_MERCHANTDB_TokenKeyCipher cipher; }; /** @@ -3540,6 +3561,83 @@ struct TALER_MERCHANTDB_Plugin (*insert_exchange_keys)(void *cls, const struct TALER_EXCHANGE_Keys *keys); + + /** + * Lookup all of the token families the given instance has configured. + * + * @param cls closure + * @param instance_id instance to lookup token families for + * @param cb function to call on all token families found + * @param cb_cls closure for @a cb + * @return database result code + */ + enum GNUNET_DB_QueryStatus + (*lookup_token_families)(void *cls, + const char *instance_id, + TALER_MERCHANTDB_TokenFamiliesCallback cb, + void *cb_cls); + + /** + * Lookup details about a particular token family. + * + * @param cls closure + * @param instance_id instance to lookup token family for + * @param token_family_slug token family to lookup + * @param[out] details set to the token family details on success, can be NULL + * (in that case we only want to check if the token family exists) + * @return database result code + */ + enum GNUNET_DB_QueryStatus + (*lookup_token_family)(void *cls, + const char *instance_id, + const char *token_family_slug, + struct TALER_MERCHANTDB_TokenFamilyDetails *details); + + /** + * Delete information about a token family. + * + * @param cls closure + * @param instance_id instance to delete token family of + * @param token_family_slug slug of token family to delete + * @return database result code + */ + enum GNUNET_DB_QueryStatus + (*delete_token_family)(void *cls, + const char *instance_id, + const char *token_family_slug); + + /** + * Update details about a particular token family. + * + * @param cls closure + * @param instance_id instance to update token family for + * @param token_family_slug slug of token family to update + * @param details set to the updated token family on success, can be NULL + * (in that case we only want to check if the token family exists) + * @return database result code + */ + enum GNUNET_DB_QueryStatus + (*update_token_family)(void *cls, + const char *instance_id, + const char *token_family_slug, + const struct TALER_MERCHANTDB_TokenFamilyDetails *details); + + + /** + * Insert details about a particular token family. + * + * @param cls closure + * @param instance_id instance to insert product for + * @param token_family_slug slug of token family to insert + * @param details the token family details to insert + * @return database result code + */ + enum GNUNET_DB_QueryStatus + (*insert_token_family)(void *cls, + const char *instance_id, + const char *token_family_slug, + const struct TALER_MERCHANTDB_TokenFamilyDetails *details); + }; #endif |