Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2023 Taler Systems SA
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 merchant_api_post_order_refund.c
19 : * @brief Implementation of the POST /orders/ID/refund request
20 : * @author Christian Grothoff
21 : * @author Marcello Stanisci
22 : */
23 : #include "platform.h"
24 : #include <curl/curl.h>
25 : #include <jansson.h>
26 : #include <microhttpd.h> /* just for HTTP status codes */
27 : #include <gnunet/gnunet_util_lib.h>
28 : #include <gnunet/gnunet_curl_lib.h>
29 : #include "taler_merchant_service.h"
30 : #include "merchant_api_curl_defaults.h"
31 : #include "merchant_api_common.h"
32 : #include <taler/taler_json_lib.h>
33 : #include <taler/taler_signatures.h>
34 : #include <taler/taler_curl_lib.h>
35 :
36 :
37 : /**
38 : * Handle for a POST /orders/ID/refund operation.
39 : */
40 : struct TALER_MERCHANT_OrderRefundHandle
41 : {
42 : /**
43 : * Complete URL where the backend offers /refund
44 : */
45 : char *url;
46 :
47 : /**
48 : * Minor context that holds body and headers.
49 : */
50 : struct TALER_CURL_PostContext post_ctx;
51 :
52 : /**
53 : * The CURL context to connect to the backend
54 : */
55 : struct GNUNET_CURL_Context *ctx;
56 :
57 : /**
58 : * The callback to pass the backend response to
59 : */
60 : TALER_MERCHANT_RefundCallback cb;
61 :
62 : /**
63 : * Clasure to pass to the callback
64 : */
65 : void *cb_cls;
66 :
67 : /**
68 : * Handle for the request
69 : */
70 : struct GNUNET_CURL_Job *job;
71 : };
72 :
73 :
74 : /**
75 : * Callback to process POST /orders/ID/refund response
76 : *
77 : * @param cls the `struct TALER_MERCHANT_OrderRefundHandle`
78 : * @param response_code HTTP response code, 0 on error
79 : * @param response response body, NULL if not JSON
80 : */
81 : static void
82 10 : handle_refund_finished (void *cls,
83 : long response_code,
84 : const void *response)
85 : {
86 10 : struct TALER_MERCHANT_OrderRefundHandle *orh = cls;
87 10 : const json_t *json = response;
88 10 : struct TALER_MERCHANT_RefundResponse rr = {
89 10 : .hr.http_status = (unsigned int) response_code,
90 : .hr.reply = json
91 : };
92 :
93 10 : orh->job = NULL;
94 10 : switch (response_code)
95 : {
96 0 : case 0:
97 0 : rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
98 0 : break;
99 6 : case MHD_HTTP_OK:
100 : {
101 : struct GNUNET_JSON_Specification spec[] = {
102 6 : GNUNET_JSON_spec_string (
103 : "taler_refund_uri",
104 : &rr.details.ok.taler_refund_uri),
105 6 : GNUNET_JSON_spec_fixed_auto (
106 : "h_contract",
107 : &rr.details.ok.h_contract),
108 6 : GNUNET_JSON_spec_end ()
109 : };
110 :
111 6 : if (GNUNET_OK !=
112 6 : GNUNET_JSON_parse (json,
113 : spec,
114 : NULL, NULL))
115 : {
116 0 : GNUNET_break_op (0);
117 0 : rr.hr.http_status = 0;
118 0 : rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
119 0 : break;
120 : }
121 6 : break;
122 : }
123 0 : case MHD_HTTP_UNAUTHORIZED:
124 0 : rr.hr.ec = TALER_JSON_get_error_code (json);
125 0 : rr.hr.hint = TALER_JSON_get_error_hint (json);
126 : /* Nothing really to verify, merchant says we need to authenticate. */
127 0 : break;
128 0 : case MHD_HTTP_FORBIDDEN:
129 0 : rr.hr.ec = TALER_JSON_get_error_code (json);
130 0 : rr.hr.hint = TALER_JSON_get_error_hint (json);
131 : /* Nothing really to verify, merchant says we need to authenticate. */
132 0 : break;
133 4 : case MHD_HTTP_NOT_FOUND:
134 : case MHD_HTTP_CONFLICT:
135 4 : rr.hr.ec = TALER_JSON_get_error_code (json);
136 4 : rr.hr.hint = TALER_JSON_get_error_hint (json);
137 4 : break;
138 0 : default:
139 0 : GNUNET_break_op (0); /* unexpected status code */
140 0 : TALER_MERCHANT_parse_error_details_ (json,
141 : response_code,
142 : &rr.hr);
143 0 : break;
144 : }
145 10 : orh->cb (orh->cb_cls,
146 : &rr);
147 10 : TALER_MERCHANT_post_order_refund_cancel (orh);
148 10 : }
149 :
150 :
151 : void
152 10 : TALER_MERCHANT_post_order_refund_cancel (
153 : struct TALER_MERCHANT_OrderRefundHandle *orh)
154 : {
155 10 : if (NULL != orh->job)
156 : {
157 0 : GNUNET_CURL_job_cancel (orh->job);
158 0 : orh->job = NULL;
159 : }
160 10 : TALER_curl_easy_post_finished (&orh->post_ctx);
161 10 : GNUNET_free (orh->url);
162 10 : GNUNET_free (orh);
163 10 : }
164 :
165 :
166 : struct TALER_MERCHANT_OrderRefundHandle *
167 10 : TALER_MERCHANT_post_order_refund (struct GNUNET_CURL_Context *ctx,
168 : const char *backend_url,
169 : const char *order_id,
170 : const struct TALER_Amount *refund,
171 : const char *reason,
172 : TALER_MERCHANT_RefundCallback cb,
173 : void *cb_cls)
174 : {
175 : struct TALER_MERCHANT_OrderRefundHandle *orh;
176 : json_t *req;
177 : CURL *eh;
178 :
179 10 : orh = GNUNET_new (struct TALER_MERCHANT_OrderRefundHandle);
180 10 : orh->ctx = ctx;
181 10 : orh->cb = cb;
182 10 : orh->cb_cls = cb_cls;
183 : {
184 : char *path;
185 :
186 10 : GNUNET_asprintf (&path,
187 : "private/orders/%s/refund",
188 : order_id);
189 10 : orh->url = TALER_url_join (backend_url,
190 : path,
191 : NULL);
192 10 : GNUNET_free (path);
193 : }
194 10 : if (NULL == orh->url)
195 : {
196 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
197 : "Could not construct request URL.\n");
198 0 : GNUNET_free (orh);
199 0 : return NULL;
200 : }
201 10 : req = GNUNET_JSON_PACK (
202 : TALER_JSON_pack_amount ("refund",
203 : refund),
204 : GNUNET_JSON_pack_string ("reason",
205 : reason));
206 10 : GNUNET_assert (NULL != req);
207 10 : eh = TALER_MERCHANT_curl_easy_get_ (orh->url);
208 10 : if (GNUNET_OK !=
209 10 : TALER_curl_easy_post (&orh->post_ctx,
210 : eh,
211 : req))
212 : {
213 0 : GNUNET_break (0);
214 0 : curl_easy_cleanup (eh);
215 0 : json_decref (req);
216 0 : GNUNET_free (orh->url);
217 0 : GNUNET_free (orh);
218 0 : return NULL;
219 : }
220 10 : json_decref (req);
221 20 : orh->job = GNUNET_CURL_job_add2 (ctx,
222 : eh,
223 10 : orh->post_ctx.headers,
224 : &handle_refund_finished,
225 : orh);
226 10 : if (NULL == orh->job)
227 : {
228 0 : GNUNET_free (orh->url);
229 0 : GNUNET_free (orh);
230 0 : return NULL;
231 : }
232 10 : return orh;
233 : }
234 :
235 :
236 : /* end of merchant_api_post_order_refund.c */
|