LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_private-post-templates.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 55.9 % 93 52
Test Date: 2025-11-06 19:31:41 Functions: 100.0 % 2 2

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   (C) 2022-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              : /**
      21              :  * @file taler-merchant-httpd_private-post-templates.c
      22              :  * @brief implementing POST /templates request handling
      23              :  * @author Priscilla HUANG
      24              :  */
      25              : #include "platform.h"
      26              : #include "taler-merchant-httpd_private-post-templates.h"
      27              : #include "taler-merchant-httpd_helper.h"
      28              : #include <taler/taler_json_lib.h>
      29              : 
      30              : 
      31              : /**
      32              :  * Check if the two templates are identical.
      33              :  *
      34              :  * @param t1 template to compare
      35              :  * @param t2 other template to compare
      36              :  * @return true if they are 'equal', false if not or of payto_uris is not an array
      37              :  */
      38              : static bool
      39            4 : templates_equal (const struct TALER_MERCHANTDB_TemplateDetails *t1,
      40              :                  const struct TALER_MERCHANTDB_TemplateDetails *t2)
      41              : {
      42            4 :   return ( (0 == strcmp (t1->template_description,
      43            6 :                          t2->template_description)) &&
      44            2 :            ( ( (NULL == t1->otp_id) &&
      45            2 :                (NULL == t2->otp_id) ) ||
      46            0 :              ( (NULL != t1->otp_id) &&
      47            0 :                (NULL != t2->otp_id) &&
      48            0 :                (0 == strcmp (t1->otp_id,
      49            0 :                              t2->otp_id))) ) &&
      50            2 :            ( ( (NULL == t1->editable_defaults) &&
      51            2 :                (NULL == t2->editable_defaults) ) ||
      52            0 :              ( (NULL != t1->editable_defaults) &&
      53            0 :                (NULL != t2->editable_defaults) &&
      54            0 :                (1 == json_equal (t1->editable_defaults,
      55            6 :                                  t2->editable_defaults))) ) &&
      56            2 :            (1 == json_equal (t1->template_contract,
      57            2 :                              t2->template_contract)) );
      58              : }
      59              : 
      60              : 
      61              : MHD_RESULT
      62           12 : TMH_private_post_templates (const struct TMH_RequestHandler *rh,
      63              :                             struct MHD_Connection *connection,
      64              :                             struct TMH_HandlerContext *hc)
      65              : {
      66           12 :   struct TMH_MerchantInstance *mi = hc->instance;
      67           12 :   struct TALER_MERCHANTDB_TemplateDetails tp = { 0 };
      68              :   const char *template_id;
      69              :   enum GNUNET_DB_QueryStatus qs;
      70              :   struct GNUNET_JSON_Specification spec[] = {
      71           12 :     GNUNET_JSON_spec_string ("template_id",
      72              :                              &template_id),
      73           12 :     GNUNET_JSON_spec_string ("template_description",
      74              :                              (const char **) &tp.template_description),
      75           12 :     GNUNET_JSON_spec_mark_optional (
      76              :       GNUNET_JSON_spec_string ("otp_id",
      77              :                                (const char **) &tp.otp_id),
      78              :       NULL),
      79           12 :     GNUNET_JSON_spec_json ("template_contract",
      80              :                            &tp.template_contract),
      81           12 :     GNUNET_JSON_spec_mark_optional (
      82              :       GNUNET_JSON_spec_json ("editable_defaults",
      83              :                              &tp.editable_defaults),
      84              :       NULL),
      85           12 :     GNUNET_JSON_spec_end ()
      86              :   };
      87           12 :   uint64_t otp_serial = 0;
      88              : 
      89           12 :   GNUNET_assert (NULL != mi);
      90              :   {
      91              :     enum GNUNET_GenericReturnValue res;
      92              : 
      93           12 :     res = TALER_MHD_parse_json_data (connection,
      94           12 :                                      hc->request_body,
      95              :                                      spec);
      96           12 :     if (GNUNET_OK != res)
      97              :     {
      98            0 :       GNUNET_break_op (0);
      99              :       return (GNUNET_NO == res)
     100              :              ? MHD_YES
     101            0 :              : MHD_NO;
     102              :     }
     103              :   }
     104           12 :   if (! TMH_template_contract_valid (tp.template_contract))
     105              :   {
     106            0 :     GNUNET_break_op (0);
     107            0 :     json_dumpf (tp.template_contract,
     108              :                 stderr,
     109              :                 JSON_INDENT (2));
     110            0 :     GNUNET_JSON_parse_free (spec);
     111            0 :     return TALER_MHD_reply_with_error (connection,
     112              :                                        MHD_HTTP_BAD_REQUEST,
     113              :                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
     114              :                                        "template_contract");
     115              :   }
     116              : 
     117           12 :   if (NULL != tp.editable_defaults)
     118              :   {
     119              :     const char *key;
     120              :     json_t *val;
     121              : 
     122            0 :     json_object_foreach (tp.editable_defaults, key, val)
     123              :     {
     124            0 :       if (NULL !=
     125            0 :           json_object_get (tp.template_contract,
     126              :                            key))
     127              :       {
     128              :         char *msg;
     129              :         MHD_RESULT ret;
     130              : 
     131            0 :         GNUNET_break_op (0);
     132            0 :         GNUNET_asprintf (&msg,
     133              :                          "editable_defaults::%s conflicts with template_contract",
     134              :                          key);
     135            0 :         GNUNET_JSON_parse_free (spec);
     136            0 :         ret = TALER_MHD_reply_with_error (connection,
     137              :                                           MHD_HTTP_BAD_REQUEST,
     138              :                                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
     139              :                                           msg);
     140            0 :         GNUNET_free (msg);
     141            0 :         return ret;
     142              :       }
     143              :     }
     144              :   }
     145              : 
     146           12 :   if (NULL != tp.otp_id)
     147              :   {
     148            2 :     qs = TMH_db->select_otp_serial (TMH_db->cls,
     149            2 :                                     mi->settings.id,
     150            2 :                                     tp.otp_id,
     151              :                                     &otp_serial);
     152            2 :     switch (qs)
     153              :     {
     154            0 :     case GNUNET_DB_STATUS_HARD_ERROR:
     155              :     case GNUNET_DB_STATUS_SOFT_ERROR:
     156            0 :       GNUNET_break (0);
     157            0 :       GNUNET_JSON_parse_free (spec);
     158            0 :       return TALER_MHD_reply_with_error (connection,
     159              :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
     160              :                                          TALER_EC_GENERIC_DB_STORE_FAILED,
     161              :                                          "select_otp_serial");
     162            0 :     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     163            0 :       GNUNET_JSON_parse_free (spec);
     164            0 :       return TALER_MHD_reply_with_error (connection,
     165              :                                          MHD_HTTP_NOT_FOUND,
     166              :                                          TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN,
     167              :                                          NULL);
     168            2 :     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     169            2 :       break;
     170              :     }
     171              :   }
     172              : 
     173           12 :   qs = TMH_db->insert_template (TMH_db->cls,
     174           12 :                                 mi->settings.id,
     175              :                                 template_id,
     176              :                                 otp_serial,
     177              :                                 &tp);
     178           12 :   switch (qs)
     179              :   {
     180            0 :   case GNUNET_DB_STATUS_HARD_ERROR:
     181              :   case GNUNET_DB_STATUS_SOFT_ERROR:
     182            0 :     GNUNET_break (0);
     183            0 :     GNUNET_JSON_parse_free (spec);
     184            0 :     return TALER_MHD_reply_with_error (connection,
     185              :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     186              :                                        TALER_EC_GENERIC_DB_STORE_FAILED,
     187              :                                        NULL);
     188            8 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     189            8 :     GNUNET_JSON_parse_free (spec);
     190            8 :     return TALER_MHD_reply_static (connection,
     191              :                                    MHD_HTTP_NO_CONTENT,
     192              :                                    NULL,
     193              :                                    NULL,
     194              :                                    0);
     195            4 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     196            4 :     break;
     197              :   }
     198              : 
     199              :   {
     200              :     /* Test if a template of this id is known */
     201              :     struct TALER_MERCHANTDB_TemplateDetails etp;
     202              : 
     203            4 :     qs = TMH_db->lookup_template (TMH_db->cls,
     204            4 :                                   mi->settings.id,
     205              :                                   template_id,
     206              :                                   &etp);
     207            4 :     switch (qs)
     208              :     {
     209            0 :     case GNUNET_DB_STATUS_HARD_ERROR:
     210              :     case GNUNET_DB_STATUS_SOFT_ERROR:
     211              :       /* Clean up and fail hard */
     212            0 :       GNUNET_break (0);
     213            0 :       GNUNET_JSON_parse_free (spec);
     214            0 :       return TALER_MHD_reply_with_error (connection,
     215              :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
     216              :                                          TALER_EC_GENERIC_DB_FETCH_FAILED,
     217              :                                          NULL);
     218            0 :     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     219            0 :       GNUNET_break (0);
     220            0 :       GNUNET_JSON_parse_free (spec);
     221            0 :       return TALER_MHD_reply_with_error (connection,
     222              :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
     223              :                                          TALER_EC_GENERIC_DB_FETCH_FAILED,
     224              :                                          "logic error");
     225            4 :     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     226            4 :       break;
     227              :     }
     228              :     /* idempotency check: is etp == tp? */
     229              :     {
     230              :       bool eq;
     231              : 
     232            4 :       eq = templates_equal (&tp,
     233              :                             &etp);
     234            4 :       TALER_MERCHANTDB_template_details_free (&etp);
     235            4 :       TMH_db->rollback (TMH_db->cls);
     236            4 :       GNUNET_JSON_parse_free (spec);
     237              :       return eq
     238            2 :         ? TALER_MHD_reply_static (connection,
     239              :                                   MHD_HTTP_NO_CONTENT,
     240              :                                   NULL,
     241              :                                   NULL,
     242              :                                   0)
     243            6 :         : TALER_MHD_reply_with_error (connection,
     244              :                                       MHD_HTTP_CONFLICT,
     245              :                                       TALER_EC_MERCHANT_PRIVATE_POST_TEMPLATES_CONFLICT_TEMPLATE_EXISTS,
     246              :                                       template_id);
     247              :     }
     248              :   }
     249              : }
     250              : 
     251              : 
     252              : /* end of taler-merchant-httpd_private-post-templates.c */
        

Generated by: LCOV version 2.0-1