gnunet-svn
[Top][All Lists]
Advanced

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

[taler-bank] branch master updated (46c04a7 -> b00298b)


From: gnunet
Subject: [taler-bank] branch master updated (46c04a7 -> b00298b)
Date: Tue, 21 Jan 2020 16:54:53 +0100

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

dold pushed a change to branch master
in repository bank.

    from 46c04a7  allow/deny registrations based on config
     new 523591e  transfer API idempotency
     new b00298b  transfer API idempotency

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 talerbank/app/migrations/0001_initial.py | 104 ++++++---------------------
 talerbank/app/models.py                  |   1 +
 talerbank/app/tests.py                   |   2 +
 talerbank/app/views.py                   | 119 ++++++++++++++++++-------------
 4 files changed, 97 insertions(+), 129 deletions(-)

diff --git a/talerbank/app/migrations/0001_initial.py 
b/talerbank/app/migrations/0001_initial.py
index 91c0e98..73a5206 100644
--- a/talerbank/app/migrations/0001_initial.py
+++ b/talerbank/app/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-# Generated by Django 3.0.2 on 2020-01-13 12:57
+# Generated by Django 3.0.2 on 2020-01-21 15:47
 
 from django.conf import settings
 from django.db import migrations, models
@@ -17,95 +17,37 @@ class Migration(migrations.Migration):
 
     operations = [
         migrations.CreateModel(
-            name="BankAccount",
+            name='BankAccount',
             fields=[
-                ("is_public", models.BooleanField(default=False)),
-                ("account_no", models.AutoField(primary_key=True, 
serialize=False)),
-                (
-                    "balance",
-                    talerbank.app.models.SignedAmountField(
-                        default=talerbank.app.models.get_zero_signed_amount
-                    ),
-                ),
-                (
-                    "user",
-                    models.OneToOneField(
-                        on_delete=django.db.models.deletion.CASCADE,
-                        to=settings.AUTH_USER_MODEL,
-                    ),
-                ),
+                ('is_public', models.BooleanField(default=False)),
+                ('account_no', models.AutoField(primary_key=True, 
serialize=False)),
+                ('balance', 
talerbank.app.models.SignedAmountField(default=talerbank.app.models.get_zero_signed_amount)),
+                ('user', 
models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, 
to=settings.AUTH_USER_MODEL)),
             ],
         ),
         migrations.CreateModel(
-            name="TalerWithdrawOperation",
+            name='TalerWithdrawOperation',
             fields=[
-                (
-                    "withdraw_id",
-                    models.UUIDField(
-                        default=uuid.uuid4,
-                        editable=False,
-                        primary_key=True,
-                        serialize=False,
-                    ),
-                ),
-                ("amount", talerbank.app.models.AmountField(default=False)),
-                ("selection_done", models.BooleanField(default=False)),
-                ("withdraw_done", models.BooleanField(default=False)),
-                ("selected_reserve_pub", models.TextField(null=True)),
-                (
-                    "selected_exchange_account",
-                    models.ForeignKey(
-                        null=True,
-                        on_delete=django.db.models.deletion.CASCADE,
-                        related_name="selected_exchange_account",
-                        to="app.BankAccount",
-                    ),
-                ),
-                (
-                    "withdraw_account",
-                    models.ForeignKey(
-                        on_delete=django.db.models.deletion.CASCADE,
-                        related_name="withdraw_account",
-                        to="app.BankAccount",
-                    ),
-                ),
+                ('withdraw_id', models.UUIDField(default=uuid.uuid4, 
editable=False, primary_key=True, serialize=False)),
+                ('amount', talerbank.app.models.AmountField(default=False)),
+                ('selection_done', models.BooleanField(default=False)),
+                ('withdraw_done', models.BooleanField(default=False)),
+                ('selected_reserve_pub', models.TextField(null=True)),
+                ('selected_exchange_account', models.ForeignKey(null=True, 
on_delete=django.db.models.deletion.CASCADE, 
related_name='selected_exchange_account', to='app.BankAccount')),
+                ('withdraw_account', 
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, 
related_name='withdraw_account', to='app.BankAccount')),
             ],
         ),
         migrations.CreateModel(
-            name="BankTransaction",
+            name='BankTransaction',
             fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                ("amount", talerbank.app.models.AmountField(default=False)),
-                (
-                    "subject",
-                    models.CharField(default="(no subject given)", 
max_length=200),
-                ),
-                ("date", models.DateTimeField(auto_now=True, db_index=True)),
-                ("cancelled", models.BooleanField(default=False)),
-                (
-                    "credit_account",
-                    models.ForeignKey(
-                        on_delete=django.db.models.deletion.CASCADE,
-                        related_name="credit_account",
-                        to="app.BankAccount",
-                    ),
-                ),
-                (
-                    "debit_account",
-                    models.ForeignKey(
-                        on_delete=django.db.models.deletion.CASCADE,
-                        related_name="debit_account",
-                        to="app.BankAccount",
-                    ),
-                ),
+                ('id', models.AutoField(auto_created=True, primary_key=True, 
serialize=False, verbose_name='ID')),
+                ('amount', talerbank.app.models.AmountField(default=False)),
+                ('subject', models.CharField(default='(no subject given)', 
max_length=200)),
+                ('date', models.DateTimeField(auto_now=True, db_index=True)),
+                ('cancelled', models.BooleanField(default=False)),
+                ('request_uid', models.CharField(max_length=128, unique=True)),
+                ('credit_account', 
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, 
related_name='credit_account', to='app.BankAccount')),
+                ('debit_account', 
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, 
related_name='debit_account', to='app.BankAccount')),
             ],
         ),
     ]
diff --git a/talerbank/app/models.py b/talerbank/app/models.py
index 08da111..3833c22 100644
--- a/talerbank/app/models.py
+++ b/talerbank/app/models.py
@@ -192,6 +192,7 @@ class BankTransaction(models.Model):
     subject = models.CharField(default="(no subject given)", max_length=200)
     date = models.DateTimeField(auto_now=True, db_index=True)
     cancelled = models.BooleanField(default=False)
+    request_uid = models.CharField(max_length=128, unique=True)
 
 
 class TalerWithdrawOperation(models.Model):
diff --git a/talerbank/app/tests.py b/talerbank/app/tests.py
index 83a8fb8..ad792b7 100644
--- a/talerbank/app/tests.py
+++ b/talerbank/app/tests.py
@@ -183,6 +183,7 @@ class RegisterTestCase(TestCase):
         clear_db()
 
     def test_register(self):
+        setattr(settings, "ALLOW_REGISTRATIONS", True)
         client = Client()
         response = client.post(
             reverse("register", urlconf=urls),
@@ -194,6 +195,7 @@ class RegisterTestCase(TestCase):
         self.assertEqual(200, response.status_code)
 
     def test_register_headless(self):
+        setattr(settings, "ALLOW_REGISTRATIONS", True)
         client = Client()
 
         # Normal case.
diff --git a/talerbank/app/views.py b/talerbank/app/views.py
index 9cd941d..f3fdbcc 100644
--- a/talerbank/app/views.py
+++ b/talerbank/app/views.py
@@ -27,6 +27,7 @@ import random
 import re
 import time
 import base64
+import uuid
 from urllib.parse import urlparse
 import django.contrib.auth
 import django.contrib.auth.views
@@ -716,22 +717,25 @@ def serve_history(request, user_account):
 
     return JsonResponse(dict(data=history), status=200)
 
+
 def expect_json_body_str(request, param_name):
-    body = json.loads(request.body) # FIXME: cache!
+    body = json.loads(request.body)  # FIXME: cache!
     val = body[param_name]
     if not isinstance(val, str):
         # FIXME: throw right exception to be handled by middleware
         raise Exception(f"expected string for {param_name}")
     return val
 
+
 def expect_json_body_amount(request, param_name):
-    body = json.loads(request.body) # FIXME: cache!
+    body = json.loads(request.body)  # FIXME: cache!
     val = body[param_name]
     if not isinstance(val, str):
         # FIXME: throw right exception to be handled by middleware
         raise Exception(f"expected string for {param_name}")
     return Amount.parse(val)
 
+
 def expect_param_str(request, param_name):
     val = request.GET[param_name]
     if not isinstance(val, str):
@@ -770,24 +774,23 @@ def twg_add_incoming(request, user_account, acct_id):
 
     if acct_id != user_account.username:
         # FIXME: respond nicely
-        raise Exception(f"credentials do not match URL ('{acct_id}' vs 
'{user_account.username}')")
+        raise Exception(
+            f"credentials do not match URL ('{acct_id}' vs 
'{user_account.username}')"
+        )
 
     reserve_pub = expect_json_body_str(request, "reserve_pub")
     debit_account_payto = expect_json_body_str(request, "debit_account")
     amount = expect_json_body_amount(request, "amount")
 
     debit_account_name = get_acct_from_payto(debit_account_payto)
-    print(f"adding incoming balance to exchange ({acct_id}) from account 
{debit_account_payto} ({debit_account_name})")
+    print(
+        f"adding incoming balance to exchange ({acct_id}) from account 
{debit_account_payto} ({debit_account_name})"
+    )
     debit_user = User.objects.get(username=debit_account_name)
     debit_account = BankAccount.objects.get(user=debit_user)
     subject = f"{reserve_pub}"
 
-    wtrans = wire_transfer(
-        amount,
-        debit_account,
-        exchange_account,
-        subject,
-    )
+    wtrans = wire_transfer(amount, debit_account, exchange_account, subject,)
 
     return JsonResponse(
         {
@@ -809,7 +812,9 @@ def twg_transfer(request, user_account, acct_id):
 
     if acct_id != user_account.username:
         # FIXME: respond nicely
-        raise Exception(f"credentials do not match URL ('{acct_id}' vs 
'{user_account.username}')")
+        raise Exception(
+            f"credentials do not match URL ('{acct_id}' vs 
'{user_account.username}')"
+        )
 
     request_uid = expect_json_body_str(request, "request_uid")
     wtid = expect_json_body_str(request, "wtid")
@@ -823,17 +828,14 @@ def twg_transfer(request, user_account, acct_id):
     except User.DoesNotExist:
         LOGGER.error(f"credit account '{credit_account_name}' does not exist")
         # FIXME: use EC from taler-util library
-        return JsonResponse(dict(code=5110, error="credit account does not 
exist"), status=404)
+        return JsonResponse(
+            dict(code=5110, error="credit account does not exist"), status=404
+        )
     credit_account = BankAccount.objects.get(user=credit_user)
 
     subject = f"{wtid} {exchange_base_url}"
 
-    wtrans = wire_transfer(
-        amount,
-        exchange_account,
-        credit_account,
-        subject,
-    )
+    wtrans = wire_transfer(amount, exchange_account, credit_account, subject, 
request_uid)
 
     return JsonResponse(
         {
@@ -853,6 +855,7 @@ def get_payto_from_account(request, acct):
     h = get_plain_host(request)
     return f"payto://x-taler-bank/{h}/{acct.user.username}"
 
+
 @require_GET
 @login_via_headers
 def twg_history_incoming(request, user_account, acct_id):
@@ -863,21 +866,18 @@ def twg_history_incoming(request, user_account, acct_id):
         start = None
     else:
         start = int(start_str)
-    qs = query_history(
-        user_account.bankaccount,
-        "credit",
-        delta,
-        start,
-    )
+    qs = query_history(user_account.bankaccount, "credit", delta, start,)
     for item in qs:
-        history.append(dict(
-            row_id=item.id,
-            amount=item.amount.stringify(settings.TALER_DIGITS),
-            date=dict(t_ms=(int(item.date.timestamp()) * 1000)),
-            reserve_pub=item.subject, # fixme: parse/truncate?
-            credit_account=get_payto_from_account(request, 
item.credit_account),
-            debit_account=get_payto_from_account(request, item.debit_account),
-        ))
+        history.append(
+            dict(
+                row_id=item.id,
+                amount=item.amount.stringify(settings.TALER_DIGITS),
+                date=dict(t_ms=(int(item.date.timestamp()) * 1000)),
+                reserve_pub=item.subject,  # fixme: parse/truncate?
+                credit_account=get_payto_from_account(request, 
item.credit_account),
+                debit_account=get_payto_from_account(request, 
item.debit_account),
+            )
+        )
     return JsonResponse(dict(incoming_transactions=history), status=200)
 
 
@@ -891,24 +891,21 @@ def twg_history_outgoing(request, user_account, acct_id):
         start = None
     else:
         start = int(start_str)
-    qs = query_history(
-        user_account.bankaccount,
-        "debit",
-        delta,
-        start,
-    )
+    qs = query_history(user_account.bankaccount, "debit", delta, start,)
     for item in qs:
         # FIXME: proper parsing, more structure in subject
         wtid, exchange_base_url = item.subject.split(" ")
-        history.append(dict(
-            row_id=item.id,
-            amount=item.amount.stringify(settings.TALER_DIGITS),
-            date=dict(t_ms=(int(item.date.timestamp()) * 1000)),
-            wtid=wtid,
-            exchange_base_url=exchange_base_url,
-            credit_account=get_payto_from_account(request, 
item.credit_account),
-            debit_account=get_payto_from_account(request, item.debit_account),
-        ))
+        history.append(
+            dict(
+                row_id=item.id,
+                amount=item.amount.stringify(settings.TALER_DIGITS),
+                date=dict(t_ms=(int(item.date.timestamp()) * 1000)),
+                wtid=wtid,
+                exchange_base_url=exchange_base_url,
+                credit_account=get_payto_from_account(request, 
item.credit_account),
+                debit_account=get_payto_from_account(request, 
item.debit_account),
+            )
+        )
     return JsonResponse(dict(outgoing_transactions=history), status=200)
 
 
@@ -1152,7 +1149,7 @@ def confirm_withdrawal(request, withdraw_id):
     raise Exception("not reached")
 
 
-def wire_transfer(amount, debit_account, credit_account, subject):
+def wire_transfer(amount, debit_account, credit_account, subject, 
request_uid=None):
     """
     Make a wire transfer between two accounts of this demo bank.
     """
@@ -1160,6 +1157,31 @@ def wire_transfer(amount, debit_account, credit_account, 
subject):
         LOGGER.error("Debit and credit account are the same!")
         raise SameAccountException()
 
+    if request_uid is None:
+        request_uid = str(uuid.uuid4())
+        pass
+    else:
+        # check for existing transfer
+        try:
+            etx = BankTransaction.objects.get(request_uid=request_uid)
+        except BankTransaction.DoesNotExist:
+            # We're good, no existing transaction with the same request_uid 
exists
+            pass
+        else:
+            if (
+                etx.amount != amount
+                or etx.debit_account != debit_account
+                or etx.credit_account != debit_account
+                or etx.subject != subject
+            ):
+                return JsonResponse(
+                    data=dict(
+                        hint="conflicting transfer with same request_uid 
exists",
+                        ec=5600,
+                    ),
+                    status=409,
+                )
+
     LOGGER.debug(
         "transfering %s => %s, %s, %s"
         % (
@@ -1175,6 +1197,7 @@ def wire_transfer(amount, debit_account, credit_account, 
subject):
         credit_account=credit_account,
         debit_account=debit_account,
         subject=subject,
+        request_uid=request_uid,
     )
 
     if debit_account.user.username == "Bank":

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



reply via email to

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