[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] [taler-bank] branch stable updated (3756eec -> d662aac),
gnunet <=