diff options
author | Marcello Stanisci <stanisci.m@gmail.com> | 2019-03-07 22:58:09 +0100 |
---|---|---|
committer | Marcello Stanisci <stanisci.m@gmail.com> | 2019-03-07 22:58:09 +0100 |
commit | b050cbfe71367529354c91f2a8a5fe48f52fa317 (patch) | |
tree | 74fc88ebcd43be7e64173b6d92613ccde104d644 /talerbank/app/views.py | |
parent | eec9e0e50bd0530b447f5549e33454939b76dc4f (diff) | |
download | bank-b050cbfe71367529354c91f2a8a5fe48f52fa317.tar.gz bank-b050cbfe71367529354c91f2a8a5fe48f52fa317.tar.bz2 bank-b050cbfe71367529354c91f2a8a5fe48f52fa317.zip |
Doxygen-commenting views.py.
Diffstat (limited to 'talerbank/app/views.py')
-rw-r--r-- | talerbank/app/views.py | 255 |
1 files changed, 210 insertions, 45 deletions
diff --git a/talerbank/app/views.py b/talerbank/app/views.py index a9a33ee..150436d 100644 --- a/talerbank/app/views.py +++ b/talerbank/app/views.py @@ -116,9 +116,6 @@ def ignore(request): # @param name name of the session value that should be retrieved. # @return the value, if found; otherwise False. def get_session_flag(request, name): - """ - Get a flag from the session and clear it. - """ if name in request.session: ret = request.session[name] del request.session[name] @@ -136,9 +133,6 @@ def get_session_flag(request, name): # @param name hint name # @return the hint (a "null" one if none was found) def get_session_hint(request, name): - """ - Get a hint from the session and clear it. - """ if name in request.session: ret = request.session[name] del request.session[name] @@ -188,7 +182,12 @@ class InputDatalist(forms.TextInput): # @param self the object itself # @param name the name of the value that will be sent # along the POST - # @param FIXME. + # @param value value to be sent along the @a name. + # @param attrs a dict indicating which HTML attribtues should + # be defined in the rendered element. + # @param renderer render engine (left as None, typically); it + # is a class that respects the low-level render API from + # Django, see [2] def render(self, name, value, attrs=None, renderer=None): html = super().render( name, value, attrs=attrs, renderer=renderer) @@ -200,8 +199,11 @@ class InputDatalist(forms.TextInput): return html + datalist +## +# Form for sending wire transfers. It usually appears in the +# user profile page. +# class WTForm(forms.Form): - '''Form used to wire transfer money internally in the bank.''' amount = forms.FloatField( min_value=0.1, widget=forms.NumberInput(attrs={"class": "currency-input"})) @@ -210,9 +212,22 @@ class WTForm(forms.Form): widget=InputDatalist(predefined_accounts_list, "receiver")) subject = forms.CharField() -# Check if user's logged in. Check if he/she has withdrawn or -# registered; render profile page. + +## +# This method serves the profile page, which is the main +# page where the user interacts with the bank, and also the +# page that the user gets after a successful login. It has +# to handle the following cases: (1) the user requests the +# profile page after haing POSTed a wire transfer request. +# (2) The user requests the page after having withdrawn coins, +# that means that a wire transfer has been issued to the exchange. +# In this latter case, the method has to notify the wallet about +# the operation outcome. (3) Ordinary GET case, where the +# straight page should be returned. +# +# @param request Django-specific HTTP request object. +# @return Django-specific HTTP response object. @login_required def profile_page(request): if request.method == "POST": @@ -258,12 +273,24 @@ def profile_page(request): return response +## +# Helper function that hashes its input. Usually +# used to hash the response to the math CAPTCHA. +# +# @param ans the plain text answer to hash. +# @return the hashed version of @a ans. def hash_answer(ans): hasher = hashlib.new("sha1") hasher.update(settings.SECRET_KEY.encode("utf-8")) hasher.update(ans.encode("utf-8")) return hasher.hexdigest() + +## +# Helper function that makes CAPTCHA's question and +# answer pair. +# +# @return the question and (hashed) answer pair. def make_question(): num1 = random.randint(1, 10) operand = random.choice(("*", "+", "-")) @@ -280,6 +307,16 @@ def make_question(): return question, hash_answer(answer) + + +## +# This method build the page containing the math CAPTCHA that +# protects coins withdrawal. It takes all the values from the +# URL and puts them into the state, for further processing after +# a successful answer from the user. +# +# @param request Django-specific HTTP request object +# @return Django-specific HTTP response object @require_GET @login_required def pin_tan_question(request): @@ -310,6 +347,13 @@ 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), +# it redirects the user to the profile page showing a success +# (failure) message into the informational bar. @require_POST @login_required def pin_tan_verify(request): @@ -334,15 +378,25 @@ def pin_tan_verify(request): request.session["just_withdrawn"] = True return redirect("profile") + + +## +# Class representing the registration form. class UserReg(forms.Form): username = forms.CharField() password = forms.CharField(widget=forms.PasswordInput()) + +## +# This method serves the request for registering a user. +# If successful, it redirects the user to their profile page; +# otherwise it will show again the same form (currently, without +# displaying _any_ error/warning message.) +# +# @param request Django-specific HTTP request object. +# @return Django-specific HTTP response object. def register(request): - """ - register a new user giving 100 KUDOS bonus - """ if request.method != "POST": return render(request, "register.html") form = UserReg(request.POST) @@ -376,15 +430,35 @@ def register(request): return redirect("profile") + +## +# Logs the user out, redirecting it to the bank's homepage. +# +# @param request Django-specific HTTP request object. +# @return Django-specific HTTP response object. def logout_view(request): - """ - Log out the user and redirect to index page. - """ django.contrib.auth.logout(request) request.session["login_hint"] = False, True, "Logged out!" return redirect("index") + +## +# Build the history array. +# +# @param account the bank account object whose history is being +# extracted. +# @param descending currently not used. +# @param delta how many history entries will be contained in the +# array (will be passed as-is to the internal routine +# @a query_history). +# @param start any history will be searched starting from this +# value (which is a row ID), and going to the past or to +# the future (depending on the user choice). However, this +# value itself will not be included in the history. +# @param sign this value ("+"/"-") determines whether the history +# entries will be younger / older than @a start. +# @return the history array. def extract_history(account, descending, delta=None, @@ -413,6 +487,15 @@ def extract_history(account, return history + +## +# Serve the page showing histories from publicly visible accounts. +# +# @param request Django-specific HTTP request object. +# @param name name of the public account to show. +# @param page given that public histories are paginated, this +# value is the page number to display in the response. +# @return Django-specific HTTP response object. def serve_public_accounts(request, name=None, page=None): try: page = abs(int(page)) @@ -460,7 +543,14 @@ def serve_public_accounts(request, name=None, page=None): ) return render(request, "public_accounts.html", context) - +## +# Decorator function that authenticates requests by fetching +# the credentials over the HTTP requests headers. +# +# @param view_func function that will be called after the +# authentication, and that will usually serve the requested +# endpoint. +# @return FIXME. def login_via_headers(view_func): def _decorator(request, *args, **kwargs): user_account = auth_and_login(request) @@ -470,23 +560,35 @@ def login_via_headers(view_func): return view_func(request, user_account, *args, **kwargs) return wraps(view_func)(_decorator) -# Internal function used by /history and /public-accounts. It -# offers abstraction against the query string definition and DB -# querying. -# -# 'bank_account': whose history is going to be retrieved. -# 'direction': (both|credit|debit|cancel+|cancel-). -# 'delta': how many results are going to be extracted. If 'None' -# is given, no filter of this kind will be applied. -# 'start': a "id" indicating the first record to be returned. -# If -1 is given, then the first record will be the youngest -# and 'delta' records will be returned, _regardless_ of the -# 'sign' being passed. -# 'sign': (+|-) indicating that we want records younger|older -# than 'start'. -# 'descending': records are sorted older->younger per default, -# unless this value is true. +## +# Helper function that sorts in a descending, or ascending +# manner, the history elements returned by the internal routine +# @a query_history_raw. +# +# @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 delta how many history entries will be contained in the +# array (will be passed as-is to the internal routine +# @a query_history). +# @param start any history will be searched starting from this +# value (which is a row ID), and going to the past or to +# the future (depending on the user choice). However, this +# value itself will not be included in the history. +# @param sign this value ("+"/"-") determines whether the history +# entries will be younger / older than @a start. +# @param descending if True, then the results will have the +# youngest entry in the first position. def query_history(bank_account, direction, delta, @@ -503,6 +605,29 @@ def query_history(bank_account, return qs.order_by(order)[:delta] + +## +# Core routine for querying the history of a customer. +# +# @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 any history will be searched starting from this +# value (which is a row ID), and going to the past or to +# the future (depending on the user choice). However, this +# value itself will not be included in the history. +# @param sign this value ("+"/"-") determines whether the history +# entries will be younger / older than @a start. +# @return the query set (that will be typically further processed). def query_history_raw(bank_account, direction, start, sign): direction_switch = { "both": (Q(debit_account=bank_account) | @@ -516,7 +641,7 @@ def query_history_raw(bank_account, direction, start, sign): } sign_filter = { - "+": Q(id__gt=start), + "+": Q(id__gt=start), # default "-": Q(id__lt=start), } @@ -525,13 +650,15 @@ def query_history_raw(bank_account, direction, start, sign): sign_filter.get(sign)); +## +# Serve a request of /history. +# +# @param request Django-specific HTTP request. +# @param user_account the account whose history should be gotten. +# @return Django-specific HTTP response object. @require_GET @login_via_headers def serve_history(request, user_account): - """ - This API is used to get a list of transactions related to one - user. - """ validate_data(request, request.GET.dict()) # delta parsed_delta = re.search(r"([\+-])?([0-9]+)", @@ -572,6 +699,14 @@ def serve_history(request, user_account): return HttpResponse(status=204) return JsonResponse(dict(data=history), status=200) + +## +# Helper function that authenticates a user by fetching the +# credentials from the HTTP headers. Typically called from +# decorators. +# +# @param request Django-specific HTTP request object. +# @return Django-specific "authentication object". def auth_and_login(request): """Return user instance after checking authentication credentials, False if errors occur""" @@ -595,6 +730,16 @@ def auth_and_login(request): username=username, password=password) + + +## +# Serve a request of /reject (for rejecting wire transfers). +# +# @param request Django-specific HTTP request object. +# @param user_account the account that is going to reject the +# transfer. Used to check whether they have this right +# or not (only accounts which _got_ payed can cancel the +# transaction.) @transaction.atomic @csrf_exempt @require_http_methods(["PUT", "POST"]) @@ -613,17 +758,19 @@ def reject(request, user_account): return HttpResponse(status=204) + +## +# Serve a request to make a wire transfer. Allows fintech +# providers to issues payments in a programmatic way. +# +# @param request Django-specific HTTP request object. +# @param user_account the (authenticated) user issuing this +# request. +# @return Django-specific HTTP response object. @csrf_exempt @require_POST @login_via_headers def add_incoming(request, user_account): - """ - Internal API used by exchanges to notify the bank - of incoming payments. - - This view is CSRF exempt, since it is not used from - within the browser, and only over the private admin interface. - """ data = json.loads(request.body.decode("utf-8")) validate_data(request, data) subject = "%s %s" % (data["subject"], data["exchange_url"]) @@ -638,6 +785,15 @@ def add_incoming(request, user_account): "timestamp": "/Date(%s)/" % int(wtrans.date.timestamp())}) + + +## +# Serve a Taler withdrawal request; takes the amount chosen +# by the user, and builds a response to trigger the wallet into +# the withdrawal protocol +# +# @param request Django-specific HTTP request. +# @return Django-specific HTTP response object. @login_required @require_POST def withdraw_nojs(request): @@ -660,6 +816,14 @@ def withdraw_nojs(request): settings.TALER_SUGGESTED_EXCHANGE return response + +## +# Make a wire transfer between two accounts (internal to the bank) +# +# @param amount how much money the wire transfer is worth. +# @param debit_account the account that gives money. +# @param credit_account the account that receives money. +# @return a @a BankTransaction object. def wire_transfer(amount, debit_account, credit_account, subject): LOGGER.debug("%s => %s, %s, %s" % @@ -722,3 +886,4 @@ def wire_transfer(amount, debit_account, credit_account, return transaction_item # [1] https://stackoverflow.com/questions/24783275/django-form-with-choices-but-also-with-freetext-option +# [2] https://docs.djangoproject.com/en/2.1/ref/forms/renderers/#low-level-widget-render-api |