[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-merchant-demos] 02/02: don't use deprecated Python APIs, r
From: |
gnunet |
Subject: |
[taler-taler-merchant-demos] 02/02: don't use deprecated Python APIs, read config from file |
Date: |
Tue, 03 Sep 2024 16:09:38 +0200 |
This is an automated email from the git hooks/post-receive script.
dold pushed a commit to branch master
in repository taler-merchant-demos.
commit 769ea2778ee20d84dd5c3acc98434f4939d6d461
Author: Florian Dold <florian@dold.me>
AuthorDate: Tue Sep 3 16:09:33 2024 +0200
don't use deprecated Python APIs, read config from file
---
talermerchantdemos/blog/blog.py | 300 +++++++++++++++---------------
talermerchantdemos/blog/content.py | 107 ++++++-----
talermerchantdemos/cli.py | 21 +--
talermerchantdemos/donations/donations.py | 65 ++++---
talermerchantdemos/httpcommon/__init__.py | 33 ++--
talermerchantdemos/landing/landing.py | 28 ++-
talermerchantdemos/util/talerconfig.py | 8 +-
7 files changed, 301 insertions(+), 261 deletions(-)
diff --git a/talermerchantdemos/blog/blog.py b/talermerchantdemos/blog/blog.py
index bcd1bb8..d90cce3 100644
--- a/talermerchantdemos/blog/blog.py
+++ b/talermerchantdemos/blog/blog.py
@@ -35,7 +35,7 @@ import time
import sys
from urllib.parse import urljoin, urlencode, urlparse
from ..util.talerconfig import TalerConfig, ConfigurationError
-from ..blog.content import ARTICLES, get_article_file, get_image_file
+from ..blog.content import ARTICLES, get_article_contents
from talermerchantdemos.httpcommon import (
backend_get,
backend_get_with_status,
@@ -48,14 +48,64 @@ from talermerchantdemos.httpcommon import (
get_locale,
)
+if not sys.version_info.major == 3 and sys.version_info.minor >= 6:
+ print("Python 3.6 or higher is required.")
+ print(
+ "You are using Python {}.{}.".format(
+ sys.version_info.major, sys.version_info.minor
+ )
+ )
+ sys.exit(1)
+
+app = flask.Flask(__name__, template_folder="../templates",
static_folder="../static")
+app.wsgi_app = ProxyFix(app.wsgi_app, x_host=1, x_prefix=1)
+app.debug = True
+app.secret_key = base64.b64encode(os.urandom(64)).decode("utf-8")
+
+logging.basicConfig()
+LOGGER = logging.getLogger(__name__)
+
+config_filename = uwsgi.opt["config_filename"].decode("utf-8")
+if config_filename == "":
+ config_filename = None
+
+config = TalerConfig.from_file(config_filename)
+
+CURRENCY = config["taler"]["currency"].value_string(required=True)
+
+ARTICLE_AMOUNT = CURRENCY + ":0.5"
+BACKEND_URL =
config["frontend-demo-blog"]["backend_url"].value_string(required=True)
+APIKEY =
config["frontend-demo-blog"]["backend_apikey"].value_string(required=True)
+
+BABEL_TRANSLATION_DIRECTORIES = "../translations"
+
+app.config.from_object(__name__)
+babel = Babel(app)
+babel.localeselector(get_locale)
+
+LOGGER.info("Using translations from:" +
":".join(list(babel.translation_directories)))
+translations = [str(translation) for translation in babel.list_translations()]
+if not "en" in translations:
+ translations.append("en")
+LOGGER.info(
+ "Operating with the following translations available: " + "
".join(translations)
+)
+
+# Add context processor that will make additional variables
+# and functions available in the template.
+app.context_processor(
+ make_utility_processor("blog",
os.environ.get("TALER_ENV_URL_MERCHANT_BLOG"))
+)
+
+
def req_add_cookie_check():
current_url = list(urllib.parse.urlparse(flask.request.base_url))
args_writable = flask.request.args.copy()
# Adding the used param.
args_writable.update(dict(expect_state="yes"))
- current_url[4] = urllib.parse.urlencode(args_writable)
+ current_url[4] = urllib.parse.urlencode(args_writable)
# Stringify the result.
- return urllib.parse.urlunparse(current_url)
+ return urllib.parse.urlunparse(current_url)
def req_rm_cookie_check():
@@ -63,9 +113,9 @@ def req_rm_cookie_check():
args_writable = flask.request.args.copy()
# Stripping the used param.
args_writable.pop("expect_state")
- current_url[4] = urllib.parse.urlencode(args_writable)
+ current_url[4] = urllib.parse.urlencode(args_writable)
# Stringify the result.
- return urllib.parse.urlunparse(current_url)
+ return urllib.parse.urlunparse(current_url)
def err_abort(abort_status_code, **params):
@@ -91,52 +141,6 @@ def refundable(pay_status):
return True
return False
-if not sys.version_info.major == 3 and sys.version_info.minor >= 6:
- print("Python 3.6 or higher is required.")
- print(
- "You are using Python {}.{}.".format(
- sys.version_info.major, sys.version_info.minor
- )
- )
- sys.exit(1)
-
-app = flask.Flask(__name__, template_folder="../templates",
static_folder="../static")
-app.wsgi_app = ProxyFix(app.wsgi_app, x_host=1, x_prefix=1)
-app.debug = True
-app.secret_key = base64.b64encode(os.urandom(64)).decode("utf-8")
-
-logging.basicConfig()
-LOGGER = logging.getLogger(__name__)
-try:
-
- BACKEND_BASE_URL = uwsgi.opt["backend_url"].decode("utf-8")
- CURRENCY = uwsgi.opt["currency"].decode("utf-8")
- APIKEY = uwsgi.opt["apikey"].decode("utf-8")
-except ConfigurationError as ce:
- print(ce)
- exit(1)
-
-ARTICLE_AMOUNT = CURRENCY + ":0.5"
-BACKEND_URL = urljoin(BACKEND_BASE_URL, "instances/blog/")
-
-BABEL_TRANSLATION_DIRECTORIES = "../translations"
-
-app.config.from_object(__name__)
-babel = Babel(app)
-babel.localeselector(get_locale)
-
-LOGGER.info("Using translations from:" +
":".join(list(babel.translation_directories)))
-translations = [str(translation) for translation in babel.list_translations()]
-if not "en" in translations:
- translations.append("en")
-LOGGER.info(
- "Operating with the following translations available: " + "
".join(translations)
-)
-
-# Add context processor that will make additional variables
-# and functions available in the template.
-app.context_processor(make_utility_processor("blog", os.environ.get
("TALER_ENV_URL_MERCHANT_BLOG")))
-
##
# "Fallback" exception handler to capture all the unmanaged errors.
@@ -162,7 +166,7 @@ def internal_error(e):
def index():
default = "en"
target = flask.request.accept_languages.best_match(translations, default)
- return flask.redirect(url_for ('index') + target + "/", code=302)
+ return flask.redirect(url_for("index") + target + "/", code=302)
##
@@ -301,14 +305,14 @@ def render_article(article_name, lang, data, order_id,
refundable):
)
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 = gettext("Supplemental file ({}) for article ({}) not
found.").format(
- data, article_name
- )
+ #if data in article_info.extra_files:
+ # return flask.send_file(get_image_file(data))
+ #m = gettext("Supplemental file ({}) for article ({}) not
found.").format(
+ # data, article_name
+ #)
err_abort(404, message=m)
# the order_id is needed for refunds
- article_contents = open(get_article_file(article_info)).read()
+ article_contents = get_article_contents(article_info)
return flask.render_template(
"blog-article-frame.html.j2",
page_title=gettext("GNU Taler Demo: Article"),
@@ -387,25 +391,25 @@ def article(article_name, lang=None, data=None):
article_url = flask.request.base_url
if not session_id:
- # If expect_state = yes then session_id should be set already
- # this is a way to check that the client supports cookies
- if maybe_expect_state == "yes":
- error_page = flask.render_template(
- "blog-error.html.j2",
- page_title=gettext("GNU Taler Demo: Error"),
- message=gettext("Please enable cookies."),
- )
- return flask.make_response(error_page, 412)
-
- # first time setting session_id
- # check if browser support cookies with a flag
- session_id = flask.session["session_id"] = str(uuid.uuid4())
- return flask.redirect(req_add_cookie_check(), code=302)
-
+ # If expect_state = yes then session_id should be set already
+ # this is a way to check that the client supports cookies
+ if maybe_expect_state == "yes":
+ error_page = flask.render_template(
+ "blog-error.html.j2",
+ page_title=gettext("GNU Taler Demo: Error"),
+ message=gettext("Please enable cookies."),
+ )
+ return flask.make_response(error_page, 412)
+
+ # first time setting session_id
+ # check if browser support cookies with a flag
+ session_id = flask.session["session_id"] = str(uuid.uuid4())
+ return flask.redirect(req_add_cookie_check(), code=302)
+
# If session is present then we know that cookies are enabled
# remove the flag if present
if maybe_expect_state == "yes":
- return flask.redirect(req_rm_cookie_check(), code=302)
+ return flask.redirect(req_rm_cookie_check(), code=302)
############################
# user has a session and cookie works
@@ -415,66 +419,69 @@ def article(article_name, lang=None, data=None):
# if an order_id is present then render if paid or refunded
if current_order_id is not None:
- status, current_order = backend_get_with_status(
- BACKEND_URL,
- f"private/orders/{current_order_id}",
- params=dict(session_id=session_id),
- auth_token=APIKEY,
- )
-
- if status == 200:
- if current_order.get("order_status") == "paid" and not
current_order.get("refunded"):
- return render_article(
- article_name,
- lang,
- data,
- current_order_id,
- refundable(current_order)
- )
-
- # Checking repurchase case. That happens when the client
- # visits this page in the same session where the article
- # was paid already.
- ai = current_order.get("already_paid_order_id")
- au = current_order.get("already_paid_fulfillment_url")
-
- if ai is not None:
- print("== Merchant says 'see other': ", ai, au)
- response = flask.redirect(article_url)
- response.set_cookie(
- "order_id",
- ai,
- path=urllib.parse.quote(url_for ('index') +
f"essay/{article_name}")
- )
- response.set_cookie(
- "order_id",
- ai,
- path=urllib.parse.quote(url_for ('index') +
f"{lang}/essay/{article_name}")
- )
- return response
-
- # If new_if_refunded == "yes" the user already acknowledge the
- # state of the current order and is asking for a new one.
- if current_order.get("refunded") and new_if_refunded != "yes":
- return flask.render_template(
- "blog-article-refunded.html.j2",
- page_title=gettext("GNU Taler Demo: Refunded"),
- article_name=article_name,
- article_lang=lang,
- order_id=current_order_id,
- )
-
- elif status != 404:
- # not found may be normal, could means that
- # merchant forgot about the order becuase
- # it was a long time without being paid
- raise BackendException(
- message=gettext("Backend returned error status"),
- backend_status=status,
- backend_json=current_order,
+ status, current_order = backend_get_with_status(
+ BACKEND_URL,
+ f"private/orders/{current_order_id}",
+ params=dict(session_id=session_id),
+ auth_token=APIKEY,
)
-
+ if status == 200:
+ if current_order.get("order_status") == "paid" and not
current_order.get(
+ "refunded"
+ ):
+ return render_article(
+ article_name,
+ lang,
+ data,
+ current_order_id,
+ refundable(current_order),
+ )
+
+ # Checking repurchase case. That happens when the client
+ # visits this page in the same session where the article
+ # was paid already.
+ ai = current_order.get("already_paid_order_id")
+ au = current_order.get("already_paid_fulfillment_url")
+
+ if ai is not None:
+ print("== Merchant says 'see other': ", ai, au)
+ response = flask.redirect(article_url)
+ response.set_cookie(
+ "order_id",
+ ai,
+ path=urllib.parse.quote(url_for("index") +
f"essay/{article_name}"),
+ )
+ response.set_cookie(
+ "order_id",
+ ai,
+ path=urllib.parse.quote(
+ url_for("index") + f"{lang}/essay/{article_name}"
+ ),
+ )
+ return response
+
+ # If new_if_refunded == "yes" the user already acknowledge the
+ # state of the current order and is asking for a new one.
+ if current_order.get("refunded") and new_if_refunded != "yes":
+ return flask.render_template(
+ "blog-article-refunded.html.j2",
+ page_title=gettext("GNU Taler Demo: Refunded"),
+ article_name=article_name,
+ article_lang=lang,
+ order_id=current_order_id,
+ )
+
+ elif status != 404:
+ # not found may be normal, could means that
+ # merchant forgot about the order becuase
+ # it was a long time without being paid
+ raise BackendException(
+ message=gettext("Backend returned error status"),
+ backend_status=status,
+ backend_json=current_order,
+ )
+
# Current order is not present or unpaid
# Check if there is a paid but not refunded order in this session
list_resp = backend_get(
@@ -483,12 +490,12 @@ def article(article_name, lang=None, data=None):
params=dict(session_id=session_id, fulfillment_url=article_url,
refunded="no"),
auth_token=APIKEY,
)
-
+
already_paid_order = None
for order in list_resp.get("orders"):
- if order.get("paid"):
- already_paid_order = order
- break
+ if order.get("paid"):
+ already_paid_order = order
+ break
if already_paid_order is not None:
# Found one, now this is the current order.
@@ -498,49 +505,46 @@ def article(article_name, lang=None, data=None):
response.set_cookie(
"order_id",
order_id,
- path=urllib.parse.quote(url_for ('index') +
f"essay/{article_name}")
+ path=urllib.parse.quote(url_for("index") +
f"essay/{article_name}"),
)
response.set_cookie(
"order_id",
order_id,
- path=urllib.parse.quote(url_for ('index') +
f"{lang}/essay/{article_name}")
+ path=urllib.parse.quote(url_for("index") +
f"{lang}/essay/{article_name}"),
)
return response
-
+
############################
# We couln't find a paid order
#
# Note that it could be the case that the user is still paying
# an order with another device, in other browser on the same
- # session or claimed in the same brower.
- # Still, creating an order is cheap and we can safely redirect
+ # session or claimed in the same brower.
+ # Still, creating an order is cheap and we can safely redirect
# to a payment page and relay on repurchase detection to avoid
# double payments.
#
# create a new order and ask for payment
############################
-
+
order_resp = post_order(article_name, article_url, session_id, lang)
order_id = order_resp["order_id"]
token = order_resp["token"]
redirect_url = backend_payment_url(
- BACKEND_URL,
- f"orders/{order_id}",
- session_id,
- token
+ BACKEND_URL, f"orders/{order_id}", session_id, token
)
print("new order URL", redirect_url)
response = flask.redirect(redirect_url)
response.set_cookie(
"order_id",
order_id,
- path=urllib.parse.quote(url_for ('index') + f"essay/{article_name}")
+ path=urllib.parse.quote(url_for("index") + f"essay/{article_name}"),
)
response.set_cookie(
"order_id",
order_id,
- path=urllib.parse.quote(url_for ('index') +
f"{lang}/essay/{article_name}")
+ path=urllib.parse.quote(url_for("index") +
f"{lang}/essay/{article_name}"),
)
return response
diff --git a/talermerchantdemos/blog/content.py
b/talermerchantdemos/blog/content.py
index 1b2a466..1f886c4 100644
--- a/talermerchantdemos/blog/content.py
+++ b/talermerchantdemos/blog/content.py
@@ -21,11 +21,12 @@ import logging
import os
import re
from bs4 import BeautifulSoup
-from pkg_resources import resource_stream, resource_filename
from os import listdir
from os.path import isfile, join
from urllib.parse import quote
+import importlib.resources
+
LOGGER = logging.getLogger(__name__)
NOISY_LOGGER = logging.getLogger("chardet.charsetprober")
@@ -39,6 +40,8 @@ Article = namedtuple("Article", "slug title teaser main_file
extra_files lang")
# articles available in that language.
ARTICLES = {}
+articles_per_lang = {}
+
##
# Add article to the list of the available articles.
@@ -54,28 +57,17 @@ def add_article(slug, title, teaser, main_file,
extra_files, lang="en"):
if not (lang in ARTICLES):
ARTICLES[lang] = OrderedDict()
ARTICLES[lang][slug] = Article(slug, title, teaser, main_file,
extra_files, lang)
+ articles_per_lang.setdefault(lang, 0)
+ articles_per_lang[lang] += 1
##
-# Build the file path of a image.
-#
-# @param image the image filename.
-# @return the path to the image file.
-def get_image_file(image):
- filex = resource_filename("talermerchantdemos", os.path.join("blog/data/",
image))
- return os.path.abspath(filex)
-
-
-##
-# Build the file path of a article.
+# Return contents of an article.
#
# @param article the article filename.
-# @return the path to the article HTML file.
-def get_article_file(article):
- filex = resource_filename(
- "talermerchantdemos", article.main_file,
- )
- return os.path.abspath(filex)
+# @return text contents of the article
+def get_article_contents(article):
+ return article.main_file.read_text()
##
@@ -90,16 +82,14 @@ def get_article_file(article):
# HTML itself, so give it here if a explicit title needs to be
# specified.
def add_from_html(resource_name, lang):
- res = resource_stream("talermerchantdemos", resource_name)
- soup = BeautifulSoup(res, "html.parser")
- res.close()
+ soup = BeautifulSoup(resource_name.read_bytes(), "html.parser")
title_el = soup.find("h2")
if title_el is None:
LOGGER.warning("Cannot extract title from '%s'", resource_name)
return
title = title_el.get_text().strip()
slug = title.replace(" ", "_")
- slug = re.sub(r'[^a-zA-Z0-9_]+', "-", slug)
+ slug = re.sub(r"[^a-zA-Z0-9_]+", "-", slug)
teaser = soup.find("p", attrs={"id": ["teaser"]})
if teaser is None:
@@ -107,7 +97,9 @@ def add_from_html(resource_name, lang):
if len(paragraphs) > 0:
teaser = paragraphs[0].prettify()
if len(teaser) < 100:
- LOGGER.warning("Cannot extract adequate teaser from '%s'",
resource_name)
+ LOGGER.warning(
+ "Cannot extract adequate teaser from '%s'", resource_name
+ )
return
else:
LOGGER.warning("Cannot extract teaser from '%s'", resource_name)
@@ -117,28 +109,53 @@ def add_from_html(resource_name, lang):
re_proc = re.compile("^/[^/][^/]/essay/[^/]+/data/[^/]+$")
imgs = soup.find_all("img")
extra_files = []
- for img in imgs:
- # We require that any image whose access is regulated is src'd
- # as "<slug>/data/img.png". We also need to check if the <slug>
- # component actually matches the article's slug
- if re_proc.match(img["src"]):
- if img["src"].split(os.sep)[2] == slug:
- LOGGER.info(
- "extra file for %s is %s" % (slug,
os.path.basename(img["src"]))
- )
- extra_files.append(os.path.basename(img["src"]))
- else:
- LOGGER.warning(
- "Image src and slug don't match: '%s' != '%s'"
- % (img["src"].split(os.sep)[2], slug)
- )
+ #for img in imgs:
+ # # We require that any image whose access is regulated is src'd
+ # # as "<slug>/data/img.png". We also need to check if the <slug>
+ # # component actually matches the article's slug
+ # if re_proc.match(img["src"]):
+ # if img["src"].split(os.sep)[2] == slug:
+ # LOGGER.info(
+ # "extra file for %s is %s" % (slug,
os.path.basename(img["src"]))
+ # )
+ # extra_files.append(os.path.basename(img["src"]))
+ # else:
+ # LOGGER.warning(
+ # "Image src and slug don't match: '%s' != '%s'"
+ # % (img["src"].split(os.sep)[2], slug)
+ # )
add_article(slug, title, teaser, resource_name, extra_files, lang)
-for l in listdir(resource_filename("talermerchantdemos", "blog/articles/")):
- # Filter by active languages, otherwise this takes quite a while to load...
- if l in {"en", "ar", "zh", "fr", "hi", "it", "ja", "ko", "pt", "pt_BR",
"ru", "tr", "de", "sv", "es"}:
- LOGGER.info("importing %s" % l)
- for a in listdir(resource_filename("talermerchantdemos",
"blog/articles/" + l)):
- if os.path.isfile(resource_filename("talermerchantdemos",
"blog/articles/" + l + "/" + a)):
- add_from_html("blog/articles/" + l + "/" + a, l)
+pkgfiles = importlib.resources.files("talermerchantdemos")
+
+supported_langs = {
+ "en",
+ "ar",
+ "zh",
+ "fr",
+ "hi",
+ "it",
+ "ja",
+ "ko",
+ "pt",
+ "pt_BR",
+ "ru",
+ "tr",
+ "de",
+ "sv",
+ "es",
+}
+
+for l in pkgfiles.joinpath("blog/articles/").iterdir():
+ lang = l.name
+ if lang not in supported_langs:
+ continue
+ LOGGER.info("importing %s" % l)
+ for a in l.iterdir():
+ if not a.is_file():
+ continue
+ # Max 50 articles per language
+ if articles_per_lang.get(lang, 0) > 50:
+ break
+ add_from_html(a, lang)
diff --git a/talermerchantdemos/cli.py b/talermerchantdemos/cli.py
index 4afb13c..93891f9 100644
--- a/talermerchantdemos/cli.py
+++ b/talermerchantdemos/cli.py
@@ -44,9 +44,11 @@ arg_load_python = "--if-not-plugin python --plugins python
--endif".split(" ")
# The effect it to launch the blog HTTP service.
#
# @param args command line options.
-def handle_serve_http(config, which_shop, port=None):
+def handle_serve_http(config_filename, which_shop, port=None):
+ config = TalerConfig.from_file(config_filename)
confsection = f"frontend-demo-{which_shop}"
currency = config["taler"]["currency"].value_string(required=True)
+ cfg_arg = "" if config_filename is None else config_filename
params = [
"uwsgi",
"uwsgi",
@@ -57,23 +59,11 @@ def handle_serve_http(config, which_shop, port=None):
"--log-format",
UWSGI_LOGFMT,
"--set-ph",
- f"currency={currency}",
+ f"config_filename={cfg_arg}",
"--module",
f"talermerchantdemos.{which_shop}:app",
]
- # Only read backend config if necessary
- has_backend = which_shop in ("blog", "donations")
- if has_backend:
- backend_url =
config[confsection]["backend"].value_string(required=True)
- apikey =
config[confsection]["backend_apikey"].value_string(required=True)
- extra = [
- "--set-ph",
- f"backend_url={backend_url}" "--set-ph",
- f"apikey={apikey}",
- ]
- params.extend(extra)
-
# Takes precedence.
if port:
http_serve = "tcp"
@@ -126,8 +116,7 @@ def demos(config, http_port, which_shop):
if which_shop not in ["blog", "donations", "landing"]:
print("Please use a valid shop name: blog, donations, landing.")
sys.exit(1)
- config_obj = TalerConfig.from_file(config)
- handle_serve_http(config_obj, which_shop, http_port)
+ handle_serve_http(config, which_shop, http_port)
demos()
diff --git a/talermerchantdemos/donations/donations.py
b/talermerchantdemos/donations/donations.py
index 1a95f45..125554d 100644
--- a/talermerchantdemos/donations/donations.py
+++ b/talermerchantdemos/donations/donations.py
@@ -54,24 +54,32 @@ app = flask.Flask(__name__, template_folder="../templates",
static_folder="../st
app.wsgi_app = ProxyFix(app.wsgi_app, x_host=1, x_prefix=1)
app.debug = True
app.secret_key = base64.b64encode(os.urandom(64)).decode("utf-8")
-
-try:
- BACKEND_BASE_URL = uwsgi.opt["backend_url"].decode("utf-8")
- CURRENCY = uwsgi.opt["currency"].decode("utf-8")
- APIKEY = uwsgi.opt["apikey"].decode("utf-8")
-except ConfigurationError as ce:
- print(ce)
- exit(1)
+app.config.from_object(__name__)
BABEL_TRANSLATION_DIRECTORIES = "../translations"
-
-app.config.from_object(__name__)
babel = Babel(app)
babel.localeselector(get_locale)
+config_filename = uwsgi.opt["config_filename"].decode("utf-8")
+if config_filename == "":
+ config_filename = None
+config = TalerConfig.from_file(config_filename)
+
+CURRENCY = config["taler"]["currency"].value_string(required=True)
+
+backend_urls = {}
+backend_apikeys = {}
+
+def add_backend(name):
+ backend_urls[name] =
config["frontend-demo-donations"][f"backend_url_{name}"].value_string(required=True)
+ backend_apikeys[name] =
config["frontend-demo-donations"][f"backend_apikey_{name}"].value_string(required=True)
+
+add_backend("tor")
+add_backend("taler")
+add_backend("gnunet")
+
LOGGER.info("Using translations from:" +
":".join(list(babel.translation_directories)))
-LOGGER.info("backend: " + BACKEND_BASE_URL)
LOGGER.info("currency: " + CURRENCY)
translations = [str(translation) for translation in babel.list_translations()]
if not "en" in translations:
@@ -82,7 +90,12 @@ LOGGER.info(
# Add context processor that will make additional variables
# and functions available in the template.
-app.context_processor(make_utility_processor("donations", os.environ.get
("TALER_ENV_URL_MERCHANT_DONATIONS")))
+app.context_processor(
+ make_utility_processor(
+ "donations", os.environ.get("TALER_ENV_URL_MERCHANT_DONATIONS")
+ )
+)
+
##
# Return a error response to the client.
@@ -102,8 +115,7 @@ def err_abort(abort_status_code, **params):
# @return the JSON response from the backend, or a error response
# if something unexpected happens.
def backend_instanced_get(instance, endpoint, params):
- backend_url = urljoin(BACKEND_BASE_URL, f"instances/{instance}/")
- return backend_get(backend_url, endpoint, params, auth_token=APIKEY)
+ return backend_get(backend_urls[instance], endpoint, params,
auth_token=backend_apikeys[instance])
##
@@ -115,8 +127,7 @@ def backend_instanced_get(instance, endpoint, params):
# @param json the POST's body.
# @return the backend response (JSON format).
def backend_instanced_post(instance, endpoint, json):
- backend_url = urljoin(BACKEND_BASE_URL, f"instances/{instance}/")
- return backend_post(backend_url, endpoint, json, auth_token=APIKEY)
+ return backend_post(backend_urls[instance], endpoint, json,
auth_token=backend_apikeys[instance])
##
@@ -142,7 +153,9 @@ def internal_error(e):
return flask.render_template(
"donations-error.html.j2",
page_title=gettext("GNU Taler Demo: Error"),
- message=str(e))
+ message=str(e),
+ )
+
##
# Serve the /favicon.ico requests.
@@ -166,7 +179,7 @@ def favicon():
def index():
default = "en"
target = flask.request.accept_languages.best_match(translations, default)
- return flask.redirect(url_for ('index') + target + "/", code=302)
+ return flask.redirect(url_for("index") + target + "/", code=302)
##
@@ -186,9 +199,9 @@ def start(lang):
)
return flask.render_template(
- "donations-index.html.j2",
+ "donations-index.html.j2",
page_title=gettext("GNU Taler Demo: Donations"),
- merchant_currency=CURRENCY
+ merchant_currency=CURRENCY,
)
@@ -221,9 +234,9 @@ def checkout(lang):
@app.route("/<lang>/provider-not-supported")
def provider_not_supported(lang):
return flask.render_template(
- "donations-provider-not-supported.html.j2",
+ "donations-provider-not-supported.html.j2",
page_title=gettext("GNU Taler Demo: Donations"),
-)
+ )
##
@@ -257,7 +270,7 @@ def donate(lang):
fulfillment_url=fulfillment_url,
summary="Donation to {}".format(donation_receiver),
wire_transfer_deadline=dict(t_s=int(time.time() + 10)),
- minimum_age = 16
+ minimum_age=16,
)
order_resp = backend_instanced_post(
donation_receiver, "private/orders", dict(order=order)
@@ -265,8 +278,8 @@ def donate(lang):
if not order_resp:
return err_abort(
- 500, # FIXME: status code got lost in the httpcommon module.
- message=gettext("Backend could not create the order")
+ 500, # FIXME: status code got lost in the httpcommon module.
+ message=gettext("Backend could not create the order"),
)
order_id = order_resp["order_id"]
@@ -311,5 +324,5 @@ def handler(e):
return flask.render_template(
"donations-error.html.j2",
page_title=gettext("GNU Taler Demo: Error"),
- message=gettext("Page not found")
+ message=gettext("Page not found"),
)
diff --git a/talermerchantdemos/httpcommon/__init__.py
b/talermerchantdemos/httpcommon/__init__.py
index d2238ff..732f06c 100644
--- a/talermerchantdemos/httpcommon/__init__.py
+++ b/talermerchantdemos/httpcommon/__init__.py
@@ -5,13 +5,14 @@ from flask import request, url_for
from datetime import datetime
import time
from flask_babel import gettext
-import babel # used for lang sanity check
+import babel # used for lang sanity check
import os
import re
import logging
LOGGER = logging.getLogger(__name__)
+
class BackendException(Exception):
"""Exception for failed communication with the Taler merchant backend"""
@@ -20,6 +21,7 @@ class BackendException(Exception):
self.backend_status = backend_status
self.backend_json = backend_json
+
##
# POST a request to the backend, and return a error
# response if any error occurs.
@@ -53,11 +55,11 @@ def backend_post(backend_url, endpoint, json,
auth_token=None):
backend_status=resp.status_code,
backend_json=response_json,
)
- print("Backend responds to {}: {}/{}".format(
- final_url,
- str(response_json),
- resp.status_code
- ))
+ print(
+ "Backend responds to {}: {}/{}".format(
+ final_url, str(response_json), resp.status_code
+ )
+ )
return response_json
@@ -78,6 +80,7 @@ def backend_get(backend_url, endpoint, params,
auth_token=None):
)
return json
+
def backend_get_with_status(backend_url, endpoint, params, auth_token=None):
headers = dict()
if auth_token is not None:
@@ -97,6 +100,7 @@ def backend_get_with_status(backend_url, endpoint, params,
auth_token=None):
print("Backend responds to {}: {}".format(final_url, str(response_json)))
return resp.status_code, response_json
+
def get_locale():
parts = request.path.split("/", 2)
if 2 >= len(parts):
@@ -117,21 +121,22 @@ def get_locale():
return "en"
return lang
+
##
# Construct the payment URL where customer can pay the order
#
# @param backend_url where the backend is located
# @param order_id id of the order already created
# @param session_id session in which the order is going to be paid
-# @param token if the order requires a token
+# @param token if the order requires a token
# @return the JSON response from the backend, or a error response
# if something unexpected happens.
def backend_payment_url(backend_url, endpoint, session_id, token):
- final_url = urljoin(backend_url, endpoint)
- query = urlencode({"token":token, "session_id":session_id})
- redirect_url = urlparse(final_url)._replace(query=query)
- return urlunparse(redirect_url)
-
+ final_url = urljoin(backend_url, endpoint)
+ query = urlencode({"token": token, "session_id": session_id})
+ redirect_url = urlparse(final_url)._replace(query=query)
+ return urlunparse(redirect_url)
+
##
# Helper function used inside Jinja2 logic to create a links
@@ -192,7 +197,7 @@ all_languages = {
# Make the environment available into templates.
#
# @return the environment-reading function
-def make_utility_processor(pagename,base_url):
+def make_utility_processor(pagename, base_url):
def utility_processor():
def getactive():
return pagename
@@ -221,7 +226,7 @@ def make_utility_processor(pagename,base_url):
getactive=getactive,
getlang=getlang,
all_languages=all_languages,
- static=static
+ static=static,
)
return utility_processor
diff --git a/talermerchantdemos/landing/landing.py
b/talermerchantdemos/landing/landing.py
index 13c8dc4..b19fd27 100644
--- a/talermerchantdemos/landing/landing.py
+++ b/talermerchantdemos/landing/landing.py
@@ -57,11 +57,15 @@ app.secret_key =
base64.b64encode(os.urandom(64)).decode("utf-8")
logging.basicConfig()
LOGGER = logging.getLogger(__name__)
-try:
- CURRENCY = uwsgi.opt["currency"].decode("utf-8")
-except ConfigurationError as ce:
- print(ce)
- exit(1)
+
+config_filename = uwsgi.opt["config_filename"].decode("utf-8")
+if config_filename == "":
+ config_filename = None
+
+config = TalerConfig.from_file(config_filename)
+
+CURRENCY = config["taler"]["currency"].value_string(required=True)
+
BABEL_TRANSLATION_DIRECTORIES = "../translations"
@@ -80,7 +84,10 @@ LOGGER.info(
# Add context processor that will make additional variables
# and functions available in the template.
-app.context_processor(make_utility_processor("landing", os.environ.get
("TALER_ENV_URL_INTRO")))
+app.context_processor(
+ make_utility_processor("landing", os.environ.get("TALER_ENV_URL_INTRO"))
+)
+
##
# Exception handler to capture all the unmanaged errors.
@@ -120,7 +127,8 @@ def favicon():
def index():
default = "en"
target = flask.request.accept_languages.best_match(translations, default)
- return flask.redirect(url_for ('index') + target + "/", code=302)
+ return flask.redirect(url_for("index") + target + "/", code=302)
+
##
# Serve the internationalized main index page.
@@ -166,13 +174,13 @@ def start(lang):
)
-@app.errorhandler(404) # How to trigger this?
+@app.errorhandler(404) # How to trigger this?
@app.errorhandler(werkzeug.exceptions.NotFound)
def handler_404(e):
return flask.render_template(
- "landing-error.html.j2",
+ "landing-error.html.j2",
page_title=gettext("GNU Taler Demo: Error"),
- message=gettext("Page not found")
+ message=gettext("Page not found"),
)
diff --git a/talermerchantdemos/util/talerconfig.py
b/talermerchantdemos/util/talerconfig.py
index 985979a..9419351 100644
--- a/talermerchantdemos/util/talerconfig.py
+++ b/talermerchantdemos/util/talerconfig.py
@@ -32,6 +32,7 @@ LOGGER = logging.getLogger(__name__)
__all__ = ["TalerConfig"]
+
##
# Exception class for a any configuration error.
class ConfigurationError(Exception):
@@ -100,6 +101,7 @@ def expand(var: str, getter: Callable[[str], str]) -> str:
return result + var[pos:]
+
##
# A configuration entry.
class Entry:
@@ -158,8 +160,10 @@ class Entry:
# @return the value, or the given @a default, if not found.
def value_string(self, default=None, required=False, warn=False) -> str:
if required and self.value is None:
- print("Missing required option '%s' in section '%s'"
- % (self.option.upper(), self.section.upper()))
+ print(
+ "Missing required option '%s' in section '%s'"
+ % (self.option.upper(), self.section.upper())
+ )
sys.exit(1)
if self.value is None:
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.