merchant

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

taler-merchant-httpd_private-post-categories.c (5717B)


      1 /*
      2   This file is part of TALER
      3   (C) 2024 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU Affero General Public License as
      7   published by the Free Software Foundation; either version 3,
      8   or (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful, but
     11   WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14 
     15   You should have received a copy of the GNU General Public
     16   License along with TALER; see the file COPYING.  If not,
     17   see <http://www.gnu.org/licenses/>
     18 */
     19 /**
     20  * @file taler-merchant-httpd_private-post-categories.c
     21  * @brief implementing POST /private/categories request handling
     22  * @author Christian Grothoff
     23  */
     24 #include "platform.h"
     25 #include "taler-merchant-httpd_private-post-categories.h"
     26 #include "taler-merchant-httpd_helper.h"
     27 #include <taler/taler_json_lib.h>
     28 
     29 
     30 /**
     31  * How often do we retry the simple INSERT database transaction?
     32  */
     33 #define MAX_RETRIES 3
     34 
     35 
     36 MHD_RESULT
     37 TMH_private_post_categories (const struct TMH_RequestHandler *rh,
     38                              struct MHD_Connection *connection,
     39                              struct TMH_HandlerContext *hc)
     40 {
     41   struct TMH_MerchantInstance *mi = hc->instance;
     42   const char *category_name;
     43   const json_t *category_name_i18n;
     44   uint64_t category_id;
     45   struct GNUNET_JSON_Specification spec[] = {
     46     GNUNET_JSON_spec_string ("name",
     47                              &category_name),
     48     GNUNET_JSON_spec_object_const ("name_i18n",
     49                                    &category_name_i18n),
     50     GNUNET_JSON_spec_end ()
     51   };
     52   enum GNUNET_DB_QueryStatus qs;
     53 
     54   GNUNET_assert (NULL != mi);
     55   {
     56     enum GNUNET_GenericReturnValue res;
     57 
     58     res = TALER_MHD_parse_json_data (connection,
     59                                      hc->request_body,
     60                                      spec);
     61     if (GNUNET_OK != res)
     62     {
     63       GNUNET_break_op (0);
     64       return (GNUNET_NO == res)
     65              ? MHD_YES
     66              : MHD_NO;
     67     }
     68   }
     69 
     70   /* finally, interact with DB until no serialization error */
     71   for (unsigned int i = 0; i<MAX_RETRIES; i++)
     72   {
     73     json_t *xcategory_name_i18n;
     74 
     75     if (GNUNET_OK !=
     76         TMH_db->start (TMH_db->cls,
     77                        "POST /categories"))
     78     {
     79       GNUNET_break (0);
     80       GNUNET_JSON_parse_free (spec);
     81       return TALER_MHD_reply_with_error (connection,
     82                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
     83                                          TALER_EC_GENERIC_DB_START_FAILED,
     84                                          NULL);
     85     }
     86     qs = TMH_db->select_category_by_name (TMH_db->cls,
     87                                           mi->settings.id,
     88                                           category_name,
     89                                           &xcategory_name_i18n,
     90                                           &category_id);
     91     switch (qs)
     92     {
     93     case GNUNET_DB_STATUS_HARD_ERROR:
     94       /* Clean up and fail hard */
     95       GNUNET_break (0);
     96       TMH_db->rollback (TMH_db->cls);
     97       GNUNET_JSON_parse_free (spec);
     98       return TALER_MHD_reply_with_error (connection,
     99                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    100                                          TALER_EC_GENERIC_DB_FETCH_FAILED,
    101                                          NULL);
    102     case GNUNET_DB_STATUS_SOFT_ERROR:
    103       /* restart transaction */
    104       goto retry;
    105     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    106       /* Good, we can proceed! */
    107       break;
    108     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    109       /* idempotency check: is etp == tp? */
    110       {
    111         bool eq;
    112 
    113         eq = (1 == json_equal (xcategory_name_i18n,
    114                                category_name_i18n));
    115         json_decref (xcategory_name_i18n);
    116         TMH_db->rollback (TMH_db->cls);
    117         GNUNET_JSON_parse_free (spec);
    118         return eq
    119           ? TALER_MHD_REPLY_JSON_PACK (connection,
    120                                        MHD_HTTP_OK,
    121                                        GNUNET_JSON_pack_uint64 ("category_id",
    122                                                                 category_id))
    123           : TALER_MHD_reply_with_error (connection,
    124                                         MHD_HTTP_CONFLICT,
    125                                         TALER_EC_MERCHANT_PRIVATE_POST_CATEGORIES_CONFLICT_CATEGORY_EXISTS,
    126                                         category_name);
    127       }
    128     } /* end switch (qs) */
    129 
    130     qs = TMH_db->insert_category (TMH_db->cls,
    131                                   mi->settings.id,
    132                                   category_name,
    133                                   category_name_i18n,
    134                                   &category_id);
    135     if (GNUNET_DB_STATUS_HARD_ERROR == qs)
    136     {
    137       TMH_db->rollback (TMH_db->cls);
    138       break;
    139     }
    140     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
    141     {
    142       qs = TMH_db->commit (TMH_db->cls);
    143       if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
    144         break;
    145     }
    146 retry:
    147     GNUNET_assert (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    148     TMH_db->rollback (TMH_db->cls);
    149   } /* for RETRIES loop */
    150   GNUNET_JSON_parse_free (spec);
    151   if (qs < 0)
    152   {
    153     GNUNET_break (0);
    154     return TALER_MHD_reply_with_error (
    155       connection,
    156       MHD_HTTP_INTERNAL_SERVER_ERROR,
    157       (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    158       ? TALER_EC_GENERIC_DB_SOFT_FAILURE
    159       : TALER_EC_GENERIC_DB_COMMIT_FAILED,
    160       NULL);
    161   }
    162   return TALER_MHD_REPLY_JSON_PACK (
    163     connection,
    164     MHD_HTTP_OK,
    165     GNUNET_JSON_pack_uint64 ("category_id",
    166                              category_id));
    167 }
    168 
    169 
    170 /* end of taler-merchant-httpd_private-post-categories.c */