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: 64 113 56.6 %
Date: 2025-06-23 16:22:09 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 ("logo",
      82             :                                (const char **) &is.logo),
      83             :       NULL),
      84           4 :     GNUNET_JSON_spec_json ("address",
      85             :                            &is.address),
      86           4 :     GNUNET_JSON_spec_json ("jurisdiction",
      87             :                            &is.jurisdiction),
      88           4 :     GNUNET_JSON_spec_bool ("use_stefan",
      89             :                            &is.use_stefan),
      90           4 :     GNUNET_JSON_spec_relative_time ("default_wire_transfer_delay",
      91             :                                     &is.default_wire_transfer_delay),
      92           4 :     GNUNET_JSON_spec_relative_time ("default_pay_delay",
      93             :                                     &is.default_pay_delay),
      94           4 :     GNUNET_JSON_spec_end ()
      95             :   };
      96             :   enum GNUNET_DB_QueryStatus qs;
      97             : 
      98           4 :   GNUNET_assert (NULL != mi);
      99           4 :   memset (&is,
     100             :           0,
     101             :           sizeof (is));
     102             :   {
     103             :     enum GNUNET_GenericReturnValue res;
     104             : 
     105           4 :     res = TALER_MHD_parse_json_data (connection,
     106           4 :                                      hc->request_body,
     107             :                                      spec);
     108           4 :     if (GNUNET_OK != res)
     109             :       return (GNUNET_NO == res)
     110             :              ? MHD_YES
     111           0 :              : MHD_NO;
     112             :   }
     113           4 :   if (! TMH_location_object_valid (is.address))
     114             :   {
     115           0 :     GNUNET_break_op (0);
     116           0 :     GNUNET_JSON_parse_free (spec);
     117           0 :     return TALER_MHD_reply_with_error (connection,
     118             :                                        MHD_HTTP_BAD_REQUEST,
     119             :                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
     120             :                                        "address");
     121             :   }
     122           4 :   if ( (NULL != is.logo) &&
     123           0 :        (! TMH_image_data_url_valid (is.logo)) )
     124             :   {
     125           0 :     GNUNET_break_op (0);
     126           0 :     GNUNET_JSON_parse_free (spec);
     127           0 :     return TALER_MHD_reply_with_error (connection,
     128             :                                        MHD_HTTP_BAD_REQUEST,
     129             :                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
     130             :                                        "logo");
     131             :   }
     132             : 
     133           4 :   if (! TMH_location_object_valid (is.jurisdiction))
     134             :   {
     135           0 :     GNUNET_break_op (0);
     136           0 :     GNUNET_JSON_parse_free (spec);
     137           0 :     return TALER_MHD_reply_with_error (connection,
     138             :                                        MHD_HTTP_BAD_REQUEST,
     139             :                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
     140             :                                        "jurisdiction");
     141             :   }
     142             : 
     143           4 :   for (unsigned int retry = 0; retry<MAX_RETRIES; retry++)
     144             :   {
     145             :     /* Cleanup after earlier loops */
     146             :     {
     147             :       struct TMH_WireMethod *wm;
     148             : 
     149           4 :       while (NULL != (wm = wm_head))
     150             :       {
     151           0 :         GNUNET_CONTAINER_DLL_remove (wm_head,
     152             :                                      wm_tail,
     153             :                                      wm);
     154           0 :         free_wm (wm);
     155             :       }
     156             :     }
     157           4 :     if (GNUNET_OK !=
     158           4 :         TMH_db->start (TMH_db->cls,
     159             :                        "PATCH /instances"))
     160             :     {
     161           0 :       GNUNET_JSON_parse_free (spec);
     162           0 :       return TALER_MHD_reply_with_error (connection,
     163             :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
     164             :                                          TALER_EC_GENERIC_DB_START_FAILED,
     165             :                                          NULL);
     166             :     }
     167             :     /* Check for equality of settings */
     168           4 :     if (! ( (0 == strcmp (mi->settings.name,
     169           2 :                           name)) &&
     170           2 :             ((mi->settings.email == is.email) ||
     171           0 :              (NULL != is.email && NULL != mi->settings.email &&
     172           0 :               0 == strcmp (mi->settings.email,
     173           0 :                            is.email))) &&
     174           2 :             ((mi->settings.website == is.website) ||
     175           0 :              (NULL != is.website && NULL != mi->settings.website &&
     176           0 :               0 == strcmp (mi->settings.website,
     177           0 :                            is.website))) &&
     178           2 :             ((mi->settings.logo == is.logo) ||
     179           0 :              (NULL != is.logo && NULL != mi->settings.logo &&
     180           0 :               0 == strcmp (mi->settings.logo,
     181           2 :                            is.logo))) &&
     182           2 :             (1 == json_equal (mi->settings.address,
     183           2 :                               is.address)) &&
     184           0 :             (1 == json_equal (mi->settings.jurisdiction,
     185           0 :                               is.jurisdiction)) &&
     186           0 :             (mi->settings.use_stefan == is.use_stefan) &&
     187           0 :             (GNUNET_TIME_relative_cmp (mi->settings.default_wire_transfer_delay,
     188             :                                        ==,
     189             :                                        is.default_wire_transfer_delay)) &&
     190           0 :             (GNUNET_TIME_relative_cmp (mi->settings.default_pay_delay,
     191             :                                        ==,
     192             :                                        is.default_pay_delay)) ) )
     193             :     {
     194           4 :       is.id = mi->settings.id;
     195           4 :       is.name = GNUNET_strdup (name);
     196           4 :       qs = TMH_db->update_instance (TMH_db->cls,
     197             :                                     &is);
     198           4 :       GNUNET_free (is.name);
     199           4 :       if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
     200             :       {
     201           0 :         TMH_db->rollback (TMH_db->cls);
     202           0 :         if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     203           0 :           goto retry;
     204             :         else
     205           0 :           goto giveup;
     206             :       }
     207             :     }
     208           4 :     qs = TMH_db->commit (TMH_db->cls);
     209           4 : retry:
     210           4 :     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     211           0 :       continue;
     212           4 :     break;
     213             :   } /* for(... MAX_RETRIES) */
     214           0 : giveup:
     215             :   /* Update our 'settings' */
     216           4 :   GNUNET_free (mi->settings.name);
     217           4 :   GNUNET_free (mi->settings.email);
     218           4 :   GNUNET_free (mi->settings.website);
     219           4 :   GNUNET_free (mi->settings.logo);
     220           4 :   json_decref (mi->settings.address);
     221           4 :   json_decref (mi->settings.jurisdiction);
     222           4 :   is.id = mi->settings.id;
     223           4 :   mi->settings = is;
     224           4 :   mi->settings.address = json_incref (mi->settings.address);
     225           4 :   mi->settings.jurisdiction = json_incref (mi->settings.jurisdiction);
     226           4 :   mi->settings.name = GNUNET_strdup (name);
     227           4 :   if (NULL != is.email)
     228           0 :     mi->settings.email = GNUNET_strdup (is.email);
     229           4 :   if (NULL != is.website)
     230           0 :     mi->settings.website = GNUNET_strdup (is.website);
     231           4 :   if (NULL != is.logo)
     232           0 :     mi->settings.logo = GNUNET_strdup (is.logo);
     233             : 
     234           4 :   GNUNET_JSON_parse_free (spec);
     235           4 :   TMH_reload_instances (mi->settings.id);
     236           4 :   return TALER_MHD_reply_static (connection,
     237             :                                  MHD_HTTP_NO_CONTENT,
     238             :                                  NULL,
     239             :                                  NULL,
     240             :                                  0);
     241             : }
     242             : 
     243             : 
     244             : MHD_RESULT
     245           0 : TMH_private_patch_instances_ID (const struct TMH_RequestHandler *rh,
     246             :                                 struct MHD_Connection *connection,
     247             :                                 struct TMH_HandlerContext *hc)
     248             : {
     249           0 :   struct TMH_MerchantInstance *mi = hc->instance;
     250             : 
     251           0 :   return patch_instances_ID (mi,
     252             :                              connection,
     253             :                              hc);
     254             : }
     255             : 
     256             : 
     257             : MHD_RESULT
     258           4 : TMH_private_patch_instances_default_ID (const struct TMH_RequestHandler *rh,
     259             :                                         struct MHD_Connection *connection,
     260             :                                         struct TMH_HandlerContext *hc)
     261             : {
     262             :   struct TMH_MerchantInstance *mi;
     263             : 
     264           4 :   mi = TMH_lookup_instance (hc->infix);
     265           4 :   if (NULL == mi)
     266             :   {
     267           0 :     return TALER_MHD_reply_with_error (connection,
     268             :                                        MHD_HTTP_NOT_FOUND,
     269             :                                        TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN,
     270           0 :                                        hc->infix);
     271             :   }
     272           4 :   if (mi->deleted)
     273             :   {
     274           0 :     return TALER_MHD_reply_with_error (connection,
     275             :                                        MHD_HTTP_CONFLICT,
     276             :                                        TALER_EC_MERCHANT_PRIVATE_PATCH_INSTANCES_PURGE_REQUIRED,
     277           0 :                                        hc->infix);
     278             :   }
     279           4 :   return patch_instances_ID (mi,
     280             :                              connection,
     281             :                              hc);
     282             : }
     283             : 
     284             : 
     285             : /* end of taler-merchant-httpd_private-patch-instances-ID.c */

Generated by: LCOV version 1.16