LCOV - code coverage report
Current view: top level - lib - merchant_api_refund.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 53 76 69.7 %
Date: 2018-07-14 06:17:23 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014, 2015, 2016, 2017 GNUnet e.V. and INRIA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Lesser General Public License as published by the Free Software
       7             :   Foundation; either version 2.1, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Lesser General Public License along with
      14             :   TALER; see the file COPYING.LGPL.  If not, see
      15             :   <http://www.gnu.org/licenses/>
      16             : */
      17             : /**
      18             :  * @file lib/merchant_api_proposal.c
      19             :  * @brief Implementation of the /refund POST and GET
      20             :  * @author Christian Grothoff
      21             :  * @author Marcello Stanisci
      22             :  */
      23             : 
      24             : #include "platform.h"
      25             : #include <curl/curl.h>
      26             : #include <jansson.h>
      27             : #include <microhttpd.h> /* just for HTTP status codes */
      28             : #include <gnunet/gnunet_util_lib.h>
      29             : #include <gnunet/gnunet_curl_lib.h>
      30             : #include "taler_merchant_service.h"
      31             : #include <taler/taler_json_lib.h>
      32             : #include <taler/taler_signatures.h>
      33             : 
      34             : 
      35             : struct TALER_MERCHANT_RefundLookupOperation
      36             : {
      37             :   /**
      38             :    * URL of the request, includes parameters
      39             :    */
      40             :   char *url;
      41             : 
      42             :   /**
      43             :    * Handle of the request
      44             :    */
      45             :   struct GNUNET_CURL_Job *job;
      46             : 
      47             :   /**
      48             :    * Function to call with the response
      49             :    */
      50             :   TALER_MERCHANT_RefundLookupCallback cb;
      51             : 
      52             :   /**
      53             :    * Closure for cb
      54             :    */
      55             :   void *cb_cls;
      56             : 
      57             :   /**
      58             :    * Reference to the execution context
      59             :    */
      60             :   struct GNUNET_CURL_Context *ctx;
      61             : 
      62             : };
      63             : 
      64             : struct TALER_MERCHANT_RefundIncreaseOperation
      65             : {
      66             :   /**
      67             :    * Complete URL where the backend offers /refund
      68             :    */
      69             :   char *url;
      70             : 
      71             :   /**
      72             :    * The request body
      73             :    */
      74             :   char *json_enc;
      75             : 
      76             :   /**
      77             :    * The CURL context to connect to the backend
      78             :    */
      79             :   struct GNUNET_CURL_Context *ctx;
      80             : 
      81             :   /**
      82             :    * The callback to pass the backend response to
      83             :    */
      84             :   TALER_MERCHANT_RefundIncreaseCallback cb;
      85             : 
      86             :   /**
      87             :    * Clasure to pass to the callback
      88             :    */
      89             :   void *cb_cls;
      90             : 
      91             :   /**
      92             :    * Handle for the request
      93             :    */
      94             :   struct GNUNET_CURL_Job *job;
      95             : 
      96             : };
      97             : 
      98             : 
      99             : /**
     100             :  * Callback to process POST /refund response
     101             :  *
     102             :  * @param cls the `struct TALER_MERCHANT_RefundIncreaseOperation`
     103             :  * @param response_code HTTP response code, 0 on error
     104             :  * @param json response body, NULL if not JSON
     105             :  */
     106             : static void
     107           5 : handle_refund_increase_finished (void *cls,
     108             :                                  long response_code,
     109             :                                  const json_t *json)
     110             : {
     111           5 :   struct TALER_MERCHANT_RefundIncreaseOperation *rio = cls;
     112             :   char *error;
     113             :   char *hint;
     114             :   enum TALER_ErrorCode code;
     115             : 
     116           5 :   rio->job = NULL;
     117           5 :   switch (response_code)
     118             :   {
     119             :   case 0:
     120             :     /* Hard error */
     121           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     122             :                 "Backend didn't even return from POST /refund\n");
     123           0 :     return;
     124             : 
     125             :   /* Good to hand everything to the callback, as all
     126             :    * the logic is actually there.  */
     127             :   case MHD_HTTP_OK:
     128             :   case MHD_HTTP_BAD_REQUEST:
     129             :   case MHD_HTTP_NOT_FOUND:
     130           5 :     rio->cb (rio->cb_cls,
     131             :              response_code,
     132             :              TALER_EC_NONE,
     133             :              json);
     134           5 :     break;
     135             :   default:
     136             :     /**
     137             :      * The backend gave response, but it's error, log it.
     138             :      * NOTE that json must be a Taler-specific error object (FIXME,
     139             :      * need a link to error objects at docs)
     140             :      */
     141           0 :     if (-1 == json_unpack
     142             :         ((json_t *) json,
     143             :          "{s:s, s:I, s:s}",
     144             :          "error", &error,
     145             :          "code", &code,
     146             :          "hint", &hint))
     147             :     
     148             :     {
     149           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     150             :                 "/refund failed (HTTP code: %lu), backend did "
     151             :                 "not give a valid error object\n", response_code);
     152           0 :       break;
     153             :     }
     154             : 
     155           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     156             :                 "/refund, error: %s, code: %d, hint: %s\n",
     157             :                 error,
     158             :                 code,
     159             :                 hint);
     160             :   }
     161           5 :   TALER_MERCHANT_refund_increase_cancel (rio);
     162             : }
     163             : 
     164             : /**
     165             :  * Cancel a POST /refund request.
     166             :  *
     167             :  * @param rio the refund increasing operation to cancel
     168             :  */
     169             : void
     170           5 : TALER_MERCHANT_refund_increase_cancel (struct TALER_MERCHANT_RefundIncreaseOperation *rio)
     171             : {
     172           5 :   if (NULL != rio->job)
     173             :   {
     174           0 :     GNUNET_CURL_job_cancel (rio->job);
     175           0 :     rio->job = NULL;
     176             :   }
     177           5 :   GNUNET_free (rio->url);
     178           5 :   GNUNET_free (rio->json_enc);
     179           5 :   GNUNET_free (rio);
     180           5 : }
     181             : 
     182             : /**
     183             :  * Increase the refund associated to a order
     184             :  *
     185             :  * @param ctx the CURL context used to connect to the backend
     186             :  * @param backend_url backend's base URL, including final "/"
     187             :  * @param order_id id of the order whose refund is to be increased
     188             :  * @param refund amount to which increase the refund
     189             :  * @param reason human-readable reason justifying the refund
     190             :  * @param instance id of the merchant instance issuing the request
     191             :  * @param cb callback processing the response from /refund
     192             :  * @param cb_cls closure for cb
     193             :  */
     194             : struct TALER_MERCHANT_RefundIncreaseOperation *
     195           5 : TALER_MERCHANT_refund_increase (struct GNUNET_CURL_Context *ctx,
     196             :                                 const char *backend_url,
     197             :                                 const char *order_id,
     198             :                                 const struct TALER_Amount *refund,
     199             :                                 const char *reason,
     200             :                                 const char *instance,
     201             :                                 TALER_MERCHANT_RefundIncreaseCallback cb,
     202             :                                 void *cb_cls)
     203             : {
     204             :   struct TALER_MERCHANT_RefundIncreaseOperation *rio;
     205             :   json_t *req;
     206             :   CURL *eh;
     207             : 
     208           5 :   rio = GNUNET_new (struct TALER_MERCHANT_RefundIncreaseOperation);
     209           5 :   rio->ctx = ctx;
     210           5 :   rio->cb = cb;
     211           5 :   rio->cb_cls = cb_cls;
     212           5 :   rio->url = TALER_url_join (backend_url, "/refund", NULL);
     213           5 :   req = json_pack ("{s:o, s:s, s:s, s:s}",
     214             :                    "refund", TALER_JSON_from_amount (refund),
     215             :                    "order_id", order_id,
     216             :                    "reason", reason,
     217             :                    "instance", instance);
     218           5 :   eh = curl_easy_init ();
     219           5 :   rio->json_enc = json_dumps (req,
     220             :                               JSON_COMPACT);
     221           5 :   json_decref (req);
     222           5 :   if (NULL == rio->json_enc)
     223             :   {
     224           0 :     GNUNET_break (0);
     225           0 :     GNUNET_free (rio);
     226           0 :     return NULL;
     227             :   }
     228           5 :   GNUNET_assert (CURLE_OK ==
     229             :                  curl_easy_setopt (eh,
     230             :                                    CURLOPT_URL,
     231             :                                    rio->url));
     232           5 :   GNUNET_assert (CURLE_OK ==
     233             :                  curl_easy_setopt (eh,
     234             :                                    CURLOPT_POSTFIELDS,
     235             :                                    rio->json_enc));
     236           5 :   GNUNET_assert (CURLE_OK ==
     237             :                  curl_easy_setopt (eh,
     238             :                                    CURLOPT_POSTFIELDSIZE,
     239             :                                    strlen (rio->json_enc)));
     240           5 :   rio->job = GNUNET_CURL_job_add (ctx,
     241             :                                   eh,
     242             :                                   GNUNET_YES,
     243             :                                   &handle_refund_increase_finished,
     244             :                                   rio);
     245           5 :   return rio;
     246             : }
     247             : 
     248             : 
     249             : /**
     250             :  * Cancel a /refund lookup operation
     251             :  *
     252             :  * @param 
     253             :  */
     254             : void
     255           5 : TALER_MERCHANT_refund_lookup_cancel (struct TALER_MERCHANT_RefundLookupOperation *rlo)
     256             : {
     257           5 :   if (NULL != rlo->job)
     258             :   {
     259           0 :     GNUNET_CURL_job_cancel (rlo->job);
     260           0 :     rlo->job = NULL;
     261             :   }
     262             :   
     263           5 :   GNUNET_free (rlo->url);
     264           5 :   GNUNET_free (rlo);
     265           5 : }
     266             : 
     267             : 
     268             : /**
     269             :  * Process GET /refund response
     270             :  */
     271             : static void
     272           5 : handle_refund_lookup_finished (void *cls,
     273             :                                long response_code,
     274             :                                const json_t *json)
     275             : {
     276           5 :   struct TALER_MERCHANT_RefundLookupOperation *rlo = cls;
     277             :   char *error;
     278             :   enum TALER_ErrorCode code;
     279             : 
     280           5 :   rlo->job = NULL;
     281           5 :   switch (response_code)
     282             :   {
     283             :   case 0:
     284             :     /* Hard error */
     285           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     286             :                 "Backend didn't even return from GET /refund\n");
     287           0 :     return;
     288             : 
     289             :   case MHD_HTTP_OK:
     290             :   case MHD_HTTP_NOT_FOUND:
     291           5 :     rlo->cb (rlo->cb_cls,
     292             :              response_code,
     293             :              TALER_EC_NONE,
     294             :              json);
     295           5 :     break;
     296             :   default:
     297             :     /**
     298             :      * The backend gave response, but it's error, log it.
     299             :      * NOTE that json must be a Taler-specific error object (FIXME,
     300             :      * need a link to error objects at docs)
     301             :      */
     302           0 :     if (-1 == json_unpack ((json_t *) json,
     303             :         "{s:s, s:I, s:s}",
     304             :         "error", &error,
     305             :         "code", &code))
     306             :     {
     307           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     308             :                   "Failed GET /refund, error: %s, code: %d\n",
     309             :                   error,
     310             :                   code);
     311           0 :       break;
     312             :     } 
     313           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     314             :                 "Failed /refund lookup, backend did not give"
     315             :                 " a valid error object, HTTP code was %lu\n",
     316             :                 response_code);
     317             :   }
     318             : 
     319           5 :   TALER_MERCHANT_refund_lookup_cancel (rlo);
     320             : }
     321             : 
     322             : 
     323             : /**
     324             :  * Does a GET /refund.
     325             :  *
     326             :  * @param ctx execution context
     327             :  * @param backend_url base URL of the merchant backend
     328             :  * @param order_id order id used to perform the lookup
     329             :  * @param cb callback which will work the response gotten from the backend
     330             :  * @param cb_cls closure to pass to the callback
     331             :  * @return handle for this operation, NULL upon errors
     332             :  */
     333             : struct TALER_MERCHANT_RefundLookupOperation *
     334           5 : TALER_MERCHANT_refund_lookup (struct GNUNET_CURL_Context *ctx,
     335             :                               const char *backend_url,
     336             :                               const char *order_id,
     337             :                               const char *instance,
     338             :                               TALER_MERCHANT_RefundLookupCallback cb,
     339             :                               void *cb_cls)
     340             : {
     341             :   struct TALER_MERCHANT_RefundLookupOperation *rlo;
     342             :   CURL *eh;
     343             :   char *base;
     344             : 
     345           5 :   rlo = GNUNET_new (struct TALER_MERCHANT_RefundLookupOperation);
     346           5 :   rlo->ctx = ctx;
     347           5 :   rlo->cb = cb;
     348           5 :   rlo->cb_cls = cb_cls;
     349             :   
     350           5 :   base = TALER_url_join (backend_url, "/public/refund", NULL);
     351           5 :   GNUNET_asprintf (&rlo->url,
     352             :                    "%s?instance=%s&order_id=%s",
     353             :                    base,
     354             :                    instance,
     355             :                    order_id);
     356           5 :   GNUNET_free (base);
     357           5 :   eh = curl_easy_init ();
     358           5 :   if (CURLE_OK != curl_easy_setopt (eh,
     359             :                                     CURLOPT_URL,
     360             :                                     rlo->url))
     361             :   {
     362           0 :     GNUNET_break (0);
     363           0 :     return NULL;
     364             :   }
     365             : 
     366           5 :   if (NULL == (rlo->job = GNUNET_CURL_job_add (ctx,
     367             :                                                eh,
     368             :                                                GNUNET_NO,
     369             :                                                handle_refund_lookup_finished,
     370             :                                                rlo)))
     371             :   {
     372           0 :     GNUNET_break (0);
     373           0 :     return NULL;
     374             :   
     375             :   }
     376             : 
     377           5 :   return rlo;
     378             : }

Generated by: LCOV version 1.13