merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

taler-merchant-httpd_post-using-templates.c (8688B)


      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 cleanup_use_context (void *cls)
     63 {
     64   struct UseContext *uc = cls;
     65 
     66   TALER_MERCHANTDB_template_details_free (&uc->etp);
     67   if (NULL != uc->ihc.cc)
     68     uc->ihc.cc (uc->ihc.ctx);
     69   json_decref (uc->ihc.request_body);
     70   GNUNET_free (uc);
     71 }
     72 
     73 
     74 MHD_RESULT
     75 TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh,
     76                              struct MHD_Connection *connection,
     77                              struct TMH_HandlerContext *hc)
     78 {
     79   struct TMH_MerchantInstance *mi = hc->instance;
     80   const char *template_id = hc->infix;
     81   const char *summary = NULL;
     82   const char *fulfillment_url = NULL;
     83   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     GNUNET_JSON_spec_mark_optional (
     89       GNUNET_JSON_spec_string ("summary",
     90                                &summary),
     91       NULL),
     92     GNUNET_JSON_spec_mark_optional (
     93       TALER_JSON_spec_amount_any ("amount",
     94                                   &amount),
     95       &no_amount),
     96     GNUNET_JSON_spec_end ()
     97   };
     98   struct UseContext *uc = hc->ctx;
     99 
    100   if (NULL == uc)
    101   {
    102     uc = GNUNET_new (struct UseContext);
    103     hc->ctx = uc;
    104     hc->cc = &cleanup_use_context;
    105     uc->ihc.instance = hc->instance;
    106   }
    107 
    108   {
    109     enum GNUNET_GenericReturnValue res;
    110 
    111     res = TALER_MHD_parse_json_data (connection,
    112                                      hc->request_body,
    113                                      spec);
    114     if (GNUNET_OK != res)
    115     {
    116       GNUNET_break_op (0);
    117       return (GNUNET_NO == res)
    118              ? MHD_YES
    119              : MHD_NO;
    120     }
    121   }
    122 
    123   if (! uc->have_etp)
    124   {
    125     enum GNUNET_DB_QueryStatus qs;
    126 
    127     qs = TMH_db->lookup_template (TMH_db->cls,
    128                                   mi->settings.id,
    129                                   template_id,
    130                                   &uc->etp);
    131     switch (qs)
    132     {
    133     case GNUNET_DB_STATUS_HARD_ERROR:
    134       /* Clean up and fail hard */
    135       GNUNET_break (0);
    136       GNUNET_JSON_parse_free (spec);
    137       return TALER_MHD_reply_with_error (
    138         connection,
    139         MHD_HTTP_INTERNAL_SERVER_ERROR,
    140         TALER_EC_GENERIC_DB_FETCH_FAILED,
    141         NULL);
    142     case GNUNET_DB_STATUS_SOFT_ERROR:
    143       /* this should be impossible (single select) */
    144       GNUNET_break (0);
    145       GNUNET_JSON_parse_free (spec);
    146       return TALER_MHD_reply_with_error (
    147         connection,
    148         MHD_HTTP_INTERNAL_SERVER_ERROR,
    149         TALER_EC_GENERIC_DB_FETCH_FAILED,
    150         NULL);
    151     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    152       /* template not found! */
    153       GNUNET_JSON_parse_free (spec);
    154       return TALER_MHD_reply_with_error (
    155         connection,
    156         MHD_HTTP_NOT_FOUND,
    157         TALER_EC_MERCHANT_GENERIC_TEMPLATE_UNKNOWN,
    158         template_id);
    159     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    160       /* all good */
    161       uc->have_etp = true;
    162       break;
    163     } /* End of the switch */
    164   }
    165   if (NULL == uc->ihc.request_body)
    166   {
    167     /* template */
    168     const char *tsummary = NULL;
    169     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       GNUNET_JSON_spec_mark_optional (
    176         GNUNET_JSON_spec_string ("summary",
    177                                  &tsummary),
    178         NULL),
    179       GNUNET_JSON_spec_mark_optional (
    180         GNUNET_JSON_spec_string ("currency",
    181                                  &tcurrency),
    182         NULL),
    183       GNUNET_JSON_spec_mark_optional (
    184         TALER_JSON_spec_amount_any ("amount",
    185                                     &tamount),
    186         &no_tamount),
    187       GNUNET_JSON_spec_uint32 ("minimum_age",
    188                                &min_age),
    189       GNUNET_JSON_spec_relative_time ("pay_duration",
    190                                       &pay_duration),
    191       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       res = GNUNET_JSON_parse (uc->etp.template_contract,
    201                                tspec,
    202                                &err_name,
    203                                &err_line);
    204       if (GNUNET_OK != res)
    205       {
    206         GNUNET_break (0);
    207         json_dumpf (uc->etp.template_contract,
    208                     stderr,
    209                     JSON_INDENT (2));
    210         GNUNET_JSON_parse_free (spec);
    211         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     if ( (! no_amount) &&
    220          (! no_tamount) )
    221     {
    222       GNUNET_JSON_parse_free (spec);
    223       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     if ( (! no_amount) &&
    231          (NULL != tcurrency) &&
    232          (0 != strcmp (tcurrency,
    233                        amount.currency)) )
    234     {
    235       GNUNET_JSON_parse_free (spec);
    236       return TALER_MHD_reply_with_error (
    237         connection,
    238         MHD_HTTP_CONFLICT,
    239         TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
    240         tcurrency);
    241     }
    242 
    243     if (no_amount && no_tamount)
    244     {
    245       GNUNET_JSON_parse_free (spec);
    246       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     if ( (NULL != summary) &&
    254          (NULL != tsummary) )
    255     {
    256       GNUNET_JSON_parse_free (spec);
    257       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     if ( (NULL == summary) &&
    265          (NULL == tsummary) )
    266     {
    267       GNUNET_JSON_parse_free (spec);
    268       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     no_summary = (NULL == summary);
    275     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     uc->ihc.request_body = fake_body;
    301   }
    302 
    303   return TMH_private_post_orders (
    304     NULL,    /* not even used */
    305     connection,
    306     &uc->ihc);
    307 }