LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_post-using-templates.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 66 85 77.6 %
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-2023 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_post-using-templates.c
      22             :  * @brief implementing POST /using-templates request handling
      23             :  * @author Priscilla HUANG
      24             :  * @author Christian Grothoff
      25             :  */
      26             : #include "platform.h"
      27             : #include "taler-merchant-httpd_post-using-templates.h"
      28             : #include "taler-merchant-httpd_private-post-orders.h"
      29             : #include "taler-merchant-httpd_helper.h"
      30             : #include <taler/taler_json_lib.h>
      31             : 
      32             : 
      33             : /**
      34             :  * Our context.
      35             :  */
      36             : struct UseContext
      37             : {
      38             :   /**
      39             :    * Internal handler context we are passing into the
      40             :    * POST /private/orders handler.
      41             :    */
      42             :   struct TMH_HandlerContext ihc;
      43             : 
      44             :   /**
      45             :    * Our template details from the DB.
      46             :    */
      47             :   struct TALER_MERCHANTDB_TemplateDetails etp;
      48             : 
      49             :   /**
      50             :    * True once @e etp was initialized.
      51             :    */
      52             :   bool have_etp;
      53             : };
      54             : 
      55             : 
      56             : /**
      57             :  * Clean up a `struct UseContext *`
      58             :  *
      59             :  * @param cls a `struct UseContext *`
      60             :  */
      61             : static void
      62          14 : cleanup_use_context (void *cls)
      63             : {
      64          14 :   struct UseContext *uc = cls;
      65             : 
      66          14 :   TALER_MERCHANTDB_template_details_free (&uc->etp);
      67          14 :   if (NULL != uc->ihc.cc)
      68           4 :     uc->ihc.cc (uc->ihc.ctx);
      69          14 :   json_decref (uc->ihc.request_body);
      70          14 :   GNUNET_free (uc);
      71          14 : }
      72             : 
      73             : 
      74             : MHD_RESULT
      75          18 : TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh,
      76             :                              struct MHD_Connection *connection,
      77             :                              struct TMH_HandlerContext *hc)
      78             : {
      79          18 :   struct TMH_MerchantInstance *mi = hc->instance;
      80          18 :   const char *template_id = hc->infix;
      81          18 :   const char *summary = NULL;
      82          18 :   const char *fulfillment_url = NULL;
      83          18 :   const char *fulfillment_message = NULL;
      84             :   struct TALER_Amount amount;
      85             :   bool no_amount;
      86             :   bool no_summary;
      87             :   struct GNUNET_JSON_Specification spec[] = {
      88          18 :     GNUNET_JSON_spec_mark_optional (
      89             :       GNUNET_JSON_spec_string ("summary",
      90             :                                &summary),
      91             :       NULL),
      92          18 :     GNUNET_JSON_spec_mark_optional (
      93             :       TALER_JSON_spec_amount_any ("amount",
      94             :                                   &amount),
      95             :       &no_amount),
      96          18 :     GNUNET_JSON_spec_end ()
      97             :   };
      98          18 :   struct UseContext *uc = hc->ctx;
      99             : 
     100          18 :   if (NULL == uc)
     101             :   {
     102          14 :     uc = GNUNET_new (struct UseContext);
     103          14 :     hc->ctx = uc;
     104          14 :     hc->cc = &cleanup_use_context;
     105          14 :     uc->ihc.instance = hc->instance;
     106             :   }
     107             : 
     108             :   {
     109             :     enum GNUNET_GenericReturnValue res;
     110             : 
     111          18 :     res = TALER_MHD_parse_json_data (connection,
     112          18 :                                      hc->request_body,
     113             :                                      spec);
     114          18 :     if (GNUNET_OK != res)
     115             :     {
     116           0 :       GNUNET_break_op (0);
     117             :       return (GNUNET_NO == res)
     118             :              ? MHD_YES
     119           0 :              : MHD_NO;
     120             :     }
     121             :   }
     122             : 
     123          18 :   if (! uc->have_etp)
     124             :   {
     125             :     enum GNUNET_DB_QueryStatus qs;
     126             : 
     127          14 :     qs = TMH_db->lookup_template (TMH_db->cls,
     128          14 :                                   mi->settings.id,
     129             :                                   template_id,
     130             :                                   &uc->etp);
     131          14 :     switch (qs)
     132             :     {
     133           0 :     case GNUNET_DB_STATUS_HARD_ERROR:
     134             :       /* Clean up and fail hard */
     135           0 :       GNUNET_break (0);
     136           0 :       GNUNET_JSON_parse_free (spec);
     137           0 :       return TALER_MHD_reply_with_error (
     138             :         connection,
     139             :         MHD_HTTP_INTERNAL_SERVER_ERROR,
     140             :         TALER_EC_GENERIC_DB_FETCH_FAILED,
     141             :         NULL);
     142           0 :     case GNUNET_DB_STATUS_SOFT_ERROR:
     143             :       /* this should be impossible (single select) */
     144           0 :       GNUNET_break (0);
     145           0 :       GNUNET_JSON_parse_free (spec);
     146           0 :       return TALER_MHD_reply_with_error (
     147             :         connection,
     148             :         MHD_HTTP_INTERNAL_SERVER_ERROR,
     149             :         TALER_EC_GENERIC_DB_FETCH_FAILED,
     150             :         NULL);
     151           2 :     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     152             :       /* template not found! */
     153           2 :       GNUNET_JSON_parse_free (spec);
     154           2 :       return TALER_MHD_reply_with_error (
     155             :         connection,
     156             :         MHD_HTTP_NOT_FOUND,
     157             :         TALER_EC_MERCHANT_GENERIC_TEMPLATE_UNKNOWN,
     158             :         template_id);
     159          12 :     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     160             :       /* all good */
     161          12 :       uc->have_etp = true;
     162          12 :       break;
     163             :     } /* End of the switch */
     164             :   }
     165          16 :   if (NULL == uc->ihc.request_body)
     166             :   {
     167             :     /* template */
     168          12 :     const char *tsummary = NULL;
     169          12 :     const char *tcurrency = NULL;
     170             :     uint32_t min_age;
     171             :     struct GNUNET_TIME_Relative pay_duration;
     172             :     struct TALER_Amount tamount;
     173             :     bool no_tamount;
     174             :     struct GNUNET_JSON_Specification tspec[] = {
     175          12 :       GNUNET_JSON_spec_mark_optional (
     176             :         GNUNET_JSON_spec_string ("summary",
     177             :                                  &tsummary),
     178             :         NULL),
     179          12 :       GNUNET_JSON_spec_mark_optional (
     180             :         GNUNET_JSON_spec_string ("currency",
     181             :                                  &tcurrency),
     182             :         NULL),
     183          12 :       GNUNET_JSON_spec_mark_optional (
     184             :         TALER_JSON_spec_amount_any ("amount",
     185             :                                     &tamount),
     186             :         &no_tamount),
     187          12 :       GNUNET_JSON_spec_uint32 ("minimum_age",
     188             :                                &min_age),
     189          12 :       GNUNET_JSON_spec_relative_time ("pay_duration",
     190             :                                       &pay_duration),
     191          12 :       GNUNET_JSON_spec_end ()
     192             :     };
     193             :     json_t *fake_body;
     194             : 
     195             :     {
     196             :       enum GNUNET_GenericReturnValue res;
     197             :       const char *err_name;
     198             :       unsigned int err_line;
     199             : 
     200          12 :       res = GNUNET_JSON_parse (uc->etp.template_contract,
     201             :                                tspec,
     202             :                                &err_name,
     203             :                                &err_line);
     204          12 :       if (GNUNET_OK != res)
     205             :       {
     206           0 :         GNUNET_break (0);
     207           0 :         json_dumpf (uc->etp.template_contract,
     208             :                     stderr,
     209             :                     JSON_INDENT (2));
     210           0 :         GNUNET_JSON_parse_free (spec);
     211           0 :         return TALER_MHD_reply_with_error (
     212             :           connection,
     213             :           MHD_HTTP_INTERNAL_SERVER_ERROR,
     214             :           TALER_EC_GENERIC_DB_FETCH_FAILED,
     215             :           err_name);
     216             :       }
     217             :     }
     218             : 
     219          12 :     if ( (! no_amount) &&
     220          10 :          (! no_tamount) )
     221             :     {
     222           4 :       GNUNET_JSON_parse_free (spec);
     223           4 :       return TALER_MHD_reply_with_error (
     224             :         connection,
     225             :         MHD_HTTP_CONFLICT,
     226             :         TALER_EC_MERCHANT_POST_USING_TEMPLATES_AMOUNT_CONFLICT_TEMPLATES_CONTRACT_AMOUNT,
     227             :         NULL);
     228             :     }
     229             : 
     230           8 :     if ( (! no_amount) &&
     231           6 :          (NULL != tcurrency) &&
     232           0 :          (0 != strcmp (tcurrency,
     233             :                        amount.currency)) )
     234             :     {
     235           0 :       GNUNET_JSON_parse_free (spec);
     236           0 :       return TALER_MHD_reply_with_error (
     237             :         connection,
     238             :         MHD_HTTP_CONFLICT,
     239             :         TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
     240             :         tcurrency);
     241             :     }
     242             : 
     243           8 :     if (no_amount && no_tamount)
     244             :     {
     245           2 :       GNUNET_JSON_parse_free (spec);
     246           2 :       return TALER_MHD_reply_with_error (
     247             :         connection,
     248             :         MHD_HTTP_CONFLICT,
     249             :         TALER_EC_MERCHANT_POST_USING_TEMPLATES_NO_AMOUNT,
     250             :         NULL);
     251             :     }
     252             : 
     253           6 :     if ( (NULL != summary) &&
     254           4 :          (NULL != tsummary) )
     255             :     {
     256           0 :       GNUNET_JSON_parse_free (spec);
     257           0 :       return TALER_MHD_reply_with_error (
     258             :         connection,
     259             :         MHD_HTTP_CONFLICT,
     260             :         TALER_EC_MERCHANT_POST_USING_TEMPLATES_SUMMARY_CONFLICT_TEMPLATES_CONTRACT_SUBJECT,
     261             :         NULL);
     262             :     }
     263             : 
     264           6 :     if ( (NULL == summary) &&
     265           2 :          (NULL == tsummary) )
     266             :     {
     267           2 :       GNUNET_JSON_parse_free (spec);
     268           2 :       return TALER_MHD_reply_with_error (
     269             :         connection,
     270             :         MHD_HTTP_CONFLICT,
     271             :         TALER_EC_MERCHANT_POST_USING_TEMPLATES_NO_SUMMARY,
     272             :         NULL);
     273             :     }
     274           4 :     no_summary = (NULL == summary);
     275           4 :     fake_body = GNUNET_JSON_PACK (
     276             :       GNUNET_JSON_pack_allow_null (
     277             :         GNUNET_JSON_pack_string ("otp_id",
     278             :                                  uc->etp.otp_id)),
     279             :       GNUNET_JSON_pack_object_steal (
     280             :         "order",
     281             :         GNUNET_JSON_PACK (
     282             :           TALER_JSON_pack_amount ("amount",
     283             :                                   no_amount ?
     284             :                                   &tamount :
     285             :                                   &amount),
     286             :           GNUNET_JSON_pack_string ("summary",
     287             :                                    no_summary ?
     288             :                                    tsummary :
     289             :                                    summary),
     290             :           GNUNET_JSON_pack_allow_null (
     291             :             GNUNET_JSON_pack_string (
     292             :               "fulfillment_url",
     293             :               fulfillment_url)),
     294             :           GNUNET_JSON_pack_allow_null (
     295             :             GNUNET_JSON_pack_string (
     296             :               "fulfillment_message",
     297             :               fulfillment_message))
     298             :           ))
     299             :       );
     300           4 :     uc->ihc.request_body = fake_body;
     301             :   }
     302             : 
     303           8 :   return TMH_private_post_orders (
     304             :     NULL,    /* not even used */
     305             :     connection,
     306             :     &uc->ihc);
     307             : }

Generated by: LCOV version 1.16