summaryrefslogtreecommitdiff
path: root/talermerchantdemos/landing/landing.py
diff options
context:
space:
mode:
Diffstat (limited to 'talermerchantdemos/landing/landing.py')
-rw-r--r--talermerchantdemos/landing/landing.py164
1 files changed, 164 insertions, 0 deletions
diff --git a/talermerchantdemos/landing/landing.py b/talermerchantdemos/landing/landing.py
new file mode 100644
index 0000000..6bc4249
--- /dev/null
+++ b/talermerchantdemos/landing/landing.py
@@ -0,0 +1,164 @@
+##
+# This file is part of GNU TALER.
+# Copyright (C) 2017, 2020 Taler Systems SA
+#
+# TALER is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free Software
+# Foundation; either version 2.1, or (at your option) any later version.
+#
+# TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License along with
+# GNU TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+#
+# @author Christian Grothoff
+# @brief Minimal Website for the landing page.
+
+import os
+import re
+import datetime
+import base64
+import logging
+from urllib.parse import urljoin
+import flask
+from flask import request
+from flask_babel import Babel
+from flask_babel import refresh
+from flask_babel import force_locale
+from flask_babel import gettext
+import traceback
+from taler.util.talerconfig import TalerConfig, ConfigurationError
+from ..httpcommon import backend_get, backend_post, self_localized
+import sys
+
+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)
+
+BASE_DIR = os.path.dirname(os.path.abspath(__file__))
+app = flask.Flask(__name__, template_folder=BASE_DIR)
+app.debug = True
+app.secret_key = base64.b64encode(os.urandom(64)).decode('utf-8')
+
+LOGGER = logging.getLogger(__name__)
+TC = TalerConfig.from_env()
+try:
+ BACKEND_URL = TC["frontends"]["backend"].value_string(required=True)
+ CURRENCY = TC["taler"]["currency"].value_string(required=True)
+ APIKEY = TC["frontends"]["backend_apikey"].value_string(required=True)
+except ConfigurationError as ce:
+ print(ce)
+ exit(1)
+
+app.config.from_object(__name__)
+babel = Babel(app)
+
+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))
+
+app.jinja_env.globals.update(self_localized=self_localized)
+
+@babel.localeselector
+def get_locale():
+ parts = request.path.split('/', 2)
+ if (2 >= len(parts)):
+ # Totally unexpected path format, do not localize
+ return "en"
+ lang = parts[1]
+ if lang in translations:
+ return lang
+ return "en"
+
+##
+# Make the environment available into templates.
+#
+# @return the environment-reading function.
+@app.context_processor
+def utility_processor():
+ def env(name, default=None):
+ return os.environ.get(name, default)
+
+ def prettydate(talerdate):
+ parsed_time = re.search(r"/Date\(([0-9]+)\)/", talerdate)
+ if not parsed_time:
+ return "malformed date given"
+ parsed_time = int(parsed_time.group(1))
+ timestamp = datetime.datetime.fromtimestamp(parsed_time)
+ # returns the YYYY-MM-DD date format.
+ return timestamp.strftime("%Y-%b-%d")
+
+ return dict(env=env, prettydate=prettydate)
+
+
+##
+# Exception handler to capture all the unmanaged errors.
+#
+# @param e the Exception object, currently unused.
+# @return flask-native response object carrying the error message
+# (and execution stack!).
+@app.errorhandler(Exception)
+def internal_error(e):
+ return flask.render_template(
+ "templates/error.html.j2",
+ message=gettext("Internal error"),
+ stack=traceback.format_exc(),
+ lang=get_locale()
+ )
+
+##
+# Serve the /favicon.ico requests.
+#
+# @return the favicon.ico file.
+@app.route("/favicon.ico")
+def favicon():
+ LOGGER.info("will look into: " + os.path.join(app.root_path, 'static'))
+ return flask.send_from_directory(
+ os.path.join(app.root_path, 'static'),
+ "favicon.ico",
+ mimetype="image/vnd.microsoft.ico"
+ )
+
+
+##
+# Serve the main index page, redirecting to /<lang>/
+#
+# @return response object of the index page.
+@app.route("/")
+def index():
+ default = 'en'
+ target = flask.request.accept_languages.best_match(translations, default)
+ return flask.redirect("/" + target + "/", code=302)
+
+##
+# Serve the internationalized main index page.
+#
+# @return response object of the index page.
+@app.route("/<lang>/", methods=["GET"])
+def start(lang):
+ return flask.render_template(
+ "templates/index.html.j2",
+ merchant_currency=CURRENCY,
+ lang=lang
+ )
+
+@app.errorhandler(404)
+def handler(e):
+ return flask.render_template(
+ "templates/error.html.j2",
+ message=gettext("Page not found"),
+ lang=get_locale()
+ )
+
+@app.errorhandler(405)
+def handler(e):
+ return flask.render_template(
+ "templates/error.html.j2",
+ message=gettext("HTTP method not allowed for this page"),
+ lang=get_locale()
+ )