LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_post-using-templates.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 77.6 % 85 66
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-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 2.0-1