gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-bank] branch stable updated (3756eec -> d662aac)


From: gnunet
Subject: [GNUnet-SVN] [taler-bank] branch stable updated (3756eec -> d662aac)
Date: Tue, 07 May 2019 19:07:43 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a change to branch stable
in repository bank.

    from 3756eec  Pick pure.css from web-common.
     add 5bde353  Build history response in a separate helper.
     add a3f2e32  New date-range-based history extractor function signature.
     add d865e0d  Dates comparison
     add 6f7415a  HTTP-Serving date-range based history query.
     add 35cb277  Calling /history-range from test cases.
     add 4a131f6  Tests.
     add ebdf0ab  Disable admin interface
     add 879a942  Also removing 'admin' from INSTALLED_APPS.
     add 3c6c616  Still on admin removal
     add 9d134d4  fix operator
     add 088708f  No custom DoesNotExist classes anymore.
     add 53bb0c6  Prevent test from seeking ~/.config/taler.conf
     add 5a9c796  test conf
     add 8060df9  Further testing with a not-found ~/.config/taler.conf.
     add 8cdf0d5  log error
     add d8517bc  doc: taler-bank-manage.1 typo fixes and format changes
     add ce43aa2  Attempt to detect more valid pip executables. Tested with 
pip3.7
     add f5099e8  Revert "Attempt to detect more valid pip executables."
     add b71b064  Attempt to detect more valid pip executables. Tested with 
pip3.7
     add 169c419  configure: Use python module loading for checking for the 
various python modules we use.
     add d662aac  re-add messages to indicate auth fail

No new revisions were added by this update.

Summary of changes:
 Makefile.am                        |  18 ++--
 bank-check.conf                    |   5 ++
 configure.ac                       |  39 +++++----
 doc/taler-bank-manage.1            |  84 +++++++++---------
 taler-bank-manage.in               |   4 +-
 talerbank/app/middleware.py        |  19 ++++-
 talerbank/app/models.py            |  20 -----
 talerbank/app/schemas.py           |  33 ++++++++
 talerbank/app/templates/login.html |  14 +++
 talerbank/app/tests.py             |  84 +++++++++++++-----
 talerbank/app/urls.py              |   1 +
 talerbank/app/views.py             | 169 +++++++++++++++++++++++++++++--------
 talerbank/settings.py              |   9 +-
 talerbank/urls.py                  |  11 +--
 unused.conf                        |   3 +
 15 files changed, 356 insertions(+), 157 deletions(-)
 create mode 100644 unused.conf

diff --git a/Makefile.am b/Makefile.am
index c6f5581..44f47b8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -60,6 +60,7 @@ check:
            "Testing against bad db string"
        @export DJANGO_SETTINGS_MODULE="talerbank.settings" \
          TALER_PREFIX="@prefix@" \
+         TALER_CONFIG_FILE="unused.conf" \
          TALER_BANK_ALTDB="bad db string" \
          PYTHONPATH="${PYTHONPATH_APPEND}:${PYTHONPATH}" \
          && python3 \
@@ -78,6 +79,14 @@ check:
            --no-input \
            talerbank.app.tests_alt.BadMaxDebitOptionTestCase
        @printf ${FMT} ${SEPARATOR} \
+           "Testing against db not found"
+       @export DJANGO_SETTINGS_MODULE="talerbank.settings" \
+         TALER_PREFIX="@prefix@" \
+         TALER_BANK_ALTDB="postgres:///idontexist" \
+         PYTHONPATH="${PYTHONPATH_APPEND}:${PYTHONPATH}" \
+         && python3 ./taler-bank-manage --config=bank-check.conf serve-uwsgi ; 
\
+         test 4 = $$?
+       @printf ${FMT} ${SEPARATOR} \
            "Testing against no currency in config"
        @export TALER_BASE_CONFIG="/tmp" \
          DJANGO_SETTINGS_MODULE="talerbank.settings" \
@@ -89,14 +98,7 @@ check:
            --no-input \
            talerbank.app.tests_alt.NoCurrencyOptionTestCase ; \
          test 3 = $$?
-       @printf ${FMT} ${SEPARATOR} \
-           "Testing against db not found"
-       @export DJANGO_SETTINGS_MODULE="talerbank.settings" \
-         TALER_PREFIX="@prefix@" \
-         TALER_BANK_ALTDB="postgres:///idontexist" \
-         PYTHONPATH="${PYTHONPATH_APPEND}:${PYTHONPATH}" \
-         && python3 ./taler-bank-manage serve-uwsgi ; \
-         test 4 = $$?
+
 
 # install into prefix
 install-exec-hook:
diff --git a/bank-check.conf b/bank-check.conf
index 46658e2..65be040 100644
--- a/bank-check.conf
+++ b/bank-check.conf
@@ -14,3 +14,8 @@ MAX_DEBT = KUDOS:50.0
 
 # FIXME
 MAX_DEBT_BANK = KUDOS:0.0
+
+UWSGI_SERVE = unix
+UWSGI_UNIXPATH = /tmp/banktest-unused.uwsgi
+UWSGI_UNIXPATH_MODE = 660
+
diff --git a/configure.ac b/configure.ac
index d70c52a..3a92cde 100644
--- a/configure.ac
+++ b/configure.ac
@@ -27,26 +27,26 @@ PC_PYTHON_CHECK_HEADERS([pyheaders=1])
 # Get Python version
 PC_PYTHON_CHECK_VERSION()
 
-#
-# Check for pip3
-#
-
-AC_MSG_CHECKING([pip3])
-pip3 --version >/dev/null
-if test $? -ne 0;
-  then
-  AC_MSG_ERROR([Please install pip3>=6.0])
-fi
+# Get python executable name
+m4_define_default([_AM_PYTHON_INTERPRETER_LIST],[python3 python3.4 python3.5 
python3.6 python3.7 python])
+AM_PATH_PYTHON([3.4],, [:])
+AC_SUBST([PYTHON])
+AM_CONDITIONAL([HAVE_PYTHON], [test "$PYTHON" != :])
 
-PIP_VERSION=$(pip3 --version | $AWK '{ print $2 }')
-
-AC_MSG_RESULT([$PIP_VERSION])
+#
+# Check for pip3.
+# Since it is either pip3 or pip[3.4,3.5,3.6,3.7],
+# we check using python module loading.
+PIP_EXE="$PYTHON -m pip"
+PIP_VERSION=$($PIP_EXE -V | grep -v "No module named" | tr -d '\n' | $AWK '{ 
print $2 }')
+AC_MSG_RESULT([pip3 version: $PIP_VERSION])
 
 AX_COMPARE_VERSION([$PIP_VERSION],[lt],[6.0], [AC_MSG_ERROR([Please install 
pip3>=6.0])])
 
 # On Debian systems, we may need to pass "--system" to pip3 to get
 # to the desired installation target directory
-pip3 install --help | grep '\-\-system' >> /dev/null
+AC_MSG_CHECKING([for pip3 --system])
+$PIP_EXE install --help | grep '\-\-system' >> /dev/null
 if test $? -ne 0;
 then
    DEBIAN_PIP3_SYSTEM=""
@@ -85,11 +85,16 @@ fi
 # Check for pylint
 #
 
-AC_MSG_CHECKING([pip3])
-pylint --version >/dev/null
+PYLINT_EXE="$PYTHON -m pylint --version"
+AC_MSG_CHECKING([for pylint])
+# If module load does not return 'No module named', we have test == 0.
+# This implies having a grep implementation which supports the -v
+# switch to be 'invert-match' (select non-matching lines), which the
+# standard implementations support.
+$PYLINT_EXE | grep -v "No module named" >/dev/null
 if test $? -ne 0;
   then
-  AC_MSG_NOTICE([WARNING: pylint NOT found.])
+  AC_MSG_WARN([pylint NOT found.])
 else
   AC_MSG_NOTICE([NOTICE: pylint found, make sure plugin 'pylint-django' is 
installed.])
 fi
diff --git a/doc/taler-bank-manage.1 b/doc/taler-bank-manage.1
index 6cf78ff..8c5875a 100644
--- a/doc/taler-bank-manage.1
+++ b/doc/taler-bank-manage.1
@@ -1,38 +1,46 @@
-.TH TALER\-BANK\-MANAGE 1 "May 13, 2016" "GNU Taler"
-
-.SH NAME
-taler\-bank\-manage \- Manager script for the Taler bank
-
-.SH SYNOPSIS
-.B taler\-bank\-manage
-.RI [ switch ]
-.RI [ options ]
-
-.br
-
-.SH DESCRIPTION
-\fBtaler\-bank\-manage\fP is a command line tool to manage the Taler bank 
demonstrator. It is mandatory to provide a
-.ul
-switch
-and each switch has its own set of
-.ul
-options.
-Give --help to each switch in order to get the list of supported options
-
-.SH SWITCHES
-.B
-.IP "django"
-this switch is a mere wrapper for the django native tool \fBdjango-admin\fP, 
therefore it takes the same options.
-Refer to the official django-admin documentation
-.B
-.IP "serve-http"
-launches the bank Web service at the port given in the --port option
-.B
-.IP "serve-uwsgi"
-launches the bank over UWSGI. Tipically used in conjuction with a Web server 
which acts like a reverse proxy 
-.B
-.IP "sampledata"
-populates the bank's database with sample wire transfers
-.B
-.IP "config"
-shows all Taler's configuration. it just retrieves values from default 
configuration files
+.Dd May 13, 2016
+.Dt TALER-BANK-MANAGE 1
+.Os
+.Sh NAME
+.Nm taler-bank-manage
+.Nd
+Manager script for the Taler bank
+.Sh SYNOPSIS
+.Nm
+.Op Fl \-django
+.Op Fl \-serve-http
+.Op Fl \-serve-uwsgi
+.Op Fl \-sampledata
+.Op Fl \-config
+.Ao Ar options Ac
+.Sh DESCRIPTION
+.Nm
+is a command line tool to manage the Taler bank demonstrator.
+It is mandatory to provide a switch.
+Each switch has its own set of options.
+Give
+.Fl \-help
+to each switch in order to get the list of supported options.
+.Ss SWITCHES
+.Bl -tag -width Ds
+.It Fl \-django
+This switch is a mere wrapper for the django native tool \fBdjango-admin\fP, 
therefore it takes the same options.
+Refer to the official django-admin documentation.
+.It Fl \-serve-http
+Launches the bank Web service at the port given in the
+.Fl \-port
+option.
+.It Fl \-serve-uwsgi
+Launches the bank over UWSGI.
+Typically used in conjuction with a Web server which acts like a reverse proxy.
+.It Fl \-sampledata
+Populates the bank's database with sample wire transfers.
+.It Fl \-config
+Shows all of Taler's configuration.
+it just retrieves values from default configuration files.
+.El
+.\".Sh EXAMPLES
+.\".Sh SEE ALSO
+.\".Sh HISTORY
+.\".Sh AUTHORS
+.\".Sh BUGS
diff --git a/taler-bank-manage.in b/taler-bank-manage.in
index 869f0af..8420b6a 100644
--- a/taler-bank-manage.in
+++ b/taler-bank-manage.in
@@ -177,7 +177,7 @@ if ARGS.config is not None:
 
 try:
     ARGS.func(ARGS)
-except django.db.utils.OperationalError:
-    LOGGER.error("Your database has serious problems. Does it exist?")
+except django.db.utils.OperationalError as error:
+    LOGGER.error(error)
     sys.exit(4)
 ## @endcond
diff --git a/talerbank/app/middleware.py b/talerbank/app/middleware.py
index f6f8c1e..371d9b6 100644
--- a/talerbank/app/middleware.py
+++ b/talerbank/app/middleware.py
@@ -106,10 +106,25 @@ class ExceptionMiddleware:
         # Check if the endpoint should cause a human-readable
         # page to be returned.
         render_to = self.render.get(request.path)
+
+        try:
+            hint = exception.hint
+            http_status_code = exception.http_status_code
+        ##
+        # This exception happens when the middleware is catching
+        # DoesNotExist exceptions; the ideal fix is to get BankAccount
+        # and BankTransaction classes to override their 'DoesNotExist'
+        # field wiht some custom class, but that wasn't straightforward
+        # (in the sense that on different systems we had different
+        # results, so we fallback on this more sound / manual approach)
+        except AttributeError:
+            hint = "The database (BankAccount / BankTransaction) object wasn't 
found."
+            http_status_code = 404
+
         if not render_to:
             return JsonResponse({"ec": taler_ec,
-                                 "error": exception.hint},
-                                status=exception.http_status_code)
+                                 "error": hint},
+                                status=http_status_code)
         request.session["profile_hint"] = \
             True, False, exception.hint
         return redirect(render_to)
diff --git a/talerbank/app/models.py b/talerbank/app/models.py
index 369a84c..e617aba 100644
--- a/talerbank/app/models.py
+++ b/talerbank/app/models.py
@@ -121,24 +121,6 @@ class AmountField(models.Field):
             raise ValidationError(
                 "Invalid input for an amount string: %s" % value)
 
-
-##
-# Exception class to raise when a non-existent bank account is
-# tried to be referenced.
-class BankAccountDoesNotExist(ObjectDoesNotExist):
-    hint = "Specified bank account does not exist"
-    http_status_code = 404
-
-
-##
-# Exception class to raise when a non-existent bank transaction is
-# tried to be referenced.
-class BankTransactionDoesNotExist(ObjectDoesNotExist):
-    hint = "Specified bank transaction does not exist"
-    http_status_code = 404
-
-
-
 ##
 # The class representing a bank account.
 class BankAccount(models.Model):
@@ -147,8 +129,6 @@ class BankAccount(models.Model):
     account_no = models.AutoField(primary_key=True)
     user = models.OneToOneField(User, on_delete=models.CASCADE)
     amount = AmountField(default=get_zero_amount)
-    DoesNotExist = BankAccountDoesNotExist
-
 
 ##
 # The class representing a bank transaction.
diff --git a/talerbank/app/schemas.py b/talerbank/app/schemas.py
index b268275..f61e448 100644
--- a/talerbank/app/schemas.py
+++ b/talerbank/app/schemas.py
@@ -148,6 +148,31 @@ REJECT_REQUEST_SCHEMA = {
 
 
 ##
+# Definition for /history-range request URL parameters.
+HISTORY_RANGE_REQUEST_SCHEMA = {
+    "type": "object",
+    "properties": {
+        "auth": {"type": "string", "pattern": "^basic$"},
+        "cancelled": {"type": "string",
+                      "pattern": "^(omit|show)$",
+                      "required": False},
+        "start": {"type": "string",
+                  "pattern": r"^[0-9]+$"},
+        "end": {"type": "string",
+                "pattern": r"^[0-9]+$"},
+        "ordering": {"type": "string",
+                     "pattern": r"^(ascending|descending)$",
+                     "required": False},
+        "direction": {"type": "string",
+                      "pattern": r"^(debit|credit|both|cancel\+|cancel-)$"},
+        "account_number": {"type": "string",
+                           "pattern": "^([0-9]+)$",
+                           "required": False}
+    }
+}
+
+
+##
 # Definition for /history request URL parameters.
 HISTORY_REQUEST_SCHEMA = {
     "type": "object",
@@ -250,6 +275,13 @@ def validate_history(data):
     validate(data, HISTORY_REQUEST_SCHEMA)
 
 ##
+# Check /history-range input data.
+#
+# @param data dict representing /history's GET parameters.
+def validate_history_range(data):
+    validate(data, HISTORY_RANGE_REQUEST_SCHEMA)
+
+##
 # Check wire details
 # (regardless of which endpoint triggered the check)
 #
@@ -288,6 +320,7 @@ def validate_data(request, data):
     switch = {
         "/reject": validate_reject,
         "/history": validate_history,
+        "/history-range": validate_history_range,
         "/admin/add/incoming": validate_add_incoming,
         "/pin/verify": check_withdraw_session,
         "/pin/question": validate_pin_tan
diff --git a/talerbank/app/templates/login.html 
b/talerbank/app/templates/login.html
index 4e0d7eb..e3081af 100644
--- a/talerbank/app/templates/login.html
+++ b/talerbank/app/templates/login.html
@@ -27,6 +27,20 @@
     <article>
       <div class="login-form">
         <h2>Please login!</h2>
+
+        {% if form.errors %}
+        <p class="informational informational-fail">Your username and password 
didn't match. Please try again.</p>
+        {% endif %}
+
+        {% if next %}
+            {% if user.is_authenticated %}
+            <p class="informational informational-fail">Your account doesn't 
have access to this page. To proceed,
+            please login with an account that has access.</p>
+            {% else %}
+            <p class="informational informational-fail">Please login to see 
this page.</p>
+            {% endif %}
+        {% endif %}
+
         <form method="post" class="pure-form" action="{{ url('login') }}">
           <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token 
}}" />
           {{ form.username }}
diff --git a/talerbank/app/tests.py b/talerbank/app/tests.py
index 3fbe170..20dccc7 100644
--- a/talerbank/app/tests.py
+++ b/talerbank/app/tests.py
@@ -18,6 +18,7 @@
 #  @author Marcello Stanisci
 
 import json
+import time
 import timeit
 import logging
 from urllib.parse import unquote
@@ -382,73 +383,116 @@ class HistoryTestCase(TestCase):
     def tearDown(self):
         clear_db()
 
+    def assert_result(self, response, ctx):
+
+        data = response.content.decode("utf-8")
+        try:
+            # FIXME, not always data is found this way.
+            data = json.loads(data)["data"][0]
+        except (json.JSONDecodeError, KeyError):
+            data = {}
+        self.assertEqual(
+            ctx.expected_resp.get("status"),
+            response.status_code,
+            "Failing request: %s?%s => raw body: %s" % \
+                (response.request["PATH_INFO"],
+                 unquote(response.request["QUERY_STRING"]),
+                 response.content.decode("utf-8")))
+
+        # extract expected data from response
+        expected_data = {}
+        response_data = {}
+        for key, value in ctx.expected_resp.get("fields", []):
+            response_data.update({key: data.get(key)})
+            expected_data.update({key: value})
+
+        self.assertEqual(expected_data, response_data)
+
+    def test_history_range(self):
+        now = int(time.time())
+
+        for ctx in (
+
+            # Expect empty results, range too ancient.
+            HistoryContext(expected_resp={"status": 204},
+                           start = 1, end = 2, direction="both"),
+
+            # Expect empty results, range too ahead.
+            HistoryContext(expected_resp={"status": 200},
+                           start = now + 40, end = now + 50,
+                           direction="both"),
+
+            # Expect non empty results.
+            HistoryContext(expected_resp={"status": 200},
+                           start = now - 30, end = now + 30,
+                           direction="both")):
+
+            response = self.client.get(
+                reverse("history-range", urlconf=urls), ctx.urlargs,
+                **{"HTTP_X_TALER_BANK_USERNAME": "User",
+                   "HTTP_X_TALER_BANK_PASSWORD": "Password"})
+
+        self.assert_result(response, ctx)
+
     def test_history(self):
         for ctx in (
+
                 HistoryContext(
                     expected_resp={"status": 200},
                     delta="-4", direction="both"),
+
                 HistoryContext(
                     expected_resp={
                         "fields": [("row_id", 9)],
                         "status": 200},
                     delta="+1", start="5", direction="both"),
+
                 HistoryContext(
                     expected_resp={
                         "fields": [("wt_subject", "c")],
                         "status": 200},
                     delta="1", start=2,
                     direction="both", ordering="ascending"),
+
                 HistoryContext(
                     expected_resp={
                         "fields": [("wt_subject", "a")],
                         "status": 200},
                     delta="-1", start=2, direction="both"),
+
                 HistoryContext(
                     expected_resp={"status": 204},
                     delta="1", start="11", direction="both"),
+
                 HistoryContext(
                     expected_resp={
                         "status": 200,
                         "fields": [("wt_subject", "i"),
                                    ("sign", "cancel-")]},
                     start=8, delta="+1", direction="cancel-"),
+
                 HistoryContext(
                     expected_resp={"status": 204},
                     start=8, delta="+1",
                     direction="cancel-", cancelled="omit"),
+
                 HistoryContext(
                     expected_resp={"status": 204},
                     start=8, delta="-1", direction="cancel-"),
+
                 HistoryContext(
                     expected_resp={"status": 204},
                     delta="+1", direction="cancel+"),
+
                 HistoryContext(expected_resp={"status": 200},
                                delta="-1", direction="debit")):
+
             response = self.client.get(
                 reverse("history", urlconf=urls), ctx.urlargs,
                 **{"HTTP_X_TALER_BANK_USERNAME": "User",
                    "HTTP_X_TALER_BANK_PASSWORD": "Password"})
-            data = response.content.decode("utf-8")
-            try:
-                data = json.loads(data)["data"][0]
-            except (json.JSONDecodeError, KeyError):
-                data = {}
-            self.assertEqual(
-                ctx.expected_resp.get("status"),
-                response.status_code,
-                "Failing request: %s?%s" % \
-                    (response.request["PATH_INFO"],
-                     unquote(response.request["QUERY_STRING"])))
-
-            # extract expected data from response
-            expected_data = {}
-            response_data = {}
-            for key, value in ctx.expected_resp.get("fields", []):
-                response_data.update({key: data.get(key)})
-                expected_data.update({key: value})
-
-            self.assertEqual(expected_data, response_data)
 
+            self.assert_result(response, ctx)
 
 class DBAmountSubtraction(TestCase):
     def setUp(self):
diff --git a/talerbank/app/urls.py b/talerbank/app/urls.py
index c4a543c..d18f971 100644
--- a/talerbank/app/urls.py
+++ b/talerbank/app/urls.py
@@ -38,6 +38,7 @@ urlpatterns = [
     url(r'^accounts/register/$', views.register, name="register"),
     url(r'^profile$', views.profile_page, name="profile"),
     url(r'^history$', views.serve_history, name="history"),
+    url(r'^history-range$', views.serve_history_range, name="history-range"),
     url(r'^reject$', views.reject, name="reject"),
     url(r'^withdraw$', views.withdraw_nojs, name="withdraw-nojs"),
     url(r'^public-accounts$', views.serve_public_accounts,
diff --git a/talerbank/app/views.py b/talerbank/app/views.py
index 2914341..b21b2fe 100644
--- a/talerbank/app/views.py
+++ b/talerbank/app/views.py
@@ -40,6 +40,7 @@ from django.contrib.auth.models import User
 from django.db.models import Q
 from django.http import JsonResponse, HttpResponse
 from django.shortcuts import render, redirect
+from datetime import datetime
 from .models import BankAccount, BankTransaction
 from .amount import Amount
 from .schemas import validate_data
@@ -346,8 +347,6 @@ def pin_tan_question(request):
     return render(request, "pin_tan.html", context)
 
 
-
-
 ##
 # This method serves the user's answer to the math CAPTCHA,
 # and reacts accordingly to its correctness.  If correct (wrong),
@@ -561,9 +560,63 @@ def login_via_headers(view_func):
 
 
 ##
-# Helper function that sorts in a descending, or ascending
-# manner, the history elements returned by the internal routine
-# @a query_history_raw.
+# Build the DB query switch based on the "direction" history
+# argument given by the user.
+#
+# @param bank_account bank account of the user requesting history.
+# @param direction the "direction" URL parameter given by the user.
+#        Note: this values got sanity-checked before this function
+#        is called.
+def direction_switch(bank_account, direction):
+    direction_switch = {
+        "both": (Q(debit_account=bank_account) |
+                 Q(credit_account=bank_account)),
+        "credit": Q(credit_account=bank_account),
+        "debit": Q(debit_account=bank_account),
+        "cancel+": (Q(credit_account=bank_account) &
+                    Q(cancelled=True)),
+        "cancel-": (Q(debit_account=bank_account) &
+                    Q(cancelled=True)),
+    }
+    return direction_switch.get(direction)
+
+##
+# Main routine querying for histories, based on _date ranges_.
+#
+# @param bank_account the bank account object whose
+#        history is being extracted.
+# @param direction takes the following three values,
+#        * debit: only entries where the querying user has _paid_
+#                 will be returned.
+#        * credit: only entries where the querying user _got_
+#                  paid will be returned.
+#        * both: both of the cases above will be returned.
+#        * cancel+: only entries where the querying user cancelled
+#                   the _receiving_ of money will be returned.
+#        * cancel-: only entries where the querying user cancelled
+#                   the _paying_ of money will be returned.
+# @param start timestamp of the oldest element allowed in the
+#        result.
+# @param end timestamp of the youngest element allowed in the
+#        result.
+# @param descending if True, then the results will have the
+#        youngest entry in the first position.
+def query_history_range(bank_account,
+                        direction,
+                        start,
+                        end,
+                        descending):
+    qs = BankTransaction.objects.filter(
+        direction_switch(bank_account, direction),
+        Q(date__gte=start),
+        Q(date__lte=end))
+    
+    order = "-id" if descending else "id"
+    return qs.order_by(order)
+
+
+##
+# Main routine querying for histories.
 #
 # @param bank_account the bank account object whose
 #        history is being extracted.
@@ -595,24 +648,13 @@ def query_history(bank_account,
                   sign,
                   descending=True):
 
-    direction_switch = {
-        "both": (Q(debit_account=bank_account) |
-                 Q(credit_account=bank_account)),
-        "credit": Q(credit_account=bank_account),
-        "debit": Q(debit_account=bank_account),
-        "cancel+": (Q(credit_account=bank_account) &
-                    Q(cancelled=True)),
-        "cancel-": (Q(debit_account=bank_account) &
-                    Q(cancelled=True)),
-    }
-
     sign_filter = {
         "+": Q(id__gt=start),
         "-": Q(id__lt=start),
     }
 
     qs = BankTransaction.objects.filter(
-        direction_switch.get(direction),
+        direction_switch(bank_account, direction),
         sign_filter.get(sign))
     
     order = "-id" if descending else "id"
@@ -620,6 +662,75 @@ def query_history(bank_account,
 
 
 ##
+# Build response object for /history.
+#
+# @param qs the query set for a history request.
+# @param cancelled controls whether we omit/show
+#        cancelled transactions.
+# @param user_account bank account of the user who
+#        asked for the history.
+# @return the history object as specified in the
+#         API reference documentation.
+def build_history_response(qs, cancelled, user_account):
+    history = []
+    for entry in qs:
+        counterpart = entry.credit_account.account_no
+        sign_ = "-"
+        if entry.cancelled and cancelled == "omit":
+            continue
+        if entry.credit_account.account_no == \
+                user_account.bankaccount.account_no:
+            counterpart = entry.debit_account.account_no
+            sign_ = "+"
+        cancel = "cancel" if entry.cancelled else ""
+        sign_ = cancel + sign_
+        history.append(dict(
+            counterpart=counterpart,
+            amount=entry.amount.dump(),
+            sign=sign_,
+            wt_subject=entry.subject,
+            row_id=entry.id,
+            date="/Date("+str(int(entry.date.timestamp()))+")/"))
+    return history
+
+##
+# Serve a request of /history-range.
+#
+# @param request Django-specific HTTP request.
+# @param user_account the account whose history should be gotten.
+# @return Django-specific HTTP response object.
address@hidden
address@hidden
+def serve_history_range(request, user_account):
+    validate_data(request, request.GET.dict())
+
+    # Ordering.
+    ordering = request.GET.get("ordering", "descending")
+
+    # Note: those values got sanity-checked by "validate_data()"
+    start = int(request.GET.get("start"))
+    end = int(request.GET.get("end"))
+    
+    start_td = datetime.fromtimestamp(start)
+    end_td = datetime.fromtimestamp(end)
+
+    qs = query_history_range(user_account.bankaccount,
+                             request.GET.get("direction"),
+                             start_td,
+                             end_td,
+                             "descending" == ordering)
+
+    history = build_history_response(qs,
+                                     request.GET.get("cancelled",
+                                                     "show"),
+                                     user_account)
+    if not history:
+        return HttpResponse(status=204)
+    return JsonResponse(dict(data=history), status=200)
+
+
+
+##
 # Serve a request of /history.
 #
 # @param request Django-specific HTTP request.
@@ -651,26 +762,10 @@ def serve_history(request, user_account):
                        sign,
                        "descending" == ordering)
 
-    history = []
-    cancelled = request.GET.get("cancelled", "show")
-    for entry in qs:
-        counterpart = entry.credit_account.account_no
-        sign_ = "-"
-        if entry.cancelled and cancelled == "omit":
-            continue
-        if entry.credit_account.account_no == \
-                user_account.bankaccount.account_no:
-            counterpart = entry.debit_account.account_no
-            sign_ = "+"
-        cancel = "cancel" if entry.cancelled else ""
-        sign_ = cancel + sign_
-        history.append(dict(
-            counterpart=counterpart,
-            amount=entry.amount.dump(),
-            sign=sign_,
-            wt_subject=entry.subject,
-            row_id=entry.id,
-            date="/Date("+str(int(entry.date.timestamp()))+")/"))
+    history = build_history_response(qs,
+                                     request.GET.get("cancelled",
+                                                     "show"),
+                                     user_account)
     if not history:
         return HttpResponse(status=204)
     return JsonResponse(dict(data=history), status=200)
diff --git a/talerbank/settings.py b/talerbank/settings.py
index 159a24c..539843b 100644
--- a/talerbank/settings.py
+++ b/talerbank/settings.py
@@ -47,6 +47,8 @@ if "demo" == os.environ.get("TALER_ENV_NAME"):
 else:
     DEBUG = True
 
+ADMIN_ENABLED = False
+
 ALLOWED_HOSTS = ["*"]
 
 LOGIN_URL = "login"
@@ -57,7 +59,6 @@ LOGIN_REDIRECT_URL = "index"
 # Application definition
 
 INSTALLED_APPS = [
-    'django.contrib.admin',
     'django.contrib.auth',
     'django.contrib.contenttypes',
     'django.contrib.sessions',
@@ -165,8 +166,10 @@ USE_I18N = True
 
 USE_L10N = True
 
-USE_TZ = True
-
+##
+# Set to False to silence this error:
+# 
https://stackoverflow.com/questions/18622007/runtimewarning-datetimefield-received-a-naive-datetime
+USE_TZ = False
 
 # Static files (CSS, JavaScript, Images)
 # https://docs.djangoproject.com/en/1.9/howto/static-files/
diff --git a/talerbank/urls.py b/talerbank/urls.py
index 62023cc..3ab39b2 100644
--- a/talerbank/urls.py
+++ b/talerbank/urls.py
@@ -16,14 +16,5 @@ Including another URLconf
 """
 from django.contrib.staticfiles.urls import staticfiles_urlpatterns
 from django.conf.urls import url
-from django.contrib import admin
 
-urlpatterns = [
-    url(r'^djangoadmin/', admin.site.urls),
-]
-
-# urlpatterns += [
-#    url(r'^static/(?P<path>.*)$', views.serve),
-# ]
-
-urlpatterns += staticfiles_urlpatterns()
+urlpatterns = staticfiles_urlpatterns()
diff --git a/unused.conf b/unused.conf
new file mode 100644
index 0000000..485ef05
--- /dev/null
+++ b/unused.conf
@@ -0,0 +1,3 @@
+[bank]
+
+database = postgres:///unused

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]