gnunet-svn
[Top][All Lists]
Advanced

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

[taler-bank] branch master updated: formatting / debugging


From: gnunet
Subject: [taler-bank] branch master updated: formatting / debugging
Date: Thu, 19 Dec 2019 11:15:38 +0100

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

dold pushed a commit to branch master
in repository bank.

The following commit(s) were added to refs/heads/master by this push:
     new 45bb124  formatting / debugging
45bb124 is described below

commit 45bb124b81d94938483a932338137465e6876a91
Author: Florian Dold <address@hidden>
AuthorDate: Thu Dec 19 11:15:19 2019 +0100

    formatting / debugging
---
 talerbank/app/views.py | 261 +++++++++++++++++++++++--------------------------
 1 file changed, 122 insertions(+), 139 deletions(-)

diff --git a/talerbank/app/views.py b/talerbank/app/views.py
index a0a58b1..a8aaa4f 100644
--- a/talerbank/app/views.py
+++ b/talerbank/app/views.py
@@ -49,9 +49,15 @@ import qrcode
 import qrcode.image.svg
 import lxml
 from .schemas import (
-    HistoryParams, HistoryRangeParams, URLParamValidationError, RejectData,
-    AddIncomingData, JSONFieldException, InvalidSession, WithdrawHeadless,
-    WithdrawHeadlessUri
+    HistoryParams,
+    HistoryRangeParams,
+    URLParamValidationError,
+    RejectData,
+    AddIncomingData,
+    JSONFieldException,
+    InvalidSession,
+    WithdrawHeadless,
+    WithdrawHeadlessUri,
 )
 
 LOGGER = logging.getLogger(__name__)
@@ -60,7 +66,7 @@ LOGGER = logging.getLogger(__name__)
 # Constant value for the biggest number the bank handles.
 # This value is just equal to the biggest number that JavaScript
 # can handle (because of the wallet).
-UINT64_MAX = (2**64) - 1
+UINT64_MAX = (2 ** 64) - 1
 
 ##
 # Exception raised upon failing login.
@@ -72,20 +78,23 @@ class LoginFailed(Exception):
         self.http_status_code = 401
         self.taler_error_code = 5109
 
+
 class InvalidInputData(Exception):
     def __init__(self, msg):
         super(InvalidInputData, self).__init__(msg)
-        self.hint = msg # should mention the picked username
+        self.hint = msg  # should mention the picked username
         self.http_status_code = 400
         self.taler_error_code = 5400
 
+
 class UsernameUnavailable(Exception):
     def __init__(self, msg):
         super(UsernameUnavailable, self).__init__(msg)
-        self.hint = msg # should mention the picked username
+        self.hint = msg  # should mention the picked username
         self.http_status_code = 406
         self.taler_error_code = 5400
 
+
 ##
 # Exception raised when the public history from
 # a ordinary user account is tried to be accessed.
@@ -130,6 +139,7 @@ class RejectNoRightsException(Exception):
         self.http_status_code = 403
         self.taler_error_code = 5200
 
+
 class UnhandledException(Exception):
     def __init__(self, msg="Unhandled exception happened!"):
         super(UnhandledException, self).__init__(msg)
@@ -137,6 +147,7 @@ class UnhandledException(Exception):
         self.http_status_code = 500
         self.taler_error_code = 5300
 
+
 ##
 # The authentication for users to log in the bank.
 #
@@ -164,6 +175,7 @@ def ignore(request):
 def decode_body(request):
     return request.body.decode("utf-8")
 
+
 ##
 # Get a flag from the session and clear it.
 #
@@ -194,8 +206,12 @@ def get_session_hint(request, hintId):
 
     return False, False, None
 
+
 def set_profile_hint(request, *, success, failure, hint):
-    set_session_hint(request, "profile_hint", success=success, 
failure=failure, hint=hint)
+    set_session_hint(
+        request, "profile_hint", success=success, failure=failure, hint=hint
+    )
+
 
 def set_session_hint(request, hintId, *, success, failure, hint):
     if hintId in request.session:
@@ -256,8 +272,7 @@ class InputDatalist(forms.TextInput):
         html = super().render(name, value, attrs=attrs, renderer=renderer)
         datalist = '<datalist id="%slist">' % self._name
         for dl_value, dl_text in self._datalist:
-            datalist += '<option value="%s">%s</option>' \
-                % (dl_value, dl_text)
+            datalist += '<option value="%s">%s</option>' % (dl_value, dl_text)
         datalist += "</datalist>"
         return html + datalist
 
@@ -268,8 +283,7 @@ class InputDatalist(forms.TextInput):
 #
 class WTForm(forms.Form):
     amount = forms.FloatField(
-        min_value=0.1,
-        widget=forms.NumberInput(attrs={"class": "currency-input"})
+        min_value=0.1, widget=forms.NumberInput(attrs={"class": 
"currency-input"})
     )
     receiver = forms.IntegerField(
         min_value=1, widget=InputDatalist(predefined_accounts_list, "receiver")
@@ -298,21 +312,18 @@ def profile_page(request):
         wtf = WTForm(request.POST)
         if wtf.is_valid():
             amount_parts = (
-                settings.TALER_CURRENCY, wtf.cleaned_data.get("amount") + 0.0
+                settings.TALER_CURRENCY,
+                wtf.cleaned_data.get("amount") + 0.0,
             )
             wire_transfer(
                 Amount.parse("%s:%s" % amount_parts),
                 BankAccount.objects.get(user=request.user),
-                BankAccount.objects.get(
-                    account_no=wtf.cleaned_data.get("receiver")
-                ), wtf.cleaned_data.get("subject")
+                
BankAccount.objects.get(account_no=wtf.cleaned_data.get("receiver")),
+                wtf.cleaned_data.get("subject"),
             )
 
             set_profile_hint(
-                request,
-                failure=False,
-                success=True,
-                hint="Wire transfer successful!"
+                request, failure=False, success=True, hint="Wire transfer 
successful!"
             )
 
             return redirect("profile")
@@ -330,9 +341,7 @@ def profile_page(request):
         currency=request.user.bankaccount.amount.currency,
         account_no=request.user.bankaccount.account_no,
         wt_form=wtf,
-        history=extract_history(
-            request.user.bankaccount, -1 * (UINT64_MAX / 2 / 2)
-        )
+        history=extract_history(request.user.bankaccount, -1 * (UINT64_MAX / 2 
/ 2)),
     )
     if settings.TALER_SUGGESTED_EXCHANGE:
         context["suggested_exchange"] = settings.TALER_SUGGESTED_EXCHANGE
@@ -397,8 +406,7 @@ def internal_register(request):
     input_data = UserReg(request.POST)
 
     if not input_data.is_valid():
-        msg = "Wrong field(s): %s." % \
-            ", ".join(input_data.errors.keys())
+        msg = "Wrong field(s): %s." % ", ".join(input_data.errors.keys())
         raise InvalidInputData(msg)
 
     username = input_data.cleaned_data["username"]
@@ -409,9 +417,7 @@ def internal_register(request):
 
     # Registration goes through.
     with transaction.atomic():
-        user = User.objects.create_user(
-            username=username,
-            password=password)
+        user = User.objects.create_user(username=username, password=password)
         user_account = BankAccount(user=user)
         user_account.save()
     bank_internal_account = BankAccount.objects.get(account_no=1)
@@ -429,7 +435,8 @@ def internal_register(request):
     wire_transfer(
         Amount(settings.TALER_CURRENCY, 100, 0),
         bank_internal_account,
-        user_account, "Joining bonus"
+        user_account,
+        "Joining bonus",
     )
 
     return user
@@ -479,25 +486,23 @@ def register(request):
 
     except InvalidInputData as e:
         return render(
-            request, "register.html", {
+            request,
+            "register.html",
+            {
                 "wrong": True,
-                "hint": "Wrong field(s): %s." % ", ".join(form.errors.keys())
-            }
+                "hint": "Wrong field(s): %s." % ", ".join(form.errors.keys()),
+            },
         )
 
     except DebitLimitException as e:
         return render(
-            request, "register.html", {
-                "wrong": True,
-                "hint": "Out of business, cannot admit new customers."
-            }
+            request,
+            "register.html",
+            {"wrong": True, "hint": "Out of business, cannot admit new 
customers."},
         )
 
     set_profile_hint(
-        request,
-        success=True,
-        failure=False,
-        hint="Registration successful!"
+        request, success=True, failure=False, hint="Registration successful!"
     )
 
     django.contrib.auth.login(request, user)
@@ -545,7 +550,7 @@ def extract_history(account, delta, start=None):
             counterpart=counterpart.account_no,
             counterpart_username=counterpart.user.username,
             subject=item.subject,
-            date=item.date.strftime("%d/%m/%y %H:%M")
+            date=item.date.strftime("%d/%m/%y %H:%M"),
         )
         history.append(entry)
     return history
@@ -583,7 +588,7 @@ def serve_public_accounts(request, name=None, page=None):
         # and django/python is not allowing slicing with big numbers.
         UINT64_MAX / 2 / 2,
         0,
-        "descending"
+        "descending",
     ).count()
     DELTA = 30
     # '//' operator is NO floating point.
@@ -592,8 +597,9 @@ def serve_public_accounts(request, name=None, page=None):
     public_accounts = BankAccount.objects.filter(is_public=True)
 
     # Retrieve DELTA records younger than 'start_row' (included).
-    history = extract_history(user.bankaccount, DELTA * page,
-                              0)[DELTA * (page - 1):(DELTA * page)]
+    history = extract_history(user.bankaccount, DELTA * page, 0)[
+        DELTA * (page - 1) : (DELTA * page)
+    ]
 
     pages = list(range(1, num_pages + 1))
 
@@ -603,11 +609,9 @@ def serve_public_accounts(request, name=None, page=None):
         forth=page + 1 if page < num_pages else None,
         public_accounts=public_accounts,
         selected_account=dict(
-            name=name,
-            number=user.bankaccount.account_no,
-            history=history,
+            name=name, number=user.bankaccount.account_no, history=history,
         ),
-        pages=pages
+        pages=pages,
     )
     return render(request, "public_accounts.html", context)
 
@@ -640,8 +644,7 @@ def login_via_headers(view_func):
 #        is called.
 def direction_switch(bank_account, direction):
     direction_switch = {
-        "both":
-        (Q(debit_account=bank_account) | Q(credit_account=bank_account)),
+        "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)),
@@ -673,8 +676,7 @@ def direction_switch(bank_account, direction):
 #        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)
+        direction_switch(bank_account, direction), Q(date__gte=start), 
Q(date__lte=end)
     )
 
     order = "-id" if descending else "id"
@@ -720,7 +722,7 @@ def query_history(bank_account, direction, delta, start, 
ordering):
         direction_switch(bank_account, direction), sign_filter
     )
     order = "-id" if "descending" == ordering else "id"
-    return qs.order_by(order)[:abs(delta)]
+    return qs.order_by(order)[: abs(delta)]
 
 
 ##
@@ -740,8 +742,7 @@ def build_history_response(qs, cancelled, user_account):
         sign_ = "-"
         if entry.cancelled and cancelled == "omit":
             continue
-        if entry.credit_account.account_no == \
-                user_account.bankaccount.account_no:
+        if entry.credit_account.account_no == 
user_account.bankaccount.account_no:
             counterpart = entry.debit_account.account_no
             sign_ = "+"
         cancel = "cancel" if entry.cancelled else ""
@@ -753,7 +754,7 @@ def build_history_response(qs, cancelled, user_account):
                 sign=sign_,
                 wt_subject=entry.subject,
                 row_id=entry.id,
-                date="/Date(" + str(int(entry.date.timestamp())) + ")/"
+                date="/Date(" + str(int(entry.date.timestamp())) + ")/",
             )
         )
     return history
@@ -779,12 +780,10 @@ def serve_history_range(request, user_account):
         args.get("direction", "both"),
         start_td,
         end_td,
-        args.get("ordering")
+        args.get("ordering"),
     )
 
-    history = build_history_response(
-        qs, args.get("cancelled", "show"), user_account
-    )
+    history = build_history_response(qs, args.get("cancelled", "show"), 
user_account)
 
     if not history:
         return HttpResponse(status=204)
@@ -806,12 +805,10 @@ def serve_history(request, user_account):
         args.get("direction"),
         args.get("delta"),
         args.get("start", None),
-        args.get("ordering", "descending")
+        args.get("ordering", "descending"),
     )
 
-    history = build_history_response(
-        qs, args.get("cancelled", "show"), user_account
-    )
+    history = build_history_response(qs, args.get("cancelled", "show"), 
user_account)
 
     if not history:
         return HttpResponse(status=204)
@@ -833,9 +830,7 @@ def auth_and_login(request):
     password = request.META.get("HTTP_X_TALER_BANK_PASSWORD")
     if not username or not password:
         raise LoginFailed("missing user/password")
-    return django.contrib.auth.authenticate(
-        username=username, password=password
-    )
+    return django.contrib.auth.authenticate(username=username, 
password=password)
 
 
 ##
@@ -855,8 +850,7 @@ def reject(request, user_account):
     data = RejectData(json.loads(decode_body(request)))
 
     trans = BankTransaction.objects.get(id=data.get("row_id"))
-    if trans.credit_account.account_no != \
-            user_account.bankaccount.account_no:
+    if trans.credit_account.account_no != user_account.bankaccount.account_no:
         raise RejectNoRightsException()
     trans.cancelled = True
     if trans.debit_account.debit:
@@ -865,11 +859,11 @@ def reject(request, user_account):
             # debit_account.amount <= trans.amount
             trans.debit_account.debit = False
             tmp = Amount(**trans.amount.dump())
-            tmp.subtract (trans.debit_account.amount)
-            trans.debit_account.amount.set (**tmp.dump())
+            tmp.subtract(trans.debit_account.amount)
+            trans.debit_account.amount.set(**tmp.dump())
         else:
             # debit_account > trans.amount
-            trans.debit_account.amount.subtract (trans.amount)
+            trans.debit_account.amount.subtract(trans.amount)
     else:
         # balance is positive, simply add
         trans.debit_account.amount.add(trans.amount)
@@ -881,8 +875,8 @@ def reject(request, user_account):
             # credit_account.amount < trans.amount
             trans.credit_account.debit = True
             tmp = Amount(**trans.amount.dump())
-            tmp.subtract (trans.credit_account.amount)
-            trans.credit_account.amount.set (**tmp.dump())
+            tmp.subtract(trans.credit_account.amount)
+            trans.credit_account.amount.set(**tmp.dump())
         else:
             # credit_account.amount >= trans.amount
             trans.credit_account.amount.subtract(trans.amount)
@@ -906,24 +900,20 @@ def add_incoming(request, user_account):
 
     data = AddIncomingData(json.loads(decode_body(request)))
 
-    subject = "%s %s" % (
-        data.get("subject"), data.get("exchange_url")
-    )
+    subject = "%s %s" % (data.get("subject"), data.get("exchange_url"))
 
-    credit_account = BankAccount.objects.get(
-        account_no=data.get("credit_account")
-    )
+    credit_account = 
BankAccount.objects.get(account_no=data.get("credit_account"))
 
     wtrans = wire_transfer(
-        Amount.parse(data.get("amount")), user_account.bankaccount,
-        credit_account, subject
+        Amount.parse(data.get("amount")),
+        user_account.bankaccount,
+        credit_account,
+        subject,
     )
 
-    return JsonResponse({
-        "row_id": wtrans.id,
-        "timestamp": "/Date(%s)/" % int(wtrans.date.timestamp())
-    })
-
+    return JsonResponse(
+        {"row_id": wtrans.id, "timestamp": "/Date(%s)/" % 
int(wtrans.date.timestamp())}
+    )
 
 
 @login_via_headers
@@ -937,9 +927,8 @@ def withdraw_headless_uri(request, user):
     op.save()
     host = request.get_host()
     taler_withdraw_uri = f"taler://withdraw/{host}/-/{op.withdraw_id}"
-    return JsonResponse({
-        "taler_withdraw_uri": taler_withdraw_uri,
-    })
+    return JsonResponse({"taler_withdraw_uri": taler_withdraw_uri,})
+
 
 ##
 # Serves a headless withdrawal request for the Taler protocol.
@@ -950,22 +939,20 @@ def withdraw_headless_uri(request, user):
 @csrf_exempt
 @require_POST
 def withdraw_headless(request, user):
-    
+
     data = WithdrawHeadless(json.loads(decode_body(request)))
-    sender_payto = "payto://x-taler-bank/%s/%d" % \
-        (request.get_host(), user.bankaccount.account_no)
-    ret_obj = ({"sender_wire_details": sender_payto})
+    sender_payto = "payto://x-taler-bank/%s/%d" % (
+        request.get_host(),
+        user.bankaccount.account_no,
+    )
+    ret_obj = {"sender_wire_details": sender_payto}
 
     exchange_payto = data.get("exchange_wire_details")
     if not exchange_payto:
-        exchange_accno = get_acct_from_payto(
-            settings.TALER_SUGGESTED_EXCHANGE_PAYTO
-        )
+        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(
-            exchange_payto
-        )
+        exchange_accno = get_acct_from_payto(exchange_payto)
 
     exchange_bankaccount = BankAccount.objects.get(account_no=exchange_accno)
 
@@ -973,7 +960,7 @@ def withdraw_headless(request, user):
         Amount.parse(data.get("amount")),
         user.bankaccount,
         exchange_bankaccount,
-        data.get("reserve_pub")
+        data.get("reserve_pub"),
     )
 
     return JsonResponse(ret_obj)
@@ -986,9 +973,7 @@ def api_withdraw_operation(request, withdraw_id):
     try:
         op = TalerWithdrawOperation.objects.get(withdraw_id=withdraw_id)
     except ObjectDoesNotExist:
-        return JsonResponse(
-            dict(error="withdraw operation does not exist"), status=404
-        )
+        return JsonResponse(dict(error="withdraw operation does not exist"), 
status=404)
     user_acct_no = op.withdraw_account.account_no
     host = request.get_host()
 
@@ -998,9 +983,7 @@ def api_withdraw_operation(request, withdraw_id):
         try:
             account_no = get_acct_from_payto(exchange_payto_uri)
         except:
-            return JsonResponse(
-                dict(error="exchange payto URI malformed"), status=400
-            )
+            return JsonResponse(dict(error="exchange payto URI malformed"), 
status=400)
         try:
             exchange_acct = BankAccount.objects.get(account_no=account_no)
         except ObjectDoesNotExist:
@@ -1009,9 +992,7 @@ def api_withdraw_operation(request, withdraw_id):
             )
         selected_reserve_pub = data.get("reserve_pub")
         if not isinstance(selected_reserve_pub, str):
-            return JsonResponse(
-                dict(error="reserve_pub must be a string"), status=400
-            )
+            return JsonResponse(dict(error="reserve_pub must be a string"), 
status=400)
         if op.selection_done or op.withdraw_done:
             if (
                 op.selected_exchange_account != exchange_acct
@@ -1019,7 +1000,7 @@ def api_withdraw_operation(request, withdraw_id):
             ):
                 return JsonResponse(
                     dict(error="selection of withdraw parameters already 
done"),
-                    status=409
+                    status=409,
                 )
             # No conflict, same data!
             return JsonResponse(dict(), status=200)
@@ -1038,14 +1019,12 @@ def api_withdraw_operation(request, withdraw_id):
                 sender_wire=f"payto://x-taler-bank/{host}/{user_acct_no}",
                 suggested_exchange=settings.TALER_SUGGESTED_EXCHANGE,
                 confirm_transfer_url=request.build_absolute_uri(
-                    reverse("withdraw-confirm", args=(withdraw_id, ))
-                )
+                    reverse("withdraw-confirm", args=(withdraw_id,))
+                ),
             )
         )
     else:
-        return JsonResponse(
-            dict(error="only GET and POST are allowed"), status=305
-        )
+        return JsonResponse(dict(error="only GET and POST are allowed"), 
status=305)
 
 
 ##
@@ -1097,9 +1076,7 @@ def show_withdrawal(request, withdraw_id):
 def confirm_withdrawal(request, withdraw_id):
     op = TalerWithdrawOperation.objects.get(withdraw_id=withdraw_id)
     if not op.selection_done:
-        raise Exception(
-            "invalid state (withdrawal parameter selection not done)"
-        )
+        raise Exception("invalid state (withdrawal parameter selection not 
done)")
     if op.withdraw_done:
         return redirect("profile")
     if request.method == "POST":
@@ -1107,24 +1084,23 @@ def confirm_withdrawal(request, withdraw_id):
         hashed_solution = request.POST.get("pin_1", "")
         if hashed_attempt != hashed_solution:
             LOGGER.warning(
-                "Wrong CAPTCHA answer: %s vs %s", type(hashed_attempt),
-                type(request.POST.get("pin_1"))
+                "Wrong CAPTCHA answer: %s vs %s",
+                type(hashed_attempt),
+                type(request.POST.get("pin_1")),
             )
-            request.session["captcha_failed"
-                            ] = True, False, "Wrong CAPTCHA answer."
+            request.session["captcha_failed"] = True, False, "Wrong CAPTCHA 
answer."
             return redirect("withdraw-confirm", withdraw_id=withdraw_id)
         op.withdraw_done = True
         op.save()
         wire_transfer(
-            op.amount, BankAccount.objects.get(user=request.user),
-            op.selected_exchange_account, op.selected_reserve_pub
+            op.amount,
+            BankAccount.objects.get(user=request.user),
+            op.selected_exchange_account,
+            op.selected_reserve_pub,
         )
-        
+
         set_profile_hint(
-            request,
-            success=True,
-            failure=False,
-            hint="Withdrawal successful!"
+            request, success=True, failure=False, hint="Withdrawal successful!"
         )
 
         request.session["just_withdrawn"] = True
@@ -1137,7 +1113,7 @@ def confirm_withdrawal(request, withdraw_id):
             hashed_answer=hashed_answer,
             withdraw_id=withdraw_id,
             amount=op.amount.stringify(settings.TALER_DIGITS),
-            exchange=op.selected_exchange_account.user
+            exchange=op.selected_exchange_account.user,
         )
         return render(request, "withdraw_confirm.html", context)
     raise Exception("not reached")
@@ -1153,9 +1129,12 @@ def confirm_withdrawal(request, withdraw_id):
 # @return a @a BankTransaction object.
 def wire_transfer(amount, debit_account, credit_account, subject):
     LOGGER.debug(
-        "%s => %s, %s, %s" % (
-            debit_account.account_no, credit_account.account_no,
-            amount.stringify(2), subject
+        "%s => %s, %s, %s"
+        % (
+            debit_account.account_no,
+            credit_account.account_no,
+            amount.stringify(2),
+            subject,
         )
     )
     if debit_account.pk == credit_account.pk:
@@ -1166,7 +1145,7 @@ def wire_transfer(amount, debit_account, credit_account, 
subject):
         amount=amount,
         credit_account=credit_account,
         debit_account=debit_account,
-        subject=subject
+        subject=subject,
     )
 
     if debit_account.debit:
@@ -1196,12 +1175,16 @@ def wire_transfer(amount, debit_account, 
credit_account, subject):
     threshold = Amount.parse(settings.TALER_MAX_DEBT)
     if debit_account.user.username == "Bank":
         threshold = Amount.parse(settings.TALER_MAX_DEBT_BANK)
-    if Amount.cmp(debit_account.amount, threshold) == 1 \
-            and Amount.cmp(Amount(settings.TALER_CURRENCY),
-                           threshold) != 0 \
-            and debit_account.debit:
+
+    LOGGER.info(
+        f"Account {debit_account.user.username} "
+        + f"(bal {debit_account.amount.stringify()}, thr 
{threshold.stringify()} requested transfer of"
+        + f"{threshold.stringify()} to account {credit_account.user.username}"
+    )
+
+    if Amount.cmp(debit_account.amount, threshold) > 0 and debit_account.debit:
         raise DebitLimitException(
-            f"Aborting payment initiated by '{debit_account.user.username}' 
for debit unallowed"
+            f"Aborting payment initiated by '{debit_account.user.username}', 
debit limit crossed."
         )
 
     with transaction.atomic():

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



reply via email to

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