summaryrefslogtreecommitdiff
path: root/talermerchantdemos/blog/blog.py
diff options
context:
space:
mode:
Diffstat (limited to 'talermerchantdemos/blog/blog.py')
-rw-r--r--talermerchantdemos/blog/blog.py151
1 files changed, 62 insertions, 89 deletions
diff --git a/talermerchantdemos/blog/blog.py b/talermerchantdemos/blog/blog.py
index c8315e5..7112b33 100644
--- a/talermerchantdemos/blog/blog.py
+++ b/talermerchantdemos/blog/blog.py
@@ -34,22 +34,8 @@ import sys
from urllib.parse import urljoin, urlencode, urlparse
from taler.util.talerconfig import TalerConfig, ConfigurationError
from ..blog.content import ARTICLES, get_article_file, get_image_file
-from talermerchantdemos.httpcommon import backend_get, backend_post, fallback_404
-from datetime import datetime
-
-class Deadline:
- def __init__(self, value):
- self.value = value
- def isExpired(self):
- if self.value == "never":
- return False
- now = int(round(time.time()) * 1000)
- now_dt = datetime.fromtimestamp(now / 1000)
- deadline_dt = datetime.fromtimestamp(self.value / 1000)
- print("debug: checking refund expiration, now: {}, deadline: {}".format(
- now_dt.strftime("%c"), deadline_dt.strftime("%c")
- ))
- return now > self.value
+from talermerchantdemos.httpcommon import backend_get, backend_post, self_localized, err_abort, Deadline
+
def refundable(pay_status):
refunded = pay_status.get("refunded")
@@ -99,24 +85,6 @@ translations.append('en')
print("Operating with the following translations available:")
print(translations)
-
-##
-# Helper function used inside Jinja2 logic to create a links
-# to the current page but in a different language. Used to
-# implement the "Language" menu.
-#
-def self_localized(lang):
- """
- Return URL for the current page in another locale.
- """
- path = request.path
- # path must have the form "/$LANG/$STUFF"
- parts = path.split('/', 2)
- if (2 >= len(parts)):
- # Totally unexpected path format, do not localize
- return path
- return "/" + lang + "/" + parts[2]
-
app.jinja_env.globals.update(self_localized=self_localized)
@@ -130,21 +98,10 @@ def utility_processor():
# These helpers will be available in templates
def env(name, default=None):
return os.environ.get(name, default)
-
return dict(env=env)
##
-# Return a error response to the client.
-#
-# @param abort_status_code status code to return along the response.
-# @param params _kw_ arguments to passed verbatim to the templating engine.
-def err_abort(abort_status_code, **params):
- t = flask.render_template("templates/error.html.j2", **params)
- flask.abort(flask.make_response(t, abort_status_code))
-
-
-##
# "Fallback" exception handler to capture all the unmanaged errors.
#
# @param e the Exception object, currently unused.
@@ -153,7 +110,9 @@ def err_abort(abort_status_code, **params):
@app.errorhandler(Exception)
def internal_error(e):
return flask.render_template(
- "templates/error.html.j2", message=gettext("Internal error"), stack=traceback.format_exc()
+ "templates/error.html.j2",
+ message=gettext("Internal error"),
+ stack=traceback.format_exc()
)
@@ -184,8 +143,15 @@ def get_locale():
# @return response object of the index page.
@app.route("/<lang>/")
def start(lang):
+ if lang in ARTICLES:
+ translated=ARTICLES[lang]
+ else:
+ translated={}
return flask.render_template(
- "templates/index.html.j2", lang=lang, merchant_currency=CURRENCY, articles=ARTICLES.values()
+ "templates/index.html.j2",
+ lang=lang,
+ merchant_currency=CURRENCY,
+ articles=translated.values()
)
@@ -198,7 +164,7 @@ def confirm_refund(lang, order_id):
order_status = pay_status.get("order_status")
if order_status != "paid":
err_abort(
- 400, message="Cannot refund unpaid article",
+ 400, message=gettext("Cannot refund unpaid article"),
)
article_name = pay_status["contract_terms"]["extra"]["article_name"]
@@ -223,7 +189,7 @@ def confirm_refund(lang, order_id):
# "refund URL" is returned; then the wallet will run
# the refund protocol in a transparent way.
@app.route("/refund/<order_id>", methods=["POST"])
-def refund(lang, order_id):
+def refund(order_id):
if not order_id:
return flask.jsonify(dict(error="Aborting refund: order unknown")), 400
session_id = flask.session.get("session_id", "")
@@ -234,11 +200,15 @@ def refund(lang, order_id):
if order_status != "paid":
err_abort(
- 402, message="You did not pay for this article (nice try!)", json=pay_status
+ 402,
+ message=gettext("You did not pay for this article (nice try!)"),
+ json=pay_status
)
if not refundable(pay_status):
err_abort(
- 403, message="Item not refundable (anymore)", json=pay_status
+ 403,
+ message=gettext("Item not refundable (anymore)"),
+ json=pay_status
)
refund_spec = dict(reason="Demo reimbursement", refund=ARTICLE_AMOUNT)
resp = backend_post(BACKEND_URL, f"private/orders/{order_id}/refund", refund_spec)
@@ -249,6 +219,7 @@ def refund(lang, order_id):
# Render the article after a successful purchase.
#
# @param article_name _slugged_ (= spaces converted to underscores) article title.
+# @param lang language the article is to be in
# @param data image filename to return along the article.
# @param order_id the ID of the order where this article got purchased.
# (Will be put in the refund-request form action, since any article
@@ -258,15 +229,15 @@ def refund(lang, order_id):
# - 404: supplemental @a data not found.
# In the successful case, a response object carrying the
# article in it will be returned.
-def render_article(article_name, data, order_id, refundable):
- article_info = ARTICLES.get(article_name)
+def render_article(article_name, lang, data, order_id, refundable):
+ article_info = ARTICLES[lang].get(article_name)
if article_info is None:
- m = "Internal error: Files for article ({}) not found.".format(article_name)
+ m = gettext("Internal error: Files for article ({}) not found.").format(article_name)
err_abort(500, message=m)
if data is not None:
if data in article_info.extra_files:
return flask.send_file(get_image_file(data))
- m = "Supplemental file ({}) for article ({}) not found.".format(
+ m = gettext("Supplemental file ({}) for article ({}) not found.").format(
data, article_name
)
err_abort(404, message=m)
@@ -276,6 +247,7 @@ def render_article(article_name, data, order_id, refundable):
article_file=get_article_file(article_info),
article_name=article_name,
order_id=order_id,
+ lang=lang,
refundable=refundable
)
@@ -291,6 +263,7 @@ def post_order(article_name,lang):
extra=dict(article_name=article_name,lang=lang),
fulfillment_url=flask.request.base_url,
summary="Essay: " + article_name.replace("_", " "),
+ # FIXME: add support for i18n of summary!
# 10 minutes time for a refund
wire_transfer_deadline=dict(t_ms=1000 * int(time.time() + 15 * 30)),
)
@@ -300,25 +273,6 @@ def post_order(article_name,lang):
dict(order=order, refund_delay=dict(d_ms=1000 * 120)))
return order_resp
-##
-# Setup a fresh order with the backend.
-#
-# @param article_name which article the order is for
-# @param lang which language to use
-#
-def post_order(article_name,lang):
- order = dict(
- amount=ARTICLE_AMOUNT,
- extra=dict(article_name=article_name,lang=lang),
- fulfillment_url=flask.request.base_url,
- summary="Essay: " + article_name.replace("_", " "),
- # 10 minutes time for a refund
- refund_deadline=dict(t_ms=1000 * int(time.time() + 10 * 30)),
- wire_transfer_deadline=dict(t_ms=1000 * int(time.time() + 15 * 30)),
- )
- order_resp = backend_post(BACKEND_URL, "private/orders", dict(order=order))
- return order_resp
-
##
# Trigger a article purchase. The logic follows the main steps:
@@ -356,23 +310,27 @@ def article(article_name, lang=None, data=None):
# First-timer; generate order first.
if not order_id:
if not lang:
- err_abort(403, message="Direct access forbidden")
+ err_abort(403, message=gettext("Direct access forbidden"))
order_resp = post_order(article_name,lang)
order_id = order_resp["order_id"]
# Ask the backend for the status of the payment
pay_status = backend_get(
- BACKEND_URL, f"private/orders/{order_id}", params=dict(session_id=session_id)
+ BACKEND_URL,
+ f"private/orders/{order_id}",
+ params=dict(session_id=session_id)
)
order_status = pay_status.get("order_status")
if order_status == "claimed":
if not lang:
- err_abort(403, message="Direct access forbidden")
+ err_abort(403, message=gettext("Direct access forbidden"))
# Order already claimed, must setup fresh order
order_resp = post_order(article_name,lang)
order_id = order_resp["order_id"]
pay_status = backend_get(
- BACKEND_URL, f"private/orders/{order_id}", params=dict(session_id=session_id)
+ BACKEND_URL,
+ f"private/orders/{order_id}",
+ params=dict(session_id=session_id)
)
order_status = pay_status.get("order_status")
# This really must be 'unpaid' now...
@@ -385,12 +343,12 @@ def article(article_name, lang=None, data=None):
article_name=article_name,
order_id=order_id,
)
- response = render_article(article_name, data, order_id, refundable(pay_status))
- response.set_cookie(
- "order_id", order_id, path=urllib.parse.quote(f"/essay/{article_name}")
- )
- response.set_cookie(
- "order_id", order_id, path=urllib.parse.quote(f"/{lang}/essay/{article_name}")
+ response = render_article(
+ article_name,
+ lang,
+ data,
+ order_id,
+ refundable(pay_status)
)
return response
@@ -401,7 +359,14 @@ def article(article_name, lang=None, data=None):
if ai is not None and au is not None:
response = flask.redirect(au)
response.set_cookie(
- "order_id", ai, path=urllib.parse.quote(f"/essay/{article_name}")
+ "order_id",
+ ai,
+ path=urllib.parse.quote(f"/essay/{article_name}")
+ )
+ response.set_cookie(
+ "order_id",
+ ai,
+ path=urllib.parse.quote(f"/{lang}/essay/{article_name}")
)
return response
@@ -409,19 +374,27 @@ def article(article_name, lang=None, data=None):
# run the payment protocol.
response = flask.redirect(pay_status["order_status_url"])
response.set_cookie(
- "order_id", order_id, path=urllib.parse.quote(f"/essay/{article_name}")
+ "order_id",
+ order_id,
+ path=urllib.parse.quote(f"/essay/{article_name}")
)
response.set_cookie(
- "order_id", order_id, path=urllib.parse.quote(f"/{lang}/essay/{article_name}")
+ "order_id",
+ order_id,
+ path=urllib.parse.quote(f"/{lang}/essay/{article_name}")
)
return response
@app.errorhandler(500)
def handler(e):
return flask.render_template(
- "templates/error.html.j2", message=gettext("Internal server error"))
+ "templates/error.html.j2",
+ message=gettext("Internal server error")
+ )
@app.errorhandler(404)
def handler(e):
return flask.render_template(
- "templates/error.html.j2", message=gettext("Page not found"))
+ "templates/error.html.j2",
+ message=gettext("Page not found")
+ )