[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] [taler-bank] branch master updated: introducing headless wi
From: |
gnunet |
Subject: |
[GNUnet-SVN] [taler-bank] branch master updated: introducing headless withdrawal |
Date: |
Sun, 30 Jun 2019 20:55:36 +0200 |
This is an automated email from the git hooks/post-receive script.
marcello pushed a commit to branch master
in repository bank.
The following commit(s) were added to refs/heads/master by this push:
new 24e28e0 introducing headless withdrawal
24e28e0 is described below
commit 24e28e0bfab5d75166bb11e9682fb6079cceb9d7
Author: Marcello Stanisci <address@hidden>
AuthorDate: Sun Jun 30 20:55:26 2019 +0200
introducing headless withdrawal
---
bank-check.conf | 2 +-
talerbank/app/middleware.py | 4 +-
talerbank/app/models.py | 2 +-
talerbank/app/schemas.py | 11 +++++-
talerbank/app/tests.py | 93 ++++++++++++++++++++++++++++++++++++++++++++-
talerbank/app/urls.py | 2 +-
talerbank/app/views.py | 45 +++++++++++++++++-----
talerbank/settings.py | 2 +
8 files changed, 144 insertions(+), 17 deletions(-)
diff --git a/bank-check.conf b/bank-check.conf
index 65be040..b977fd9 100644
--- a/bank-check.conf
+++ b/bank-check.conf
@@ -18,4 +18,4 @@ MAX_DEBT_BANK = KUDOS:0.0
UWSGI_SERVE = unix
UWSGI_UNIXPATH = /tmp/banktest-unused.uwsgi
UWSGI_UNIXPATH_MODE = 660
-
+SUGGESTED_EXCHANGE_PAYTO = payto://x-taler-bank/bank.example.com/2
diff --git a/talerbank/app/middleware.py b/talerbank/app/middleware.py
index d7c3775..e2ba00b 100644
--- a/talerbank/app/middleware.py
+++ b/talerbank/app/middleware.py
@@ -73,7 +73,6 @@ class ExceptionMiddleware:
BankTransaction.DoesNotExist: 1,
SameAccountException: 2,
DebitLimitException: 3,
-
##
# FIXME: needs own error code.
InvalidSession: 0,
@@ -96,6 +95,7 @@ class ExceptionMiddleware:
# to generate exceptions.
self.apis = {
"/withdraw": 5400,
+ "/taler/withdraw": 5500,
"/reject": 5300,
"/history": 5200,
"/admin/add/incoming": 5100}
@@ -159,7 +159,7 @@ class ExceptionMiddleware:
# 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
+ # field with 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:
diff --git a/talerbank/app/models.py b/talerbank/app/models.py
index e617aba..b930030 100644
--- a/talerbank/app/models.py
+++ b/talerbank/app/models.py
@@ -26,7 +26,7 @@ from django.conf import settings
from django.core.exceptions import \
ValidationError, \
ObjectDoesNotExist
-from .amount import Amount, BadFormatAmount, NumberTooBig
+from .amount import Amount, BadFormatAmount, NumberTooBig, CurrencyMismatch
class InvalidAmount(Amount):
def __init__(self, currency):
diff --git a/talerbank/app/schemas.py b/talerbank/app/schemas.py
index db2ce7b..ee79abe 100644
--- a/talerbank/app/schemas.py
+++ b/talerbank/app/schemas.py
@@ -177,11 +177,20 @@ class HistoryRangeParams(HistoryParamsBase):
start = forms.IntegerField()
class PaytoField(forms.Field):
- # TODO: try removing this method.
+ def __init__(self, **kwargs):
+ super().__init__(**kwargs)
+
def to_python(self, value):
return value
def validate(self, value):
+
+ # The request misses this, default exchange
+ # will be used. NOTE: experience showed that the
+ # "required=False" argument given when init the object
+ # does NOT prevent this function from being called!
+ if not value:
+ return
wire_uri = urlparse(value)
if "payto" != wire_uri.scheme:
raise ValidationError("URL is not 'payto'")
diff --git a/talerbank/app/tests.py b/talerbank/app/tests.py
index 9a14498..80ddeb2 100644
--- a/talerbank/app/tests.py
+++ b/talerbank/app/tests.py
@@ -184,6 +184,7 @@ class RegisterTestCase(TestCase):
def test_register_headless(self):
client = Client()
+ # Normal case.
response = client.post(reverse("register-headless", urlconf=urls),
{"username": "test_register_headless",
"password": "password*+#@"})
@@ -193,12 +194,13 @@ class RegisterTestCase(TestCase):
self.assertTrue(self.client.login(username="test_register_headless",
password="password*+#@"))
+ # Try registering unavailable username.
response = client.post(reverse("register-headless", urlconf=urls),
{"username": "test_register_headless",
"password": "password"})
self.assertEqual(409, response.status_code)
- # NOTE: Django 2.2.2 allows ANY character!
+ # NOTE: Django 2.2.2 allows ANY character! Is this normal?
response = client.post(reverse("register-headless", urlconf=urls),
{"username": "'''+++;;;'''",
"password": "password2"})
@@ -300,6 +302,93 @@ class RejectTestCase(TestCase):
self.assertEqual(response.status_code, 204)
+class WithdrawHeadlessTestCase(TestCase):
+
+ def setUp(self):
+ BankAccount(
+ user=User.objects.create_user(
+ username="headless_wallet",
+ password="headless_password"),
+ amount=Amount(settings.TALER_CURRENCY, 10)).save()
+ # Gets account #2, in line with config.
+ BankAccount(user=User.objects.create_user(
+ username="normal_exchange",
+ password="normal_password")).save()
+
+ def test_withdraw_headless(self):
+ client = Client()
+
+ # Use default exchange.
+ data = '{"auth": {"type": "basic"}, \
+ "reserve_pub": "RESERVEPUB", \
+ "amount": "%s:10"}' % settings.TALER_CURRENCY
+ response = client.post(
+ reverse("withdraw-headless", urlconf=urls),
+ data=data,
+ content_type="application/json",
+ follow=True,
+ **{"HTTP_X_TALER_BANK_USERNAME": "headless_wallet",
+ "HTTP_X_TALER_BANK_PASSWORD": "headless_password"})
+ self.assertEqual(200, response.status_code)
+
+ # Try withdrawing more than owning.
+ data = '{"auth": {"type": "basic"}, \
+ "reserve_pub": "RESERVEPUB", \
+ "amount": "%s:100"}' % settings.TALER_CURRENCY
+ response = client.post(
+ reverse("withdraw-headless", urlconf=urls),
+ data=data,
+ content_type="application/json",
+ follow=True,
+ **{"HTTP_X_TALER_BANK_USERNAME": "headless_wallet",
+ "HTTP_X_TALER_BANK_PASSWORD": "headless_password"})
+ self.assertEqual(406, response.status_code)
+
+ # Try withdrawing giving exchange field.
+ data = '{"auth": {"type": "basic"}, \
+ "exchange_wire_details":
"payto://x-taler-bank/bank.example.com/2", \
+ "reserve_pub": "RESERVEPUB", \
+ "amount": "%s:0.4"}' % settings.TALER_CURRENCY
+ response = client.post(
+ reverse("withdraw-headless", urlconf=urls),
+ data=data,
+ content_type="application/json",
+ follow=True,
+ **{"HTTP_X_TALER_BANK_USERNAME": "headless_wallet",
+ "HTTP_X_TALER_BANK_PASSWORD": "headless_password"})
+ self.assertEqual(200, response.status_code)
+
+ # Try withdrawing giving non-existent recipient.
+ data = '{"auth": {"type": "basic"}, \
+ "exchange_wire_details":
"payto://x-taler-bank/bank.example.com/2222", \
+ "reserve_pub": "RESERVEPUB", \
+ "amount": "%s:0.4"}' % settings.TALER_CURRENCY
+ response = client.post(
+ reverse("withdraw-headless", urlconf=urls),
+ data=data,
+ content_type="application/json",
+ follow=True,
+ **{"HTTP_X_TALER_BANK_USERNAME": "headless_wallet",
+ "HTTP_X_TALER_BANK_PASSWORD": "headless_password"})
+ self.assertEqual(404, response.status_code)
+
+ # Try withdrawing giving invalid JSON.
+ data = '{"auth": {"type": "basic"}, \
+ "XXX": "YYY", \
+ "amount": "%s:0.4"}' % settings.TALER_CURRENCY
+ response = client.post(
+ reverse("withdraw-headless", urlconf=urls),
+ data=data,
+ content_type="application/json",
+ follow=True,
+ **{"HTTP_X_TALER_BANK_USERNAME": "headless_wallet",
+ "HTTP_X_TALER_BANK_PASSWORD": "headless_password"})
+ self.assertEqual(400, response.status_code)
+
+ def tearDown(self):
+ clear_db()
+
+
class AddIncomingTestCase(TestCase):
"""Test money transfer's API"""
@@ -372,7 +461,7 @@ class AddIncomingTestCase(TestCase):
follow=True,
**{"HTTP_X_TALER_BANK_USERNAME": "user_user",
"HTTP_X_TALER_BANK_PASSWORD": "user_password"})
- self.assertEqual(403, response.status_code)
+ self.assertEqual(406, response.status_code)
# Try use a non-existent recipient.
data = '{"auth": {"type": "basic"}, \
"credit_account": 1987, \
diff --git a/talerbank/app/urls.py b/talerbank/app/urls.py
index 8a2d1e5..d9b4491 100644
--- a/talerbank/app/urls.py
+++ b/talerbank/app/urls.py
@@ -42,7 +42,7 @@ urlpatterns = [
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'^taler/withdraw$', views.withdraw_nojs, name="withdraw-headless"),
+ url(r'^taler/withdraw$', views.withdraw_headless,
name="withdraw-headless"),
url(r'^public-accounts$', views.serve_public_accounts,
name="public-accounts"),
url(r'^public-accounts/(?P<name>[a-zA-Z0-9]+)$',
diff --git a/talerbank/app/views.py b/talerbank/app/views.py
index e868a4b..dbf8940 100644
--- a/talerbank/app/views.py
+++ b/talerbank/app/views.py
@@ -49,7 +49,7 @@ from .schemas import \
URLParamValidationError, RejectData,
AddIncomingData, JSONFieldException,
PinTanParams, InvalidSession,
- WithdrawSessionData)
+ WithdrawSessionData, WithdrawHeadless)
LOGGER = logging.getLogger(__name__)
@@ -81,13 +81,12 @@ class PrivateAccountException(Exception):
hint = "The selected account is private"
http_status_code = 402
-
##
# Exception raised when some financial operation goes
# beyond the limit threshold.
class DebitLimitException(Exception):
- hint = "Debit too high, operation forbidden."
- http_status_code = 403
+ hint = "Insufficient credit, operation not acceptable."
+ http_status_code = 406
##
# Exception raised when some financial operation is
@@ -320,11 +319,10 @@ def make_question():
question = "{} {} {}".format(num1, operand, num2)
return question, hash_answer(answer)
-
def get_acct_from_payto(uri_str: str) -> int:
wire_uri = urlparse(uri_str)
if wire_uri.scheme != "payto":
- raise Exception("wire URI must be a payto URI")
+ raise Exception("Bad Payto URI: '%s'" % uri_str)
return int(wire_uri.path.split("/")[-1])
@@ -923,10 +921,39 @@ def add_incoming(request, user_account):
@login_via_headers
@csrf_exempt
@require_POST
-def withdraw_headless(request):
- pass
+def withdraw_headless(request, user):
+ data = json.loads(request.body.decode("utf-8"))
+ data = WithdrawHeadless(data)
+
+ sender_payto = "payto://x-taler-bank/%s/%d" % \
+ (request.get_host(), user.bankaccount.account_no)
+ ret_obj = (
+ {"sender_wire_details": sender_payto})
+
+ if not data.is_valid():
+ raise JSONFieldException(data.errors, 400)
+
+ # Pick default exchange.
+ if None == data.cleaned_data["exchange_wire_details"]:
+ exchange_accno = get_acct_from_payto(
+ settings.TALER_SUGGESTED_EXCHANGE_PAYTO)
+ ret_obj.update(
+ exchange_url=settings.TALER_SUGGESTED_EXCHANGE)
+ else:
+ exchange_accno = get_acct_from_payto(
+ data.cleaned_data["exchange_wire_details"])
+ exchange_bankaccount = BankAccount.objects.get(
+ account_no=exchange_accno)
+ wire_transfer(
+ Amount.parse(data.cleaned_data["amount"]),
+ user.bankaccount,
+ exchange_bankaccount,
+ data.cleaned_data["reserve_pub"])
+
+ return JsonResponse(ret_obj)
+
##
# Serve a Taler withdrawal request; takes the amount chosen
# by the user, and builds a response to trigger the wallet into
@@ -959,7 +986,7 @@ def withdraw_nojs(request):
##
# Make a wire transfer between two accounts (internal to the bank)
#
-# @param amount how much money the wire transfer is worth.
+# @param amount (object type) how much money the wire transfer is worth.
# FIXME: a check about whether this value is zero is missing
# @param debit_account the account that gives money.
# @param credit_account the account that receives money.
diff --git a/talerbank/settings.py b/talerbank/settings.py
index f3f099d..44fcf70 100644
--- a/talerbank/settings.py
+++ b/talerbank/settings.py
@@ -209,3 +209,5 @@ TALER_EXPECTS_DONATIONS = [
'Tor', 'GNUnet', 'Taler', 'FSF']
TALER_SUGGESTED_EXCHANGE = TC.value_string(
"bank", "suggested_exchange")
+TALER_SUGGESTED_EXCHANGE_PAYTO = TC.value_string(
+ "bank", "suggested_exchange_payto")
--
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 master updated: introducing headless withdrawal,
gnunet <=