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

Generated by: LCOV version 2.0-1