diff options
Diffstat (limited to 'src/bank-lib')
| -rw-r--r-- | src/bank-lib/bank_api_admin.c | 4 | ||||
| -rw-r--r-- | src/bank-lib/bank_api_history.c | 333 | ||||
| -rw-r--r-- | src/bank-lib/fakebank.c | 11 | ||||
| -rw-r--r-- | src/bank-lib/test_bank_interpreter.c | 2 | ||||
| -rw-r--r-- | src/bank-lib/testing_api_cmd_history.c | 209 | 
5 files changed, 462 insertions, 97 deletions
| diff --git a/src/bank-lib/bank_api_admin.c b/src/bank-lib/bank_api_admin.c index 3a1ec4ef..8eff229f 100644 --- a/src/bank-lib/bank_api_admin.c +++ b/src/bank-lib/bank_api_admin.c @@ -79,6 +79,7 @@ handle_admin_add_incoming_finished (void *cls,  {    struct TALER_BANK_AdminAddIncomingHandle *aai = cls;    uint64_t row_id = UINT64_MAX; +  struct GNUNET_TIME_Absolute timestamp;    enum TALER_ErrorCode ec;    const json_t *j = response; @@ -93,6 +94,8 @@ handle_admin_add_incoming_finished (void *cls,        struct GNUNET_JSON_Specification spec[] = {          GNUNET_JSON_spec_uint64 ("row_id",                                   &row_id), +        GNUNET_JSON_spec_absolute_time ("timestamp", +                                        ×tamp),          GNUNET_JSON_spec_end()        }; @@ -148,6 +151,7 @@ handle_admin_add_incoming_finished (void *cls,             response_code,             ec,             row_id, +           timestamp,             j);    TALER_BANK_admin_add_incoming_cancel (aai);  } diff --git a/src/bank-lib/bank_api_history.c b/src/bank-lib/bank_api_history.c index ab757a2d..4b9ea3c3 100644 --- a/src/bank-lib/bank_api_history.c +++ b/src/bank-lib/bank_api_history.c @@ -2,22 +2,26 @@    This file is part of TALER    Copyright (C) 2017 GNUnet e.V. & Inria -  TALER is free software; you can redistribute it and/or modify it under the -  terms of the GNU General Public License as published by the Free Software -  Foundation; either version 3, or (at your option) any later version. - -  TALER is distributed in the hope that it will be useful, but WITHOUT ANY -  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -  A PARTICULAR PURPOSE.  See the GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License along with -  TALER; see the file COPYING.  If not, see -  <http://www.gnu.org/licenses/> +  TALER is free software; you can redistribute it and/or +  modify it under the terms of the GNU General Public License +  as published by the Free Software Foundation; either version 3, +  or (at your option) any later version. + +  TALER is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +  GNU General Public License for more details. + +  You should have received a copy of the GNU General Public +  License along with TALER; see the file COPYING.  If not, +  see <http://www.gnu.org/licenses/>  */  /**   * @file bank-lib/bank_api_history.c - * @brief Implementation of the /history requests of the bank's HTTP API + * @brief Implementation of the /history[-range] + *        requests of the bank's HTTP API.   * @author Christian Grothoff + * @author Marcello Stanisci   */  #include "platform.h"  #include "bank_api_common.h" @@ -60,7 +64,23 @@ struct TALER_BANK_HistoryHandle     * Closure for @a cb.     */    void *hcb_cls; +}; + + +/** + * Represent a URL argument+value pair. + */ +struct HistoryArgumentURL +{ +  /** +   * Name of the URL argument. +   */ +  char argument[20]; +  /** +   * Value of the URL argument. +   */ +  char value[20];  }; @@ -248,24 +268,202 @@ handle_history_finished (void *cls,  } + +/** + * Backend of both the /history[-range] requests. + * + * @param ctx curl context for the event loop + * @param bank_base_url base URL of the bank. + * @param urlargs path + URL arguments. + * @param auth authentication data to use + * @param hres_cb the callback to call with the transaction + *        history + * @param hres_cb_cls closure for the above callback + * @return NULL if the inputs are invalid (i.e. zero value for + *         @e num_results). In this case, the callback is not + *         called. + */ +static struct TALER_BANK_HistoryHandle * +put_history_job (struct GNUNET_CURL_Context *ctx, +                 const char *bank_base_url, +                 const char *urlargs, +                 const struct TALER_BANK_AuthenticationData *auth, +                 TALER_BANK_HistoryResultCallback hres_cb, +                 void *hres_cb_cls) +{ +  struct TALER_BANK_HistoryHandle *hh; +  CURL *eh; + +  hh = GNUNET_new (struct TALER_BANK_HistoryHandle); +  hh->hcb = hres_cb; +  hh->hcb_cls = hres_cb_cls; +  hh->bank_base_url = GNUNET_strdup (bank_base_url); +  hh->request_url = TALER_BANK_path_to_url_ (bank_base_url, +                                             urlargs); + +  hh->authh = TALER_BANK_make_auth_header_ (auth); +  eh = curl_easy_init (); +  GNUNET_assert (CURLE_OK == +                 curl_easy_setopt (eh, +                                   CURLOPT_HTTPHEADER, +                                   hh->authh)); +  GNUNET_assert (CURLE_OK == +                 curl_easy_setopt (eh, +                                   CURLOPT_URL, +                                   hh->request_url)); +  hh->job = GNUNET_CURL_job_add (ctx, +                                 eh, +                                 GNUNET_NO, +                                 &handle_history_finished, +                                 hh); +  return hh; +} + + +/** + * Convert fixed value 'direction' into string. + * + * @param direction the value to convert. + * @return string representation of @a direction.  When length + *         is zero, an error occurred. + */ +static struct HistoryArgumentURL +conv_direction (enum TALER_BANK_Direction direction) +{ +  struct HistoryArgumentURL ret; + +  if (TALER_BANK_DIRECTION_NONE == direction) +  { +    /* Should just never happen.  */ +    GNUNET_assert (0); +    return ret; +  } + +  if (TALER_BANK_DIRECTION_BOTH == +      (TALER_BANK_DIRECTION_BOTH & direction)) +    strcpy (&ret.value[0], +            "both"); +  else if (TALER_BANK_DIRECTION_CREDIT == +      (TALER_BANK_DIRECTION_CREDIT & direction)) +    strcpy (&ret.value[0], +            "credit"); +  else if (TALER_BANK_DIRECTION_DEBIT == +      (TALER_BANK_DIRECTION_BOTH & direction)) /*why use 'both' flag?*/ +    strcpy (&ret.value[0], +            "debit"); +  return ret; +} + + +/** + * Convert fixed value 'direction' into string representation + * of the "cancel" argument. + * + * @param direction the value to convert. + * @return string representation of @a direction.  When length + *         is zero, an error occurred. + */ +static struct HistoryArgumentURL +conv_cancel (enum TALER_BANK_Direction direction) +{ +  struct HistoryArgumentURL ret; + +  if (TALER_BANK_DIRECTION_CANCEL == +      (TALER_BANK_DIRECTION_CANCEL & direction)) +    strcpy (&ret.value[0], +            "show"); +  else +    strcpy (&ret.value[0], +            "omit"); +  return ret; +} + +/** + * Request the wire transfer history of a bank account, + * using time stamps to narrow the results. + * + * @param ctx curl context for the event loop + * @param bank_base_url URL of the bank (used to execute this + *        request) + * @param auth authentication data to use + * @param account_number which account number should we query + * @param direction what kinds of wire transfers should be + *        returned + * @param ascending if GNUNET_YES, history elements will + *        be returned in chronological order. + * @param start_date threshold for oldest result. + * @param end_date threshold for youngest result. + * @param hres_cb the callback to call with the transaction + *        history + * @param hres_cb_cls closure for the above callback + * @return NULL if the inputs are invalid (i.e. zero value for + *         @e num_results). In this case, the callback is not + *         called. + */ +struct TALER_BANK_HistoryHandle * +TALER_BANK_history_range (struct GNUNET_CURL_Context *ctx, +                          const char *bank_base_url, +                          const struct TALER_BANK_AuthenticationData *auth, +                          uint64_t account_number, +                          enum TALER_BANK_Direction direction, +                          unsigned int ascending, +                          struct GNUNET_TIME_Absolute start_date, +                          struct GNUNET_TIME_Absolute end_date, +                          TALER_BANK_HistoryResultCallback hres_cb, +                          void *hres_cb_cls) +{ +  struct TALER_BANK_HistoryHandle *hh; +  char *url; + +  GNUNET_TIME_round_abs (&start_date); +  GNUNET_TIME_round_abs (&end_date); + +  GNUNET_asprintf (&url, +                   "/history?auth=basic&account_number=%llu&start=%llu&end=%llu&direction=%s&cancelled=%s&ordering=%s", +                   (unsigned long long) account_number, +                   start_date.abs_value_us / 1000LL / 1000LL, +                   end_date.abs_value_us / 1000LL / 1000LL, +                   conv_direction (direction).value, +                   conv_cancel (direction).value, +                   (GNUNET_YES == ascending) ? "ascending" : "descending"); + +  hh = put_history_job (ctx, +                        bank_base_url, +                        url, +                        auth, +                        hres_cb, +                        hres_cb_cls); + +  GNUNET_free (url); +  return hh; +} + + +  /**   * Request the wire transfer history of a bank account.   *   * @param ctx curl context for the event loop - * @param bank_base_url URL of the bank (used to execute this request) + * @param bank_base_url URL of the bank (used to execute this + *        request)   * @param auth authentication data to use   * @param account_number which account number should we query - * @param direction what kinds of wire transfers should be returned - * @param ascending if GNUNET_YES, history elements will be returned in chronological order. - * @param start_row from which row on do we want to get results, use UINT64_MAX for the latest; exclusive - * @param num_results how many results do we want; negative numbers to go into the past, - *                    positive numbers to go into the future starting at @a start_row; - *                    must not be zero. - * @param hres_cb the callback to call with the transaction history + * @param direction what kinds of wire transfers should be + *        returned + * @param ascending if GNUNET_YES, history elements will + *        be returned in chronological order. + * @param start_row from which row on do we want to get results, + *        use UINT64_MAX for the latest; exclusive + * @param num_results how many results do we want; + *        negative numbers to go into the past, positive numbers + *        to go into the future starting at @a start_row; + *        must not be zero. + * @param hres_cb the callback to call with the transaction + *        history   * @param hres_cb_cls closure for the above callback - * @return NULL - *         if the inputs are invalid (i.e. zero value for @e num_results). - *         In this case, the callback is not called. + * @return NULL if the inputs are invalid (i.e. zero value for + *         @e num_results). In this case, the callback is not + *         called.   */  struct TALER_BANK_HistoryHandle *  TALER_BANK_history (struct GNUNET_CURL_Context *ctx, @@ -280,91 +478,44 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,                      void *hres_cb_cls)  {    struct TALER_BANK_HistoryHandle *hh; -  CURL *eh;    char *url; -  const char *dir; -  const char *can;    if (0 == num_results)    {      GNUNET_break (0);      return NULL;    } -  if (TALER_BANK_DIRECTION_NONE == direction) -  { -    GNUNET_break (0); -    return NULL; -  } - -  dir = NULL; -  if (TALER_BANK_DIRECTION_BOTH == (TALER_BANK_DIRECTION_BOTH & direction)) -    dir = "both"; -  else if (TALER_BANK_DIRECTION_CREDIT == (TALER_BANK_DIRECTION_CREDIT & direction)) -    dir = "credit"; -  else if (TALER_BANK_DIRECTION_DEBIT == (TALER_BANK_DIRECTION_BOTH & direction)) -    dir = "debit"; -  if (NULL == dir) -  { -    GNUNET_break (0); -    return NULL; -  } -  if (TALER_BANK_DIRECTION_CANCEL == (TALER_BANK_DIRECTION_CANCEL & direction)) -    can = "show"; -  else -    can = "omit"; +  GNUNET_asprintf (&url, +                   "/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s&ordering=%s&start=%llu", +                   (unsigned long long) account_number, +                   (long long) num_results, +                   conv_direction (direction).value, +                   conv_cancel (direction).value, +                   (GNUNET_YES == ascending) ? "ascending" : "descending", +                   start_row); + +  /* Locate and "cut" the 'start' argument, +   * if the user didn't provide one.  */    if (UINT64_MAX == start_row) -  { -    GNUNET_asprintf (&url, -                     "/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s&ordering=%s", -                     (unsigned long long) account_number, -                     (long long) num_results, -                     dir, -                     can, -                     (GNUNET_YES == ascending) ? "ascending" : "descending"); +    *strstr (url, "&start=") = '\0'; -  } -  else -  { -    GNUNET_asprintf (&url, -                     "/history?auth=basic&account_number=%llu&delta=%lld&start=%llu&direction=%s&cancelled=%s&ordering=%s", -                     (unsigned long long) account_number, -                     (long long) num_results, -                     (unsigned long long) start_row, -                     dir, -                     can, -                     (GNUNET_YES == ascending) ? "ascending" : "descending"); -  } +  hh = put_history_job (ctx, +                        bank_base_url, +                        url, +                        auth, +                        hres_cb, +                        hres_cb_cls); -  hh = GNUNET_new (struct TALER_BANK_HistoryHandle); -  hh->hcb = hres_cb; -  hh->hcb_cls = hres_cb_cls; -  hh->bank_base_url = GNUNET_strdup (bank_base_url); -  hh->request_url = TALER_BANK_path_to_url_ (bank_base_url, -                                             url);    GNUNET_free (url); -  hh->authh = TALER_BANK_make_auth_header_ (auth); -  eh = curl_easy_init (); -  GNUNET_assert (CURLE_OK == -                 curl_easy_setopt (eh, -                                   CURLOPT_HTTPHEADER, -                                   hh->authh)); -  GNUNET_assert (CURLE_OK == -                 curl_easy_setopt (eh, -                                   CURLOPT_URL, -                                   hh->request_url)); -  hh->job = GNUNET_CURL_job_add (ctx, -                                 eh, -                                 GNUNET_NO, -                                 &handle_history_finished, -                                 hh);    return hh;  }  /** - * Cancel a history request.  This function cannot be used on a request - * handle if a response is already served for it. + * Cancel a history request.  This function cannot be + * used on a request handle if a response is already + * served for it.   *   * @param hh the history request handle   */ diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c index 37aae042..9915516c 100644 --- a/src/bank-lib/fakebank.c +++ b/src/bank-lib/fakebank.c @@ -160,11 +160,12 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,    struct Transaction *t;    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, -              "Making transfer from %llu to %llu over %s and subject %s\n", +              "Making transfer from %llu to %llu over %s and subject %s; for exchange: %s\n",                (unsigned long long) debit_account,                (unsigned long long) credit_account,                TALER_amount2s (amount), -              subject); +              subject, +              exchange_base_url);    t = GNUNET_new (struct Transaction);    t->debit_account = debit_account;    t->credit_account = credit_account; @@ -463,9 +464,11 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,      void *json_str;      size_t json_len; -    json = json_pack ("{s:I}", +    json = json_pack ("{s:I, s:s}",                        "row_id", -                      (json_int_t) row_id); +                      (json_int_t) row_id, +                      "timestamp", "/Date(0)/"); /*dummy tmp */ +      json_str = json_dumps (json,                             JSON_INDENT(2));      json_decref (json); diff --git a/src/bank-lib/test_bank_interpreter.c b/src/bank-lib/test_bank_interpreter.c index fc765779..9430e84b 100644 --- a/src/bank-lib/test_bank_interpreter.c +++ b/src/bank-lib/test_bank_interpreter.c @@ -530,6 +530,7 @@ next (struct InterpreterState *is)   *                    0 if the bank's reply is bogus (fails to follow the protocol)   * @param ec taler status code   * @param row_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error + * @param timestamp time stamp of when the transaction settled at the bank   * @param json detailed response from the HTTPD, or NULL if reply was not in JSON   */  static void @@ -537,6 +538,7 @@ add_incoming_cb (void *cls,                   unsigned int http_status,                   enum TALER_ErrorCode ec,                   uint64_t row_id, +                 struct GNUNET_TIME_Absolute timestamp,                   const json_t *json)  {    struct InterpreterState *is = cls; diff --git a/src/bank-lib/testing_api_cmd_history.c b/src/bank-lib/testing_api_cmd_history.c index e3b05c83..37e15af8 100644 --- a/src/bank-lib/testing_api_cmd_history.c +++ b/src/bank-lib/testing_api_cmd_history.c @@ -90,6 +90,27 @@ struct HistoryState     * chronological order.     */    unsigned int ascending; + +  /********************************** +   * Following defs are specific to * +   * the "/history-range" version.  * +   **********************************/ + +  /** +   * Last row number we want in the result.  Only used +   * as a trait source when using the /history-range API. +   */ +  const char *end_row_reference; + +  /** +   * Start date for /history-range. +   */ +  struct GNUNET_TIME_Absolute start_date; + +  /** +   * End date for /history-range. +   */ +  struct GNUNET_TIME_Absolute end_date;  };  /** @@ -669,6 +690,8 @@ history_cb (void *cls,    struct TALER_TESTING_Interpreter *is = cls;    struct HistoryState *hs = is->commands[is->ip].cls; +  /* Possibly we got the 204 status code +   * as a "end of list" marker.  */    if (MHD_HTTP_OK != http_status)    {      hs->hh = NULL; @@ -710,7 +733,7 @@ history_cb (void *cls,                          JSON_COMPACT);        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,                    "Result %u was `%s'\n", -                  (unsigned int) hs->results_obtained, +                  (unsigned int) hs->results_obtained++,                    acc);        if (NULL != acc)          free (acc); @@ -758,7 +781,6 @@ history_run (void *cls,      TALER_LOG_DEBUG ("row id (from trait) is %llu\n",                       (unsigned long long) row_id); -    }    auth = &AUTHS[hs->account_no - 1]; @@ -777,6 +799,81 @@ history_run (void *cls,  /** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +history_range_run (void *cls, +                   const struct TALER_TESTING_Command *cmd, +                   struct TALER_TESTING_Interpreter *is) +{ +   +  struct HistoryState *hs = cls; +  const struct GNUNET_TIME_Absolute *start_date; +  const struct GNUNET_TIME_Absolute *end_date; +  struct TALER_BANK_AuthenticationData *auth; + +  if (NULL != hs->start_row_reference) +  { +       +    const struct TALER_TESTING_Command *history_cmd; + +    history_cmd = TALER_TESTING_interpreter_lookup_command +      (is, hs->start_row_reference); + +    if (NULL == history_cmd) +      TALER_TESTING_FAIL (is); + +    if (GNUNET_OK != TALER_TESTING_get_trait_absolute_time +        (history_cmd, 0, &start_date)) +      TALER_TESTING_FAIL (is); +  } +  else +  { +    GNUNET_assert (UINT64_MAX != hs->start_date.abs_value_us); +    start_date = &hs->start_date; +  } + +  if (NULL != hs->end_row_reference) +  { + +    const struct TALER_TESTING_Command *history_cmd; + +    history_cmd = TALER_TESTING_interpreter_lookup_command +      (is, hs->end_row_reference); + +    if (NULL == history_cmd) +      TALER_TESTING_FAIL (is); + +    if (GNUNET_OK != TALER_TESTING_get_trait_absolute_time +        (history_cmd, 0, &end_date)) +      TALER_TESTING_FAIL (is); +  } +  else +  { +    GNUNET_assert (UINT64_MAX != hs->end_date.abs_value_us); +    end_date = &hs->end_date; +  } + +  auth = &AUTHS[hs->account_no - 1]; +  hs->hh = TALER_BANK_history_range (is->ctx, +                                     hs->bank_url, +                                     auth, +                                     hs->account_no, +                                     hs->direction, +                                     hs->ascending, +                                     *start_date, +                                     *end_date, +                                     &history_cb, +                                     is); +  GNUNET_assert (NULL != hs->hh); +} + + +/**   * Free the state from a "history" CMD, and possibly cancel   * a pending operation thereof.   * @@ -848,4 +945,112 @@ TALER_TESTING_cmd_bank_history    return cmd;  } + +/** + * Make a "history-range" CMD, picking dates from traits. + * + * @param label command label. + * @param bank_url base URL of the bank offering the "history" + *        operation. + * @param account_no bank account number to ask the history for. + * @param direction which direction this operation is interested. + * @param ascending if GNUNET_YES, the bank will return the rows + *        in ascending (= chronological) order. + * @param start_row_reference reference to a command that can + *        offer a absolute time to use as the 'start' argument + *        for "/history-range". + * @param end_row_reference reference to a command that can + *        offer a absolute time to use as the 'end' argument + *        for "/history-range". + * @param num_result how many rows we want in the result.  + * + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_bank_history_range +  (const char *label, +   const char *bank_url, +   uint64_t account_no, +   enum TALER_BANK_Direction direction, +   unsigned int ascending, +   const char *start_row_reference, +   const char *end_row_reference, +   long long num_results) +{ +  struct HistoryState *hs; + +  hs = GNUNET_new (struct HistoryState); +  hs->bank_url = bank_url; +  hs->account_no = account_no; +  hs->direction = direction; +  hs->start_row_reference = start_row_reference; +  hs->end_row_reference = end_row_reference; +  hs->num_results = num_results; +  hs->ascending = ascending; +  hs->start_date = GNUNET_TIME_UNIT_FOREVER_ABS; +  hs->end_date = GNUNET_TIME_UNIT_FOREVER_ABS; + +  struct TALER_TESTING_Command cmd = { +    .label = label, +    .cls = hs, +    .run = &history_range_run, +    .cleanup = &history_cleanup, +    .traits = &history_traits +  }; + +  return cmd; +} + + +/** + * Make a "history-range" CMD, picking dates from the arguments. + * + * @param label command label. + * @param bank_url base URL of the bank offering the "history" + *        operation. + * @param account_no bank account number to ask the history for. + * @param direction which direction this operation is interested. + * @param ascending if GNUNET_YES, the bank will return the rows + *        in ascending (= chronological) order. + * @param start_date value for the 'start' argument + *        of "/history-range". + * @param end_date value for the 'end' argument + *        of "/history-range". + * @param num_result how many rows we want in the result.  + * + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_bank_history_range_with_dates +  (const char *label, +   const char *bank_url, +   uint64_t account_no, +   enum TALER_BANK_Direction direction, +   unsigned int ascending, +   struct GNUNET_TIME_Absolute start_date, +   struct GNUNET_TIME_Absolute end_date, +   long long num_results) +{ +  struct HistoryState *hs; + +  hs = GNUNET_new (struct HistoryState); +  hs->bank_url = bank_url; +  hs->account_no = account_no; +  hs->direction = direction; +  hs->num_results = num_results; +  hs->ascending = ascending; +  hs->start_date = start_date; +  hs->end_date = start_date; + +  struct TALER_TESTING_Command cmd = { +    .label = label, +    .cls = hs, +    .run = &history_range_run, +    .cleanup = &history_cleanup, +    .traits = &history_traits +  }; + +  return cmd; +} +  /* end of testing_api_cmd_history.c */ | 
