gnunet-svn
[Top][All Lists]
Advanced

[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.



reply via email to

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