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

          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 1.16