summaryrefslogtreecommitdiff
path: root/src/koszko_org_website/app.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/koszko_org_website/app.py')
-rw-r--r--src/koszko_org_website/app.py159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/koszko_org_website/app.py b/src/koszko_org_website/app.py
new file mode 100644
index 0000000..e3e6339
--- /dev/null
+++ b/src/koszko_org_website/app.py
@@ -0,0 +1,159 @@
+# SPDX-License-Identifier: CC0-1.0
+
+# koszko.org website logic.
+
+# Copyright (C) 2021, 2022 Wojtek Kosior
+
+import gettext
+import dataclasses as dc
+import typing as t
+
+from pathlib import Path, PurePosixPath
+
+import flask
+import werkzeug
+import jinja2
+import jinja2.exceptions
+
+
+here = Path(__file__).resolve().parent
+
+
+pages = {
+ 'index.html'
+}
+
+
+langs_short_2_long = {
+ 'en': 'en_US',
+ 'pl': 'pl_PL'
+}
+
+langs_long_2_short = dict((v, k) for k, v in langs_short_2_long.items())
+
+default_locale = 'pl_PL'
+
+
+def raise_exception(msg) -> t.NoReturn:
+ raise Exception(msg)
+
+
+@dc.dataclass(init=False)
+class Website(flask.Flask):
+ def __init__(self) -> None:
+ super().__init__(__name__)
+
+ self.jinja_options = {
+ **self.jinja_options,
+ 'loader': jinja2.PackageLoader(__package__),
+ 'autoescape': jinja2.select_autoescape(['.jinja']),
+ 'lstrip_blocks': True,
+ 'extensions': [
+ *self.jinja_options.get('extensions', []),
+ 'jinja2.ext.i18n',
+ 'jinja2.ext.do'
+ ]
+ }
+
+ self.jinja_env.globals['raise'] = raise_exception
+
+ def koszko_install_translations(self, locale: str) -> None:
+ translations = gettext.translation(
+ 'messages',
+ localedir = here / 'locales',
+ languages = [locale]
+ )
+ self.jinja_env.install_gettext_translations(translations)
+
+
+website_app = Website()
+
+
+def show_page(lang_short: str, page_path: str) -> str:
+ for segment in PurePosixPath(page_path).parts:
+ if segment.startswith('__'):
+ flask.abort(404)
+
+ effective_page_path = '__index.html' if page_path == '' else page_path
+
+ app = t.cast(Website, flask.current_app)
+ app.koszko_install_translations(langs_short_2_long[lang_short])
+
+ for prefix in [f'{lang_short}', '']:
+ pure_path = PurePosixPath(prefix) / f'{effective_page_path}.jinja'
+ footer_path = pure_path.parent / f'__footer_for_{pure_path.name}'
+ try:
+ html = flask.render_template(
+ str(pure_path),
+ lang_short = lang_short,
+ page_path = page_path,
+ dedicated_footer_path = str(footer_path)
+ )
+ break
+ except jinja2.exceptions.TemplateNotFound:
+ if prefix == '':
+ raise
+
+ return html
+
+for lang in langs_short_2_long.keys():
+ def __show_page_in_lang(page_path: str, lang_short: str = lang) -> str:
+ return show_page(lang_short, page_path)
+
+ website_app.add_url_rule(
+ f'/{lang}/<path:page_path>',
+ f'show_page_in_{lang}',
+ __show_page_in_lang,
+ methods=['GET']
+ )
+
+ def __show_main_page_in_lang(lang_short: str = lang) -> str:
+ return show_page(lang_short, '')
+
+ website_app.add_url_rule(
+ f'/{lang}/',
+ f'show_main_page_in_{lang}',
+ __show_main_page_in_lang,
+ methods=['GET']
+ )
+
+@website_app.route('/<path:page_path>', methods=['GET'])
+def redirect_to_resource(page_path) -> werkzeug.Response:
+ if page_path != '':
+ path_start = PurePosixPath(page_path).parts[0]
+
+ if path_start == 'sideload':
+ return flask.Response(
+ "Incomplete server configuration - requests for '/sideload/' not routed as they should be.",
+ 500
+ )
+
+ # Route to other stuff that was on this domain before and has been moved
+ # under '/sideload/'.
+ for name in ['fraktal', 'mm']:
+ if path_start == name:
+ return flask.redirect(f'/sideload/{name}')
+
+ # Make all resources from '/static' aliased under '/'.
+ if not page_path.endswith('.html'):
+ return flask.redirect(f'/static/{page_path}')
+
+ # Redirect to the most suitable language version of a page.
+ chosen_locale = flask.request.accept_languages.best_match(
+ langs_short_2_long.values(),
+ default = default_locale
+ )
+ if chosen_locale is None:
+ chosen_locale = default_locale
+
+ lang_short = langs_long_2_short[chosen_locale]
+
+ url = flask.url_for(
+ f'.show_page_in_{lang_short}',
+ page_path = page_path
+ )
+ return flask.redirect(url)
+
+@website_app.route('/', methods=['GET'])
+def redirect_to_lang_main_page() -> werkzeug.Response:
+ return redirect_to_resource('')