LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_private-patch-instances-ID.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 67 117 57.3 %
Date: 2025-08-28 06:06:54 Functions: 2 4 50.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   (C) 2020-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_private-patch-instances-ID.c
      22             :  * @brief implementing PATCH /instances/$ID request handling
      23             :  * @author Christian Grothoff
      24             :  */
      25             : #include "platform.h"
      26             : #include "taler-merchant-httpd_private-patch-instances-ID.h"
      27             : #include "taler-merchant-httpd_helper.h"
      28             : #include <taler/taler_json_lib.h>
      29             : #include <taler/taler_dbevents.h>
      30             : 
      31             : 
      32             : /**
      33             :  * How often do we retry the simple INSERT database transaction?
      34             :  */
      35             : #define MAX_RETRIES 3
      36             : 
      37             : 
      38             : /**
      39             :  * Free memory used by @a wm
      40             :  *
      41             :  * @param wm wire method to free
      42             :  */
      43             : static void
      44           0 : free_wm (struct TMH_WireMethod *wm)
      45             : {
      46           0 :   GNUNET_free (wm->payto_uri.full_payto);
      47           0 :   GNUNET_free (wm->wire_method);
      48           0 :   GNUNET_free (wm);
      49           0 : }
      50             : 
      51             : 
      52             : /**
      53             :  * PATCH configuration of an existing instance, given its configuration.
      54             :  *
      55             :  * @param mi instance to patch
      56             :  * @param connection the MHD connection to handle
      57             :  * @param[in,out] hc context with further information about the request
      58             :  * @return MHD result code
      59             :  */
      60             : static MHD_RESULT
      61           4 : patch_instances_ID (struct TMH_MerchantInstance *mi,
      62             :                     struct MHD_Connection *connection,
      63             :                     struct TMH_HandlerContext *hc)
      64             : {
      65             :   struct TALER_MERCHANTDB_InstanceSettings is;
      66             :   const char *name;
      67           4 :   struct TMH_WireMethod *wm_head = NULL;
      68           4 :   struct TMH_WireMethod *wm_tail = NULL;
      69             :   struct GNUNET_JSON_Specification spec[] = {
      70           4 :     GNUNET_JSON_spec_string ("name",
      71             :                              &name),
      72           4 :     GNUNET_JSON_spec_mark_optional (
      73             :       GNUNET_JSON_spec_string ("website",
      74             :                                (const char **) &is.website),
      75             :       NULL),
      76           4 :     GNUNET_JSON_spec_mark_optional (
      77             :       GNUNET_JSON_spec_string ("email",
      78             :                                (const char **) &is.email),
      79             :       NULL),
      80           4 :     GNUNET_JSON_spec_mark_optional (
      81             :       GNUNET_JSON_spec_string ("phone_number",
      82             :                                (const char **) &is.phone),
      83             :       NULL),
      84           4 :     GNUNET_JSON_spec_mark_optional (
      85             :       GNUNET_JSON_spec_string ("logo",
      86             :                                (const char **) &is.logo),
      87             :       NULL),
      88           4 :     GNUNET_JSON_spec_json ("address",
      89             :                            &is.address),
      90           4 :     GNUNET_JSON_spec_json ("jurisdiction",
      91             :                            &is.jurisdiction),
      92           4 :     GNUNET_JSON_spec_bool ("use_stefan",
      93             :                            &is.use_stefan),
      94           4 :     GNUNET_JSON_spec_relative_time ("default_wire_transfer_delay",
      95             :                                     &is.default_wire_transfer_delay),
      96           4 :     GNUNET_JSON_spec_relative_time ("default_pay_delay",
      97             :                                     &is.default_pay_delay),
      98           4 :     GNUNET_JSON_spec_end ()
      99             :   };
     100             :   enum GNUNET_DB_QueryStatus qs;
     101             : 
     102           4 :   GNUNET_assert (NULL != mi);
     103           4 :   memset (&is,
     104             :           0,
     105             :           sizeof (is));
     106             :   {
     107             :     enum GNUNET_GenericReturnValue res;
     108             : 
     109           4 :     res = TALER_MHD_parse_json_data (connection,
     110           4 :                                      hc->request_body,
     111             :                                      spec);
     112           4 :     if (GNUNET_OK != res)
     113             :       return (GNUNET_NO == res)
     114             :              ? MHD_YES
     115           0 :              : MHD_NO;
     116             :   }
     117           4 :   if (! TMH_location_object_valid (is.address))
     118             :   {
     119           0 :     GNUNET_break_op (0);
     120           0 :     GNUNET_JSON_parse_free (spec);
     121           0 :     return TALER_MHD_reply_with_error (connection,
     122             :                                        MHD_HTTP_BAD_REQUEST,
     123             :                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
     124             :                                        "address");
     125             :   }
     126           4 :   if ( (NULL != is.logo) &&
     127           0 :        (! TMH_image_data_url_valid (is.logo)) )
     128             :   {
     129           0 :     GNUNET_break_op (0);
     130           0 :     GNUNET_JSON_parse_free (spec);
     131           0 :     return TALER_MHD_reply_with_error (connection,
     132             :                                        MHD_HTTP_BAD_REQUEST,
     133             :                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
     134             :                                        "logo");
     135             :   }
     136             : 
     137           4 :   if (! TMH_location_object_valid (is.jurisdiction))
     138             :   {
     139           0 :     GNUNET_break_op (0);
     140           0 :     GNUNET_JSON_parse_free (spec);
     141           0 :     return TALER_MHD_reply_with_error (connection,
     142             :                                        MHD_HTTP_BAD_REQUEST,
     143             :                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
     144             :                                        "jurisdiction");
     145             :   }
     146             : 
     147           4 :   for (unsigned int retry = 0; retry<MAX_RETRIES; retry++)
     148             :   {
     149             :     /* Cleanup after earlier loops */
     150             :     {
     151             :       struct TMH_WireMethod *wm;
     152             : 
     153           4 :       while (NULL != (wm = wm_head))
     154             :       {
     155           0 :         GNUNET_CONTAINER_DLL_remove (wm_head,
     156             :                                      wm_tail,
     157             :                                      wm);
     158           0 :         free_wm (wm);
     159             :       }
     160             :     }
     161           4 :     if (GNUNET_OK !=
     162           4 :         TMH_db->start (TMH_db->cls,
     163             :                        "PATCH /instances"))
     164             :     {
     165           0 :       GNUNET_JSON_parse_free (spec);
     166           0 :       return TALER_MHD_reply_with_error (connection,
     167             :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
     168             :                                          TALER_EC_GENERIC_DB_START_FAILED,
     169             :                                          NULL);
     170             :     }
     171             :     /* Check for equality of settings */
     172           4 :     if (! ( (0 == strcmp (mi->settings.name,
     173           2 :                           name)) &&
     174           2 :             ((mi->settings.email == is.email) ||
     175           0 :              (NULL != is.email && NULL != mi->settings.email &&
     176           0 :               0 == strcmp (mi->settings.email,
     177           0 :                            is.email))) &&
     178           2 :             ((mi->settings.website == is.website) ||
     179           0 :              (NULL != is.website && NULL != mi->settings.website &&
     180           0 :               0 == strcmp (mi->settings.website,
     181           0 :                            is.website))) &&
     182           2 :             ((mi->settings.logo == is.logo) ||
     183           0 :              (NULL != is.logo && NULL != mi->settings.logo &&
     184           0 :               0 == strcmp (mi->settings.logo,
     185           2 :                            is.logo))) &&
     186           2 :             (1 == json_equal (mi->settings.address,
     187           2 :                               is.address)) &&
     188           0 :             (1 == json_equal (mi->settings.jurisdiction,
     189           0 :                               is.jurisdiction)) &&
     190           0 :             (mi->settings.use_stefan == is.use_stefan) &&
     191           0 :             (GNUNET_TIME_relative_cmp (mi->settings.default_wire_transfer_delay,
     192             :                                        ==,
     193             :                                        is.default_wire_transfer_delay)) &&
     194           0 :             (GNUNET_TIME_relative_cmp (mi->settings.default_pay_delay,
     195             :                                        ==,
     196             :                                        is.default_pay_delay)) ) )
     197             :     {
     198           4 :       is.id = mi->settings.id;
     199           4 :       is.name = GNUNET_strdup (name);
     200           4 :       qs = TMH_db->update_instance (TMH_db->cls,
     201             :                                     &is);
     202           4 :       GNUNET_free (is.name);
     203           4 :       if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
     204             :       {
     205           0 :         TMH_db->rollback (TMH_db->cls);
     206           0 :         if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     207           0 :           goto retry;
     208             :         else
     209           0 :           goto giveup;
     210             :       }
     211             :     }
     212           4 :     qs = TMH_db->commit (TMH_db->cls);
     213           4 : retry:
     214           4 :     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     215           0 :       continue;
     216           4 :     break;
     217             :   } /* for(... MAX_RETRIES) */
     218           0 : giveup:
     219             :   /* Update our 'settings' */
     220           4 :   GNUNET_free (mi->settings.name);
     221           4 :   GNUNET_free (mi->settings.email);
     222           4 :   GNUNET_free (mi->settings.phone);
     223           4 :   GNUNET_free (mi->settings.website);
     224           4 :   GNUNET_free (mi->settings.logo);
     225           4 :   json_decref (mi->settings.address);
     226           4 :   json_decref (mi->settings.jurisdiction);
     227           4 :   is.id = mi->settings.id;
     228           4 :   mi->settings = is;
     229           4 :   mi->settings.address = json_incref (mi->settings.address);
     230           4 :   mi->settings.jurisdiction = json_incref (mi->settings.jurisdiction);
     231           4 :   mi->settings.name = GNUNET_strdup (name);
     232           4 :   if (NULL != is.email)
     233           0 :     mi->settings.email = GNUNET_strdup (is.email);
     234           4 :   if (NULL != is.phone)
     235           0 :     mi->settings.phone = GNUNET_strdup (is.phone);
     236           4 :   if (NULL != is.website)
     237           0 :     mi->settings.website = GNUNET_strdup (is.website);
     238           4 :   if (NULL != is.logo)
     239           0 :     mi->settings.logo = GNUNET_strdup (is.logo);
     240             : 
     241           4 :   GNUNET_JSON_parse_free (spec);
     242           4 :   TMH_reload_instances (mi->settings.id);
     243           4 :   return TALER_MHD_reply_static (connection,
     244             :                                  MHD_HTTP_NO_CONTENT,
     245             :                                  NULL,
     246             :                                  NULL,
     247             :                                  0);
     248             : }
     249             : 
     250             : 
     251             : MHD_RESULT
     252           0 : TMH_private_patch_instances_ID (const struct TMH_RequestHandler *rh,
     253             :                                 struct MHD_Connection *connection,
     254             :                                 struct TMH_HandlerContext *hc)
     255             : {
     256           0 :   struct TMH_MerchantInstance *mi = hc->instance;
     257             : 
     258           0 :   return patch_instances_ID (mi,
     259             :                              connection,
     260             :                              hc);
     261             : }
     262             : 
     263             : 
     264             : MHD_RESULT
     265           4 : TMH_private_patch_instances_default_ID (const struct TMH_RequestHandler *rh,
     266             :                                         struct MHD_Connection *connection,
     267             :                                         struct TMH_HandlerContext *hc)
     268             : {
     269             :   struct TMH_MerchantInstance *mi;
     270             : 
     271           4 :   mi = TMH_lookup_instance (hc->infix);
     272           4 :   if (NULL == mi)
     273             :   {
     274           0 :     return TALER_MHD_reply_with_error (connection,
     275             :                                        MHD_HTTP_NOT_FOUND,
     276             :                                        TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN,
     277           0 :                                        hc->infix);
     278             :   }
     279           4 :   if (mi->deleted)
     280             :   {
     281           0 :     return TALER_MHD_reply_with_error (connection,
     282             :                                        MHD_HTTP_CONFLICT,
     283             :                                        TALER_EC_MERCHANT_PRIVATE_PATCH_INSTANCES_PURGE_REQUIRED,
     284           0 :                                        hc->infix);
     285             :   }
     286           4 :   return patch_instances_ID (mi,
     287             :                              connection,
     288             :                              hc);
     289             : }
     290             : 
     291             : 
     292             : /* end of taler-merchant-httpd_private-patch-instances-ID.c */

Generated by: LCOV version 1.16